<commit_before>// Copyright(c) 2016 Jounayd Id Salah
// Distributed under the MIT License (See accompanying file LICENSE.md file or copy at http://opensource.org/licenses/MIT).
#include "neural/pch.h"
#include "neural/process/training/coNeuralTrainingNet_f.h"
#include "neural/process/training/coNeuralTrainingNet.h"
#include "neural/process/training/coNeuralTrainingLayer.h"
#include "neural/process/training/coNeuralTrainingLayer_f.h"
#include "neural/process/training/coNeuralDataSet.h"
#include "neural/process/training/coNeuralTrainingConfig.h"
#include "neural/process/coNeuralLayer_f.h"
#include "neural/process/coNeuralNet_f.h"
#include "neural/process/coNeuralActivation_f.h"
#include "neural/network/coNeuralNet.h"
#include "neural/network/coNeuralLayer.h"
#include "lang/result/coResult_f.h"

void coComputeForwardPass(coNeuralTrainingNet& _trainingNet, const coArray<coFloat>& _targetInputs)
{
	coArray<coFloat> inputs = _targetInputs;
	for (coNeuralTrainingLayer* trainingLayer : _trainingNet.GetTrainingLayers())
	{
		coComputeOutputs(*trainingLayer->layer, inputs, trainingLayer->outputs);
		inputs = trainingLayer->outputs;
	}
}

void coComputeGradients(coNeuralTrainingNet& _trainingNet, const coArray<coFloat>& _targetOutputs)
{
	const coArray<coNeuralTrainingLayer*>& trainingLayers = _trainingNet.GetTrainingLayers();

	// Last layer
	{
		coNeuralTrainingLayer* trainingLayer = coBack(trainingLayers);
		const coUint nbOutputs = trainingLayer->outputs.count;
		coArray<coFloat>& gradients = trainingLayer->gradients;
		const coArray<coFloat>& values = trainingLayer->outputs;
		for (coUint i = 0; i < nbOutputs; ++i)
		{
			const coFloat value = values[i];
			const coFloat targetValue = _targetOutputs[i];
			const coFloat error = targetValue - value;
			gradients[i] = error * coComputeNeuralActivationDerivativeTransfer(value);
		}
	}

	// Rest of the layers
	for (coInt j = trainingLayers.count - 2; j >= 0; --j)
	{
		coNeuralTrainingLayer* curTrainingLayer = trainingLayers[j];
		coNeuralTrainingLayer* nextTrainingLayer = trainingLayers[j + 1];
		coArray<coFloat>& curGradients = curTrainingLayer->gradients;
		const coArray<coFloat>& nextGradients = nextTrainingLayer->gradients;
		const coArray<coFloat>& curOutputs = curTrainingLayer->outputs;

		const coNeuralLayer* curData = curTrainingLayer->layer;
		const coNeuralLayer* nextData = nextTrainingLayer->layer;
		const coArray<coFloat>& nextWeights = nextData->GetWeightBuffer();
		const coUint nbCurOutputs = curData->GetNbOutputs();
		const coUint nbNextOutputs = nextData->GetNbOutputs();
		for (coUint k = 0; k < nbCurOutputs; ++k)
		{
			coFloat sum = 0.0f;
			for (coUint l = 0; l < nbNextOutputs; ++l)
			{
				const coUint weightIndex = l * nbCurOutputs + k;
				sum += nextGradients.data[l] * nextWeights.data[weightIndex];
			}
			const coFloat output = curOutputs.data[k];
			curGradients.data[k] = sum * coComputeNeuralActivationDerivativeTransfer(output);
		}
	}
}

void coClearForEpoch(coNeuralTrainingNet& _trainingNet)
{
	for (coNeuralTrainingLayer* trainingLayer : _trainingNet.GetTrainingLayers())
	{
		coClearForEpoch(*trainingLayer);
	}
}

void coUpdateWeights(coNeuralTrainingNet& _trainingNet, coFloat _learningRate, coFloat _momentum, const coArray<coFloat>& _inputs)
{
	const coArray<coNeuralTrainingLayer*>& trainingLayers = _trainingNet.GetTrainingLayers();
	coArray<coFloat> layerInputs(_inputs);
	for (coNeuralTrainingLayer* trainingLayer : trainingLayers)
	{
		coNeuralLayer* data = trainingLayer->layer;
		const coUint nbInputs = data->GetNbInputs();
		const coUint nbOutputs = data->GetNbOutputs();
		coArray<coFloat>& biasBuffer = data->GetBiasBuffer();
		coArray<coFloat>& weightBuffer = data->GetWeightBuffer();
		coArray<coFloat>& biasDeltas = trainingLayer->biasDeltas;
		coArray<coFloat>& weightDeltas = trainingLayer->weightDeltas;
		const coArray<coFloat>& gradients = trainingLayer->gradients;

		const coFloat decay = 0.0f;//0.000001f;

		coUint weightIndex = 0;
		for (coUint k = 0; k < nbOutputs; ++k)
		{
			const coFloat gradient = gradients.data[k];

			// Biases
			{
				coFloat& curBias = biasBuffer.data[k];
				coFloat& curDelta = biasDeltas.data[k];
				curDelta = _learningRate * gradient + _momentum * curDelta - decay * _learningRate * curBias;
				curBias += curDelta;
			}

			// Weights
			for (coUint l = 0; l < nbInputs; ++l)
			{
				coFloat& curWeight = weightBuffer.data[weightIndex];
				coFloat& curDelta = weightDeltas.data[weightIndex];
				curDelta = _learningRate * gradient * layerInputs.data[l] + _momentum * curDelta - decay * _learningRate* curWeight;
				curWeight += curDelta;
				++weightIndex;
			}
		}

		layerInputs = trainingLayer->outputs;
	}
}

coFloat coComputeErrorSum(const coNeuralTrainingNet& _trainingNet, const coArray<coFloat>& _targetOutputs)
{
	coFloat error = 0.0f;
	const coArray<coNeuralTrainingLayer*>& trainingLayers = _trainingNet.GetTrainingLayers();
	coNeuralTrainingLayer* lastTrainingLayer = coBack(trainingLayers);
	const coArray<coFloat>& outputs = lastTrainingLayer->outputs;
	coASSERT(outputs.count == _targetOutputs.count);
	const coUint nbOutputs = lastTrainingLayer->outputs.count;
	for (coUint i = 0; i < nbOutputs; ++i)
	{
		error += coPow2(_targetOutputs[i] - outputs[i]);
	}
	return error;
}

coResult coTrain(coNeuralTrainingNet& _trainingNet, const coNeuralDataSet& _dataSet, const coNeuralTrainingConfig& _config, coUint32& _seed)
{
	// References:
	// - "On Large-Batch Training for Deep Learning: Generalization Gap and Sharp Minima" (arXiv:1609.04836).

	coTRY(_config.targetError >= 0.0f, nullptr);

	const coFloat meanSquareErrorTarget = coPow2(_config.targetError);

	//coTRY(learnRate < 1.0f, nullptr);

	coNeuralNet* net = _trainingNet.GetNet();
	coTRY(net, nullptr);

	const coUint nbNetInputs = net->GetNbInputs();
	const coUint nbNetOutputs = net->GetNbOutputs();

	coDynamicArray<coUint> sampleIndices;
	coResize(sampleIndices, _dataSet.nbSamples);
	for (coUint i = 0; i < sampleIndices.count; ++i)
		sampleIndices[i] = i;

#ifdef coDEBUG
	coDynamicArray<coFloat> errors;
	coReserve(errors, _dataSet.nbSamples);
#endif

	// For each epoch
	coFloat err = coFloat_inf;
	coUint nbEpochs = 0;
	do
	{
		coClearForEpoch(_trainingNet);
		coShuffle(sampleIndices, _seed);

		const coUint32 nbTrainingSamples = coUint32(_config.sampleRatio * _dataSet.nbSamples);
		const coUint32 nbValidationSamples = _dataSet.nbSamples - nbTrainingSamples;

		// For each sample
		for (coUint i = 0; i < nbTrainingSamples; ++i)
		{
			const coUint sampleIndex = sampleIndices[i];
			const coArray<coFloat> sampleInputs(_dataSet.inputs.data + sampleIndex * nbNetInputs, nbNetInputs);
			const coArray<coFloat> sampleOutputs(_dataSet.outputs.data + sampleIndex * nbNetOutputs, nbNetOutputs);
			coComputeForwardPass(_trainingNet, sampleInputs);
			coComputeGradients(_trainingNet, sampleOutputs);
			coUpdateWeights(_trainingNet, _config.learningRate, _config.momentum, sampleInputs);
		}

		++nbEpochs;

		// Error
		if (nbEpochs % _config.nbEpochsBeforeValidation == 0 && nbEpochs < _config.maxNbEpochs)
		{
			err = 0.0f;
			for (coUint i = nbTrainingSamples; i < _dataSet.nbSamples; ++i)
			{
				const coUint sampleIndex = sampleIndices[i];
				const coArray<coFloat> sampleInputs(_dataSet.inputs.data + sampleIndex * nbNetInputs, nbNetInputs);
				const coArray<coFloat> sampleOutputs(_dataSet.outputs.data + sampleIndex * nbNetOutputs, nbNetOutputs);
				coComputeForwardPass(_trainingNet, sampleInputs);
				err += coComputeErrorSum(_trainingNet, sampleOutputs);
			}

			coASSERT(nbValidationSamples);
			err /= coFloat(nbValidationSamples * nbNetOutputs);

#ifdef coDEBUG
			coPushBack(errors, err);
#endif
		}

	} while (err > meanSquareErrorTarget && nbEpochs < _config.maxNbEpochs);

	return true;
}
<commit_msg>Fixed validation error.<commit_after>// Copyright(c) 2016 Jounayd Id Salah
// Distributed under the MIT License (See accompanying file LICENSE.md file or copy at http://opensource.org/licenses/MIT).
#include "neural/pch.h"
#include "neural/process/training/coNeuralTrainingNet_f.h"
#include "neural/process/training/coNeuralTrainingNet.h"
#include "neural/process/training/coNeuralTrainingLayer.h"
#include "neural/process/training/coNeuralTrainingLayer_f.h"
#include "neural/process/training/coNeuralDataSet.h"
#include "neural/process/training/coNeuralTrainingConfig.h"
#include "neural/process/coNeuralLayer_f.h"
#include "neural/process/coNeuralNet_f.h"
#include "neural/process/coNeuralActivation_f.h"
#include "neural/network/coNeuralNet.h"
#include "neural/network/coNeuralLayer.h"
#include "lang/result/coResult_f.h"

void coComputeForwardPass(coNeuralTrainingNet& _trainingNet, const coArray<coFloat>& _targetInputs)
{
	coArray<coFloat> inputs = _targetInputs;
	for (coNeuralTrainingLayer* trainingLayer : _trainingNet.GetTrainingLayers())
	{
		coComputeOutputs(*trainingLayer->layer, inputs, trainingLayer->outputs);
		inputs = trainingLayer->outputs;
	}
}

void coComputeGradients(coNeuralTrainingNet& _trainingNet, const coArray<coFloat>& _targetOutputs)
{
	const coArray<coNeuralTrainingLayer*>& trainingLayers = _trainingNet.GetTrainingLayers();

	// Last layer
	{
		coNeuralTrainingLayer* trainingLayer = coBack(trainingLayers);
		const coUint nbOutputs = trainingLayer->outputs.count;
		coArray<coFloat>& gradients = trainingLayer->gradients;
		const coArray<coFloat>& values = trainingLayer->outputs;
		for (coUint i = 0; i < nbOutputs; ++i)
		{
			const coFloat value = values[i];
			const coFloat targetValue = _targetOutputs[i];
			const coFloat error = targetValue - value;
			gradients[i] = error * coComputeNeuralActivationDerivativeTransfer(value);
		}
	}

	// Rest of the layers
	for (coInt j = trainingLayers.count - 2; j >= 0; --j)
	{
		coNeuralTrainingLayer* curTrainingLayer = trainingLayers[j];
		coNeuralTrainingLayer* nextTrainingLayer = trainingLayers[j + 1];
		coArray<coFloat>& curGradients = curTrainingLayer->gradients;
		const coArray<coFloat>& nextGradients = nextTrainingLayer->gradients;
		const coArray<coFloat>& curOutputs = curTrainingLayer->outputs;

		const coNeuralLayer* curData = curTrainingLayer->layer;
		const coNeuralLayer* nextData = nextTrainingLayer->layer;
		const coArray<coFloat>& nextWeights = nextData->GetWeightBuffer();
		const coUint nbCurOutputs = curData->GetNbOutputs();
		const coUint nbNextOutputs = nextData->GetNbOutputs();
		for (coUint k = 0; k < nbCurOutputs; ++k)
		{
			coFloat sum = 0.0f;
			for (coUint l = 0; l < nbNextOutputs; ++l)
			{
				const coUint weightIndex = l * nbCurOutputs + k;
				sum += nextGradients.data[l] * nextWeights.data[weightIndex];
			}
			const coFloat output = curOutputs.data[k];
			curGradients.data[k] = sum * coComputeNeuralActivationDerivativeTransfer(output);
		}
	}
}

void coClearForEpoch(coNeuralTrainingNet& _trainingNet)
{
	for (coNeuralTrainingLayer* trainingLayer : _trainingNet.GetTrainingLayers())
	{
		coClearForEpoch(*trainingLayer);
	}
}

void coUpdateWeights(coNeuralTrainingNet& _trainingNet, coFloat _learningRate, coFloat _momentum, const coArray<coFloat>& _inputs)
{
	const coArray<coNeuralTrainingLayer*>& trainingLayers = _trainingNet.GetTrainingLayers();
	coArray<coFloat> layerInputs(_inputs);
	for (coNeuralTrainingLayer* trainingLayer : trainingLayers)
	{
		coNeuralLayer* data = trainingLayer->layer;
		const coUint nbInputs = data->GetNbInputs();
		const coUint nbOutputs = data->GetNbOutputs();
		coArray<coFloat>& biasBuffer = data->GetBiasBuffer();
		coArray<coFloat>& weightBuffer = data->GetWeightBuffer();
		coArray<coFloat>& biasDeltas = trainingLayer->biasDeltas;
		coArray<coFloat>& weightDeltas = trainingLayer->weightDeltas;
		const coArray<coFloat>& gradients = trainingLayer->gradients;

		const coFloat decay = 0.0f;//0.000001f;

		coUint weightIndex = 0;
		for (coUint k = 0; k < nbOutputs; ++k)
		{
			const coFloat gradient = gradients.data[k];

			// Biases
			{
				coFloat& curBias = biasBuffer.data[k];
				coFloat& curDelta = biasDeltas.data[k];
				curDelta = _learningRate * gradient + _momentum * curDelta - decay * _learningRate * curBias;
				curBias += curDelta;
			}

			// Weights
			for (coUint l = 0; l < nbInputs; ++l)
			{
				coFloat& curWeight = weightBuffer.data[weightIndex];
				coFloat& curDelta = weightDeltas.data[weightIndex];
				curDelta = _learningRate * gradient * layerInputs.data[l] + _momentum * curDelta - decay * _learningRate* curWeight;
				curWeight += curDelta;
				++weightIndex;
			}
		}

		layerInputs = trainingLayer->outputs;
	}
}

coFloat coComputeErrorSum(const coNeuralTrainingNet& _trainingNet, const coArray<coFloat>& _targetOutputs)
{
	coFloat error = 0.0f;
	const coArray<coNeuralTrainingLayer*>& trainingLayers = _trainingNet.GetTrainingLayers();
	coNeuralTrainingLayer* lastTrainingLayer = coBack(trainingLayers);
	const coArray<coFloat>& outputs = lastTrainingLayer->outputs;
	coASSERT(outputs.count == _targetOutputs.count);
	const coUint nbOutputs = lastTrainingLayer->outputs.count;
	for (coUint i = 0; i < nbOutputs; ++i)
	{
		error += coPow2(_targetOutputs[i] - outputs[i]);
	}
	return error;
}

coResult coTrain(coNeuralTrainingNet& _trainingNet, const coNeuralDataSet& _dataSet, const coNeuralTrainingConfig& _config, coUint32& _seed)
{
	// References:
	// - "On Large-Batch Training for Deep Learning: Generalization Gap and Sharp Minima" (arXiv:1609.04836).

	coTRY(_config.targetError >= 0.0f, nullptr);

	const coFloat meanSquareErrorTarget = coPow2(_config.targetError);

	//coTRY(learnRate < 1.0f, nullptr);

	coNeuralNet* net = _trainingNet.GetNet();
	coTRY(net, nullptr);

	const coUint nbNetInputs = net->GetNbInputs();
	const coUint nbNetOutputs = net->GetNbOutputs();

	coDynamicArray<coUint> sampleIndices;
	coResize(sampleIndices, _dataSet.nbSamples);
	for (coUint i = 0; i < sampleIndices.count; ++i)
		sampleIndices[i] = i;

#ifdef coDEBUG
	coDynamicArray<coFloat> errors;
	coReserve(errors, _dataSet.nbSamples);
#endif

	// For each epoch
	coFloat err = coFloat_inf;
	coUint nbEpochs = 0;
	do
	{
		coClearForEpoch(_trainingNet);

		// Shuffle samples
		coShuffle(sampleIndices, _seed);

		const coUint32 nbTrainingSamples = coUint32(_config.sampleRatio * _dataSet.nbSamples);
		const coUint32 nbValidationSamples = _dataSet.nbSamples - nbTrainingSamples;

		// Train
		for (coUint i = 0; i < nbTrainingSamples; ++i)
		{
			const coUint sampleIndex = sampleIndices[i];
			const coArray<coFloat> sampleInputs(_dataSet.inputs.data + sampleIndex * nbNetInputs, nbNetInputs);
			const coArray<coFloat> sampleOutputs(_dataSet.outputs.data + sampleIndex * nbNetOutputs, nbNetOutputs);
			coComputeForwardPass(_trainingNet, sampleInputs);
			coComputeGradients(_trainingNet, sampleOutputs);
			coUpdateWeights(_trainingNet, _config.learningRate, _config.momentum, sampleInputs);
		}

		++nbEpochs;

		// Update validation error
		if (nbEpochs % _config.nbEpochsBeforeValidation == 0 && nbEpochs < _config.maxNbEpochs)
		{
			err = 0.0f;
			for (coUint i = nbTrainingSamples; i < _dataSet.nbSamples; ++i)
			{
				const coUint sampleIndex = sampleIndices[i];
				const coArray<coFloat> sampleInputs(_dataSet.inputs.data + sampleIndex * nbNetInputs, nbNetInputs);
				const coArray<coFloat> sampleOutputs(_dataSet.outputs.data + sampleIndex * nbNetOutputs, nbNetOutputs);
				coComputeForwardPass(_trainingNet, sampleInputs);
				err += coComputeErrorSum(_trainingNet, sampleOutputs);
			}

			coASSERT(nbValidationSamples);
			err /= coFloat(nbValidationSamples);

#ifdef coDEBUG
			coPushBack(errors, err);
#endif
		}

	} while (err > meanSquareErrorTarget && nbEpochs < _config.maxNbEpochs);

	return true;
}
<|endoftext|>


<commit_before>#include "socketutils.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
//BSD socket stuff
#ifndef _WIN32
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netdb.h>
#endif

#ifdef _WIN32
typedef int socklen_t;

struct WSASocketGlobal
{
public:
  bool started,failed;
  WSASocketGlobal() : started(false),failed(false) {}
  ~WSASocketGlobal() {
    if(started) {
      printf("Shutting down the Winsock 2.2 dll\n");
      WSACleanup();
    }
  }
  bool Init() {
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
        /* Tell the user that we could not find a usable */
        /* Winsock DLL.                                  */
        printf("WSAStartup failed with error: %d\n", err);
		failed = true;
        return false;
    }

/* Confirm that the WinSock DLL supports 2.2.*/
/* Note that if the DLL supports versions greater    */
/* than 2.2 in addition to 2.2, it will still return */
/* 2.2 in wVersion since that is the version we      */
/* requested.                                        */

    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        printf("Could not find a usable version of Winsock.dll\n");
        WSACleanup();
		failed = true;
        return false;
    }
    else {
        printf("The Winsock 2.2 dll was found successfully\n");
	started = true;
	return true;
    }
  }
};

static WSASocketGlobal gWSASocketObject;

bool EnsureSocketStarted()
{
  if(gWSASocketObject.failed) return false;
  if(gWSASocketObject.started) return true;
  return gWSASocketObject.Init();
}

#else

bool EnsureSocketStarted() { return true; }

#endif //_WIN32

///Caller must ensure that protocol and host are large enough to handle the
///items.  Simple way of doing this is to allocate to size strlen(addr)
bool ParseAddr(const char* addr,char* protocol,char* host,int& port)
{
  const char* pos=strstr(addr,"://");
  if(pos == NULL) return false;
  //parse protocol
  int spos = pos-addr;
  strncpy(protocol,addr,spos);
  protocol[spos] = 0;
  //parse address and port
  pos += 3;
  spos += 3;
  const char* colonpos = strstr(pos,":");
  if(colonpos==NULL) {
    strcpy(host,pos);
  }
  else {
    strncpy(host,pos,colonpos-pos);
    host[colonpos-pos]=0;
  }
  port = -1;
  //default http port
  if(strcmp(protocol,"http")==0)
    port = 80;
  //default ftp port
  if(strcmp(protocol,"ftp")==0)
    port = 21;

  if(colonpos != NULL) {
    //parse port
    colonpos ++;
    char* endptr;
    long int res = strtol(colonpos,&endptr,0);
    if(res==0 && endptr==colonpos) {
      fprintf(stderr,"ParseAddr: address did not contain valid port\n");
      return false;
    }
    if(res < 0 || res > 0xffff) {
      fprintf(stderr,"ParseAddr: address did not contain valid port\n");
      return false;
    }
    port = (int)res;
  }

  if(port < 0) {
    fprintf(stderr,"ParseAddr: address did not contain valid port\n");
    return false;
  }
  return true;
}

SOCKET Connect(const char* addr)
{
  if(!EnsureSocketStarted()) return INVALID_SOCKET;

  char* protocol = new char[strlen(addr)];
  char* host = new char[strlen(addr)];
  int port;
  if(!ParseAddr(addr,protocol,host,port)) {
    fprintf(stderr,"Connect: Error parsing address %s\n",addr);
    delete [] protocol;
    delete [] host;
    return INVALID_SOCKET;
  }

  struct sockaddr_in serv_addr;
  struct hostent *server;

  int sockettype = SOCK_STREAM;
  if(0==strcmp(protocol,"udp")) {
    sockettype = SOCK_DGRAM;
  }
  delete [] protocol;

  SOCKET sockfd = socket(AF_INET, sockettype, 0);
  if (sockfd == INVALID_SOCKET) {
    fprintf(stderr,"Connect: Error creating socket\n");
    delete [] host;
    return INVALID_SOCKET;
  }
  server = gethostbyname(host);
  if (server == NULL) {
    fprintf(stderr,"Connect: Error, no such host %s:%d\n",host,port);
    CloseSocket(sockfd);
    delete [] host;
    return INVALID_SOCKET;
  }
  memset(&serv_addr, 0, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  memcpy(&serv_addr.sin_addr.s_addr,
	 server->h_addr,
	 server->h_length);
  serv_addr.sin_port = htons(port);

  if (connect(sockfd,(sockaddr*)&serv_addr,sizeof(serv_addr)) < 0) {
    fprintf(stderr,"socketutils.cpp Connect: Connect to server %s:%d failed\n",host,port);
    perror("  Reason");
    CloseSocket(sockfd);
    delete [] host;
    return INVALID_SOCKET;
  }

  return sockfd;
}

SOCKET Bind(const char* addr,bool block)
{
  if(!EnsureSocketStarted()) return INVALID_SOCKET;

  char* protocol = new char[strlen(addr)];
  char* host = new char[strlen(addr)];
  int port;
  if(!ParseAddr(addr,protocol,host,port)) {
    fprintf(stderr,"Error parsing address %s\n",addr);
    delete [] protocol;
    delete [] host;
    return INVALID_SOCKET;
  }

  struct sockaddr_in serv_addr;
  struct hostent *server;

  int sockettype = SOCK_STREAM;
  if(0==strcmp(protocol,"udp")) {
    sockettype = SOCK_DGRAM;
  }
  delete [] protocol;

  SOCKET sockfd = socket(AF_INET, sockettype, 0);
  if (sockfd == INVALID_SOCKET) {
    fprintf(stderr,"socketutils.cpp Bind: Error creating socket\n");
    delete [] host;
    return INVALID_SOCKET;
  }
  if(!block)  {
	  SetNonblock(sockfd);
  }

  server = gethostbyname(host);
  if (server == NULL) {
    fprintf(stderr,"socketutils.cpp Bind: Error, no such host %s:%d\n",host,port);
    CloseSocket(sockfd);
    delete [] host;
    return INVALID_SOCKET;
  }
  memset(&serv_addr, 0, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  memcpy(&serv_addr.sin_addr.s_addr,
	 server->h_addr,
	 server->h_length);
  serv_addr.sin_port = htons(port);

  if (bind(sockfd,(sockaddr*)&serv_addr,sizeof(serv_addr)) < 0) {
    fprintf(stderr,"socketutils.cpp Bind: Bind server to %s:%d failed\n",host,port);
    perror("  Reason");
    CloseSocket(sockfd);
    delete [] host;
    return INVALID_SOCKET ;
  }
  delete [] host;
  return sockfd;
}

SOCKET Accept(SOCKET sockfd)
{
  if(!EnsureSocketStarted()) return INVALID_SOCKET;

  struct sockaddr_in cli_addr;
  socklen_t clilen = sizeof(cli_addr);
  SOCKET clientsocket = accept(sockfd, (struct sockaddr *)&cli_addr,
			    &clilen);
  return clientsocket;
}

SOCKET Accept(SOCKET sockfd,double timeout)
{
  if(!EnsureSocketStarted()) return INVALID_SOCKET;

  fd_set rfds;
  FD_ZERO(&rfds);
  FD_SET(sockfd, &rfds);

  timeval tv;
  double secs = floor(timeout);
  tv.tv_sec = (int)secs;
  tv.tv_usec = (timeout-secs)*1000000;

  int result = select(sockfd + 1, &rfds, (fd_set *) 0, (fd_set *) 0, &tv);
  if(result > 0) {
    struct sockaddr_in cli_addr;
    socklen_t clilen = sizeof(cli_addr);
    SOCKET clientsocket = accept(sockfd, (struct sockaddr *)&cli_addr,
				 &clilen);
    return clientsocket;
  }
  else  {
    if(result < 0) {
      printf("Error using select()\n");
    }
     //always here, even if i connect from another application
    return INVALID_SOCKET;
  }
}

void SetNonblock(SOCKET sockfd,bool enabled)
{
#ifdef _WIN32
	u_long iMode=1;
	if(!enabled) iMode = 0;
	ioctlsocket(sockfd,FIONBIO,&iMode);
#else
	if(enabled)
	  fcntl(sockfd,F_SETFL,FNDELAY);
	else
	  fcntl(sockfd,F_SETFL,0);
#endif //_WIN32
}

void SetNodelay(SOCKET sockfd,bool enabled)
{
  int arg = 1;
  if(!enabled) arg = 1;
  setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &arg, sizeof(arg));
}

void CloseSocket(SOCKET sockfd)
{
#ifdef _WIN32
	shutdown(sockfd,SD_BOTH);
	closesocket(sockfd);
#else
	shutdown(sockfd,SHUT_RDWR);
	close(sockfd);
#endif
}

bool ReadAvailable(SOCKET socketfd)
{
  fd_set fds;
  timeval tv;
  // clear the set ahead of time
  FD_ZERO(&fds);

  // add our descriptors to the set
  FD_SET(socketfd, &fds);

#ifdef _WIN32
  int n = 0; //this parameter is ignored
#else
  int n = socketfd + 1;
#endif

  // wait until either socket has data ready to be recv()d (timeout 10.5 secs)
  tv.tv_sec = 0;
  tv.tv_usec = 0;
  int rv = select(n, &fds, NULL, NULL, &tv);

  if (rv == -1) {
    perror("select"); // error occurred in select()
    return false;
  } else if (rv == 0) {
    return false;
  } else {
    if(FD_ISSET(socketfd, &fds))
      return true;
    else
      printf("ReadAvailable: weird, select returned 1 but the FD set is not set\n");
    return false;
  }
}

bool WriteAvailable(SOCKET socketfd)
{
  fd_set fds;
  timeval tv;
  // clear the set ahead of time
  FD_ZERO(&fds);

  // add our descriptors to the set
  FD_SET(socketfd, &fds);

#ifdef _WIN32
  int n = 0; //this parameter is ignored
#else
  int n = socketfd + 1;
#endif

  // wait until either socket has data ready to be recv()d (timeout 10.5 secs)
  tv.tv_sec = 0;
  tv.tv_usec = 0;
  int rv = select(n, NULL, &fds, NULL, &tv);

  if (rv == -1) {
    perror("select"); // error occurred in select()
    return false;
  } else if (rv == 0) {
    return false;
  } else {
    if(FD_ISSET(socketfd, &fds))
      return true;
    else
      printf("WriteAvailable: weird, select returned 1 but the FD set is not set\n");
    return false;
  }
}

bool HasException(SOCKET socketfd)
{
  fd_set fds;
  timeval tv;
  // clear the set ahead of time
  FD_ZERO(&fds);

  // add our descriptors to the set
  FD_SET(socketfd, &fds);

#ifdef _WIN32
  int n = 0; //this parameter is ignored
#else
  int n = socketfd + 1;
#endif

  // wait until either socket has data ready to be recv()d (timeout 10.5 secs)
  tv.tv_sec = 0;
  tv.tv_usec = 0;
  int rv = select(n, NULL, NULL, &fds, &tv);

  if (rv == -1) {
    perror("select"); // error occurred in select()
    return false;
  } else if (rv == 0) {
    return false;
  } else {
    if(FD_ISSET(socketfd, &fds))
      return true;
    else
      printf("HasException: weird, select returned 1 but the FD set is not set\n");
    return false;
  }
}
<commit_msg>Fixed TCP include for ubuntu<commit_after>#include "socketutils.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
//BSD socket stuff
#ifndef _WIN32
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#endif

#ifdef _WIN32
typedef int socklen_t;

struct WSASocketGlobal
{
public:
  bool started,failed;
  WSASocketGlobal() : started(false),failed(false) {}
  ~WSASocketGlobal() {
    if(started) {
      printf("Shutting down the Winsock 2.2 dll\n");
      WSACleanup();
    }
  }
  bool Init() {
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
        /* Tell the user that we could not find a usable */
        /* Winsock DLL.                                  */
        printf("WSAStartup failed with error: %d\n", err);
		failed = true;
        return false;
    }

/* Confirm that the WinSock DLL supports 2.2.*/
/* Note that if the DLL supports versions greater    */
/* than 2.2 in addition to 2.2, it will still return */
/* 2.2 in wVersion since that is the version we      */
/* requested.                                        */

    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        printf("Could not find a usable version of Winsock.dll\n");
        WSACleanup();
		failed = true;
        return false;
    }
    else {
        printf("The Winsock 2.2 dll was found successfully\n");
	started = true;
	return true;
    }
  }
};

static WSASocketGlobal gWSASocketObject;

bool EnsureSocketStarted()
{
  if(gWSASocketObject.failed) return false;
  if(gWSASocketObject.started) return true;
  return gWSASocketObject.Init();
}

#else

bool EnsureSocketStarted() { return true; }

#endif //_WIN32

///Caller must ensure that protocol and host are large enough to handle the
///items.  Simple way of doing this is to allocate to size strlen(addr)
bool ParseAddr(const char* addr,char* protocol,char* host,int& port)
{
  const char* pos=strstr(addr,"://");
  if(pos == NULL) return false;
  //parse protocol
  int spos = pos-addr;
  strncpy(protocol,addr,spos);
  protocol[spos] = 0;
  //parse address and port
  pos += 3;
  spos += 3;
  const char* colonpos = strstr(pos,":");
  if(colonpos==NULL) {
    strcpy(host,pos);
  }
  else {
    strncpy(host,pos,colonpos-pos);
    host[colonpos-pos]=0;
  }
  port = -1;
  //default http port
  if(strcmp(protocol,"http")==0)
    port = 80;
  //default ftp port
  if(strcmp(protocol,"ftp")==0)
    port = 21;

  if(colonpos != NULL) {
    //parse port
    colonpos ++;
    char* endptr;
    long int res = strtol(colonpos,&endptr,0);
    if(res==0 && endptr==colonpos) {
      fprintf(stderr,"ParseAddr: address did not contain valid port\n");
      return false;
    }
    if(res < 0 || res > 0xffff) {
      fprintf(stderr,"ParseAddr: address did not contain valid port\n");
      return false;
    }
    port = (int)res;
  }

  if(port < 0) {
    fprintf(stderr,"ParseAddr: address did not contain valid port\n");
    return false;
  }
  return true;
}

SOCKET Connect(const char* addr)
{
  if(!EnsureSocketStarted()) return INVALID_SOCKET;

  char* protocol = new char[strlen(addr)];
  char* host = new char[strlen(addr)];
  int port;
  if(!ParseAddr(addr,protocol,host,port)) {
    fprintf(stderr,"Connect: Error parsing address %s\n",addr);
    delete [] protocol;
    delete [] host;
    return INVALID_SOCKET;
  }

  struct sockaddr_in serv_addr;
  struct hostent *server;

  int sockettype = SOCK_STREAM;
  if(0==strcmp(protocol,"udp")) {
    sockettype = SOCK_DGRAM;
  }
  delete [] protocol;

  SOCKET sockfd = socket(AF_INET, sockettype, 0);
  if (sockfd == INVALID_SOCKET) {
    fprintf(stderr,"Connect: Error creating socket\n");
    delete [] host;
    return INVALID_SOCKET;
  }
  server = gethostbyname(host);
  if (server == NULL) {
    fprintf(stderr,"Connect: Error, no such host %s:%d\n",host,port);
    CloseSocket(sockfd);
    delete [] host;
    return INVALID_SOCKET;
  }
  memset(&serv_addr, 0, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  memcpy(&serv_addr.sin_addr.s_addr,
	 server->h_addr,
	 server->h_length);
  serv_addr.sin_port = htons(port);

  if (connect(sockfd,(sockaddr*)&serv_addr,sizeof(serv_addr)) < 0) {
    fprintf(stderr,"socketutils.cpp Connect: Connect to server %s:%d failed\n",host,port);
    perror("  Reason");
    CloseSocket(sockfd);
    delete [] host;
    return INVALID_SOCKET;
  }

  return sockfd;
}

SOCKET Bind(const char* addr,bool block)
{
  if(!EnsureSocketStarted()) return INVALID_SOCKET;

  char* protocol = new char[strlen(addr)];
  char* host = new char[strlen(addr)];
  int port;
  if(!ParseAddr(addr,protocol,host,port)) {
    fprintf(stderr,"Error parsing address %s\n",addr);
    delete [] protocol;
    delete [] host;
    return INVALID_SOCKET;
  }

  struct sockaddr_in serv_addr;
  struct hostent *server;

  int sockettype = SOCK_STREAM;
  if(0==strcmp(protocol,"udp")) {
    sockettype = SOCK_DGRAM;
  }
  delete [] protocol;

  SOCKET sockfd = socket(AF_INET, sockettype, 0);
  if (sockfd == INVALID_SOCKET) {
    fprintf(stderr,"socketutils.cpp Bind: Error creating socket\n");
    delete [] host;
    return INVALID_SOCKET;
  }
  if(!block)  {
	  SetNonblock(sockfd);
  }

  server = gethostbyname(host);
  if (server == NULL) {
    fprintf(stderr,"socketutils.cpp Bind: Error, no such host %s:%d\n",host,port);
    CloseSocket(sockfd);
    delete [] host;
    return INVALID_SOCKET;
  }
  memset(&serv_addr, 0, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  memcpy(&serv_addr.sin_addr.s_addr,
	 server->h_addr,
	 server->h_length);
  serv_addr.sin_port = htons(port);

  if (bind(sockfd,(sockaddr*)&serv_addr,sizeof(serv_addr)) < 0) {
    fprintf(stderr,"socketutils.cpp Bind: Bind server to %s:%d failed\n",host,port);
    perror("  Reason");
    CloseSocket(sockfd);
    delete [] host;
    return INVALID_SOCKET ;
  }
  delete [] host;
  return sockfd;
}

SOCKET Accept(SOCKET sockfd)
{
  if(!EnsureSocketStarted()) return INVALID_SOCKET;

  struct sockaddr_in cli_addr;
  socklen_t clilen = sizeof(cli_addr);
  SOCKET clientsocket = accept(sockfd, (struct sockaddr *)&cli_addr,
			    &clilen);
  return clientsocket;
}

SOCKET Accept(SOCKET sockfd,double timeout)
{
  if(!EnsureSocketStarted()) return INVALID_SOCKET;

  fd_set rfds;
  FD_ZERO(&rfds);
  FD_SET(sockfd, &rfds);

  timeval tv;
  double secs = floor(timeout);
  tv.tv_sec = (int)secs;
  tv.tv_usec = (timeout-secs)*1000000;

  int result = select(sockfd + 1, &rfds, (fd_set *) 0, (fd_set *) 0, &tv);
  if(result > 0) {
    struct sockaddr_in cli_addr;
    socklen_t clilen = sizeof(cli_addr);
    SOCKET clientsocket = accept(sockfd, (struct sockaddr *)&cli_addr,
				 &clilen);
    return clientsocket;
  }
  else  {
    if(result < 0) {
      printf("Error using select()\n");
    }
     //always here, even if i connect from another application
    return INVALID_SOCKET;
  }
}

void SetNonblock(SOCKET sockfd,bool enabled)
{
#ifdef _WIN32
	u_long iMode=1;
	if(!enabled) iMode = 0;
	ioctlsocket(sockfd,FIONBIO,&iMode);
#else
	if(enabled)
	  fcntl(sockfd,F_SETFL,FNDELAY);
	else
	  fcntl(sockfd,F_SETFL,0);
#endif //_WIN32
}

void SetNodelay(SOCKET sockfd,bool enabled)
{
  int arg = 1;
  if(!enabled) arg = 1;
  setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &arg, sizeof(arg));
}

void CloseSocket(SOCKET sockfd)
{
#ifdef _WIN32
	shutdown(sockfd,SD_BOTH);
	closesocket(sockfd);
#else
	shutdown(sockfd,SHUT_RDWR);
	close(sockfd);
#endif
}

bool ReadAvailable(SOCKET socketfd)
{
  fd_set fds;
  timeval tv;
  // clear the set ahead of time
  FD_ZERO(&fds);

  // add our descriptors to the set
  FD_SET(socketfd, &fds);

#ifdef _WIN32
  int n = 0; //this parameter is ignored
#else
  int n = socketfd + 1;
#endif

  // wait until either socket has data ready to be recv()d (timeout 10.5 secs)
  tv.tv_sec = 0;
  tv.tv_usec = 0;
  int rv = select(n, &fds, NULL, NULL, &tv);

  if (rv == -1) {
    perror("select"); // error occurred in select()
    return false;
  } else if (rv == 0) {
    return false;
  } else {
    if(FD_ISSET(socketfd, &fds))
      return true;
    else
      printf("ReadAvailable: weird, select returned 1 but the FD set is not set\n");
    return false;
  }
}

bool WriteAvailable(SOCKET socketfd)
{
  fd_set fds;
  timeval tv;
  // clear the set ahead of time
  FD_ZERO(&fds);

  // add our descriptors to the set
  FD_SET(socketfd, &fds);

#ifdef _WIN32
  int n = 0; //this parameter is ignored
#else
  int n = socketfd + 1;
#endif

  // wait until either socket has data ready to be recv()d (timeout 10.5 secs)
  tv.tv_sec = 0;
  tv.tv_usec = 0;
  int rv = select(n, NULL, &fds, NULL, &tv);

  if (rv == -1) {
    perror("select"); // error occurred in select()
    return false;
  } else if (rv == 0) {
    return false;
  } else {
    if(FD_ISSET(socketfd, &fds))
      return true;
    else
      printf("WriteAvailable: weird, select returned 1 but the FD set is not set\n");
    return false;
  }
}

bool HasException(SOCKET socketfd)
{
  fd_set fds;
  timeval tv;
  // clear the set ahead of time
  FD_ZERO(&fds);

  // add our descriptors to the set
  FD_SET(socketfd, &fds);

#ifdef _WIN32
  int n = 0; //this parameter is ignored
#else
  int n = socketfd + 1;
#endif

  // wait until either socket has data ready to be recv()d (timeout 10.5 secs)
  tv.tv_sec = 0;
  tv.tv_usec = 0;
  int rv = select(n, NULL, NULL, &fds, &tv);

  if (rv == -1) {
    perror("select"); // error occurred in select()
    return false;
  } else if (rv == 0) {
    return false;
  } else {
    if(FD_ISSET(socketfd, &fds))
      return true;
    else
      printf("HasException: weird, select returned 1 but the FD set is not set\n");
    return false;
  }
}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id: map.hpp 39 2005-04-10 20:39:53Z pavlenko $

#ifndef MAP_HPP
#define MAP_HPP

#include <mapnik/feature_type_style.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/layer.hpp>

namespace mapnik
{
    class MAPNIK_DECL Map
    {
        static const unsigned MIN_MAPSIZE=16;
        static const unsigned MAX_MAPSIZE=2048;
        unsigned width_;
        unsigned height_;
        std::string  srs_;
        boost::optional<Color> background_;
        std::map<std::string,feature_type_style> styles_;
        std::vector<Layer> layers_;
        Envelope<double> currentExtent_;

    public:
        typedef std::map<std::string,feature_type_style>::const_iterator const_style_iterator;
        typedef std::map<std::string,feature_type_style>::iterator style_iterator;

        /*! \brief Default constructor.
         *
         *  Creates a map with these parameters:
         *  - width = 400
         *  - height = 400
         *  - projection = "+proj=latlong +datum=WGS84"
         */
        Map();

        /*! \brief Constructor
         *  @param width Initial map width.
         *  @param height Initial map height.
         *  @param srs Initial map projection.
         */
        Map(int width, int height, std::string const& srs="+proj=latlong +datum=WGS84");

        /*! \brief Copy Constructur.
         *
         *  @param rhs Map to copy from.
         */
        Map(const Map& rhs);

        /*! \brief Assignment operator
         *
         *  TODO: to be documented
         *
         */
        Map& operator=(const Map& rhs);

        /*! \brief Get first iterator in styles.
         *  @return Constant style iterator.
         */
        const_style_iterator begin_styles() const;

        /*! \brief Get last iterator in styles.
         *  @return Constant style iterator.
         */
        const_style_iterator end_styles() const;

        /*! \brief Get first iterator in styles.
         *  @return Non-constant style iterator.
         */
        style_iterator begin_styles();

        /*! \brief Get last iterator in styles.
         *  @return Non-constant style iterator.
         */
        style_iterator end_styles();

        /*! \brief Insert a style in the map.
         *  @param name The name of the style.
         *  @param style The style to insert.
         *  @return true If success.
         *  @return false If no success.
         */
        bool insert_style(std::string const& name,feature_type_style const& style);

        /*! \brief Remove a style from the map.
         *  @param The name of the style.
         */
        void remove_style(const std::string& name);

        /*! \brief Find a style.
         * @param name The name of the style.
         *  @return The style if found. If not found return the default map style.
         */
        feature_type_style const& find_style(std::string const& name) const;

        /*! \brief Get number of all layers.
         */
        size_t layerCount() const;

        /*! \brief Add a layer to the map.
         *  @param l The layer to add.
         */
        void addLayer(const Layer& l);

        /*! \brief Get a layer.
         *  @param index Layer number.
         *  @return Constant layer.
         */
        const Layer& getLayer(size_t index) const;

        /*! \brief Get a layer.
         *  @param index Layer number.
         *  @return Non-constant layer.
         */
        Layer& getLayer(size_t index);

        /*! \brief Remove a layer.
         *  @param index Layer number.
         */
        void removeLayer(size_t index);

        /*! \brief Get all layers.
         *  @return Constant layers.
         */
        std::vector<Layer> const& layers() const;

        /*! \brief Get all layers.
         *  @return Non-constant layers.
         */
        std::vector<Layer> & layers();

        /*! \brief Remove all layers and styles from the map.
         */
        void remove_all();

        /*! \brief Get map width.
         */
        unsigned getWidth() const;

        /*! \brief Get map height.
         */
        unsigned getHeight() const;

        /*! \brief Set map width.
         */
        void setWidth(unsigned width);

        /*! \brief Set map height.
         */
        void setHeight(unsigned height);

        /*! \brief Resize the map.
         */
        void resize(unsigned width,unsigned height);

        /*! \brief Get the map projection.
         *  @return Map projection.
         */
        std::string const& srs() const;

        /*! \brief Set the map projection.
         *  @param srs Map projection.
         */
        void set_srs(std::string const& srs);

        /*! \brief Set the map background color.
         *  @param c Background color.
         */
        void setBackground(const Color& c);

        /*! \brief Get the map background color.
         *  @return Background color.
         */
        const Color& getBackground() const;

        /*! \brief Zoom the map at the current position.
         *  @param factor The factor how much the map is zoomed in or out.
         */
        void zoom(double factor);

        /*! \brief Zoom the map to a bounding box.
         *
         *  Aspect is handled automatic if not fitting to width/height.
         *  @param box The bounding box where to zoom.
         */
        void zoomToBox(const Envelope<double>& box);

        /*! \brief Zoom the map to show all data.
         */
        void zoom_all();

        void pan(int x,int y);

        void pan_and_zoom(int x,int y,double zoom);

        /*! \brief Get current bounding box.
         *  @return The current bounding box.
         */
        const Envelope<double>& getCurrentExtent() const;

        double scale() const;

        CoordTransform view_transform() const;

        featureset_ptr query_point(unsigned index, double x, double y) const;

        featureset_ptr query_map_point(unsigned index, double x, double y) const;
        ~Map();
    private:
        void fixAspectRatio();
    };
}

#endif //MAP_HPP
<commit_msg>applied changes overwritten betweed r504-505  <commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id: map.hpp 39 2005-04-10 20:39:53Z pavlenko $

#ifndef MAP_HPP
#define MAP_HPP

#include <mapnik/feature_type_style.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/layer.hpp>
#include <boost/optional/optional.hpp>

namespace mapnik
{
    class MAPNIK_DECL Map
    {
        static const unsigned MIN_MAPSIZE=16;
        static const unsigned MAX_MAPSIZE=MIN_MAPSIZE<<10;
        unsigned width_;
        unsigned height_;
        std::string  srs_;
        boost::optional<Color> background_;
        std::map<std::string,feature_type_style> styles_;
        std::vector<Layer> layers_;
        Envelope<double> currentExtent_;

    public:
        typedef std::map<std::string,feature_type_style>::const_iterator const_style_iterator;
        typedef std::map<std::string,feature_type_style>::iterator style_iterator;

        /*! \brief Default constructor.
         *
         *  Creates a map with these parameters:
         *  - width = 400
         *  - height = 400
         *  - projection = "+proj=latlong +datum=WGS84"
         */
        Map();

        /*! \brief Constructor
         *  @param width Initial map width.
         *  @param height Initial map height.
         *  @param srs Initial map projection.
         */
        Map(int width, int height, std::string const& srs="+proj=latlong +datum=WGS84");

        /*! \brief Copy Constructur.
         *
         *  @param rhs Map to copy from.
         */
        Map(const Map& rhs);

        /*! \brief Assignment operator
         *
         *  TODO: to be documented
         *
         */
        Map& operator=(const Map& rhs);

        /*! \brief Get all style names
         * @return Const reference to styles
         */
        std::map<std::string,feature_type_style> const& styles() const;

        /*! \brief Get all style names
         * @return Non-constant reference to styles
         */
        std::map<std::string,feature_type_style> & styles();

        /*! \brief Get first iterator in styles.
         *  @return Constant style iterator.
         */
        const_style_iterator begin_styles() const;

        /*! \brief Get last iterator in styles.
         *  @return Constant style iterator.
         */
        const_style_iterator end_styles() const;

        /*! \brief Get first iterator in styles.
         *  @return Non-constant style iterator.
         */
        style_iterator begin_styles();

        /*! \brief Get last iterator in styles.
         *  @return Non-constant style iterator.
         */
        style_iterator end_styles();

        /*! \brief Insert a style in the map.
         *  @param name The name of the style.
         *  @param style The style to insert.
         *  @return true If success.
         *  @return false If no success.
         */
        bool insert_style(std::string const& name,feature_type_style const& style);

        /*! \brief Remove a style from the map.
         *  @param The name of the style.
         */
        void remove_style(const std::string& name);

        /*! \brief Find a style.
         * @param name The name of the style.
         *  @return The style if found. If not found return the default map style.
         */
        feature_type_style const& find_style(std::string const& name) const;

        /*! \brief Get number of all layers.
         */
        size_t layerCount() const;

        /*! \brief Add a layer to the map.
         *  @param l The layer to add.
         */
        void addLayer(const Layer& l);

        /*! \brief Get a layer.
         *  @param index Layer number.
         *  @return Constant layer.
         */
        const Layer& getLayer(size_t index) const;

        /*! \brief Get a layer.
         *  @param index Layer number.
         *  @return Non-constant layer.
         */
        Layer& getLayer(size_t index);

        /*! \brief Remove a layer.
         *  @param index Layer number.
         */
        void removeLayer(size_t index);

        /*! \brief Get all layers.
         *  @return Constant layers.
         */
        std::vector<Layer> const& layers() const;

        /*! \brief Get all layers.
         *  @return Non-constant layers.
         */
        std::vector<Layer> & layers();

        /*! \brief Remove all layers and styles from the map.
         */
        void remove_all();

        /*! \brief Get map width.
         */
        unsigned getWidth() const;

        /*! \brief Get map height.
         */
        unsigned getHeight() const;

        /*! \brief Set map width.
         */
        void setWidth(unsigned width);

        /*! \brief Set map height.
         */
        void setHeight(unsigned height);

        /*! \brief Resize the map.
         */
        void resize(unsigned width,unsigned height);

        /*! \brief Get the map projection.
         *  @return Map projection.
         */
        std::string const& srs() const;

        /*! \brief Set the map projection.
         *  @param srs Map projection.
         */
        void set_srs(std::string const& srs);

        /*! \brief Set the map background color.
         *  @param c Background color.
         */
        void set_background(const Color& c);

        /*! \brief Get the map background color
         *  @return Background color as boost::optional
         *  object
         */
        boost::optional<Color> const& background() const;

        /*! \brief Zoom the map at the current position.
         *  @param factor The factor how much the map is zoomed in or out.
         */
        void zoom(double factor);

        /*! \brief Zoom the map to a bounding box.
         *
         *  Aspect is handled automatic if not fitting to width/height.
         *  @param box The bounding box where to zoom.
         */
        void zoomToBox(const Envelope<double>& box);

        /*! \brief Zoom the map to show all data.
         */
        void zoom_all();

        void pan(int x,int y);

        void pan_and_zoom(int x,int y,double zoom);

        /*! \brief Get current bounding box.
         *  @return The current bounding box.
         */
        const Envelope<double>& getCurrentExtent() const;

        double scale() const;

        CoordTransform view_transform() const;

        featureset_ptr query_point(unsigned index, double x, double y) const;

        featureset_ptr query_map_point(unsigned index, double x, double y) const;
        ~Map();
    private:
        void fixAspectRatio();
    };
}

#endif //MAP_HPP
<|endoftext|>


<commit_before>/*
Copyright (C) 2016 - Gbor "Razzie" Grzsny

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
*/

#pragma once

#include <mutex>
#include <type_traits>
#include "raz/bitset.hpp"

namespace raz
{
	class IMemoryPool
	{
	public:
		virtual ~IMemoryPool() = default;
		virtual void* allocate(size_t bytes) = 0;
		virtual void  deallocate(void* ptr, size_t bytes) = 0;
		virtual size_t getFreeMemory() const = 0;
		virtual size_t getUsedMemory() const = 0;
	};

	template<size_t SIZE, size_t ALIGNMENT = 128, class Mutex = std::mutex>
	class MemoryPool : public IMemoryPool
	{
		static_assert(SIZE % ALIGNMENT == 0, "Incorrect alignment");

	public:
		MemoryPool() = default;
		MemoryPool(const MemoryPool&) = delete;
		~MemoryPool() = default;

		MemoryPool& operator=(const MemoryPool&) = delete;

		virtual void* allocate(size_t bytes)
		{
			std::lock_guard<Lock> guard(m_lock);

			auto available = m_chunks.falsebits();
			auto begin_iter = available.begin();
			auto end_iter = available.end();

			if (begin_iter == end_iter)
				throw std::bad_alloc();

			const size_t chunks = ((bytes - 1) / ALIGNMENT) + 1;
			size_t current_chunk_pos = *begin_iter;
			size_t current_chunk_size = 0;

			for (auto iter = begin_iter; iter != end_iter; ++iter)
			{
				if (*iter == current_chunk_pos + current_chunk_size)
				{
					++current_chunk_size;
					if (current_chunk_size == chunks)
					{
						for (size_t i = current_chunk_pos; i < current_chunk_pos + current_chunk_size; ++i)
						{
							m_chunks.set(i);
						}
						return m_memory + (current_chunk_pos * ALIGNMENT);
					}
				}
				else
				{
					current_chunk_pos = *iter;
					current_chunk_size = 1;
				}
			}

			throw std::bad_alloc();
		}

		virtual void deallocate(void* ptr, size_t bytes)
		{
			std::lock_guard<Lock> guard(m_lock);

			const size_t chunks = ((bytes - 1) / ALIGNMENT) + 1;
			const size_t starting_chunk = (static_cast<char*>(ptr) - m_memory) / ALIGNMENT;

			for (size_t i = starting_chunk; i < starting_chunk + chunks; ++i)
			{
				m_chunks.unset(i);
			}
		}

		virtual size_t getFreeMemory() const
		{
			return (m_chunks.falsebits().count() * ALIGNMENT);
		}

		virtual size_t getUsedMemory() const
		{
			return (m_chunks.truebits().count() * ALIGNMENT);
		}

	private:
		struct DummyMutex
		{
			void lock() {};
			void unlock() {};
		};

		typedef std::conditional_t<std::is_same<Mutex, void>::value, DummyMutex, Mutex> Lock;

		Bitset<SIZE / ALIGNMENT> m_chunks;
		Lock m_lock;
		char m_memory[SIZE];
	};

	template<class T>
	class Allocator
	{
	public:
		typedef T value_type;

		template<class U>
		struct rebind
		{
			typedef Allocator<U> other;
		};

		Allocator(IMemoryPool* memory = nullptr) : m_memory(memory)
		{
		}

		template<class U>
		Allocator(const Allocator<U>& other) : m_memory(other.m_memory)
		{
		}

		Allocator& operator=(const Allocator&) = delete;

		T* allocate(size_t n)
		{
			if (m_memory)
				return reinterpret_cast<T*>(m_memory->allocate(n * sizeof(T)));
			else
				return reinterpret_cast<T*>(::operator new(n * sizeof(T)));
		}

		void deallocate(T* ptr, size_t n)
		{
			if (m_memory)
				m_memory->deallocate(ptr, n * sizeof(T));
			else
				delete reinterpret_cast<void*>(ptr);
		}

		IMemoryPool* getMemoryPool() const
		{
			return m_memory;
		}

		template<class U>
		bool operator==(const Allocator<U>& other) const
		{
			return (m_memory == other.m_memory);
		}

		template<class U>
		bool operator!=(const Allocator<U>& other) const
		{
			return (m_memory != other.m_memory);
		}

	private:
		mutable IMemoryPool* m_memory;

		template<class U>
		friend class Allocator;
	};

	namespace literal
	{
		constexpr unsigned long long operator"" _KB(unsigned long long size)
		{
			return (size * 1024);
		}

		constexpr unsigned long long operator"" _MB(unsigned long long size)
		{
			return (size * 1024_KB);
		}

		constexpr unsigned long long operator"" _GB(unsigned long long size)
		{
			return (size * 1024_MB);
		}
	}
}
<commit_msg>Added create and destroy functions to IMemoryPool<commit_after>/*
Copyright (C) 2016 - Gbor "Razzie" Grzsny

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
*/

#pragma once

#include <mutex>
#include <type_traits>
#include "raz/bitset.hpp"

namespace raz
{
	class IMemoryPool
	{
	public:
		virtual ~IMemoryPool() = default;
		virtual void* allocate(size_t bytes) = 0;
		virtual void  deallocate(void* ptr, size_t bytes) = 0;
		virtual size_t getFreeMemory() const = 0;
		virtual size_t getUsedMemory() const = 0;

		template<class T, class... Args>
		T* create(Args... args)
		{
			raz::Allocator<T> alloc(this);
			T* t = std::allocator_traits<raz::Allocator<T>>::allocate(alloc, 1);
			std::allocator_traits<raz::Allocator<T>>::construct(alloc, t, std::forward<Args>(args)...);
			return t;
		}

		template<class T>
		void destroy(T* t)
		{
			raz::Allocator<T> alloc(this);
			std::allocator_traits<raz::Allocator<T>>::destroy(alloc, t);
			std::allocator_traits<raz::Allocator<T>>::deallocate(alloc, t, 1);
		}
	};

	template<size_t SIZE, size_t ALIGNMENT = 128, class Mutex = std::mutex>
	class MemoryPool : public IMemoryPool
	{
		static_assert(SIZE % ALIGNMENT == 0, "Incorrect alignment");

	public:
		MemoryPool() = default;
		MemoryPool(const MemoryPool&) = delete;
		~MemoryPool() = default;

		MemoryPool& operator=(const MemoryPool&) = delete;

		virtual void* allocate(size_t bytes)
		{
			std::lock_guard<Lock> guard(m_lock);

			auto available = m_chunks.falsebits();
			auto begin_iter = available.begin();
			auto end_iter = available.end();

			if (begin_iter == end_iter)
				throw std::bad_alloc();

			const size_t chunks = ((bytes - 1) / ALIGNMENT) + 1;
			size_t current_chunk_pos = *begin_iter;
			size_t current_chunk_size = 0;

			for (auto iter = begin_iter; iter != end_iter; ++iter)
			{
				if (*iter == current_chunk_pos + current_chunk_size)
				{
					++current_chunk_size;
					if (current_chunk_size == chunks)
					{
						for (size_t i = current_chunk_pos; i < current_chunk_pos + current_chunk_size; ++i)
						{
							m_chunks.set(i);
						}
						return m_memory + (current_chunk_pos * ALIGNMENT);
					}
				}
				else
				{
					current_chunk_pos = *iter;
					current_chunk_size = 1;
				}
			}

			throw std::bad_alloc();
		}

		virtual void deallocate(void* ptr, size_t bytes)
		{
			std::lock_guard<Lock> guard(m_lock);

			const size_t chunks = ((bytes - 1) / ALIGNMENT) + 1;
			const size_t starting_chunk = (static_cast<char*>(ptr) - m_memory) / ALIGNMENT;

			for (size_t i = starting_chunk; i < starting_chunk + chunks; ++i)
			{
				m_chunks.unset(i);
			}
		}

		virtual size_t getFreeMemory() const
		{
			return (m_chunks.falsebits().count() * ALIGNMENT);
		}

		virtual size_t getUsedMemory() const
		{
			return (m_chunks.truebits().count() * ALIGNMENT);
		}

	private:
		struct DummyMutex
		{
			void lock() {};
			void unlock() {};
		};

		typedef std::conditional_t<std::is_same<Mutex, void>::value, DummyMutex, Mutex> Lock;

		Bitset<SIZE / ALIGNMENT> m_chunks;
		Lock m_lock;
		char m_memory[SIZE];
	};

	template<class T>
	class Allocator
	{
	public:
		typedef T value_type;

		template<class U>
		struct rebind
		{
			typedef Allocator<U> other;
		};

		Allocator(IMemoryPool* memory = nullptr) : m_memory(memory)
		{
		}

		template<class U>
		Allocator(const Allocator<U>& other) : m_memory(other.m_memory)
		{
		}

		Allocator& operator=(const Allocator&) = delete;

		T* allocate(size_t n)
		{
			if (m_memory)
				return reinterpret_cast<T*>(m_memory->allocate(n * sizeof(T)));
			else
				return reinterpret_cast<T*>(::operator new(n * sizeof(T)));
		}

		void deallocate(T* ptr, size_t n)
		{
			if (m_memory)
				m_memory->deallocate(ptr, n * sizeof(T));
			else
				delete reinterpret_cast<void*>(ptr);
		}

		IMemoryPool* getMemoryPool() const
		{
			return m_memory;
		}

		template<class U>
		bool operator==(const Allocator<U>& other) const
		{
			return (m_memory == other.m_memory);
		}

		template<class U>
		bool operator!=(const Allocator<U>& other) const
		{
			return (m_memory != other.m_memory);
		}

	private:
		mutable IMemoryPool* m_memory;

		template<class U>
		friend class Allocator;
	};

	namespace literal
	{
		constexpr unsigned long long operator"" _KB(unsigned long long size)
		{
			return (size * 1024);
		}

		constexpr unsigned long long operator"" _MB(unsigned long long size)
		{
			return (size * 1024_KB);
		}

		constexpr unsigned long long operator"" _GB(unsigned long long size)
		{
			return (size * 1024_MB);
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright (C) 2016 - Gbor "Razzie" Grzsny

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
*/

#pragma once

#include <exception>
#include <functional>
#include <future>
#include <mutex>
#include <thread>
#include <vector>
#include "raz/memory.hpp"

namespace raz
{
	struct ThreadStop
	{
	};

	template<class T>
	class Thread
	{
	public:
		// please note that IMemoryPool must be thread-safe
		Thread(IMemoryPool* memory = nullptr) :
			m_memory(memory),
			m_call_queue(memory)
		{
		}

		Thread(const Thread&) = delete;

		Thread& operator=(const Thread&) = delete;

		~Thread()
		{
			if (m_thread.joinable())
			{
				m_exit_token.set_value();
				m_thread.join();
			}
		}

		template<class... Args>
		std::future<void> start(Args... args)
		{
			std::lock_guard<std::mutex> guard(m_mutex);

			if (m_thread.joinable())
			{
				m_exit_token.set_value();
				m_thread.join();
			}

			m_exit_token = std::move(std::promise<void>());
			m_thread = std::thread(&Thread<T>::run<Args...>, this, std::forward<Args>(args)...);
			m_thread_end = std::move(std::promise<void>());
			return m_thread_end.get_future();
		}

		void stop()
		{
			std::lock_guard<std::mutex> guard(m_mutex);

			if (m_thread.joinable())
			{
				m_exit_token.set_value();
				m_thread.join();
			}
		}

		void clear()
		{
			std::lock_guard<std::mutex> guard(m_mutex);
			m_call_queue.clear();
		}

		template<class... Args>
		void operator()(Args... args)
		{
			std::lock_guard<std::mutex> guard(m_mutex);
			m_call_queue.emplace_back(std::allocator_arg, raz::Allocator<char>(m_memory), [args...](T& object) { object(args...); });
		}

	private:
		typedef std::function<void(T&)> ForwardedCall;
		typedef std::vector<ForwardedCall, raz::Allocator<ForwardedCall>> ForwardedCallQueue;

		IMemoryPool* m_memory;
		std::thread m_thread;
		std::promise<void> m_exit_token;
		std::promise<void> m_thread_end;
		std::mutex m_mutex;
		ForwardedCallQueue m_call_queue;

		template<class... Args>
		class OpCaller
		{
			template<class U>
			static auto test(bool) -> decltype(std::declval<U>()(std::declval<Args>()...), void(), std::true_type{})
			{
				return {};
			}

			template<class U>
			static auto test(int) -> std::false_type
			{
				return {};
			}

			static constexpr bool has_parenthesis_op = decltype(test<T>(true))::value;

			template<bool value>
			static std::enable_if_t<value> _call(T& object, Args... args)
			{
				object(std::forward<Args>(args)...);
			}

			template<int value>
			static std::enable_if_t<!value> _call(T& object, Args... args)
			{
			}

		public:
			static void call(T& object, Args... args)
			{
				_call<has_parenthesis_op>(object, std::forward<Args>(args)...);
			}
		};

		template<class... Args>
		void run(Args... args)
		{
			try
			{
				T object(std::forward<Args>(args)...);

				std::future<void> exit_token = m_exit_token.get_future();
				ForwardedCallQueue call_queue(m_memory);

				for (;;)
				{
					m_mutex.lock();
					std::swap(m_call_queue, call_queue);
					m_mutex.unlock();

					for (auto& call : call_queue)
					{
						try
						{
							call(object);
						}
						catch (ThreadStop)
						{
							m_thread_end.set_value();
							return;
						}
						catch (std::exception& e)
						{
							OpCaller<std::exception&>::call(object, e);
						}
						catch (...)
						{
							OpCaller<std::exception_ptr>::call(object, std::current_exception());
						}
					}

					call_queue.clear();

					try
					{
						OpCaller<>::call(object);
					}
					catch (ThreadStop)
					{
						m_thread_end.set_value();
						return;
					}
					catch (std::exception& e)
					{
						OpCaller<std::exception&>::call(object, e);
					}
					catch (...)
					{
						OpCaller<std::exception_ptr>::call(object, std::current_exception());
					}

					auto exit_status = exit_token.wait_for(std::chrono::milliseconds(1));
					if (exit_status == std::future_status::ready)
					{
						m_thread_end.set_value();
						return;
					}
				}
			}
			catch (...)
			{
				m_thread_end.set_exception(std::current_exception());
			}
		}
	};
}
<commit_msg>Better usage of memory pool in thread<commit_after>/*
Copyright (C) 2016 - Gbor "Razzie" Grzsny

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
*/

#pragma once

#include <exception>
#include <functional>
#include <future>
#include <mutex>
#include <thread>
#include <vector>
#include "raz/memory.hpp"

namespace raz
{
	struct ThreadStop
	{
	};

	template<class T>
	class Thread
	{
	public:
		// please note that IMemoryPool must be thread-safe
		Thread(IMemoryPool* memory = nullptr) :
			m_memory(memory),
			m_exit_token(std::allocator_arg, raz::Allocator<int>(memory)),
			m_thread_result(std::allocator_arg, raz::Allocator<int>(memory)),
			m_call_queue(memory)
		{
		}

		Thread(const Thread&) = delete;

		Thread& operator=(const Thread&) = delete;

		~Thread()
		{
			if (m_thread.joinable())
			{
				m_exit_token.set_value();
				m_thread.join();
			}
		}

		template<class... Args>
		std::future<void> start(Args... args)
		{
			std::lock_guard<std::mutex> guard(m_mutex);

			if (m_thread.joinable())
			{
				m_exit_token.set_value();
				m_thread.join();
			}

			m_exit_token = std::move(std::promise<void>(std::allocator_arg, raz::Allocator<int>(m_memory)));
			m_thread_result = std::move(std::promise<void>(std::allocator_arg, raz::Allocator<int>(m_memory)));
			m_thread = std::thread(&Thread<T>::run<Args...>, this, std::forward<Args>(args)...);
			return m_thread_result.get_future();
		}

		void stop()
		{
			std::lock_guard<std::mutex> guard(m_mutex);

			if (m_thread.joinable())
			{
				m_exit_token.set_value();
				m_thread.join();
			}
		}

		void clear()
		{
			std::lock_guard<std::mutex> guard(m_mutex);
			m_call_queue.clear();
		}

		template<class... Args>
		void operator()(Args... args)
		{
			std::lock_guard<std::mutex> guard(m_mutex);
			m_call_queue.emplace_back(std::allocator_arg, raz::Allocator<char>(m_memory), [args...](T& object) { object(args...); });
		}

	private:
		typedef std::function<void(T&)> ForwardedCall;
		typedef std::vector<ForwardedCall, raz::Allocator<ForwardedCall>> ForwardedCallQueue;

		IMemoryPool* m_memory;
		std::thread m_thread;
		std::promise<void> m_exit_token;
		std::promise<void> m_thread_result;
		std::mutex m_mutex;
		ForwardedCallQueue m_call_queue;

		template<class... Args>
		class OpCaller
		{
			template<class U>
			static auto test(bool) -> decltype(std::declval<U>()(std::declval<Args>()...), void(), std::true_type{})
			{
				return {};
			}

			template<class U>
			static auto test(int) -> std::false_type
			{
				return {};
			}

			static constexpr bool has_parenthesis_op = decltype(test<T>(true))::value;

			template<bool value>
			static std::enable_if_t<value> _call(T& object, Args... args)
			{
				object(std::forward<Args>(args)...);
			}

			template<int value>
			static std::enable_if_t<!value> _call(T& object, Args... args)
			{
			}

		public:
			static void call(T& object, Args... args)
			{
				_call<has_parenthesis_op>(object, std::forward<Args>(args)...);
			}
		};

		template<class... Args>
		void run(Args... args)
		{
			try
			{
				T object(std::forward<Args>(args)...);

				std::future<void> exit_token = m_exit_token.get_future();
				ForwardedCallQueue call_queue(m_memory);

				for (;;)
				{
					m_mutex.lock();
					std::swap(m_call_queue, call_queue);
					m_mutex.unlock();

					for (auto& call : call_queue)
					{
						try
						{
							call(object);
						}
						catch (ThreadStop)
						{
							m_thread_result.set_value();
							return;
						}
						catch (std::exception& e)
						{
							OpCaller<std::exception&>::call(object, e);
						}
						catch (...)
						{
							OpCaller<std::exception_ptr>::call(object, std::current_exception());
						}
					}

					call_queue.clear();

					try
					{
						OpCaller<>::call(object);
					}
					catch (ThreadStop)
					{
						m_thread_result.set_value();
						return;
					}
					catch (std::exception& e)
					{
						OpCaller<std::exception&>::call(object, e);
					}
					catch (...)
					{
						OpCaller<std::exception_ptr>::call(object, std::current_exception());
					}

					auto exit_status = exit_token.wait_for(std::chrono::milliseconds(1));
					if (exit_status == std::future_status::ready)
					{
						m_thread_result.set_value();
						return;
					}
				}
			}
			catch (...)
			{
				m_thread_result.set_exception(std::current_exception());
			}
		}
	};
}
<|endoftext|>


<commit_before>/*
 * 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 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2013 Shell Hu
 * Copyright (C) 2013 Shell Hu
 */

#include <shogun/structure/FactorGraph.h>

using namespace shogun;

CFactorGraph::CFactorGraph()
{
	SG_UNSTABLE("CFactorGraph::CFactorGraph()", "\n");

	register_parameters();
}

CFactorGraph::CFactorGraph(SGVector<int32_t> card)
	: m_cardinalities(card)
{
	register_parameters();
}

CFactorGraph::CFactorGraph(const CFactorGraph &fg)
{
	register_parameters();
	m_cardinalities = fg.get_cardinalities();
	// No need to unref and ref in this case
	// TODO test if need to copy element by element
	m_factors = fg.get_factors();
	m_datasources = fg.get_factor_data_sources();
}

CFactorGraph::~CFactorGraph()
{
	SG_UNREF(m_factors);
	SG_UNREF(m_datasources);

	if (m_factors != NULL)
		SG_DEBUG("CFactorGraph::~CFactorGraph(): m_factors->ref_count() = %d.\n", m_factors->ref_count());

	if (m_datasources != NULL)
		SG_DEBUG("CFactorGraph::~CFactorGraph(): m_datasources->ref_count() = %d.\n", m_datasources->ref_count());

	SG_DEBUG("CFactorGraph::~CFactorGraph(): this->ref_count() = %d.\n", this->ref_count());
}

void CFactorGraph::register_parameters()
{
	SG_ADD(&m_cardinalities, "m_cardinalities", "Cardinalities", MS_NOT_AVAILABLE);
	SG_ADD((CSGObject**)&m_factors, "m_factors", "Factors", MS_NOT_AVAILABLE);
	SG_ADD((CSGObject**)&m_datasources, "m_datasources", "Factor data sources", MS_NOT_AVAILABLE);

	m_factors = NULL;
	m_datasources = NULL;
	m_factors = new CDynamicObjectArray();
	m_datasources = new CDynamicObjectArray();

	if (m_factors != NULL)
		SG_DEBUG("CFactorGraph::register_parameters(): m_factors->ref_count() = %d.\n", m_factors->ref_count());

	SG_REF(m_factors);
	SG_REF(m_datasources);
}

CDynamicObjectArray* CFactorGraph::get_factors() const
{
	SG_REF(m_factors);
	return m_factors;
}

SGVector<int32_t> CFactorGraph::get_cardinalities() const
{
	return m_cardinalities;
}

void CFactorGraph::set_cardinalities(SGVector<int32_t> cards)
{
	m_cardinalities = cards.clone();
}

CDynamicObjectArray* CFactorGraph::get_factor_data_sources() const
{
	SG_REF(m_datasources);
	return m_datasources;
}

void CFactorGraph::compute_energies()
{
	for (int32_t fi = 0; fi < m_factors->get_num_elements(); ++fi)
	{
		CFactor* fac = dynamic_cast<CFactor*>(m_factors->get_element(fi));
		fac->compute_energies();
		SG_UNREF(fac);
	}
}

float64_t CFactorGraph::evaluate_energy(const SGVector<int32_t> state) const
{
	ASSERT(state.size() == m_cardinalities.size());

	float64_t energy = 0.0;
	for (int32_t fi = 0; fi < m_factors->get_num_elements(); ++fi)
	{
		CFactor* fac = dynamic_cast<CFactor*>(m_factors->get_element(fi));
		energy += fac->evaluate_energy(state);
		SG_UNREF(fac);
	}
	return energy;
}

float64_t CFactorGraph::evaluate_energy(const CFactorGraphObservation* obs) const
{
	return evaluate_energy(obs->get_data());
}

void CFactorGraph::add_factor(CFactor* factor)
{
	m_factors->push_back(factor);
}

void CFactorGraph::add_data_source(CFactorDataSource* datasource)
{
	m_datasources->push_back(datasource);
}

CFactorGraph* CFactorGraph::duplicate() const
{
	return new CFactorGraph(*this);
}

int32_t CFactorGraph::get_num_vectors() const
{
	return m_factors->get_num_elements();
}

<commit_msg>ifdef refcount debug access to fix build failure when refcounting is not available<commit_after>/*
 * 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 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2013 Shell Hu
 * Copyright (C) 2013 Shell Hu
 */

#include <shogun/structure/FactorGraph.h>

using namespace shogun;

CFactorGraph::CFactorGraph()
{
	SG_UNSTABLE("CFactorGraph::CFactorGraph()", "\n");

	register_parameters();
}

CFactorGraph::CFactorGraph(SGVector<int32_t> card)
	: m_cardinalities(card)
{
	register_parameters();
}

CFactorGraph::CFactorGraph(const CFactorGraph &fg)
{
	register_parameters();
	m_cardinalities = fg.get_cardinalities();
	// No need to unref and ref in this case
	// TODO test if need to copy element by element
	m_factors = fg.get_factors();
	m_datasources = fg.get_factor_data_sources();
}

CFactorGraph::~CFactorGraph()
{
	SG_UNREF(m_factors);
	SG_UNREF(m_datasources);

	if (m_factors != NULL)
		SG_DEBUG("CFactorGraph::~CFactorGraph(): m_factors->ref_count() = %d.\n", m_factors->ref_count());

#ifdef USE_REFERENCE_COUNTING
	if (m_datasources != NULL)
		SG_DEBUG("CFactorGraph::~CFactorGraph(): m_datasources->ref_count() = %d.\n", m_datasources->ref_count());

	SG_DEBUG("CFactorGraph::~CFactorGraph(): this->ref_count() = %d.\n", this->ref_count());
#endif
}

void CFactorGraph::register_parameters()
{
	SG_ADD(&m_cardinalities, "m_cardinalities", "Cardinalities", MS_NOT_AVAILABLE);
	SG_ADD((CSGObject**)&m_factors, "m_factors", "Factors", MS_NOT_AVAILABLE);
	SG_ADD((CSGObject**)&m_datasources, "m_datasources", "Factor data sources", MS_NOT_AVAILABLE);

	m_factors = NULL;
	m_datasources = NULL;
	m_factors = new CDynamicObjectArray();
	m_datasources = new CDynamicObjectArray();

#ifdef USE_REFERENCE_COUNTING
	if (m_factors != NULL)
		SG_DEBUG("CFactorGraph::register_parameters(): m_factors->ref_count() = %d.\n", m_factors->ref_count());
#endif

	SG_REF(m_factors);
	SG_REF(m_datasources);
}

CDynamicObjectArray* CFactorGraph::get_factors() const
{
	SG_REF(m_factors);
	return m_factors;
}

SGVector<int32_t> CFactorGraph::get_cardinalities() const
{
	return m_cardinalities;
}

void CFactorGraph::set_cardinalities(SGVector<int32_t> cards)
{
	m_cardinalities = cards.clone();
}

CDynamicObjectArray* CFactorGraph::get_factor_data_sources() const
{
	SG_REF(m_datasources);
	return m_datasources;
}

void CFactorGraph::compute_energies()
{
	for (int32_t fi = 0; fi < m_factors->get_num_elements(); ++fi)
	{
		CFactor* fac = dynamic_cast<CFactor*>(m_factors->get_element(fi));
		fac->compute_energies();
		SG_UNREF(fac);
	}
}

float64_t CFactorGraph::evaluate_energy(const SGVector<int32_t> state) const
{
	ASSERT(state.size() == m_cardinalities.size());

	float64_t energy = 0.0;
	for (int32_t fi = 0; fi < m_factors->get_num_elements(); ++fi)
	{
		CFactor* fac = dynamic_cast<CFactor*>(m_factors->get_element(fi));
		energy += fac->evaluate_energy(state);
		SG_UNREF(fac);
	}
	return energy;
}

float64_t CFactorGraph::evaluate_energy(const CFactorGraphObservation* obs) const
{
	return evaluate_energy(obs->get_data());
}

void CFactorGraph::add_factor(CFactor* factor)
{
	m_factors->push_back(factor);
}

void CFactorGraph::add_data_source(CFactorDataSource* datasource)
{
	m_datasources->push_back(datasource);
}

CFactorGraph* CFactorGraph::duplicate() const
{
	return new CFactorGraph(*this);
}

int32_t CFactorGraph::get_num_vectors() const
{
	return m_factors->get_num_elements();
}

<|endoftext|>


<commit_before>//
// Created by salmon on 17-9-5.
//
#include "TimeIntegrator.h"
#include "Atlas.h"
#include "Domain.h"
#include "simpla/data/DataNode.h"
namespace simpla {
namespace engine {
struct TimeIntegrator::pimpl_s {
    Real m_time_now_ = 0.0;
    Real m_time_end_ = 1.0;
    Real m_time_step_ = 1.0;
};
TimeIntegrator::TimeIntegrator() : m_pimpl_(new pimpl_s) {}
TimeIntegrator::~TimeIntegrator() { delete m_pimpl_; }
Real TimeIntegrator::GetTimeNow() const { return m_pimpl_->m_time_now_; }
void TimeIntegrator::SetTimeNow(Real t) { m_pimpl_->m_time_now_ = t; }
Real TimeIntegrator::GetTimeEnd() const { return m_pimpl_->m_time_end_; }
void TimeIntegrator::SetTimeEnd(Real t) { m_pimpl_->m_time_end_ = t; }
Real TimeIntegrator::GetTimeStep() const { return m_pimpl_->m_time_step_; }
void TimeIntegrator::SetTimeStep(Real t) { m_pimpl_->m_time_step_ = t; }

std::shared_ptr<data::DataNode> TimeIntegrator::Serialize() const { return base_type::Serialize(); }
void TimeIntegrator::Deserialize(std::shared_ptr<data::DataNode> const &tdb) { base_type::Deserialize(tdb); }

void TimeIntegrator::InitialCondition(Real time_now) {
    for (auto &d : GetDomains()) { d.second->InitialCondition(time_now); }
}
void TimeIntegrator::BoundaryCondition(Real time_now, Real dt) {
    for (auto &d : GetDomains()) { d.second->BoundaryCondition(time_now, dt); }
}

void TimeIntegrator::ComputeFluxes(Real time_now, Real dt) {
    for (auto &d : GetDomains()) { d.second->ComputeFluxes(time_now, dt); }
}
Real TimeIntegrator::ComputeStableDtOnPatch(Real time_now, Real time_dt) {
    for (auto &d : GetDomains()) { time_dt = std::min(time_dt, d.second->ComputeStableDtOnPatch(time_now, time_dt)); }
    return time_dt;
}

void TimeIntegrator::Advance(Real time_now, Real time_dt) {
    Update();
    GetAtlas()->Foreach([&](std::shared_ptr<engine::MeshBlock> const &blk) {
        ASSERT(blk != nullptr);
        VERBOSE << std::setw(20) << "Block : " << blk->IndexBox();
        auto patch = GetPatch(blk->GetGUID());
        auto out_patch = data::DataNode::New(data::DataNode::DN_TABLE);
        bool need_init_cond = false;
        if (patch == nullptr) {
            patch = data::DataNode::New(data::DataNode::DN_TABLE);
            need_init_cond = true;
        }

        for (auto &item : GetDomains()) {
            item.second->SetBlock(blk);
            int chk_bdry = item.second->CheckBoundary();
            if (chk_bdry == DomainBase::OUT_BOUNDARY) { continue; }
            item.second->Push(patch);
            if (need_init_cond) { item.second->InitialCondition(time_now); }
            item.second->Advance(time_now, time_dt);
            if (chk_bdry == DomainBase::ON_BOUNDARY) { item.second->BoundaryCondition(time_now, time_dt); }
            patch->Set(item.second->Pop());
        }

        SetPatch(blk->GetGUID(), patch);

    });
}
void TimeIntegrator::DoSetUp() {
    SetStepNumber(db()->GetValue<size_type>("Step", GetStepNumber()));
    SetMaxStep(db()->GetValue<size_type>("MaxStep", 100));
    base_type::DoSetUp();
}
void TimeIntegrator::DoTearDown() { base_type::DoTearDown(); }
void TimeIntegrator::Run() {
    Update();
    while (!Done()) {
        VERBOSE << " [ STEP:" << std::setw(5) << GetStepNumber() << " START ] ";
        Synchronize(0);
        NextStep();
        if (GetCheckPointInterval() > 0 && (GetStepNumber() % GetCheckPointInterval() == 0)) { CheckPoint(); };
        if (GetDumpInterval() > 0 && (GetStepNumber() % GetDumpInterval() == 0)) { Dump(); };

        VERBOSE << " [ STEP:" << std::setw(5) << GetStepNumber() - 1 << " STOP  ] ";
    }
    CheckPoint();
}
void TimeIntegrator::NextStep() {
    Advance(GetTimeNow(), GetTimeStep());
    m_pimpl_->m_time_now_ += m_pimpl_->m_time_step_;
    base_type::NextStep();
}

void TimeIntegrator::Synchronize(int level) { base_type::Synchronize(level); }
bool TimeIntegrator::Done() const { return GetTimeNow() >= GetTimeEnd() || GetStepNumber() >= GetMaxStep(); }
}
}<commit_msg>update Write XDMF<commit_after>//
// Created by salmon on 17-9-5.
//
#include "TimeIntegrator.h"
#include "Atlas.h"
#include "Domain.h"
#include "simpla/data/DataNode.h"
namespace simpla {
namespace engine {
struct TimeIntegrator::pimpl_s {
    Real m_time_now_ = 0.0;
    Real m_time_end_ = 1.0;
    Real m_time_step_ = 1.0;
};
TimeIntegrator::TimeIntegrator() : m_pimpl_(new pimpl_s) {}
TimeIntegrator::~TimeIntegrator() { delete m_pimpl_; }
Real TimeIntegrator::GetTimeNow() const { return m_pimpl_->m_time_now_; }
void TimeIntegrator::SetTimeNow(Real t) { m_pimpl_->m_time_now_ = t; }
Real TimeIntegrator::GetTimeEnd() const { return m_pimpl_->m_time_end_; }
void TimeIntegrator::SetTimeEnd(Real t) { m_pimpl_->m_time_end_ = t; }
Real TimeIntegrator::GetTimeStep() const { return m_pimpl_->m_time_step_; }
void TimeIntegrator::SetTimeStep(Real t) { m_pimpl_->m_time_step_ = t; }

std::shared_ptr<data::DataNode> TimeIntegrator::Serialize() const { return base_type::Serialize(); }
void TimeIntegrator::Deserialize(std::shared_ptr<data::DataNode> const &tdb) { base_type::Deserialize(tdb); }

void TimeIntegrator::InitialCondition(Real time_now) {
    for (auto &d : GetDomains()) { d.second->InitialCondition(time_now); }
}
void TimeIntegrator::BoundaryCondition(Real time_now, Real dt) {
    for (auto &d : GetDomains()) { d.second->BoundaryCondition(time_now, dt); }
}

void TimeIntegrator::ComputeFluxes(Real time_now, Real dt) {
    for (auto &d : GetDomains()) { d.second->ComputeFluxes(time_now, dt); }
}
Real TimeIntegrator::ComputeStableDtOnPatch(Real time_now, Real time_dt) {
    for (auto &d : GetDomains()) { time_dt = std::min(time_dt, d.second->ComputeStableDtOnPatch(time_now, time_dt)); }
    return time_dt;
}

void TimeIntegrator::Advance(Real time_now, Real time_dt) {
    Update();
    GetAtlas()->Foreach([&](std::shared_ptr<engine::MeshBlock> const &blk) {
        ASSERT(blk != nullptr);
        VERBOSE << std::setw(20) << "Block : " << blk->IndexBox();
        auto patch = GetPatch(blk->GetGUID());
        auto out_patch = data::DataNode::New(data::DataNode::DN_TABLE);
        bool need_init_cond = false;
        if (patch == nullptr) {
            patch = data::DataNode::New(data::DataNode::DN_TABLE);
            need_init_cond = true;
        }

        for (auto &item : GetDomains()) {
            item.second->SetBlock(blk);
            int chk_bdry = item.second->CheckBoundary();
            if (chk_bdry == DomainBase::OUT_BOUNDARY) { continue; }
            item.second->Push(patch);
            if (need_init_cond) { item.second->InitialCondition(time_now); }
            item.second->Advance(time_now, time_dt);
            if (chk_bdry == DomainBase::ON_BOUNDARY) { item.second->BoundaryCondition(time_now, time_dt); }
            patch->Set(item.second->Pop());
        }

        SetPatch(blk->GetGUID(), patch);

    });
}
void TimeIntegrator::DoSetUp() {
    SetStepNumber(db()->GetValue<size_type>("Step", GetStepNumber()));
    SetMaxStep(db()->GetValue<size_type>("MaxStep", 100));
    base_type::DoSetUp();
}
void TimeIntegrator::DoTearDown() { base_type::DoTearDown(); }
void TimeIntegrator::Run() {
    Update();
    while (!Done()) {
        VERBOSE << " [ STEP:" << std::setw(5) << GetStepNumber() << " START ] ";
        NextStep();
        Synchronize(0);
        if (GetCheckPointInterval() > 0 && (GetStepNumber() % GetCheckPointInterval() == 0)) { CheckPoint(); };
        if (GetDumpInterval() > 0 && (GetStepNumber() % GetDumpInterval() == 0)) { Dump(); };

        VERBOSE << " [ STEP:" << std::setw(5) << GetStepNumber() - 1 << " STOP  ] ";
    }
    CheckPoint();
}
void TimeIntegrator::NextStep() {
    Advance(GetTimeNow(), GetTimeStep());
    m_pimpl_->m_time_now_ += m_pimpl_->m_time_step_;
    base_type::NextStep();
}

void TimeIntegrator::Synchronize(int level) { base_type::Synchronize(level); }
bool TimeIntegrator::Done() const { return GetTimeNow() >= GetTimeEnd() || GetStepNumber() >= GetMaxStep(); }
}
}<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2015 Skorezore

//  Permission is hereby granted, free of charge, to any person obtaining a
//  copy of this software and associated documentation files (the "Software"),
//  to deal in the Software without restriction, including without limitation
//  the rights to use, copy, modify, merge, publish, distribute, sublicense,
//  and/or sell copies of the Software, and to permit persons to whom the
//  Software is furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
//  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//  DEALINGS IN THE SOFTWARE.

#pragma once
#ifndef REFERENCE_PROXY_HPP
#define REFERENCE_PROXY_HPP

#include <ostream>

template <class T>
class reference_proxy {
	friend std::ostream & operator<<(std::ostream & strm, const reference_proxy & px) {
		strm << '[' << px.mem << ']';
		return strm;
	}

private:
	T & mem;
	bool share;

public:
	reference_proxy(T & ref, bool shr = true) noexcept;
	reference_proxy(const T & ref) noexcept;

	reference_proxy & operator=(const T & val) noexcept(noexcept(mem = val));

	bool operator==(const T & val) noexcept(noexcept(mem == val));
	bool operator!=(const T & val) noexcept(noexcept(mem != val));
};

template <class T>
bool operator<(const reference_proxy<T> & lhs, const reference_proxy<T> & rhs) {
	return lhs.mem < rhs.mem;
}

template <class T>
bool operator>(const reference_proxy<T> & lhs, const reference_proxy<T> & rhs) {
	return lhs.mem > rhs.mem;
}

template <class T>
reference_proxy<T>::reference_proxy(T & ref, bool shr) noexcept : mem(ref), share(shr) {}

template <class T>
reference_proxy<T>::reference_proxy(const T & ref) noexcept : reference_proxy(const_cast<T &>(ref), false) {}

template <class T>
reference_proxy<T> & reference_proxy<T>::operator=(const T & val) noexcept(noexcept(mem = val)) {
	if(share)
		mem = val;
	return *this;
}

template <class T>
bool reference_proxy<T>::operator==(const T & val) noexcept(noexcept(mem == val)) {
	return mem == val;
}

template <class T>
bool reference_proxy<T>::operator!=(const T & val) noexcept(noexcept(mem != val)) {
	return mem != val;
}

#endif  // REFERENCE_PROXY_HPP
<commit_msg>A well-deserved comment.<commit_after>// The MIT License (MIT)

// Copyright (c) 2015 Skorezore

//  Permission is hereby granted, free of charge, to any person obtaining a
//  copy of this software and associated documentation files (the "Software"),
//  to deal in the Software without restriction, including without limitation
//  the rights to use, copy, modify, merge, publish, distribute, sublicense,
//  and/or sell copies of the Software, and to permit persons to whom the
//  Software is furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
//  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//  DEALINGS IN THE SOFTWARE.

#pragma once
#ifndef REFERENCE_PROXY_HPP
#define REFERENCE_PROXY_HPP

#include <ostream>

template <class T>
class reference_proxy {
	friend std::ostream & operator<<(std::ostream & strm, const reference_proxy & px) {
		strm << '[' << px.mem << ']';
		return strm;
	}

private:
	T & mem;
	bool share;

public:
	reference_proxy(T & ref, bool shr = true) noexcept;
	reference_proxy(const T & ref) noexcept;

	reference_proxy & operator=(const T & val) noexcept(noexcept(mem = val));

	bool operator==(const T & val) noexcept(noexcept(mem == val));
	bool operator!=(const T & val) noexcept(noexcept(mem != val));
};

template <class T>
bool operator<(const reference_proxy<T> & lhs, const reference_proxy<T> & rhs) {
	return lhs.mem < rhs.mem;
}

template <class T>
bool operator>(const reference_proxy<T> & lhs, const reference_proxy<T> & rhs) {
	return lhs.mem > rhs.mem;
}

template <class T>
reference_proxy<T>::reference_proxy(T & ref, bool shr) noexcept : mem(ref), share(shr) {}

template <class T>
reference_proxy<T>::reference_proxy(const T & ref) noexcept : reference_proxy(const_cast<T &>(ref), false) {}

template <class T>
reference_proxy<T> & reference_proxy<T>::operator=(const T & val) noexcept(noexcept(mem = val)) {
	if(share) // WUT - so we silently swallow assignments... :( BAD ideas
		mem = val;
	return *this;
}

template <class T>
bool reference_proxy<T>::operator==(const T & val) noexcept(noexcept(mem == val)) {
	return mem == val;
}

template <class T>
bool reference_proxy<T>::operator!=(const T & val) noexcept(noexcept(mem != val)) {
	return mem != val;
}

#endif  // REFERENCE_PROXY_HPP
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011 Stephen Williams (steve@icarus.com)
 *
 *    This source code is free software; you can redistribute it
 *    and/or modify it in source code form 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
 */

# include  "entity.h"
# include  "architec.h"
# include  <iostream>
# include  <fstream>
# include  <iomanip>
# include  <ivl_assert.h>

int emit_entities(void)
{
      int errors = 0;

      for (map<perm_string,Entity*>::iterator cur = design_entities.begin()
		 ; cur != design_entities.end() ; ++cur) {
	    errors += cur->second->emit(cout);
      }

      return errors;
}

int Entity::emit(ostream&out)
{
      int errors = 0;

      out << "module ";
	// If there are generics, emit them
      if (parms_.size() > 0) {
	    out << "#(";
	    for (vector<InterfacePort*>::const_iterator cur = parms_.begin()
		       ; cur != parms_.end() ; ++cur) {
		  const InterfacePort*curp = *cur;
		  if (cur != parms_.begin())
			out << ", ";
		  out << "parameter \\" << curp->name << " = ";
		  ivl_assert(*this, curp->expr);
		  errors += curp->expr->emit(out, this, 0);
	    }
	    out << ") ";
      }

      out << get_name();

	// If there are ports, emit them.
      if (ports_.size() > 0) {
	    out << "(";
	    const char*sep = 0;
	    for (vector<InterfacePort*>::const_iterator cur = ports_.begin()
		       ; cur != ports_.end() ; ++cur) {
		  InterfacePort*port = *cur;

		  VType::decl_t&decl = declarations_[port->name];

		  if (sep) out << sep;
		  else sep = ", ";

		  switch (port->mode) {
		      case PORT_NONE: // Should not happen
			out << "NO_PORT " << port->name;
			break;
		      case PORT_IN:
			out << "input ";
			errors += decl.emit(out, port->name);
			break;
		      case PORT_OUT:
			out << "output ";
			errors += decl.emit(out, port->name);
			break;
		  }
	    }
	    cout << ")";
      }

      out << ";" << endl;

      errors += bind_arch_->emit(out, this);

      out << "endmodule" << endl;

      return errors;
}
<commit_msg>Get parameter output syntax right for vhdlpp.<commit_after>/*
 * Copyright (c) 2011 Stephen Williams (steve@icarus.com)
 *
 *    This source code is free software; you can redistribute it
 *    and/or modify it in source code form 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
 */

# include  "entity.h"
# include  "architec.h"
# include  <iostream>
# include  <fstream>
# include  <iomanip>
# include  <ivl_assert.h>

int emit_entities(void)
{
      int errors = 0;

      for (map<perm_string,Entity*>::iterator cur = design_entities.begin()
		 ; cur != design_entities.end() ; ++cur) {
	    errors += cur->second->emit(cout);
      }

      return errors;
}

int Entity::emit(ostream&out)
{
      int errors = 0;

      out << "module \\" << get_name() << " ";

	// If there are generics, emit them
      if (parms_.size() > 0) {
	    out << "#(";
	    for (vector<InterfacePort*>::const_iterator cur = parms_.begin()
		       ; cur != parms_.end() ; ++cur) {
		  const InterfacePort*curp = *cur;
		  if (cur != parms_.begin())
			out << ", ";
		  out << "parameter \\" << curp->name << " = ";
		  ivl_assert(*this, curp->expr);
		  errors += curp->expr->emit(out, this, 0);
	    }
	    out << ") ";
      }

	// If there are ports, emit them.
      if (ports_.size() > 0) {
	    out << "(";
	    const char*sep = 0;
	    for (vector<InterfacePort*>::const_iterator cur = ports_.begin()
		       ; cur != ports_.end() ; ++cur) {
		  InterfacePort*port = *cur;

		  VType::decl_t&decl = declarations_[port->name];

		  if (sep) out << sep;
		  else sep = ", ";

		  switch (port->mode) {
		      case PORT_NONE: // Should not happen
			out << "NO_PORT " << port->name;
			break;
		      case PORT_IN:
			out << "input ";
			errors += decl.emit(out, port->name);
			break;
		      case PORT_OUT:
			out << "output ";
			errors += decl.emit(out, port->name);
			break;
		  }
	    }
	    cout << ")";
      }

      out << ";" << endl;

      errors += bind_arch_->emit(out, this);

      out << "endmodule" << endl;

      return errors;
}
<|endoftext|>