<commit_before>#include "secondary-pop-nodes/annealer/SimulatedAnnealer.hpp"
#include <string>
#include <sstream>
#include <random>
#include <cmath>

using namespace std;

SimulatedAnnealer::SimulatedAnnealer(
	Individual * templateIndividual,
	bool maximize,
	int maxIterations,
	int accelerationFactor,
	TemperatureSchedule * schedule,
	EndCondition * condition,
	FitnessPropagator * propagator
) : PopulationNode(
	1,
	templateIndividual,
	maxIterations,
	accelerationFactor,
	NULL,
	condition,
	propagator
) {
	init(maximize, schedule);
}

SimulatedAnnealer::SimulatedAnnealer(
	int populationSize,
	Individual * templateIndividual,
	bool maximize,
	int maxIterations,
	int accelerationFactor,
	TemperatureSchedule * schedule,
	EndCondition * condition,
	FitnessPropagator * propagator
) : PopulationNode(
	populationSize,
	templateIndividual,
	maxIterations,
	accelerationFactor,
	NULL,
	condition,
	propagator
) {
	init(maximize, schedule);
}

SimulatedAnnealer::SimulatedAnnealer(
	Individual * templateIndividual,
	bool maximize,
	int maxIterations,
	int accelerationFactor,
	TemperatureSchedule * schedule,
	EndCondition * condition,
	FitnessPropagator * propagator,
	unsigned seed
) : PopulationNode(
	1,
	templateIndividual,
	maxIterations,
	accelerationFactor,
	seed,
	NULL,
	condition,
	propagator
) {
	init(maximize, schedule);
}

SimulatedAnnealer::SimulatedAnnealer(
	int populationSize,
	Individual * templateIndividual,
	bool maximize,
	int maxIterations,
	int accelerationFactor,
	TemperatureSchedule * schedule,
	EndCondition * condition,
	FitnessPropagator * propagator,
	unsigned seed
) : PopulationNode(
	populationSize,
	templateIndividual,
	maxIterations,
	accelerationFactor,
	seed,
	NULL,
	condition,
	propagator
) {
	init(maximize, schedule);
}

void SimulatedAnnealer::init(bool maximize, TemperatureSchedule * schedule) {
	this->maximize = maximize;
	this->schedule = schedule;
}

Individual ** SimulatedAnnealer::newPopulation() {
	Individual ** population = (Individual**)malloc(
		sizeof(Individual*)*populationSize
	);

	for (int i = 0; i < populationSize; i++) {
		population[i] = getNeighbour(myPopulation[i]);
	}

	return population;
}

int SimulatedAnnealer::compareNeighbourliness(
	Individual * base,
	Individual * target
) {
	string basePhenotype = base->toGenomeString();
	string targetPhenotype = target->toGenomeString();
	int length = basePhenotype.length();

	int diff = 0;
	for (int i = 0; i < length; i++) {
		diff += abs(basePhenotype[i]-targetPhenotype[i]);
	}

	return diff;
}

Individual * SimulatedAnnealer::getNeighbour(Individual * target) {
	int genomeLength = target->getGenomeLength();
	Individual ** neighbours = (Individual**)malloc(
		sizeof(Individual*)*genomeLength
	);
	Individual * temp;
	Genome * tempGenome;

	Genome * baseGenome = target->getGenome();
	GeneNode ** nodes = baseGenome->getGeneNodes();
	int * genes = baseGenome->getGenome();
	int diff;

	for (int i = 0; i < genomeLength; i++) {
		int lowestDiff = 0;
		Individual * nearestKnownNeighbour = NULL;

		// Since we don't know where our nearest neighbour is in a
		// population of components, we have to cycle through them all
		int numAlleles = nodes[i]->getPopulationSize();
		for (int k = 0; k < numAlleles; k++) {
			if (genes[i] == k) {
				if (k < numAlleles - 1) {
					k++;
				} else {
					break;
				}
			}

			int * tempGenes = (int*)malloc(
				sizeof(int)*genomeLength
			);

			for (int c = 0; c < genomeLength; c++) {
				tempGenes[c] = genes[c]; // Reset
			}

			tempGenes[i] = k;

			tempGenome = new Genome(
				tempGenes,
				genomeLength,
				nodes
			);

			temp = target->copyWithNewGenome(tempGenome);
			delete(tempGenome);
			free(tempGenes);
			diff = compareNeighbourliness(target, temp);

			if ((diff < lowestDiff && diff > 0) || lowestDiff == 0) {
				delete(nearestKnownNeighbour);
				nearestKnownNeighbour = temp;
				lowestDiff = diff;
			} else {
				delete(temp);
			}
		}

		if (lowestDiff == 0) {
			// The lowest diff being zero means that we have no
			// neighbours (i.e. all the available choices result
			// in no change)
			neighbours[i] = NULL;
		} else {
			neighbours[i] = nearestKnownNeighbour;
		}
	}

	uniform_int_distribution<int> neighbourDistribution(0, genomeLength-1);
	int choice = neighbourDistribution(generator);

	// Make sure we're not picking identical values over and over again
	for (int i = 0; i < genomeLength && neighbours[choice] == NULL; i++) {
		choice = neighbourDistribution(generator);
	}

	if (neighbours[choice] == NULL) return target;
	int targetFitness = target->checkFitness();
	int neighbourFitness = neighbours[choice]->checkFitness();

	Individual * neighbour = neighbours[choice]->deepCopy();
	for (int i = 0; i < genomeLength; i++) {
		delete(neighbours[i]);
	}

	free(neighbours);

	if (
		(maximize && targetFitness < neighbourFitness) ||
		(!maximize && targetFitness > neighbourFitness)
	) {
		return neighbour;
	} else {
		double temp = schedule->currentTemp(currentGeneration);
		if (temp == 0) {
			delete(neighbour);
			return target;
		}

		int delta = maximize ? neighbourFitness - targetFitness :
			targetFitness - neighbourFitness;

		double probability = exp(-delta/temp);

		uniform_real_distribution<double>
			goingWrongWayDistribution(0, 1);

		if (goingWrongWayDistribution(generator) < probability) {
			return neighbour;
		} else {
			delete(neighbour);
			return target;
		}
	}
}

string SimulatedAnnealer::toString() {
	stringstream ss;

	ss << "Population size: " << populationSize << "\n";
	ss << populationStrings();

	if (!readOnce) ss << "Seed: " << seed << "\n";
	readOnce = true;

	return ss.str();
}
<commit_msg>[SimulatedAnnealer]: Plugged memory leak<commit_after>#include "secondary-pop-nodes/annealer/SimulatedAnnealer.hpp"
#include <string>
#include <sstream>
#include <random>
#include <cmath>

using namespace std;

SimulatedAnnealer::SimulatedAnnealer(
	Individual * templateIndividual,
	bool maximize,
	int maxIterations,
	int accelerationFactor,
	TemperatureSchedule * schedule,
	EndCondition * condition,
	FitnessPropagator * propagator
) : PopulationNode(
	1,
	templateIndividual,
	maxIterations,
	accelerationFactor,
	NULL,
	condition,
	propagator
) {
	init(maximize, schedule);
}

SimulatedAnnealer::SimulatedAnnealer(
	int populationSize,
	Individual * templateIndividual,
	bool maximize,
	int maxIterations,
	int accelerationFactor,
	TemperatureSchedule * schedule,
	EndCondition * condition,
	FitnessPropagator * propagator
) : PopulationNode(
	populationSize,
	templateIndividual,
	maxIterations,
	accelerationFactor,
	NULL,
	condition,
	propagator
) {
	init(maximize, schedule);
}

SimulatedAnnealer::SimulatedAnnealer(
	Individual * templateIndividual,
	bool maximize,
	int maxIterations,
	int accelerationFactor,
	TemperatureSchedule * schedule,
	EndCondition * condition,
	FitnessPropagator * propagator,
	unsigned seed
) : PopulationNode(
	1,
	templateIndividual,
	maxIterations,
	accelerationFactor,
	seed,
	NULL,
	condition,
	propagator
) {
	init(maximize, schedule);
}

SimulatedAnnealer::SimulatedAnnealer(
	int populationSize,
	Individual * templateIndividual,
	bool maximize,
	int maxIterations,
	int accelerationFactor,
	TemperatureSchedule * schedule,
	EndCondition * condition,
	FitnessPropagator * propagator,
	unsigned seed
) : PopulationNode(
	populationSize,
	templateIndividual,
	maxIterations,
	accelerationFactor,
	seed,
	NULL,
	condition,
	propagator
) {
	init(maximize, schedule);
}

void SimulatedAnnealer::init(bool maximize, TemperatureSchedule * schedule) {
	this->maximize = maximize;
	this->schedule = schedule;
}

Individual ** SimulatedAnnealer::newPopulation() {
	Individual ** population = (Individual**)malloc(
		sizeof(Individual*)*populationSize
	);

	for (int i = 0; i < populationSize; i++) {
		population[i] = getNeighbour(myPopulation[i]);;
		delete(myPopulation[i]);
	}

	return population;
}

int SimulatedAnnealer::compareNeighbourliness(
	Individual * base,
	Individual * target
) {
	string basePhenotype = base->toGenomeString();
	string targetPhenotype = target->toGenomeString();
	int length = basePhenotype.length();

	int diff = 0;
	for (int i = 0; i < length; i++) {
		diff += abs(basePhenotype[i]-targetPhenotype[i]);
	}

	return diff;
}

Individual * SimulatedAnnealer::getNeighbour(Individual * target) {
	int genomeLength = target->getGenomeLength();
	Individual ** neighbours = (Individual**)malloc(
		sizeof(Individual*)*genomeLength
	);
	Individual * temp;
	Genome * tempGenome;

	Genome * baseGenome = target->getGenome();
	GeneNode ** nodes = baseGenome->getGeneNodes();
	int * genes = baseGenome->getGenome();
	int diff;

	for (int i = 0; i < genomeLength; i++) {
		int lowestDiff = 0;
		Individual * nearestKnownNeighbour = NULL;

		// Since we don't know where our nearest neighbour is in a
		// population of components, we have to cycle through them all
		int numAlleles = nodes[i]->getPopulationSize();
		for (int k = 0; k < numAlleles; k++) {
			if (genes[i] == k) {
				if (k < numAlleles - 1) {
					k++;
				} else {
					break;
				}
			}

			int * tempGenes = (int*)malloc(
				sizeof(int)*genomeLength
			);

			for (int c = 0; c < genomeLength; c++) {
				tempGenes[c] = genes[c]; // Reset
			}

			tempGenes[i] = k;

			tempGenome = new Genome(
				tempGenes,
				genomeLength,
				nodes
			);

			temp = target->copyWithNewGenome(tempGenome);
			delete(tempGenome);
			free(tempGenes);
			diff = compareNeighbourliness(target, temp);

			if ((diff < lowestDiff && diff > 0) || lowestDiff == 0) {
				delete(nearestKnownNeighbour);
				nearestKnownNeighbour = temp;
				lowestDiff = diff;
			} else {
				delete(temp);
			}
		}

		if (lowestDiff == 0) {
			// The lowest diff being zero means that we have no
			// neighbours (i.e. all the available choices result
			// in no change)
			neighbours[i] = NULL;
		} else {
			neighbours[i] = nearestKnownNeighbour;
		}
	}

	uniform_int_distribution<int> neighbourDistribution(0, genomeLength-1);
	int choice = neighbourDistribution(generator);

	// Make sure we're not picking identical values over and over again
	for (int i = 0; i < genomeLength && neighbours[choice] == NULL; i++) {
		choice = neighbourDistribution(generator);
	}

	if (neighbours[choice] == NULL) return target;
	int targetFitness = target->checkFitness();
	int neighbourFitness = neighbours[choice]->checkFitness();

	Individual * neighbour = neighbours[choice]->deepCopy();
	for (int i = 0; i < genomeLength; i++) {
		delete(neighbours[i]);
	}

	free(neighbours);

	if (
		(maximize && targetFitness < neighbourFitness) ||
		(!maximize && targetFitness > neighbourFitness)
	) {
		return neighbour;
	} else {
		double temp = schedule->currentTemp(currentGeneration);
		if (temp == 0) {
			delete(neighbour);
			return target;
		}

		int delta = maximize ? neighbourFitness - targetFitness :
			targetFitness - neighbourFitness;

		double probability = exp(-delta/temp);

		uniform_real_distribution<double>
			goingWrongWayDistribution(0, 1);

		if (goingWrongWayDistribution(generator) < probability) {
			return neighbour;
		} else {
			delete(neighbour);
			return target;
		}
	}
}

string SimulatedAnnealer::toString() {
	stringstream ss;

	ss << "Population size: " << populationSize << "\n";
	ss << populationStrings();

	if (!readOnce) ss << "Seed: " << seed << "\n";
	readOnce = true;

	return ss.str();
}
<|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) 2011 Sergey Lisitsyn
 * Copyright (C) 2011 Berlin Institute of Technology and Max-Planck-Society
 */

#include <shogun/preprocessor/LocalTangentSpaceAlignment.h>
#ifdef HAVE_LAPACK
#include <shogun/mathematics/arpack.h>
#include <shogun/mathematics/lapack.h>
#include <shogun/lib/common.h>
#include <shogun/mathematics/Math.h>
#include <shogun/io/SGIO.h>
#include <shogun/distance/EuclidianDistance.h>
#include <shogun/lib/Signal.h>

#ifndef WIN32
#include <pthread.h>
#endif

using namespace shogun;

#ifndef DOXYGEN_SHOULD_SKIP_THIS
struct D_THREAD_PARAM
{
	int32_t idx_start;
	int32_t idx_step;
	int32_t idx_stop;
	int32_t m_k;
	int32_t m_target_dim;
	int32_t dim;
	int32_t N;
	const int32_t* neighborhood_matrix;
	float64_t* G_matrix;
	float64_t* mean_vector;
	float64_t* local_feature_matrix;
	const float64_t* feature_matrix;
	float64_t* s_values_vector;
	float64_t* q_matrix;
	float64_t* W_matrix;
#ifndef WIN32
	pthread_mutex_t* W_matrix_mutex;
#endif
};
#endif

CLocalTangentSpaceAlignment::CLocalTangentSpaceAlignment() :
		CLocallyLinearEmbedding()
{
}

CLocalTangentSpaceAlignment::~CLocalTangentSpaceAlignment()
{
}

bool CLocalTangentSpaceAlignment::init(CFeatures* features)
{
	return true;
}

void CLocalTangentSpaceAlignment::cleanup()
{
}

SGMatrix<float64_t> CLocalTangentSpaceAlignment::apply_to_feature_matrix(CFeatures* features)
{
	// shorthand for simplefeatures
	CSimpleFeatures<float64_t>* simple_features = (CSimpleFeatures<float64_t>*) features;
	ASSERT(simple_features);

	// get dimensionality and number of vectors of data
	int32_t dim = simple_features->get_num_features();
	ASSERT(m_target_dim<=dim);
	int32_t N = simple_features->get_num_vectors();
	ASSERT(m_k<N);

	// loop variables
	int32_t t;

	// compute distance matrix
	CDistance* distance = new CEuclidianDistance(simple_features,simple_features);
	SGMatrix<int32_t> neighborhood_matrix = get_neighborhood_matrix(distance);

	// init W (weight) matrix
	float64_t* W_matrix = SG_CALLOC(float64_t, N*N);

#ifndef WIN32
	int32_t num_threads = parallel->get_num_threads();
	ASSERT(num_threads>0);
	// allocate threads and params
	pthread_t* threads = SG_MALLOC(pthread_t, num_threads);
	D_THREAD_PARAM* parameters = SG_MALLOC(D_THREAD_PARAM, num_threads);
#else
	int32_t num_threads = 1;
#endif

	// init matrices and norm factor to be used
	float64_t* local_feature_matrix = SG_MALLOC(float64_t, m_k*dim*num_threads);
	float64_t* mean_vector = SG_MALLOC(float64_t, dim*num_threads);
	float64_t* q_matrix = SG_MALLOC(float64_t, m_k*m_k*num_threads);
	float64_t* s_values_vector = SG_MALLOC(float64_t, dim*num_threads);
	float64_t* G_matrix = SG_MALLOC(float64_t, m_k*(1+m_target_dim)*num_threads);

	// get feature matrix
	SGMatrix<float64_t> feature_matrix = simple_features->get_feature_matrix();

#ifndef WIN32
	pthread_mutex_t W_matrix_mutex;
	pthread_attr_t attr;
	pthread_mutex_init(&W_matrix_mutex, NULL);
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

	for (t=0; t<num_threads; t++)
	{
		parameters[t].idx_start = t;
		parameters[t].idx_step = num_threads;
		parameters[t].idx_stop = N;
		parameters[t].m_k = m_k;
		parameters[t].m_target_dim = m_target_dim;
		parameters[t].dim = dim;
		parameters[t].N = N;
		parameters[t].neighborhood_matrix = neighborhood_matrix.matrix;
		parameters[t].G_matrix = G_matrix + (m_k*(1+m_target_dim))*t;
		parameters[t].mean_vector = mean_vector + dim*t;
		parameters[t].local_feature_matrix = local_feature_matrix + (m_k*dim)*t;
		parameters[t].feature_matrix = feature_matrix.matrix;
		parameters[t].s_values_vector = s_values_vector + dim*t;
		parameters[t].q_matrix = q_matrix + (m_k*m_k)*t;
		parameters[t].W_matrix = W_matrix;
		parameters[t].W_matrix_mutex = &W_matrix_mutex;
		pthread_create(&threads[t], &attr, run_ltsa_thread, (void*)&parameters[t]);
	}
	for (t=0; t<num_threads; t++)
		pthread_join(threads[t], NULL);
	//pthread_mutex_destroy(&W_matrix_mutex);
	SG_FREE(parameters);
	SG_FREE(threads);
	//pthread_exit(NULL);
#else
	D_THREAD_PARAM single_thread_param;
	single_thread_param.idx_start = 0;
	single_thread_param.idx_step = 1;
	single_thread_param.idx_stop = N;
	single_thread_param.m_k = m_k;
	single_thread_param.m_target_dim = m_target_dim;
	single_thread_param.dim = dim;
	single_thread_param.N = N;
	single_thread_param.neighborhood_matrix = neighborhood_matrix.matrix;
	single_thread_param.G_matrix = G_matrix;
	single_thread_param.mean_vector = mean_vector;
	single_thread_param.local_feature_matrix = local_feature_matrix;
	single_thread_param.feature_matrix = feature_matrix.matrix;
	single_thread_param.s_values_vector = s_values_vector;
	single_thread_param.q_matrix = q_matrix;
	single_thread_param.W_matrix = W_matrix;
	run_ltsa_thread((void*)&single_thread_param);
#endif

	// clean
	SG_FREE(G_matrix);
	SG_FREE(s_values_vector);
	SG_FREE(mean_vector);
	neighborhood_matrix.destroy_matrix();
	SG_FREE(local_feature_matrix);
	SG_FREE(q_matrix);

	// finally construct embedding
	SGMatrix<float64_t> W_sgmatrix(W_matrix,N,N);
	simple_features->set_feature_matrix(find_null_space(W_sgmatrix,m_target_dim,false));
	W_sgmatrix.destroy_matrix();

	return simple_features->get_feature_matrix();
}

SGVector<float64_t> CLocalTangentSpaceAlignment::apply_to_feature_vector(SGVector<float64_t> vector)
{
	SG_NOTIMPLEMENTED;
	return vector;
}

void* CLocalTangentSpaceAlignment::run_ltsa_thread(void* p)
{
	D_THREAD_PARAM* parameters = (D_THREAD_PARAM*)p;
	int32_t idx_start = parameters->idx_start;
	int32_t idx_step = parameters->idx_step;
	int32_t idx_stop = parameters->idx_stop;
	int32_t m_k = parameters->m_k;
	int32_t m_target_dim = parameters->m_target_dim;
	int32_t dim = parameters->dim;
	int32_t N = parameters->N;
	const int32_t* neighborhood_matrix = parameters->neighborhood_matrix;
	float64_t* G_matrix = parameters->G_matrix;
	float64_t* mean_vector = parameters->mean_vector;
	float64_t* local_feature_matrix = parameters->local_feature_matrix;
	const float64_t* feature_matrix = parameters->feature_matrix;
	float64_t* s_values_vector = parameters->s_values_vector;
	float64_t* q_matrix = parameters->q_matrix;
	float64_t* W_matrix = parameters->W_matrix;
	pthread_mutex_t* W_matrix_mutex = parameters->W_matrix_mutex;

	int i,j,k;

	for (i=idx_start; i<idx_stop; i+=idx_step)
	{
		for (j=0; j<m_k; j++)
			G_matrix[j] = 1.0/CMath::sqrt((float64_t)m_k);

		// fill mean vector with zeros
		for (j=0; j<dim; j++)
			mean_vector[j] = 0.0;

		// compute local feature matrix containing neighbors of i-th vector
		for (j=0; j<m_k; j++)
		{
			for (k=0; k<dim; k++)
			{
				local_feature_matrix[j*dim+k] = feature_matrix[neighborhood_matrix[j*N+i]*dim+k];
				mean_vector[k] += local_feature_matrix[j*dim+k];
			}
		}

		// compute mean
		for (j=0; j<dim; j++)
			mean_vector[j] /= m_k;

		// center feature vectors by mean
		for (j=0; j<m_k; j++)
		{
			for (k=0; k<dim; k++)
				local_feature_matrix[j*dim+k] -= mean_vector[k];
		}

		int32_t info = 0;
		// find right eigenvectors of local_feature_matrix
		wrap_dgesvd('N','O', dim,m_k,local_feature_matrix,dim,
		                     s_values_vector,
		                     NULL,1, NULL,1, &info);
		ASSERT(info==0);

		for (j=0; j<m_target_dim; j++)
		{
			for (k=0; k<m_k; k++)
				G_matrix[(j+1)*m_k+k] = local_feature_matrix[k*dim+j];
		}

		// compute GG'
		cblas_dgemm(CblasColMajor,CblasNoTrans,CblasTrans,
		            m_k,m_k,1+m_target_dim,
		            1.0,G_matrix,m_k,
		                G_matrix,m_k,
		            0.0,q_matrix,m_k);

		// W[neighbors of i, neighbors of i] = I - GG'
#ifndef WIN32
		pthread_mutex_lock(W_matrix_mutex);
#endif
		for (j=0; j<m_k; j++)
		{
			W_matrix[N*neighborhood_matrix[j*N+i]+neighborhood_matrix[j*N+i]] += 1.0;
			for (k=0; k<m_k; k++)
				W_matrix[N*neighborhood_matrix[k*N+i]+neighborhood_matrix[j*N+i]] -= q_matrix[j*m_k+k];
		}
#ifndef WIN32
		pthread_mutex_unlock(W_matrix_mutex);
#endif
	}
	return NULL;
}

#endif /* HAVE_LAPACK */
<commit_msg>Some clean for LTSA parallelization<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) 2011 Sergey Lisitsyn
 * Copyright (C) 2011 Berlin Institute of Technology and Max-Planck-Society
 */

#include <shogun/preprocessor/LocalTangentSpaceAlignment.h>
#ifdef HAVE_LAPACK
#include <shogun/mathematics/arpack.h>
#include <shogun/mathematics/lapack.h>
#include <shogun/lib/common.h>
#include <shogun/mathematics/Math.h>
#include <shogun/io/SGIO.h>
#include <shogun/distance/EuclidianDistance.h>
#include <shogun/lib/Signal.h>

#ifndef WIN32
#include <pthread.h>
#endif

using namespace shogun;

#ifndef DOXYGEN_SHOULD_SKIP_THIS
struct D_THREAD_PARAM
{
	int32_t idx_start;
	int32_t idx_step;
	int32_t idx_stop;
	int32_t m_k;
	int32_t m_target_dim;
	int32_t dim;
	int32_t N;
	const int32_t* neighborhood_matrix;
	float64_t* G_matrix;
	float64_t* mean_vector;
	float64_t* local_feature_matrix;
	const float64_t* feature_matrix;
	float64_t* s_values_vector;
	float64_t* q_matrix;
	float64_t* W_matrix;
#ifndef WIN32
	pthread_mutex_t* W_matrix_mutex;
#endif
};
#endif

CLocalTangentSpaceAlignment::CLocalTangentSpaceAlignment() :
		CLocallyLinearEmbedding()
{
}

CLocalTangentSpaceAlignment::~CLocalTangentSpaceAlignment()
{
}

bool CLocalTangentSpaceAlignment::init(CFeatures* features)
{
	return true;
}

void CLocalTangentSpaceAlignment::cleanup()
{
}

SGMatrix<float64_t> CLocalTangentSpaceAlignment::apply_to_feature_matrix(CFeatures* features)
{
	// shorthand for simplefeatures
	CSimpleFeatures<float64_t>* simple_features = (CSimpleFeatures<float64_t>*) features;
	ASSERT(simple_features);

	// get dimensionality and number of vectors of data
	int32_t dim = simple_features->get_num_features();
	ASSERT(m_target_dim<=dim);
	int32_t N = simple_features->get_num_vectors();
	ASSERT(m_k<N);

	// loop variables
	int32_t t;

	// compute distance matrix
	CDistance* distance = new CEuclidianDistance(simple_features,simple_features);
	SGMatrix<int32_t> neighborhood_matrix = get_neighborhood_matrix(distance);

	// init W (weight) matrix
	float64_t* W_matrix = SG_CALLOC(float64_t, N*N);

#ifndef WIN32
	int32_t num_threads = parallel->get_num_threads();
	ASSERT(num_threads>0);
	// allocate threads and params
	pthread_t* threads = SG_MALLOC(pthread_t, num_threads);
	D_THREAD_PARAM* parameters = SG_MALLOC(D_THREAD_PARAM, num_threads);
#else
	int32_t num_threads = 1;
#endif

	// init matrices and norm factor to be used
	float64_t* local_feature_matrix = SG_MALLOC(float64_t, m_k*dim*num_threads);
	float64_t* mean_vector = SG_MALLOC(float64_t, dim*num_threads);
	float64_t* q_matrix = SG_MALLOC(float64_t, m_k*m_k*num_threads);
	float64_t* s_values_vector = SG_MALLOC(float64_t, dim*num_threads);
	float64_t* G_matrix = SG_MALLOC(float64_t, m_k*(1+m_target_dim)*num_threads);

	// get feature matrix
	SGMatrix<float64_t> feature_matrix = simple_features->get_feature_matrix();

#ifndef WIN32
	pthread_mutex_t W_matrix_mutex;
	pthread_attr_t attr;
	pthread_mutex_init(&W_matrix_mutex, NULL);
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

	for (t=0; t<num_threads; t++)
	{
		parameters[t].idx_start = t;
		parameters[t].idx_step = num_threads;
		parameters[t].idx_stop = N;
		parameters[t].m_k = m_k;
		parameters[t].m_target_dim = m_target_dim;
		parameters[t].dim = dim;
		parameters[t].N = N;
		parameters[t].neighborhood_matrix = neighborhood_matrix.matrix;
		parameters[t].G_matrix = G_matrix + (m_k*(1+m_target_dim))*t;
		parameters[t].mean_vector = mean_vector + dim*t;
		parameters[t].local_feature_matrix = local_feature_matrix + (m_k*dim)*t;
		parameters[t].feature_matrix = feature_matrix.matrix;
		parameters[t].s_values_vector = s_values_vector + dim*t;
		parameters[t].q_matrix = q_matrix + (m_k*m_k)*t;
		parameters[t].W_matrix = W_matrix;
		parameters[t].W_matrix_mutex = &W_matrix_mutex;
		pthread_create(&threads[t], &attr, run_ltsa_thread, (void*)&parameters[t]);
	}
	for (t=0; t<num_threads; t++)
		pthread_join(threads[t], NULL);
	pthread_mutex_destroy(&W_matrix_mutex);
	SG_FREE(parameters);
	SG_FREE(threads);
#else
	D_THREAD_PARAM single_thread_param;
	single_thread_param.idx_start = 0;
	single_thread_param.idx_step = 1;
	single_thread_param.idx_stop = N;
	single_thread_param.m_k = m_k;
	single_thread_param.m_target_dim = m_target_dim;
	single_thread_param.dim = dim;
	single_thread_param.N = N;
	single_thread_param.neighborhood_matrix = neighborhood_matrix.matrix;
	single_thread_param.G_matrix = G_matrix;
	single_thread_param.mean_vector = mean_vector;
	single_thread_param.local_feature_matrix = local_feature_matrix;
	single_thread_param.feature_matrix = feature_matrix.matrix;
	single_thread_param.s_values_vector = s_values_vector;
	single_thread_param.q_matrix = q_matrix;
	single_thread_param.W_matrix = W_matrix;
	run_ltsa_thread((void*)&single_thread_param);
#endif

	// clean
	SG_FREE(G_matrix);
	SG_FREE(s_values_vector);
	SG_FREE(mean_vector);
	neighborhood_matrix.destroy_matrix();
	SG_FREE(local_feature_matrix);
	SG_FREE(q_matrix);

	// finally construct embedding
	SGMatrix<float64_t> W_sgmatrix(W_matrix,N,N);
	simple_features->set_feature_matrix(find_null_space(W_sgmatrix,m_target_dim,false));
	W_sgmatrix.destroy_matrix();

	return simple_features->get_feature_matrix();
}

SGVector<float64_t> CLocalTangentSpaceAlignment::apply_to_feature_vector(SGVector<float64_t> vector)
{
	SG_NOTIMPLEMENTED;
	return vector;
}

void* CLocalTangentSpaceAlignment::run_ltsa_thread(void* p)
{
	D_THREAD_PARAM* parameters = (D_THREAD_PARAM*)p;
	int32_t idx_start = parameters->idx_start;
	int32_t idx_step = parameters->idx_step;
	int32_t idx_stop = parameters->idx_stop;
	int32_t m_k = parameters->m_k;
	int32_t m_target_dim = parameters->m_target_dim;
	int32_t dim = parameters->dim;
	int32_t N = parameters->N;
	const int32_t* neighborhood_matrix = parameters->neighborhood_matrix;
	float64_t* G_matrix = parameters->G_matrix;
	float64_t* mean_vector = parameters->mean_vector;
	float64_t* local_feature_matrix = parameters->local_feature_matrix;
	const float64_t* feature_matrix = parameters->feature_matrix;
	float64_t* s_values_vector = parameters->s_values_vector;
	float64_t* q_matrix = parameters->q_matrix;
	float64_t* W_matrix = parameters->W_matrix;
#ifndef WIN32
	pthread_mutex_t* W_matrix_mutex = parameters->W_matrix_mutex;
#endif

	int i,j,k;

	for (i=idx_start; i<idx_stop; i+=idx_step)
	{
		for (j=0; j<m_k; j++)
			G_matrix[j] = 1.0/CMath::sqrt((float64_t)m_k);

		// fill mean vector with zeros
		for (j=0; j<dim; j++)
			mean_vector[j] = 0.0;

		// compute local feature matrix containing neighbors of i-th vector
		for (j=0; j<m_k; j++)
		{
			for (k=0; k<dim; k++)
			{
				local_feature_matrix[j*dim+k] = feature_matrix[neighborhood_matrix[j*N+i]*dim+k];
				mean_vector[k] += local_feature_matrix[j*dim+k];
			}
		}

		// compute mean
		for (j=0; j<dim; j++)
			mean_vector[j] /= m_k;

		// center feature vectors by mean
		for (j=0; j<m_k; j++)
		{
			for (k=0; k<dim; k++)
				local_feature_matrix[j*dim+k] -= mean_vector[k];
		}

		int32_t info = 0;
		// find right eigenvectors of local_feature_matrix
		wrap_dgesvd('N','O', dim,m_k,local_feature_matrix,dim,
		                     s_values_vector,
		                     NULL,1, NULL,1, &info);
		ASSERT(info==0);

		for (j=0; j<m_target_dim; j++)
		{
			for (k=0; k<m_k; k++)
				G_matrix[(j+1)*m_k+k] = local_feature_matrix[k*dim+j];
		}

		// compute GG'
		cblas_dgemm(CblasColMajor,CblasNoTrans,CblasTrans,
		            m_k,m_k,1+m_target_dim,
		            1.0,G_matrix,m_k,
		                G_matrix,m_k,
		            0.0,q_matrix,m_k);

		// W[neighbors of i, neighbors of i] = I - GG'
#ifndef WIN32
		pthread_mutex_lock(W_matrix_mutex);
#endif
		for (j=0; j<m_k; j++)
		{
			W_matrix[N*neighborhood_matrix[j*N+i]+neighborhood_matrix[j*N+i]] += 1.0;
			for (k=0; k<m_k; k++)
				W_matrix[N*neighborhood_matrix[k*N+i]+neighborhood_matrix[j*N+i]] -= q_matrix[j*m_k+k];
		}
#ifndef WIN32
		pthread_mutex_unlock(W_matrix_mutex);
#endif
	}
	return NULL;
}

#endif /* HAVE_LAPACK */
<|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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*   Product name: redemption, a FLOSS RDP proxy
*   Copyright (C) Wallix 2010-2015
*   Author(s): Jonathan Poelen
*/

#ifndef PPOCR_SRC_OCR2_PROBABILITIES_HPP
#define PPOCR_SRC_OCR2_PROBABILITIES_HPP

#include <new>
#include <utility>
#include <algorithm>

namespace ppocr { namespace ocr2 {

struct Probability
{
    unsigned i;
    double prob;

    Probability(unsigned i) noexcept
    : i(i)
    {}

    Probability(unsigned i, double prob) noexcept
    : i(i)
    , prob(prob)
    {}
};

struct Probabilities
{
    using iterator = Probability *;
    using size_type = std::size_t;

    Probabilities(size_type sz)
    : data(static_cast<Probability*>(::operator new(sz * sizeof(Probability))))
    , current(data)
    {}

    template<class It>
    Probabilities(It first, It last)
    : data(static_cast<Probability*>(::operator new((last-first) * sizeof(Probability))))
    , current(data + (last-first))
    { std::copy(first, last, data); }

    Probabilities(Probabilities &&) = delete;
    Probabilities(Probabilities const &) = delete;

    void swap(Probabilities & p) noexcept
    {
        std::swap(p.data, data);
        std::swap(p.current, current);
    }

    ~Probabilities() {
      ::operator delete(this->data);
    }

    iterator begin() const { return data; }
    iterator end() const { return current; }
    size_type size() const { return current - data; }
    bool empty() const { return current == data; }
    void push_back(Probability const & p) { *current++ = p; }
    template<class... Args>
    void emplace_back(Args const & ... args) { *current++ = {args...}; }
    void clear() { current = data; }

    Probability const & front() const { return *data; }
    Probability const & back() const { return *(current-1); }
    Probability const & operator[](size_type i) const { return data[i]; }

    void resize(size_type n) {
        current = data + n;
    }

private:
    Probability * data;
    Probability * current;
};

void swap(Probabilities & a, Probabilities & b) noexcept
{ a.swap(b); }

struct GtProb {
    GtProb() {}
    bool operator()(Probability const & a, Probability const & b) const {
        return a.prob > b.prob;
    }
};

} }

#endif
<commit_msg>fix multiple definition<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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*   Product name: redemption, a FLOSS RDP proxy
*   Copyright (C) Wallix 2010-2015
*   Author(s): Jonathan Poelen
*/

#ifndef PPOCR_SRC_OCR2_PROBABILITIES_HPP
#define PPOCR_SRC_OCR2_PROBABILITIES_HPP

#include <new>
#include <utility>
#include <algorithm>

namespace ppocr { namespace ocr2 {

struct Probability
{
    unsigned i;
    double prob;

    Probability(unsigned i) noexcept
    : i(i)
    {}

    Probability(unsigned i, double prob) noexcept
    : i(i)
    , prob(prob)
    {}
};

struct Probabilities
{
    using iterator = Probability *;
    using size_type = std::size_t;

    Probabilities(size_type sz)
    : data(static_cast<Probability*>(::operator new(sz * sizeof(Probability))))
    , current(data)
    {}

    template<class It>
    Probabilities(It first, It last)
    : data(static_cast<Probability*>(::operator new((last-first) * sizeof(Probability))))
    , current(data + (last-first))
    { std::copy(first, last, data); }

    Probabilities(Probabilities &&) = delete;
    Probabilities(Probabilities const &) = delete;

    void swap(Probabilities & p) noexcept
    {
        std::swap(p.data, data);
        std::swap(p.current, current);
    }

    ~Probabilities() {
      ::operator delete(this->data);
    }

    iterator begin() const { return data; }
    iterator end() const { return current; }
    size_type size() const { return current - data; }
    bool empty() const { return current == data; }
    void push_back(Probability const & p) { *current++ = p; }
    template<class... Args>
    void emplace_back(Args const & ... args) { *current++ = {args...}; }
    void clear() { current = data; }

    Probability const & front() const { return *data; }
    Probability const & back() const { return *(current-1); }
    Probability const & operator[](size_type i) const { return data[i]; }

    void resize(size_type n) {
        current = data + n;
    }

private:
    Probability * data;
    Probability * current;
};

inline void swap(Probabilities & a, Probabilities & b) noexcept
{ a.swap(b); }

struct GtProb {
    GtProb() {}
    bool operator()(Probability const & a, Probability const & b) const {
        return a.prob > b.prob;
    }
};

} }

#endif
<|endoftext|>


<commit_before>//
// Created by Artur Troian on 10/20/16.
//
#include <propertypp/sqlite.hpp>
#include <tools/base64.hpp>

#include <exception>
#include <stdexcept>

#include <cstdlib>
#include <iostream>

namespace property {

int sqlite_property::select_exec_cb(void *ptr, int argc, char **argv, char **names)
{
	// suppress: warning: unused parameter 'names' [-Wunused-parameter]
	(void)names;

	req_value *value = reinterpret_cast<req_value *>(ptr);

	value->found = true;

	if (argc == 2) {
		value->blob  = std::string(argv[0]);
		value->type  = (value_type)atoi(argv[1]);
		value->valid = true;
	} else {
		value->valid = false;
	}

	return 0;
}

int sqlite_property::type_exec_cb(void *ptr, int argc, char **argv, char **names)
{
	// suppress: warning: unused parameter 'names' [-Wunused-parameter]
	(void)names;

	req_value *value = reinterpret_cast<req_value *>(ptr);

	value->found = true;

	if (argc == 1) {
		value->type  = (value_type)atoi(argv[1]);
		value->valid = true;
	} else {
		value->valid = false;
	}

	return 0;
}

const std::string sqlite_property::property_table_("property_table");

sqlite_property::sqlite_property(const std::string &db) :
	  prop()
	, db_(NULL)
{
	std::string uri(db);

	if (sqlite3_open(db.c_str(), &db_) != SQLITE_OK) {
		std::string error ("Couldn't open database file");
		error += sqlite3_errmsg(db_);
		sqlite3_close(db_);
		throw std::runtime_error(error);
	}

//	sqlite3_extended_result_codes(db_, true);
	const char *sql = "CREATE TABLE IF NOT EXISTS property_table(key STRING PRIMARY KEY, value BLOB, type INTEGER);";

	if (sqlite3_exec(db_, sql, 0, 0, 0) != SQLITE_OK) {
		std::string error ("Couldn't create table");
		error += sqlite3_errmsg(db_);
		sqlite3_close(db_);
		throw std::runtime_error(error);
	}
}

sqlite_property::~sqlite_property()
{
	sqlite3_close(db_);
}

prop_status sqlite_property::get(const std::string &key, void *value, value_type type)
{
	std::string sql = "SELECT value, type FROM " + property_table_ + " WHERE key = \'" + key + "\'";
	int ret;
	char *errmsg = NULL;
	req_value rsp;

	ret = sqlite3_exec(db_, sql.c_str(), select_exec_cb, &rsp, &errmsg);

	if (ret == SQLITE_OK) {
		if (rsp.found) {
			if (type != rsp.type)
				return prop_status::PROP_STATUS_INVALID_TYPE;
			else {
				switch (type) {
				case value_type::VALUE_TYPE_STRING: {
					std::string *val = reinterpret_cast<std::string *>(value);
					*val = rsp.blob;
					break;
				}
				case value_type::VALUE_TYPE_INT: {
					int32_t *val = reinterpret_cast<int32_t *>(value);
					*val = std::stoi(rsp.blob);
					break;
				}
				case value_type::VALUE_TYPE_INT64: {
					int64_t *val = reinterpret_cast<int64_t *>(value);
					*val = std::stoll(rsp.blob);
					break;
				}
				case value_type::VALUE_TYPE_DOUBLE: {
					double *val = reinterpret_cast<double *>(value);
					*val = std::stod(rsp.blob);
					break;
				}
				case value_type::VALUE_TYPE_BOOL: {
					bool *val = reinterpret_cast<bool *>(value);

					if (rsp.blob.compare("false") == 0)
						*val = false;
					else
						*val = true;

					break;
				}
				case value_type::VALUE_TYPE_BLOB: {
					prop::blob_type *val = reinterpret_cast<prop::blob_type *>(value);

					prop::blob_type tmp = tools::base64::decode<prop::blob_type>(rsp.blob);
					*val = std::move(tmp);
					break;
				}
				}
			}
		} else {
			return prop_status::PROP_STATUS_NOT_FOUND;
		}

	} else {
		sqlite3_free(errmsg);
		std::cout << "Error: " << ret << std::endl;
		return prop_status::PROP_STATUS_UNKNOWN_ERROR;
	}

	return prop_status::PROP_STATUS_OK;
}

prop_status sqlite_property::set(const std::string &key, const void * const val, value_type type, bool update)
{
	prop_status ret = prop_status::PROP_STATUS_OK;

	std::string sql = "INSERT INTO " + property_table_ + "(key, value, type) values (?,?,?)";
	sqlite3_stmt *stmt;

	std::string value;

	switch (type) {
	case value_type::VALUE_TYPE_STRING: {
		value = *(reinterpret_cast<const std::string * const>(val));
		break;
	}
	case value_type::VALUE_TYPE_INT: {
		const int32_t * const v = reinterpret_cast<const int32_t * const>(val);
		value = std::to_string(*v);
		break;
	}
	case value_type::VALUE_TYPE_INT64: {
		const int64_t * const v = reinterpret_cast<const int64_t * const>(val);
		value = std::to_string(*v);
		break;
	}
	case value_type::VALUE_TYPE_DOUBLE: {
		const double * const v = reinterpret_cast<const double * const>(val);
		value = std::to_string(*v);
		break;
	}
	case value_type::VALUE_TYPE_BOOL: {
		const bool * const v = reinterpret_cast<const bool * const>(val);
		value = (*v) == true ? "true" : "false";
		break;
	}
	case value_type::VALUE_TYPE_BLOB: {
		const prop::blob_type * const v = reinterpret_cast<const prop::blob_type * const>(val);
		tools::base64::encode(value, v);
		break;
	}
	default:
		break;
	}

	int rc = sqlite3_prepare_v2(db_, sql.c_str(), sql.size(), &stmt, NULL);

	if (rc == SQLITE_OK) {
		// bind values

		sqlite3_bind_text(stmt, 1, key.c_str(), key.size(), 0);
		sqlite3_bind_blob(stmt, 2, value.c_str(), value.size(), NULL);
		sqlite3_bind_int(stmt, 3, (int)type);

		// commit
		sqlite3_step(stmt);
		rc = sqlite3_finalize(stmt);

		if (rc != SQLITE_OK) {
			if (rc == SQLITE_CONSTRAINT) {
				if (update == false) {
					ret = prop_status::PROP_STATUS_ALREADY_EXISTS;
				} else {
					value_type prop_type;

					ret = sqlite_property::type(key, prop_type);
					if (ret == prop_status::PROP_STATUS_OK) {
						if (prop_type != type) {
							ret = prop_status::PROP_STATUS_INVALID_TYPE;
						} else {
							sql = "UPDATE " + property_table_ + " SET value = ? WHERE key = \'" + key + "\'";
							rc = sqlite3_prepare_v2(db_, sql.c_str(), sql.size(), &stmt, NULL);
							if (rc == SQLITE_OK) {
								sqlite3_bind_blob(stmt, 1, value.c_str(), value.size(), NULL);

								sqlite3_step(stmt);
								rc = sqlite3_finalize(stmt);

								if (rc != SQLITE_OK) {
									ret = prop_status::PROP_STATUS_UNKNOWN_ERROR;
									std::cerr << "Error commiting: " << sqlite3_errmsg(db_) << std::endl;
								} else {
									ret = prop_status::PROP_STATUS_OK;
								}
							} else {
								std::cerr << "Error commiting: " << sqlite3_errmsg(db_) << std::endl;
								ret = prop_status::PROP_STATUS_UNKNOWN_ERROR;
							}
						}
					}
				}
			} else {
				ret = prop_status::PROP_STATUS_UNKNOWN_ERROR;
			}
		}
	} else {
		std::cout << "Error commiting: " << sqlite3_errmsg(db_) << std::endl;
	}

	return ret;
}

prop_status sqlite_property::del(const std::string &key)
{
	prop_status ret = prop_status::PROP_STATUS_OK;

	std::string sql = "DELETE FROM " + property_table_ + " WHERE key = \'" + key + "\'";

	sqlite3_stmt *stmt;

	if (sqlite3_prepare_v2(db_, sql.c_str(), sql.size(), &stmt, NULL) == SQLITE_OK) {
		while (sqlite3_step(stmt) == SQLITE_DONE) {}
		ret = prop_status::PROP_STATUS_OK;
	} else {
		ret = prop_status::PROP_STATUS_UNKNOWN_ERROR;
	}

	sqlite3_finalize(stmt);

	return ret;
}

prop_status sqlite_property::type(const std::string &key, value_type &type) const
{
	prop_status retval = prop_status::PROP_STATUS_OK;

	std::string sql = "SELECT type FROM " + property_table_ + " WHERE key = \'" + key + "\'";

	int ret;
	char *errmsg = NULL;
	req_value rsp;

	ret = sqlite3_exec(db_, sql.c_str(), type_exec_cb, &rsp, &errmsg);

	if (ret == SQLITE_OK) {
		if (rsp.found) {
	   	    type = rsp.type;
		} else {
			retval = prop_status::PROP_STATUS_NOT_FOUND;
		}
	} else {
		sqlite3_free(errmsg);
		retval = prop_status::PROP_STATUS_UNKNOWN_ERROR;
	}

	return retval;
}

prop_status sqlite_property::type(const std::string &key, value_type &type)
{
	prop_status retval = prop_status::PROP_STATUS_OK;

	std::string sql = "SELECT type FROM " + property_table_ + " WHERE key = \'" + key + "\'";

	int ret;
	char *errmsg = NULL;
	req_value rsp;

	ret = sqlite3_exec(db_, sql.c_str(), type_exec_cb, &rsp, &errmsg);

	if (ret == SQLITE_OK) {
		if (rsp.found) {
			type = rsp.type;
		} else {
			retval = prop_status::PROP_STATUS_NOT_FOUND;
		}
	} else {
		sqlite3_free(errmsg);
		retval = prop_status::PROP_STATUS_UNKNOWN_ERROR;
	}

	return retval;
}

} // namespace property
<commit_msg>Fix array access offset for type value<commit_after>//
// Created by Artur Troian on 10/20/16.
//
#include <propertypp/sqlite.hpp>
#include <tools/base64.hpp>

#include <exception>
#include <stdexcept>

#include <cstdlib>
#include <iostream>

namespace property {

int sqlite_property::select_exec_cb(void *ptr, int argc, char **argv, char **names)
{
	// suppress: warning: unused parameter 'names' [-Wunused-parameter]
	(void)names;

	req_value *value = reinterpret_cast<req_value *>(ptr);

	value->found = true;

	if (argc == 2) {
		value->blob  = std::string(argv[0]);
		value->type  = (value_type)atoi(argv[1]);
		value->valid = true;
	} else {
		value->valid = false;
	}

	return 0;
}

int sqlite_property::type_exec_cb(void *ptr, int argc, char **argv, char **names)
{
	// suppress: warning: unused parameter 'names' [-Wunused-parameter]
	(void)names;

	req_value *value = reinterpret_cast<req_value *>(ptr);

	value->found = true;

	if (argc == 1) {
		value->type  = (value_type)atoi(argv[0]);
		value->valid = true;
	} else {
		value->valid = false;
	}

	return 0;
}

const std::string sqlite_property::property_table_("property_table");

sqlite_property::sqlite_property(const std::string &db) :
	  prop()
	, db_(NULL)
{
	std::string uri(db);

	if (sqlite3_open(db.c_str(), &db_) != SQLITE_OK) {
		std::string error ("Couldn't open database file");
		error += sqlite3_errmsg(db_);
		sqlite3_close(db_);
		throw std::runtime_error(error);
	}

//	sqlite3_extended_result_codes(db_, true);
	const char *sql = "CREATE TABLE IF NOT EXISTS property_table(key STRING PRIMARY KEY, value BLOB, type INTEGER);";

	if (sqlite3_exec(db_, sql, 0, 0, 0) != SQLITE_OK) {
		std::string error ("Couldn't create table");
		error += sqlite3_errmsg(db_);
		sqlite3_close(db_);
		throw std::runtime_error(error);
	}
}

sqlite_property::~sqlite_property()
{
	sqlite3_close(db_);
}

prop_status sqlite_property::get(const std::string &key, void *value, value_type type)
{
	std::string sql = "SELECT value, type FROM " + property_table_ + " WHERE key = \'" + key + "\'";
	int ret;
	char *errmsg = NULL;
	req_value rsp;

	ret = sqlite3_exec(db_, sql.c_str(), select_exec_cb, &rsp, &errmsg);

	if (ret == SQLITE_OK) {
		if (rsp.found) {
			if (type != rsp.type)
				return prop_status::PROP_STATUS_INVALID_TYPE;
			else {
				switch (type) {
				case value_type::VALUE_TYPE_STRING: {
					std::string *val = reinterpret_cast<std::string *>(value);
					*val = rsp.blob;
					break;
				}
				case value_type::VALUE_TYPE_INT: {
					int32_t *val = reinterpret_cast<int32_t *>(value);
					*val = std::stoi(rsp.blob);
					break;
				}
				case value_type::VALUE_TYPE_INT64: {
					int64_t *val = reinterpret_cast<int64_t *>(value);
					*val = std::stoll(rsp.blob);
					break;
				}
				case value_type::VALUE_TYPE_DOUBLE: {
					double *val = reinterpret_cast<double *>(value);
					*val = std::stod(rsp.blob);
					break;
				}
				case value_type::VALUE_TYPE_BOOL: {
					bool *val = reinterpret_cast<bool *>(value);

					if (rsp.blob.compare("false") == 0)
						*val = false;
					else
						*val = true;

					break;
				}
				case value_type::VALUE_TYPE_BLOB: {
					prop::blob_type *val = reinterpret_cast<prop::blob_type *>(value);

					prop::blob_type tmp = tools::base64::decode<prop::blob_type>(rsp.blob);
					*val = std::move(tmp);
					break;
				}
				}
			}
		} else {
			return prop_status::PROP_STATUS_NOT_FOUND;
		}

	} else {
		sqlite3_free(errmsg);
		std::cout << "Error: " << ret << std::endl;
		return prop_status::PROP_STATUS_UNKNOWN_ERROR;
	}

	return prop_status::PROP_STATUS_OK;
}

prop_status sqlite_property::set(const std::string &key, const void * const val, value_type type, bool update)
{
	prop_status ret = prop_status::PROP_STATUS_OK;

	std::string sql = "INSERT INTO " + property_table_ + "(key, value, type) values (?,?,?)";
	sqlite3_stmt *stmt;

	std::string value;

	switch (type) {
	case value_type::VALUE_TYPE_STRING: {
		value = *(reinterpret_cast<const std::string * const>(val));
		break;
	}
	case value_type::VALUE_TYPE_INT: {
		const int32_t * const v = reinterpret_cast<const int32_t * const>(val);
		value = std::to_string(*v);
		break;
	}
	case value_type::VALUE_TYPE_INT64: {
		const int64_t * const v = reinterpret_cast<const int64_t * const>(val);
		value = std::to_string(*v);
		break;
	}
	case value_type::VALUE_TYPE_DOUBLE: {
		const double * const v = reinterpret_cast<const double * const>(val);
		value = std::to_string(*v);
		break;
	}
	case value_type::VALUE_TYPE_BOOL: {
		const bool * const v = reinterpret_cast<const bool * const>(val);
		value = (*v) == true ? "true" : "false";
		break;
	}
	case value_type::VALUE_TYPE_BLOB: {
		const prop::blob_type * const v = reinterpret_cast<const prop::blob_type * const>(val);
		tools::base64::encode(value, v);
		break;
	}
	default:
		break;
	}

	int rc = sqlite3_prepare_v2(db_, sql.c_str(), sql.size(), &stmt, NULL);

	if (rc == SQLITE_OK) {
		// bind values

		sqlite3_bind_text(stmt, 1, key.c_str(), key.size(), 0);
		sqlite3_bind_blob(stmt, 2, value.c_str(), value.size(), NULL);
		sqlite3_bind_int(stmt, 3, (int)type);

		// commit
		sqlite3_step(stmt);
		rc = sqlite3_finalize(stmt);

		if (rc != SQLITE_OK) {
			if (rc == SQLITE_CONSTRAINT) {
				if (update == false) {
					ret = prop_status::PROP_STATUS_ALREADY_EXISTS;
				} else {
					value_type prop_type;

					ret = sqlite_property::type(key, prop_type);
					if (ret == prop_status::PROP_STATUS_OK) {
						if (prop_type != type) {
							ret = prop_status::PROP_STATUS_INVALID_TYPE;
						} else {
							sql = "UPDATE " + property_table_ + " SET value = ? WHERE key = \'" + key + "\'";
							rc = sqlite3_prepare_v2(db_, sql.c_str(), sql.size(), &stmt, NULL);
							if (rc == SQLITE_OK) {
								sqlite3_bind_blob(stmt, 1, value.c_str(), value.size(), NULL);

								sqlite3_step(stmt);
								rc = sqlite3_finalize(stmt);

								if (rc != SQLITE_OK) {
									ret = prop_status::PROP_STATUS_UNKNOWN_ERROR;
									std::cerr << "Error commiting: " << sqlite3_errmsg(db_) << std::endl;
								} else {
									ret = prop_status::PROP_STATUS_OK;
								}
							} else {
								std::cerr << "Error commiting: " << sqlite3_errmsg(db_) << std::endl;
								ret = prop_status::PROP_STATUS_UNKNOWN_ERROR;
							}
						}
					} else {
						std::cerr << "Error commiting: " << sqlite3_errmsg(db_) << std::endl;
					}
				}
			} else {
				ret = prop_status::PROP_STATUS_UNKNOWN_ERROR;
			}
		}
	} else {
		std::cout << "Error commiting: " << sqlite3_errmsg(db_) << std::endl;
	}

	return ret;
}

prop_status sqlite_property::del(const std::string &key)
{
	prop_status ret = prop_status::PROP_STATUS_OK;

	std::string sql = "DELETE FROM " + property_table_ + " WHERE key = \'" + key + "\'";

	sqlite3_stmt *stmt;

	if (sqlite3_prepare_v2(db_, sql.c_str(), sql.size(), &stmt, NULL) == SQLITE_OK) {
		while (sqlite3_step(stmt) == SQLITE_DONE) {}
		ret = prop_status::PROP_STATUS_OK;
	} else {
		ret = prop_status::PROP_STATUS_UNKNOWN_ERROR;
	}

	sqlite3_finalize(stmt);

	return ret;
}

prop_status sqlite_property::type(const std::string &key, value_type &type) const
{
	prop_status retval = prop_status::PROP_STATUS_OK;

	std::string sql = "SELECT type FROM " + property_table_ + " WHERE key = \'" + key + "\'";

	int ret;
	char *errmsg = NULL;
	req_value rsp;

	ret = sqlite3_exec(db_, sql.c_str(), type_exec_cb, &rsp, &errmsg);

	if (ret == SQLITE_OK) {
		if (rsp.found) {
	   	    type = rsp.type;
		} else {
			retval = prop_status::PROP_STATUS_NOT_FOUND;
		}
	} else {
		sqlite3_free(errmsg);
		retval = prop_status::PROP_STATUS_UNKNOWN_ERROR;
	}

	return retval;
}

prop_status sqlite_property::type(const std::string &key, value_type &type)
{
	prop_status retval = prop_status::PROP_STATUS_OK;

	std::string sql = "SELECT type FROM " + property_table_ + " WHERE key = \'" + key + "\'";

	int ret;
	char *errmsg = NULL;
	req_value rsp;

	ret = sqlite3_exec(db_, sql.c_str(), type_exec_cb, &rsp, &errmsg);

	if (ret == SQLITE_OK) {
		if (rsp.found) {
			type = rsp.type;
		} else {
			retval = prop_status::PROP_STATUS_NOT_FOUND;
		}
	} else {
		sqlite3_free(errmsg);
		retval = prop_status::PROP_STATUS_UNKNOWN_ERROR;
	}

	return retval;
}

} // namespace property
<|endoftext|>


<commit_before>// Copyright 2015-2018 Elviss Strazdins. All rights reserved.

#ifndef OUZEL_UTILS_LOG_HPP
#define OUZEL_UTILS_LOG_HPP

#include <atomic>
#include <condition_variable>
#include <mutex>
#include <queue>
#include <string>
#include <thread>
#include <vector>
#include "math/Matrix4.hpp"
#include "math/Quaternion.hpp"
#include "math/Size2.hpp"
#include "math/Size3.hpp"
#include "math/Vector2.hpp"
#include "math/Vector3.hpp"
#include "math/Vector4.hpp"

namespace ouzel
{
    class Logger;

    class Log final
    {
    public:
        enum class Level
        {
            OFF,
            ERR,
            WARN,
            INFO,
            ALL
        };

        explicit Log(const Logger& initLogger, Level initLevel = Level::INFO):
            logger(initLogger), level(initLevel)
        {
        }

        Log(const Log& other):
            logger(other.logger)
        {
            level = other.level;
            s = other.s;
        }

        Log(Log&& other):
            logger(other.logger)
        {
            level = other.level;
            other.level = Level::INFO;
            s = std::move(other.s);
        }

        Log& operator=(const Log& other)
        {
            level = other.level;
            s = other.s;

            return *this;
        }

        Log& operator=(Log&& other)
        {
            if (&other != this)
            {
                level = other.level;
                other.level = Level::INFO;
                s = std::move(other.s);
            }

            return *this;
        }

        ~Log();

        template<typename T> Log& operator<<(T val)
        {
            s += std::to_string(val);
            return *this;
        }

        Log& operator<<(const std::string& val)
        {
            s += val;
            return *this;
        }

        Log& operator<<(const char* val)
        {
            s += val;

            return *this;
        }

        Log& operator<<(char* val)
        {
            s += val;
            return *this;
        }

        Log& operator<<(const std::vector<std::string>& val)
        {
            bool first = true;

            for (const std::string& str : val)
            {
                if (!first) s += ", ";
                first = false;
                s += str;
            }

            return *this;
        }

        Log& operator<<(const Matrix4& val)
        {
            s += std::to_string(val.m[0]) + "," + std::to_string(val.m[1]) + "," + std::to_string(val.m[2]) + "," + std::to_string(val.m[3]) + "\n" +
                std::to_string(val.m[4]) + "," + std::to_string(val.m[5]) + "," + std::to_string(val.m[6]) + "," + std::to_string(val.m[7]) + "\n" +
                std::to_string(val.m[8]) + "," + std::to_string(val.m[9]) + "," + std::to_string(val.m[10]) + "," + std::to_string(val.m[11]) + "\n" +
                std::to_string(val.m[12]) + "," + std::to_string(val.m[13]) + "," + std::to_string(val.m[14]) + "," + std::to_string(val.m[15]);

            return *this;
        }

        Log& operator<<(const Quaternion& val)
        {
            s += std::to_string(val.x) + "," + std::to_string(val.y) + "," +
                std::to_string(val.z) + "," + std::to_string(val.w);

            return *this;
        }

        Log& operator<<(const Size2& val)
        {
            s += std::to_string(val.width) + "," + std::to_string(val.height);
            return *this;
        }

        Log& operator<<(const Size3& val)
        {
            s += std::to_string(val.width) + "," + std::to_string(val.height) + "," +
                std::to_string(val.depth);

            return *this;
        }

        Log& operator<<(const Vector2& val)
        {
            s += std::to_string(val.x) + "," + std::to_string(val.y);

            return *this;
        }

        Log& operator<<(const Vector3& val)
        {
            s += std::to_string(val.x) + "," + std::to_string(val.y) + "," +
                std::to_string(val.z);

            return *this;
        }

        Log& operator<<(const Vector4& val)
        {
            s += std::to_string(val.x) + "," + std::to_string(val.y) + "," +
                std::to_string(val.z) + "," + std::to_string(val.w);

            return *this;
        }

    private:
        const Logger& logger;
        Level level = Level::INFO;
        std::string s;
    };

    class Logger final
    {
    public:
        explicit Logger(Log::Level initThreshold = Log::Level::ALL):
            threshold(initThreshold)
        {
#if OUZEL_MULTITHREADED
            logThread = std::thread(&Logger::logLoop, this);
#endif
        }

        ~Logger()
        {
#if OUZEL_MULTITHREADED
            std::unique_lock<std::mutex> lock(queueMutex);
            running = false;
            lock.unlock();
            logCondition.notify_all();
#endif
        }

        Log log(Log::Level level = Log::Level::INFO) const
        {
            return Log(*this, level);
        }

        void log(const std::string& str, Log::Level level = Log::Level::INFO) const
        {
            if (level <= threshold)
            {
#if OUZEL_MULTITHREADED
                std::unique_lock<std::mutex> lock(queueMutex);
                logQueue.push(std::make_pair(level, str));
                lock.unlock();
                logCondition.notify_all();
#else

                logString(str, level);
#endif
            }
        }

    private:
        void logString(const std::string& str, Log::Level level = Log::Level::INFO) const;

#ifdef DEBUG
        std::atomic<Log::Level> threshold{Log::Level::ALL};
#else
        std::atomic<Log::Level> threshold{Log::Level::INFO};
#endif

#if OUZEL_MULTITHREADED
        void logLoop();

        mutable std::condition_variable logCondition;
        mutable std::mutex queueMutex;
        mutable std::queue<std::pair<Log::Level, std::string>> logQueue;
        std::thread logThread;
        bool running = true;
#endif
    };
}

#endif // OUZEL_UTILS_LOG_HPP
<commit_msg>Join the log thread in the destructor of Log to avoid crash at exit on Windows<commit_after>// Copyright 2015-2018 Elviss Strazdins. All rights reserved.

#ifndef OUZEL_UTILS_LOG_HPP
#define OUZEL_UTILS_LOG_HPP

#include <atomic>
#include <condition_variable>
#include <mutex>
#include <queue>
#include <string>
#include <thread>
#include <vector>
#include "math/Matrix4.hpp"
#include "math/Quaternion.hpp"
#include "math/Size2.hpp"
#include "math/Size3.hpp"
#include "math/Vector2.hpp"
#include "math/Vector3.hpp"
#include "math/Vector4.hpp"

namespace ouzel
{
    class Logger;

    class Log final
    {
    public:
        enum class Level
        {
            OFF,
            ERR,
            WARN,
            INFO,
            ALL
        };

        explicit Log(const Logger& initLogger, Level initLevel = Level::INFO):
            logger(initLogger), level(initLevel)
        {
        }

        Log(const Log& other):
            logger(other.logger)
        {
            level = other.level;
            s = other.s;
        }

        Log(Log&& other):
            logger(other.logger)
        {
            level = other.level;
            other.level = Level::INFO;
            s = std::move(other.s);
        }

        Log& operator=(const Log& other)
        {
            level = other.level;
            s = other.s;

            return *this;
        }

        Log& operator=(Log&& other)
        {
            if (&other != this)
            {
                level = other.level;
                other.level = Level::INFO;
                s = std::move(other.s);
            }

            return *this;
        }

        ~Log();

        template<typename T> Log& operator<<(T val)
        {
            s += std::to_string(val);
            return *this;
        }

        Log& operator<<(const std::string& val)
        {
            s += val;
            return *this;
        }

        Log& operator<<(const char* val)
        {
            s += val;

            return *this;
        }

        Log& operator<<(char* val)
        {
            s += val;
            return *this;
        }

        Log& operator<<(const std::vector<std::string>& val)
        {
            bool first = true;

            for (const std::string& str : val)
            {
                if (!first) s += ", ";
                first = false;
                s += str;
            }

            return *this;
        }

        Log& operator<<(const Matrix4& val)
        {
            s += std::to_string(val.m[0]) + "," + std::to_string(val.m[1]) + "," + std::to_string(val.m[2]) + "," + std::to_string(val.m[3]) + "\n" +
                std::to_string(val.m[4]) + "," + std::to_string(val.m[5]) + "," + std::to_string(val.m[6]) + "," + std::to_string(val.m[7]) + "\n" +
                std::to_string(val.m[8]) + "," + std::to_string(val.m[9]) + "," + std::to_string(val.m[10]) + "," + std::to_string(val.m[11]) + "\n" +
                std::to_string(val.m[12]) + "," + std::to_string(val.m[13]) + "," + std::to_string(val.m[14]) + "," + std::to_string(val.m[15]);

            return *this;
        }

        Log& operator<<(const Quaternion& val)
        {
            s += std::to_string(val.x) + "," + std::to_string(val.y) + "," +
                std::to_string(val.z) + "," + std::to_string(val.w);

            return *this;
        }

        Log& operator<<(const Size2& val)
        {
            s += std::to_string(val.width) + "," + std::to_string(val.height);
            return *this;
        }

        Log& operator<<(const Size3& val)
        {
            s += std::to_string(val.width) + "," + std::to_string(val.height) + "," +
                std::to_string(val.depth);

            return *this;
        }

        Log& operator<<(const Vector2& val)
        {
            s += std::to_string(val.x) + "," + std::to_string(val.y);

            return *this;
        }

        Log& operator<<(const Vector3& val)
        {
            s += std::to_string(val.x) + "," + std::to_string(val.y) + "," +
                std::to_string(val.z);

            return *this;
        }

        Log& operator<<(const Vector4& val)
        {
            s += std::to_string(val.x) + "," + std::to_string(val.y) + "," +
                std::to_string(val.z) + "," + std::to_string(val.w);

            return *this;
        }

    private:
        const Logger& logger;
        Level level = Level::INFO;
        std::string s;
    };

    class Logger final
    {
    public:
        explicit Logger(Log::Level initThreshold = Log::Level::ALL):
            threshold(initThreshold)
        {
#if OUZEL_MULTITHREADED
            logThread = std::thread(&Logger::logLoop, this);
#endif
        }

        ~Logger()
        {
#if OUZEL_MULTITHREADED
            std::unique_lock<std::mutex> lock(queueMutex);
            running = false;
            lock.unlock();
            logCondition.notify_all();
            if (logThread.joinable()) logThread.join();
#endif
        }

        Log log(Log::Level level = Log::Level::INFO) const
        {
            return Log(*this, level);
        }

        void log(const std::string& str, Log::Level level = Log::Level::INFO) const
        {
            if (level <= threshold)
            {
#if OUZEL_MULTITHREADED
                std::unique_lock<std::mutex> lock(queueMutex);
                logQueue.push(std::make_pair(level, str));
                lock.unlock();
                logCondition.notify_all();
#else

                logString(str, level);
#endif
            }
        }

    private:
        void logString(const std::string& str, Log::Level level = Log::Level::INFO) const;

#ifdef DEBUG
        std::atomic<Log::Level> threshold{Log::Level::ALL};
#else
        std::atomic<Log::Level> threshold{Log::Level::INFO};
#endif

#if OUZEL_MULTITHREADED
        void logLoop();

        mutable std::condition_variable logCondition;
        mutable std::mutex queueMutex;
        mutable std::queue<std::pair<Log::Level, std::string>> logQueue;
        std::thread logThread;
        bool running = true;
#endif
    };
}

#endif // OUZEL_UTILS_LOG_HPP
<|endoftext|>


<commit_before>//vbSort.cpp
//Copyright (c) 2015 mmYYmmdd
#include "stdafx.h"
#include <algorithm>
#include "VBA_NestFunc.hpp"

//比較関数
class compareByVBAfunc   {
    VARIANT*    begin;
    std::shared_ptr<functionExpr> comp;
public:
    compareByVBAfunc(VARIANT* pA, VARIANT* f) : begin(pA), comp(std::make_shared<functionExpr>(f))
    {    }
    bool valid() const  { return static_cast<bool>(comp);  }
    bool operator ()(__int32 i, __int32 j) const
    {
        return comp->eval(begin + i, begin + j)->lVal ? true: false;
    }
};

//1次元昇順
class compFunctor  {
    VARIANT*    begin;
public:
    compFunctor(VARIANT* pA) : begin(pA) { }
    bool operator ()(__int32 i, __int32 j) const
    {
        return VARCMP_LT == VarCmp(begin + i, begin + j, LANG_JAPANESE, 0);
    }
};

//2次元昇順
class compDictionaryFunctor  {
    VARIANT*    begin;
public:
    compDictionaryFunctor(VARIANT* pA) : begin(pA) { }
    bool operator ()(__int32 i, __int32 j) const
    {
        safearrayRef arr1(begin + i);
        safearrayRef arr2(begin + j);
        if ( arr1.getDim() == 1 || arr2.getDim() == 1 )     return false;
        for ( ULONG k = 0; k < arr1.getSize(1) && k < arr2.getSize(1); ++k )
        {
            if ( VARCMP_LT == VarCmp(&arr1(k), &arr2(k), LANG_JAPANESE, 0) )
                return true;
            if ( VARCMP_LT == VarCmp(&arr2(k), &arr1(k), LANG_JAPANESE, 0) )
                return false;
        }
        return false;
    }
};

VARIANT __stdcall stdsort(VARIANT* array, __int32 defaultFlag, VARIANT* pComp)
{
    VARIANT      ret;
    ::VariantInit(&ret);
    safearrayRef arrIn(array);
    if ( 1 != arrIn.getDim() )          return ret;
    auto index = std::make_unique<__int32[]>(arrIn.getSize(1));
    auto VArray = std::make_unique<VARIANT[]>(arrIn.getSize(1));
    for (std::size_t i = 0; i < arrIn.getSize(1); ++i)
    {
        index[i] = static_cast<__int32>(i);
        ::VariantInit(&VArray[i]);
        ::VariantCopyInd(&VArray[i], &arrIn(i));
    }
    if ( defaultFlag == 1 ) //1次元昇順
    {
        compFunctor   functor(VArray.get());
        std::sort(index.get(), index.get() + arrIn.getSize(1), functor);
    }
    else if ( defaultFlag == 2 ) //2次元昇順
    {
        compDictionaryFunctor   functor(VArray.get());
        std::sort(index.get(), index.get() + arrIn.getSize(1), functor);
    }
    else if ( pComp )
    {
        compareByVBAfunc functor(VArray.get(), pComp);
        if ( functor.valid() )
            std::sort(index.get(), index.get() + arrIn.getSize(1), functor);
    }
    //-------------------------------------------------------
    SAFEARRAYBOUND boundRet = { static_cast<ULONG>(arrIn.getSize(1)), 0};   //要素数、LBound
    SAFEARRAY* retArray = ::SafeArrayCreate(VT_VARIANT, 1, &boundRet);
    ret.vt = VT_ARRAY | VT_VARIANT;
    ret.parray = retArray;
    safearrayRef arrOut(&ret);
    VARIANT elem;
    ::VariantInit(&elem);
    elem.vt = VT_I4;
    for ( std::size_t i = 0; i < arrIn.getSize(1); ++i )
    {
        elem.lVal = static_cast<LONG>(index[i] + arrIn.getOriginalLBound(1));
        ::VariantCopy(&arrOut(i), &elem);
    }
    return      ret;
}
<commit_msg>リファクタリング<commit_after>//vbSort.cpp
//Copyright (c) 2015 mmYYmmdd
#include "stdafx.h"
#include <algorithm>
#include "VBA_NestFunc.hpp"

//比較関数
class compareByVBAfunc   {
    VARIANT*    begin;
    std::shared_ptr<functionExpr> comp;
public:
    compareByVBAfunc(VARIANT* pA, VARIANT* f) : begin(pA), comp(std::make_shared<functionExpr>(f))
    {    }
    bool valid() const  { return static_cast<bool>(comp);  }
    bool operator ()(__int32 i, __int32 j) const
    {
        return comp->eval(begin + i, begin + j)->lVal ? true: false;
    }
};

//1次元昇順
class compFunctor  {
    VARIANT*    begin;
public:
    compFunctor(VARIANT* pA) : begin(pA) { }
    bool operator ()(__int32 i, __int32 j) const
    {
        return VARCMP_LT == VarCmp(begin + i, begin + j, LANG_JAPANESE, 0);
    }
};

//2次元昇順
class compDictionaryFunctor  {
    VARIANT*    begin;
public:
    compDictionaryFunctor(VARIANT* pA) : begin(pA) { }
    bool operator ()(__int32 i, __int32 j) const
    {
        safearrayRef arr1(begin + i);
        safearrayRef arr2(begin + j);
        if ( arr1.getDim() == 1 || arr2.getDim() == 1 )     return false;
        for ( ULONG k = 0; k < arr1.getSize(1) && k < arr2.getSize(1); ++k )
        {
            if ( VARCMP_LT == VarCmp(&arr1(k), &arr2(k), LANG_JAPANESE, 0) )
                return true;
            if ( VARCMP_LT == VarCmp(&arr2(k), &arr1(k), LANG_JAPANESE, 0) )
                return false;
        }
        return false;
    }
};

VARIANT __stdcall stdsort(VARIANT* array, __int32 defaultFlag, VARIANT* pComp)
{
    VARIANT      ret;
    ::VariantInit(&ret);
    safearrayRef arrIn(array);
    if ( 1 != arrIn.getDim() )          return ret;
    auto index = std::make_unique<__int32[]>(arrIn.getSize(1));
    auto VArray = std::make_unique<VARIANT[]>(arrIn.getSize(1));
    for (std::size_t i = 0; i < arrIn.getSize(1); ++i)
    {
        index[i] = static_cast<__int32>(i);
        ::VariantInit(&VArray[i]);
        ::VariantCopyInd(&VArray[i], &arrIn(i));
    }
    if ( defaultFlag == 1 ) //1次元昇順
    {
        compFunctor   functor(VArray.get());
        std::sort(index.get(), index.get() + arrIn.getSize(1), functor);
    }
    else if ( defaultFlag == 2 ) //2次元昇順
    {
        compDictionaryFunctor   functor(VArray.get());
        std::sort(index.get(), index.get() + arrIn.getSize(1), functor);
    }
    else if ( pComp )
    {
        compareByVBAfunc functor(VArray.get(), pComp);
        if ( functor.valid() )
            std::sort(index.get(), index.get() + arrIn.getSize(1), functor);
    }
    //-------------------------------------------------------
    SAFEARRAYBOUND boundRet = { static_cast<ULONG>(arrIn.getSize(1)), 0};   //要素数、LBound
    ret.vt = VT_ARRAY | VT_VARIANT;
    ret.parray = ::SafeArrayCreate(VT_VARIANT, 1, &boundRet);
    safearrayRef arrOut(&ret);
    VARIANT elem;
    ::VariantInit(&elem);
    elem.vt = VT_I4;
    for ( std::size_t i = 0; i < arrIn.getSize(1); ++i )
    {
        elem.lVal = static_cast<LONG>(index[i] + arrIn.getOriginalLBound(1));
        ::VariantCopy(&arrOut(i), &elem);
    }
    return      ret;
}
<|endoftext|>


<commit_before>// Copyright 2015-2018 Elviss Strazdins. All rights reserved.

#include "core/Setup.h"

#if OUZEL_COMPILE_XAUDIO2

#include <stdexcept>
#include "AudioDeviceXA2.hpp"
#include "XAudio27.hpp"
#include "core/Engine.hpp"
#include "utils/Log.hpp"
#include "utils/Utils.hpp"

static const char* XAUDIO2_DLL_28 = "xaudio2_8.dll";
static const char* XAUDIO2_DLL_27 = "xaudio2_7.dll";

typedef HRESULT(__stdcall *XAudio2CreateProc)(IXAudio2** ppXAudio2, UINT32 Flags, XAUDIO2_PROCESSOR XAudio2Processor);

namespace ouzel
{
    namespace audio
    {
        AudioDeviceXA2::AudioDeviceXA2(bool debugAudio):
            AudioDevice(Driver::XAUDIO2), running(true)
        {
            xAudio2Library = LoadLibraryA(XAUDIO2_DLL_28);

            if (xAudio2Library)
            {
                apiMajorVersion = 2;
                apiMinorVersion = 8;

                XAudio2CreateProc xAudio2CreateProc = reinterpret_cast<XAudio2CreateProc>(GetProcAddress(xAudio2Library, "XAudio2Create"));

                if (!xAudio2CreateProc)
                    throw std::runtime_error("Failed to get address of XAudio2Create");

                HRESULT hr;
                if (FAILED(hr = xAudio2CreateProc(&xAudio, 0, XAUDIO2_DEFAULT_PROCESSOR)))
                    throw std::runtime_error("Failed to initialize XAudio2, error: " + std::to_string(hr));

                if (debugAudio)
                {
                    XAUDIO2_DEBUG_CONFIGURATION debugConfiguration;
                    debugConfiguration.TraceMask = XAUDIO2_LOG_WARNINGS | XAUDIO2_LOG_DETAIL;
                    debugConfiguration.BreakMask = XAUDIO2_LOG_ERRORS;
                    debugConfiguration.LogThreadID = FALSE;
                    debugConfiguration.LogFileline = FALSE;
                    debugConfiguration.LogFunctionName = FALSE;
                    debugConfiguration.LogTiming = FALSE;

                    xAudio->SetDebugConfiguration(&debugConfiguration);
                }
            }
            else
            {
                engine->log(Log::Level::INFO) << "Failed to load " << XAUDIO2_DLL_28;

                xAudio2Library = LoadLibraryA(XAUDIO2_DLL_27);

                if (xAudio2Library)
                {
                    apiMajorVersion = 2;
                    apiMinorVersion = 7;
                }
                else
                    throw std::runtime_error("Failed to load " + std::string(XAUDIO2_DLL_27));

                const UINT XAUDIO2_DEBUG_ENGINE = 0x0001;

                UINT32 flags = 0;
                if (debugAudio) flags |= XAUDIO2_DEBUG_ENGINE;

                HRESULT hr;
                if (FAILED(hr = XAudio27CreateProc(&xAudio, flags, XAUDIO2_DEFAULT_PROCESSOR)))
                    throw std::runtime_error("Failed to initialize XAudio2, error: " + std::to_string(hr));
            }

            WAVEFORMATEX waveFormat;
            waveFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
            waveFormat.nChannels = channels;
            waveFormat.nSamplesPerSec = sampleRate;
            waveFormat.wBitsPerSample = 32;
            waveFormat.nBlockAlign = waveFormat.nChannels * (waveFormat.wBitsPerSample / 8);
            waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
            waveFormat.cbSize = 0;

            if (apiMajorVersion == 2 && apiMinorVersion == 7)
            {
                HRESULT hr;
                if (FAILED(hr = IXAudio2CreateMasteringVoice(xAudio, &masteringVoice)))
                    throw std::runtime_error("Failed to create XAudio2 mastering voice, error: " + std::to_string(hr));

                if (FAILED(hr = IXAudio2CreateSourceVoice(xAudio, &sourceVoice, &waveFormat, 0, XAUDIO2_DEFAULT_FREQ_RATIO, this)))
                    throw std::runtime_error("Failed to create source voice, error: " + std::to_string(hr));
            }
            else
            {
                HRESULT hr;
                if (FAILED(hr = xAudio->CreateMasteringVoice(&masteringVoice)))
                    throw std::runtime_error("Failed to create XAudio2 mastering voice, error: " + std::to_string(hr));

                if (FAILED(hr = xAudio->CreateSourceVoice(&sourceVoice, &waveFormat, 0, XAUDIO2_DEFAULT_FREQ_RATIO, this)))
                    throw std::runtime_error("Failed to create source voice, error: " + std::to_string(hr));
            }

            sampleFormat = SampleFormat::FLOAT32;

            getData(bufferSize / (channels * sizeof(float)), data[0]);

            XAUDIO2_BUFFER bufferData;
            bufferData.Flags = 0;
            bufferData.AudioBytes = static_cast<UINT32>(data[0].size());
            bufferData.pAudioData = data[0].data();
            bufferData.PlayBegin = 0;
            bufferData.PlayLength = 0;
            bufferData.LoopBegin = 0;
            bufferData.LoopLength = 0;
            bufferData.LoopCount = 0;
            bufferData.pContext = nullptr;

            HRESULT hr;
            if (FAILED(hr = sourceVoice->SubmitSourceBuffer(&bufferData)))
                throw std::runtime_error("Failed to upload sound data, error: " + std::to_string(hr));

            getData(bufferSize / (channels * sizeof(float)), data[1]);
            bufferData.AudioBytes = static_cast<UINT32>(data[1].size());
            bufferData.pAudioData = data[1].data();

            if (FAILED(hr = sourceVoice->SubmitSourceBuffer(&bufferData)))
                throw std::runtime_error("Failed to upload sound data, error: " + std::to_string(hr));

            nextBuffer = 0;

            if (FAILED(hr = sourceVoice->Start()))
                throw std::runtime_error("Failed to start consuming sound data, error: " + std::to_string(hr));

            audioThread = std::thread(&AudioDeviceXA2::run, this);
        }

        AudioDeviceXA2::~AudioDeviceXA2()
        {
            running = false;

            if (audioThread.joinable())
            {
                std::unique_lock<std::mutex> lock(fillDataMutex);
                fillDataCondition.notify_all();
                lock.unlock();
                audioThread.join();
            }

            if (sourceVoice) sourceVoice->DestroyVoice();
            if (masteringVoice) masteringVoice->DestroyVoice();
            if (xAudio)
            {
                if (apiMajorVersion == 2 && apiMinorVersion == 7) IXAudio2Release(xAudio);
                else xAudio->Release();
            }
            if (xAudio2Library) FreeModule(xAudio2Library);
        }

        void AudioDeviceXA2::run()
        {
            setCurrentThreadName("Audio");

            for (;;)
            {
                try
                {
                    std::unique_lock<std::mutex> lock(fillDataMutex);
                    while (!fillData && running) fillDataCondition.wait(lock);

                    if (!running) break;

                    process();

                    getData(bufferSize / (channels * sizeof(float)), data[nextBuffer]);

                    XAUDIO2_BUFFER bufferData;
                    bufferData.Flags = 0;
                    bufferData.AudioBytes = static_cast<UINT32>(data[nextBuffer].size());
                    bufferData.pAudioData = data[nextBuffer].data();
                    bufferData.PlayBegin = 0;
                    bufferData.PlayLength = 0;
                    bufferData.LoopBegin = 0;
                    bufferData.LoopLength = 0;
                    bufferData.LoopCount = 0;
                    bufferData.pContext = nullptr;

                    HRESULT hr;
                    if (FAILED(hr = sourceVoice->SubmitSourceBuffer(&bufferData)))
                        throw std::runtime_error("Failed to upload sound data, error: " + std::to_string(hr));

                    nextBuffer = (nextBuffer == 0) ? 1 : 0;

                    fillData = false;
                }
                catch (const std::exception& e)
                {
                    engine->log(Log::Level::ERR) << e.what();
                }
            }
        }

        void AudioDeviceXA2::OnVoiceProcessingPassStart(UINT32)
        {
        }

        void AudioDeviceXA2::OnVoiceProcessingPassEnd()
        {
        }

        void AudioDeviceXA2::OnStreamEnd()
        {
        }

        void AudioDeviceXA2::OnBufferStart(void*)
        {
        }

        void AudioDeviceXA2::OnBufferEnd(void*)
        {
            std::unique_lock<std::mutex> lock(fillDataMutex);
            fillData = true;
            lock.unlock();
            fillDataCondition.notify_all();
        }

        void AudioDeviceXA2::OnLoopEnd(void*)
        {
        }

        void AudioDeviceXA2::OnVoiceError(void*, HRESULT error)
        {
            throw std::runtime_error("Xaudio2 voice error: " + std::to_string(error));
        }
    } // namespace audio
} // namespace ouzel

#endif
<commit_msg>Add category for XAudio2 errors<commit_after>// Copyright 2015-2018 Elviss Strazdins. All rights reserved.

#include "core/Setup.h"

#if OUZEL_COMPILE_XAUDIO2

#include <stdexcept>
#include "AudioDeviceXA2.hpp"
#include "XAudio27.hpp"
#include "core/Engine.hpp"
#include "utils/Log.hpp"
#include "utils/Utils.hpp"

static const char* XAUDIO2_DLL_28 = "xaudio2_8.dll";
static const char* XAUDIO2_DLL_27 = "xaudio2_7.dll";

typedef HRESULT(__stdcall *XAudio2CreateProc)(IXAudio2** ppXAudio2, UINT32 Flags, XAUDIO2_PROCESSOR XAudio2Processor);

namespace ouzel
{
    namespace audio
    {
        class XAudio2ErrorCategory: public std::error_category
        {
        public:
            const char* name() const noexcept override
            {
                return "XAudio2";
            }

            std::string message(int condition) const override
            {
                switch (condition)
                {
                    case XAUDIO2_E_INVALID_CALL: return "XAUDIO2_E_INVALID_CALL";
                    case XAUDIO2_E_XMA_DECODER_ERROR: return "XAUDIO2_E_XMA_DECODER_ERROR";
                    case XAUDIO2_E_XAPO_CREATION_FAILED: return "XAUDIO2_E_XAPO_CREATION_FAILED";
                    case XAUDIO2_E_DEVICE_INVALIDATED: return "XAUDIO2_E_DEVICE_INVALIDATED";
                    default: return "Unknown error (" + std::to_string(condition) + ")";
                }
            }
        };

        const XAudio2ErrorCategory xAudio2ErrorCategory {};

        AudioDeviceXA2::AudioDeviceXA2(bool debugAudio):
            AudioDevice(Driver::XAUDIO2), running(true)
        {
            xAudio2Library = LoadLibraryA(XAUDIO2_DLL_28);

            if (xAudio2Library)
            {
                apiMajorVersion = 2;
                apiMinorVersion = 8;

                XAudio2CreateProc xAudio2CreateProc = reinterpret_cast<XAudio2CreateProc>(GetProcAddress(xAudio2Library, "XAudio2Create"));

                if (!xAudio2CreateProc)
                    throw std::runtime_error("Failed to get address of XAudio2Create");

                HRESULT hr;
                if (FAILED(hr = xAudio2CreateProc(&xAudio, 0, XAUDIO2_DEFAULT_PROCESSOR)))
                    throw std::system_error(hr, xAudio2ErrorCategory, "Failed to initialize XAudio2");

                if (debugAudio)
                {
                    XAUDIO2_DEBUG_CONFIGURATION debugConfiguration;
                    debugConfiguration.TraceMask = XAUDIO2_LOG_WARNINGS | XAUDIO2_LOG_DETAIL;
                    debugConfiguration.BreakMask = XAUDIO2_LOG_ERRORS;
                    debugConfiguration.LogThreadID = FALSE;
                    debugConfiguration.LogFileline = FALSE;
                    debugConfiguration.LogFunctionName = FALSE;
                    debugConfiguration.LogTiming = FALSE;

                    xAudio->SetDebugConfiguration(&debugConfiguration);
                }
            }
            else
            {
                engine->log(Log::Level::INFO) << "Failed to load " << XAUDIO2_DLL_28;

                xAudio2Library = LoadLibraryA(XAUDIO2_DLL_27);

                if (xAudio2Library)
                {
                    apiMajorVersion = 2;
                    apiMinorVersion = 7;
                }
                else
                    throw std::runtime_error("Failed to load " + std::string(XAUDIO2_DLL_27));

                const UINT XAUDIO2_DEBUG_ENGINE = 0x0001;

                UINT32 flags = 0;
                if (debugAudio) flags |= XAUDIO2_DEBUG_ENGINE;

                HRESULT hr;
                if (FAILED(hr = XAudio27CreateProc(&xAudio, flags, XAUDIO2_DEFAULT_PROCESSOR)))
                    throw std::system_error(hr, xAudio2ErrorCategory, "Failed to initialize XAudio2");
            }

            WAVEFORMATEX waveFormat;
            waveFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
            waveFormat.nChannels = channels;
            waveFormat.nSamplesPerSec = sampleRate;
            waveFormat.wBitsPerSample = 32;
            waveFormat.nBlockAlign = waveFormat.nChannels * (waveFormat.wBitsPerSample / 8);
            waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
            waveFormat.cbSize = 0;

            if (apiMajorVersion == 2 && apiMinorVersion == 7)
            {
                HRESULT hr;
                if (FAILED(hr = IXAudio2CreateMasteringVoice(xAudio, &masteringVoice)))
                    throw std::system_error(hr, xAudio2ErrorCategory, "Failed to create XAudio2 mastering voice");

                if (FAILED(hr = IXAudio2CreateSourceVoice(xAudio, &sourceVoice, &waveFormat, 0, XAUDIO2_DEFAULT_FREQ_RATIO, this)))
                    throw std::system_error(hr, xAudio2ErrorCategory, "Failed to create source voice");
            }
            else
            {
                HRESULT hr;
                if (FAILED(hr = xAudio->CreateMasteringVoice(&masteringVoice)))
                    throw std::system_error(hr, xAudio2ErrorCategory, "Failed to create XAudio2 mastering voice");

                if (FAILED(hr = xAudio->CreateSourceVoice(&sourceVoice, &waveFormat, 0, XAUDIO2_DEFAULT_FREQ_RATIO, this)))
                    throw std::system_error(hr, xAudio2ErrorCategory, "Failed to create source voice");
            }

            sampleFormat = SampleFormat::FLOAT32;

            getData(bufferSize / (channels * sizeof(float)), data[0]);

            XAUDIO2_BUFFER bufferData;
            bufferData.Flags = 0;
            bufferData.AudioBytes = static_cast<UINT32>(data[0].size());
            bufferData.pAudioData = data[0].data();
            bufferData.PlayBegin = 0;
            bufferData.PlayLength = 0;
            bufferData.LoopBegin = 0;
            bufferData.LoopLength = 0;
            bufferData.LoopCount = 0;
            bufferData.pContext = nullptr;

            HRESULT hr;
            if (FAILED(hr = sourceVoice->SubmitSourceBuffer(&bufferData)))
                throw std::system_error(hr, xAudio2ErrorCategory, "Failed to upload sound data");

            getData(bufferSize / (channels * sizeof(float)), data[1]);
            bufferData.AudioBytes = static_cast<UINT32>(data[1].size());
            bufferData.pAudioData = data[1].data();

            if (FAILED(hr = sourceVoice->SubmitSourceBuffer(&bufferData)))
                throw std::system_error(hr, xAudio2ErrorCategory, "Failed to upload sound data");

            nextBuffer = 0;

            if (FAILED(hr = sourceVoice->Start()))
                throw std::system_error(hr, xAudio2ErrorCategory, "Failed to start consuming sound data");

            audioThread = std::thread(&AudioDeviceXA2::run, this);
        }

        AudioDeviceXA2::~AudioDeviceXA2()
        {
            running = false;

            if (audioThread.joinable())
            {
                std::unique_lock<std::mutex> lock(fillDataMutex);
                fillDataCondition.notify_all();
                lock.unlock();
                audioThread.join();
            }

            if (sourceVoice) sourceVoice->DestroyVoice();
            if (masteringVoice) masteringVoice->DestroyVoice();
            if (xAudio)
            {
                if (apiMajorVersion == 2 && apiMinorVersion == 7) IXAudio2Release(xAudio);
                else xAudio->Release();
            }
            if (xAudio2Library) FreeModule(xAudio2Library);
        }

        void AudioDeviceXA2::run()
        {
            setCurrentThreadName("Audio");

            for (;;)
            {
                try
                {
                    std::unique_lock<std::mutex> lock(fillDataMutex);
                    while (!fillData && running) fillDataCondition.wait(lock);

                    if (!running) break;

                    process();

                    getData(bufferSize / (channels * sizeof(float)), data[nextBuffer]);

                    XAUDIO2_BUFFER bufferData;
                    bufferData.Flags = 0;
                    bufferData.AudioBytes = static_cast<UINT32>(data[nextBuffer].size());
                    bufferData.pAudioData = data[nextBuffer].data();
                    bufferData.PlayBegin = 0;
                    bufferData.PlayLength = 0;
                    bufferData.LoopBegin = 0;
                    bufferData.LoopLength = 0;
                    bufferData.LoopCount = 0;
                    bufferData.pContext = nullptr;

                    HRESULT hr;
                    if (FAILED(hr = sourceVoice->SubmitSourceBuffer(&bufferData)))
                        throw std::system_error(hr, xAudio2ErrorCategory, "Failed to upload sound data");

                    nextBuffer = (nextBuffer == 0) ? 1 : 0;

                    fillData = false;
                }
                catch (const std::exception& e)
                {
                    engine->log(Log::Level::ERR) << e.what();
                }
            }
        }

        void AudioDeviceXA2::OnVoiceProcessingPassStart(UINT32)
        {
        }

        void AudioDeviceXA2::OnVoiceProcessingPassEnd()
        {
        }

        void AudioDeviceXA2::OnStreamEnd()
        {
        }

        void AudioDeviceXA2::OnBufferStart(void*)
        {
        }

        void AudioDeviceXA2::OnBufferEnd(void*)
        {
            std::unique_lock<std::mutex> lock(fillDataMutex);
            fillData = true;
            lock.unlock();
            fillDataCondition.notify_all();
        }

        void AudioDeviceXA2::OnLoopEnd(void*)
        {
        }

        void AudioDeviceXA2::OnVoiceError(void*, HRESULT error)
        {
            throw std::runtime_error("Xaudio2 voice error: " + std::to_string(error));
        }
    } // namespace audio
} // namespace ouzel

#endif
<|endoftext|>