<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) 2012 Fernando José Iglesias García
 * Copyright (C) 2012 Fernando José Iglesias García
 */

#include <shogun/converter/StochasticProximityEmbedding.h>
#include <shogun/lib/config.h>
#ifdef HAVE_LAPACK
#include <shogun/converter/EmbeddingConverter.h>
#include <shogun/io/SGIO.h>
#include <shogun/lib/CoverTree.h>
#include <shogun/mathematics/Math.h>
#include <shogun/distance/Distance.h>

using namespace shogun;

class SPE_COVERTREE_POINT
{
public:

	SPE_COVERTREE_POINT(int32_t index, CDistance* specp_distance)
	{
		m_point_index = index;
		m_distance = specp_distance;
	}

	inline double distance(const SPE_COVERTREE_POINT& p) const
	{
		return m_distance->distance(m_point_index, p.m_point_index);
	}

	inline bool operator==(const SPE_COVERTREE_POINT& p) const
	{
		return (p.m_point_index == m_point_index);
	}

	int32_t m_point_index;
	CDistance* m_distance;
};

CStochasticProximityEmbedding::CStochasticProximityEmbedding() :
	CEmbeddingConverter()
{
	// Initialize to default values
	m_k         = 12;
	m_nupdates  = 100;
	m_strategy  = SPE_GLOBAL;
	m_tolerance = 1e-5;

	init();
}

void CStochasticProximityEmbedding::init()
{
	SG_ADD(&m_k, "m_k", "Number of neighbors", MS_NOT_AVAILABLE);
	SG_ADD((machine_int_t*) &m_strategy, "m_strategy", "SPE strategy",
			MS_NOT_AVAILABLE);
	SG_ADD(&m_tolerance, "m_tolerance", "Regularization parameter",
			MS_NOT_AVAILABLE);
}

CStochasticProximityEmbedding::~CStochasticProximityEmbedding()
{
}

void CStochasticProximityEmbedding::set_k(int32_t k)
{
	if ( k <= 0 )
		SG_ERROR("Number of neighbors k must be greater than 0");

	m_k = k;
}

int32_t CStochasticProximityEmbedding::get_k() const
{
	return m_k;
}

void CStochasticProximityEmbedding::set_strategy(ESPEStrategy strategy)
{
	m_strategy = strategy;
}

ESPEStrategy CStochasticProximityEmbedding::get_strategy() const
{
	return m_strategy;
}

void CStochasticProximityEmbedding::set_tolerance(float32_t tolerance)
{
	if ( tolerance <= 0 )
		SG_ERROR("Tolerance regularization parameter must be greater "
			 "than 0");

	m_tolerance = tolerance;
}

int32_t CStochasticProximityEmbedding::get_tolerance() const
{
	return m_tolerance;
}

void CStochasticProximityEmbedding::set_nupdates(int32_t nupdates)
{
	if ( nupdates <= 0 )
		SG_ERROR("The number of updates must be greater than 0");

	m_nupdates = nupdates;
}

int32_t CStochasticProximityEmbedding::get_nupdates() const
{
	return m_nupdates;
}

const char * CStochasticProximityEmbedding::get_name() const
{
	return "StochasticProximityEmbedding";
}

CFeatures* CStochasticProximityEmbedding::apply(CFeatures* features)
{
	if ( !features )
		SG_ERROR("Features are required to apply SPE\n");

	// Shorthand for the SimpleFeatures
	CSimpleFeatures< float64_t >* simple_features =
		(CSimpleFeatures< float64_t >*) features;
	SG_REF(features);

	// Get and check the number of vectors
	int32_t N = simple_features->get_num_vectors();
	if ( m_strategy == SPE_LOCAL && m_k >= N )
		SG_ERROR("The number of neighbors (%d) must be less than "
		         "the number of vectors (%d)\n", m_k, N);

	if ( 2*m_nupdates > N )
		SG_ERROR("The number of vectors (%d) must be at least two times "
			 "the number of updates (%d)\n", N, m_nupdates);

	m_distance->init(simple_features, simple_features);
	CSimpleFeatures< float64_t >* embedding = embed_distance(m_distance);
	m_distance->remove_lhs_and_rhs();

	SG_UNREF(features);
	return (CFeatures*)embedding;
}

SGMatrix<int32_t> CStochasticProximityEmbedding::get_neighborhood_matrix(CDistance* distance, int32_t k, int32_t N, float64_t max_dist)
{
	int32_t i;
	int32_t* neighborhood_matrix = SG_MALLOC(int32_t, N*k);

	CoverTree<SPE_COVERTREE_POINT>* coverTree = new CoverTree<SPE_COVERTREE_POINT>(max_dist);

	for (i=0; i<N; i++)
		coverTree->insert(SPE_COVERTREE_POINT(i, distance));

	for (i=0; i<N; i++)
	{
		std::vector<SPE_COVERTREE_POINT> neighbors =
		   coverTree->kNearestNeighbors(SPE_COVERTREE_POINT(i, distance), k+1);
		for (std::size_t m=1; m<unsigned(k+1); m++)
			neighborhood_matrix[i*k+m-1] = neighbors[m].m_point_index;
	}

	delete coverTree;

	return SGMatrix<int32_t>(neighborhood_matrix,k,N);
}

CSimpleFeatures< float64_t >* CStochasticProximityEmbedding::embed_distance(CDistance* distance)
{
	if ( !distance )
		SG_ERROR("Embed distance received no instance of CDistance\n");

	// Compute distance matrix
	SG_DEBUG("Computing distance matrix\n");

	if ( distance->get_distance_type() != D_EUCLIDIAN )
		SG_ERROR("SPE only supports Euclidian distance, %s given\n",
				distance->get_name());

	// Get the number of features, assume that distance(features, features)
	int32_t N = distance->get_num_vec_rhs();

	// Look for the maximum distance (make the same assumption)
	int32_t i, j, k;
	float64_t max = 0.0, tmp = 0.0;
	for ( i = 0 ; i < N ; ++i )
		for ( j = 0 ; j < N ; ++j )
			if ( ( tmp = distance->distance(i, j) ) > max )
				max = tmp;

	// Compute a normalizer to be used for the distances if global strategy selected
	float64_t alpha = 0.0;
	if ( m_strategy == SPE_GLOBAL )
		alpha = 1.0 / max * CMath::sqrt(2.0);

	// Compute neighborhood matrix if local strategy used
	SGMatrix< int32_t > neighbors_mat;
	if ( m_strategy == SPE_LOCAL )
	{
		SG_DEBUG("Computing neighborhood matrix\n");
		neighbors_mat = get_neighborhood_matrix(distance, m_k, N, max);
	}

	// Initialize vectors in the embedded space randomly, Y is the short for
	// new_feature_matrix
	SGMatrix< float64_t > Y(m_target_dim, N);
	CMath::random_vector(Y.matrix, m_target_dim*N, 0.0, 1.0);

	// SPE's loop

	// Initialize the maximum number of iterations
	int32_t max_iter = 2000 + CMath::round(0.04 * N*N);
	if ( m_strategy == SPE_LOCAL )
		max_iter *= 3;

	// Initialize the learning parameter
	float32_t lambda = 1.0;

	// Initialize variables to use in the main loop
	float64_t sum = 0.0;
	index_t   idx1 = 0, idx2 = 0, idx = 0;

	SGVector< float64_t > scale(m_nupdates);
	SGVector< float64_t > D(m_nupdates);
	SGMatrix< float64_t > Yd(m_nupdates, m_target_dim);
	SGVector< float64_t > Rt(m_nupdates);
	int32_t* ind2 = NULL;

	// Variables required just if local strategy used
	SGMatrix< int32_t > ind1Neighbors;
	SGVector< int32_t > J2;
	if ( m_strategy == SPE_LOCAL )
	{
		ind2 = SG_MALLOC(int32_t, m_nupdates);

		CMath::resize(ind1Neighbors.matrix, 0, m_k*m_nupdates);
		ind1Neighbors.num_rows = m_k;
		ind1Neighbors.num_cols = m_nupdates;

		CMath::resize(J2.vector, 0, m_nupdates);
		J2.vlen = m_nupdates;
	}

	for ( i = 0 ; i < max_iter ; ++i )
	{
		if ( !(i % 1000) )
			SG_DEBUG("SPE's loop, iteration %d of %d\n", i, max_iter);

		// Select the vectors to be updated in this iteration
		int32_t* J = CMath::randperm(N);

		// Pointer to the first set of vector indices to update
		int32_t* ind1 = J;

		// Pointer ind2 to the second set of vector indices to update
		if ( m_strategy == SPE_GLOBAL )
			ind2 = J + m_nupdates;
		else
		{
			// Select the second set of indices to update among neighbors
			// of the first set

			// Get the neighbors of interest
			for ( j = 0 ; j < m_nupdates ; ++j )
			{
				for ( k = 0 ; k < m_k ; ++k )
					ind1Neighbors[k + j*m_k] =
						neighbors_mat.matrix[k + ind1[j]*m_k];
			}

			// Generate pseudo-random indices
			for ( j = 0 ; j < m_nupdates ; ++j )
			{
				J2[j] = CMath::round( CMath::random(0.0, 1.0)*(m_k-1) )
						+ m_k*j;
			}

			// Select final indices
			for ( j = 0 ; j < m_nupdates ; ++j )
				ind2[j] = ind1Neighbors.matrix[ J2[j] ];
		}

		// Compute distances betweeen the selected points in embedded space

		for ( j = 0 ; j < m_nupdates ; ++j )
		{
			sum = 0.0;

			for ( k = 0 ; k < m_target_dim ; ++k )
			{
				idx1 = k + ind1[j]*m_target_dim;
				idx2 = k + ind2[j]*m_target_dim;
				sum += CMath::sq(Y.matrix[idx1] - Y.matrix[idx2]);
			}

			D[j] = CMath::sqrt(sum);
		}

		// Get the corresponding distances in the original space

		if ( m_strategy == SPE_LOCAL )
			Rt.set_const(1);
		else	// SPE_GLOBAL strategy used
			Rt.set_const(alpha);

		for ( j = 0 ; j < m_nupdates ; ++j )
			Rt[j] *= distance->distance( ind1[j], ind2[j] );

		// Compute some terms for update

		// Scale factor: (Rt - D) ./ (D + m_tolerance)
		for ( j = 0 ; j < m_nupdates ; ++j )
			scale[j] = ( Rt[j] - D[j] ) / ( D[j] + m_tolerance );

		// Difference matrix: Y(ind1) - Y(ind2)
		for ( j = 0 ; j < m_nupdates ; ++j )
			for ( k = 0 ; k < m_target_dim ; ++k )
			{
				idx1 = k + ind1[j]*m_target_dim;
				idx2 = k + ind2[j]*m_target_dim;
				idx  = k +      j *m_target_dim;

				Yd[idx] = Y[idx1] - Y[idx2];
			}

		// Update the location of the vectors in the embedded space
		for ( j = 0 ; j < m_nupdates ; ++j )
			for ( k = 0 ; k < m_target_dim ; ++k )
			{
				idx1 = k + ind1[j]*m_target_dim;
				idx2 = k + ind2[j]*m_target_dim;
				idx  = k +      j *m_target_dim;

				Y[idx1] += lambda / 2 * scale[j] * Yd[idx];
				Y[idx2] -= lambda / 2 * scale[j] * Yd[idx];
			}

		// Update the learning parameter
		lambda = lambda - ( lambda / max_iter );

		// Free memory
		delete[] J;
	}

	// Free memory
	scale.destroy_vector();
	D.destroy_vector();
	Yd.destroy_matrix();
	Rt.destroy_vector();
	if ( m_strategy == SPE_LOCAL )
	{
		ind1Neighbors.destroy_matrix();
		neighbors_mat.destroy_matrix();
		J2.destroy_vector();
		delete[] ind2;
	}

	return new CSimpleFeatures< float64_t >(Y);
}

#endif /* HAVE_LAPACK */
<commit_msg>~ faster max distance calculation<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) 2012 Fernando José Iglesias García
 * Copyright (C) 2012 Fernando José Iglesias García
 */

#include <shogun/converter/StochasticProximityEmbedding.h>
#include <shogun/lib/config.h>
#ifdef HAVE_LAPACK
#include <shogun/converter/EmbeddingConverter.h>
#include <shogun/io/SGIO.h>
#include <shogun/lib/CoverTree.h>
#include <shogun/mathematics/Math.h>
#include <shogun/distance/Distance.h>

using namespace shogun;

class SPE_COVERTREE_POINT
{
public:

	SPE_COVERTREE_POINT(int32_t index, CDistance* specp_distance)
	{
		m_point_index = index;
		m_distance = specp_distance;
	}

	inline double distance(const SPE_COVERTREE_POINT& p) const
	{
		return m_distance->distance(m_point_index, p.m_point_index);
	}

	inline bool operator==(const SPE_COVERTREE_POINT& p) const
	{
		return (p.m_point_index == m_point_index);
	}

	int32_t m_point_index;
	CDistance* m_distance;
};

CStochasticProximityEmbedding::CStochasticProximityEmbedding() :
	CEmbeddingConverter()
{
	// Initialize to default values
	m_k         = 12;
	m_nupdates  = 100;
	m_strategy  = SPE_GLOBAL;
	m_tolerance = 1e-5;

	init();
}

void CStochasticProximityEmbedding::init()
{
	SG_ADD(&m_k, "m_k", "Number of neighbors", MS_NOT_AVAILABLE);
	SG_ADD((machine_int_t*) &m_strategy, "m_strategy", "SPE strategy",
			MS_NOT_AVAILABLE);
	SG_ADD(&m_tolerance, "m_tolerance", "Regularization parameter",
			MS_NOT_AVAILABLE);
}

CStochasticProximityEmbedding::~CStochasticProximityEmbedding()
{
}

void CStochasticProximityEmbedding::set_k(int32_t k)
{
	if ( k <= 0 )
		SG_ERROR("Number of neighbors k must be greater than 0");

	m_k = k;
}

int32_t CStochasticProximityEmbedding::get_k() const
{
	return m_k;
}

void CStochasticProximityEmbedding::set_strategy(ESPEStrategy strategy)
{
	m_strategy = strategy;
}

ESPEStrategy CStochasticProximityEmbedding::get_strategy() const
{
	return m_strategy;
}

void CStochasticProximityEmbedding::set_tolerance(float32_t tolerance)
{
	if ( tolerance <= 0 )
		SG_ERROR("Tolerance regularization parameter must be greater "
			 "than 0");

	m_tolerance = tolerance;
}

int32_t CStochasticProximityEmbedding::get_tolerance() const
{
	return m_tolerance;
}

void CStochasticProximityEmbedding::set_nupdates(int32_t nupdates)
{
	if ( nupdates <= 0 )
		SG_ERROR("The number of updates must be greater than 0");

	m_nupdates = nupdates;
}

int32_t CStochasticProximityEmbedding::get_nupdates() const
{
	return m_nupdates;
}

const char * CStochasticProximityEmbedding::get_name() const
{
	return "StochasticProximityEmbedding";
}

CFeatures* CStochasticProximityEmbedding::apply(CFeatures* features)
{
	if ( !features )
		SG_ERROR("Features are required to apply SPE\n");

	// Shorthand for the SimpleFeatures
	CSimpleFeatures< float64_t >* simple_features =
		(CSimpleFeatures< float64_t >*) features;
	SG_REF(features);

	// Get and check the number of vectors
	int32_t N = simple_features->get_num_vectors();
	if ( m_strategy == SPE_LOCAL && m_k >= N )
		SG_ERROR("The number of neighbors (%d) must be less than "
		         "the number of vectors (%d)\n", m_k, N);

	if ( 2*m_nupdates > N )
		SG_ERROR("The number of vectors (%d) must be at least two times "
			 "the number of updates (%d)\n", N, m_nupdates);

	m_distance->init(simple_features, simple_features);
	CSimpleFeatures< float64_t >* embedding = embed_distance(m_distance);
	m_distance->remove_lhs_and_rhs();

	SG_UNREF(features);
	return (CFeatures*)embedding;
}

SGMatrix<int32_t> CStochasticProximityEmbedding::get_neighborhood_matrix(CDistance* distance, int32_t k, int32_t N, float64_t max_dist)
{
	int32_t i;
	int32_t* neighborhood_matrix = SG_MALLOC(int32_t, N*k);

	CoverTree<SPE_COVERTREE_POINT>* coverTree = new CoverTree<SPE_COVERTREE_POINT>(max_dist);

	for (i=0; i<N; i++)
		coverTree->insert(SPE_COVERTREE_POINT(i, distance));

	for (i=0; i<N; i++)
	{
		std::vector<SPE_COVERTREE_POINT> neighbors =
			coverTree->kNearestNeighbors(SPE_COVERTREE_POINT(i, distance), k+1);
		for (std::size_t m=1; m<unsigned(k+1); m++)
			neighborhood_matrix[i*k+m-1] = neighbors[m].m_point_index;
	}

	delete coverTree;

	return SGMatrix<int32_t>(neighborhood_matrix,k,N);
}

CSimpleFeatures< float64_t >* CStochasticProximityEmbedding::embed_distance(CDistance* distance)
{
	if ( !distance )
		SG_ERROR("Embed distance received no instance of CDistance\n");

	// Compute distance matrix
	SG_DEBUG("Computing distance matrix\n");

	if ( distance->get_distance_type() != D_EUCLIDIAN )
		SG_ERROR("SPE only supports Euclidian distance, %s given\n",
				distance->get_name());

	// Get the number of features, assume that distance(features, features)
	int32_t N = distance->get_num_vec_rhs();

	// Look for the maximum distance (make the same assumption)
	int32_t i, j, k;
	float64_t max = 0.0, tmp = 0.0;
	for ( i = 0 ; i < N ; ++i )
		for ( j = i+1 ; j < N ; ++j )
			if ( ( tmp = distance->distance(i, j) ) > max )
				max = tmp;

	// Compute a normalizer to be used for the distances if global strategy selected
	float64_t alpha = 0.0;
	if ( m_strategy == SPE_GLOBAL )
		alpha = 1.0 / max * CMath::sqrt(2.0);

	// Compute neighborhood matrix if local strategy used
	SGMatrix< int32_t > neighbors_mat;
	if ( m_strategy == SPE_LOCAL )
	{
		SG_DEBUG("Computing neighborhood matrix\n");
		neighbors_mat = get_neighborhood_matrix(distance, m_k, N, max);
	}

	// Initialize vectors in the embedded space randomly, Y is the short for
	// new_feature_matrix
	SGMatrix< float64_t > Y(m_target_dim, N);
	CMath::random_vector(Y.matrix, m_target_dim*N, 0.0, 1.0);

	// SPE's loop

	// Initialize the maximum number of iterations
	int32_t max_iter = 2000 + CMath::round(0.04 * N*N);
	if ( m_strategy == SPE_LOCAL )
		max_iter *= 3;

	// Initialize the learning parameter
	float32_t lambda = 1.0;

	// Initialize variables to use in the main loop
	float64_t sum = 0.0;
	index_t   idx1 = 0, idx2 = 0, idx = 0;

	SGVector< float64_t > scale(m_nupdates);
	SGVector< float64_t > D(m_nupdates);
	SGMatrix< float64_t > Yd(m_nupdates, m_target_dim);
	SGVector< float64_t > Rt(m_nupdates);
	int32_t* ind2 = NULL;

	// Variables required just if local strategy used
	SGMatrix< int32_t > ind1Neighbors;
	SGVector< int32_t > J2;
	if ( m_strategy == SPE_LOCAL )
	{
		ind2 = SG_MALLOC(int32_t, m_nupdates);

		CMath::resize(ind1Neighbors.matrix, 0, m_k*m_nupdates);
		ind1Neighbors.num_rows = m_k;
		ind1Neighbors.num_cols = m_nupdates;

		CMath::resize(J2.vector, 0, m_nupdates);
		J2.vlen = m_nupdates;
	}

	for ( i = 0 ; i < max_iter ; ++i )
	{
		if ( !(i % 1000) )
			SG_DEBUG("SPE's loop, iteration %d of %d\n", i, max_iter);

		// Select the vectors to be updated in this iteration
		int32_t* J = CMath::randperm(N);

		// Pointer to the first set of vector indices to update
		int32_t* ind1 = J;

		// Pointer ind2 to the second set of vector indices to update
		if ( m_strategy == SPE_GLOBAL )
			ind2 = J + m_nupdates;
		else
		{
			// Select the second set of indices to update among neighbors
			// of the first set

			// Get the neighbors of interest
			for ( j = 0 ; j < m_nupdates ; ++j )
			{
				for ( k = 0 ; k < m_k ; ++k )
					ind1Neighbors[k + j*m_k] =
						neighbors_mat.matrix[k + ind1[j]*m_k];
			}

			// Generate pseudo-random indices
			for ( j = 0 ; j < m_nupdates ; ++j )
			{
				J2[j] = CMath::round( CMath::random(0.0, 1.0)*(m_k-1) )
						+ m_k*j;
			}

			// Select final indices
			for ( j = 0 ; j < m_nupdates ; ++j )
				ind2[j] = ind1Neighbors.matrix[ J2[j] ];
		}

		// Compute distances betweeen the selected points in embedded space

		for ( j = 0 ; j < m_nupdates ; ++j )
		{
			sum = 0.0;

			for ( k = 0 ; k < m_target_dim ; ++k )
			{
				idx1 = k + ind1[j]*m_target_dim;
				idx2 = k + ind2[j]*m_target_dim;
				sum += CMath::sq(Y.matrix[idx1] - Y.matrix[idx2]);
			}

			D[j] = CMath::sqrt(sum);
		}

		// Get the corresponding distances in the original space

		if ( m_strategy == SPE_LOCAL )
			Rt.set_const(1);
		else	// SPE_GLOBAL strategy used
			Rt.set_const(alpha);

		for ( j = 0 ; j < m_nupdates ; ++j )
			Rt[j] *= distance->distance( ind1[j], ind2[j] );

		// Compute some terms for update

		// Scale factor: (Rt - D) ./ (D + m_tolerance)
		for ( j = 0 ; j < m_nupdates ; ++j )
			scale[j] = ( Rt[j] - D[j] ) / ( D[j] + m_tolerance );

		// Difference matrix: Y(ind1) - Y(ind2)
		for ( j = 0 ; j < m_nupdates ; ++j )
			for ( k = 0 ; k < m_target_dim ; ++k )
			{
				idx1 = k + ind1[j]*m_target_dim;
				idx2 = k + ind2[j]*m_target_dim;
				idx  = k +      j *m_target_dim;

				Yd[idx] = Y[idx1] - Y[idx2];
			}

		// Update the location of the vectors in the embedded space
		for ( j = 0 ; j < m_nupdates ; ++j )
			for ( k = 0 ; k < m_target_dim ; ++k )
			{
				idx1 = k + ind1[j]*m_target_dim;
				idx2 = k + ind2[j]*m_target_dim;
				idx  = k +      j *m_target_dim;

				Y[idx1] += lambda / 2 * scale[j] * Yd[idx];
				Y[idx2] -= lambda / 2 * scale[j] * Yd[idx];
			}

		// Update the learning parameter
		lambda = lambda - ( lambda / max_iter );

		// Free memory
		delete[] J;
	}

	// Free memory
	scale.destroy_vector();
	D.destroy_vector();
	Yd.destroy_matrix();
	Rt.destroy_vector();
	if ( m_strategy == SPE_LOCAL )
	{
		ind1Neighbors.destroy_matrix();
		neighbors_mat.destroy_matrix();
		J2.destroy_vector();
		delete[] ind2;
	}

	return new CSimpleFeatures< float64_t >(Y);
}

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


<commit_before>#include "CCollisionSystem.h"

#include "CCollidable.h"
#include "debug/Log.h"

#include <stdexcept>

#include "util/mmgr.h"

unsigned int CCollisionSystem::getNewGroupId()
{
	// Add new collision group
	m_entities.push_back(std::list<CCollidable*>());
	// Return the group id
	return m_entities.size() - 1;
}

// Cleanup
CCollisionSystem::~CCollisionSystem()
{
	for (unsigned int i = 0; i < m_entities.size(); ++i)
	{
		for (auto iter = m_entities[i].begin(); iter != m_entities[i].end(); ++iter)
		{
			delete (*iter);
		}
	}
}

CCollidable* CCollisionSystem::add(const CAABBox& box, unsigned int groupId)
{
	if (groupId >= m_entities.size())
	{
		LOG_ERROR("Group id %i does not exist", groupId);
		throw std::runtime_error("CCollisionSystem.add: Invalid goup id");
	}
	// Create new entity and add to the collision group
	CCollidable* entity = new CCollidable(groupId, box);
	m_entities[groupId].push_back(entity);
	return entity;
}

// Removes collidable entity
void CCollisionSystem::remove(CCollidable* entity)
{
	m_entities[entity->getGroupId()].remove(entity);
	delete entity;
}

// Test all entities for collision
void CCollisionSystem::update()
{
	for (unsigned int i = 0; i < m_entities.size(); ++i)
	{
		auto iter = m_entities[i].begin();
		while (iter != m_entities[i].end())
		{
			// Delete if requested
			if ((*iter)->deleteRequested())
			{
				CCollidable* temp = (*iter);
				iter = m_entities[i].erase(iter);
				delete temp;
			}
			else
			{
				if ((*iter)->isCollidable())
				{
					testCollision((*iter), i);
				}
				++iter;
			}
		}
	}
}

// Tests collidable entity against all entities not in the group
void CCollisionSystem::testCollision(CCollidable* entity, unsigned int group)
{
	// Everything gets tested twice, make this faster
	for (unsigned int i = 0; i < m_entities.size(); ++i)
	{
		if (i != group)
		{
			auto iter = m_entities[i].begin();
			while (iter != m_entities[i].end())
			{
				// Delete if requested
				if ((*iter)->deleteRequested())
				{
					CCollidable* temp = (*iter);
					iter = m_entities[i].erase(iter);
					delete temp;
				}
				else
				{
					if ((*iter)->isCollidable())
					{
						if (collides(entity->getAABBox(), (*iter)->getAABBox()))
						{
							// Since every collision is tested both ways, damage only happens from first entity to second entity
							(*iter)->receiveDamage(entity->getDamage());
						}
					}
					++iter;
				}
			}
		}
	}
}<commit_msg>CCollisionSystem.cpp implemented<commit_after>#include "CCollisionSystem.h"

#include "CCollidable.h"
#include "debug/Log.h"

#include <stdexcept>

unsigned int CCollisionSystem::getNewGroupId()
{
	// Add new collision group
	m_entities.push_back(std::list<CCollidable*>());
	// Return the group id
	return m_entities.size() - 1;
}

// Cleanup
CCollisionSystem::~CCollisionSystem()
{
	for (unsigned int i = 0; i < m_entities.size(); ++i)
	{
		for (auto iter = m_entities[i].begin(); iter != m_entities[i].end(); ++iter)
		{
			delete (*iter);
		}
	}
}

CCollidable* CCollisionSystem::add(const CAABBox& box, unsigned int groupId)
{
	if (groupId >= m_entities.size())
	{
		LOG_ERROR("Group id %i does not exist", groupId);
		throw std::runtime_error("CCollisionSystem.add: Invalid goup id");
	}
	// Create new entity and add to the collision group
	CCollidable* entity = new CCollidable(groupId, box);
	m_entities[groupId].push_back(entity);
	return entity;
}

// Removes collidable entity
void CCollisionSystem::remove(CCollidable* entity)
{
	m_entities[entity->getGroupId()].remove(entity);
	delete entity;
}

// Test all entities for collision
void CCollisionSystem::update()
{
	for (unsigned int i = 0; i < m_entities.size(); ++i)
	{
		auto iter = m_entities[i].begin();
		while (iter != m_entities[i].end())
		{
			// Delete if requested
			if ((*iter)->deleteRequested())
			{
				CCollidable* temp = (*iter);
				iter = m_entities[i].erase(iter);
				delete temp;
			}
			else
			{
				if ((*iter)->isCollidable())
				{
					testCollision((*iter), i);
				}
				++iter;
			}
		}
	}
}

// Tests collidable entity against all entities not in the group
void CCollisionSystem::testCollision(CCollidable* entity, unsigned int group)
{
	// Everything gets tested twice, make this faster
	for (unsigned int i = 0; i < m_entities.size(); ++i)
	{
		if (i != group)
		{
			auto iter = m_entities[i].begin();
			while (iter != m_entities[i].end())
			{
				// Delete if requested
				if ((*iter)->deleteRequested())
				{
					CCollidable* temp = (*iter);
					iter = m_entities[i].erase(iter);
					delete temp;
				}
				else
				{
					if ((*iter)->isCollidable())
					{
						if (collides(entity->getAABBox(), (*iter)->getAABBox()))
						{
							// Since every collision is tested both ways, damage only happens from first entity to second entity
							(*iter)->receiveDamage(entity->getDamage());
						}
					}
					++iter;
				}
			}
		}
	}
}<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2013 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "condition.h"

#if defined(__WIN32__) && !defined(PTHREADS_WIN32)

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

namespace embree
{
  struct ConditionImplementation
  {
    __forceinline ConditionImplementation ()
      : count(0)
    {
      //mutex = CreateMutex(NULL,FALSE,NULL);
      event = CreateEvent(NULL,TRUE,FALSE,NULL);
    }

    __forceinline ~ConditionImplementation ()
    {
      //CloseHandle(mutex);
      CloseHandle(event);
    }

    __forceinline void wait(MutexSys& mutex_in)
    {
      /* atomically increment thread count */
      //WaitForSingleObject(mutex,INFINITE);
	    //mutex.lock();
      ssize_t cnt0 = atomic_add(&count,+1);
	    //mutex.unlock();
      //ReleaseMutex(mutex);
      mutex_in.unlock();

      /* all threads except the last one are wait in the barrier */
      if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0)
        throw std::runtime_error("WaitForSingleObject failed");

      /* atomically decrement thread count */
      mutex_in.lock();
  	  //WaitForSingleObject(mutex,INFINITE);
	    mutex.lock();
      ssize_t cnt1 = atomic_add(&count,-1);
	    mutex.unlock();
      //ReleaseMutex(mutex);

      /* the last thread that left the barrier resets the event again */
      if (cnt1 == 1) {
        if (ResetEvent(event) == 0)
          throw std::runtime_error("ResetEvent failed");
      }
    }

    __forceinline void broadcast()
    {
      /* we support only one broadcast at a given time */
      //WaitForSingleObject(mutex,INFINITE);
	    //mutex.lock();
	    bool hasWaiters = count > 0;
	    //mutex.unlock();
	    //ReleaseMutex(mutex);

      /* if threads are waiting, let them continue */
      if (hasWaiters)
      {
        if (SetEvent(event) == 0)
          throw std::runtime_error("SetEvent failed");
      }
    }

  public:
    //HANDLE mutex;
    AtomicMutex mutex;
    HANDLE event;
    volatile atomic_t count;
  };
}
#endif

#if defined(__UNIX__) || defined(PTHREADS_WIN32)
#include <pthread.h>
namespace embree
{
  struct ConditionImplementation
  {
    __forceinline ConditionImplementation () {
      pthread_cond_init(&cond,NULL);
    }

    __forceinline ~ConditionImplementation() {
      pthread_cond_destroy(&cond);
    }

    __forceinline void wait(MutexSys& mutex) {
      pthread_cond_wait(&cond, (pthread_mutex_t*)mutex.mutex);
    }

    __forceinline void broadcast() {
      pthread_cond_broadcast(&cond);
    }

  public:
    pthread_cond_t cond;
  };
}
#endif

namespace embree
{
  ConditionSys::ConditionSys () {
    cond = new ConditionImplementation;
  }

  ConditionSys::~ConditionSys() {
    delete (ConditionImplementation*) cond;
  }

  void ConditionSys::wait(MutexSys& mutex) {
    ((ConditionImplementation*) cond)->wait(mutex);
  }

  void ConditionSys::broadcast() {
    ((ConditionImplementation*) cond)->broadcast();
  }
}
<commit_msg>replacement for windows condition also in 2.2<commit_after>// ======================================================================== //
// Copyright 2009-2013 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "condition.h"

#if defined(__WIN32__) && !defined(PTHREADS_WIN32)

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

namespace embree
{
#if 1
  struct ConditionImplementation
  {
    __forceinline ConditionImplementation ()
    {
      InitializeConditionVariable(&cond);
    }

    __forceinline ~ConditionImplementation ()
    {

    }

    __forceinline void wait(MutexSys& mutex_in)
    {
      SleepConditionVariableCS(&cond, (LPCRITICAL_SECTION)mutex_in.mutex, INFINITE);
    }

    __forceinline void broadcast()
    {
      WakeAllConditionVariable(&cond);
    }

  public:
    CONDITION_VARIABLE cond;
  };
#else
  struct ConditionImplementation
  {
    __forceinline ConditionImplementation ()
      : count(0)
    {
      //mutex = CreateMutex(NULL,FALSE,NULL);
      event = CreateEvent(NULL,TRUE,FALSE,NULL);
    }

    __forceinline ~ConditionImplementation ()
    {
      //CloseHandle(mutex);
      CloseHandle(event);
    }

    __forceinline void wait(MutexSys& mutex_in)
    {
      /* atomically increment thread count */
      //WaitForSingleObject(mutex,INFINITE);
      //mutex.lock();
      ssize_t cnt0 = atomic_add(&count,+1);
      //mutex.unlock();
      //ReleaseMutex(mutex);
      mutex_in.unlock();

      /* all threads except the last one are wait in the barrier */
      if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0)
        throw std::runtime_error("WaitForSingleObject failed");

      /* atomically decrement thread count */
      mutex_in.lock();
      //WaitForSingleObject(mutex,INFINITE);
      //mutex.lock();
      ssize_t cnt1 = atomic_add(&count,-1);
      //mutex.unlock();
      //ReleaseMutex(mutex);

      /* the last thread that left the barrier resets the event again */
      if (cnt1 == 1) {
        if (ResetEvent(event) == 0)
          throw std::runtime_error("ResetEvent failed");
      }
    }

    __forceinline void broadcast()
    {
      /* we support only one broadcast at a given time */
      //WaitForSingleObject(mutex,INFINITE);
      //mutex.lock();
      bool hasWaiters = count > 0;
      //mutex.unlock();
      //ReleaseMutex(mutex);

      /* if threads are waiting, let them continue */
      if (hasWaiters)
	{
	  if (SetEvent(event) == 0)
	    throw std::runtime_error("SetEvent failed");
	}
    }

  public:
    //HANDLE mutex;
    AtomicMutex mutex;
    HANDLE event;
    volatile atomic_t count;
  };
#endif
}
#endif

#if defined(__UNIX__) || defined(PTHREADS_WIN32)
#include <pthread.h>
namespace embree
{
  struct ConditionImplementation
  {
    __forceinline ConditionImplementation () {
      pthread_cond_init(&cond,NULL);
    }

    __forceinline ~ConditionImplementation() {
      pthread_cond_destroy(&cond);
    }

    __forceinline void wait(MutexSys& mutex) {
      pthread_cond_wait(&cond, (pthread_mutex_t*)mutex.mutex);
    }

    __forceinline void broadcast() {
      pthread_cond_broadcast(&cond);
    }

  public:
    pthread_cond_t cond;
  };
}
#endif

namespace embree
{
  ConditionSys::ConditionSys () {
    cond = new ConditionImplementation;
  }

  ConditionSys::~ConditionSys() {
    delete (ConditionImplementation*) cond;
  }

  void ConditionSys::wait(MutexSys& mutex) {
    ((ConditionImplementation*) cond)->wait(mutex);
  }

  void ConditionSys::broadcast() {
    ((ConditionImplementation*) cond)->broadcast();
  }
}
<|endoftext|>


<commit_before>/// @file wlog_tools.cpp
/// @brief Well Logs manipulation algorithms
/// @author uentity
/// @version 1.0
/// @date 27.02.2014
/// @copyright This source code is released under the terms of
///            the BSD License. See LICENSE for more details.

#ifndef WLOG_TOOLS_TMEEHO84
#define WLOG_TOOLS_TMEEHO84

#include "bs_kernel.h"
#include "conf.h"
#include <limits>
// DEBUG
//#include <iostream>

namespace blue_sky {

// hidden implementation
namespace {

typedef v_float::iterator vf_iterator;
typedef v_float::const_iterator cvf_iterator;
typedef v_float::reverse_iterator vf_riterator;
typedef v_float::const_reverse_iterator cvf_riterator;

// depth and share same iterator type
template< class data_iterator, class grid_iterator, class res_iterator >
void projection_impl(
	//const spv_float& wlog_data, const spv_float& wlog_dept,
	const data_iterator& p_data_begin, const data_iterator& p_data_end,
	const data_iterator& p_dept_begin, const data_iterator& p_dept_end,
	grid_iterator& p_grid, const grid_iterator& p_grid_end,
	res_iterator& p_res
) {
	// setup iterators
	//const cvf_iterator p_dept_begin = wlog_dept->begin();
	//const cvf_iterator p_dept_end = p_dept_begin + wlog_sz;

	const ulong wlog_sz = std::min< ulong >(p_data_end - p_data_begin, p_dept_end - p_dept_begin);
	//const ulong wlog_sz = std::min(wlog_data->size(), wlog_dept->size());
	if(wlog_sz == 0)
		return;

	// find starting point on well log
	data_iterator p_dept = std::lower_bound(
		p_dept_begin, p_dept_end, *p_grid
	);
	data_iterator p_data = p_data_begin + (p_dept - p_dept_begin);

	// DEBUG
	//std::cout << "++wlog_mean_projection:" << std::endl;
	//std::cout << "log_dept = [" << *p_dept << ", " << *(p_dept_end - 1) << "]" << std::endl;
	//std::cout << "grid = [" << *p_grid << ", " << *(p_grid_end - 1) << "]" << std::endl;
	// position dest grid to next boundary
	++p_grid;
	const res_iterator p_res_end = p_res + (p_grid_end - p_grid - 1);

	// main cycle
	t_float win_sum = 0;
	// win_sz counts only valid numbers that fits in window
	// raw_sz counts all values in window, including NaNs
	ulong win_sz = 0, raw_sz = 0;
	while(p_grid != p_grid_end) {
		// if we reached window boundary
		if(*p_dept > *p_grid) {
			if(win_sz)
				*p_res = win_sum / win_sz;
			else if(!raw_sz && (p_dept != p_dept_begin)) {
				// assign prev log value only if we had no NaNs in window
				*p_res = *(p_data - 1);
			}

			// next step on dest grid and resulting array
			if(++p_res == p_res_end)
				break;
			++p_grid;
			win_sum = 0;
			win_sz = 0;
			raw_sz = 0;
		}
		else {
			// we're inside window
			// check for NaN
			if(!(*p_data != *p_data)) {
				win_sum += *p_data;
				++win_sz;
			}
			// count all values in raw_sz
			++raw_sz;
			// next step in well log
			++p_data; ++p_dept;
			if(p_dept == p_dept_end) {
				if(win_sz)
					*p_res = win_sum / win_sz;
				break;
			}
		}
	}
}

} // eof hidden namespace

BS_API spv_float wlog_mean_projection(
	spv_float wlog_data, spv_float wlog_dept, spv_float dest_grid
) {
	// sanity
	spv_float res = BS_KERNEL.create_object(v_float::bs_type());
	if(!wlog_data->size() || !wlog_dept->size() || dest_grid->size() < 2 || !res)
		return res;
	res->resize(dest_grid->size() - 1);
	// fill resulting array with NaN
	std::fill(res->begin(), res->end(), std::numeric_limits< double >::quiet_NaN());

	// check grid ordering
	if(dest_grid->ss(0) < dest_grid->ss(dest_grid->size() - 1)) {
		// normal ordering
		cvf_iterator p_grid = dest_grid->begin();
		const cvf_iterator p_grid_end = dest_grid->end();
		vf_iterator p_res = res->begin();

		// check depth ordering
		if(wlog_dept->ss(0) < wlog_dept->ss(wlog_dept->size() - 1)) {
			projection_impl(
				wlog_data->begin(), wlog_data->end(),
				wlog_dept->begin(), wlog_dept->end(),
				p_grid, p_grid_end, p_res
			);
		}
		else {
			projection_impl(
				wlog_data->rbegin(), wlog_data->rend(),
				wlog_dept->rbegin(), wlog_dept->rend(),
				p_grid, p_grid_end, p_res
			);
		}
	}
	else {
		// reversed grid ordering
		cvf_riterator p_grid = dest_grid->rbegin();
		const cvf_riterator p_grid_end = dest_grid->rend();
		vf_riterator p_res = res->rbegin();

		// check depth ordering
		if(wlog_dept->ss(0) < wlog_dept->ss(wlog_dept->size() - 1)) {
			projection_impl(
				wlog_data->begin(), wlog_data->end(),
				wlog_dept->begin(), wlog_dept->end(),
				p_grid, p_grid_end, p_res
			);
		}
		else {
			projection_impl(
				wlog_data->rbegin(), wlog_data->rend(),
				wlog_dept->rbegin(), wlog_dept->rend(),
				p_grid, p_grid_end, p_res
			);
		}
		//projection_impl(wlog_data, wlog_dept, p_grid, p_grid_end, p_res);
	}
	return res;
}

} /* namespace blue_sky */

#endif /* end of include guard: WLOG_TOOLS_TMEEHO84 */

<commit_msg>wlog_tools: check if target grid is fully outside of well log bounds<commit_after>/// @file wlog_tools.cpp
/// @brief Well Logs manipulation algorithms
/// @author uentity
/// @version 1.0
/// @date 27.02.2014
/// @copyright This source code is released under the terms of
///            the BSD License. See LICENSE for more details.

#ifndef WLOG_TOOLS_TMEEHO84
#define WLOG_TOOLS_TMEEHO84

#include "bs_kernel.h"
#include "conf.h"
#include <limits>
// DEBUG
//#include <iostream>

namespace blue_sky {

// hidden implementation
namespace {

typedef v_float::iterator vf_iterator;
typedef v_float::const_iterator cvf_iterator;
typedef v_float::reverse_iterator vf_riterator;
typedef v_float::const_reverse_iterator cvf_riterator;

// depth and share same iterator type
template< class data_iterator, class grid_iterator, class res_iterator >
void projection_impl(
	//const spv_float& wlog_data, const spv_float& wlog_dept,
	const data_iterator& p_data_begin, const data_iterator& p_data_end,
	const data_iterator& p_dept_begin, const data_iterator& p_dept_end,
	grid_iterator& p_grid, const grid_iterator& p_grid_end,
	res_iterator& p_res
) {
	// setup iterators
	//const cvf_iterator p_dept_begin = wlog_dept->begin();
	//const cvf_iterator p_dept_end = p_dept_begin + wlog_sz;

	const ulong wlog_sz = std::min< ulong >(p_data_end - p_data_begin, p_dept_end - p_dept_begin);
	//const ulong wlog_sz = std::min(wlog_data->size(), wlog_dept->size());
	if(wlog_sz == 0)
		return;

	// find starting point on well log
	data_iterator p_dept = std::lower_bound(
		p_dept_begin, p_dept_end, *p_grid
	);
	if(p_dept == p_dept_end)
		// grid is fully outside of well log depths
		return;

	data_iterator p_data = p_data_begin + (p_dept - p_dept_begin);

	// DEBUG
	//std::cout << "++wlog_mean_projection:" << std::endl;
	//std::cout << "log_dept = [" << *p_dept << ", " << *(p_dept_end - 1) << "]" << std::endl;
	//std::cout << "grid = [" << *p_grid << ", " << *(p_grid_end - 1) << "]" << std::endl;
	// position dest grid to next boundary
	++p_grid;
	const res_iterator p_res_end = p_res + (p_grid_end - p_grid - 1);

	// main cycle
	t_float win_sum = 0;
	// win_sz counts only valid numbers that fits in window
	// raw_sz counts all values in window, including NaNs
	ulong win_sz = 0, raw_sz = 0;
	while(p_grid != p_grid_end) {
		// if we reached window boundary
		if(*p_dept > *p_grid) {
			if(win_sz)
				*p_res = win_sum / win_sz;
			else if(!raw_sz && (p_dept != p_dept_begin)) {
				// assign prev log value only if we had no NaNs in window
				*p_res = *(p_data - 1);
			}

			// next step on dest grid and resulting array
			if(++p_res == p_res_end)
				break;
			++p_grid;
			win_sum = 0;
			win_sz = 0;
			raw_sz = 0;
		}
		else {
			// we're inside window
			// check for NaN
			if(!(*p_data != *p_data)) {
				win_sum += *p_data;
				++win_sz;
			}
			// count all values in raw_sz
			++raw_sz;
			// next step in well log
			++p_data; ++p_dept;
			if(p_dept == p_dept_end) {
				if(win_sz)
					*p_res = win_sum / win_sz;
				break;
			}
		}
	}
}

} // eof hidden namespace

BS_API spv_float wlog_mean_projection(
	spv_float wlog_data, spv_float wlog_dept, spv_float dest_grid
) {
	// sanity
	spv_float res = BS_KERNEL.create_object(v_float::bs_type());
	if(!wlog_data->size() || !wlog_dept->size() || dest_grid->size() < 2 || !res)
		return res;
	res->resize(dest_grid->size() - 1);
	// fill resulting array with NaN
	std::fill(res->begin(), res->end(), std::numeric_limits< double >::quiet_NaN());

	// check grid ordering
	if(dest_grid->ss(0) < dest_grid->ss(dest_grid->size() - 1)) {
		// normal ordering
		cvf_iterator p_grid = dest_grid->begin();
		const cvf_iterator p_grid_end = dest_grid->end();
		vf_iterator p_res = res->begin();

		// check depth ordering
		if(wlog_dept->ss(0) < wlog_dept->ss(wlog_dept->size() - 1)) {
			projection_impl(
				wlog_data->begin(), wlog_data->end(),
				wlog_dept->begin(), wlog_dept->end(),
				p_grid, p_grid_end, p_res
			);
		}
		else {
			projection_impl(
				wlog_data->rbegin(), wlog_data->rend(),
				wlog_dept->rbegin(), wlog_dept->rend(),
				p_grid, p_grid_end, p_res
			);
		}
	}
	else {
		// reversed grid ordering
		cvf_riterator p_grid = dest_grid->rbegin();
		const cvf_riterator p_grid_end = dest_grid->rend();
		vf_riterator p_res = res->rbegin();

		// check depth ordering
		if(wlog_dept->ss(0) < wlog_dept->ss(wlog_dept->size() - 1)) {
			projection_impl(
				wlog_data->begin(), wlog_data->end(),
				wlog_dept->begin(), wlog_dept->end(),
				p_grid, p_grid_end, p_res
			);
		}
		else {
			projection_impl(
				wlog_data->rbegin(), wlog_data->rend(),
				wlog_dept->rbegin(), wlog_dept->rend(),
				p_grid, p_grid_end, p_res
			);
		}
		//projection_impl(wlog_data, wlog_dept, p_grid, p_grid_end, p_res);
	}
	return res;
}

} /* namespace blue_sky */

#endif /* end of include guard: WLOG_TOOLS_TMEEHO84 */

<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "main.h"
#include <Eigen/LU>

template<typename MatrixType> void inverse(const MatrixType& m)
{
  using std::abs;
  typedef typename MatrixType::Index Index;
  /* this test covers the following files:
     Inverse.h
  */
  Index rows = m.rows();
  Index cols = m.cols();

  typedef typename MatrixType::Scalar Scalar;

  MatrixType m1(rows, cols),
             m2(rows, cols),
             identity = MatrixType::Identity(rows, rows);
  createRandomPIMatrixOfRank(rows,rows,rows,m1);
  m2 = m1.inverse();
  VERIFY_IS_APPROX(m1, m2.inverse() );

  VERIFY_IS_APPROX((Scalar(2)*m2).inverse(), m2.inverse()*Scalar(0.5));

  VERIFY_IS_APPROX(identity, m1.inverse() * m1 );
  VERIFY_IS_APPROX(identity, m1 * m1.inverse() );

  VERIFY_IS_APPROX(m1, m1.inverse().inverse() );

  // since for the general case we implement separately row-major and col-major, test that
  VERIFY_IS_APPROX(MatrixType(m1.transpose().inverse()), MatrixType(m1.inverse().transpose()));

#if !defined(EIGEN_TEST_PART_5) && !defined(EIGEN_TEST_PART_6)
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;

  //computeInverseAndDetWithCheck tests
  //First: an invertible matrix
  bool invertible;
  RealScalar det;

  m2.setZero();
  m1.computeInverseAndDetWithCheck(m2, det, invertible);
  VERIFY(invertible);
  VERIFY_IS_APPROX(identity, m1*m2);
  VERIFY_IS_APPROX(det, m1.determinant());

  m2.setZero();
  m1.computeInverseWithCheck(m2, invertible);
  VERIFY(invertible);
  VERIFY_IS_APPROX(identity, m1*m2);

  //Second: a rank one matrix (not invertible, except for 1x1 matrices)
  VectorType v3 = VectorType::Random(rows);
  MatrixType m3 = v3*v3.transpose(), m4(rows,cols);
  m3.computeInverseAndDetWithCheck(m4, det, invertible);
  VERIFY( rows==1 ? invertible : !invertible );
  VERIFY_IS_MUCH_SMALLER_THAN(abs(det-m3.determinant()), RealScalar(1));
  m3.computeInverseWithCheck(m4, invertible);
  VERIFY( rows==1 ? invertible : !invertible );

  // check with submatrices
  {
    Matrix<Scalar, MatrixType::RowsAtCompileTime+1, MatrixType::RowsAtCompileTime+1, MatrixType::Options> m3;
    m3.setRandom();
    m2 = m3.template topLeftCorner<MatrixType::RowsAtCompileTime,MatrixType::ColsAtCompileTime>().inverse();
    VERIFY_IS_APPROX( (m3.template topLeftCorner<MatrixType::RowsAtCompileTime,MatrixType::ColsAtCompileTime>()), m2.inverse() );
  }
#endif

  // check in-place inversion
  if(MatrixType::RowsAtCompileTime>=2 && MatrixType::RowsAtCompileTime<=4)
  {
    // in-place is forbidden
    VERIFY_RAISES_ASSERT(m1 = m1.inverse());
  }
  else
  {
    m2 = m1.inverse();
    m1 = m1.inverse();
    VERIFY_IS_APPROX(m1,m2);
  }
}

void test_inverse()
{
  int s = 0;
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( inverse(Matrix<double,1,1>()) );
    CALL_SUBTEST_2( inverse(Matrix2d()) );
    CALL_SUBTEST_3( inverse(Matrix3f()) );
    CALL_SUBTEST_4( inverse(Matrix4f()) );
    CALL_SUBTEST_4( inverse(Matrix<float,4,4,DontAlign>()) );
    s = internal::random<int>(50,320);
    CALL_SUBTEST_5( inverse(MatrixXf(s,s)) );
    s = internal::random<int>(25,100);
    CALL_SUBTEST_6( inverse(MatrixXcd(s,s)) );
    CALL_SUBTEST_7( inverse(Matrix4d()) );
    CALL_SUBTEST_7( inverse(Matrix<double,4,4,DontAlign>()) );
  }
  TEST_SET_BUT_UNUSED_VARIABLE(s)
}
<commit_msg>Fix inverse unit test making sure we try to invert an invertible matrix<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "main.h"
#include <Eigen/LU>

template<typename MatrixType> void inverse(const MatrixType& m)
{
  using std::abs;
  typedef typename MatrixType::Index Index;
  /* this test covers the following files:
     Inverse.h
  */
  Index rows = m.rows();
  Index cols = m.cols();

  typedef typename MatrixType::Scalar Scalar;

  MatrixType m1(rows, cols),
             m2(rows, cols),
             identity = MatrixType::Identity(rows, rows);
  createRandomPIMatrixOfRank(rows,rows,rows,m1);
  m2 = m1.inverse();
  VERIFY_IS_APPROX(m1, m2.inverse() );

  VERIFY_IS_APPROX((Scalar(2)*m2).inverse(), m2.inverse()*Scalar(0.5));

  VERIFY_IS_APPROX(identity, m1.inverse() * m1 );
  VERIFY_IS_APPROX(identity, m1 * m1.inverse() );

  VERIFY_IS_APPROX(m1, m1.inverse().inverse() );

  // since for the general case we implement separately row-major and col-major, test that
  VERIFY_IS_APPROX(MatrixType(m1.transpose().inverse()), MatrixType(m1.inverse().transpose()));

#if !defined(EIGEN_TEST_PART_5) && !defined(EIGEN_TEST_PART_6)
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;

  //computeInverseAndDetWithCheck tests
  //First: an invertible matrix
  bool invertible;
  RealScalar det;

  m2.setZero();
  m1.computeInverseAndDetWithCheck(m2, det, invertible);
  VERIFY(invertible);
  VERIFY_IS_APPROX(identity, m1*m2);
  VERIFY_IS_APPROX(det, m1.determinant());

  m2.setZero();
  m1.computeInverseWithCheck(m2, invertible);
  VERIFY(invertible);
  VERIFY_IS_APPROX(identity, m1*m2);

  //Second: a rank one matrix (not invertible, except for 1x1 matrices)
  VectorType v3 = VectorType::Random(rows);
  MatrixType m3 = v3*v3.transpose(), m4(rows,cols);
  m3.computeInverseAndDetWithCheck(m4, det, invertible);
  VERIFY( rows==1 ? invertible : !invertible );
  VERIFY_IS_MUCH_SMALLER_THAN(abs(det-m3.determinant()), RealScalar(1));
  m3.computeInverseWithCheck(m4, invertible);
  VERIFY( rows==1 ? invertible : !invertible );

  // check with submatrices
  {
    Matrix<Scalar, MatrixType::RowsAtCompileTime+1, MatrixType::RowsAtCompileTime+1, MatrixType::Options> m3;
    m3.setRandom();
    m3.topLeftCorner(rows,rows) = m1;
    m2 = m3.template topLeftCorner<MatrixType::RowsAtCompileTime,MatrixType::ColsAtCompileTime>().inverse();
    VERIFY_IS_APPROX( (m3.template topLeftCorner<MatrixType::RowsAtCompileTime,MatrixType::ColsAtCompileTime>()), m2.inverse() );
  }
#endif

  // check in-place inversion
  if(MatrixType::RowsAtCompileTime>=2 && MatrixType::RowsAtCompileTime<=4)
  {
    // in-place is forbidden
    VERIFY_RAISES_ASSERT(m1 = m1.inverse());
  }
  else
  {
    m2 = m1.inverse();
    m1 = m1.inverse();
    VERIFY_IS_APPROX(m1,m2);
  }
}

void test_inverse()
{
  int s = 0;
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( inverse(Matrix<double,1,1>()) );
    CALL_SUBTEST_2( inverse(Matrix2d()) );
    CALL_SUBTEST_3( inverse(Matrix3f()) );
    CALL_SUBTEST_4( inverse(Matrix4f()) );
    CALL_SUBTEST_4( inverse(Matrix<float,4,4,DontAlign>()) );
    s = internal::random<int>(50,320);
    CALL_SUBTEST_5( inverse(MatrixXf(s,s)) );
    s = internal::random<int>(25,100);
    CALL_SUBTEST_6( inverse(MatrixXcd(s,s)) );
    CALL_SUBTEST_7( inverse(Matrix4d()) );
    CALL_SUBTEST_7( inverse(Matrix<double,4,4,DontAlign>()) );
  }
  TEST_SET_BUT_UNUSED_VARIABLE(s)
}
<|endoftext|>


<commit_before>#include "stan/math/functions/binary_log_loss.hpp"
#include <gtest/gtest.h>

TEST(MathFunctions, binary_log_loss) {
  EXPECT_FLOAT_EQ(0.0, stan::math::binary_log_loss(0,0.0));
  EXPECT_FLOAT_EQ(0.0, stan::math::binary_log_loss(1,1.0));
  EXPECT_FLOAT_EQ(-log(0.5), stan::math::binary_log_loss(0,0.5));
  EXPECT_FLOAT_EQ(-log(0.5), stan::math::binary_log_loss(1,0.5));
  EXPECT_FLOAT_EQ(-log(0.75), stan::math::binary_log_loss(0,0.25));
  EXPECT_FLOAT_EQ(-log(0.75), stan::math::binary_log_loss(1,0.75));
}

<commit_msg>added NaN test for binary_log_loss<commit_after>#include <stan/math/functions/binary_log_loss.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
#include <gtest/gtest.h>

TEST(MathFunctions, binary_log_loss) {
  EXPECT_FLOAT_EQ(0.0, stan::math::binary_log_loss(0,0.0));
  EXPECT_FLOAT_EQ(0.0, stan::math::binary_log_loss(1,1.0));
  EXPECT_FLOAT_EQ(-log(0.5), stan::math::binary_log_loss(0,0.5));
  EXPECT_FLOAT_EQ(-log(0.5), stan::math::binary_log_loss(1,0.5));
  EXPECT_FLOAT_EQ(-log(0.75), stan::math::binary_log_loss(0,0.25));
  EXPECT_FLOAT_EQ(-log(0.75), stan::math::binary_log_loss(1,0.75));
}

TEST(MathFunctions, binary_log_loss_nan) {
  double nan = std::numeric_limits<double>::quiet_NaN();

  EXPECT_PRED1(boost::math::isnan<double>,
               stan::math::binary_log_loss(0, nan));

  EXPECT_PRED1(boost::math::isnan<double>,
               stan::math::binary_log_loss(1, nan));
}
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 2001, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 * $Log$
 * Revision 1.8  2001/10/09 20:46:19  peiyongz
 * NOTATION: checkContent(): <URI>:<localPart>
 *
 * Revision 1.7  2001/10/02 18:59:29  peiyongz
 * Invalid_Facet_Tag to display the tag name
 *
 * Revision 1.6  2001/09/24 15:33:15  peiyongz
 * DTV Reorganization: virtual methods moved to *.cpp
 *
 * Revision 1.5  2001/09/20 15:14:47  peiyongz
 * DTV reorganization: inherit from AbstractStringVaildator
 *
 * Revision 1.3  2001/08/21 18:42:53  peiyongz
 * Bugzilla# 2816: cleanUp() declared with external linkage and called
 *                          before defined as inline
 *
 * Revision 1.2  2001/08/14 22:11:56  peiyongz
 * new exception message added
 *
 * Revision 1.1  2001/07/05 20:15:27  peiyongz
 * NOTATIONDatatypeValidator
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <validators/datatype/NOTATIONDatatypeValidator.hpp>
#include <util/XMLUri.hpp>
#include <validators/datatype/InvalidDatatypeFacetException.hpp>
#include <validators/datatype/InvalidDatatypeValueException.hpp>

// ---------------------------------------------------------------------------
//  Constructors and Destructor
// ---------------------------------------------------------------------------
NOTATIONDatatypeValidator::NOTATIONDatatypeValidator()
:AbstractStringValidator(0, 0, 0, DatatypeValidator::NOTATION)
{}

NOTATIONDatatypeValidator::~NOTATIONDatatypeValidator()
{}

NOTATIONDatatypeValidator::NOTATIONDatatypeValidator(
                          DatatypeValidator*            const baseValidator
                        , RefHashTableOf<KVStringPair>* const facets
                        , RefVectorOf<XMLCh>*           const enums
                        , const int                           finalSet)
:AbstractStringValidator(baseValidator, facets, finalSet, DatatypeValidator::NOTATION)
{
    init(enums);
}

DatatypeValidator* NOTATIONDatatypeValidator::newInstance(
                                      RefHashTableOf<KVStringPair>* const facets
                                    , RefVectorOf<XMLCh>*           const enums
                                    , const int                           finalSet)
{
    return (DatatypeValidator*) new NOTATIONDatatypeValidator(this, facets, enums, finalSet);
}

// ---------------------------------------------------------------------------
//  Utilities
// ---------------------------------------------------------------------------
void NOTATIONDatatypeValidator::assignAdditionalFacet( const XMLCh* const key
                                                     , const XMLCh* const)
{
    ThrowXML1(InvalidDatatypeFacetException
            , XMLExcepts::FACET_Invalid_Tag
            , key);
}

void NOTATIONDatatypeValidator::inheritAdditionalFacet()
{}

void NOTATIONDatatypeValidator::checkAdditionalFacetConstraints() const
{}

void NOTATIONDatatypeValidator::checkAdditionalFacet(const XMLCh* const) const
{}

void NOTATIONDatatypeValidator::checkValueSpace(const XMLCh* const content)
{
    //
    //  NOTATATION: <URI>:<localPart>
    //  both URI and localPart must be present
    //
    int contentLength = XMLString::stringLen(content);
    int colonPosition = XMLString::lastIndexOf(content, chColon);

    if ((colonPosition == -1)                ||  // no ':'
        (colonPosition == 0 )                ||  // ':'<localPart>
        (colonPosition == contentLength - 1)  )  // <URI>':'
        ThrowXML1(InvalidDatatypeValueException
                , XMLExcepts::VALUE_NOTATION_Invalid
                , content);

    // Extract URI
    XMLCh* uriPart = new XMLCh[colonPosition + 1];
    ArrayJanitor<XMLCh> jan1(uriPart);
    XMLString::subString(uriPart, content, 0, colonPosition - 1);

    try
    {
        // no relative uri support here
        XMLUri  *newURI = new XMLUri(uriPart);
        delete newURI;
    }
    catch (...)
    {
        ThrowXML1(InvalidDatatypeValueException
                , XMLExcepts::VALUE_NOTATION_Invalid
                , content);
    }

    // Extract localpart
    XMLCh* localPart = new XMLCh[contentLength - colonPosition];
    ArrayJanitor<XMLCh> jan2(localPart);
    XMLString::subString(localPart, content, colonPosition + 1, contentLength - 1);

    if ( !XMLString::isValidNCName(localPart))
    {
        ThrowXML1(InvalidDatatypeValueException
                , XMLExcepts::VALUE_NOTATION_Invalid
                , content);
    }

}

int NOTATIONDatatypeValidator::getLength(const XMLCh* const content) const
{
    return XMLString::stringLen(content);
}

/**
  * End of file NOTATIONDatatypeValidator.cpp
  */
<commit_msg><URI>:<LocalPart> where <URI> can be optional.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 2001, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 * $Log$
 * Revision 1.9  2001/10/10 14:17:50  peiyongz
 * <URI>:<LocalPart> where <URI> can be optional.
 *
 * Revision 1.8  2001/10/09 20:46:19  peiyongz
 * NOTATION: checkContent(): <URI>:<localPart>
 *
 * Revision 1.7  2001/10/02 18:59:29  peiyongz
 * Invalid_Facet_Tag to display the tag name
 *
 * Revision 1.6  2001/09/24 15:33:15  peiyongz
 * DTV Reorganization: virtual methods moved to *.cpp
 *
 * Revision 1.5  2001/09/20 15:14:47  peiyongz
 * DTV reorganization: inherit from AbstractStringVaildator
 *
 * Revision 1.3  2001/08/21 18:42:53  peiyongz
 * Bugzilla# 2816: cleanUp() declared with external linkage and called
 *                          before defined as inline
 *
 * Revision 1.2  2001/08/14 22:11:56  peiyongz
 * new exception message added
 *
 * Revision 1.1  2001/07/05 20:15:27  peiyongz
 * NOTATIONDatatypeValidator
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <validators/datatype/NOTATIONDatatypeValidator.hpp>
#include <util/XMLUri.hpp>
#include <validators/datatype/InvalidDatatypeFacetException.hpp>
#include <validators/datatype/InvalidDatatypeValueException.hpp>

// ---------------------------------------------------------------------------
//  Constructors and Destructor
// ---------------------------------------------------------------------------
NOTATIONDatatypeValidator::NOTATIONDatatypeValidator()
:AbstractStringValidator(0, 0, 0, DatatypeValidator::NOTATION)
{}

NOTATIONDatatypeValidator::~NOTATIONDatatypeValidator()
{}

NOTATIONDatatypeValidator::NOTATIONDatatypeValidator(
                          DatatypeValidator*            const baseValidator
                        , RefHashTableOf<KVStringPair>* const facets
                        , RefVectorOf<XMLCh>*           const enums
                        , const int                           finalSet)
:AbstractStringValidator(baseValidator, facets, finalSet, DatatypeValidator::NOTATION)
{
    init(enums);
}

DatatypeValidator* NOTATIONDatatypeValidator::newInstance(
                                      RefHashTableOf<KVStringPair>* const facets
                                    , RefVectorOf<XMLCh>*           const enums
                                    , const int                           finalSet)
{
    return (DatatypeValidator*) new NOTATIONDatatypeValidator(this, facets, enums, finalSet);
}

// ---------------------------------------------------------------------------
//  Utilities
// ---------------------------------------------------------------------------
void NOTATIONDatatypeValidator::assignAdditionalFacet( const XMLCh* const key
                                                     , const XMLCh* const)
{
    ThrowXML1(InvalidDatatypeFacetException
            , XMLExcepts::FACET_Invalid_Tag
            , key);
}

void NOTATIONDatatypeValidator::inheritAdditionalFacet()
{}

void NOTATIONDatatypeValidator::checkAdditionalFacetConstraints() const
{}

void NOTATIONDatatypeValidator::checkAdditionalFacet(const XMLCh* const) const
{}

void NOTATIONDatatypeValidator::checkValueSpace(const XMLCh* const content)
{
    //
    //  NOTATATION: <URI>:<localPart>
    //  where URI is optional
    //        ':' and localPart must be present
    //
    int contentLength = XMLString::stringLen(content);
    int colonPosition = XMLString::lastIndexOf(content, chColon);

    if ((colonPosition == -1)                ||  // no ':'
        (colonPosition == contentLength - 1)  )  // <URI>':'
        ThrowXML1(InvalidDatatypeValueException
                , XMLExcepts::VALUE_NOTATION_Invalid
                , content);

    // Extract URI
    XMLCh* uriPart = new XMLCh[colonPosition + 1];
    ArrayJanitor<XMLCh> jan1(uriPart);
    XMLString::subString(uriPart, content, 0, colonPosition);

    try
    {
        // no relative uri support here
        XMLUri  newURI(uriPart);
    }
    catch (...)
    {
        ThrowXML1(InvalidDatatypeValueException
                , XMLExcepts::VALUE_NOTATION_Invalid
                , content);
    }

    // Extract localpart
    XMLCh* localPart = new XMLCh[contentLength - colonPosition];
    ArrayJanitor<XMLCh> jan2(localPart);
    XMLString::subString(localPart, content, colonPosition + 1, contentLength);

    if ( !XMLString::isValidNCName(localPart))
    {
        ThrowXML1(InvalidDatatypeValueException
                , XMLExcepts::VALUE_NOTATION_Invalid
                , content);
    }

}

int NOTATIONDatatypeValidator::getLength(const XMLCh* const content) const
{
    return XMLString::stringLen(content);
}

/**
  * End of file NOTATIONDatatypeValidator.cpp
  */
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2011-2013 Yule Fox. All rights reserved.
 * http://www.yulefox.com/
 */

#include <elf/log.h>
#include <elf/memory.h>
#include <elf/time.h>
#include <elf/timer.h>
#include <algorithm>
#include <list>
#include <map>

namespace elf {
#define WHEEL_SET_BIT0                  8
#define WHEEL_SET_BITS                  (WHEEL_SET_BIT0 * 4)
#define WHEEL_SET_BIT(l)                (WHEEL_SET_BIT0 * (l))
#define WHEEL_SET_SIZE0                 (1 << WHEEL_SET_BIT0)
#define WHEEL_SET_SIZE(l)               WHEEL_SET_SIZE0
#define MAX_WHEEL_SET_SIZE              (WHEEL_SET_SIZE0 * 4)
#define MAX_CURSOR                      (1LL << WHEEL_SET_BITS)
#define MAX_LIFE                        (MAX_CURSOR * s_mgr.interval)
#define FRAME_DIFFER(l, r)              (int)(l - r)

union cursor_t {
    struct wheel_t {
        unsigned char w0;
        unsigned char w1;
        unsigned char w2;
        unsigned char w3;
    };
    wheel_t w;
    int a;
};

struct timer_t {
    oid_t id; // identification
    time64_t life; // life from now
    cursor_t cursor; // expired frame
    bool script;
    union cb_t {
        char script[1024]; // script function name
        callback func; // callback function
    };
    cb_t cb; // callback function
    void *args; // callback arguments
    timer_t *next; // the next node of the tail node is NULL
    timer_t *prev; // the previous node of the head node is the tail
    int bucket;
    bool manual; // manual destroy args
    bool alive;
};

struct mgr_t {
    time64_t start_time; // start time
    time64_t end_time; // end time
    time64_t cur_time; // current frame time
    time64_t last_time; // last pause time
    time64_t interval; // frame interval time
    cursor_t cursor; // current cursor (number of escaped frames)
    int round; // current round
    int last_cursor; // last pause cursor
    int timer_total; // total number of timers
    int timer_remain; // remain timers
    int timer_passed; // total number of passed timers
    int timer_cancelled; // total number of cancelled timers
    bool pause; // suspend all timers
    timer_t *timers[MAX_WHEEL_SET_SIZE];
};

typedef std::list<callback> handler_list;
typedef std::map<oid_t, timer_t*> timer_map;

static handler_list s_handlers;

static const time64_t TIMER_FRAME_INTERVAL_DEFAULT = 50; // (ms)
static const time64_t TIMER_FRAME_INTERVAL_MIN = 1; // (frame)
static const time64_t TIMER_FRAME_INTERVAL_MAX = 1000; // (frame)
static mgr_t s_mgr;
static timer_map s_timers;

/// calculate the number of life frames
#define FRAME_CALC(t) ((time64_t)(t) / s_mgr.interval)

// @{
/// get current bucket cursor at wheel 0
#define CURRENT_WHEEL_CURSOR    s_mgr.cursor.w.w0

/// compare given cursor with current bucket cursor at wheel @param l
#define WHEEL_CMP(cur, l)                                                   \
    ((int)cur.w.w##l - (int)s_mgr.cursor.w.w##l)

/// map cursor at wheel @param l
#define BUCKET_MAP(cur, l)                                                  \
    (cur.w.w##l + WHEEL_SET_SIZE0 * l)

/// calculate the number of frames elapsed from last cursor
#define FRAME_BINGO (s_mgr.last_cursor +                                    \
        FRAME_CALC(s_mgr.cur_time - s_mgr.last_time) - s_mgr.cursor.a)
// @}

static void reset(void);
static void push(timer_t *t, int bucket);
static void destroy(timer_t *t);
static int schedule(timer_t *t);
static void expire(timer_t *t);
static void bingo(void);
static void hash(int bucket);
static bool timer_min(void *args);

int timer_init(void)
{
    MODULE_IMPORT_SWITCH;
    s_mgr.interval = TIMER_FRAME_INTERVAL_DEFAULT;
    s_mgr.start_time = s_mgr.last_time = time_ms();
    s_mgr.pause = true;
    s_mgr.cursor.a = 0;
    s_mgr.round = 0;
    memset(s_mgr.timers, 0, sizeof(s_mgr.timers[0]) * MAX_WHEEL_SET_SIZE);

    time_t ms = time_ms() % 1000;
    time_t cur = time_s();
    time64_t tm_timer;
    struct tm tm_cur;

    localtime_r(&cur, &tm_cur);
    tm_timer = (60 - tm_cur.tm_sec) * 1000llu - ms;

    timer_add(tm_timer, timer_min, NULL, true);
    return 0;
}

int timer_fini(void)
{
    MODULE_IMPORT_SWITCH;
    s_mgr.end_time = time_ms();
    for (int i = 0; i < MAX_WHEEL_SET_SIZE; ++i) {
        timer_t *head = s_mgr.timers[i];
        timer_t *t = head;

        while (t) {
            timer_t *n = t->next;

            destroy(t);
            if (n == head) break;
            t = n;
        }
    }
    return 0;
}

void timer_run(void)
{
    if (s_mgr.pause || s_mgr.timer_remain <= 0) {
        return;
    }

    // frame may greater than 1 while CPU busying
    s_mgr.cur_time = time_ms();
    int frame = FRAME_BINGO;

    // time anomaly
    if (frame < 0) {
        LOG_WARN("timer", "(%u)%08X: %llu - %llu(%d).",
                s_mgr.round, s_mgr.cursor.a,
                s_mgr.cur_time, s_mgr.last_time,
                frame);
        assert(frame >= 0);
        return;
    }
    // while processors is busy
    if (frame > 5) {
        LOG_WARN("timer", "(%u)%08X: %llu - %llu(%d).",
                s_mgr.round, s_mgr.cursor.a,
                s_mgr.cur_time, s_mgr.last_time,
                frame);
    }
    for (int i = 1; i <= frame; ++i) { // BINGO!
        unsigned char bucket = CURRENT_WHEEL_CURSOR;

        timer_t *head = s_mgr.timers[bucket];
        timer_t *t = head;
        while (t) { // expire all timers
            _timer_del(t);
            if (!t->alive) {
                _timer_remove(t);
                continue;
            }
            expire(t);
            ++s_mgr.timer_passed;
            --s_mgr.timer_remain;

            if (t->next == t) {
                s_mgr.timers[bucket] = NULL;
                break;
            }
            t = t->next;
        }
        bingo();
    }
}

void timer_stat(void)
{
    LOG_INFO("timer",
            "ST: %lld RND: %u FRM: %u TMT: %u TMP: %u TMC: %u.",
            s_mgr.start_time, s_mgr.round, s_mgr.cursor.a,
            s_mgr.timer_total, s_mgr.timer_passed, s_mgr.timer_cancelled);
}

int timer_size(void)
{
    return s_mgr.timer_remain;
}

const oid_t &timer_add(time64_t life, const char *func)
{
    if (life < 0 || life >= MAX_LIFE) {
        LOG_WARN("timer",
                "Timer added FAILED: invalid timer life(%lld) [0, %lld).",
                life, MAX_LIFE);
        return OID_NIL;
    }

    timer_t *t = E_NEW timer_t;

    memset(t, 0, sizeof(*t));
    t->id = oid_gen();
    t->life = std::max(life, s_mgr.interval);
    t->cursor.a = (FRAME_CALC(t->life) + s_mgr.cursor.a) % MAX_CURSOR;
    t->script = true;
    strcpy(t->cb.script, func);
    t->prev = t;
    t->next = t;
    t->args = NULL;
    t->manual = true;
    t->alive = true;
    t->bucket = schedule(t);
    ++s_mgr.timer_total;
    ++s_mgr.timer_remain;
    return t->id;
}

const oid_t &timer_add(time64_t life, callback func, void *args, bool manual)
{
    if (life < 0 || life >= MAX_LIFE) {
        LOG_WARN("timer",
                "Timer added FAILED: invalid timer life(%lld) [0, %lld).",
                life, MAX_LIFE);
        return OID_NIL;
    }
    if (life == 0) {
        func(args);
        E_FREE(args);
        return OID_NIL;
    }

    timer_t *t = E_NEW timer_t;

    memset(t, 0, sizeof(*t));
    t->id = oid_gen();
    t->life = std::max(life, s_mgr.interval);
    t->cursor.a = (FRAME_CALC(t->life) + s_mgr.cursor.a) % MAX_CURSOR;
    t->script = false;
    t->cb.func = func;
    t->prev = t;
    t->next = t;
    t->args = args;
    t->manual = manual;
    t->alive = true;
    t->bucket = schedule(t);
    ++s_mgr.timer_total;
    ++s_mgr.timer_remain;
    s_timers[t->id] = t;
    return t->id;
}

void timer_cycle(callback func)
{
    s_handlers.push_back(func);
}

void timer_remove(const oid_t &tid)
{
    timer_map::iterator itr = s_timers.find(tid);
    if (itr != s_timers.end()) {
        timer_t *t = itr->second;
        t->alive = false;
    }
}

static void _timer_add(timer_t *head, timer_t *t)
{
    head->next->prev = t;
    t->next = head->next;
    t->prev = head;
    head->next = t;
}

static void _timer_del(timer_t *t)
{
    t->prev->next = t->next;
    t->next->prev = t->prev;
}

static void _timer_remove(timer_t *t)
{
    if (t == NULL) {
        return;
    }
    if (t) {
        s_timers.erase(t->id);

        destroy(t);
        ++s_mgr.timer_cancelled;
        --s_mgr.timer_remain;
    }
}

void timer_pause(void)
{
    if (!s_mgr.pause) {
        s_mgr.pause = true;
    }
}

void timer_resume(void)
{
    if (s_mgr.pause) {
        s_mgr.pause = false;
        reset();
    }
}

void timer_pause(const oid_t &tid)
{
}

void timer_resume(const oid_t &tid)
{
}

void timer_interval(time64_t t)
{
    ELF_ASSERT(t >= TIMER_FRAME_INTERVAL_MIN && t <= TIMER_FRAME_INTERVAL_MAX);
    s_mgr.interval = t;
    reset();
}

void timer_bucket(unsigned char no, int l)
{
    switch (l) {
        case 0:
            s_mgr.cursor.w.w0 = no;
            break;
        case 1:
            s_mgr.cursor.w.w1 = no;
            break;
        case 2:
            s_mgr.cursor.w.w2 = no;
            break;
        case 3:
            s_mgr.cursor.w.w3 = no;
            break;
    }
    reset();
}

static void reset(void)
{
    s_mgr.last_time = time_ms();
    s_mgr.last_cursor = s_mgr.cursor.a;
}

static void push(timer_t *t, int bucket)
{
    timer_t *head = s_mgr.timers[bucket];

    if (head == NULL) {
        s_mgr.timers[bucket] = t;
    } else {
        _timer_add(head, t);
    }
}

static void destroy(timer_t *t)
{
    if (t) {
        if (!t->manual) {
            E_FREE(t->args);
        }
        S_DELETE(t);
    }
}

static int schedule(timer_t *t)
{
    int frame = FRAME_DIFFER(t->cursor.a, s_mgr.cursor.a);
    int bucket = 0;

    if (frame < WHEEL_SET_SIZE0) { // hash into wheel 0
        bucket = BUCKET_MAP(t->cursor, 0);
    } else if (WHEEL_CMP(t->cursor, 3)) { // hash into wheel 3
        bucket = BUCKET_MAP(t->cursor, 3);
    } else if (WHEEL_CMP(t->cursor, 2)) { // hash into wheel 2
        bucket = BUCKET_MAP(t->cursor, 2);
    } else if (WHEEL_CMP(t->cursor, 1)) { // hash into wheel 1
        bucket = BUCKET_MAP(t->cursor, 1);
    }
    push(t, bucket);
    return bucket;
}

static void expire(timer_t *t)
{
    ELF_ASSERT(t);
    if (t->script) {
        // script_func_exec(t->cb.script, 0);
    } else {
        t->cb.func(t->args);
    }
    destroy(t);
}

static void bingo(void)
{
    int bucket = 0;
    cursor_t next_cursor = s_mgr.cursor;

    ++next_cursor.a;
    if (WHEEL_CMP(next_cursor, 3)) {
        bucket = BUCKET_MAP(next_cursor, 3);
        LOG_WARN("timer", "WHEEL 3 <%d>.",
                next_cursor.a);
    } else if (WHEEL_CMP(next_cursor, 2)) {
        bucket = BUCKET_MAP(next_cursor, 2);
    } else if (WHEEL_CMP(next_cursor, 1)) {
        bucket = BUCKET_MAP(next_cursor, 1);
    }
    if (++s_mgr.cursor.a == 0) {
        ++s_mgr.round;
    }
    if (bucket > 0) { // hash to more precisely wheel
        hash(bucket);
    }
}

static void hash(int bucket)
{
    timer_t head;
    head.prev = &head;
    head.next = &head;
    _timer_add(&head, s_mgr.timers[bucket]);
    s_mgr.timers[bucket] = NULL;
    for (timer_t *t = head.next;t != &head; t = t->next) {
        timer_t *curr = t;
        _timer_del(curr);
        schedule(curr);
    }
}

static bool timer_min(void *args)
{
    time_t cur = time_s();
    time64_t tm_timer;
    struct tm tm_cur;

    localtime_r(&cur, &tm_cur);
    tm_timer = (60 - tm_cur.tm_sec) * 1000llu;
    timer_add(tm_timer, timer_min, NULL, true);

    handler_list::const_iterator itr = s_handlers.begin();

    for (; itr != s_handlers.end(); ++itr) {
        (*itr)(&cur);
    }
    return true;
}
} // namespace elf

<commit_msg>[MOD] timer<commit_after>/*
 * Copyright (C) 2011-2013 Yule Fox. All rights reserved.
 * http://www.yulefox.com/
 */

#include <elf/log.h>
#include <elf/memory.h>
#include <elf/time.h>
#include <elf/timer.h>
#include <algorithm>
#include <list>
#include <map>

namespace elf {
#define WHEEL_SET_BIT0                  8
#define WHEEL_SET_BITS                  (WHEEL_SET_BIT0 * 4)
#define WHEEL_SET_BIT(l)                (WHEEL_SET_BIT0 * (l))
#define WHEEL_SET_SIZE0                 (1 << WHEEL_SET_BIT0)
#define WHEEL_SET_SIZE(l)               WHEEL_SET_SIZE0
#define MAX_WHEEL_SET_SIZE              (WHEEL_SET_SIZE0 * 4)
#define MAX_CURSOR                      (1LL << WHEEL_SET_BITS)
#define MAX_LIFE                        (MAX_CURSOR * s_mgr.interval)
#define FRAME_DIFFER(l, r)              (int)(l - r)

union cursor_t {
    struct wheel_t {
        unsigned char w0;
        unsigned char w1;
        unsigned char w2;
        unsigned char w3;
    };
    wheel_t w;
    int a;
};

struct timer_t {
    oid_t id; // identification
    time64_t life; // life from now
    cursor_t cursor; // expired frame
    bool script;
    union cb_t {
        char script[1024]; // script function name
        callback func; // callback function
    };
    cb_t cb; // callback function
    void *args; // callback arguments
    timer_t *next; // the next node of the tail node is NULL
    timer_t *prev; // the previous node of the head node is the tail
    int bucket;
    bool manual; // manual destroy args
    bool alive;
};

struct mgr_t {
    time64_t start_time; // start time
    time64_t end_time; // end time
    time64_t cur_time; // current frame time
    time64_t last_time; // last pause time
    time64_t interval; // frame interval time
    cursor_t cursor; // current cursor (number of escaped frames)
    int round; // current round
    int last_cursor; // last pause cursor
    int timer_total; // total number of timers
    int timer_remain; // remain timers
    int timer_passed; // total number of passed timers
    int timer_cancelled; // total number of cancelled timers
    bool pause; // suspend all timers
    timer_t *timers[MAX_WHEEL_SET_SIZE];
};

typedef std::list<callback> handler_list;
typedef std::map<oid_t, timer_t*> timer_map;

static handler_list s_handlers;

static const time64_t TIMER_FRAME_INTERVAL_DEFAULT = 50; // (ms)
static const time64_t TIMER_FRAME_INTERVAL_MIN = 1; // (frame)
static const time64_t TIMER_FRAME_INTERVAL_MAX = 1000; // (frame)
static mgr_t s_mgr;
static timer_map s_timers;

/// calculate the number of life frames
#define FRAME_CALC(t) ((time64_t)(t) / s_mgr.interval)

// @{
/// get current bucket cursor at wheel 0
#define CURRENT_WHEEL_CURSOR    s_mgr.cursor.w.w0

/// compare given cursor with current bucket cursor at wheel @param l
#define WHEEL_CMP(cur, l)                                                   \
    ((int)cur.w.w##l - (int)s_mgr.cursor.w.w##l)

/// map cursor at wheel @param l
#define BUCKET_MAP(cur, l)                                                  \
    (cur.w.w##l + WHEEL_SET_SIZE0 * l)

/// calculate the number of frames elapsed from last cursor
#define FRAME_BINGO (s_mgr.last_cursor +                                    \
        FRAME_CALC(s_mgr.cur_time - s_mgr.last_time) - s_mgr.cursor.a)
// @}

static void reset(void);
static void push(timer_t *t, int bucket);
static void destroy(timer_t *t);
static int schedule(timer_t *t);
static void expire(timer_t *t);
static void bingo(void);
static void hash(int bucket);
static bool timer_min(void *args);
static void _timer_add(timer_t *head, timer_t *t);
static void _timer_del(timer_t *t);
static void _timer_remove(timer_t *t);

int timer_init(void)
{
    MODULE_IMPORT_SWITCH;
    s_mgr.interval = TIMER_FRAME_INTERVAL_DEFAULT;
    s_mgr.start_time = s_mgr.last_time = time_ms();
    s_mgr.pause = true;
    s_mgr.cursor.a = 0;
    s_mgr.round = 0;
    memset(s_mgr.timers, 0, sizeof(s_mgr.timers[0]) * MAX_WHEEL_SET_SIZE);

    time_t ms = time_ms() % 1000;
    time_t cur = time_s();
    time64_t tm_timer;
    struct tm tm_cur;

    localtime_r(&cur, &tm_cur);
    tm_timer = (60 - tm_cur.tm_sec) * 1000llu - ms;

    timer_add(tm_timer, timer_min, NULL, true);
    return 0;
}

int timer_fini(void)
{
    MODULE_IMPORT_SWITCH;
    s_mgr.end_time = time_ms();
    for (int i = 0; i < MAX_WHEEL_SET_SIZE; ++i) {
        timer_t *head = s_mgr.timers[i];
        timer_t *t = head;

        while (t) {
            timer_t *n = t->next;

            destroy(t);
            if (n == head) break;
            t = n;
        }
    }
    return 0;
}

void timer_run(void)
{
    if (s_mgr.pause || s_mgr.timer_remain <= 0) {
        return;
    }

    // frame may greater than 1 while CPU busying
    s_mgr.cur_time = time_ms();
    int frame = FRAME_BINGO;

    // time anomaly
    if (frame < 0) {
        LOG_WARN("timer", "(%u)%08X: %llu - %llu(%d).",
                s_mgr.round, s_mgr.cursor.a,
                s_mgr.cur_time, s_mgr.last_time,
                frame);
        assert(frame >= 0);
        return;
    }
    // while processors is busy
    if (frame > 5) {
        LOG_WARN("timer", "(%u)%08X: %llu - %llu(%d).",
                s_mgr.round, s_mgr.cursor.a,
                s_mgr.cur_time, s_mgr.last_time,
                frame);
    }
    for (int i = 1; i <= frame; ++i) { // BINGO!
        unsigned char bucket = CURRENT_WHEEL_CURSOR;

        timer_t *head = s_mgr.timers[bucket];
        timer_t *t = head;
        while (t) { // expire all timers
            _timer_del(t);
            if (!t->alive) {
                _timer_remove(t);
                continue;
            }
            expire(t);
            ++s_mgr.timer_passed;
            --s_mgr.timer_remain;

            if (t->next == t) {
                s_mgr.timers[bucket] = NULL;
                break;
            }
            t = t->next;
        }
        bingo();
    }
}

void timer_stat(void)
{
    LOG_INFO("timer",
            "ST: %lld RND: %u FRM: %u TMT: %u TMP: %u TMC: %u.",
            s_mgr.start_time, s_mgr.round, s_mgr.cursor.a,
            s_mgr.timer_total, s_mgr.timer_passed, s_mgr.timer_cancelled);
}

int timer_size(void)
{
    return s_mgr.timer_remain;
}

const oid_t &timer_add(time64_t life, const char *func)
{
    if (life < 0 || life >= MAX_LIFE) {
        LOG_WARN("timer",
                "Timer added FAILED: invalid timer life(%lld) [0, %lld).",
                life, MAX_LIFE);
        return OID_NIL;
    }

    timer_t *t = E_NEW timer_t;

    memset(t, 0, sizeof(*t));
    t->id = oid_gen();
    t->life = std::max(life, s_mgr.interval);
    t->cursor.a = (FRAME_CALC(t->life) + s_mgr.cursor.a) % MAX_CURSOR;
    t->script = true;
    strcpy(t->cb.script, func);
    t->prev = t;
    t->next = t;
    t->args = NULL;
    t->manual = true;
    t->alive = true;
    t->bucket = schedule(t);
    ++s_mgr.timer_total;
    ++s_mgr.timer_remain;
    return t->id;
}

const oid_t &timer_add(time64_t life, callback func, void *args, bool manual)
{
    if (life < 0 || life >= MAX_LIFE) {
        LOG_WARN("timer",
                "Timer added FAILED: invalid timer life(%lld) [0, %lld).",
                life, MAX_LIFE);
        return OID_NIL;
    }
    if (life == 0) {
        func(args);
        E_FREE(args);
        return OID_NIL;
    }

    timer_t *t = E_NEW timer_t;

    memset(t, 0, sizeof(*t));
    t->id = oid_gen();
    t->life = std::max(life, s_mgr.interval);
    t->cursor.a = (FRAME_CALC(t->life) + s_mgr.cursor.a) % MAX_CURSOR;
    t->script = false;
    t->cb.func = func;
    t->prev = t;
    t->next = t;
    t->args = args;
    t->manual = manual;
    t->alive = true;
    t->bucket = schedule(t);
    ++s_mgr.timer_total;
    ++s_mgr.timer_remain;
    s_timers[t->id] = t;
    return t->id;
}

void timer_cycle(callback func)
{
    s_handlers.push_back(func);
}

void timer_remove(const oid_t &tid)
{
    timer_map::iterator itr = s_timers.find(tid);
    if (itr != s_timers.end()) {
        timer_t *t = itr->second;
        t->alive = false;
    }
}

static void _timer_add(timer_t *head, timer_t *t)
{
    head->next->prev = t;
    t->next = head->next;
    t->prev = head;
    head->next = t;
}

static void _timer_del(timer_t *t)
{
    t->prev->next = t->next;
    t->next->prev = t->prev;
}

static void _timer_remove(timer_t *t)
{
    if (t == NULL) {
        return;
    }
    if (t) {
        s_timers.erase(t->id);

        destroy(t);
        ++s_mgr.timer_cancelled;
        --s_mgr.timer_remain;
    }
}

void timer_pause(void)
{
    if (!s_mgr.pause) {
        s_mgr.pause = true;
    }
}

void timer_resume(void)
{
    if (s_mgr.pause) {
        s_mgr.pause = false;
        reset();
    }
}

void timer_pause(const oid_t &tid)
{
}

void timer_resume(const oid_t &tid)
{
}

void timer_interval(time64_t t)
{
    ELF_ASSERT(t >= TIMER_FRAME_INTERVAL_MIN && t <= TIMER_FRAME_INTERVAL_MAX);
    s_mgr.interval = t;
    reset();
}

void timer_bucket(unsigned char no, int l)
{
    switch (l) {
        case 0:
            s_mgr.cursor.w.w0 = no;
            break;
        case 1:
            s_mgr.cursor.w.w1 = no;
            break;
        case 2:
            s_mgr.cursor.w.w2 = no;
            break;
        case 3:
            s_mgr.cursor.w.w3 = no;
            break;
    }
    reset();
}

static void reset(void)
{
    s_mgr.last_time = time_ms();
    s_mgr.last_cursor = s_mgr.cursor.a;
}

static void push(timer_t *t, int bucket)
{
    timer_t *head = s_mgr.timers[bucket];

    if (head == NULL) {
        s_mgr.timers[bucket] = t;
    } else {
        _timer_add(head, t);
    }
}

static void destroy(timer_t *t)
{
    if (t) {
        if (!t->manual) {
            E_FREE(t->args);
        }
        S_DELETE(t);
    }
}

static int schedule(timer_t *t)
{
    int frame = FRAME_DIFFER(t->cursor.a, s_mgr.cursor.a);
    int bucket = 0;

    if (frame < WHEEL_SET_SIZE0) { // hash into wheel 0
        bucket = BUCKET_MAP(t->cursor, 0);
    } else if (WHEEL_CMP(t->cursor, 3)) { // hash into wheel 3
        bucket = BUCKET_MAP(t->cursor, 3);
    } else if (WHEEL_CMP(t->cursor, 2)) { // hash into wheel 2
        bucket = BUCKET_MAP(t->cursor, 2);
    } else if (WHEEL_CMP(t->cursor, 1)) { // hash into wheel 1
        bucket = BUCKET_MAP(t->cursor, 1);
    }
    push(t, bucket);
    return bucket;
}

static void expire(timer_t *t)
{
    ELF_ASSERT(t);
    if (t->script) {
        // script_func_exec(t->cb.script, 0);
    } else {
        t->cb.func(t->args);
    }
    destroy(t);
}

static void bingo(void)
{
    int bucket = 0;
    cursor_t next_cursor = s_mgr.cursor;

    ++next_cursor.a;
    if (WHEEL_CMP(next_cursor, 3)) {
        bucket = BUCKET_MAP(next_cursor, 3);
        LOG_WARN("timer", "WHEEL 3 <%d>.",
                next_cursor.a);
    } else if (WHEEL_CMP(next_cursor, 2)) {
        bucket = BUCKET_MAP(next_cursor, 2);
    } else if (WHEEL_CMP(next_cursor, 1)) {
        bucket = BUCKET_MAP(next_cursor, 1);
    }
    if (++s_mgr.cursor.a == 0) {
        ++s_mgr.round;
    }
    if (bucket > 0) { // hash to more precisely wheel
        hash(bucket);
    }
}

static void hash(int bucket)
{
    timer_t head;
    head.prev = &head;
    head.next = &head;
    _timer_add(&head, s_mgr.timers[bucket]);
    s_mgr.timers[bucket] = NULL;
    for (timer_t *t = head.next;t != &head; t = t->next) {
        timer_t *curr = t;
        _timer_del(curr);
        schedule(curr);
    }
}

static bool timer_min(void *args)
{
    time_t cur = time_s();
    time64_t tm_timer;
    struct tm tm_cur;

    localtime_r(&cur, &tm_cur);
    tm_timer = (60 - tm_cur.tm_sec) * 1000llu;
    timer_add(tm_timer, timer_min, NULL, true);

    handler_list::const_iterator itr = s_handlers.begin();

    for (; itr != s_handlers.end(); ++itr) {
        (*itr)(&cur);
    }
    return true;
}
} // namespace elf

<|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 Library 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.
 *
 * DynamicPluginLoader.cpp
 * This class is responsible for loading and unloading the plugins
 * Copyright (C) 2005-2009 Simon Newton
 */

#if HAVE_CONFIG_H
#  include <config.h>
#endif

#include <vector>
#include "olad/Plugin.h"
#include "olad/DynamicPluginLoader.h"

#include "plugins/dummy/DummyPlugin.h"
#include "plugins/e131/E131Plugin.h"
#include "plugins/espnet/EspNetPlugin.h"
#include "plugins/opendmx/OpenDmxPlugin.h"
#include "plugins/pathport/PathportPlugin.h"
#include "plugins/sandnet/SandNetPlugin.h"
#include "plugins/shownet/ShowNetPlugin.h"
#include "plugins/stageprofi/StageProfiPlugin.h"
#include "plugins/usbpro/UsbProPlugin.h"

#ifdef HAVE_LIBUSB
#include "plugins/usbdmx/UsbDmxPlugin.h"
#endif

#ifdef HAVE_ARTNET
#include "plugins/artnet/ArtNetPlugin.h"
#endif

#ifdef HAVE_DMX4LINUX
#include "plugins/dmx4linux/Dmx4LinuxPlugin.h"
#endif

namespace ola {

using std::vector;

/*
 * Load the plugins that we were linked against
 * @returns a vector of plugins
 */
vector<AbstractPlugin*> DynamicPluginLoader::LoadPlugins() {
  vector<AbstractPlugin*> plugins;

#ifdef HAVE_ARTNET
  plugins.push_back(new ola::plugin::artnet::ArtNetPlugin(m_plugin_adaptor));
#endif

#ifdef HAVE_DMX4LINUX
  plugins.push_back(
      new ola::plugin::dmx4linux::Dmx4LinuxPlugin(m_plugin_adaptor));
#endif

  plugins.push_back(new ola::plugin::dummy::DummyPlugin(m_plugin_adaptor));
  plugins.push_back(new ola::plugin::e131::E131Plugin(m_plugin_adaptor));
  plugins.push_back(new ola::plugin::espnet::EspNetPlugin(m_plugin_adaptor));
  plugins.push_back(
      new ola::plugin::opendmx::OpenDmxPlugin(m_plugin_adaptor));
  plugins.push_back(
      new ola::plugin::sandnet::SandNetPlugin(m_plugin_adaptor));
  plugins.push_back(
      new ola::plugin::shownet::ShowNetPlugin(m_plugin_adaptor));
  plugins.push_back(
      new ola::plugin::stageprofi::StageProfiPlugin(m_plugin_adaptor));
  plugins.push_back(new ola::plugin::usbpro::UsbProPlugin(m_plugin_adaptor));
  plugins.push_back(new ola::plugin::usbdmx::UsbDmxPlugin(m_plugin_adaptor));
  plugins.push_back(
      new ola::plugin::pathport::PathportPlugin(m_plugin_adaptor));
  return plugins;
}
}  // ola
<commit_msg> * fix a stupid build error<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 Library 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.
 *
 * DynamicPluginLoader.cpp
 * This class is responsible for loading and unloading the plugins
 * Copyright (C) 2005-2009 Simon Newton
 */

#if HAVE_CONFIG_H
#  include <config.h>
#endif

#include <vector>
#include "olad/Plugin.h"
#include "olad/DynamicPluginLoader.h"

#include "plugins/dummy/DummyPlugin.h"
#include "plugins/e131/E131Plugin.h"
#include "plugins/espnet/EspNetPlugin.h"
#include "plugins/opendmx/OpenDmxPlugin.h"
#include "plugins/pathport/PathportPlugin.h"
#include "plugins/sandnet/SandNetPlugin.h"
#include "plugins/shownet/ShowNetPlugin.h"
#include "plugins/stageprofi/StageProfiPlugin.h"
#include "plugins/usbpro/UsbProPlugin.h"

#ifdef HAVE_LIBUSB
#include "plugins/usbdmx/UsbDmxPlugin.h"
#endif

#ifdef HAVE_ARTNET
#include "plugins/artnet/ArtNetPlugin.h"
#endif

#ifdef HAVE_DMX4LINUX
#include "plugins/dmx4linux/Dmx4LinuxPlugin.h"
#endif

namespace ola {

using std::vector;

/*
 * Load the plugins that we were linked against
 * @returns a vector of plugins
 */
vector<AbstractPlugin*> DynamicPluginLoader::LoadPlugins() {
  vector<AbstractPlugin*> plugins;

#ifdef HAVE_ARTNET
  plugins.push_back(new ola::plugin::artnet::ArtNetPlugin(m_plugin_adaptor));
#endif

#ifdef HAVE_DMX4LINUX
  plugins.push_back(
      new ola::plugin::dmx4linux::Dmx4LinuxPlugin(m_plugin_adaptor));
#endif

  plugins.push_back(new ola::plugin::dummy::DummyPlugin(m_plugin_adaptor));
  plugins.push_back(new ola::plugin::e131::E131Plugin(m_plugin_adaptor));
  plugins.push_back(new ola::plugin::espnet::EspNetPlugin(m_plugin_adaptor));
  plugins.push_back(
      new ola::plugin::opendmx::OpenDmxPlugin(m_plugin_adaptor));
  plugins.push_back(
      new ola::plugin::sandnet::SandNetPlugin(m_plugin_adaptor));
  plugins.push_back(
      new ola::plugin::shownet::ShowNetPlugin(m_plugin_adaptor));
  plugins.push_back(
      new ola::plugin::stageprofi::StageProfiPlugin(m_plugin_adaptor));
  plugins.push_back(new ola::plugin::usbpro::UsbProPlugin(m_plugin_adaptor));
#ifdef HAVE_LIBUSB
  plugins.push_back(new ola::plugin::usbdmx::UsbDmxPlugin(m_plugin_adaptor));
#endif
  plugins.push_back(
      new ola::plugin::pathport::PathportPlugin(m_plugin_adaptor));
  return plugins;
}
}  // ola
<|endoftext|>