<commit_before>// ------------------------------------------------------------------------
// midiio-aseq.cpp: Input and output of MIDI streams using
//                  ALSA Sequencer
// Copyright (C) 2005 Pedro Lopez-Cabanillas
// Copyright (C) 2005 Kai Vehmanen
//
// Attributes:
//     eca-style-version: 3
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
// ------------------------------------------------------------------------

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef ECA_COMPILE_ALSA

#include <cstdio>
#include <fcntl.h>
#include <unistd.h>
#include "midiio-aseq.h"

#include "eca-logger.h"

MIDI_IO_ASEQ::MIDI_IO_ASEQ(const std::string& name) { label("alsaseq"); device_name_rep = name; }

MIDI_IO_ASEQ::~MIDI_IO_ASEQ(void) { if (is_open()) close(); }

void MIDI_IO_ASEQ::open(void)
{
  int open_flags = 0, port_flags = 0;

  switch(io_mode()) {
  case io_read:
    {
      open_flags = SND_SEQ_OPEN_INPUT;
      port_flags = SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE;
      break;
    }
  case io_write:
    {
      open_flags = SND_SEQ_OPEN_OUTPUT;
      port_flags = SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ;
      break;
    }
  case io_readwrite:
    {
      open_flags = SND_SEQ_OPEN_DUPLEX;
      port_flags = SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE |
                   SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ;
      break;
    }
  }

  ECA_LOG_MSG(ECA_LOGGER::system_objects, "Opening ALSA sequencer");
  int err = snd_seq_open(&seq_handle_repp, "default", open_flags, SND_SEQ_NONBLOCK);
  if (err < 0) {
    toggle_open_state(false);
  }
  else {
    toggle_open_state(true);
  }

  // Set client name.
  snd_seq_set_client_name(seq_handle_repp, "ecasound");
  // Create a simple port
  port_rep = snd_seq_create_simple_port( seq_handle_repp, "ecasound",
                                         port_flags,
                                         SND_SEQ_PORT_TYPE_MIDI_GENERIC);
  // Parse the device name, and connect it to the port when successful
  snd_seq_addr_t subs;
  err = snd_seq_parse_address(seq_handle_repp, &subs, device_name_rep.c_str());
  if( err == 0) {
    switch(io_mode()) {
    case io_read:
      snd_seq_connect_to(seq_handle_repp, port_rep, subs.client, subs.port);
      break;
    case io_write:
      snd_seq_connect_from(seq_handle_repp, port_rep, subs.client, subs.port);
      break;
    case io_readwrite:
      snd_seq_connect_to(seq_handle_repp, port_rep, subs.client, subs.port);
      snd_seq_connect_from(seq_handle_repp, port_rep, subs.client, subs.port);
      break;
    }
  }
  // Create the encoder/decoder instance
  err = snd_midi_event_new( buffer_size_rep = 16, &coder_repp );
  // ...
  finished_rep = false;
}

void MIDI_IO_ASEQ::close(void)
{
  // Release the xxcoder instance
  snd_midi_event_free( coder_repp );
  // Delete the port
  snd_seq_delete_port( seq_handle_repp, port_rep );
  // Close the sequencer client
  snd_seq_close( seq_handle_repp );
  toggle_open_state(false);
}

int MIDI_IO_ASEQ::poll_descriptor(void) const
{
  struct pollfd *pfds;
  int npfds;
  npfds = snd_seq_poll_descriptors_count(seq_handle_repp, POLLIN|POLLOUT);
  pfds = reinterpret_cast<struct pollfd*>(alloca(sizeof(*pfds) * npfds));
  snd_seq_poll_descriptors(seq_handle_repp, pfds, npfds, POLLIN|POLLOUT);
  return pfds->fd;
}

bool MIDI_IO_ASEQ::finished(void) const { return finished_rep; }

long int MIDI_IO_ASEQ::read_bytes(void* target_buffer, long int bytes)
{
  snd_seq_event_t *event;
  int err = 0, position = 0;
  if ( bytes > buffer_size_rep ) {
     snd_midi_event_resize_buffer ( coder_repp, bytes );
     buffer_size_rep = bytes;
  }
  while (true) {
    if (snd_seq_event_input_pending(seq_handle_repp, 1) == 0) {
    	return position;
    }
    err = snd_seq_event_input(seq_handle_repp, &event);
    if (err < 0) {
    	break;
    }
    if ( event->type == SND_SEQ_EVENT_CONTROLLER ||
         event->type == SND_SEQ_EVENT_CONTROL14 ||
         event->type == SND_SEQ_EVENT_NONREGPARAM ||
         event->type == SND_SEQ_EVENT_REGPARAM ||
         event->type == SND_SEQ_EVENT_SYSEX ) {
      err = snd_midi_event_decode( coder_repp,
                                   ((unsigned char *)target_buffer) + position,
                                   bytes - position,
                                   event );
      if (err < 0) {
      	break;
      }
      position += err;
      if ( position >= bytes) return position;
    }
  }
  finished_rep = true;
  return err;
}

long int MIDI_IO_ASEQ::write_bytes(void* target_buffer, long int bytes) {
  snd_seq_event_t ev;
  int err = 0;
  if ( bytes > buffer_size_rep ) {
     snd_midi_event_resize_buffer ( coder_repp, bytes );
     buffer_size_rep = bytes;
  }
  snd_seq_ev_clear(&ev);
  snd_seq_ev_set_source(&ev, port_rep);
  snd_seq_ev_set_subs(&ev);
  snd_seq_ev_set_direct(&ev);
  err = snd_midi_event_encode( coder_repp,
                    	       (unsigned char *)target_buffer,
                               bytes, &ev );
  if (err == bytes) {
     snd_seq_event_output(seq_handle_repp, &ev);
     snd_seq_drain_output(seq_handle_repp);
     return err;
  }
  finished_rep = true;
  return err;
}

void MIDI_IO_ASEQ::set_parameter(int param,
				std::string value)
{
  switch (param) {
  case 1:
    label(value);
    break;

  case 2:
    device_name_rep = value;
    break;
  }
}

std::string MIDI_IO_ASEQ::get_parameter(int param) const
{
  switch (param) {
  case 1:
    return label();

  case 2:
    return device_name_rep;
  }
  return "";
}

/**
 * FIXME: This is an alternative to using the poll_descriptor()
 *        interface...
 */
bool MIDI_IO_ASEQ::pending_messages(unsigned long timeout) const
{
  struct pollfd *pfds;
  int result = 0;
  int npfds = snd_seq_poll_descriptors_count(seq_handle_repp, POLLIN);
  pfds = (struct pollfd *)alloca(sizeof(*pfds) * npfds);
  snd_seq_poll_descriptors(seq_handle_repp, pfds, npfds, POLLIN);
  result = poll(pfds, npfds, timeout);
  return (result > 0);
}

#endif /* COMPILE_ALSA */
<commit_msg>Better error reporting.<commit_after>// ------------------------------------------------------------------------
// midiio-aseq.cpp: Input and output of MIDI streams using
//                  ALSA Sequencer
// Copyright (C) 2005 Pedro Lopez-Cabanillas
// Copyright (C) 2005 Kai Vehmanen
//
// Attributes:
//     eca-style-version: 3
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
// ------------------------------------------------------------------------

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef ECA_COMPILE_ALSA

#include <cstdio>
#include <fcntl.h>
#include <unistd.h>

#include "midiio-aseq.h"
#include "eca-logger.h"

MIDI_IO_ASEQ::MIDI_IO_ASEQ(const std::string& name) { label("alsaseq"); device_name_rep = name; }

MIDI_IO_ASEQ::~MIDI_IO_ASEQ(void) { if (is_open()) close(); }

void MIDI_IO_ASEQ::open(void)
{
  int open_flags = 0, port_flags = 0;

  switch(io_mode()) {
  case io_read:
    {
      open_flags = SND_SEQ_OPEN_INPUT;
      port_flags = SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE;
      break;
    }
  case io_write:
    {
      open_flags = SND_SEQ_OPEN_OUTPUT;
      port_flags = SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ;
      break;
    }
  case io_readwrite:
    {
      open_flags = SND_SEQ_OPEN_DUPLEX;
      port_flags = SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE |
                   SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ;
      break;
    }
  }

  ECA_LOG_MSG(ECA_LOGGER::system_objects, "Opening ALSA sequencer");
  int err = snd_seq_open(&seq_handle_repp, "default", open_flags, SND_SEQ_NONBLOCK);
  if (err < 0) {
    toggle_open_state(false);
  }
  else {
    toggle_open_state(true);
  }

  // Set client name.
  snd_seq_set_client_name(seq_handle_repp, "ecasound");
  // Create a simple port
  port_rep = snd_seq_create_simple_port( seq_handle_repp, "ecasound",
                                         port_flags,
                                         SND_SEQ_PORT_TYPE_MIDI_GENERIC);
  // Parse the device name, and connect it to the port when successful
  snd_seq_addr_t subs;
  err = snd_seq_parse_address(seq_handle_repp, &subs, device_name_rep.c_str());
  if( err == 0) {
    switch(io_mode()) {
    case io_read:
      snd_seq_connect_to(seq_handle_repp, port_rep, subs.client, subs.port);
      break;
    case io_write:
      snd_seq_connect_from(seq_handle_repp, port_rep, subs.client, subs.port);
      break;
    case io_readwrite:
      snd_seq_connect_to(seq_handle_repp, port_rep, subs.client, subs.port);
      snd_seq_connect_from(seq_handle_repp, port_rep, subs.client, subs.port);
      break;
    }
  }
  // Create the encoder/decoder instance
  err = snd_midi_event_new( buffer_size_rep = 16, &coder_repp );
  // ...
  finished_rep = false;
}

void MIDI_IO_ASEQ::close(void)
{
  // Release the xxcoder instance
  snd_midi_event_free( coder_repp );
  // Delete the port
  snd_seq_delete_port( seq_handle_repp, port_rep );
  // Close the sequencer client
  snd_seq_close( seq_handle_repp );
  toggle_open_state(false);
}

int MIDI_IO_ASEQ::poll_descriptor(void) const
{
  struct pollfd *pfds;
  int npfds;
  npfds = snd_seq_poll_descriptors_count(seq_handle_repp, POLLIN|POLLOUT);
  pfds = reinterpret_cast<struct pollfd*>(alloca(sizeof(*pfds) * npfds));
  snd_seq_poll_descriptors(seq_handle_repp, pfds, npfds, POLLIN|POLLOUT);
  return pfds->fd;
}

bool MIDI_IO_ASEQ::finished(void) const { return finished_rep; }

long int MIDI_IO_ASEQ::read_bytes(void* target_buffer, long int bytes)
{
  snd_seq_event_t *event;
  int err = 0, position = 0;
  if ( bytes > buffer_size_rep ) {
     snd_midi_event_resize_buffer ( coder_repp, bytes );
     buffer_size_rep = bytes;
  }
  while (true) {
    if (snd_seq_event_input_pending(seq_handle_repp, 1) == 0) {
    	return position;
    }
    err = snd_seq_event_input(seq_handle_repp, &event);
    if (err < 0) {
    	break;
    }
    if ( event->type == SND_SEQ_EVENT_CONTROLLER ||
         event->type == SND_SEQ_EVENT_CONTROL14 ||
         event->type == SND_SEQ_EVENT_NONREGPARAM ||
         event->type == SND_SEQ_EVENT_REGPARAM ||
         event->type == SND_SEQ_EVENT_SYSEX ) {
      err = snd_midi_event_decode( coder_repp,
                                   ((unsigned char *)target_buffer) + position,
                                   bytes - position,
                                   event );
      if (err < 0) {
      	break;
      }
      position += err;
      if ( position >= bytes) return position;
    }
  }
  finished_rep = true;
  ECA_LOG_MSG(ECA_LOGGER::system_objects,
	      std::string("error while reading from ALSA sequencer: ") + snd_strerror(err));
  return err;
}

long int MIDI_IO_ASEQ::write_bytes(void* target_buffer, long int bytes) {
  snd_seq_event_t ev;
  int err = 0;
  if ( bytes > buffer_size_rep ) {
     snd_midi_event_resize_buffer ( coder_repp, bytes );
     buffer_size_rep = bytes;
  }
  snd_seq_ev_clear(&ev);
  snd_seq_ev_set_source(&ev, port_rep);
  snd_seq_ev_set_subs(&ev);
  snd_seq_ev_set_direct(&ev);
  err = snd_midi_event_encode( coder_repp,
                    	       (unsigned char *)target_buffer,
                               bytes, &ev );
  if (err == bytes) {
     snd_seq_event_output(seq_handle_repp, &ev);
     snd_seq_drain_output(seq_handle_repp);
     return err;
  }
  finished_rep = true;
  return err;
}

void MIDI_IO_ASEQ::set_parameter(int param,
				std::string value)
{
  switch (param) {
  case 1:
    label(value);
    break;

  case 2:
    device_name_rep = value;
    break;
  }
}

std::string MIDI_IO_ASEQ::get_parameter(int param) const
{
  switch (param) {
  case 1:
    return label();

  case 2:
    return device_name_rep;
  }
  return "";
}

/**
 * FIXME: This is an alternative to using the poll_descriptor()
 *        interface...
 */
bool MIDI_IO_ASEQ::pending_messages(unsigned long timeout) const
{
  struct pollfd *pfds;
  int result = 0;
  int npfds = snd_seq_poll_descriptors_count(seq_handle_repp, POLLIN);
  pfds = (struct pollfd *)alloca(sizeof(*pfds) * npfds);
  snd_seq_poll_descriptors(seq_handle_repp, pfds, npfds, POLLIN);
  result = poll(pfds, npfds, timeout);
  return (result > 0);
}

#endif /* COMPILE_ALSA */
<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Precompiled.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 */

#include "Precompiled.h"

#include <libdevcore/Log.h>
#include <libdevcore/SHA3.h>
#include <libdevcore/Hash.h>
#include <libdevcrypto/Common.h>
#include <libethcore/Common.h>
#include <libevmcore/Params.h>
using namespace std;
using namespace dev;
using namespace dev::eth;

namespace
{

void ecrecoverCode(bytesConstRef _in, bytesRef _out)
{
	struct inType
	{
		h256 hash;
		h256 v;
		h256 r;
		h256 s;
	} in;

	memcpy(&in, _in.data(), min(_in.size(), sizeof(in)));

	h256 ret;
	if ((u256)in.v <= 28)
	{
		SignatureStruct sig(in.r, in.s, (byte)((int)(u256)in.v - 27));
		if (sig.isValid())
		{
			try
			{
				ret = sha3(recover(sig, in.hash));
			}
			catch (...) {}
		}
	}

	memset(ret.data(), 0, 12);
	ret.ref().copyTo(_out);
}

void sha256Code(bytesConstRef _in, bytesRef _out)
{
	sha256(_in).ref().copyTo(_out);
}

void ripemd160Code(bytesConstRef _in, bytesRef _out)
{
	h256(ripemd160(_in), h256::AlignRight).ref().copyTo(_out);
}

void identityCode(bytesConstRef _in, bytesRef _out)
{
	_in.copyTo(_out);
}

}

std::unordered_map<unsigned, PrecompiledAddress> const& dev::eth::precompiled()
{
	static const std::unordered_map<unsigned, PrecompiledAddress> s_precompiled =
	{
		{ 1, { [](bytesConstRef) -> bigint { return c_ecrecoverGas; }, ecrecoverCode }},
		{ 2, { [](bytesConstRef i) -> bigint { return c_sha256Gas + (i.size() + 31) / 32 * c_sha256WordGas; }, sha256Code }},
		{ 3, { [](bytesConstRef i) -> bigint { return c_ripemd160Gas + (i.size() + 31) / 32 * c_ripemd160WordGas; }, ripemd160Code }},
		{ 4, { [](bytesConstRef i) -> bigint { return c_identityGas + (i.size() + 31) / 32 * c_identityWordGas; }, identityCode }}
	};
	return s_precompiled;
}
<commit_msg>Style correction.<commit_after>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Precompiled.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 */

#include "Precompiled.h"

#include <libdevcore/Log.h>
#include <libdevcore/SHA3.h>
#include <libdevcore/Hash.h>
#include <libdevcrypto/Common.h>
#include <libethcore/Common.h>
#include <libevmcore/Params.h>
using namespace std;
using namespace dev;
using namespace dev::eth;

namespace
{

void ecrecoverCode(bytesConstRef _in, bytesRef _out)
{
	struct inType
	{
		h256 hash;
		h256 v;
		h256 r;
		h256 s;
	} in;

	memcpy(&in, _in.data(), min(_in.size(), sizeof(in)));

	h256 ret;
	if ((u256)in.v <= 28)
	{
		SignatureStruct sig(in.r, in.s, (byte)((int)(u256)in.v - 27));
		if (sig.isValid())
		{
			try
			{
				ret = sha3(recover(sig, in.hash));
			}
			catch (...) {}
		}
	}

	memset(ret.data(), 0, 12);
	ret.ref().copyTo(_out);
}

void sha256Code(bytesConstRef _in, bytesRef _out)
{
	sha256(_in).ref().copyTo(_out);
}

void ripemd160Code(bytesConstRef _in, bytesRef _out)
{
	h256(ripemd160(_in), h256::AlignRight).ref().copyTo(_out);
}

void identityCode(bytesConstRef _in, bytesRef _out)
{
	_in.copyTo(_out);
}

}

std::unordered_map<unsigned, PrecompiledAddress> const& dev::eth::precompiled()
{
	static const std::unordered_map<unsigned, PrecompiledAddress> c_precompiled =
	{
		{ 1, { [](bytesConstRef) -> bigint { return c_ecrecoverGas; }, ecrecoverCode }},
		{ 2, { [](bytesConstRef i) -> bigint { return c_sha256Gas + (i.size() + 31) / 32 * c_sha256WordGas; }, sha256Code }},
		{ 3, { [](bytesConstRef i) -> bigint { return c_ripemd160Gas + (i.size() + 31) / 32 * c_ripemd160WordGas; }, ripemd160Code }},
		{ 4, { [](bytesConstRef i) -> bigint { return c_identityGas + (i.size() + 31) / 32 * c_identityWordGas; }, identityCode }}
	};
	return c_precompiled;
}
<|endoftext|>


<commit_before>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Gearmand client and server library.
 *
 *  Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
 *  Copyright (C) 2008 Brian Aker, Eric Day
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *
 *      * Redistributions of source code must retain the above copyright
 *  notice, this list of conditions and the following disclaimer.
 *
 *      * Redistributions in binary form must reproduce the above
 *  copyright notice, this list of conditions and the following disclaimer
 *  in the documentation and/or other materials provided with the
 *  distribution.
 *
 *      * The names of its contributors may not be used to endorse or
 *  promote products derived from this software without specific prior
 *  written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/**
 * @file
 * @brief Server connection definitions
 */

#include "gear_config.h"
#include "libgearman-server/common.h"

#include <libgearman/command.h>

#include <cassert>
#include <cerrno>
#include <cstring>
#include <memory>

#ifndef __INTEL_COMPILER
#pragma GCC diagnostic ignored "-Wold-style-cast"
#endif

/*
 * Public definitions
 */

gearman_server_packet_st *
gearman_server_packet_create(gearman_server_thread_st *thread,
                             bool from_thread)
{
  gearman_server_packet_st *server_packet= NULL;

  if (from_thread && Server->flags.threaded)
  {
    if (thread->free_packet_count > 0)
    {
      server_packet= thread->free_packet_list;
      thread->free_packet_list= server_packet->next;
      thread->free_packet_count--;
    }
  }
  else
  {
    if (Server->free_packet_count > 0)
    {
      server_packet= Server->free_packet_list;
      Server->free_packet_list= server_packet->next;
      Server->free_packet_count--;
    }
  }

  if (server_packet == NULL)
  {
    server_packet= new (std::nothrow) gearman_server_packet_st;
    if (server_packet == NULL)
    {
      gearmand_perror(errno, "new() gearman_server_packet_st");
      return NULL;
    }
  }

  server_packet->next= NULL;

  return server_packet;
}

void destroy_gearman_server_packet_st(gearman_server_packet_st *packet)
{
  delete packet;
}

void gearman_server_packet_free(gearman_server_packet_st *packet,
                                gearman_server_thread_st *thread,
                                bool from_thread)
{
  if (from_thread and Server->flags.threaded)
  {
    if (thread->free_packet_count < GEARMAN_MAX_FREE_SERVER_PACKET)
    {
      packet->next= thread->free_packet_list;
      thread->free_packet_list= packet;
      thread->free_packet_count++;
    }
    else
    {
      gearmand_debug("delete() gearman_server_packet_st");
      delete packet;
    }
  }
  else
  {
    if (Server->free_packet_count < GEARMAN_MAX_FREE_SERVER_PACKET)
    {
      packet->next= Server->free_packet_list;
      Server->free_packet_list= packet;
      Server->free_packet_count++;
    }
    else
    {
      gearmand_debug("delete() gearman_server_packet_st");
      delete packet;
    }
  }
}

gearmand_error_t gearman_server_io_packet_add(gearman_server_con_st *con,
                                              bool take_data,
                                              enum gearman_magic_t magic,
                                              gearman_command_t command,
                                              const void *arg, ...)
{
  gearman_server_packet_st *server_packet;
  va_list ap;

  server_packet= gearman_server_packet_create(con->thread, false);
  if (server_packet == NULL)
  {
    return GEARMAN_MEMORY_ALLOCATION_FAILURE;
  }

  server_packet->packet.reset(magic, command);

  va_start(ap, arg);

  while (arg)
  {
    size_t arg_size= va_arg(ap, size_t);

    gearmand_error_t ret= gearmand_packet_create(&(server_packet->packet), arg, arg_size);
    if (gearmand_failed(ret))
    {
      va_end(ap);
      gearmand_packet_free(&(server_packet->packet));
      gearman_server_packet_free(server_packet, con->thread, false);
      return ret;
    }

    arg= va_arg(ap, void *);
  }

  va_end(ap);

  gearmand_error_t ret= gearmand_packet_pack_header(&(server_packet->packet));
  if (gearmand_failed(ret))
  {
    gearmand_packet_free(&(server_packet->packet));
    gearman_server_packet_free(server_packet, con->thread, false);
    return ret;
  }

  if (take_data)
  {
    server_packet->packet.options.free_data= true;
  }

  int error;
  if ((error= pthread_mutex_lock(&con->thread->lock)) == 0)
  {
    GEARMAN_FIFO__ADD(con->io_packet, server_packet);
    if ((error= pthread_mutex_unlock(&con->thread->lock)))
    {
      gearmand_log_fatal_perror(GEARMAN_DEFAULT_LOG_PARAM, error, "pthread_mutex_unlock");
    }
  }
  else
  {
    gearmand_log_fatal_perror(GEARMAN_DEFAULT_LOG_PARAM, error, "pthread_mutex_lock");
  }

  gearman_server_con_io_add(con);

  return GEARMAN_SUCCESS;
}

void gearman_server_io_packet_remove(gearman_server_con_st *con)
{
  gearman_server_packet_st *server_packet= con->io_packet_list;

  gearmand_packet_free(&(server_packet->packet));

  int error;
  if ((error= pthread_mutex_lock(&con->thread->lock)) == 0)
  {
    GEARMAN_FIFO__DEL(con->io_packet, server_packet);
    if ((error= pthread_mutex_unlock(&con->thread->lock)))
    {
      gearmand_log_fatal_perror(GEARMAN_DEFAULT_LOG_PARAM, error, "pthread_mutex_unlock");
    }
  }
  else
  {
    gearmand_log_fatal_perror(GEARMAN_DEFAULT_LOG_PARAM, error, "pthread_mutex_lock");
  }

  gearman_server_packet_free(server_packet, con->thread, true);
}

void gearman_server_proc_packet_add(gearman_server_con_st *con,
                                    gearman_server_packet_st *packet)
{
  int error;
  if ((error= pthread_mutex_lock(&con->thread->lock)) == 0)
  {
    GEARMAN_FIFO__ADD(con->proc_packet, packet);
    if ((error= pthread_mutex_unlock(&con->thread->lock)))
    {
      gearmand_log_fatal_perror(GEARMAN_DEFAULT_LOG_PARAM, error, "pthread_mutex_unlock");
    }
  }
  else
  {
    gearmand_log_fatal_perror(GEARMAN_DEFAULT_LOG_PARAM, error, "pthread_mutex_lock");
  }

  gearman_server_con_proc_add(con);
}

gearman_server_packet_st *
gearman_server_proc_packet_remove(gearman_server_con_st *con)
{
  gearman_server_packet_st *server_packet= con->proc_packet_list;

  if (server_packet == NULL)
  {
    return NULL;
  }

  int error;
  if ((error= pthread_mutex_lock(&con->thread->lock)) == 0)
  {
    GEARMAN_FIFO__DEL(con->proc_packet, server_packet);
    if ((error= pthread_mutex_unlock(&con->thread->lock)) != 0)
    {
      gearmand_log_fatal_perror(GEARMAN_DEFAULT_LOG_PARAM, error, "pthread_mutex_unlock");
    }
  }
  else
  {
    gearmand_log_fatal_perror(GEARMAN_DEFAULT_LOG_PARAM, error, "pthread_mutex_lock");
  }

  return server_packet;
}

const char *gearmand_strcommand(gearmand_packet_st *packet)
{
  assert(packet);
  return gearman_command_info(packet->command)->name;
}

inline static gearmand_error_t packet_create_arg(gearmand_packet_st *packet,
                                                 const void *arg, size_t arg_size)
{
  if (packet->argc == gearman_command_info(packet->command)->argc and
      (not (gearman_command_info(packet->command)->data) or
       packet->data))
  {
    gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "too many arguments for command(%s)", gearman_command_info(packet->command)->name);
    return GEARMAN_TOO_MANY_ARGS;
  }

  if (packet->argc == gearman_command_info(packet->command)->argc)
  {
    packet->data= static_cast<const char *>(arg);
    packet->data_size= arg_size;
    return GEARMAN_SUCCESS;
  }

  if (packet->args_size == 0 and packet->magic != GEARMAN_MAGIC_TEXT)
  {
    packet->args_size= GEARMAN_PACKET_HEADER_SIZE;
  }

  if ((packet->args_size + arg_size) < GEARMAN_ARGS_BUFFER_SIZE)
  {
    packet->args= packet->args_buffer;
  }
  else
  {
    gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "resizing packet buffer");
    if (packet->args == packet->args_buffer)
    {
      packet->args= (char *)malloc(packet->args_size + arg_size);
      memcpy(packet->args, packet->args_buffer, packet->args_size);
    }
    else
    {
      char *new_args= (char *)realloc(packet->args, packet->args_size + arg_size);
      if (new_args == NULL)
      {
        return gearmand_perror(errno, "realloc");
      }
      packet->args= new_args;
    }
  }

  memcpy(packet->args + packet->args_size, arg, arg_size);
  packet->args_size+= arg_size;
  packet->arg_size[packet->argc]= arg_size;
  packet->argc++;

  size_t offset;
  if (packet->magic == GEARMAN_MAGIC_TEXT)
  {
    offset= 0;
  }
  else
  {
    offset= GEARMAN_PACKET_HEADER_SIZE;
  }

  for (uint8_t x= 0; x < packet->argc; ++x)
  {
    packet->arg[x]= packet->args + offset;
    offset+= packet->arg_size[x];
  }

  return GEARMAN_SUCCESS;
}

/** @} */

/*
 * Public Definitions
 */

void gearmand_packet_st::reset(enum gearman_magic_t magic_, gearman_command_t command_)
{
  options.complete= false;
  options.free_data= false;

  magic= magic_;
  command= command_;
  argc= 0;
  args_size= 0;
  data_size= 0;

  args= NULL;
  data= NULL;
}

gearmand_error_t gearmand_packet_create(gearmand_packet_st *packet,
                                          const void *arg, size_t arg_size)
{
  return packet_create_arg(packet, arg, arg_size);
}

void gearmand_packet_free(gearmand_packet_st *packet)
{
  if (packet->args != packet->args_buffer && packet->args != NULL)
  {
    gearmand_debug("free packet's args");
    free(packet->args);
    packet->args= NULL;
  }

  if (packet->options.free_data && packet->data != NULL)
  {
    gearmand_debug("free() packet's data");
    free((void *)packet->data); //@todo fix the need for the casting.
    packet->data= NULL;
  }
}

gearmand_error_t gearmand_packet_pack_header(gearmand_packet_st *packet)
{
  if (packet->magic == GEARMAN_MAGIC_TEXT)
  {
    packet->options.complete= true;
    return GEARMAN_SUCCESS;
  }

  if (packet->args_size == 0)
  {
    packet->args= packet->args_buffer;
    packet->args_size= GEARMAN_PACKET_HEADER_SIZE;
  }

  switch (packet->magic)
  {
  case GEARMAN_MAGIC_TEXT:
    break;

  case GEARMAN_MAGIC_REQUEST:
    memcpy(packet->args, "\0REQ", 4);
    break;

  case GEARMAN_MAGIC_RESPONSE:
    memcpy(packet->args, "\0RES", 4);
    break;

  default:
    gearmand_error("invalid magic value");
    return GEARMAN_INVALID_MAGIC;
  }

  if (packet->command == GEARMAN_COMMAND_TEXT ||
      packet->command >= GEARMAN_COMMAND_MAX)
  {
    gearmand_error("invalid command value");
    return GEARMAN_INVALID_COMMAND;
  }

  uint32_t tmp= packet->command;
  tmp= htonl(tmp);
  memcpy(packet->args + 4, &tmp, 4);

  uint64_t length_64= packet->args_size + packet->data_size - GEARMAN_PACKET_HEADER_SIZE;

  // Check for overflow on 32bit(portable?).
  if (length_64 >= UINT32_MAX || length_64 < packet->data_size)
  {
    gearmand_error("data size too too long");
    return GEARMAN_ARGUMENT_TOO_LARGE;
  }

  tmp= (uint32_t)length_64;
  tmp= htonl(tmp);
  memcpy(packet->args + 8, &tmp, 4);

  packet->options.complete= true;

  return GEARMAN_SUCCESS;
}
<commit_msg>Small style fix.<commit_after>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Gearmand client and server library.
 *
 *  Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
 *  Copyright (C) 2008 Brian Aker, Eric Day
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *
 *      * Redistributions of source code must retain the above copyright
 *  notice, this list of conditions and the following disclaimer.
 *
 *      * Redistributions in binary form must reproduce the above
 *  copyright notice, this list of conditions and the following disclaimer
 *  in the documentation and/or other materials provided with the
 *  distribution.
 *
 *      * The names of its contributors may not be used to endorse or
 *  promote products derived from this software without specific prior
 *  written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/**
 * @file
 * @brief Server connection definitions
 */

#include "gear_config.h"
#include "libgearman-server/common.h"

#include <libgearman/command.h>

#include <cassert>
#include <cerrno>
#include <cstring>
#include <memory>

#ifndef __INTEL_COMPILER
#pragma GCC diagnostic ignored "-Wold-style-cast"
#endif

/*
 * Public definitions
 */

gearman_server_packet_st *
gearman_server_packet_create(gearman_server_thread_st *thread,
                             bool from_thread)
{
  gearman_server_packet_st *server_packet= NULL;

  if (from_thread && Server->flags.threaded)
  {
    if (thread->free_packet_count > 0)
    {
      server_packet= thread->free_packet_list;
      thread->free_packet_list= server_packet->next;
      thread->free_packet_count--;
    }
  }
  else
  {
    if (Server->free_packet_count > 0)
    {
      server_packet= Server->free_packet_list;
      Server->free_packet_list= server_packet->next;
      Server->free_packet_count--;
    }
  }

  if (server_packet == NULL)
  {
    server_packet= new (std::nothrow) gearman_server_packet_st;
    if (server_packet == NULL)
    {
      gearmand_perror(errno, "new() gearman_server_packet_st");
      return NULL;
    }
  }

  server_packet->next= NULL;

  return server_packet;
}

void destroy_gearman_server_packet_st(gearman_server_packet_st *packet)
{
  delete packet;
}

void gearman_server_packet_free(gearman_server_packet_st *packet,
                                gearman_server_thread_st *thread,
                                bool from_thread)
{
  if (from_thread and Server->flags.threaded)
  {
    if (thread->free_packet_count < GEARMAN_MAX_FREE_SERVER_PACKET)
    {
      packet->next= thread->free_packet_list;
      thread->free_packet_list= packet;
      thread->free_packet_count++;
    }
    else
    {
      gearmand_debug("delete() gearman_server_packet_st");
      delete packet;
    }
  }
  else
  {
    if (Server->free_packet_count < GEARMAN_MAX_FREE_SERVER_PACKET)
    {
      packet->next= Server->free_packet_list;
      Server->free_packet_list= packet;
      Server->free_packet_count++;
    }
    else
    {
      gearmand_debug("delete() gearman_server_packet_st");
      delete packet;
    }
  }
}

gearmand_error_t gearman_server_io_packet_add(gearman_server_con_st *con,
                                              bool take_data,
                                              enum gearman_magic_t magic,
                                              gearman_command_t command,
                                              const void *arg, ...)
{
  gearman_server_packet_st *server_packet;
  va_list ap;

  server_packet= gearman_server_packet_create(con->thread, false);
  if (server_packet == NULL)
  {
    return GEARMAN_MEMORY_ALLOCATION_FAILURE;
  }

  server_packet->packet.reset(magic, command);

  va_start(ap, arg);

  while (arg)
  {
    size_t arg_size= va_arg(ap, size_t);

    gearmand_error_t ret= gearmand_packet_create(&(server_packet->packet), arg, arg_size);
    if (gearmand_failed(ret))
    {
      va_end(ap);
      gearmand_packet_free(&(server_packet->packet));
      gearman_server_packet_free(server_packet, con->thread, false);
      return ret;
    }

    arg= va_arg(ap, void *);
  }

  va_end(ap);

  gearmand_error_t ret= gearmand_packet_pack_header(&(server_packet->packet));
  if (gearmand_failed(ret))
  {
    gearmand_packet_free(&(server_packet->packet));
    gearman_server_packet_free(server_packet, con->thread, false);
    return ret;
  }

  if (take_data)
  {
    server_packet->packet.options.free_data= true;
  }

  int error;
  if ((error= pthread_mutex_lock(&con->thread->lock)) == 0)
  {
    GEARMAN_FIFO__ADD(con->io_packet, server_packet);
    if ((error= pthread_mutex_unlock(&con->thread->lock)))
    {
      gearmand_log_fatal_perror(GEARMAN_DEFAULT_LOG_PARAM, error, "pthread_mutex_unlock");
    }
  }
  else
  {
    gearmand_log_fatal_perror(GEARMAN_DEFAULT_LOG_PARAM, error, "pthread_mutex_lock");
  }

  gearman_server_con_io_add(con);

  return GEARMAN_SUCCESS;
}

void gearman_server_io_packet_remove(gearman_server_con_st *con)
{
  gearman_server_packet_st *server_packet= con->io_packet_list;

  gearmand_packet_free(&(server_packet->packet));

  int error;
  if ((error= pthread_mutex_lock(&con->thread->lock)) == 0)
  {
    GEARMAN_FIFO__DEL(con->io_packet, server_packet);
    if ((error= pthread_mutex_unlock(&con->thread->lock)))
    {
      gearmand_log_fatal_perror(GEARMAN_DEFAULT_LOG_PARAM, error, "pthread_mutex_unlock");
    }
  }
  else
  {
    gearmand_log_fatal_perror(GEARMAN_DEFAULT_LOG_PARAM, error, "pthread_mutex_lock");
  }

  gearman_server_packet_free(server_packet, con->thread, true);
}

void gearman_server_proc_packet_add(gearman_server_con_st *con,
                                    gearman_server_packet_st *packet)
{
  int error;
  if ((error= pthread_mutex_lock(&con->thread->lock)) == 0)
  {
    GEARMAN_FIFO__ADD(con->proc_packet, packet);
    if ((error= pthread_mutex_unlock(&con->thread->lock)))
    {
      gearmand_log_fatal_perror(GEARMAN_DEFAULT_LOG_PARAM, error, "pthread_mutex_unlock");
    }
  }
  else
  {
    gearmand_log_fatal_perror(GEARMAN_DEFAULT_LOG_PARAM, error, "pthread_mutex_lock");
  }

  gearman_server_con_proc_add(con);
}

gearman_server_packet_st *
gearman_server_proc_packet_remove(gearman_server_con_st *con)
{
  gearman_server_packet_st *server_packet= con->proc_packet_list;

  if (server_packet)
  {
    int error;
    if ((error= pthread_mutex_lock(&con->thread->lock)) == 0)
    {
      GEARMAN_FIFO__DEL(con->proc_packet, server_packet);
      if ((error= pthread_mutex_unlock(&con->thread->lock)) != 0)
      {
        gearmand_log_fatal_perror(GEARMAN_DEFAULT_LOG_PARAM, error, "pthread_mutex_unlock");
      }
    }
    else
    {
      gearmand_log_fatal_perror(GEARMAN_DEFAULT_LOG_PARAM, error, "pthread_mutex_lock");
    }
  }

  return server_packet;
}

const char *gearmand_strcommand(gearmand_packet_st *packet)
{
  assert(packet);
  return gearman_command_info(packet->command)->name;
}

inline static gearmand_error_t packet_create_arg(gearmand_packet_st *packet,
                                                 const void *arg, size_t arg_size)
{
  if (packet->argc == gearman_command_info(packet->command)->argc and
      (not (gearman_command_info(packet->command)->data) or
       packet->data))
  {
    gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "too many arguments for command(%s)", gearman_command_info(packet->command)->name);
    return GEARMAN_TOO_MANY_ARGS;
  }

  if (packet->argc == gearman_command_info(packet->command)->argc)
  {
    packet->data= static_cast<const char *>(arg);
    packet->data_size= arg_size;
    return GEARMAN_SUCCESS;
  }

  if (packet->args_size == 0 and packet->magic != GEARMAN_MAGIC_TEXT)
  {
    packet->args_size= GEARMAN_PACKET_HEADER_SIZE;
  }

  if ((packet->args_size + arg_size) < GEARMAN_ARGS_BUFFER_SIZE)
  {
    packet->args= packet->args_buffer;
  }
  else
  {
    gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "resizing packet buffer");
    if (packet->args == packet->args_buffer)
    {
      packet->args= (char *)malloc(packet->args_size + arg_size);
      memcpy(packet->args, packet->args_buffer, packet->args_size);
    }
    else
    {
      char *new_args= (char *)realloc(packet->args, packet->args_size + arg_size);
      if (new_args == NULL)
      {
        return gearmand_perror(errno, "realloc");
      }
      packet->args= new_args;
    }
  }

  memcpy(packet->args + packet->args_size, arg, arg_size);
  packet->args_size+= arg_size;
  packet->arg_size[packet->argc]= arg_size;
  packet->argc++;

  size_t offset;
  if (packet->magic == GEARMAN_MAGIC_TEXT)
  {
    offset= 0;
  }
  else
  {
    offset= GEARMAN_PACKET_HEADER_SIZE;
  }

  for (uint8_t x= 0; x < packet->argc; ++x)
  {
    packet->arg[x]= packet->args + offset;
    offset+= packet->arg_size[x];
  }

  return GEARMAN_SUCCESS;
}

/** @} */

/*
 * Public Definitions
 */

void gearmand_packet_st::reset(enum gearman_magic_t magic_, gearman_command_t command_)
{
  options.complete= false;
  options.free_data= false;

  magic= magic_;
  command= command_;
  argc= 0;
  args_size= 0;
  data_size= 0;

  args= NULL;
  data= NULL;
}

gearmand_error_t gearmand_packet_create(gearmand_packet_st *packet,
                                          const void *arg, size_t arg_size)
{
  return packet_create_arg(packet, arg, arg_size);
}

void gearmand_packet_free(gearmand_packet_st *packet)
{
  if (packet->args != packet->args_buffer && packet->args != NULL)
  {
    gearmand_debug("free packet's args");
    free(packet->args);
    packet->args= NULL;
  }

  if (packet->options.free_data && packet->data != NULL)
  {
    gearmand_debug("free() packet's data");
    free((void *)packet->data); //@todo fix the need for the casting.
    packet->data= NULL;
  }
}

gearmand_error_t gearmand_packet_pack_header(gearmand_packet_st *packet)
{
  if (packet->magic == GEARMAN_MAGIC_TEXT)
  {
    packet->options.complete= true;
    return GEARMAN_SUCCESS;
  }

  if (packet->args_size == 0)
  {
    packet->args= packet->args_buffer;
    packet->args_size= GEARMAN_PACKET_HEADER_SIZE;
  }

  switch (packet->magic)
  {
  case GEARMAN_MAGIC_TEXT:
    break;

  case GEARMAN_MAGIC_REQUEST:
    memcpy(packet->args, "\0REQ", 4);
    break;

  case GEARMAN_MAGIC_RESPONSE:
    memcpy(packet->args, "\0RES", 4);
    break;

  default:
    gearmand_error("invalid magic value");
    return GEARMAN_INVALID_MAGIC;
  }

  if (packet->command == GEARMAN_COMMAND_TEXT ||
      packet->command >= GEARMAN_COMMAND_MAX)
  {
    gearmand_error("invalid command value");
    return GEARMAN_INVALID_COMMAND;
  }

  uint32_t tmp= packet->command;
  tmp= htonl(tmp);
  memcpy(packet->args + 4, &tmp, 4);

  uint64_t length_64= packet->args_size + packet->data_size - GEARMAN_PACKET_HEADER_SIZE;

  // Check for overflow on 32bit(portable?).
  if (length_64 >= UINT32_MAX || length_64 < packet->data_size)
  {
    gearmand_error("data size too too long");
    return GEARMAN_ARGUMENT_TOO_LARGE;
  }

  tmp= (uint32_t)length_64;
  tmp= htonl(tmp);
  memcpy(packet->args + 8, &tmp, 4);

  packet->options.complete= true;

  return GEARMAN_SUCCESS;
}
<|endoftext|>


<commit_before>/* -*- C++ -*-; c-basic-offset: 4; indent-tabs-mode: nil */
/*
 * Implementation for URIQueue class.
 *
 * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */

/* This must be included before anything else */
#if HAVE_CONFIG_H
#  include <config.h>
#endif

#include "opflex/modb/internal/URIQueue.h"

#include "LockGuard.h"
#include "opflex/logging/internal/logging.hpp"

namespace opflex {
namespace modb {

URIQueue::URIQueue(QProcessor* processor_)
    : processor(processor_), proc_shouldRun(false) {
    uv_mutex_init(&item_mutex);
    uv_cond_init(&item_cond);
}

URIQueue::~URIQueue() {
    stop();
    uv_cond_destroy(&item_cond);
    uv_mutex_destroy(&item_mutex);
}

// listen on the item queue and dispatch events where required
void URIQueue::proc_thread_func(void* queue_) {
    URIQueue* queue = (URIQueue*)queue_;
    URIQueue::item d;

    while (queue->proc_shouldRun) {
        {
            util::LockGuard guard(&queue->item_mutex);
            while (queue->item_queue.size() == 0 && queue->proc_shouldRun)
                uv_cond_wait(&queue->item_cond, &queue->item_mutex);
            if (!queue->proc_shouldRun) return;

            // dequeue and process
            d = queue->item_queue.front();
            queue->item_queue.pop_front();
        }
        try {
            queue->processor->processItem(d.uri, d.data);
        } catch (const std::exception& ex) {
            LOG(ERROR) << "Exception while processing notification queue: " <<
                ex.what();
        } catch (...) {
            LOG(ERROR) << "Unknown error while processing notification queue";
        }
    }
}

void URIQueue::start() {
    proc_shouldRun = true;
    uv_thread_create(&proc_thread, proc_thread_func, this);
}

void URIQueue::stop() {
    if (proc_shouldRun) {
        proc_shouldRun = false;
        {
            util::LockGuard guard(&item_mutex);
            uv_cond_signal(&item_cond);
        }
        uv_thread_join(&proc_thread);

        {
            util::LockGuard guard(&item_mutex);
            item_queue.clear();
        }
    }
}

void URIQueue::queueItem(const URI& uri, const boost::any& data) {
    {
        util::LockGuard guard(&item_mutex);
        item_queue.push_back(item(uri, data));
        uv_cond_signal(&item_cond);
    }
}

} /* namespace modb */
} /* namespace opflex */
<commit_msg>Remove CPU hotspot in URIQueue::proc_thread_func()<commit_after>/* -*- C++ -*-; c-basic-offset: 4; indent-tabs-mode: nil */
/*
 * Implementation for URIQueue class.
 *
 * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */

/* This must be included before anything else */
#if HAVE_CONFIG_H
#  include <config.h>
#endif

#include <boost/foreach.hpp>
#include "opflex/modb/internal/URIQueue.h"

#include "LockGuard.h"
#include "opflex/logging/internal/logging.hpp"

namespace opflex {
namespace modb {

URIQueue::URIQueue(QProcessor* processor_)
    : processor(processor_), proc_shouldRun(false) {
    uv_mutex_init(&item_mutex);
    uv_cond_init(&item_cond);
}

URIQueue::~URIQueue() {
    stop();
    uv_cond_destroy(&item_cond);
    uv_mutex_destroy(&item_mutex);
}

// listen on the item queue and dispatch events where required
void URIQueue::proc_thread_func(void* queue_) {
    URIQueue* queue = (URIQueue*)queue_;

    while (queue->proc_shouldRun) {
        item_queue_t toProcess;
        {
            util::LockGuard guard(&queue->item_mutex);
            while (queue->item_queue.size() == 0 && queue->proc_shouldRun)
                uv_cond_wait(&queue->item_cond, &queue->item_mutex);
            if (!queue->proc_shouldRun) return;

            toProcess.swap(queue->item_queue);
        }

        BOOST_FOREACH (const URIQueue::item& d, toProcess) {
            if (!queue->proc_shouldRun) return;
            try {
                queue->processor->processItem(d.uri, d.data);
            } catch (const std::exception& ex) {
                LOG(ERROR) << "Exception while processing notification queue: " <<
                    ex.what();
            } catch (...) {
                LOG(ERROR) << "Unknown error while processing notification queue";
            }
        }
    }
}

void URIQueue::start() {
    proc_shouldRun = true;
    uv_thread_create(&proc_thread, proc_thread_func, this);
}

void URIQueue::stop() {
    if (proc_shouldRun) {
        proc_shouldRun = false;
        {
            util::LockGuard guard(&item_mutex);
            uv_cond_signal(&item_cond);
        }
        uv_thread_join(&proc_thread);

        {
            util::LockGuard guard(&item_mutex);
            item_queue.clear();
        }
    }
}

void URIQueue::queueItem(const URI& uri, const boost::any& data) {
    {
        util::LockGuard guard(&item_mutex);
        item_queue.push_back(item(uri, data));
        uv_cond_signal(&item_cond);
    }
}

} /* namespace modb */
} /* namespace opflex */
<|endoftext|>


<commit_before>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	largeobject.cxx
 *
 *   DESCRIPTION
 *      Implementation of the Large Objects interface
 *   Allows access to large objects directly, or though I/O streams
 *
 * Copyright (c) 2003-2005, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 *
 *-------------------------------------------------------------------------
 */
#include "pqxx/compiler.h"

#include <cerrno>
#include <stdexcept>

#include "libpq-fe.h"
#include "libpq/libpq-fs.h"

#include "pqxx/largeobject"

using namespace PGSTD;
using namespace pqxx::internal;

namespace
{

inline int StdModeToPQMode(ios::openmode mode)
{
  return ((mode & ios::in)  ? INV_READ  : 0) |
         ((mode & ios::out) ? INV_WRITE : 0);
}

inline int StdDirToPQDir(ios::seekdir dir) throw ()
{
  // TODO: Figure out whether seekdir values match C counterparts!
#ifdef PQXX_SEEKDIRS_MATCH_C
  return dir;
#else
  int pqdir;
  switch (dir)
  {
  case ios::beg: pqdir=SEEK_SET; break;
  case ios::cur: pqdir=SEEK_CUR; break;
  case ios::end: pqdir=SEEK_END; break;

  /* Added mostly to silence compiler warning, but also to help compiler detect
   * cases where this function can be optimized away completely.  This latter
   * reason should go away as soon as PQXX_SEEKDIRS_MATCH_C works.
   */
  default: pqdir = dir; break;
  }
  return pqdir;
#endif
}

} // namespace

pqxx::largeobject::largeobject() throw () :
  m_ID(oid_none)
{
}

pqxx::largeobject::largeobject(dbtransaction &T) :
  m_ID()
{
  m_ID = lo_creat(RawConnection(T), INV_READ|INV_WRITE);
  if (m_ID == oid_none)
  {
    const int err = errno;
    if (err == ENOMEM) throw bad_alloc();
    throw runtime_error("Could not create large object: " + Reason(err));
  }
}

pqxx::largeobject::largeobject(dbtransaction &T, const string &File) :
  m_ID()
{
  m_ID = lo_import(RawConnection(T), File.c_str());
  if (m_ID == oid_none)
  {
    const int err = errno;
    if (err == ENOMEM) throw bad_alloc();
    throw runtime_error("Could not import file '" + File + "' "
	                "to large object: " + Reason(err));
  }
}

pqxx::largeobject::largeobject(const largeobjectaccess &O) throw () :
  m_ID(O.id())
{
}

void pqxx::largeobject::to_file(dbtransaction &T, const string &File) const
{
  if (lo_export(RawConnection(T), id(), File.c_str()) == -1)
  {
    const int err = errno;
    if (err == ENOMEM) throw bad_alloc();
    throw runtime_error("Could not export large object " + to_string(m_ID) + " "
	                "to file '" + File + "': " +
			Reason(err));
  }
}

void pqxx::largeobject::remove(dbtransaction &T) const
{
  if (lo_unlink(RawConnection(T), id()) == -1)
  {
    const int err = errno;
    if (err == ENOMEM) throw bad_alloc();
    throw runtime_error("Could not delete large object " +
	                to_string(m_ID) + ": " +
			Reason(err));
  }
}

string pqxx::largeobject::Reason(int err) const
{
  if (err == ENOMEM) return "Out of memory";
  if (id() == oid_none) return "No object selected";

  char buf[500];
  return string(strerror_wrapper(err, buf, sizeof(buf)));
}

pqxx::largeobjectaccess::largeobjectaccess(dbtransaction &T, openmode mode) :
  largeobject(T),
  m_Trans(T),
  m_fd(-1)
{
  open(mode);
}

pqxx::largeobjectaccess::largeobjectaccess(dbtransaction &T,
    					   oid O,
					   openmode mode) :
  largeobject(O),
  m_Trans(T),
  m_fd(-1)
{
  open(mode);
}

pqxx::largeobjectaccess::largeobjectaccess(dbtransaction &T,
    					   largeobject O,
					   openmode mode) :
  largeobject(O),
  m_Trans(T),
  m_fd(-1)
{
  open(mode);
}

pqxx::largeobjectaccess::largeobjectaccess(dbtransaction &T,
					   const string &File,
					   openmode mode) :
  largeobject(T, File),
  m_Trans(T),
  m_fd(-1)
{
  open(mode);
}

pqxx::largeobjectaccess::size_type
pqxx::largeobjectaccess::seek(size_type dest, seekdir dir)
{
  const size_type Result = cseek(dest, dir);
  if (Result == -1)
  {
    const int err = errno;
    if (err == ENOMEM) throw bad_alloc();
    throw runtime_error("Error seeking in large object: " + Reason(err));
  }

  return Result;
}

long pqxx::largeobjectaccess::cseek(off_type dest, seekdir dir) throw ()
{
  return lo_lseek(RawConnection(), m_fd, dest, StdDirToPQDir(dir));
}

long pqxx::largeobjectaccess::cwrite(const char Buf[], size_type Len) throw ()
{
  return
    PGSTD::max(lo_write(RawConnection(),m_fd,const_cast<char *>(Buf), Len), -1);
}

long pqxx::largeobjectaccess::cread(char Buf[], size_type Bytes) throw ()
{
  return PGSTD::max(lo_read(RawConnection(), m_fd, Buf, Bytes), -1);
}

pqxx::largeobjectaccess::pos_type
pqxx::largeobjectaccess::ctell() const throw ()
{
  return
#if defined(PQXX_HAVE_LO_TELL)
        lo_tell(RawConnection(), m_fd);
#else
        lo_lseek(RawConnection(), m_fd, 0, SEEK_CUR);
#endif
}

void pqxx::largeobjectaccess::write(const char Buf[], size_type Len)
{
  const long Bytes = cwrite(Buf, Len);
  if (Bytes < Len)
  {
    const int err = errno;
    if (err == ENOMEM) throw bad_alloc();
    if (Bytes < 0)
      throw runtime_error("Error writing to large object "
                          "#" + to_string(id()) + ": " +
	                  Reason(err));
    if (Bytes == 0)
      throw runtime_error("Could not write to large object #" +
	                  to_string(id()) + ": " + Reason(err));

    throw runtime_error("Wanted to write " + to_string(Len) + " bytes "
	                "to large object #" + to_string(id()) + "; "
			"could only write " + to_string(Bytes));
  }
}

pqxx::largeobjectaccess::size_type
pqxx::largeobjectaccess::read(char Buf[], size_type Len)
{
  const long Bytes = cread(Buf, Len);
  if (Bytes < 0)
  {
    const int err = errno;
    if (err == ENOMEM) throw bad_alloc();
    throw runtime_error("Error reading from large object #" + to_string(id()) +
	                ": " + Reason(err));
  }
  return Bytes;
}

void pqxx::largeobjectaccess::open(openmode mode)
{
  m_fd = lo_open(RawConnection(), id(), StdModeToPQMode(mode));
  if (m_fd < 0)
  {
    const int err = errno;
    if (err == ENOMEM) throw bad_alloc();
    throw runtime_error("Could not open large object " + to_string(id()) + ":"
			" " + Reason(err));
  }
}

void pqxx::largeobjectaccess::close() throw ()
{
#ifdef PQXX_QUIET_DESTRUCTORS
  disable_noticer Quiet(m_Trans.conn());
#endif
  if (m_fd >= 0) lo_close(RawConnection(), m_fd);
}

pqxx::largeobjectaccess::size_type pqxx::largeobjectaccess::tell() const
{
  const size_type res = ctell();
  if (res == -1) throw runtime_error(Reason(errno));
  return res;
}

string pqxx::largeobjectaccess::Reason(int err) const
{
  return (m_fd == -1) ? "No object opened" : largeobject::Reason(err);
}

void pqxx::largeobjectaccess::process_notice(const string &s) throw ()
{
  m_Trans.process_notice(s);
}
<commit_msg>No longer needs libpq-fs.h!<commit_after>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	largeobject.cxx
 *
 *   DESCRIPTION
 *      Implementation of the Large Objects interface
 *   Allows access to large objects directly, or though I/O streams
 *
 * Copyright (c) 2003-2005, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 *
 *-------------------------------------------------------------------------
 */
#include "pqxx/compiler.h"

#include <cerrno>
#include <stdexcept>

#include "libpq-fe.h"

//#include "libpq/libpq-fs.h"
/// Copied from libpq/libpq-fs.h so we don't need that header anymore
#define INV_WRITE		0x00020000
/// Copied from libpq/libpq-fs.h so we don't need that header anymore
#define INV_READ		0x00040000

#include "pqxx/largeobject"

using namespace PGSTD;
using namespace pqxx::internal;

namespace
{

inline int StdModeToPQMode(ios::openmode mode)
{
  return ((mode & ios::in)  ? INV_READ  : 0) |
         ((mode & ios::out) ? INV_WRITE : 0);
}

inline int StdDirToPQDir(ios::seekdir dir) throw ()
{
  // TODO: Figure out whether seekdir values match C counterparts!
#ifdef PQXX_SEEKDIRS_MATCH_C
  return dir;
#else
  int pqdir;
  switch (dir)
  {
  case ios::beg: pqdir=SEEK_SET; break;
  case ios::cur: pqdir=SEEK_CUR; break;
  case ios::end: pqdir=SEEK_END; break;

  /* Added mostly to silence compiler warning, but also to help compiler detect
   * cases where this function can be optimized away completely.  This latter
   * reason should go away as soon as PQXX_SEEKDIRS_MATCH_C works.
   */
  default: pqdir = dir; break;
  }
  return pqdir;
#endif
}

} // namespace

pqxx::largeobject::largeobject() throw () :
  m_ID(oid_none)
{
}

pqxx::largeobject::largeobject(dbtransaction &T) :
  m_ID()
{
  m_ID = lo_creat(RawConnection(T), INV_READ|INV_WRITE);
  if (m_ID == oid_none)
  {
    const int err = errno;
    if (err == ENOMEM) throw bad_alloc();
    throw runtime_error("Could not create large object: " + Reason(err));
  }
}

pqxx::largeobject::largeobject(dbtransaction &T, const string &File) :
  m_ID()
{
  m_ID = lo_import(RawConnection(T), File.c_str());
  if (m_ID == oid_none)
  {
    const int err = errno;
    if (err == ENOMEM) throw bad_alloc();
    throw runtime_error("Could not import file '" + File + "' "
	                "to large object: " + Reason(err));
  }
}

pqxx::largeobject::largeobject(const largeobjectaccess &O) throw () :
  m_ID(O.id())
{
}

void pqxx::largeobject::to_file(dbtransaction &T, const string &File) const
{
  if (lo_export(RawConnection(T), id(), File.c_str()) == -1)
  {
    const int err = errno;
    if (err == ENOMEM) throw bad_alloc();
    throw runtime_error("Could not export large object " + to_string(m_ID) + " "
	                "to file '" + File + "': " +
			Reason(err));
  }
}

void pqxx::largeobject::remove(dbtransaction &T) const
{
  if (lo_unlink(RawConnection(T), id()) == -1)
  {
    const int err = errno;
    if (err == ENOMEM) throw bad_alloc();
    throw runtime_error("Could not delete large object " +
	                to_string(m_ID) + ": " +
			Reason(err));
  }
}

string pqxx::largeobject::Reason(int err) const
{
  if (err == ENOMEM) return "Out of memory";
  if (id() == oid_none) return "No object selected";

  char buf[500];
  return string(strerror_wrapper(err, buf, sizeof(buf)));
}

pqxx::largeobjectaccess::largeobjectaccess(dbtransaction &T, openmode mode) :
  largeobject(T),
  m_Trans(T),
  m_fd(-1)
{
  open(mode);
}

pqxx::largeobjectaccess::largeobjectaccess(dbtransaction &T,
    					   oid O,
					   openmode mode) :
  largeobject(O),
  m_Trans(T),
  m_fd(-1)
{
  open(mode);
}

pqxx::largeobjectaccess::largeobjectaccess(dbtransaction &T,
    					   largeobject O,
					   openmode mode) :
  largeobject(O),
  m_Trans(T),
  m_fd(-1)
{
  open(mode);
}

pqxx::largeobjectaccess::largeobjectaccess(dbtransaction &T,
					   const string &File,
					   openmode mode) :
  largeobject(T, File),
  m_Trans(T),
  m_fd(-1)
{
  open(mode);
}

pqxx::largeobjectaccess::size_type
pqxx::largeobjectaccess::seek(size_type dest, seekdir dir)
{
  const size_type Result = cseek(dest, dir);
  if (Result == -1)
  {
    const int err = errno;
    if (err == ENOMEM) throw bad_alloc();
    throw runtime_error("Error seeking in large object: " + Reason(err));
  }

  return Result;
}

long pqxx::largeobjectaccess::cseek(off_type dest, seekdir dir) throw ()
{
  return lo_lseek(RawConnection(), m_fd, dest, StdDirToPQDir(dir));
}

long pqxx::largeobjectaccess::cwrite(const char Buf[], size_type Len) throw ()
{
  return
    PGSTD::max(lo_write(RawConnection(),m_fd,const_cast<char *>(Buf), Len), -1);
}

long pqxx::largeobjectaccess::cread(char Buf[], size_type Bytes) throw ()
{
  return PGSTD::max(lo_read(RawConnection(), m_fd, Buf, Bytes), -1);
}

pqxx::largeobjectaccess::pos_type
pqxx::largeobjectaccess::ctell() const throw ()
{
  return
#if defined(PQXX_HAVE_LO_TELL)
        lo_tell(RawConnection(), m_fd);
#else
        lo_lseek(RawConnection(), m_fd, 0, SEEK_CUR);
#endif
}

void pqxx::largeobjectaccess::write(const char Buf[], size_type Len)
{
  const long Bytes = cwrite(Buf, Len);
  if (Bytes < Len)
  {
    const int err = errno;
    if (err == ENOMEM) throw bad_alloc();
    if (Bytes < 0)
      throw runtime_error("Error writing to large object "
                          "#" + to_string(id()) + ": " +
	                  Reason(err));
    if (Bytes == 0)
      throw runtime_error("Could not write to large object #" +
	                  to_string(id()) + ": " + Reason(err));

    throw runtime_error("Wanted to write " + to_string(Len) + " bytes "
	                "to large object #" + to_string(id()) + "; "
			"could only write " + to_string(Bytes));
  }
}

pqxx::largeobjectaccess::size_type
pqxx::largeobjectaccess::read(char Buf[], size_type Len)
{
  const long Bytes = cread(Buf, Len);
  if (Bytes < 0)
  {
    const int err = errno;
    if (err == ENOMEM) throw bad_alloc();
    throw runtime_error("Error reading from large object #" + to_string(id()) +
	                ": " + Reason(err));
  }
  return Bytes;
}

void pqxx::largeobjectaccess::open(openmode mode)
{
  m_fd = lo_open(RawConnection(), id(), StdModeToPQMode(mode));
  if (m_fd < 0)
  {
    const int err = errno;
    if (err == ENOMEM) throw bad_alloc();
    throw runtime_error("Could not open large object " + to_string(id()) + ":"
			" " + Reason(err));
  }
}

void pqxx::largeobjectaccess::close() throw ()
{
#ifdef PQXX_QUIET_DESTRUCTORS
  disable_noticer Quiet(m_Trans.conn());
#endif
  if (m_fd >= 0) lo_close(RawConnection(), m_fd);
}

pqxx::largeobjectaccess::size_type pqxx::largeobjectaccess::tell() const
{
  const size_type res = ctell();
  if (res == -1) throw runtime_error(Reason(errno));
  return res;
}

string pqxx::largeobjectaccess::Reason(int err) const
{
  return (m_fd == -1) ? "No object opened" : largeobject::Reason(err);
}

void pqxx::largeobjectaccess::process_notice(const string &s) throw ()
{
  m_Trans.process_notice(s);
}
<|endoftext|>


<commit_before>/*~
 * Copyright (C) 2015 George Makrydakis <george@irrequietus.eu>
 *
 * The 'typestring' header is a single header C++ library for creating types
 * to use as type parameters in template instantiations, repository available
 * at https://github.com/irrequietus/typestring. Conceptually stemming from
 * own implementation of the same thing (but in a more complicated manner to
 * be revised) in 'clause': https://github.com/irrequietus/clause.
 *
 * File subject to the terms and conditions of the Mozilla Public License v 2.0.
 * If a copy of the MPLv2 license text was not distributed with this file, you
 * can obtain it at: http://mozilla.org/MPL/2.0/.
 */

#ifndef IRQUS_TYPESTRING_HH_
#define IRQUS_TYPESTRING_HH_

namespace irqus {

/*~
 * @desc A class 'storing' strings into distinct, reusable compile-time types that
 *       can be used as type parameters in a template parameter list.
 * @tprm C... : char non-type parameter pack whose ordered sequence results
 *              into a specific string.
 * @note Could have wrapped up everything in a single class, eventually will,
 *       once some compilers fix their class scope lookups! I have added some
 *       utility functions because asides being a fun little project, it is of
 *       use in certain constructs related to template metaprogramming
 *       nonetheless.
 */
template<char... C>
struct typestring final {
private:
    static constexpr char const   vals[sizeof...(C)+1] = { C...,'\0' };
    static constexpr unsigned int sval = sizeof...(C);
public:

    static constexpr char const * data() noexcept
    { return &vals[0]; }

    static constexpr unsigned int size() noexcept
    { return sval; };

    static constexpr char const * cbegin() noexcept
    { return &vals[0]; }

    static constexpr char const * cend() noexcept
    { return &vals[sval]; }
};

template<char... C>
constexpr char const typestring<C...>::vals[sizeof...(C)+1];

//*~ part 1: preparing the ground, because function templates are awesome.

/*~
 * @note While it is easy to resort to constexpr strings for use in constexpr
 *       metaprogramming, what we want is to convert compile time string in situ
 *       definitions into reusable, distinct types, for use in advanced template
 *       metaprogramming techniques. We want such features because this kind of
 *       metaprogramming constitutes a pure, non-strict, untyped functional
 *       programming language with pattern matching where declarative semantics
 *       can really shine.
 *
 *       Currently, there is no feature in C++ that offers the opportunity to
 *       use strings as type parameter types themselves, despite there are
 *       several, different library implementations. This implementation is a
 *       fast, short, single-header, stupid-proof solution that works with any
 *       C++11 compliant compiler and up, with the resulting type being easily
 *       reusable throughout the code.
 *
 * @usge Just include the header and enable -std=c++11 or -std=c++14 etc, use
 *       like in the following example:
 *
 *            typestring_is("Hello!")
 *
 *       is essentially identical to the following template instantiation:
 *
 *            irqus::typestring<'H', 'e', 'l', 'l', 'o', '!'>
 *
 *       By passing -DUSE_TYPESTRING=<power of 2> during compilation, you can
 *       set the maximum length of the 'typestring' from 1 to 1024 (2^0 to 2^10).
 *       Although all preprocessor implementations tested are capable of far
 *       more with this method, exceeding this limit may cause internal compiler
 *       errors in most, with at times rather hilarious results.
 */

template<int N, int M>
constexpr char tygrab(char const(&c)[M]) noexcept
{ return c[N < M ? N : M-1]; }

//*~ part2: Function template type signatures for type deduction purposes. In
//          other words, exploiting the functorial nature of parameter packs
//          while mixing them with an obvious catamorphism through pattern
//          matching galore (partial ordering in this case in C++ "parlance").

template<char... X>
auto typoke(typestring<X...>) // as is...
  -> typestring<X...>;

template<char... X, char... Y>
auto typoke(typestring<X...>, typestring<'\0'>, typestring<Y>...)
  -> typestring<X...>;

template<char A, char... X, char... Y>
auto typoke(typestring<X...>, typestring<A>, typestring<Y>...)
  -> decltype(typoke(typestring<X...,A>(), typestring<Y>()...));

template<char... C>
auto typeek(typestring<C...>)
  -> decltype(typoke(typestring<C>()...));

} /* irqus */

//*~ part3: some necessary code generation using preprocessor metaprogramming!
//          There is functional nature in preprocessor metaprogramming as well.

/*~
 * @note Code generation block. Undoubtedly, the preprocessor implementations
 *       of both clang++ and g++ are relatively competent in producing a
 *       relatively adequate amount of boilerplate for implementing features
 *       that the language itself will probably be having as features in a few
 *       years. At times, like herein, the preprocessor is able to generate
 *       boilerplate *extremely* fast, but over a certain limit the compiler is
 *       incapable of compiling it. For the record, only certain versions of
 *       g++ where capable of going beyond 4K, so I thought of going from base
 *       16 to base 2 for USE_TYPESTRING power base. For the record, it takes
 *       a few milliseconds to generate boilerplate for several thousands worth
 *       of "string" length through such an 'fmap' like procedure.
 */

/* 2^0 = 1 */
#define TYPESTRING1(n,x) irqus::tygrab<0x##n##0>(x)

/* 2^1 = 2 */
#define TYPESTRING2(n,x) irqus::tygrab<0x##n##0>(x), irqus::tygrab<0x##n##1>(x)

/* 2^2 = 2 */
#define TYPESTRING4(n,x) \
        irqus::tygrab<0x##n##0>(x), irqus::tygrab<0x##n##1>(x) \
      , irqus::tygrab<0x##n##2>(x), irqus::tygrab<0x##n##3>(x)

/* 2^3 = 8 */
#define TYPESTRING8(n,x) \
        irqus::tygrab<0x##n##0>(x), irqus::tygrab<0x##n##1>(x) \
      , irqus::tygrab<0x##n##2>(x), irqus::tygrab<0x##n##3>(x) \
      , irqus::tygrab<0x##n##4>(x), irqus::tygrab<0x##n##5>(x) \
      , irqus::tygrab<0x##n##6>(x), irqus::tygrab<0x##n##7>(x)

/* 2^4 = 16 */
#define TYPESTRING16(n,x) \
        irqus::tygrab<0x##n##0>(x), irqus::tygrab<0x##n##1>(x) \
      , irqus::tygrab<0x##n##2>(x), irqus::tygrab<0x##n##3>(x) \
      , irqus::tygrab<0x##n##4>(x), irqus::tygrab<0x##n##5>(x) \
      , irqus::tygrab<0x##n##6>(x), irqus::tygrab<0x##n##7>(x) \
      , irqus::tygrab<0x##n##8>(x), irqus::tygrab<0x##n##9>(x) \
      , irqus::tygrab<0x##n##A>(x), irqus::tygrab<0x##n##B>(x) \
      , irqus::tygrab<0x##n##C>(x), irqus::tygrab<0x##n##D>(x) \
      , irqus::tygrab<0x##n##E>(x), irqus::tygrab<0x##n##F>(x)

/* 2^5 = 32 */
#define TYPESTRING32(n,x) \
        TYPESTRING16(n##0,x),TYPESTRING16(n##1,x)

/* 2^6 = 64 */
#define TYPESTRING64(n,x) \
        TYPESTRING16(n##0,x), TYPESTRING16(n##1,x), TYPESTRING16(n##2,x) \
      , TYPESTRING16(n##3,x)

/* 2^7 = 128 */
#define TYPESTRING128(n,x) \
        TYPESTRING16(n##0,x), TYPESTRING16(n##1,x), TYPESTRING16(n##2,x) \
      , TYPESTRING16(n##3,x), TYPESTRING16(n##4,x), TYPESTRING16(n##5,x) \
      , TYPESTRING16(n##6,x), TYPESTRING16(n##7,x)

/* 2^8 = 256 */
#define TYPESTRING256(n,x) \
        TYPESTRING16(n##0,x), TYPESTRING16(n##1,x), TYPESTRING16(n##2,x) \
      , TYPESTRING16(n##3,x), TYPESTRING16(n##4,x), TYPESTRING16(n##5,x) \
      , TYPESTRING16(n##6,x), TYPESTRING16(n##7,x), TYPESTRING16(n##8,x) \
      , TYPESTRING16(n##9,x), TYPESTRING16(n##A,x), TYPESTRING16(n##B,x) \
      , TYPESTRING16(n##C,x), TYPESTRING16(n##D,x), TYPESTRING16(n##E,x) \
      , TYPESTRING16(n##F,x)

/* 2^9 = 512 */
#define TYPESTRING512(n,x) \
        TYPESTRING256(n##0,x), TYPESTRING256(n##1,x)

/* 2^10 = 1024 */
#define TYPESTRING1024(n,x) \
        TYPESTRING256(n##0,x), TYPESTRING256(n##1,x), TYPESTRING256(n##2,x) \
      , TYPESTRING128(n##3,x), TYPESTRING16(n##38,x), TYPESTRING16(n##39,x) \
      , TYPESTRING16(n##3A,x), TYPESTRING16(n##3B,x), TYPESTRING16(n##3C,x) \
      , TYPESTRING16(n##3D,x), TYPESTRING16(n##3E,x), TYPESTRING16(n##3F,x)

//*~ part4 : Let's give some logic with a -DUSE_TYPESTRING flag!

#ifdef USE_TYPESTRING
#if USE_TYPESTRING == 0
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING1(,x)>()))
#elif USE_TYPESTRING == 1
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING2(,x)>()))
#elif USE_TYPESTRING == 2
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING4(,x)>()))
#elif USE_TYPESTRING == 3
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING8(,x)>()))
#elif USE_TYPESTRING == 4
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING16(,x)>()))
#elif USE_TYPESTRING == 5
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING32(,x)>()))
#elif USE_TYPESTRING == 6
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING64(,x)>()))
#elif USE_TYPESTRING == 7
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING128(,x)>()))
#elif USE_TYPESTRING == 8
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING256(,x)>()))
#elif USE_TYPESTRING == 9
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING512(,x)>()))
#elif USE_TYPESTRING == 10
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING1024(,x)>()))
#elif USE_TYPESTRING > 10

#warning !!!: custom typestring length exceeded allowed (1024)            !!!
#warning !!!: all typestrings to default maximum typestring length of 64  !!!
#warning !!!: you can use -DUSE_TYPESTRING=<power of two> to set length   !!!

#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING64(,x)>()))

#elif USE_TYPESTRING < 0

#warning !!!: You used USE_TYPESTRING with a negative size specified      !!!
#warning !!!: all typestrings to default maximum typestring length of 64  !!!
#warning !!!: you can use -DUSE_TYPESTRING=<power of two> to set length   !!!

#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING64(,x)>()))

#endif
#else
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING64(,x)>()))
#endif
#endif /* IRQUS_TYPESTRING_HH_ */
<commit_msg>Added a tycat by popular request.<commit_after>/*~
 * Copyright (C) 2015, 2016 George Makrydakis <george@irrequietus.eu>
 *
 * The 'typestring' header is a single header C++ library for creating types
 * to use as type parameters in template instantiations, repository available
 * at https://github.com/irrequietus/typestring. Conceptually stemming from
 * own implementation of the same thing (but in a more complicated manner to
 * be revised) in 'clause': https://github.com/irrequietus/clause.
 *
 * File subject to the terms and conditions of the Mozilla Public License v 2.0.
 * If a copy of the MPLv2 license text was not distributed with this file, you
 * can obtain it at: http://mozilla.org/MPL/2.0/.
 */

#ifndef IRQUS_TYPESTRING_HH_
#define IRQUS_TYPESTRING_HH_

namespace irqus {

/*~
 * @desc A class 'storing' strings into distinct, reusable compile-time types that
 *       can be used as type parameters in a template parameter list.
 * @tprm C... : char non-type parameter pack whose ordered sequence results
 *              into a specific string.
 * @note Could have wrapped up everything in a single class, eventually will,
 *       once some compilers fix their class scope lookups! I have added some
 *       utility functions because asides being a fun little project, it is of
 *       use in certain constructs related to template metaprogramming
 *       nonetheless.
 */
template<char... C>
struct typestring final {
private:
    static constexpr char const   vals[sizeof...(C)+1] = { C...,'\0' };
    static constexpr unsigned int sval = sizeof...(C);
public:

    static constexpr char const * data() noexcept
    { return &vals[0]; }

    static constexpr unsigned int size() noexcept
    { return sval; };

    static constexpr char const * cbegin() noexcept
    { return &vals[0]; }

    static constexpr char const * cend() noexcept
    { return &vals[sval]; }
};

template<char... C>
constexpr char const typestring<C...>::vals[sizeof...(C)+1];

//*~ part 1: preparing the ground, because function templates are awesome.

/*~
 * @note While it is easy to resort to constexpr strings for use in constexpr
 *       metaprogramming, what we want is to convert compile time string in situ
 *       definitions into reusable, distinct types, for use in advanced template
 *       metaprogramming techniques. We want such features because this kind of
 *       metaprogramming constitutes a pure, non-strict, untyped functional
 *       programming language with pattern matching where declarative semantics
 *       can really shine.
 *
 *       Currently, there is no feature in C++ that offers the opportunity to
 *       use strings as type parameter types themselves, despite there are
 *       several, different library implementations. This implementation is a
 *       fast, short, single-header, stupid-proof solution that works with any
 *       C++11 compliant compiler and up, with the resulting type being easily
 *       reusable throughout the code.
 *
 * @usge Just include the header and enable -std=c++11 or -std=c++14 etc, use
 *       like in the following example:
 *
 *            typestring_is("Hello!")
 *
 *       is essentially identical to the following template instantiation:
 *
 *            irqus::typestring<'H', 'e', 'l', 'l', 'o', '!'>
 *
 *       By passing -DUSE_TYPESTRING=<power of 2> during compilation, you can
 *       set the maximum length of the 'typestring' from 1 to 1024 (2^0 to 2^10).
 *       Although all preprocessor implementations tested are capable of far
 *       more with this method, exceeding this limit may cause internal compiler
 *       errors in most, with at times rather hilarious results.
 */

template<int N, int M>
constexpr char tygrab(char const(&c)[M]) noexcept
{ return c[N < M ? N : M-1]; }

//*~ part2: Function template type signatures for type deduction purposes. In
//          other words, exploiting the functorial nature of parameter packs
//          while mixing them with an obvious catamorphism through pattern
//          matching galore (partial ordering in this case in C++ "parlance").

template<char... X>
auto typoke(typestring<X...>) // as is...
  -> typestring<X...>;

template<char... X, char... Y>
auto typoke(typestring<X...>, typestring<'\0'>, typestring<Y>...)
  -> typestring<X...>;

template<char A, char... X, char... Y>
auto typoke(typestring<X...>, typestring<A>, typestring<Y>...)
  -> decltype(typoke(typestring<X...,A>(), typestring<Y>()...));

template<char... C>
auto typeek(typestring<C...>)
  -> decltype(typoke(typestring<C>()...));

template<char... A, char... B, typename... X>
auto tycat_(typestring<A...>, typestring<B...>, X... x)
   -> decltype(tycat_(typestring<A..., B...>(), x...));

template<char... X>
auto tycat_(typestring<X...>)
   -> typestring<X...>;

/*
 * Some people actually using this header as is asked me to include
 * a typestring "cat" utility given that it is easy enough to implement.
 * I have added this functionality through the template alias below. For
 * the obvious implementation, nothing more to say. All T... must be
 * of course, "typestrings".
 */
template<typename... T>
using tycat
    = decltype(tycat_(T()...));

} /* irqus */

//*~ part3: some necessary code generation using preprocessor metaprogramming!
//          There is functional nature in preprocessor metaprogramming as well.

/*~
 * @note Code generation block. Undoubtedly, the preprocessor implementations
 *       of both clang++ and g++ are relatively competent in producing a
 *       relatively adequate amount of boilerplate for implementing features
 *       that the language itself will probably be having as features in a few
 *       years. At times, like herein, the preprocessor is able to generate
 *       boilerplate *extremely* fast, but over a certain limit the compiler is
 *       incapable of compiling it. For the record, only certain versions of
 *       g++ where capable of going beyond 4K, so I thought of going from base
 *       16 to base 2 for USE_TYPESTRING power base. For the record, it takes
 *       a few milliseconds to generate boilerplate for several thousands worth
 *       of "string" length through such an 'fmap' like procedure.
 */

/* 2^0 = 1 */
#define TYPESTRING1(n,x) irqus::tygrab<0x##n##0>(x)

/* 2^1 = 2 */
#define TYPESTRING2(n,x) irqus::tygrab<0x##n##0>(x), irqus::tygrab<0x##n##1>(x)

/* 2^2 = 2 */
#define TYPESTRING4(n,x) \
        irqus::tygrab<0x##n##0>(x), irqus::tygrab<0x##n##1>(x) \
      , irqus::tygrab<0x##n##2>(x), irqus::tygrab<0x##n##3>(x)

/* 2^3 = 8 */
#define TYPESTRING8(n,x) \
        irqus::tygrab<0x##n##0>(x), irqus::tygrab<0x##n##1>(x) \
      , irqus::tygrab<0x##n##2>(x), irqus::tygrab<0x##n##3>(x) \
      , irqus::tygrab<0x##n##4>(x), irqus::tygrab<0x##n##5>(x) \
      , irqus::tygrab<0x##n##6>(x), irqus::tygrab<0x##n##7>(x)

/* 2^4 = 16 */
#define TYPESTRING16(n,x) \
        irqus::tygrab<0x##n##0>(x), irqus::tygrab<0x##n##1>(x) \
      , irqus::tygrab<0x##n##2>(x), irqus::tygrab<0x##n##3>(x) \
      , irqus::tygrab<0x##n##4>(x), irqus::tygrab<0x##n##5>(x) \
      , irqus::tygrab<0x##n##6>(x), irqus::tygrab<0x##n##7>(x) \
      , irqus::tygrab<0x##n##8>(x), irqus::tygrab<0x##n##9>(x) \
      , irqus::tygrab<0x##n##A>(x), irqus::tygrab<0x##n##B>(x) \
      , irqus::tygrab<0x##n##C>(x), irqus::tygrab<0x##n##D>(x) \
      , irqus::tygrab<0x##n##E>(x), irqus::tygrab<0x##n##F>(x)

/* 2^5 = 32 */
#define TYPESTRING32(n,x) \
        TYPESTRING16(n##0,x),TYPESTRING16(n##1,x)

/* 2^6 = 64 */
#define TYPESTRING64(n,x) \
        TYPESTRING16(n##0,x), TYPESTRING16(n##1,x), TYPESTRING16(n##2,x) \
      , TYPESTRING16(n##3,x)

/* 2^7 = 128 */
#define TYPESTRING128(n,x) \
        TYPESTRING16(n##0,x), TYPESTRING16(n##1,x), TYPESTRING16(n##2,x) \
      , TYPESTRING16(n##3,x), TYPESTRING16(n##4,x), TYPESTRING16(n##5,x) \
      , TYPESTRING16(n##6,x), TYPESTRING16(n##7,x)

/* 2^8 = 256 */
#define TYPESTRING256(n,x) \
        TYPESTRING16(n##0,x), TYPESTRING16(n##1,x), TYPESTRING16(n##2,x) \
      , TYPESTRING16(n##3,x), TYPESTRING16(n##4,x), TYPESTRING16(n##5,x) \
      , TYPESTRING16(n##6,x), TYPESTRING16(n##7,x), TYPESTRING16(n##8,x) \
      , TYPESTRING16(n##9,x), TYPESTRING16(n##A,x), TYPESTRING16(n##B,x) \
      , TYPESTRING16(n##C,x), TYPESTRING16(n##D,x), TYPESTRING16(n##E,x) \
      , TYPESTRING16(n##F,x)

/* 2^9 = 512 */
#define TYPESTRING512(n,x) \
        TYPESTRING256(n##0,x), TYPESTRING256(n##1,x)

/* 2^10 = 1024 */
#define TYPESTRING1024(n,x) \
        TYPESTRING256(n##0,x), TYPESTRING256(n##1,x), TYPESTRING256(n##2,x) \
      , TYPESTRING128(n##3,x), TYPESTRING16(n##38,x), TYPESTRING16(n##39,x) \
      , TYPESTRING16(n##3A,x), TYPESTRING16(n##3B,x), TYPESTRING16(n##3C,x) \
      , TYPESTRING16(n##3D,x), TYPESTRING16(n##3E,x), TYPESTRING16(n##3F,x)

//*~ part4 : Let's give some logic with a -DUSE_TYPESTRING flag!

#ifdef USE_TYPESTRING
#if USE_TYPESTRING == 0
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING1(,x)>()))
#elif USE_TYPESTRING == 1
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING2(,x)>()))
#elif USE_TYPESTRING == 2
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING4(,x)>()))
#elif USE_TYPESTRING == 3
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING8(,x)>()))
#elif USE_TYPESTRING == 4
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING16(,x)>()))
#elif USE_TYPESTRING == 5
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING32(,x)>()))
#elif USE_TYPESTRING == 6
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING64(,x)>()))
#elif USE_TYPESTRING == 7
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING128(,x)>()))
#elif USE_TYPESTRING == 8
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING256(,x)>()))
#elif USE_TYPESTRING == 9
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING512(,x)>()))
#elif USE_TYPESTRING == 10
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING1024(,x)>()))
#elif USE_TYPESTRING > 10

#warning !!!: custom typestring length exceeded allowed (1024)            !!!
#warning !!!: all typestrings to default maximum typestring length of 64  !!!
#warning !!!: you can use -DUSE_TYPESTRING=<power of two> to set length   !!!

#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING64(,x)>()))

#elif USE_TYPESTRING < 0

#warning !!!: You used USE_TYPESTRING with a negative size specified      !!!
#warning !!!: all typestrings to default maximum typestring length of 64  !!!
#warning !!!: you can use -DUSE_TYPESTRING=<power of two> to set length   !!!

#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING64(,x)>()))

#endif
#else
#define typestring_is(x) \
    decltype(irqus::typeek(irqus::typestring<TYPESTRING64(,x)>()))
#endif
#endif /* IRQUS_TYPESTRING_HH_ */
<|endoftext|>