<commit_before>// This file is part of Poseidon.
// Copyleft 2020, LH_Mouse. All wrongs reserved.

#ifndef POSEIDON_SOCKET_ABSTRACT_SOCKET_
#define POSEIDON_SOCKET_ABSTRACT_SOCKET_

#include "../fwd.hpp"
#include "enums.hpp"
#include "socket_address.hpp"

namespace poseidon {

class Abstract_Socket
  : public ::asteria::Rcfwd<Abstract_Socket>
  {
    friend Network_Driver;

  protected:
    unique_FD m_fd;
    atomic_relaxed<bool> m_resident = { false };  // don't delete if orphaned

    // These are used by network driver.
    uint64_t m_epoll_data = UINT64_MAX;
    uint32_t m_epoll_events = UINT32_MAX;

    // This the local address. It is initialized upon the first request.
    mutable once_flag m_local_addr_once;
    mutable Socket_Address m_local_addr;

    // These are I/O components.
    mutable simple_mutex m_io_mutex;
    Connection_State m_connection_state = connection_state_empty;
    linear_buffer m_rqueue;
    linear_buffer m_wqueue;

  protected:
    // Adopts a foreign or accepted socket.
    explicit
    Abstract_Socket(unique_FD&& fd);

    // Creates a new non-blocking socket.
    explicit
    Abstract_Socket(::sa_family_t family, int type, int protocol = 0);

  protected:
    // The network driver notifies incoming data via this callback.
    // `lock` shall lock `*this` after the call if locking is supported.
    // Please mind thread safety, as this function is called by the network thread.
    virtual
    IO_Result
    do_socket_on_poll_read(simple_mutex::unique_lock& lock)
      = 0;

    // This function shall return the number of bytes that are pending for writing.
    // `lock` shall lock `*this` after the call if locking is supported.
    virtual
    size_t
    do_write_queue_size(simple_mutex::unique_lock& lock) const
      = 0;

    // The network driver notifies possibility of outgoing data via this callback.
    // `lock` shall lock `*this` after the call if locking is supported.
    // Please mind thread safety, as this function is called by the network thread.
    virtual
    IO_Result
    do_socket_on_poll_write(simple_mutex::unique_lock& lock)
      = 0;

    // The network driver notifies closure via this callback.
    // `err` is zero for graceful shutdown.
    // Please mind thread safety, as this function is called by the network thread.
    virtual
    void
    do_socket_on_poll_close(int err)
      = 0;

  public:
    ASTERIA_NONCOPYABLE_DESTRUCTOR(Abstract_Socket);

    // Prevents this socket from being deleted if network driver holds its last
    // reference.
    bool
    set_resident(bool value = true) noexcept
      { return this->m_resident.exchange(value);  }

    // Returns the stream descriptor.
    // This is used to query and adjust stream flags. You shall not perform I/O
    // operations on it.
    ROCKET_PURE
    int
    get_fd() const noexcept
      { return this->m_fd;  }

    // Causes abnormal termination of this stream.
    // Any data that have not been delivered to the other peer are discarded.
    // The other peer is likely to see a 'connection reset by peer' error.
    void
    kill() noexcept;

    // Gets the (bound) address of the local peer.
    const Socket_Address&
    get_local_address() const;
  };

}  // namespace poseidon

#endif
<commit_msg>abstract_socket: Make private data private<commit_after>// This file is part of Poseidon.
// Copyleft 2020, LH_Mouse. All wrongs reserved.

#ifndef POSEIDON_SOCKET_ABSTRACT_SOCKET_
#define POSEIDON_SOCKET_ABSTRACT_SOCKET_

#include "../fwd.hpp"
#include "enums.hpp"
#include "socket_address.hpp"

namespace poseidon {

class Abstract_Socket
  : public ::asteria::Rcfwd<Abstract_Socket>
  {
    friend Network_Driver;

  private:
    unique_FD m_fd;
    atomic_relaxed<bool> m_resident = { false };  // don't delete if orphaned

    // These are used by network driver.
    uint64_t m_epoll_data = UINT64_MAX;
    uint32_t m_epoll_events = UINT32_MAX;

    // This the local address. It is initialized upon the first request.
    mutable once_flag m_local_addr_once;
    mutable Socket_Address m_local_addr;

  protected:
    // These are I/O components.
    mutable simple_mutex m_io_mutex;
    Connection_State m_connection_state = connection_state_empty;
    linear_buffer m_rqueue;
    linear_buffer m_wqueue;

  protected:
    // Adopts a foreign or accepted socket.
    explicit
    Abstract_Socket(unique_FD&& fd);

    // Creates a new non-blocking socket.
    explicit
    Abstract_Socket(::sa_family_t family, int type, int protocol = 0);

  protected:
    // The network driver notifies incoming data via this callback.
    // `lock` shall lock `*this` after the call if locking is supported.
    // Please mind thread safety, as this function is called by the network thread.
    virtual
    IO_Result
    do_socket_on_poll_read(simple_mutex::unique_lock& lock)
      = 0;

    // This function shall return the number of bytes that are pending for writing.
    // `lock` shall lock `*this` after the call if locking is supported.
    virtual
    size_t
    do_write_queue_size(simple_mutex::unique_lock& lock) const
      = 0;

    // The network driver notifies possibility of outgoing data via this callback.
    // `lock` shall lock `*this` after the call if locking is supported.
    // Please mind thread safety, as this function is called by the network thread.
    virtual
    IO_Result
    do_socket_on_poll_write(simple_mutex::unique_lock& lock)
      = 0;

    // The network driver notifies closure via this callback.
    // `err` is zero for graceful shutdown.
    // Please mind thread safety, as this function is called by the network thread.
    virtual
    void
    do_socket_on_poll_close(int err)
      = 0;

  public:
    ASTERIA_NONCOPYABLE_DESTRUCTOR(Abstract_Socket);

    // Prevents this socket from being deleted if network driver holds its last
    // reference.
    bool
    set_resident(bool value = true) noexcept
      { return this->m_resident.exchange(value);  }

    // Returns the stream descriptor.
    // This is used to query and adjust stream flags. You shall not perform I/O
    // operations on it.
    ROCKET_PURE
    int
    get_fd() const noexcept
      { return this->m_fd;  }

    // Causes abnormal termination of this stream.
    // Any data that have not been delivered to the other peer are discarded.
    // The other peer is likely to see a 'connection reset by peer' error.
    void
    kill() noexcept;

    // Gets the (bound) address of the local peer.
    const Socket_Address&
    get_local_address() const;
  };

}  // namespace poseidon

#endif
<|endoftext|>


<commit_before>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2011-2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */

#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <string.h>
#include <fnordmetric/sql/svalue.h>
#include <fnordmetric/sql/symboltable.h>
#include <fnordmetric/util/runtimeexception.h>

namespace fnordmetric {
namespace query {

void eqExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  assert(argc == 2);
  SValue* lhs = argv;
  SValue* rhs = argv + 1;

  switch(lhs->getType()) {
    case SValue::T_INTEGER:
      switch(rhs->getType()) {
        case SValue::T_INTEGER:
          *out = SValue(lhs->getInteger() == rhs->getInteger());
          return;
        case SValue::T_FLOAT:
          *out = SValue(lhs->getInteger() == rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    case SValue::T_FLOAT:
      switch(rhs->getType()) {
        case SValue::T_INTEGER:
          *out = SValue(lhs->getFloat() == rhs->getInteger());
          return;
        case SValue::T_FLOAT:
          *out = SValue(lhs->getFloat() == rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    default:
      break;
  }

  RAISE(util::RuntimeException, "can't compare %s with %s",
      lhs->getTypeName(),
      rhs->getTypeName());
}

static SymbolTableEntry __eq_symbol("eq", &eqExpr);

void andExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  assert(argc == 2);
  SValue* lhs = argv;
  SValue* rhs = argv + 1;

  switch(lhs->getType()) {
    case SValue::T_BOOL:
      switch(rhs->getType()) {
        case SValue::T_BOOL:
          *out = SValue(lhs->getBool() && rhs->getBool());
          return;
      }
  }

  assert(0);
}

static SymbolTableEntry __and_symbol("and", &andExpr);

void orExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  assert(argc == 2);
  SValue* lhs = argv;
  SValue* rhs = argv + 1;

  switch(lhs->getType()) {
    case SValue::T_BOOL:
      switch(rhs->getType()) {
        case SValue::T_BOOL:
          *out = SValue(lhs->getBool() || rhs->getBool());
          return;
      }
  }

  assert(0);
}

static SymbolTableEntry __or_symbol("or", &orExpr);

void negExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  assert(argc == 1);
  SValue* val = argv;

  switch(val->getType()) {
    case SValue::T_INTEGER:
      *out = SValue(val->getInteger() * -1);
      return;
    case SValue::T_FLOAT:
      *out = SValue(val->getFloat() * -1.0f);
      return;
    case SValue::T_BOOL:
      *out = SValue(!val->getBool());
      return;
    default:
      break;
  }

  assert(0);
}

static SymbolTableEntry __neg_symbol("neg", &negExpr);

void ltExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  assert(argc == 2);
  SValue* lhs = argv;
  SValue* rhs = argv + 1;

  switch(lhs->getType()) {
    case SValue::T_INTEGER:
      switch(rhs->getType()) {
        case SValue::T_INTEGER:
          *out = SValue(lhs->getInteger() < rhs->getInteger());
          return;
        case SValue::T_FLOAT:
          *out = SValue(lhs->getInteger() < rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    case SValue::T_FLOAT:
      switch(rhs->getType()) {
        case SValue::T_INTEGER:
          *out = SValue(lhs->getFloat() < rhs->getInteger());
          return;
        case SValue::T_FLOAT:
          *out = SValue(lhs->getFloat() < rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    default:
      break;
  }

  assert(0);
}

static SymbolTableEntry __lt_symbol("lt", &ltExpr);

void gtExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  assert(argc == 2);
  SValue* lhs = argv;
  SValue* rhs = argv + 1;

  switch(lhs->getType()) {
    case SValue::T_INTEGER:
      switch(rhs->getType()) {
        case SValue::T_INTEGER:
          *out = SValue(lhs->getInteger() > rhs->getInteger());
          return;
        case SValue::T_FLOAT:
          *out = SValue(lhs->getInteger() > rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    case SValue::T_FLOAT:
      switch(rhs->getType()) {
        case SValue::T_INTEGER:
          *out = SValue(lhs->getFloat() > rhs->getInteger());
          return;
        case SValue::T_FLOAT:
          *out = SValue(lhs->getFloat() > rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    default:
      break;
  }

  assert(0); // FIXPAUL
}

static SymbolTableEntry __gt_symbol("gt", &gtExpr);

}
}
<commit_msg>boolean expressions...<commit_after>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2011-2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */

#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <string.h>
#include <fnordmetric/sql/svalue.h>
#include <fnordmetric/sql/symboltable.h>
#include <fnordmetric/util/runtimeexception.h>

namespace fnordmetric {
namespace query {

void eqExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  assert(argc == 2);
  SValue* lhs = argv;
  SValue* rhs = argv + 1;

  switch(lhs->getType()) {
    case SValue::T_INTEGER:
      switch(rhs->getType()) {
        case SValue::T_INTEGER:
          *out = SValue(lhs->getInteger() == rhs->getInteger());
          return;
        case SValue::T_FLOAT:
          *out = SValue(lhs->getInteger() == rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    case SValue::T_FLOAT:
      switch(rhs->getType()) {
        case SValue::T_INTEGER:
          *out = SValue(lhs->getFloat() == rhs->getInteger());
          return;
        case SValue::T_FLOAT:
          *out = SValue(lhs->getFloat() == rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    default:
      break;
  }

  *out = SValue(*lhs == *rhs);
}

static SymbolTableEntry __eq_symbol("eq", &eqExpr);

void andExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  assert(argc == 2);
  SValue* lhs = argv;
  SValue* rhs = argv + 1;

  switch(lhs->getType()) {
    case SValue::T_BOOL:
      switch(rhs->getType()) {
        case SValue::T_BOOL:
          *out = SValue(lhs->getBool() && rhs->getBool());
          return;
      }
  }

  RAISE(util::RuntimeException, "can't AND %s with %s",
      lhs->getTypeName(),
      rhs->getTypeName());
}

static SymbolTableEntry __and_symbol("and", &andExpr);

void orExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  assert(argc == 2);
  SValue* lhs = argv;
  SValue* rhs = argv + 1;

  switch(lhs->getType()) {
    case SValue::T_BOOL:
      switch(rhs->getType()) {
        case SValue::T_BOOL:
          *out = SValue(lhs->getBool() || rhs->getBool());
          return;
      }
  }

  RAISE(util::RuntimeException, "can't OR %s with %s",
      lhs->getTypeName(),
      rhs->getTypeName());
}

static SymbolTableEntry __or_symbol("or", &orExpr);

void negExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  assert(argc == 1);
  SValue* val = argv;

  switch(val->getType()) {
    case SValue::T_INTEGER:
      *out = SValue(val->getInteger() * -1);
      return;
    case SValue::T_FLOAT:
      *out = SValue(val->getFloat() * -1.0f);
      return;
    case SValue::T_BOOL:
      *out = SValue(!val->getBool());
      return;
    default:
      break;
  }

  RAISE(util::RuntimeException, "can't negate %s",
      val->getTypeName());
}

static SymbolTableEntry __neg_symbol("neg", &negExpr);

void ltExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  assert(argc == 2);
  SValue* lhs = argv;
  SValue* rhs = argv + 1;

  switch(lhs->getType()) {
    case SValue::T_INTEGER:
      switch(rhs->getType()) {
        case SValue::T_INTEGER:
          *out = SValue(lhs->getInteger() < rhs->getInteger());
          return;
        case SValue::T_FLOAT:
          *out = SValue(lhs->getInteger() < rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    case SValue::T_FLOAT:
      switch(rhs->getType()) {
        case SValue::T_INTEGER:
          *out = SValue(lhs->getFloat() < rhs->getInteger());
          return;
        case SValue::T_FLOAT:
          *out = SValue(lhs->getFloat() < rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    default:
      break;
  }

  RAISE(util::RuntimeException, "can't compare %s with %s",
      lhs->getTypeName(),
      rhs->getTypeName());
}

static SymbolTableEntry __lt_symbol("lt", &ltExpr);

void gtExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  assert(argc == 2);
  SValue* lhs = argv;
  SValue* rhs = argv + 1;

  switch(lhs->getType()) {
    case SValue::T_INTEGER:
      switch(rhs->getType()) {
        case SValue::T_INTEGER:
          *out = SValue(lhs->getInteger() > rhs->getInteger());
          return;
        case SValue::T_FLOAT:
          *out = SValue(lhs->getInteger() > rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    case SValue::T_FLOAT:
      switch(rhs->getType()) {
        case SValue::T_INTEGER:
          *out = SValue(lhs->getFloat() > rhs->getInteger());
          return;
        case SValue::T_FLOAT:
          *out = SValue(lhs->getFloat() > rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    default:
      break;
  }

  RAISE(util::RuntimeException, "can't compare %s with %s",
      lhs->getTypeName(),
      rhs->getTypeName());
}

static SymbolTableEntry __gt_symbol("gt", &gtExpr);

}
}
<|endoftext|>


<commit_before>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2011-2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */

#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <string.h>
#include <fnordmetric/sql/svalue.h>
#include <fnordmetric/sql/symboltable.h>
#include <fnordmetric/util/runtimeexception.h>

namespace fnordmetric {
namespace query {

void eqExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  if (argc != 2) {
    RAISE(
        util::RuntimeException,
        "wrong number of arguments for eq. expected: 2, got: %i", argc);
  }

  SValue* lhs = argv;
  SValue* rhs = argv + 1;

  switch(lhs->testTypeWithNumericConversion()) {
    case SValue::T_INTEGER:
      switch(rhs->testTypeWithNumericConversion()) {
        case SValue::T_INTEGER:
          *out = SValue(lhs->getInteger() == rhs->getInteger());
          return;
        case SValue::T_FLOAT:
          *out = SValue(lhs->getFloat() == rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    case SValue::T_FLOAT:
      switch(rhs->testTypeWithNumericConversion()) {
        case SValue::T_INTEGER:
        case SValue::T_FLOAT:
          *out = SValue(lhs->getFloat() == rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    default:
      break;
  }

  if (lhs->getType() == SValue::T_STRING ||
      rhs->getType() == SValue::T_STRING) {
    *out = SValue(lhs->toString() == rhs->toString());
    return;
  }

  RAISE(util::RuntimeException, "can't compare %s with %s",
      lhs->getTypeName(),
      rhs->getTypeName());
}

static SymbolTableEntry __eq_symbol("eq", &eqExpr);

void andExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  if (argc != 2) {
    RAISE(
        util::RuntimeException,
        "wrong number of arguments for and. expected: 2, got: %i", argc);
  }

  SValue* lhs = argv;
  SValue* rhs = argv + 1;

  switch(lhs->getType()) {
    case SValue::T_BOOL:
      switch(rhs->getType()) {
        case SValue::T_BOOL:
          *out = SValue(lhs->getBool() && rhs->getBool());
          return;
      }
  }

  RAISE(util::RuntimeException, "can't AND %s with %s",
      lhs->getTypeName(),
      rhs->getTypeName());
}

static SymbolTableEntry __and_symbol("and", &andExpr);

void orExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  if (argc != 2) {
    RAISE(
        util::RuntimeException,
        "wrong number of arguments for or. expected: 2, got: %i", argc);
  }

  SValue* lhs = argv;
  SValue* rhs = argv + 1;

  switch(lhs->getType()) {
    case SValue::T_BOOL:
      switch(rhs->getType()) {
        case SValue::T_BOOL:
          *out = SValue(lhs->getBool() || rhs->getBool());
          return;
      }
  }

  RAISE(util::RuntimeException, "can't OR %s with %s",
      lhs->getTypeName(),
      rhs->getTypeName());
}

static SymbolTableEntry __or_symbol("or", &orExpr);

void negExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  if (argc != 1) {
    RAISE(
        util::RuntimeException,
        "wrong number of arguments for neg. expected: 1, got: %i", argc);
  }

  SValue* val = argv;

  switch(val->getType()) {
    case SValue::T_INTEGER:
      *out = SValue(val->getInteger() * -1);
      return;
    case SValue::T_FLOAT:
      *out = SValue(val->getFloat() * -1.0f);
      return;
    case SValue::T_BOOL:
      *out = SValue(!val->getBool());
      return;
    default:
      break;
  }

  RAISE(util::RuntimeException, "can't negate %s",
      val->getTypeName());
}

static SymbolTableEntry __neg_symbol("neg", &negExpr);

void ltExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  if (argc != 2) {
    RAISE(
        util::RuntimeException,
        "wrong number of arguments for lt. expected: 2, got: %i", argc);
  }

  SValue* lhs = argv;
  SValue* rhs = argv + 1;

  switch(lhs->getType()) {
    case SValue::T_INTEGER:
      switch(rhs->testTypeWithNumericConversion()) {
        case SValue::T_INTEGER:
          *out = SValue(lhs->getInteger() < rhs->getInteger());
          return;
        case SValue::T_FLOAT:
          *out = SValue(lhs->getInteger() < rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    case SValue::T_FLOAT:
      switch(rhs->testTypeWithNumericConversion()) {
        case SValue::T_INTEGER:
          *out = SValue(lhs->getFloat() < rhs->getInteger());
          return;
        case SValue::T_FLOAT:
          *out = SValue(lhs->getFloat() < rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    default:
      break;
  }

  RAISE(util::RuntimeException, "can't compare %s with %s",
      lhs->getTypeName(),
      rhs->getTypeName());
}

static SymbolTableEntry __lt_symbol("lt", &ltExpr);

void gtExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  if (argc != 2) {
    RAISE(
        util::RuntimeException,
        "wrong number of arguments for gt. expected: 2, got: %i", argc);
  }

  SValue* lhs = argv;
  SValue* rhs = argv + 1;

  switch(lhs->getType()) {
    case SValue::T_INTEGER:
      switch(rhs->getType()) {
        case SValue::T_INTEGER:
          *out = SValue(lhs->getInteger() > rhs->getInteger());
          return;
        case SValue::T_FLOAT:
          *out = SValue(lhs->getInteger() > rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    case SValue::T_FLOAT:
      switch(rhs->getType()) {
        case SValue::T_INTEGER:
          *out = SValue(lhs->getFloat() > rhs->getInteger());
          return;
        case SValue::T_FLOAT:
          *out = SValue(lhs->getFloat() > rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    default:
      break;
  }

  RAISE(util::RuntimeException, "can't ompare %s with %s",
      lhs->getTypeName(),
      rhs->getTypeName());
}

static SymbolTableEntry __gt_symbol("gt", &gtExpr);

}
}
<commit_msg>numeric conversion in lt/gt expressions<commit_after>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2011-2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */

#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <string.h>
#include <fnordmetric/sql/svalue.h>
#include <fnordmetric/sql/symboltable.h>
#include <fnordmetric/util/runtimeexception.h>

namespace fnordmetric {
namespace query {

void eqExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  if (argc != 2) {
    RAISE(
        util::RuntimeException,
        "wrong number of arguments for eq. expected: 2, got: %i", argc);
  }

  SValue* lhs = argv;
  SValue* rhs = argv + 1;

  switch(lhs->testTypeWithNumericConversion()) {
    case SValue::T_INTEGER:
      switch(rhs->testTypeWithNumericConversion()) {
        case SValue::T_INTEGER:
          *out = SValue(lhs->getInteger() == rhs->getInteger());
          return;
        case SValue::T_FLOAT:
          *out = SValue(lhs->getFloat() == rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    case SValue::T_FLOAT:
      switch(rhs->testTypeWithNumericConversion()) {
        case SValue::T_INTEGER:
        case SValue::T_FLOAT:
          *out = SValue(lhs->getFloat() == rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    default:
      break;
  }

  if (lhs->getType() == SValue::T_STRING ||
      rhs->getType() == SValue::T_STRING) {
    *out = SValue(lhs->toString() == rhs->toString());
    return;
  }

  RAISE(util::RuntimeException, "can't compare %s with %s",
      lhs->getTypeName(),
      rhs->getTypeName());
}

static SymbolTableEntry __eq_symbol("eq", &eqExpr);

void andExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  if (argc != 2) {
    RAISE(
        util::RuntimeException,
        "wrong number of arguments for and. expected: 2, got: %i", argc);
  }

  SValue* lhs = argv;
  SValue* rhs = argv + 1;

  switch(lhs->getType()) {
    case SValue::T_BOOL:
      switch(rhs->getType()) {
        case SValue::T_BOOL:
          *out = SValue(lhs->getBool() && rhs->getBool());
          return;
      }
  }

  RAISE(util::RuntimeException, "can't AND %s with %s",
      lhs->getTypeName(),
      rhs->getTypeName());
}

static SymbolTableEntry __and_symbol("and", &andExpr);

void orExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  if (argc != 2) {
    RAISE(
        util::RuntimeException,
        "wrong number of arguments for or. expected: 2, got: %i", argc);
  }

  SValue* lhs = argv;
  SValue* rhs = argv + 1;

  switch(lhs->getType()) {
    case SValue::T_BOOL:
      switch(rhs->getType()) {
        case SValue::T_BOOL:
          *out = SValue(lhs->getBool() || rhs->getBool());
          return;
      }
  }

  RAISE(util::RuntimeException, "can't OR %s with %s",
      lhs->getTypeName(),
      rhs->getTypeName());
}

static SymbolTableEntry __or_symbol("or", &orExpr);

void negExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  if (argc != 1) {
    RAISE(
        util::RuntimeException,
        "wrong number of arguments for neg. expected: 1, got: %i", argc);
  }

  SValue* val = argv;

  switch(val->testTypeWithNumericConversion()) {
    case SValue::T_INTEGER:
      *out = SValue(val->getInteger() * -1);
      return;
    case SValue::T_FLOAT:
      *out = SValue(val->getFloat() * -1.0f);
      return;
    case SValue::T_BOOL:
      *out = SValue(!val->getBool());
      return;
    default:
      break;
  }

  RAISE(util::RuntimeException, "can't negate %s",
      val->getTypeName());
}

static SymbolTableEntry __neg_symbol("neg", &negExpr);

void ltExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  if (argc != 2) {
    RAISE(
        util::RuntimeException,
        "wrong number of arguments for lt. expected: 2, got: %i", argc);
  }

  SValue* lhs = argv;
  SValue* rhs = argv + 1;

  switch(lhs->testTypeWithNumericConversion()) {
    case SValue::T_INTEGER:
      switch(rhs->testTypeWithNumericConversion()) {
        case SValue::T_INTEGER:
          *out = SValue(lhs->getInteger() < rhs->getInteger());
          return;
        case SValue::T_FLOAT:
          *out = SValue(lhs->getFloat() < rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    case SValue::T_FLOAT:
      switch(rhs->testTypeWithNumericConversion()) {
        case SValue::T_INTEGER:
        case SValue::T_FLOAT:
          *out = SValue(lhs->getFloat() < rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    default:
      break;
  }

  RAISE(util::RuntimeException, "can't compare %s with %s",
      lhs->getTypeName(),
      rhs->getTypeName());
}

static SymbolTableEntry __lt_symbol("lt", &ltExpr);

void gtExpr(void* scratchpad, int argc, SValue* argv, SValue* out) {
  if (argc != 2) {
    RAISE(
        util::RuntimeException,
        "wrong number of arguments for gt. expected: 2, got: %i", argc);
  }

  SValue* lhs = argv;
  SValue* rhs = argv + 1;

  switch(lhs->testTypeWithNumericConversion()) {
    case SValue::T_INTEGER:
      switch(rhs->testTypeWithNumericConversion()) {
        case SValue::T_INTEGER:
          *out = SValue(lhs->getInteger() > rhs->getInteger());
          return;
        case SValue::T_FLOAT:
          *out = SValue(lhs->getFloat() > rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    case SValue::T_FLOAT:
      switch(rhs->testTypeWithNumericConversion()) {
        case SValue::T_INTEGER:
        case SValue::T_FLOAT:
          *out = SValue(lhs->getFloat() > rhs->getFloat());
          return;
        default:
          break;
      }
      break;
    default:
      break;
  }

  RAISE(util::RuntimeException, "can't compare %s with %s",
      lhs->getTypeName(),
      rhs->getTypeName());
}

static SymbolTableEntry __gt_symbol("gt", &gtExpr);

}
}
<|endoftext|>


<commit_before>
#include "util/zorba.h"
#include "store/naive/qname_pool.h"

namespace xqp
{

QNamePool* QNameImpl::theQNamePool = NULL;
//const xqp_unsignedLong QNamePool::MAX_CACHE_SIZE = 65536;
const float QNamePool::DEFAULT_LOAD_FACTOR = 0.6;

/////////////////////////////////////////////////////////////////////////////////
//                                                                             //
//  QNamePool                                                                  //
//                                                                             //
/////////////////////////////////////////////////////////////////////////////////

/*******************************************************************************

********************************************************************************/
QNamePool::QNamePool(xqp_unsignedLong size)
  :
  theCache(new QNameImpl[size]),
  theCacheSize(size),
  theFirstFree(1),
  theNumFree(size - 1),
  theNumQNames(0),
  theHashTabSize(2 * size),
  theLoadFactor(DEFAULT_LOAD_FACTOR)
{
  // Put all the preallocated slots in the free list of the cahce.
  for (xqp_unsignedLong i = 1; i < size - 1; i++)
  {
    theCache[i].theNextFree = i + 1;
    theCache[i].thePrevFree = i - 1;
    theCache[i].thePosition = i;
  }
  theCache[size-1].theNextFree = 0;
  theCache[size-1].thePrevFree = size - 2;
  theCache[size-1].thePosition = size - 1;

  // Allocate the hash table. Its initial size is double the size of theCache,
  // plus an inital 32 overflow entries.
  theHashTab.resize(theHashTabSize + 32);

  // Format the overflow area of theHashTab as a list of free entries
  HashEntry* lastentry = &theHashTab[theHashTabSize + 31];
  for (HashEntry* entry = &theHashTab[theHashTabSize]; entry < lastentry; entry++)
    entry->theNext = entry + 1;
}

/*******************************************************************************

********************************************************************************/
QNamePool::~QNamePool()
{
#if 0
  xqp_unsignedLong n = theOverflow.size();
  for (xqp_unsignedLong i = 0; i < n; i++)
  {
    if (theOverflow[i] != NULL)
      delete theOverflow[i];
  }
#else
  xqp_unsignedLong n = theHashTab.size();
  for (xqp_unsignedLong i = 0; i < n; i++)
  {
    if (theHashTab[i].theQName != NULL && theHashTab[i].theQName->isOverflow())
      ::delete theHashTab[i].theQName;
  }
#endif

  if (theCache != NULL)
  {
    delete [] theCache;
    theCache = NULL;
  }
}

/*******************************************************************************

********************************************************************************/
QNameImpl* QNamePool::insert(
    const char* ns,
    const char* pre,
    const char* ln)
{
  QNameImpl* qn;

  HashEntry* entry = hash(ns, pre, ln);

  // If the qname is already in the pool, return a ptr to its containing slot.
  // If the slot is in the free list of the cache, it is first removed from
  // that list.
  if (entry->theQName != NULL)
  {
    qn = entry->theQName;

    if (qn->isInCache())
    {
      if (qn->theNextFree != 0)
        theCache[qn->theNextFree].thePrevFree = qn->thePrevFree;

      if (qn->thePrevFree != 0)
      {
        theCache[qn->thePrevFree].theNextFree = qn->theNextFree;
      }
      else if (theFirstFree == qn->thePosition)
      {
        theFirstFree = qn->theNextFree;
      }

      qn->theNextFree = qn->thePrevFree = 0;
      theNumFree--;
    }

    return qn;
  }

  // The qname is not in the pool.
  // Use the 1st slot from the free list of the cache to store the new qname.
  // The qname was is currently in that slot is removed from the cache.
  if (theFirstFree != 0)
  {
    qn = &theCache[theFirstFree];
    entry->theQName = qn;

    theFirstFree = qn->theNextFree;
    theCache[theFirstFree].thePrevFree = 0;

    if (!qn->theLocal.empty())
      unhash(qn->theNamespace.c_str(), qn->thePrefix.c_str(), qn->theLocal.c_str());

    qn->theNextFree = qn->thePrevFree = 0;
    qn->theNamespace = ns;
    qn->thePrefix = pre;
    qn->theLocal = ln;

    theNumFree--;

    return qn;
  }

  // The cache was full, so allocate a QNameItem from the heap.
  qn = new QNameImpl(ns, pre, ln);
  //theOverflow.push_back(qn);
  entry->theQName = qn;
  return qn;
}

/*******************************************************************************

********************************************************************************/
void QNamePool::remove(QNameImpl* qn)
{
  if (qn->get_refCount() > 0)
    return;

  if (qn->isInCache())
  {
    qn->theNextFree = theFirstFree;
    theCache[theFirstFree].thePrevFree = qn->thePosition;
    theFirstFree = qn->thePosition;
    theNumFree++;
  }
  else
  {
    // If all the pointers to QNameItems were smart pointers, we could leave
    // qn in the pool, and let the pool garbage-collect it later (if it still
    // unused). If however QNameItems may be referenced by regular pointers as
    // well, then qn must be removed from the pool and really deleted
    unhash(qn->getNamespace().c_str(),
           qn->getPrefix().c_str(),
           qn->getLocalName().c_str());

    //std::vector<QNameImpl *>::iterator it;
    //it = theOverflow.begin() + qn->thePosition;
    //theOverflow.erase(it);

    ::delete qn;
  }
}

/*******************************************************************************
  Check if the given qname is already in the pool, and if so, return its hash
  entry. If not, allocate a new hash entry for it, and return it to the caller.
********************************************************************************/
QNamePool::HashEntry*
QNamePool::hash(const char* ns, const char* pre, const char* ln)
{
  xqp_unsignedLong len;
  HashEntry* entry;
  HashEntry* lastentry;

  // Get ptr to the 1st entry of the hash bucket corresponding to the given qname
  xqp_unsignedLong hval = hashfun::h32(pre, hashfun::h32(ln, hashfun::h32(ns))) % theHashTabSize;
  entry = &theHashTab[ hval % theHashTabSize];

  // If the hash bucket is empty, its 1st entry is used to store the new qname.
  if (entry->isFree())
  {
    theNumQNames++;
    return entry;
  }

  // Search the hash bucket looking for the given qname.
  while (entry != NULL)
  {
    QNameImpl* qn = entry->theQName;

    len = qn->theLocal.bytes();
    if (len != strlen(ln) || memcmp(qn->theLocal.c_str(), ln, len) != 0)
    {
      lastentry = entry;
      entry =  entry->theNext;
      continue;
    }

    len = qn->theNamespace.bytes();
    if (len != strlen(ns) || memcmp(qn->theNamespace.c_str(), ns, len) != 0)
    {
      lastentry = entry;
      entry =  entry->theNext;
      continue;
    }

    len = qn->thePrefix.bytes();
    if (len != strlen(pre) || memcmp(qn->thePrefix.c_str(), pre, len) != 0)
    {
      lastentry = entry;
      entry =  entry->theNext;
      continue;
    }

    return entry;
  }

  // The qname was not found.

  // Double the size of hash table if it is more than 60% full.
  if (theNumQNames > theHashTabSize * theLoadFactor)
    resizeHashTab();

  // Get an entry from the free list in the overflow section of the hash teble
  // If no free entry exists, a new entry is appended into the hash table.
  if (theHashTab[theHashTabSize].theNext == 0)
  {
    theHashTab.push_back(HashEntry());
    entry = &theHashTab[theHashTab.size() - 1];
    lastentry->theNext = entry;
  }
  else
  {
    entry = theHashTab[theHashTabSize].theNext;
    theHashTab[theHashTabSize].theNext = entry->theNext;
    lastentry->theNext = entry;
    entry->theNext = NULL;
  }

  theNumQNames++;

  return entry;
}

/*******************************************************************************
  Remove the given qname from the hash table, if it is found there.
********************************************************************************/
void QNamePool::unhash(const char* ns, const char* pre, const char* ln)
{
  xqp_unsignedLong len;
  HashEntry* entry;
  HashEntry* preventry = NULL;

  // Get ptr to the 1st entry of the hash bucket corresponding to the given qname
  xqp_unsignedLong hval = hashfun::h32(pre, hashfun::h32(ln, hashfun::h32(ns))) % theHashTabSize;
  entry = &theHashTab[ hval % theHashTabSize];

  // If the hash bucket is empty, the qname is not in the hash table.
  if (entry->isFree())
    return;

  // Search the hash bucket looking for the given qname.
  while (entry != NULL)
  {
    QNameImpl* qn = entry->theQName;

    len = qn->theLocal.bytes();
    if (len != strlen(ln) || memcmp(qn->theLocal.c_str(), ln, len) != 0)
    {
      preventry = entry;
      entry =  entry->theNext;
      continue;
    }

    len = qn->theNamespace.bytes();
    if (len != strlen(ns) || memcmp(qn->theNamespace.c_str(), ns, len) != 0)
    {
      preventry = entry;
      entry =  entry->theNext;
      continue;
    }

    len = qn->thePrefix.bytes();
    if (len != strlen(pre) || memcmp(qn->thePrefix.c_str(), pre, len) != 0)
    {
      preventry = entry;
      entry =  entry->theNext;
      continue;
    }

    // Found the qname in the current entry. Must remove the entry from the
    // hash bucket and add it to the free list.
    if (preventry != NULL)
    {
      preventry->theNext = entry->theNext;
      entry->theQName = NULL;
      entry->theNext = theHashTab[theHashTabSize].theNext;
      theHashTab[theHashTabSize].theNext = entry;
    }
    else if (entry->theNext != NULL)
    {
      HashEntry* nextentry = entry->theNext;
      *entry = *nextentry;
      nextentry->theQName = NULL;
      nextentry->theNext = theHashTab[theHashTabSize].theNext;
      theHashTab[theHashTabSize].theNext = nextentry;
    }
    else
    {
      entry->theQName = NULL;
    }

    theNumQNames--;

    return;
  }
}

/*******************************************************************************

********************************************************************************/
void QNamePool::resizeHashTab()
{
  HashEntry* entry;
  HashEntry* lastentry;

  // Make a copy of theHashTab, and then resize it to double theHashTabSize
  std::vector<HashEntry> oldTab = theHashTab;
  xqp_unsignedLong oldsize = oldTab.size();

  theHashTabSize <<= 1;

  theHashTab.clear();
  theHashTab.resize(theHashTabSize + 32);

  // Format the overflow area of theHashTab as a list of free entries
  lastentry = &theHashTab[theHashTabSize + 31];
  for (entry = &theHashTab[theHashTabSize]; entry < lastentry; entry++)
    entry->theNext = entry + 1;

  // Now rehash every entry
  for (xqp_unsignedLong i = 0; i < oldsize; i++)
  {
    QNameImpl* qn = oldTab[i].theQName;

    xqp_unsignedLong h = hashfun::h32(qn->thePrefix.c_str(),
                           hashfun::h32(qn->theLocal.c_str(),
                                        hashfun::h32(qn->theNamespace.c_str())));
    entry = &theHashTab[h % theHashTabSize];

    if (!entry->isFree())
    {
      // Go to the last entry of the current bucket
      HashEntry* lastentry = entry;
      while (lastentry->theNext != NULL)
        lastentry = lastentry->theNext;

      // Get an entry from the free list in the overflow section of the hash
      // table. If no free entry exists, a new entry is appended into the table.
      if (theHashTab[theHashTabSize].theNext == 0)
      {
        theHashTab.push_back(HashEntry());
        entry = &theHashTab[theHashTab.size() - 1];
        lastentry->theNext = entry;
      }
      else
      {
        entry = theHashTab[theHashTabSize].theNext;
        theHashTab[theHashTabSize].theNext = entry->theNext;
        lastentry->theNext = entry;
        entry->theNext = NULL;
      }
    }

    entry->theQName = qn;
  }
}

/////////////////////////////////////////////////////////////////////////////////
//                                                                             //
//  QNameItem                                                                  //
//                                                                             //
/////////////////////////////////////////////////////////////////////////////////

QNameImpl::QNameImpl(
    const xqp_string& ns,
    const xqp_string& pre,
    const xqp_string& local)
  :
  theNamespace(ns),
  thePrefix (pre),
  theLocal(local),
  theNextFree(0),
  thePrevFree(0)
{
}

QNameImpl::QNameImpl(
    const char* ns,
    const char* pre,
    const char* local)
  :
  theNamespace(ns),
  thePrefix (pre),
  theLocal(local),
  theNextFree(0),
  thePrevFree(0)
{
}

void QNameImpl::setQNamePool(QNamePool* p)
{
  theQNamePool = p;
}

void QNameImpl::free()
{
  getQNamePool()->remove(this);
}

qnamekey_t QNameImpl::getQNameKey( ) const
{
  return Item::createQNameKey(theNamespace, thePrefix, theLocal);
}

Item_t QNameImpl::getAtomizationValue( ) const
{
  return zorba::getItemFactory()->createQName(theNamespace, thePrefix, theLocal).get_ptr();
}

bool QNameImpl::equals(Item_t item) const
{
  return (this == item.get_ptr() ||
          (item->getNamespace() == theNamespace &&
           item->getLocalName() == theLocal));
}

Item_t QNameImpl::getEBV( ) const
{
  ZorbaErrorAlerts::error_alert (
        error_messages::FORG0006_INVALID_ARGUMENT_TYPE,
		    error_messages::RUNTIME_ERROR,
		    NULL,
		    false,
		    "Effective Boolean Value is not defined for QName!");
  return NULL;
}

xqp_string QNameImpl::getStringProperty( ) const
{
  return thePrefix != "" ? thePrefix + ":" + theLocal : theLocal;
}

xqp_string QNameImpl::show() const
{
  return "xs:qname(" + theNamespace + "," + thePrefix + "," + theLocal + ")";
}

}
<commit_msg>tiny (?) optimizations in qnamae pool constructor/desctructor<commit_after>
#include "util/zorba.h"
#include "store/naive/qname_pool.h"

namespace xqp
{

QNamePool* QNameImpl::theQNamePool = NULL;

const float QNamePool::DEFAULT_LOAD_FACTOR = 0.6;

/////////////////////////////////////////////////////////////////////////////////
//                                                                             //
//  QNamePool                                                                  //
//                                                                             //
/////////////////////////////////////////////////////////////////////////////////

/*******************************************************************************

********************************************************************************/
QNamePool::QNamePool(xqp_unsignedLong size)
  :
  theCache(new QNameImpl[size]),
  theCacheSize(size),
  theFirstFree(1),
  theNumFree(size - 1),
  theNumQNames(0),
  theHashTabSize(2 * size),
  theLoadFactor(DEFAULT_LOAD_FACTOR)
{
  // Put all the preallocated slots in the free list of the cahce.
  QNameImpl* qn = &theCache[1];
  QNameImpl* last = qn + size - 1;

  for (xqp_unsignedLong i = 1; qn < last; qn++, i++)
  {
    qn->theNextFree = i + 1;
    qn->thePrevFree = i - 1;
    qn->thePosition = i;
  }
  qn->theNextFree = 0;

  // Allocate the hash table. Its initial size is double the size of theCache,
  // plus an inital 32 overflow entries.
  theHashTab.resize(theHashTabSize + 32);

  // Format the overflow area of theHashTab as a list of free entries
  HashEntry* lastentry = &theHashTab[theHashTabSize + 31];
  for (HashEntry* entry = &theHashTab[theHashTabSize]; entry < lastentry; entry++)
    entry->theNext = entry + 1;
}

/*******************************************************************************

********************************************************************************/
QNamePool::~QNamePool()
{
#if 0
  xqp_unsignedLong n = theOverflow.size();
  for (xqp_unsignedLong i = 0; i < n; i++)
  {
    if (theOverflow[i] != NULL)
      delete theOverflow[i];
  }
#else
  xqp_unsignedLong n = theHashTab.size();
  for (xqp_unsignedLong i = 0; i < n; i++)
  {
    if (theHashTab[i].theQName != NULL && theHashTab[i].theQName->isOverflow())
      ::delete theHashTab[i].theQName;
  }
#endif

  if (theCache != NULL)
  {
    delete [] theCache;
    theCache = NULL;
  }
}

/*******************************************************************************

********************************************************************************/
QNameImpl* QNamePool::insert(
    const char* ns,
    const char* pre,
    const char* ln)
{
  QNameImpl* qn;

  HashEntry* entry = hash(ns, pre, ln);

  // If the qname is already in the pool, return a ptr to its containing slot.
  // If the slot is in the free list of the cache, it is first removed from
  // that list.
  if (entry->theQName != NULL)
  {
    qn = entry->theQName;

    if (qn->isInCache())
    {
      if (qn->theNextFree != 0)
        theCache[qn->theNextFree].thePrevFree = qn->thePrevFree;

      if (qn->thePrevFree != 0)
      {
        theCache[qn->thePrevFree].theNextFree = qn->theNextFree;
      }
      else if (theFirstFree == qn->thePosition)
      {
        theFirstFree = qn->theNextFree;
      }

      qn->theNextFree = qn->thePrevFree = 0;
      theNumFree--;
    }

    return qn;
  }

  // The qname is not in the pool.
  // Use the 1st slot from the free list of the cache to store the new qname.
  // The qname was is currently in that slot is removed from the cache.
  if (theFirstFree != 0)
  {
    qn = &theCache[theFirstFree];
    entry->theQName = qn;

    theFirstFree = qn->theNextFree;
    theCache[theFirstFree].thePrevFree = 0;

    if (!qn->theLocal.empty())
      unhash(qn->theNamespace.c_str(), qn->thePrefix.c_str(), qn->theLocal.c_str());

    qn->theNextFree = qn->thePrevFree = 0;
    qn->theNamespace = ns;
    qn->thePrefix = pre;
    qn->theLocal = ln;

    theNumFree--;

    return qn;
  }

  // The cache was full, so allocate a QNameItem from the heap.
  qn = new QNameImpl(ns, pre, ln);
  //theOverflow.push_back(qn);
  entry->theQName = qn;
  return qn;
}

/*******************************************************************************

********************************************************************************/
void QNamePool::remove(QNameImpl* qn)
{
  if (qn->get_refCount() > 0)
    return;

  if (qn->isInCache())
  {
    qn->theNextFree = theFirstFree;
    theCache[theFirstFree].thePrevFree = qn->thePosition;
    theFirstFree = qn->thePosition;
    theNumFree++;
  }
  else
  {
    // If all the pointers to QNameItems were smart pointers, we could leave
    // qn in the pool, and let the pool garbage-collect it later (if it still
    // unused). If however QNameItems may be referenced by regular pointers as
    // well, then qn must be removed from the pool and really deleted
    unhash(qn->getNamespace().c_str(),
           qn->getPrefix().c_str(),
           qn->getLocalName().c_str());

    //std::vector<QNameImpl *>::iterator it;
    //it = theOverflow.begin() + qn->thePosition;
    //theOverflow.erase(it);

    ::delete qn;
  }
}

/*******************************************************************************
  Check if the given qname is already in the pool, and if so, return its hash
  entry. If not, allocate a new hash entry for it, and return it to the caller.
********************************************************************************/
QNamePool::HashEntry*
QNamePool::hash(const char* ns, const char* pre, const char* ln)
{
  xqp_unsignedLong len;
  HashEntry* entry;
  HashEntry* lastentry;

  // Get ptr to the 1st entry of the hash bucket corresponding to the given qname
  xqp_unsignedLong hval = hashfun::h32(pre,
                                       hashfun::h32(ln,
                                                    hashfun::h32(ns))) % theHashTabSize;
  entry = &theHashTab[ hval % theHashTabSize];

  // If the hash bucket is empty, its 1st entry is used to store the new qname.
  if (entry->isFree())
  {
    theNumQNames++;
    return entry;
  }

  // Search the hash bucket looking for the given qname.
  while (entry != NULL)
  {
    QNameImpl* qn = entry->theQName;

    len = qn->theLocal.bytes();
    if (len != strlen(ln) || memcmp(qn->theLocal.c_str(), ln, len) != 0)
    {
      lastentry = entry;
      entry =  entry->theNext;
      continue;
    }

    len = qn->theNamespace.bytes();
    if (len != strlen(ns) || memcmp(qn->theNamespace.c_str(), ns, len) != 0)
    {
      lastentry = entry;
      entry =  entry->theNext;
      continue;
    }

    len = qn->thePrefix.bytes();
    if (len != strlen(pre) || memcmp(qn->thePrefix.c_str(), pre, len) != 0)
    {
      lastentry = entry;
      entry =  entry->theNext;
      continue;
    }

    return entry;
  }

  // The qname was not found.

  // Double the size of hash table if it is more than 60% full.
  if (theNumQNames > theHashTabSize * theLoadFactor)
    resizeHashTab();

  // Get an entry from the free list in the overflow section of the hash teble
  // If no free entry exists, a new entry is appended into the hash table.
  if (theHashTab[theHashTabSize].theNext == 0)
  {
    theHashTab.push_back(HashEntry());
    entry = &theHashTab[theHashTab.size() - 1];
    lastentry->theNext = entry;
  }
  else
  {
    entry = theHashTab[theHashTabSize].theNext;
    theHashTab[theHashTabSize].theNext = entry->theNext;
    lastentry->theNext = entry;
    entry->theNext = NULL;
  }

  theNumQNames++;

  return entry;
}

/*******************************************************************************
  Remove the given qname from the hash table, if it is found there.
********************************************************************************/
void QNamePool::unhash(const char* ns, const char* pre, const char* ln)
{
  xqp_unsignedLong len;
  HashEntry* entry;
  HashEntry* preventry = NULL;

  // Get ptr to the 1st entry of the hash bucket corresponding to the given qname
  xqp_unsignedLong hval = hashfun::h32(pre,
                                       hashfun::h32(ln,
                                                    hashfun::h32(ns))) % theHashTabSize;
  entry = &theHashTab[ hval % theHashTabSize];

  // If the hash bucket is empty, the qname is not in the hash table.
  if (entry->isFree())
    return;

  // Search the hash bucket looking for the given qname.
  while (entry != NULL)
  {
    QNameImpl* qn = entry->theQName;

    len = qn->theLocal.bytes();
    if (len != strlen(ln) || memcmp(qn->theLocal.c_str(), ln, len) != 0)
    {
      preventry = entry;
      entry =  entry->theNext;
      continue;
    }

    len = qn->theNamespace.bytes();
    if (len != strlen(ns) || memcmp(qn->theNamespace.c_str(), ns, len) != 0)
    {
      preventry = entry;
      entry =  entry->theNext;
      continue;
    }

    len = qn->thePrefix.bytes();
    if (len != strlen(pre) || memcmp(qn->thePrefix.c_str(), pre, len) != 0)
    {
      preventry = entry;
      entry =  entry->theNext;
      continue;
    }

    // Found the qname in the current entry. Must remove the entry from the
    // hash bucket and add it to the free list.
    if (preventry != NULL)
    {
      preventry->theNext = entry->theNext;
      entry->theQName = NULL;
      entry->theNext = theHashTab[theHashTabSize].theNext;
      theHashTab[theHashTabSize].theNext = entry;
    }
    else if (entry->theNext != NULL)
    {
      HashEntry* nextentry = entry->theNext;
      *entry = *nextentry;
      nextentry->theQName = NULL;
      nextentry->theNext = theHashTab[theHashTabSize].theNext;
      theHashTab[theHashTabSize].theNext = nextentry;
    }
    else
    {
      entry->theQName = NULL;
    }

    theNumQNames--;

    return;
  }
}

/*******************************************************************************

********************************************************************************/
void QNamePool::resizeHashTab()
{
  HashEntry* entry;
  HashEntry* lastentry;

  // Make a copy of theHashTab, and then resize it to double theHashTabSize
  std::vector<HashEntry> oldTab = theHashTab;
  xqp_unsignedLong oldsize = oldTab.size();

  theHashTabSize <<= 1;

  theHashTab.clear();
  theHashTab.resize(theHashTabSize + 32);

  // Format the overflow area of theHashTab as a list of free entries
  lastentry = &theHashTab[theHashTabSize + 31];
  for (entry = &theHashTab[theHashTabSize]; entry < lastentry; entry++)
    entry->theNext = entry + 1;

  // Now rehash every entry
  for (xqp_unsignedLong i = 0; i < oldsize; i++)
  {
    QNameImpl* qn = oldTab[i].theQName;

    xqp_unsignedLong h = hashfun::h32(qn->thePrefix.c_str(),
                           hashfun::h32(qn->theLocal.c_str(),
                                        hashfun::h32(qn->theNamespace.c_str())));
    entry = &theHashTab[h % theHashTabSize];

    if (!entry->isFree())
    {
      // Go to the last entry of the current bucket
      HashEntry* lastentry = entry;
      while (lastentry->theNext != NULL)
        lastentry = lastentry->theNext;

      // Get an entry from the free list in the overflow section of the hash
      // table. If no free entry exists, a new entry is appended into the table.
      if (theHashTab[theHashTabSize].theNext == 0)
      {
        theHashTab.push_back(HashEntry());
        entry = &theHashTab[theHashTab.size() - 1];
        lastentry->theNext = entry;
      }
      else
      {
        entry = theHashTab[theHashTabSize].theNext;
        theHashTab[theHashTabSize].theNext = entry->theNext;
        lastentry->theNext = entry;
        entry->theNext = NULL;
      }
    }

    entry->theQName = qn;
  }
}

/////////////////////////////////////////////////////////////////////////////////
//                                                                             //
//  QNameItem                                                                  //
//                                                                             //
/////////////////////////////////////////////////////////////////////////////////

QNameImpl::QNameImpl(
    const xqp_string& ns,
    const xqp_string& pre,
    const xqp_string& local)
  :
  theNamespace(ns),
  thePrefix (pre),
  theLocal(local),
  theNextFree(0),
  thePrevFree(0)
{
}

QNameImpl::QNameImpl(
    const char* ns,
    const char* pre,
    const char* local)
  :
  theNamespace(ns),
  thePrefix (pre),
  theLocal(local),
  theNextFree(0),
  thePrevFree(0)
{
}

void QNameImpl::setQNamePool(QNamePool* p)
{
  theQNamePool = p;
}

void QNameImpl::free()
{
  getQNamePool()->remove(this);
}

qnamekey_t QNameImpl::getQNameKey( ) const
{
  return Item::createQNameKey(theNamespace, thePrefix, theLocal);
}

Item_t QNameImpl::getAtomizationValue( ) const
{
  return zorba::getItemFactory()->createQName(theNamespace, thePrefix, theLocal).get_ptr();
}

bool QNameImpl::equals(Item_t item) const
{
  return (this == item.get_ptr() ||
          (item->getNamespace() == theNamespace &&
           item->getLocalName() == theLocal));
}

Item_t QNameImpl::getEBV( ) const
{
  ZorbaErrorAlerts::error_alert (
        error_messages::FORG0006_INVALID_ARGUMENT_TYPE,
		    error_messages::RUNTIME_ERROR,
		    NULL,
		    false,
		    "Effective Boolean Value is not defined for QName!");
  return NULL;
}

xqp_string QNameImpl::getStringProperty( ) const
{
  return thePrefix != "" ? thePrefix + ":" + theLocal : theLocal;
}

xqp_string QNameImpl::show() const
{
  return "xs:qname(" + theNamespace + "," + thePrefix + "," + theLocal + ")";
}

}
<|endoftext|>


<commit_before>/**********************************************************
 * Author        : Hsin-Yi Chou
 * Email         : hchou@cern.ch
 * Last modified : 2015-07-22 16:29
 * Filename      : YiProdNtuple.C
 * Description   :
 * *******************************************************/
#ifndef __YiProdNtuple_C__
#define __YiProdNtuple_C__
#include "YiProdNtuple.h"
#include "YiProdNtuple.tcc"
#include <string.h>

int main(int argc, const char ** argv) {
	COUT("\n**--------------------------**\n");
	COUT("\n**    YiProdNtuple START    **\n");
	COUT("\n**--------------------------**\n");

    google::InitGoogleLogging(argv[0]);
    google::SetStderrLogging(google::GLOG_FATAL);

    TrackSys::Sys::SetEnv("TRACKSys_MagBox", "/ams_home/hchou/AMSData/magnetic/AMS02Mag.bin");
    TrackSys::Sys::SetEnv("TRACKSys_MatBox", "/ams_home/hchou/AMSData/material");

    //TrackSys::Sys::SetEnv("TRACKSys_MagBox", "/eos/ams/user/h/hchou/ExternalLibs/DB/magnetic/AMS02Mag.bin");
    //TrackSys::Sys::SetEnv("TRACKSys_MatBox", "/eos/ams/user/h/hchou/ExternalLibs/DB/material");

    //TrackSys::Sys::SetEnv("TRACKSys_MagBox", "/afs/cern.ch/work/h/hchou/public/DATABASE/DB/magnetic/AMS02Mag.bin");
    //TrackSys::Sys::SetEnv("TRACKSys_MatBox", "/afs/cern.ch/work/h/hchou/public/DATABASE/DB/material");

	YiNtuple::setSelectionMode(YiNtuple::NORM);
	//YiNtuple::setSelectionMode(YiNtuple::COPY);

	DataSelection::setOption(DataSelection::LIST, DataSelection::ON);
	DataSelection::setOption(DataSelection::RTI, DataSelection::ON);
	DataSelection::setOption(DataSelection::TRG, DataSelection::ON);
	DataSelection::setOption(DataSelection::TOF, DataSelection::ON);
	DataSelection::setOption(DataSelection::ACC, DataSelection::ON);
	DataSelection::setOption(DataSelection::TRK, DataSelection::ON);
	DataSelection::setOption(DataSelection::TRD, DataSelection::ON);
	DataSelection::setOption(DataSelection::RICH, DataSelection::ON);
	DataSelection::setOption(DataSelection::ECAL, DataSelection::ON);

	EventBase::setEventVersion(EventBase::B950);

	COUT("\n\n");
	COUT("Usage : YiProdNtuple event_mode file_list group_id group_size (path)\n");
	COUT("    Parameters : \n");
	COUT("    event_mode [ISS BT MC]\n");
	COUT("    file_list\n");
	COUT("    group_id\n");
	COUT("    group_size\n");
	COUT("    (path)\n");
	COUT("\n\n");

	if (argc != 5 && argc != 6)
		MGSys::ShowErrorAndExit(LOCADR(), "Number of argument is not conform! Exiting ...");

	std::string event_mode = argv[1];
	std::string file_list = argv[2];
	Long64_t group_id = atol(argv[3]);
	Long64_t group_size = atol(argv[4]);

	std::use_facet<std::ctype<char> >(std::locale()).toupper(&event_mode[0], &event_mode[0] + event_mode.size());
	if (event_mode == "ISS") EventBase::setEventMode(EventBase::ISS);
	else if (event_mode == "BT") EventBase::setEventMode(EventBase::BT);
	else if (event_mode == "MC") EventBase::setEventMode(EventBase::MC);
	else MGSys::ShowErrorAndExit(LOCADR(), "Can't find event mode (ISS, BT, MC)! Exiting ...");

	std::string outputFile = "";
	if (YiNtuple::checkSelectionMode(YiNtuple::NORM))
		outputFile = STR("YiNtuple_%s.%07ld.root", event_mode.c_str(), group_id);
	else if (YiNtuple::checkSelectionMode(YiNtuple::COPY))
		outputFile = STR("YiMirror_%s.%07ld.root", event_mode.c_str(), group_id);

	std::string path = ".";
	if (argc == 6) path = argv[5];

	bool isMultiTree = false;
	YiNtuple * ntuple = new YiNtuple();
	ntuple->setOutputFile(outputFile, path, isMultiTree);
	ntuple->readDataFrom(file_list, group_id, group_size);
	ntuple->loopEventChain();

	if (ntuple != nullptr) delete ntuple;
	ntuple = nullptr;

	COUT("\n**------------------------**\n");
	COUT("\n**    YiProdNtuple END    **\n");
	COUT("\n**------------------------**\n");
	return 0;
}
#endif // __YiProdNtuple_C__
<commit_msg>update<commit_after>/**********************************************************
 * Author        : Hsin-Yi Chou
 * Email         : hchou@cern.ch
 * Last modified : 2015-07-22 16:29
 * Filename      : YiProdNtuple.C
 * Description   :
 * *******************************************************/
#ifndef __YiProdNtuple_C__
#define __YiProdNtuple_C__
#include "YiProdNtuple.h"
#include "YiProdNtuple.tcc"
#include <string.h>

int main(int argc, const char ** argv) {
	COUT("\n**--------------------------**\n");
	COUT("\n**    YiProdNtuple START    **\n");
	COUT("\n**--------------------------**\n");

    google::InitGoogleLogging(argv[0]);
    google::SetStderrLogging(google::GLOG_FATAL);

    //TrackSys::Sys::SetEnv("TRACKSys_MagBox", "/ams_home/hchou/AMSData/magnetic/AMS02Mag.bin");
    //TrackSys::Sys::SetEnv("TRACKSys_MatBox", "/ams_home/hchou/AMSData/material");

    //TrackSys::Sys::SetEnv("TRACKSys_MagBox", "/eos/ams/user/h/hchou/ExternalLibs/DB/magnetic/AMS02Mag.bin");
    //TrackSys::Sys::SetEnv("TRACKSys_MatBox", "/eos/ams/user/h/hchou/ExternalLibs/DB/material");

    TrackSys::Sys::SetEnv("TRACKSys_MagBox", "/afs/cern.ch/work/h/hchou/public/DATABASE/DB/magnetic/AMS02Mag.bin");
    TrackSys::Sys::SetEnv("TRACKSys_MatBox", "/afs/cern.ch/work/h/hchou/public/DATABASE/DB/material");

	YiNtuple::setSelectionMode(YiNtuple::NORM);
	//YiNtuple::setSelectionMode(YiNtuple::COPY);

	DataSelection::setOption(DataSelection::LIST, DataSelection::ON);
	DataSelection::setOption(DataSelection::RTI, DataSelection::ON);
	DataSelection::setOption(DataSelection::TRG, DataSelection::ON);
	DataSelection::setOption(DataSelection::TOF, DataSelection::ON);
	DataSelection::setOption(DataSelection::ACC, DataSelection::ON);
	DataSelection::setOption(DataSelection::TRK, DataSelection::ON);
	DataSelection::setOption(DataSelection::TRD, DataSelection::ON);
	DataSelection::setOption(DataSelection::RICH, DataSelection::ON);
	DataSelection::setOption(DataSelection::ECAL, DataSelection::ON);

	EventBase::setEventVersion(EventBase::B950);

	COUT("\n\n");
	COUT("Usage : YiProdNtuple event_mode file_list group_id group_size (path)\n");
	COUT("    Parameters : \n");
	COUT("    event_mode [ISS BT MC]\n");
	COUT("    file_list\n");
	COUT("    group_id\n");
	COUT("    group_size\n");
	COUT("    (path)\n");
	COUT("\n\n");

	if (argc != 5 && argc != 6)
		MGSys::ShowErrorAndExit(LOCADR(), "Number of argument is not conform! Exiting ...");

	std::string event_mode = argv[1];
	std::string file_list = argv[2];
	Long64_t group_id = atol(argv[3]);
	Long64_t group_size = atol(argv[4]);

	std::use_facet<std::ctype<char> >(std::locale()).toupper(&event_mode[0], &event_mode[0] + event_mode.size());
	if (event_mode == "ISS") EventBase::setEventMode(EventBase::ISS);
	else if (event_mode == "BT") EventBase::setEventMode(EventBase::BT);
	else if (event_mode == "MC") EventBase::setEventMode(EventBase::MC);
	else MGSys::ShowErrorAndExit(LOCADR(), "Can't find event mode (ISS, BT, MC)! Exiting ...");

	std::string outputFile = "";
	if (YiNtuple::checkSelectionMode(YiNtuple::NORM))
		outputFile = STR("YiNtuple_%s.%07ld.root", event_mode.c_str(), group_id);
	else if (YiNtuple::checkSelectionMode(YiNtuple::COPY))
		outputFile = STR("YiMirror_%s.%07ld.root", event_mode.c_str(), group_id);

	std::string path = ".";
	if (argc == 6) path = argv[5];

	bool isMultiTree = false;
	YiNtuple * ntuple = new YiNtuple();
	ntuple->setOutputFile(outputFile, path, isMultiTree);
	ntuple->readDataFrom(file_list, group_id, group_size);
	ntuple->loopEventChain();

	if (ntuple != nullptr) delete ntuple;
	ntuple = nullptr;

	COUT("\n**------------------------**\n");
	COUT("\n**    YiProdNtuple END    **\n");
	COUT("\n**------------------------**\n");
	return 0;
}
#endif // __YiProdNtuple_C__
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <directshoweventloop.h>

#include <QtCore/qcoreapplication.h>
#include <QtCore/qcoreevent.h>

QT_BEGIN_NAMESPACE

class DirectShowPostedEvent
{
public:
    DirectShowPostedEvent(QObject *receiver, QEvent *event)
        : receiver(receiver)
        , event(event)
        , next(0)
    {
    }

    ~DirectShowPostedEvent()
    {
        delete event;
    }

    QObject *receiver;
    QEvent *event;
    DirectShowPostedEvent *next;
};

DirectShowEventLoop::DirectShowEventLoop(QObject *parent)
    : QWinEventNotifier(parent)
    , m_postsHead(0)
    , m_postsTail(0)
    , m_eventHandle(::CreateEvent(0, 0, 0, 0))
    , m_waitHandle(::CreateEvent(0, 0, 0, 0))
{
    setHandle(m_eventHandle);
    setEnabled(true);
}

DirectShowEventLoop::~DirectShowEventLoop()
{
    setEnabled(false);

    ::CloseHandle(m_eventHandle);
    ::CloseHandle(m_waitHandle);

    for (DirectShowPostedEvent *post = m_postsHead; post; post = m_postsHead) {
        m_postsHead = m_postsHead->next;

        delete post;
    }
}

void DirectShowEventLoop::wait(QMutex *mutex)
{
    ::ResetEvent(m_waitHandle);

    mutex->unlock();

    HANDLE handles[] = { m_eventHandle, m_waitHandle };
    while (::WaitForMultipleObjects(2, handles, false, INFINITE) == WAIT_OBJECT_0)
        processEvents();

    mutex->lock();
}

void DirectShowEventLoop::wake()
{
    ::SetEvent(m_waitHandle);
}

void DirectShowEventLoop::postEvent(QObject *receiver, QEvent *event)
{
    QMutexLocker locker(&m_mutex);

    DirectShowPostedEvent *post = new DirectShowPostedEvent(receiver, event);

    if (m_postsTail)
        m_postsTail->next = post;
    else
        m_postsHead = post;

    m_postsTail = post;

    ::SetEvent(m_eventHandle);
}

bool DirectShowEventLoop::event(QEvent *event)
{
    if (event->type() == QEvent::WinEventAct) {
        processEvents();

        return true;
    } else {
        return QWinEventNotifier::event(event);
    }
}

void DirectShowEventLoop::processEvents()
{
    QMutexLocker locker(&m_mutex);

    while(m_postsHead) {
        ::ResetEvent(m_eventHandle);

        DirectShowPostedEvent *post = m_postsHead;
        m_postsHead = m_postsHead->next;

        locker.unlock();
        QCoreApplication::sendEvent(post->receiver, post->event);
        delete post;
        locker.relock();
    }

    m_postsTail = 0;
}

QT_END_NAMESPACE
<commit_msg>Fix corruption of Direct Show event queue.<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <directshoweventloop.h>

#include <QtCore/qcoreapplication.h>
#include <QtCore/qcoreevent.h>

QT_BEGIN_NAMESPACE

class DirectShowPostedEvent
{
public:
    DirectShowPostedEvent(QObject *receiver, QEvent *event)
        : receiver(receiver)
        , event(event)
        , next(0)
    {
    }

    ~DirectShowPostedEvent()
    {
        delete event;
    }

    QObject *receiver;
    QEvent *event;
    DirectShowPostedEvent *next;
};

DirectShowEventLoop::DirectShowEventLoop(QObject *parent)
    : QWinEventNotifier(parent)
    , m_postsHead(0)
    , m_postsTail(0)
    , m_eventHandle(::CreateEvent(0, 0, 0, 0))
    , m_waitHandle(::CreateEvent(0, 0, 0, 0))
{
    setHandle(m_eventHandle);
    setEnabled(true);
}

DirectShowEventLoop::~DirectShowEventLoop()
{
    setEnabled(false);

    ::CloseHandle(m_eventHandle);
    ::CloseHandle(m_waitHandle);

    for (DirectShowPostedEvent *post = m_postsHead; post; post = m_postsHead) {
        m_postsHead = m_postsHead->next;

        delete post;
    }
}

void DirectShowEventLoop::wait(QMutex *mutex)
{
    ::ResetEvent(m_waitHandle);

    mutex->unlock();

    HANDLE handles[] = { m_eventHandle, m_waitHandle };
    while (::WaitForMultipleObjects(2, handles, false, INFINITE) == WAIT_OBJECT_0)
        processEvents();

    mutex->lock();
}

void DirectShowEventLoop::wake()
{
    ::SetEvent(m_waitHandle);
}

void DirectShowEventLoop::postEvent(QObject *receiver, QEvent *event)
{
    QMutexLocker locker(&m_mutex);

    DirectShowPostedEvent *post = new DirectShowPostedEvent(receiver, event);

    if (m_postsTail)
        m_postsTail->next = post;
    else
        m_postsHead = post;

    m_postsTail = post;

    ::SetEvent(m_eventHandle);
}

bool DirectShowEventLoop::event(QEvent *event)
{
    if (event->type() == QEvent::WinEventAct) {
        processEvents();

        return true;
    } else {
        return QWinEventNotifier::event(event);
    }
}

void DirectShowEventLoop::processEvents()
{
    QMutexLocker locker(&m_mutex);

    while(m_postsHead) {
        ::ResetEvent(m_eventHandle);

        DirectShowPostedEvent *post = m_postsHead;
        m_postsHead = m_postsHead->next;

        if (!m_postsHead)
            m_postsTail = 0;

        locker.unlock();
        QCoreApplication::sendEvent(post->receiver, post->event);
        delete post;
        locker.relock();
    }
}

QT_END_NAMESPACE
<|endoftext|>


<commit_before>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#pragma once

#include "core/CompileConfig.h"

#if OUZEL_SUPPORTS_DIRECTSOUND

#include <thread>

#include <dsound.h>
#include "audio/AudioDevice.hpp"

namespace ouzel
{
    namespace audio
    {
        class AudioDeviceDS: public AudioDevice
        {
            friend Audio;
        public:
            virtual ~AudioDeviceDS();

            virtual bool update() override;

            IDirectSound8* getDirectSound() const { return directSound; }

        protected:
            AudioDeviceDS();
            virtual bool init(bool debugAudio) override;

            void run();

            IDirectSound8* directSound = nullptr;

            IDirectSoundBuffer* primaryBuffer = nullptr;
            IDirectSoundBuffer8* buffer = nullptr;

            uint32_t nextBuffer = 0;

            bool running = true;

            std::vector<uint8_t> data;

#if OUZEL_MULTITHREADED
            std::thread audioThread;
#endif
        };
    } // namespace audio
} // namespace ouzel

#endif
<commit_msg>Remove the declaration of update()<commit_after>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#pragma once

#include "core/CompileConfig.h"

#if OUZEL_SUPPORTS_DIRECTSOUND

#include <thread>

#include <dsound.h>
#include "audio/AudioDevice.hpp"

namespace ouzel
{
    namespace audio
    {
        class AudioDeviceDS: public AudioDevice
        {
            friend Audio;
        public:
            virtual ~AudioDeviceDS();

            IDirectSound8* getDirectSound() const { return directSound; }

        protected:
            AudioDeviceDS();
            virtual bool init(bool debugAudio) override;

            void run();

            IDirectSound8* directSound = nullptr;

            IDirectSoundBuffer* primaryBuffer = nullptr;
            IDirectSoundBuffer8* buffer = nullptr;

            uint32_t nextBuffer = 0;

            bool running = true;

            std::vector<uint8_t> data;

#if OUZEL_MULTITHREADED
            std::thread audioThread;
#endif
        };
    } // namespace audio
} // namespace ouzel

#endif
<|endoftext|>


<commit_before>/*
* (C) 2015 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include "tests.h"

#if defined(BOTAN_HAS_COMPRESSION)
   #include <botan/compression.h>
#endif

namespace Botan_Tests {

#if defined(BOTAN_HAS_COMPRESSION)

namespace {

const char* text_str =
   "'Twas brillig, and the slithy toves"
   "Did gyre and gimble in the wabe:"
   "All mimsy were the borogoves,"
   "And the mome raths outgrabe."

   "'Beware the Jabberwock, my son!"
   "The jaws that bite, the claws that catch!"
   "Beware the Jubjub bird, and shun"
   "The frumious Bandersnatch!'"

   "He took his vorpal sword in hand;"
   "Long time the manxome foe he sought-"
   "So rested he by the Tumtum tree"
   "And stood awhile in thought."

   "And, as in uffish thought he stood,"
   "The Jabberwock, with eyes of flame,"
   "Came whiffling through the tulgey wood,"
   "And burbled as it came!"

   "One, two! One, two! And through and through"
   "The vorpal blade went snicker-snack!"
   "He left it dead, and with its head"
   "He went galumphing back."

   "'And hast thou slain the Jabberwock?"
   "Come to my arms, my beamish boy!"
   "O frabjous day! Callooh! Callay!'"
   "He chortled in his joy."

   "'Twas brillig, and the slithy toves"
   "Did gyre and gimble in the wabe:"
   "All mimsy were the borogoves,"
   "And the mome raths outgrabe.";

class Compression_Tests final : public Test
   {
   public:
      std::vector<Test::Result> run() override
         {
         std::vector<Test::Result> results;
         const size_t text_len = std::strlen(text_str);

         for(std::string algo : { "zlib", "deflate", "gzip", "bz2", "lzma" })
            {
            try
               {
               Test::Result result(algo + " compression");

               std::unique_ptr<Botan::Compression_Algorithm> c(Botan::make_compressor(algo));
               std::unique_ptr<Botan::Decompression_Algorithm> d(Botan::make_decompressor(algo));

               if(!c || !d)
                  {
                  result.note_missing(algo);
                  continue;
                  }

               result.test_ne("Not the same name", c->name(), d->name());

               const Botan::secure_vector<uint8_t> empty;
               const Botan::secure_vector<uint8_t> all_zeros(text_len, 0);
               const Botan::secure_vector<uint8_t> random_binary = Test::rng().random_vec(text_len);
               const Botan::secure_vector<uint8_t> short_text = { 'f', 'o', 'o', '\n' };

               const uint8_t* textb = reinterpret_cast<const uint8_t*>(text_str);
               const Botan::secure_vector<uint8_t> text(textb, textb + text_len);

               const size_t c1_e = run_compression(result, 1, *c, *d, empty);
               const size_t c9_e = run_compression(result, 9, *c, *d, empty);
               const size_t c1_z = run_compression(result, 1, *c, *d, all_zeros);
               const size_t c9_z = run_compression(result, 9, *c, *d, all_zeros);
               const size_t c1_r = run_compression(result, 1, *c, *d, random_binary);
               const size_t c9_r = run_compression(result, 9, *c, *d, random_binary);
               const size_t c1_t = run_compression(result, 1, *c, *d, text);
               const size_t c9_t = run_compression(result, 9, *c, *d, text);
               const size_t c1_s = run_compression(result, 1, *c, *d, short_text);
               const size_t c9_s = run_compression(result, 9, *c, *d, short_text);

               result.test_gte("Empty input L1 compresses to non-empty output", c1_e, 1);
               result.test_gte("Empty input L9 compresses to non-empty output", c9_e, 1);

               result.test_gte("Level 9 compresses empty at least as well as level 1", c1_e, c9_e);
               result.test_gte("Level 9 compresses zeros at least as well as level 1", c1_z, c9_z);
               result.test_gte("Level 9 compresses random at least as well as level 1", c1_r, c9_r);
               result.test_gte("Level 9 compresses text at least as well as level 1", c1_t, c9_t);
               result.test_gte("Level 9 compresses short text at least as well as level 1", c1_s, c9_s);

               result.test_lt("Zeros compresses much better than text", c1_z / 8, c1_t);
               result.test_lt("Text compresses much better than random", c1_t / 2, c1_r);

               results.emplace_back(result);
               }
            catch(std::exception& e)
               {
               results.emplace_back(Test::Result::Failure("testing " + algo, e.what()));
               }
            }

         return results;
         }

   private:

      // Returns # of bytes of compressed message
      size_t run_compression(Test::Result& result,
                             size_t level,
                             Botan::Compression_Algorithm& c,
                             Botan::Decompression_Algorithm& d,
                             const Botan::secure_vector<uint8_t>& msg)
         {
         Botan::secure_vector<uint8_t> compressed(2*msg.size());

         for(bool with_flush : { true, false })
            {
            try
               {
               compressed = msg;

               c.start(level);
               c.update(compressed, 0, false);

               if(with_flush)
                  {
                  Botan::secure_vector<uint8_t> flush_bits;
                  c.update(flush_bits, 0, true);
                  compressed += flush_bits;
                  }

               Botan::secure_vector<uint8_t> final_bits;
               c.finish(final_bits);
               compressed += final_bits;

               Botan::secure_vector<uint8_t> decompressed = compressed;
               d.start();
               d.update(decompressed);

               Botan::secure_vector<uint8_t> final_outputs;
               d.finish(final_outputs);

               decompressed += final_outputs;

               result.test_eq("compression round tripped", msg, decompressed);
               }
            catch(Botan::Exception& e)
               {
               result.test_failure(e.what());
               }
            }

         return compressed.size();
         }
   };

BOTAN_REGISTER_TEST("compression", "compression", Compression_Tests);

class CompressionCreate_Tests final : public Test
   {
   public:
      std::vector<Test::Result> run() override
         {
         std::vector<Test::Result> results;

         for(std::string algo : { "zlib", "deflate", "gzip", "bz2", "lzma" })
            {
            try
               {
               Test::Result result(algo + " create compression");

               std::unique_ptr<Botan::Compression_Algorithm> c1(Botan::Compression_Algorithm::create(algo));
               std::unique_ptr<Botan::Decompression_Algorithm> d1(Botan::Decompression_Algorithm::create(algo));

               if(!c1 || !d1)
                  {
                  result.note_missing(algo);
                  continue;
                  }
               result.test_ne("Not the same name after create", c1->name(), d1->name());

               std::unique_ptr<Botan::Compression_Algorithm> c2(Botan::Compression_Algorithm::create_or_throw(algo));
               std::unique_ptr<Botan::Decompression_Algorithm> d2(Botan::Decompression_Algorithm::create_or_throw(algo));

               if(!c2 || !d2)
                  {
                  result.note_missing(algo);
                  continue;
                  }
               result.test_ne("Not the same name after create_or_throw", c2->name(), d2->name());

               results.emplace_back(result);
               }
            catch(std::exception& e)
               {
               results.emplace_back(Test::Result::Failure("testing " + algo, e.what()));
               }
            }

            {
            Test::Result result("create invalid compression");
            result.test_throws("lookup error",
                               "Unavailable Compression bogocompress",
                               [&]() { Botan::Compression_Algorithm::create_or_throw("bogocompress"); });
            result.test_throws("lookup error",
                               "Unavailable Decompression bogocompress",
                               [&]() { Botan::Decompression_Algorithm::create_or_throw("bogocompress"); });
            results.emplace_back(result);
            }

         return results;
         }
   };

BOTAN_REGISTER_TEST("compression", "create_compression", CompressionCreate_Tests);

}

#endif

}
<commit_msg>Time compression tests<commit_after>/*
* (C) 2015 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include "tests.h"

#if defined(BOTAN_HAS_COMPRESSION)
   #include <botan/compression.h>
#endif

namespace Botan_Tests {

#if defined(BOTAN_HAS_COMPRESSION)

namespace {

const char* text_str =
   "'Twas brillig, and the slithy toves"
   "Did gyre and gimble in the wabe:"
   "All mimsy were the borogoves,"
   "And the mome raths outgrabe."

   "'Beware the Jabberwock, my son!"
   "The jaws that bite, the claws that catch!"
   "Beware the Jubjub bird, and shun"
   "The frumious Bandersnatch!'"

   "He took his vorpal sword in hand;"
   "Long time the manxome foe he sought-"
   "So rested he by the Tumtum tree"
   "And stood awhile in thought."

   "And, as in uffish thought he stood,"
   "The Jabberwock, with eyes of flame,"
   "Came whiffling through the tulgey wood,"
   "And burbled as it came!"

   "One, two! One, two! And through and through"
   "The vorpal blade went snicker-snack!"
   "He left it dead, and with its head"
   "He went galumphing back."

   "'And hast thou slain the Jabberwock?"
   "Come to my arms, my beamish boy!"
   "O frabjous day! Callooh! Callay!'"
   "He chortled in his joy."

   "'Twas brillig, and the slithy toves"
   "Did gyre and gimble in the wabe:"
   "All mimsy were the borogoves,"
   "And the mome raths outgrabe.";

class Compression_Tests final : public Test
   {
   public:
      std::vector<Test::Result> run() override
         {
         std::vector<Test::Result> results;
         const size_t text_len = std::strlen(text_str);

         for(std::string algo : { "zlib", "deflate", "gzip", "bz2", "lzma" })
            {
            try
               {
               Test::Result result(algo + " compression");

               result.start_timer();

               std::unique_ptr<Botan::Compression_Algorithm> c(Botan::make_compressor(algo));
               std::unique_ptr<Botan::Decompression_Algorithm> d(Botan::make_decompressor(algo));

               if(!c || !d)
                  {
                  result.note_missing(algo);
                  continue;
                  }

               result.test_ne("Not the same name", c->name(), d->name());

               const Botan::secure_vector<uint8_t> empty;
               const Botan::secure_vector<uint8_t> all_zeros(text_len, 0);
               const Botan::secure_vector<uint8_t> random_binary = Test::rng().random_vec(text_len);
               const Botan::secure_vector<uint8_t> short_text = { 'f', 'o', 'o', '\n' };

               const uint8_t* textb = reinterpret_cast<const uint8_t*>(text_str);
               const Botan::secure_vector<uint8_t> text(textb, textb + text_len);

               const size_t c1_e = run_compression(result, 1, *c, *d, empty);
               const size_t c9_e = run_compression(result, 9, *c, *d, empty);
               const size_t c1_z = run_compression(result, 1, *c, *d, all_zeros);
               const size_t c9_z = run_compression(result, 9, *c, *d, all_zeros);
               const size_t c1_r = run_compression(result, 1, *c, *d, random_binary);
               const size_t c9_r = run_compression(result, 9, *c, *d, random_binary);
               const size_t c1_t = run_compression(result, 1, *c, *d, text);
               const size_t c9_t = run_compression(result, 9, *c, *d, text);
               const size_t c1_s = run_compression(result, 1, *c, *d, short_text);
               const size_t c9_s = run_compression(result, 9, *c, *d, short_text);

               result.test_gte("Empty input L1 compresses to non-empty output", c1_e, 1);
               result.test_gte("Empty input L9 compresses to non-empty output", c9_e, 1);

               result.test_gte("Level 9 compresses empty at least as well as level 1", c1_e, c9_e);
               result.test_gte("Level 9 compresses zeros at least as well as level 1", c1_z, c9_z);
               result.test_gte("Level 9 compresses random at least as well as level 1", c1_r, c9_r);
               result.test_gte("Level 9 compresses text at least as well as level 1", c1_t, c9_t);
               result.test_gte("Level 9 compresses short text at least as well as level 1", c1_s, c9_s);

               result.test_lt("Zeros compresses much better than text", c1_z / 8, c1_t);
               result.test_lt("Text compresses much better than random", c1_t / 2, c1_r);

               result.end_timer();

               results.emplace_back(result);
               }
            catch(std::exception& e)
               {
               results.emplace_back(Test::Result::Failure("testing " + algo, e.what()));
               }
            }

         return results;
         }

   private:

      // Returns # of bytes of compressed message
      size_t run_compression(Test::Result& result,
                             size_t level,
                             Botan::Compression_Algorithm& c,
                             Botan::Decompression_Algorithm& d,
                             const Botan::secure_vector<uint8_t>& msg)
         {
         Botan::secure_vector<uint8_t> compressed(2*msg.size());

         for(bool with_flush : { true, false })
            {
            try
               {
               compressed = msg;

               c.start(level);
               c.update(compressed, 0, false);

               if(with_flush)
                  {
                  Botan::secure_vector<uint8_t> flush_bits;
                  c.update(flush_bits, 0, true);
                  compressed += flush_bits;
                  }

               Botan::secure_vector<uint8_t> final_bits;
               c.finish(final_bits);
               compressed += final_bits;

               Botan::secure_vector<uint8_t> decompressed = compressed;
               d.start();
               d.update(decompressed);

               Botan::secure_vector<uint8_t> final_outputs;
               d.finish(final_outputs);

               decompressed += final_outputs;

               result.test_eq("compression round tripped", msg, decompressed);
               }
            catch(Botan::Exception& e)
               {
               result.test_failure(e.what());
               }
            }

         return compressed.size();
         }
   };

BOTAN_REGISTER_TEST("compression", "compression", Compression_Tests);

class CompressionCreate_Tests final : public Test
   {
   public:
      std::vector<Test::Result> run() override
         {
         std::vector<Test::Result> results;

         for(std::string algo : { "zlib", "deflate", "gzip", "bz2", "lzma" })
            {
            try
               {
               Test::Result result(algo + " create compression");

               std::unique_ptr<Botan::Compression_Algorithm> c1(Botan::Compression_Algorithm::create(algo));
               std::unique_ptr<Botan::Decompression_Algorithm> d1(Botan::Decompression_Algorithm::create(algo));

               if(!c1 || !d1)
                  {
                  result.note_missing(algo);
                  continue;
                  }
               result.test_ne("Not the same name after create", c1->name(), d1->name());

               std::unique_ptr<Botan::Compression_Algorithm> c2(Botan::Compression_Algorithm::create_or_throw(algo));
               std::unique_ptr<Botan::Decompression_Algorithm> d2(Botan::Decompression_Algorithm::create_or_throw(algo));

               if(!c2 || !d2)
                  {
                  result.note_missing(algo);
                  continue;
                  }
               result.test_ne("Not the same name after create_or_throw", c2->name(), d2->name());

               results.emplace_back(result);
               }
            catch(std::exception& e)
               {
               results.emplace_back(Test::Result::Failure("testing " + algo, e.what()));
               }
            }

            {
            Test::Result result("create invalid compression");
            result.test_throws("lookup error",
                               "Unavailable Compression bogocompress",
                               [&]() { Botan::Compression_Algorithm::create_or_throw("bogocompress"); });
            result.test_throws("lookup error",
                               "Unavailable Decompression bogocompress",
                               [&]() { Botan::Decompression_Algorithm::create_or_throw("bogocompress"); });
            results.emplace_back(result);
            }

         return results;
         }
   };

BOTAN_REGISTER_TEST("compression", "create_compression", CompressionCreate_Tests);

}

#endif

}
<|endoftext|>


<commit_before>/*
 * header.cpp
 *
 *  Created on: Aug 24, 2015
 *      Author: zmij
 */

#include <tip/http/common/header.hpp>
#include <boost/spirit/include/qi.hpp>
#include <tip/http/common/grammar/header_generate.hpp>

namespace tip {
namespace http {

std::ostream&
operator << (std::ostream& out, header const& val)
{
	namespace karma = boost::spirit::karma;
	typedef std::ostream_iterator<char> output_iterator;
	typedef grammar::gen::header_grammar<output_iterator> header_grammar;
	std::ostream::sentry s(out);
	if (s) {
		output_iterator oi(out);
		karma::generate(oi, header_grammar(), val);
	}
	return out;
}

std::ostream&
operator << (std::ostream& out, headers const& val)
{
	namespace karma = boost::spirit::karma;
	typedef std::ostream_iterator<char> output_iterator;
	typedef grammar::gen::headers_grammar<output_iterator> headers_grammar;
	std::ostream::sentry s(out);
	if (s) {
		output_iterator oi(out);
		karma::generate(oi, headers_grammar(), val);
	}
	return out;
}

size_t
content_length(headers const& hdrs)
{
	namespace qi = boost::spirit::qi;
	typedef std::string::const_iterator string_iterator;
	auto p = hdrs.find(ContentLength);
	if (p != hdrs.end()) {
		string_iterator f = p->second.begin();
		string_iterator l = p->second.end();
		size_t res;
		if (qi::parse(f, l, qi::int_parser<size_t, 10>(), res) && f == l)
			return res;
		else
			throw std::runtime_error("Invalid Content-Length header");
	}
	return 0;
}

bool
chunked_transfer_encoding(headers const& hdrs)
{
	typedef std::string::const_iterator string_iterator;
	auto p = hdrs.find(TransferEncoding);
	if (p != hdrs.end()) {
		return p->second == "chunked";
	}
	return false;
}
}  // namespace http
}  // namespace tip
<commit_msg>Pedantic code cleanup<commit_after>/*
 * header.cpp
 *
 *  Created on: Aug 24, 2015
 *      Author: zmij
 */

#include <tip/http/common/header.hpp>
#include <boost/spirit/include/qi.hpp>
#include <tip/http/common/grammar/header_generate.hpp>

namespace tip {
namespace http {

std::ostream&
operator << (std::ostream& out, header const& val)
{
	namespace karma = boost::spirit::karma;
	typedef std::ostream_iterator<char> output_iterator;
	typedef grammar::gen::header_grammar<output_iterator> header_grammar;
	std::ostream::sentry s(out);
	if (s) {
		output_iterator oi(out);
		karma::generate(oi, header_grammar(), val);
	}
	return out;
}

std::ostream&
operator << (std::ostream& out, headers const& val)
{
	namespace karma = boost::spirit::karma;
	typedef std::ostream_iterator<char> output_iterator;
	typedef grammar::gen::headers_grammar<output_iterator> headers_grammar;
	std::ostream::sentry s(out);
	if (s) {
		output_iterator oi(out);
		karma::generate(oi, headers_grammar(), val);
	}
	return out;
}

size_t
content_length(headers const& hdrs)
{
	namespace qi = boost::spirit::qi;
	typedef std::string::const_iterator string_iterator;
	auto p = hdrs.find(ContentLength);
	if (p != hdrs.end()) {
		string_iterator f = p->second.begin();
		string_iterator l = p->second.end();
		size_t res;
		if (qi::parse(f, l, qi::int_parser<size_t, 10>(), res) && f == l)
			return res;
		else
			throw std::runtime_error("Invalid Content-Length header");
	}
	return 0;
}

bool
chunked_transfer_encoding(headers const& hdrs)
{
	auto p = hdrs.find(TransferEncoding);
	if (p != hdrs.end()) {
		return p->second == "chunked";
	}
	return false;
}
}  // namespace http
}  // namespace tip
<|endoftext|>