<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2008, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "IECoreMaya/FromMayaShapeConverter.h"
#include "IECoreMaya/FromMayaPlugConverter.h"

#include "IECore/CompoundParameter.h"
#include "IECore/Primitive.h"
#include "IECore/MessageHandler.h"
#include "IECore/DespatchTypedData.h"

#include "maya/MFnDependencyNode.h"
#include "maya/MFnAttribute.h"

using namespace IECoreMaya;

FromMayaShapeConverter::FromMayaShapeConverter( const std::string &name, const std::string &description, const MObject &object )
	:	FromMayaObjectConverter( name, description, object )
{
	constructCommon();
}

FromMayaShapeConverter::FromMayaShapeConverter( const std::string &name, const std::string &description, const MDagPath &dagPath )
	:	FromMayaObjectConverter( name, description, dagPath.node() ), m_dagPath( dagPath )
{
	constructCommon();
}

void FromMayaShapeConverter::constructCommon()
{

	IECore::IntParameter::PresetsMap spacePresets;
	spacePresets["Object"] = Object;
	spacePresets["World"] = World;
	m_spaceParameter = new IECore::IntParameter(
		"space",
		"The space in which the object is exported.",
		Object,
		Object,
		World,
		spacePresets,
		true
	);

	IECore::StringParameter::PresetsMap primVarAttrPrefixPresets;
	primVarAttrPrefixPresets["MTOR"] = "rman";
	primVarAttrPrefixPresets["3Delight"] = "delight";
	primVarAttrPrefixPresets["None"] = "";
	m_primVarAttrPrefixParameter = new IECore::StringParameter(
		"primVarAttrPrefix",
		"Any attribute names beginning with this prefix are considered to represent primitive variables and are converted as such."
		"The interpolation type of the variable is guessed, unless the attribute name begins with prefix_?_, in which case the ? is"
		"used to specify type - C for constant, U for uniform, V for Vertex, Y for varying and F for facevarying",
		"delight", // compatibility with 3delight by default
		primVarAttrPrefixPresets
	);

	parameters()->addParameter( m_spaceParameter );
	parameters()->addParameter( m_primVarAttrPrefixParameter );

}

IECore::IntParameterPtr FromMayaShapeConverter::spaceParameter()
{
	return m_spaceParameter;
}

IECore::ConstIntParameterPtr FromMayaShapeConverter::spaceParameter() const
{
	return m_spaceParameter;
}

IECore::StringParameterPtr FromMayaShapeConverter::primVarAttrPrefixParameter()
{
	return m_primVarAttrPrefixParameter;
}

IECore::ConstStringParameterPtr FromMayaShapeConverter::primVarAttrPrefixParameter() const
{
	return m_primVarAttrPrefixParameter;
}

IECore::ObjectPtr FromMayaShapeConverter::doConversion( const MObject &object, IECore::ConstCompoundObjectPtr operands ) const
{
	IECore::PrimitivePtr p = 0;

	/// \todo Surely here we should only be specifying "true" for argument "emitSpaceWarnings" if we're not converting from some DG data?
	const MDagPath *d = dagPath( true );
	if( d )
	{
		p = doPrimitiveConversion( *d, operands );
	}
	else
	{
		p = doPrimitiveConversion( object, operands );
	}
	if( p )
	{
		addPrimVars( object, p );
	}
	return p;
}

void FromMayaShapeConverter::addPrimVars( const MObject &object, IECore::PrimitivePtr primitive ) const
{
	MFnDependencyNode fnNode( object );
	if( !fnNode.hasObj( object ) )
	{
		return;
	}

	MString prefix = m_primVarAttrPrefixParameter->getTypedValue().c_str();
	unsigned int n = fnNode.attributeCount();
	for( unsigned int i=0; i<n; i++ )
	{
		MObject attr = fnNode.attribute( i );
		MFnAttribute fnAttr( attr );
		MString attrName = fnAttr.name();
		if( attrName.substring( 0, prefix.length()-1 )==prefix && attrName.length() > prefix.length() )
		{
			MPlug plug = fnNode.findPlug( attr );
			if( !plug.parent().isNull() )
			{
				continue; // we don't want to pick up the children of compound numeric attributes
			}
			MString plugName = plug.name();

			// find a converter for the plug, asking for conversion to float types by preference
			FromMayaConverterPtr converter = FromMayaPlugConverter::create( plug, IECore::FloatDataTypeId );
			if( !converter )
			{
				converter = FromMayaPlugConverter::create( plug, IECore::V3fDataTypeId );
			}
			if( !converter )
			{
				converter = FromMayaPlugConverter::create( plug, IECore::V3fVectorDataTypeId );
			}
			if( !converter )
			{
				converter = FromMayaPlugConverter::create( plug, IECore::FloatVectorDataTypeId );
			}
			if( !converter )
			{
				converter = FromMayaPlugConverter::create( plug );
			}

			// run the conversion and check we've got data as a result
			IECore::DataPtr data = 0;
			if( converter )
			{
				 data = IECore::runTimeCast<IECore::Data>( converter->convert() );
			}
			if( !data )
			{
				IECore::msg( IECore::Msg::Warning, "FromMayaShapeConverter::addPrimVars", boost::format( "Attribute \"%s\" could not be converted to Data." ) % plugName.asChar() );
				continue;
			}

			// convert V3fData to Color3fData if attribute has usedAsColor() set.
			if( IECore::V3fDataPtr vData = IECore::runTimeCast<IECore::V3fData>( data ) )
			{
				if( fnAttr.isUsedAsColor() )
				{
					Imath::V3f v = vData->readable();
					data = new IECore::Color3fData( Imath::Color3f( v.x, v.y, v.z ) );
				}
			}

			// see if interpolation has been specified, and find primitive variable name
			std::string primVarName = attrName.asChar() + prefix.length();
			IECore::PrimitiveVariable::Interpolation interpolation = IECore::PrimitiveVariable::Invalid;
			if( attrName.length()>prefix.length()+3 )
			{
				const char *c = attrName.asChar();
				if( c[prefix.length()]=='_' && c[prefix.length()+2]=='_' )
				{
					char t = c[prefix.length()+1];
					primVarName = attrName.asChar() + prefix.length() + 3;
					switch( t )
					{
						case 'C' :
							interpolation = IECore::PrimitiveVariable::Constant;
							break;
						case 'U' :
							interpolation = IECore::PrimitiveVariable::Uniform;
							break;
						case 'V' :
							interpolation = IECore::PrimitiveVariable::Vertex;
							break;
						case 'Y' :
							interpolation = IECore::PrimitiveVariable::Varying;
							break;
						case 'F' :
							interpolation = IECore::PrimitiveVariable::FaceVarying;
							break;
						default :
							IECore::msg( IECore::Msg::Warning, "FromMayaShapeConverter::addPrimVars", boost::format( "Attribute \"%s\" has unknown interpolation - guessing interpolation." ) % plugName.asChar() );
							break;
					}
				}
			}

			// guess interpolation if not specified
			if( interpolation==IECore::PrimitiveVariable::Invalid )
			{
				interpolation = primitive->inferInterpolation( data );
			}

			if( interpolation==IECore::PrimitiveVariable::Invalid )
			{
				IECore::msg( IECore::Msg::Warning, "FromMayaShapeConverter::addPrimVars", boost::format( "Attribute \"%s\" has unsuitable size." ) % plugName.asChar() );
				continue;
			}

			// finally add the primvar
			primitive->variables[primVarName] = IECore::PrimitiveVariable( interpolation, data );

		}
	}

}

MSpace::Space FromMayaShapeConverter::space() const
{
	Space s = (Space)m_spaceParameter->getNumericValue();
	switch( s )
	{
		case Object :
			return MSpace::kObject;
		case World :
			return MSpace::kWorld;
	}
	assert( 0 ); // should never get here
	return MSpace::kObject;
}

const MDagPath *FromMayaShapeConverter::dagPath( bool emitSpaceWarnings ) const
{
	if( m_dagPath.isValid() )
	{
		return &m_dagPath;
	}

	if( emitSpaceWarnings && space()==MSpace::kWorld )
	{
		IECore::msg( IECore::Msg::Warning, "FromMayaShapeConverter", "World space requested but no dag path provided." );
	}

	return 0;
}

FromMayaShapeConverterPtr FromMayaShapeConverter::create( const MDagPath &dagPath, IECore::TypeId resultType )
{
	const ShapeTypesToFnsMap *m = shapeTypesToFns();
	ShapeTypesToFnsMap::const_iterator it = m->find( ShapeTypes( dagPath.apiType(), resultType ) );
	if( it!=m->end() )
	{
		return it->second( dagPath );
	}
	return 0;
}

void FromMayaShapeConverter::registerShapeConverter( const MFn::Type fromType, IECore::TypeId resultType, ShapeCreatorFn creator )
{
	ShapeTypesToFnsMap *m = shapeTypesToFns();
	m->insert( ShapeTypesToFnsMap::value_type( ShapeTypes( fromType, resultType ), creator ) );
	m->insert( ShapeTypesToFnsMap::value_type( ShapeTypes( fromType, IECore::InvalidTypeId ), creator ) ); // for the create function which doesn't care about resultType
}

FromMayaShapeConverter::ShapeTypesToFnsMap *FromMayaShapeConverter::shapeTypesToFns()
{
	static ShapeTypesToFnsMap *m = new ShapeTypesToFnsMap;
	return m;
}

<commit_msg>Suppressed space warnings for DG data<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2008, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "IECoreMaya/FromMayaShapeConverter.h"
#include "IECoreMaya/FromMayaPlugConverter.h"

#include "IECore/CompoundParameter.h"
#include "IECore/Primitive.h"
#include "IECore/MessageHandler.h"
#include "IECore/DespatchTypedData.h"

#include "maya/MFnDependencyNode.h"
#include "maya/MFnAttribute.h"

using namespace IECoreMaya;

FromMayaShapeConverter::FromMayaShapeConverter( const std::string &name, const std::string &description, const MObject &object )
	:	FromMayaObjectConverter( name, description, object )
{
	constructCommon();
}

FromMayaShapeConverter::FromMayaShapeConverter( const std::string &name, const std::string &description, const MDagPath &dagPath )
	:	FromMayaObjectConverter( name, description, dagPath.node() ), m_dagPath( dagPath )
{
	constructCommon();
}

void FromMayaShapeConverter::constructCommon()
{

	IECore::IntParameter::PresetsMap spacePresets;
	spacePresets["Object"] = Object;
	spacePresets["World"] = World;
	m_spaceParameter = new IECore::IntParameter(
		"space",
		"The space in which the object is exported.",
		Object,
		Object,
		World,
		spacePresets,
		true
	);

	IECore::StringParameter::PresetsMap primVarAttrPrefixPresets;
	primVarAttrPrefixPresets["MTOR"] = "rman";
	primVarAttrPrefixPresets["3Delight"] = "delight";
	primVarAttrPrefixPresets["None"] = "";
	m_primVarAttrPrefixParameter = new IECore::StringParameter(
		"primVarAttrPrefix",
		"Any attribute names beginning with this prefix are considered to represent primitive variables and are converted as such."
		"The interpolation type of the variable is guessed, unless the attribute name begins with prefix_?_, in which case the ? is"
		"used to specify type - C for constant, U for uniform, V for Vertex, Y for varying and F for facevarying",
		"delight", // compatibility with 3delight by default
		primVarAttrPrefixPresets
	);

	parameters()->addParameter( m_spaceParameter );
	parameters()->addParameter( m_primVarAttrPrefixParameter );

}

IECore::IntParameterPtr FromMayaShapeConverter::spaceParameter()
{
	return m_spaceParameter;
}

IECore::ConstIntParameterPtr FromMayaShapeConverter::spaceParameter() const
{
	return m_spaceParameter;
}

IECore::StringParameterPtr FromMayaShapeConverter::primVarAttrPrefixParameter()
{
	return m_primVarAttrPrefixParameter;
}

IECore::ConstStringParameterPtr FromMayaShapeConverter::primVarAttrPrefixParameter() const
{
	return m_primVarAttrPrefixParameter;
}

IECore::ObjectPtr FromMayaShapeConverter::doConversion( const MObject &object, IECore::ConstCompoundObjectPtr operands ) const
{
	IECore::PrimitivePtr p = 0;

	const MDagPath *d = dagPath( true );
	if( d )
	{
		p = doPrimitiveConversion( *d, operands );
	}
	else
	{
		p = doPrimitiveConversion( object, operands );
	}
	if( p )
	{
		addPrimVars( object, p );
	}
	return p;
}

void FromMayaShapeConverter::addPrimVars( const MObject &object, IECore::PrimitivePtr primitive ) const
{
	MFnDependencyNode fnNode( object );
	if( !fnNode.hasObj( object ) )
	{
		return;
	}

	MString prefix = m_primVarAttrPrefixParameter->getTypedValue().c_str();
	unsigned int n = fnNode.attributeCount();
	for( unsigned int i=0; i<n; i++ )
	{
		MObject attr = fnNode.attribute( i );
		MFnAttribute fnAttr( attr );
		MString attrName = fnAttr.name();
		if( attrName.substring( 0, prefix.length()-1 )==prefix && attrName.length() > prefix.length() )
		{
			MPlug plug = fnNode.findPlug( attr );
			if( !plug.parent().isNull() )
			{
				continue; // we don't want to pick up the children of compound numeric attributes
			}
			MString plugName = plug.name();

			// find a converter for the plug, asking for conversion to float types by preference
			FromMayaConverterPtr converter = FromMayaPlugConverter::create( plug, IECore::FloatDataTypeId );
			if( !converter )
			{
				converter = FromMayaPlugConverter::create( plug, IECore::V3fDataTypeId );
			}
			if( !converter )
			{
				converter = FromMayaPlugConverter::create( plug, IECore::V3fVectorDataTypeId );
			}
			if( !converter )
			{
				converter = FromMayaPlugConverter::create( plug, IECore::FloatVectorDataTypeId );
			}
			if( !converter )
			{
				converter = FromMayaPlugConverter::create( plug );
			}

			// run the conversion and check we've got data as a result
			IECore::DataPtr data = 0;
			if( converter )
			{
				 data = IECore::runTimeCast<IECore::Data>( converter->convert() );
			}
			if( !data )
			{
				IECore::msg( IECore::Msg::Warning, "FromMayaShapeConverter::addPrimVars", boost::format( "Attribute \"%s\" could not be converted to Data." ) % plugName.asChar() );
				continue;
			}

			// convert V3fData to Color3fData if attribute has usedAsColor() set.
			if( IECore::V3fDataPtr vData = IECore::runTimeCast<IECore::V3fData>( data ) )
			{
				if( fnAttr.isUsedAsColor() )
				{
					Imath::V3f v = vData->readable();
					data = new IECore::Color3fData( Imath::Color3f( v.x, v.y, v.z ) );
				}
			}

			// see if interpolation has been specified, and find primitive variable name
			std::string primVarName = attrName.asChar() + prefix.length();
			IECore::PrimitiveVariable::Interpolation interpolation = IECore::PrimitiveVariable::Invalid;
			if( attrName.length()>prefix.length()+3 )
			{
				const char *c = attrName.asChar();
				if( c[prefix.length()]=='_' && c[prefix.length()+2]=='_' )
				{
					char t = c[prefix.length()+1];
					primVarName = attrName.asChar() + prefix.length() + 3;
					switch( t )
					{
						case 'C' :
							interpolation = IECore::PrimitiveVariable::Constant;
							break;
						case 'U' :
							interpolation = IECore::PrimitiveVariable::Uniform;
							break;
						case 'V' :
							interpolation = IECore::PrimitiveVariable::Vertex;
							break;
						case 'Y' :
							interpolation = IECore::PrimitiveVariable::Varying;
							break;
						case 'F' :
							interpolation = IECore::PrimitiveVariable::FaceVarying;
							break;
						default :
							IECore::msg( IECore::Msg::Warning, "FromMayaShapeConverter::addPrimVars", boost::format( "Attribute \"%s\" has unknown interpolation - guessing interpolation." ) % plugName.asChar() );
							break;
					}
				}
			}

			// guess interpolation if not specified
			if( interpolation==IECore::PrimitiveVariable::Invalid )
			{
				interpolation = primitive->inferInterpolation( data );
			}

			if( interpolation==IECore::PrimitiveVariable::Invalid )
			{
				IECore::msg( IECore::Msg::Warning, "FromMayaShapeConverter::addPrimVars", boost::format( "Attribute \"%s\" has unsuitable size." ) % plugName.asChar() );
				continue;
			}

			// finally add the primvar
			primitive->variables[primVarName] = IECore::PrimitiveVariable( interpolation, data );

		}
	}

}

MSpace::Space FromMayaShapeConverter::space() const
{
	Space s = (Space)m_spaceParameter->getNumericValue();
	switch( s )
	{
		case Object :
			return MSpace::kObject;
		case World :
			return MSpace::kWorld;
	}
	assert( 0 ); // should never get here
	return MSpace::kObject;
}

const MDagPath *FromMayaShapeConverter::dagPath( bool emitSpaceWarnings ) const
{
	if( m_dagPath.isValid() )
	{
		return &m_dagPath;
	}

	if( emitSpaceWarnings && !object().hasFn( MFn::kData ) && space()==MSpace::kWorld )
	{
		IECore::msg( IECore::Msg::Warning, "FromMayaShapeConverter", "World space requested but no dag path provided." );
	}

	return 0;
}

FromMayaShapeConverterPtr FromMayaShapeConverter::create( const MDagPath &dagPath, IECore::TypeId resultType )
{
	const ShapeTypesToFnsMap *m = shapeTypesToFns();
	ShapeTypesToFnsMap::const_iterator it = m->find( ShapeTypes( dagPath.apiType(), resultType ) );
	if( it!=m->end() )
	{
		return it->second( dagPath );
	}
	return 0;
}

void FromMayaShapeConverter::registerShapeConverter( const MFn::Type fromType, IECore::TypeId resultType, ShapeCreatorFn creator )
{
	ShapeTypesToFnsMap *m = shapeTypesToFns();
	m->insert( ShapeTypesToFnsMap::value_type( ShapeTypes( fromType, resultType ), creator ) );
	m->insert( ShapeTypesToFnsMap::value_type( ShapeTypes( fromType, IECore::InvalidTypeId ), creator ) ); // for the create function which doesn't care about resultType
}

FromMayaShapeConverter::ShapeTypesToFnsMap *FromMayaShapeConverter::shapeTypesToFns()
{
	static ShapeTypesToFnsMap *m = new ShapeTypesToFnsMap;
	return m;
}

<|endoftext|>


<commit_before>#include "gtest.h"
#include "proposer.h"

class ProposerTest : public testing::Test {
protected:

	int id;
	int instances;
	struct proposer* p;

	virtual void SetUp() {
		id = 2;
		instances = 100;
		p = proposer_new(id, instances);
	}

	virtual void TearDown() { }
};

TEST_F(ProposerTest, Prepare) {
	prepare_req pr;
	for (int i = 0; i < 10; ++i) {
		pr = proposer_prepare(p);
		ASSERT_EQ(pr.iid, i+1);
		ASSERT_EQ(pr.ballot, id + MAX_N_OF_PROPOSERS);
	}
}

TEST_F(ProposerTest, PrepareAndAccept) {
	prepare_req pr;
	prepare_ack pa;
	accept_req* ar;
	accept_ack aa;

	pr = proposer_prepare(p);

	// aid, iid, bal, val_bal, val_size
	pa = (prepare_ack) {1, pr.iid, pr.ballot, 0, 0};
	proposer_receive_prepare_ack(p, &pa);
	pa = (prepare_ack) {2, pr.iid, pr.ballot, 0, 0};
	proposer_receive_prepare_ack(p, &pa);

	// we have no value to propose!
	ASSERT_EQ(proposer_accept(p), (void*)NULL);

	proposer_propose(p, (char*)"value", 6);
	ar = proposer_accept(p);
	ASSERT_NE(ar, (accept_req*)NULL);
	ASSERT_EQ(ar->iid, pr.iid);
	ASSERT_EQ(ar->ballot, pr.ballot);
	ASSERT_EQ(ar->value_size, 6);
	ASSERT_STREQ(ar->value, "value");

	// aid, iid, bal, val_bal, final, size
	prepare_req* req;
	aa = (accept_ack) {0, ar->iid, ar->ballot, ar->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_accept_ack(p, &aa), (void*)NULL);
	aa = (accept_ack) {1, ar->iid, ar->ballot, ar->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_accept_ack(p, &aa), (void*)NULL);
}

TEST_F(ProposerTest, PreparePreempted) {
	prepare_req pr;
	prepare_ack pa;
	prepare_req* pr_preempt;
	accept_req* ar;
	char value[] = "some value";
	int value_size = strlen(value) + 1;

	pr = proposer_prepare(p);
	proposer_propose(p, value, value_size);

	// preempt! proposer receives a different ballot...
	pa = (prepare_ack) {1, pr.iid, pr.ballot+1, 0, 0};
	pr_preempt = proposer_receive_prepare_ack(p, &pa);
	ASSERT_NE((void*)NULL, pr_preempt);
	ASSERT_EQ(pr_preempt->iid, pr.iid);
	ASSERT_GT(pr_preempt->ballot, pr.ballot);

	pa = (prepare_ack) {0, pr_preempt->iid, pr_preempt->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);
	pa = (prepare_ack) {1, pr_preempt->iid, pr_preempt->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);

	ar = proposer_accept(p);
	ASSERT_NE(ar, (void*)NULL);
	ASSERT_EQ(ar->iid, pr_preempt->iid);
	ASSERT_EQ(ar->ballot, pr_preempt->ballot);
	ASSERT_EQ(ar->value_size, value_size);
	ASSERT_STREQ(ar->value, value);

	free(ar);
	free(pr_preempt);
}

TEST_F(ProposerTest, AcceptPreempted) {
	prepare_req pr;
	prepare_ack pa;
	prepare_req* pr_preempt;
	accept_req* ar;
	accept_ack aa;
	char value[] = "some value";
	int value_size = strlen(value) + 1;

	pr = proposer_prepare(p);
	proposer_propose(p, value, value_size);

	pa = (prepare_ack) {0, pr.iid, pr.ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);
	pa = (prepare_ack) {1, pr.iid, pr.ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);

	ar = proposer_accept(p);
	ASSERT_NE(ar, (void*)NULL);

	// preempt! proposer receives accept nack
	aa = (accept_ack) {0, ar->iid, ar->ballot+1, 0, 0, 0};
	pr_preempt = proposer_receive_accept_ack(p, &aa);
	ASSERT_NE((void*)NULL, pr_preempt);
	ASSERT_EQ(pr_preempt->iid, pr.iid);
	ASSERT_GT(pr_preempt->ballot, ar->ballot);
	free(ar);

	// finally acquire the instance
	pa = (prepare_ack) {0, pr_preempt->iid, pr_preempt->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);
	pa = (prepare_ack) {1, pr_preempt->iid, pr_preempt->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);

	// accept again
	ar = proposer_accept(p);
	ASSERT_NE(ar, (void*)NULL);
	ASSERT_EQ(pr_preempt->iid, ar->iid);
	ASSERT_EQ(pr_preempt->ballot, ar->ballot);
	ASSERT_EQ(value_size, ar->value_size);
	ASSERT_STREQ(value, ar->value);

	aa = (accept_ack) {0, ar->iid, ar->ballot, ar->ballot, 0, value_size};
	ASSERT_EQ(proposer_receive_accept_ack(p, &aa), (void*)NULL);
	aa = (accept_ack) {1, ar->iid, ar->ballot, ar->ballot, 0, value_size};
	ASSERT_EQ(proposer_receive_accept_ack(p, &aa), (void*)NULL);

	free(ar);
	free(pr_preempt);
}
<commit_msg>Adds test for proposer_proposed_count() in ProposerTest.<commit_after>#include "gtest.h"
#include "proposer.h"

class ProposerTest : public testing::Test {
protected:

	int id;
	int instances;
	struct proposer* p;

	virtual void SetUp() {
		id = 2;
		instances = 100;
		p = proposer_new(id, instances);
	}

	virtual void TearDown() { }
};

TEST_F(ProposerTest, Prepare) {
	int count = 10;
	prepare_req pr;
	for (int i = 0; i < count; ++i) {
		pr = proposer_prepare(p);
		ASSERT_EQ(pr.iid, i+1);
		ASSERT_EQ(pr.ballot, id + MAX_N_OF_PROPOSERS);
	}
	ASSERT_EQ(count, proposer_prepared_count(p));
}

TEST_F(ProposerTest, PrepareAndAccept) {
	prepare_req pr;
	prepare_ack pa;
	accept_req* ar;
	accept_ack aa;

	pr = proposer_prepare(p);

	// aid, iid, bal, val_bal, val_size
	pa = (prepare_ack) {1, pr.iid, pr.ballot, 0, 0};
	proposer_receive_prepare_ack(p, &pa);
	pa = (prepare_ack) {2, pr.iid, pr.ballot, 0, 0};
	proposer_receive_prepare_ack(p, &pa);

	// we have no value to propose!
	ASSERT_EQ(proposer_accept(p), (void*)NULL);

	proposer_propose(p, (char*)"value", 6);
	ar = proposer_accept(p);
	ASSERT_NE(ar, (accept_req*)NULL);
	ASSERT_EQ(ar->iid, pr.iid);
	ASSERT_EQ(ar->ballot, pr.ballot);
	ASSERT_EQ(ar->value_size, 6);
	ASSERT_STREQ(ar->value, "value");

	// aid, iid, bal, val_bal, final, size
	prepare_req* req;
	aa = (accept_ack) {0, ar->iid, ar->ballot, ar->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_accept_ack(p, &aa), (void*)NULL);
	aa = (accept_ack) {1, ar->iid, ar->ballot, ar->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_accept_ack(p, &aa), (void*)NULL);
}

TEST_F(ProposerTest, PreparePreempted) {
	prepare_req pr;
	prepare_ack pa;
	prepare_req* pr_preempt;
	accept_req* ar;
	char value[] = "some value";
	int value_size = strlen(value) + 1;

	pr = proposer_prepare(p);
	proposer_propose(p, value, value_size);

	// preempt! proposer receives a different ballot...
	pa = (prepare_ack) {1, pr.iid, pr.ballot+1, 0, 0};
	pr_preempt = proposer_receive_prepare_ack(p, &pa);
	ASSERT_NE((void*)NULL, pr_preempt);
	ASSERT_EQ(pr_preempt->iid, pr.iid);
	ASSERT_GT(pr_preempt->ballot, pr.ballot);

	pa = (prepare_ack) {0, pr_preempt->iid, pr_preempt->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);
	pa = (prepare_ack) {1, pr_preempt->iid, pr_preempt->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);

	ar = proposer_accept(p);
	ASSERT_NE(ar, (void*)NULL);
	ASSERT_EQ(ar->iid, pr_preempt->iid);
	ASSERT_EQ(ar->ballot, pr_preempt->ballot);
	ASSERT_EQ(ar->value_size, value_size);
	ASSERT_STREQ(ar->value, value);

	free(ar);
	free(pr_preempt);
}

TEST_F(ProposerTest, AcceptPreempted) {
	prepare_req pr;
	prepare_ack pa;
	prepare_req* pr_preempt;
	accept_req* ar;
	accept_ack aa;
	char value[] = "some value";
	int value_size = strlen(value) + 1;

	pr = proposer_prepare(p);
	proposer_propose(p, value, value_size);

	pa = (prepare_ack) {0, pr.iid, pr.ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);
	pa = (prepare_ack) {1, pr.iid, pr.ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);

	ar = proposer_accept(p);
	ASSERT_NE(ar, (void*)NULL);

	// preempt! proposer receives accept nack
	aa = (accept_ack) {0, ar->iid, ar->ballot+1, 0, 0, 0};
	pr_preempt = proposer_receive_accept_ack(p, &aa);
	ASSERT_NE((void*)NULL, pr_preempt);
	ASSERT_EQ(pr_preempt->iid, pr.iid);
	ASSERT_GT(pr_preempt->ballot, ar->ballot);
	free(ar);

	// finally acquire the instance
	pa = (prepare_ack) {0, pr_preempt->iid, pr_preempt->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);
	pa = (prepare_ack) {1, pr_preempt->iid, pr_preempt->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);

	// accept again
	ar = proposer_accept(p);
	ASSERT_NE(ar, (void*)NULL);
	ASSERT_EQ(pr_preempt->iid, ar->iid);
	ASSERT_EQ(pr_preempt->ballot, ar->ballot);
	ASSERT_EQ(value_size, ar->value_size);
	ASSERT_STREQ(value, ar->value);

	aa = (accept_ack) {0, ar->iid, ar->ballot, ar->ballot, 0, value_size};
	ASSERT_EQ(proposer_receive_accept_ack(p, &aa), (void*)NULL);
	aa = (accept_ack) {1, ar->iid, ar->ballot, ar->ballot, 0, value_size};
	ASSERT_EQ(proposer_receive_accept_ack(p, &aa), (void*)NULL);

	free(ar);
	free(pr_preempt);
}

TEST_F(ProposerTest, ProposedCount) {
	int count = 10;
	prepare_req pr;
	prepare_ack pa;
	accept_req* ar;
	char value[] = "a value";
	int value_size = strlen(value) + 1;

	for (size_t i = 0; i < count; ++i) {
		pr = proposer_prepare(p);
		proposer_propose(p, value, value_size);
		ASSERT_EQ(i + 1, proposer_prepared_count(p));
	}

	for (size_t i = 0; i < count; ++i)
		proposer_accept(p);
	ASSERT_EQ(count, proposer_prepared_count(p));

	for (size_t i = 0; i < count; ++i) {
		pa = (prepare_ack) {0, i+1, pr.ballot, 0, 0};
		proposer_receive_prepare_ack(p, &pa);
		pa = (prepare_ack) {1, i+1, pr.ballot, 0, 0};
		proposer_receive_prepare_ack(p, &pa);
		ar = proposer_accept(p);
		free(ar);
		ASSERT_EQ(count-(i+1), proposer_prepared_count(p));
	}
}
<|endoftext|>


<commit_before>/*
* Vulkan examples debug wrapper
*
* Appendix for VK_EXT_Debug_Report can be found at https://github.com/KhronosGroup/Vulkan-Docs/blob/1.0-VK_EXT_debug_report/doc/specs/vulkan/appendices/debug_report.txt
*
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/

#include "Debug.h"

namespace Saiga {
namespace Vulkan {

static const std::vector<std::string> typeNames = {
    "VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT                     ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT                    ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT             ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT                      ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT                       ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT                   ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT              ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT                       ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT               ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT                      ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT                       ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT                       ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT                  ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT                 ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT                  ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT               ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT              ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT             ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT                 ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT                    ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT       ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT                     ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT             ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT              ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT                 ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT                ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT                 ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT               ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT   ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT                 ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT            ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT            ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT",
    "VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT        ",
};

VkBool32 messageCallback(
        VkDebugReportFlagsEXT flags,
        VkDebugReportObjectTypeEXT objType,
        uint64_t srcObject,
        size_t location,
        int32_t msgCode,
        const char* pLayerPrefix,
        const char* pMsg,
        void* pUserData)
{
    // Select prefix depending on flags passed to the callback
    // Note that multiple flags may be set for a single validation message
    std::string prefix("");

    // Error that may result in undefined behaviour
    if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
    {
        prefix += "ERROR";
    };
    // Warnings may hint at unexpected / non-spec API usage
    if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
    {
        prefix += "WARNING";
    };
    // May indicate sub-optimal usage of the API
    if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)
    {
        prefix += "PERFORMANCE";
    };
    // Informal messages that may become handy during debugging
    if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)
    {
        prefix += "INFO";
    }
    // Diagnostic info from the Vulkan loader and layers
    // Usually not helpful in terms of API usage, but may help to debug layer and loader problems
    if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT)
    {
        prefix += "DEBUG";
    }

    std::string typestring = (int)objType<typeNames.size() ? typeNames[objType] : std::to_string((int)objType);

    // Display message to default output (console/logcat)

    std::cerr <<
                 "Vulkan " << pLayerPrefix << " callback" << endl <<
                 "  Severity    : " << prefix << endl <<
                 "  Code        : " << msgCode << endl <<
                 "  Object ID   : " << srcObject << endl <<
                 "  Object Type : " << typestring << endl <<
                 "  Location    : " << location << endl <<
                 "  Message     : " << pMsg << endl << endl;

    SAIGA_ASSERT(0);
    // The return value of this callback controls wether the Vulkan call that caused
    // the validation message will be aborted or not
    // We return VK_FALSE as we DON'T want Vulkan calls that cause a validation message
    // (and return a VkResult) to abort
    // If you instead want to have calls abort, pass in VK_TRUE and the function will
    // return VK_ERROR_VALIDATION_FAILED_EXT
    return VK_TRUE;
}

void Debug::init(VkInstance _instance, VkDebugReportFlagsEXT flags, VkDebugReportCallbackEXT callBack)
{
    instance = _instance;

    CreateDebugReportCallback = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"));
    DestroyDebugReportCallback = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"));
    dbgBreakCallback = reinterpret_cast<PFN_vkDebugReportMessageEXT>(vkGetInstanceProcAddr(instance, "vkDebugReportMessageEXT"));

    VkDebugReportCallbackCreateInfoEXT dbgCreateInfo = {};
    dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
    dbgCreateInfo.pfnCallback = (PFN_vkDebugReportCallbackEXT)messageCallback;
    dbgCreateInfo.flags = flags;

    VkResult err = CreateDebugReportCallback(
                instance,
                &dbgCreateInfo,
                nullptr,
                (callBack != VK_NULL_HANDLE) ? &callBack : &msgCallback);
    SAIGA_ASSERT(!err);
}

void Debug::destroy()
{
    if (msgCallback != VK_NULL_HANDLE)
    {
        DestroyDebugReportCallback(instance, msgCallback, nullptr);
    }
}

std::vector<const char *> Debug::getDebugValidationLayers()
{
#ifdef __APPLE__
    // lunarg validation not supported on moltenvk
    return {};
#else
    return {
        "VK_LAYER_LUNARG_standard_validation"
    };
#endif

}

}
}

<commit_msg>Enable debug on MoltenVK since it is supported in the meantime<commit_after>/*
* Vulkan examples debug wrapper
*
* Appendix for VK_EXT_Debug_Report can be found at https://github.com/KhronosGroup/Vulkan-Docs/blob/1.0-VK_EXT_debug_report/doc/specs/vulkan/appendices/debug_report.txt
*
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/

#include "Debug.h"

namespace Saiga {
namespace Vulkan {

static const std::vector<std::string> typeNames = {
    "VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT                     ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT                    ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT             ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT                      ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT                       ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT                   ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT              ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT                       ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT               ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT                      ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT                       ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT                       ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT                  ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT                 ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT                  ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT               ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT              ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT             ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT                 ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT                    ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT       ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT                     ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT             ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT              ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT                 ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT                ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT                 ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT               ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT   ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT                 ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT            ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT            ",
    "VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT",
    "VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT        ",
};

VkBool32 messageCallback(
        VkDebugReportFlagsEXT flags,
        VkDebugReportObjectTypeEXT objType,
        uint64_t srcObject,
        size_t location,
        int32_t msgCode,
        const char* pLayerPrefix,
        const char* pMsg,
        void* pUserData)
{
    // Select prefix depending on flags passed to the callback
    // Note that multiple flags may be set for a single validation message
    std::string prefix("");

    // Error that may result in undefined behaviour
    if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
    {
        prefix += "ERROR";
    };
    // Warnings may hint at unexpected / non-spec API usage
    if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
    {
        prefix += "WARNING";
    };
    // May indicate sub-optimal usage of the API
    if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)
    {
        prefix += "PERFORMANCE";
    };
    // Informal messages that may become handy during debugging
    if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)
    {
        prefix += "INFO";
    }
    // Diagnostic info from the Vulkan loader and layers
    // Usually not helpful in terms of API usage, but may help to debug layer and loader problems
    if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT)
    {
        prefix += "DEBUG";
    }

    std::string typestring = (int)objType<typeNames.size() ? typeNames[objType] : std::to_string((int)objType);

    // Display message to default output (console/logcat)

    std::cerr <<
                 "Vulkan " << pLayerPrefix << " callback" << endl <<
                 "  Severity    : " << prefix << endl <<
                 "  Code        : " << msgCode << endl <<
                 "  Object ID   : " << srcObject << endl <<
                 "  Object Type : " << typestring << endl <<
                 "  Location    : " << location << endl <<
                 "  Message     : " << pMsg << endl << endl;

    SAIGA_ASSERT(0);
    // The return value of this callback controls wether the Vulkan call that caused
    // the validation message will be aborted or not
    // We return VK_FALSE as we DON'T want Vulkan calls that cause a validation message
    // (and return a VkResult) to abort
    // If you instead want to have calls abort, pass in VK_TRUE and the function will
    // return VK_ERROR_VALIDATION_FAILED_EXT
    return VK_TRUE;
}

void Debug::init(VkInstance _instance, VkDebugReportFlagsEXT flags, VkDebugReportCallbackEXT callBack)
{
    instance = _instance;

    CreateDebugReportCallback = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"));
    DestroyDebugReportCallback = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"));
    dbgBreakCallback = reinterpret_cast<PFN_vkDebugReportMessageEXT>(vkGetInstanceProcAddr(instance, "vkDebugReportMessageEXT"));

    VkDebugReportCallbackCreateInfoEXT dbgCreateInfo = {};
    dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
    dbgCreateInfo.pfnCallback = (PFN_vkDebugReportCallbackEXT)messageCallback;
    dbgCreateInfo.flags = flags;

    VkResult err = CreateDebugReportCallback(
                instance,
                &dbgCreateInfo,
                nullptr,
                (callBack != VK_NULL_HANDLE) ? &callBack : &msgCallback);
    SAIGA_ASSERT(!err);
}

void Debug::destroy()
{
    if (msgCallback != VK_NULL_HANDLE)
    {
        DestroyDebugReportCallback(instance, msgCallback, nullptr);
    }
}

std::vector<const char *> Debug::getDebugValidationLayers()
{
    return {
        "VK_LAYER_LUNARG_standard_validation"
    };
}

}
}

<|endoftext|>


<commit_before>#include <babylon/rendering/bounding_box_renderer.h>

#include <babylon/babylon_stl_util.h>
#include <babylon/buffers/vertex_buffer.h>
#include <babylon/culling/bounding_box.h>
#include <babylon/engines/engine.h>
#include <babylon/engines/scene.h>
#include <babylon/materials/ishader_material_options.h>
#include <babylon/materials/shader_material.h>
#include <babylon/meshes/builders/mesh_builder_options.h>
#include <babylon/meshes/sub_mesh.h>
#include <babylon/meshes/vertex_data.h>

namespace BABYLON {

BoundingBoxRenderer::BoundingBoxRenderer(Scene* iScene)
    : frontColor{Color3(1.f, 1.f, 1.f)}
    , backColor{Color3(0.1f, 0.1f, 0.1f)}
    , showBackLines{true}
    , enabled{true}
    , _colorShader{nullptr}
    , _indexBuffer{nullptr}
    , _fillIndexBuffer{nullptr}
{
  scene = iScene;
  renderList.reserve(32);
}

BoundingBoxRenderer::~BoundingBoxRenderer() = default;

void BoundingBoxRenderer::addToScene(const BoundingBoxRendererPtr& newBoundingBoxRenderer)
{
  ISceneComponent::name = BoundingBoxRenderer::name;
  scene->_addComponent(newBoundingBoxRenderer);
}

void BoundingBoxRenderer::_register()
{
  scene->_beforeEvaluateActiveMeshStage.registerStep(
    SceneComponentConstants::STEP_BEFOREEVALUATEACTIVEMESH_BOUNDINGBOXRENDERER, this,
    [this]() -> void { reset(); });

  scene->_preActiveMeshStage.registerStep(
    SceneComponentConstants::STEP_PREACTIVEMESH_BOUNDINGBOXRENDERER, this,
    [this](AbstractMesh* mesh) -> void { _preActiveMesh(mesh); });

  scene->_evaluateSubMeshStage.registerStep(
    SceneComponentConstants::STEP_EVALUATESUBMESH_BOUNDINGBOXRENDERER, this,
    [this](AbstractMesh* mesh, SubMesh* subMesh) -> void { _evaluateSubMesh(mesh, subMesh); });

  scene->_afterRenderingGroupDrawStage.registerStep(
    SceneComponentConstants::STEP_AFTERRENDERINGGROUPDRAW_BOUNDINGBOXRENDERER, this,
    [this](int renderingGroupId) -> void { render(renderingGroupId); });
}

void BoundingBoxRenderer::_evaluateSubMesh(AbstractMesh* mesh, SubMesh* subMesh)
{
  if (mesh->showSubMeshesBoundingBox) {
    auto& boundingInfo            = *subMesh->getBoundingInfo();
    boundingInfo.boundingBox._tag = mesh->renderingGroupId;
    renderList.emplace_back(boundingInfo.boundingBox);
  }
}

void BoundingBoxRenderer::_preActiveMesh(AbstractMesh* mesh)
{
  if (mesh->showBoundingBox || scene->forceShowBoundingBoxes) {
    auto& boundingInfo            = *mesh->getBoundingInfo();
    boundingInfo.boundingBox._tag = mesh->renderingGroupId;
    renderList.emplace_back(boundingInfo.boundingBox);
  }
}

void BoundingBoxRenderer::_prepareResources()
{
  if (_colorShader) {
    return;
  }

  IShaderMaterialOptions shaderMaterialOptions;
  shaderMaterialOptions.attributes = {VertexBuffer::PositionKind};
  shaderMaterialOptions.uniforms   = {"world", "viewProjection", "color"};

  _colorShader = ShaderMaterial::New("colorShader", scene, "color", shaderMaterialOptions);

  auto engine = scene->getEngine();
  BoxOptions options;
  options.size = 1.f;
  auto boxdata = VertexData::CreateBox(options);
  _vertexBuffers[VertexBuffer::PositionKind]
    = std::make_shared<VertexBuffer>(engine, boxdata->positions, VertexBuffer::PositionKind, false);
  _createIndexBuffer();
  _fillIndexData = boxdata->indices;
  onResourcesReadyObservable.notifyObservers(this);
}

void BoundingBoxRenderer::_createIndexBuffer()
{
  auto engine = scene->getEngine();
  const Uint32Array indices{0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 7, 1, 6, 2, 5, 3, 4};
  _indexBuffer = engine->createIndexBuffer(indices);
}

void BoundingBoxRenderer::rebuild()
{
  if (stl_util::contains(_vertexBuffers, VertexBuffer::PositionKind)) {
    auto& vb = _vertexBuffers[VertexBuffer::PositionKind];
    if (vb) {
      vb->_rebuild();
    }
  }
  _createIndexBuffer();
}

void BoundingBoxRenderer::reset()
{
  renderList.clear();
}

void BoundingBoxRenderer::render(int renderingGroupId)
{
  if (renderList.empty() || !enabled) {
    return;
  }

  _prepareResources();

  if (!_colorShader->isReady()) {
    return;
  }

  auto engine = scene->getEngine();
  engine->setDepthWrite(false);
  _colorShader->_preBind(EffectPtr{nullptr});

  for (auto& boundingBox : renderList) {
    if (boundingBox._tag != renderingGroupId) {
      continue;
    }

    onBeforeBoxRenderingObservable.notifyObservers(&boundingBox);

    const auto& min = boundingBox.minimum;
    const auto& max = boundingBox.maximum;
    auto diff       = max.subtract(min);
    auto median     = min.add(diff.scale(0.5f));

    auto worldMatrix = Matrix::Scaling(diff.x, diff.y, diff.z)
                         .multiply(Matrix::Translation(median.x, median.y, median.z))
                         .multiply(boundingBox.getWorldMatrix());

    // VBOs
    engine->bindBuffers(_vertexBuffers, _indexBuffer, _colorShader->getEffect());

    if (showBackLines) {
      // Back
      engine->setDepthFunctionToGreaterOrEqual();
      scene->resetCachedMaterial();
      _colorShader->setColor4("color", backColor.toColor4());
      _colorShader->bind(worldMatrix, nullptr);

      // Draw order
      engine->drawElementsType(Material::LineListDrawMode, 0, 24);
    }

    // Front
    engine->setDepthFunctionToLess();
    scene->resetCachedMaterial();
    _colorShader->setColor4("color", frontColor.toColor4());
    _colorShader->bind(worldMatrix);

    // Draw order
    engine->drawElementsType(Material::LineListDrawMode, 0, 24);

    onAfterBoxRenderingObservable.notifyObservers(&boundingBox);
  }
  _colorShader->unbind();
  engine->setDepthFunctionToLessOrEqual();
  engine->setDepthWrite(true);
}

void BoundingBoxRenderer::renderOcclusionBoundingBox(AbstractMesh* mesh)
{
  _prepareResources();

  if (!_colorShader->isReady() || !mesh->_boundingInfo) {
    return;
  }

  auto engine = scene->getEngine();
  if (!_fillIndexBuffer) {
    _fillIndexBuffer = engine->createIndexBuffer(_fillIndexData);
  }

  engine->setDepthWrite(false);
  engine->setColorWrite(false);
  _colorShader->_preBind(EffectPtr{nullptr});

  auto& boundingBox = mesh->_boundingInfo->boundingBox;
  auto min          = boundingBox.minimum;
  auto max          = boundingBox.maximum;
  auto diff         = max.subtract(min);
  auto median       = min.add(diff.scale(0.5f));

  auto worldMatrix = Matrix::Scaling(diff.x, diff.y, diff.z)
                       .multiply(Matrix::Translation(median.x, median.y, median.z))
                       .multiply(boundingBox.getWorldMatrix());

  engine->bindBuffers(_vertexBuffers, _fillIndexBuffer, _colorShader->getEffect());

  engine->setDepthFunctionToLess();
  scene->resetCachedMaterial();
  _colorShader->bind(worldMatrix);

  engine->drawElementsType(Material::TriangleFillMode, 0, 36);

  _colorShader->unbind();
  engine->setDepthFunctionToLessOrEqual();
  engine->setDepthWrite(true);
  engine->setColorWrite(true);
}

void BoundingBoxRenderer::dispose()
{
  if (!_colorShader) {
    return;
  }

  onBeforeBoxRenderingObservable.clear();
  onAfterBoxRenderingObservable.clear();
  onResourcesReadyObservable.clear();

  renderList.clear();

  _colorShader->dispose();

  if (stl_util::contains(_vertexBuffers, VertexBuffer::PositionKind)) {
    auto& buffer = _vertexBuffers[VertexBuffer::PositionKind];
    if (buffer) {
      buffer->dispose();
      buffer = nullptr;
      _vertexBuffers.erase(VertexBuffer::PositionKind);
    }
  }

  scene->getEngine()->_releaseBuffer(_indexBuffer);

  if (_fillIndexBuffer) {
    scene->getEngine()->_releaseBuffer(_fillIndexBuffer);
    _fillIndexBuffer = nullptr;
  }
}

} // end of namespace BABYLON
<commit_msg>Taking useReverseDepthBuffer value into account for depth function<commit_after>#include <babylon/rendering/bounding_box_renderer.h>

#include <babylon/babylon_stl_util.h>
#include <babylon/buffers/vertex_buffer.h>
#include <babylon/culling/bounding_box.h>
#include <babylon/engines/engine.h>
#include <babylon/engines/scene.h>
#include <babylon/materials/ishader_material_options.h>
#include <babylon/materials/shader_material.h>
#include <babylon/meshes/builders/mesh_builder_options.h>
#include <babylon/meshes/sub_mesh.h>
#include <babylon/meshes/vertex_data.h>

namespace BABYLON {

BoundingBoxRenderer::BoundingBoxRenderer(Scene* iScene)
    : frontColor{Color3(1.f, 1.f, 1.f)}
    , backColor{Color3(0.1f, 0.1f, 0.1f)}
    , showBackLines{true}
    , enabled{true}
    , _colorShader{nullptr}
    , _indexBuffer{nullptr}
    , _fillIndexBuffer{nullptr}
{
  scene = iScene;
  renderList.reserve(32);
}

BoundingBoxRenderer::~BoundingBoxRenderer() = default;

void BoundingBoxRenderer::addToScene(const BoundingBoxRendererPtr& newBoundingBoxRenderer)
{
  ISceneComponent::name = BoundingBoxRenderer::name;
  scene->_addComponent(newBoundingBoxRenderer);
}

void BoundingBoxRenderer::_register()
{
  scene->_beforeEvaluateActiveMeshStage.registerStep(
    SceneComponentConstants::STEP_BEFOREEVALUATEACTIVEMESH_BOUNDINGBOXRENDERER, this,
    [this]() -> void { reset(); });

  scene->_preActiveMeshStage.registerStep(
    SceneComponentConstants::STEP_PREACTIVEMESH_BOUNDINGBOXRENDERER, this,
    [this](AbstractMesh* mesh) -> void { _preActiveMesh(mesh); });

  scene->_evaluateSubMeshStage.registerStep(
    SceneComponentConstants::STEP_EVALUATESUBMESH_BOUNDINGBOXRENDERER, this,
    [this](AbstractMesh* mesh, SubMesh* subMesh) -> void { _evaluateSubMesh(mesh, subMesh); });

  scene->_afterRenderingGroupDrawStage.registerStep(
    SceneComponentConstants::STEP_AFTERRENDERINGGROUPDRAW_BOUNDINGBOXRENDERER, this,
    [this](int renderingGroupId) -> void { render(renderingGroupId); });
}

void BoundingBoxRenderer::_evaluateSubMesh(AbstractMesh* mesh, SubMesh* subMesh)
{
  if (mesh->showSubMeshesBoundingBox) {
    auto& boundingInfo            = *subMesh->getBoundingInfo();
    boundingInfo.boundingBox._tag = mesh->renderingGroupId;
    renderList.emplace_back(boundingInfo.boundingBox);
  }
}

void BoundingBoxRenderer::_preActiveMesh(AbstractMesh* mesh)
{
  if (mesh->showBoundingBox || scene->forceShowBoundingBoxes) {
    auto& boundingInfo            = *mesh->getBoundingInfo();
    boundingInfo.boundingBox._tag = mesh->renderingGroupId;
    renderList.emplace_back(boundingInfo.boundingBox);
  }
}

void BoundingBoxRenderer::_prepareResources()
{
  if (_colorShader) {
    return;
  }

  IShaderMaterialOptions shaderMaterialOptions;
  shaderMaterialOptions.attributes = {VertexBuffer::PositionKind};
  shaderMaterialOptions.uniforms   = {"world", "viewProjection", "color"};

  _colorShader = ShaderMaterial::New("colorShader", scene, "color", shaderMaterialOptions);

  auto engine = scene->getEngine();
  BoxOptions options;
  options.size = 1.f;
  auto boxdata = VertexData::CreateBox(options);
  _vertexBuffers[VertexBuffer::PositionKind]
    = std::make_shared<VertexBuffer>(engine, boxdata->positions, VertexBuffer::PositionKind, false);
  _createIndexBuffer();
  _fillIndexData = boxdata->indices;
  onResourcesReadyObservable.notifyObservers(this);
}

void BoundingBoxRenderer::_createIndexBuffer()
{
  auto engine = scene->getEngine();
  const Uint32Array indices{0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 7, 1, 6, 2, 5, 3, 4};
  _indexBuffer = engine->createIndexBuffer(indices);
}

void BoundingBoxRenderer::rebuild()
{
  if (stl_util::contains(_vertexBuffers, VertexBuffer::PositionKind)) {
    auto& vb = _vertexBuffers[VertexBuffer::PositionKind];
    if (vb) {
      vb->_rebuild();
    }
  }
  _createIndexBuffer();
}

void BoundingBoxRenderer::reset()
{
  renderList.clear();
}

void BoundingBoxRenderer::render(int renderingGroupId)
{
  if (renderList.empty() || !enabled) {
    return;
  }

  _prepareResources();

  if (!_colorShader->isReady()) {
    return;
  }

  auto engine = scene->getEngine();
  engine->setDepthWrite(false);
  _colorShader->_preBind(EffectPtr{nullptr});

  for (auto& boundingBox : renderList) {
    if (boundingBox._tag != renderingGroupId) {
      continue;
    }

    onBeforeBoxRenderingObservable.notifyObservers(&boundingBox);

    const auto& min = boundingBox.minimum;
    const auto& max = boundingBox.maximum;
    auto diff       = max.subtract(min);
    auto median     = min.add(diff.scale(0.5f));

    auto worldMatrix = Matrix::Scaling(diff.x, diff.y, diff.z)
                         .multiply(Matrix::Translation(median.x, median.y, median.z))
                         .multiply(boundingBox.getWorldMatrix());

    // VBOs
    engine->bindBuffers(_vertexBuffers, _indexBuffer, _colorShader->getEffect());

    const auto useReverseDepthBuffer = engine->useReverseDepthBuffer;

    if (showBackLines) {
      // Back
      if (useReverseDepthBuffer) {
        engine->setDepthFunctionToLessOrEqual();
      }
      else {
        engine->setDepthFunctionToGreaterOrEqual();
      }
      scene->resetCachedMaterial();
      _colorShader->setColor4("color", backColor.toColor4());
      _colorShader->bind(worldMatrix, nullptr);

      // Draw order
      engine->drawElementsType(Material::LineListDrawMode, 0, 24);
    }

    // Front
    if (useReverseDepthBuffer) {
      engine->setDepthFunctionToGreater();
    }
    else {
      engine->setDepthFunctionToLess();
    }
    scene->resetCachedMaterial();
    _colorShader->setColor4("color", frontColor.toColor4());
    _colorShader->bind(worldMatrix);

    // Draw order
    engine->drawElementsType(Material::LineListDrawMode, 0, 24);

    onAfterBoxRenderingObservable.notifyObservers(&boundingBox);
  }
  _colorShader->unbind();
  engine->setDepthFunctionToLessOrEqual();
  engine->setDepthWrite(true);
}

void BoundingBoxRenderer::renderOcclusionBoundingBox(AbstractMesh* mesh)
{
  _prepareResources();

  if (!_colorShader->isReady() || !mesh->_boundingInfo) {
    return;
  }

  auto engine = scene->getEngine();
  if (!_fillIndexBuffer) {
    _fillIndexBuffer = engine->createIndexBuffer(_fillIndexData);
  }

  engine->setDepthWrite(false);
  engine->setColorWrite(false);
  _colorShader->_preBind(EffectPtr{nullptr});

  auto& boundingBox = mesh->_boundingInfo->boundingBox;
  auto min          = boundingBox.minimum;
  auto max          = boundingBox.maximum;
  auto diff         = max.subtract(min);
  auto median       = min.add(diff.scale(0.5f));

  auto worldMatrix = Matrix::Scaling(diff.x, diff.y, diff.z)
                       .multiply(Matrix::Translation(median.x, median.y, median.z))
                       .multiply(boundingBox.getWorldMatrix());

  engine->bindBuffers(_vertexBuffers, _fillIndexBuffer, _colorShader->getEffect());

  engine->setDepthFunctionToLess();
  scene->resetCachedMaterial();
  _colorShader->bind(worldMatrix);

  engine->drawElementsType(Material::TriangleFillMode, 0, 36);

  _colorShader->unbind();
  engine->setDepthFunctionToLessOrEqual();
  engine->setDepthWrite(true);
  engine->setColorWrite(true);
}

void BoundingBoxRenderer::dispose()
{
  if (!_colorShader) {
    return;
  }

  onBeforeBoxRenderingObservable.clear();
  onAfterBoxRenderingObservable.clear();
  onResourcesReadyObservable.clear();

  renderList.clear();

  _colorShader->dispose();

  if (stl_util::contains(_vertexBuffers, VertexBuffer::PositionKind)) {
    auto& buffer = _vertexBuffers[VertexBuffer::PositionKind];
    if (buffer) {
      buffer->dispose();
      buffer = nullptr;
      _vertexBuffers.erase(VertexBuffer::PositionKind);
    }
  }

  scene->getEngine()->_releaseBuffer(_indexBuffer);

  if (_fillIndexBuffer) {
    scene->getEngine()->_releaseBuffer(_fillIndexBuffer);
    _fillIndexBuffer = nullptr;
  }
}

} // end of namespace BABYLON
<|endoftext|>


<commit_before>#include "buffer_pool.hpp"
#include <utility>
#include <turbo/container/mpmc_ring_queue.hxx>

namespace {

} // anonymous namespace

namespace beam {
namespace message {

buffer_pool::buffer_pool(std::size_t message_size, capacity_type capacity)
    :
	pool_(),
	free_list_(capacity)
{
    for (auto iter = pool_.begin(); iter != pool_.end(); ++iter)
    {
	*iter = make_buffer(message_size);
	free_list_.try_enqueue_copy(pool_.begin() - iter);
    }
}

buffer_pool::capacity_type buffer_pool::reserve()
{
    namespace tar = turbo::algorithm::recovery;
    capacity_type reservation = 0U;
    tar::retry_with_random_backoff([&] () -> tar::try_state
    {
	switch (free_list_.try_dequeue_copy(reservation))
	{
	    case free_list_type::consumer::result::success:
	    {
		return tar::try_state::done;
	    }
	    default:
	    {
		return tar::try_state::retry;
	    }
	}
    });
    return reservation;
}

void buffer_pool::revoke(capacity_type reservation)
{
    namespace tar = turbo::algorithm::recovery;
    tar::retry_with_random_backoff([&] () -> tar::try_state
    {
	switch (free_list_.try_enqueue_copy(reservation))
	{
	    case free_list_type::producer::result::success:
	    {
		return tar::try_state::done;
	    }
	    default:
	    {
		return tar::try_state::retry;
	    }
	}
    });
}

unique_pool_ptr buffer_pool::borrow()
{
    capacity_type reservation = reserve();
    unique_pool_ptr result(
	    &(pool_[reservation]),
	    std::bind(&buffer_pool::reinstate, this, std::placeholders::_1));
    return std::move(result);
}

void buffer_pool::reinstate(buffer* ptr)
{
    capacity_type reservation = &(pool_[0]) - ptr;
    revoke(reservation);
}

} // namespace message
} // namespace beam
<commit_msg>adding an optimisation to not allocate when the message size is 0<commit_after>#include "buffer_pool.hpp"
#include <utility>
#include <turbo/container/mpmc_ring_queue.hxx>

namespace {

} // anonymous namespace

namespace beam {
namespace message {

buffer_pool::buffer_pool(std::size_t message_size, capacity_type capacity)
    :
	pool_(),
	free_list_(capacity)
{
    for (auto iter = pool_.begin(); iter != pool_.end(); ++iter)
    {
	if (message_size > 0U)
	{
	    *iter = make_buffer(message_size);
	}
	free_list_.try_enqueue_copy(pool_.begin() - iter);
    }
}

buffer_pool::capacity_type buffer_pool::reserve()
{
    namespace tar = turbo::algorithm::recovery;
    capacity_type reservation = 0U;
    tar::retry_with_random_backoff([&] () -> tar::try_state
    {
	switch (free_list_.try_dequeue_copy(reservation))
	{
	    case free_list_type::consumer::result::success:
	    {
		return tar::try_state::done;
	    }
	    default:
	    {
		return tar::try_state::retry;
	    }
	}
    });
    return reservation;
}

void buffer_pool::revoke(capacity_type reservation)
{
    namespace tar = turbo::algorithm::recovery;
    tar::retry_with_random_backoff([&] () -> tar::try_state
    {
	switch (free_list_.try_enqueue_copy(reservation))
	{
	    case free_list_type::producer::result::success:
	    {
		return tar::try_state::done;
	    }
	    default:
	    {
		return tar::try_state::retry;
	    }
	}
    });
}

unique_pool_ptr buffer_pool::borrow()
{
    capacity_type reservation = reserve();
    unique_pool_ptr result(
	    &(pool_[reservation]),
	    std::bind(&buffer_pool::reinstate, this, std::placeholders::_1));
    return std::move(result);
}

void buffer_pool::reinstate(buffer* ptr)
{
    capacity_type reservation = &(pool_[0]) - ptr;
    revoke(reservation);
}

} // namespace message
} // namespace beam
<|endoftext|>


<commit_before>#pragma once

#include <type_traits>
#include <functional>
#include <utility>
#include <vector>

#include <SFML/Graphics.hpp>
#include "imgui/imgui.h"

#include "Time.hpp"

struct Game
{
public:
	Game();

	virtual ~Game();

	Game(Game const& other) = delete;

	Game(Game&& other) = delete;

	Game& operator=(Game const& other) = delete;

	Game& operator=(Game&& other) = delete;

	virtual inline int error_state() const final
	{ return _error_state; }

	virtual inline bool is_running() const final
	{ return _is_running; }

	virtual inline sf::RenderTarget& target() final
	{ return _window; }

	virtual void quit(int errorCode = 0) final;

	virtual void init(int argc, char** argv);

	virtual void frame_start();

	virtual void process_event(sf::Event& e);

	virtual void update(Seconds delta_time);

	virtual void frame_end();

private:
	sf::RenderWindow _window;
	int _error_state;
	bool _is_running;
};

class GameState
{
	friend class GameStateStack;

public:
	inline GameState() : _game(nullptr)
	{ }

	virtual inline ~GameState()
	{ }

	GameState(GameState const& other) = delete;

	GameState(GameState&& other) = delete;

	GameState& operator=(GameState const& other) = delete;

	GameState& operator=(GameState&& other) = delete;

	virtual inline void init()
	{ }

	virtual inline void load_resources()
	{ }

	virtual inline void unload_resources()
	{ }

	virtual inline void update(Seconds)
	{ }

	virtual inline void render()
	{ }

	virtual inline void on_pause()
	{ }

	virtual inline void on_resume()
	{ }

protected:
	template<class GameType>
	inline GameType& game()
	{
		static_assert(std::is_base_of<Game, GameType>::value, "GameType must be a Game");
		return *dynamic_cast<GameType*>(_game);
	}

	template<class GameType>
	inline Game const& game() const
	{
		static_assert(std::is_base_of<Game, GameType>::value, "GameType must be a Game");
		return *dynamic_cast<GameType*>(_game);
	}

private:
	Game* _game;
};

/// \brief An enumeration used for a stack
///
/// This describes different ways to push
/// a game state on a stack
enum class PushType
{
	/// Pushes on a new GameState,
	/// without popping off the previous GameState
	/// Acts like a regular stack push operation
	PushWithoutPopping,

	/// Pushes on a new GameState, and pops off the
	/// previous GameState that was pushed on the stack
	/// (if there is a previous GameState).
	PushAndPop,

	/// Pushes on a new GameState,
	/// and pops off all previous states on the stack
	PushAndPopAllPreviousStates,

	/// Pushes on a new GameState, without popping off the last GameState
	/// Unlike `PushWithoutPopping`, this enumeration makes it so that
	/// the previous GameState is still updated, whilst the new GameState is updated
	PushWithoutPoppingSilenty
};

class GameStateStackListener
{
public:
	virtual inline ~GameStateStackListener()
	{ }

	virtual void on_gamestate_will_be_pushed(class GameStateStack& sender, GameState& state) = 0;

	virtual void on_gamestate_was_pushed(class GameStateStack& sender, GameState& state) = 0;

	virtual void on_gamestate_will_be_removed(class GameStateStack& sender, GameState& state) = 0;

	virtual void on_stack_will_be_popped(class GameStateStack& sender) = 0;

	virtual void on_stack_will_be_cleared(class GameStateStack& sender) = 0;
};

class GameStateStack
{
public:
	inline GameStateStack(Game* game) : _game(game)
	{ }

	inline ~GameStateStack()
	{ clear(); }

	GameStateStack(GameStateStack const& other) = default;

	GameStateStack(GameStateStack&& other) = default;

	GameStateStack& operator=(GameStateStack const& other) = default;

	GameStateStack& operator=(GameStateStack&& other) = default;

	template<class StateT, PushType Push, class... Args>
	inline void push(Args&&... args)
	{
		push(new StateT{std::forward<Args>(args)...}, Push);
	}

	void push(GameState* state, PushType pushType = PushType::PushWithoutPopping);

	void pop();

	void update(Seconds delta_time);

	void render();

	void clear();

	void remove(GameState* state);

	Game& game() const { return *_game; }

	void add_listener(GameStateStackListener* listener);

	void remove_listener(GameStateStackListener* listener);

private:
	template <typename F>
	inline void perform_f_on_stack(F f)
	{
		// we're going to loop through the stack backwards
		// if the top is silently pushed on, we will iterate again
		for(size_t i = _stack.size(); i-- > 0;)
		{
			f(_stack[i].first.get());

			// if we no longer need to continue to iterate
			if(_stack[i].second != PushType::PushWithoutPoppingSilenty)
				break;
		}
	}

	struct GameStateDeleter
	{
		inline void operator()(GameState* state) const
		{
			state->unload_resources();
			delete state;
		}
	};

	typedef std::unique_ptr<GameState, GameStateDeleter> GameStatePtrImpl;
	typedef std::pair<GameStatePtrImpl, PushType> GameStatePair;
	typedef std::vector<GameStatePair> StackImpl;
	typedef std::vector<GameStateStackListener*> ListenerArray;

	ListenerArray _listeners;
	StackImpl _stack;
	Game* _game;
};

template<class GameType>
static inline int run(int argc, char** argv)
{
	static_assert(std::is_base_of<Game, GameType>::value, "GameType must be a Game");
	GameType app;
	app.init(argc, argv);

	Seconds last_time = time_now();
	while (app.is_running())
	{
		Seconds current = time_now();
		Seconds frame_time = current - last_time;
		last_time = current;

		app.frame_start();
		app.update(frame_time);
		app.frame_end();
	}

	return app.error_state();
}
<commit_msg>Added a wrapper for the Render Target's getter in GameState<commit_after>#pragma once

#include <type_traits>
#include <functional>
#include <utility>
#include <vector>

#include <SFML/Graphics.hpp>
#include "imgui/imgui.h"

#include "Time.hpp"

struct Game
{
public:
	Game();

	virtual ~Game();

	Game(Game const& other) = delete;

	Game(Game&& other) = delete;

	Game& operator=(Game const& other) = delete;

	Game& operator=(Game&& other) = delete;

	virtual inline int error_state() const final
	{ return _error_state; }

	virtual inline bool is_running() const final
	{ return _is_running; }

	virtual inline sf::RenderTarget& target() final
	{ return _window; }

	virtual void quit(int errorCode = 0) final;

	virtual void init(int argc, char** argv);

	virtual void frame_start();

	virtual void process_event(sf::Event& e);

	virtual void update(Seconds delta_time);

	virtual void frame_end();

private:
	sf::RenderWindow _window;
	int _error_state;
	bool _is_running;
};

class GameState
{
	friend class GameStateStack;

public:
	inline GameState() : _game(nullptr)
	{ }

	virtual inline ~GameState()
	{ }

	GameState(GameState const& other) = delete;

	GameState(GameState&& other) = delete;

	GameState& operator=(GameState const& other) = delete;

	GameState& operator=(GameState&& other) = delete;

	virtual inline sf::RenderTarget& target() final
	{ return _game->target(); }

	virtual inline void init()
	{ }

	virtual inline void load_resources()
	{ }

	virtual inline void unload_resources()
	{ }

	virtual inline void update(Seconds)
	{ }

	virtual inline void render()
	{ }

	virtual inline void on_pause()
	{ }

	virtual inline void on_resume()
	{ }

protected:
	template<class GameType>
	inline GameType& game()
	{
		static_assert(std::is_base_of<Game, GameType>::value, "GameType must be a Game");
		return *dynamic_cast<GameType*>(_game);
	}

	template<class GameType>
	inline Game const& game() const
	{
		static_assert(std::is_base_of<Game, GameType>::value, "GameType must be a Game");
		return *dynamic_cast<GameType*>(_game);
	}

private:
	Game* _game;
};

/// \brief An enumeration used for a stack
///
/// This describes different ways to push
/// a game state on a stack
enum class PushType
{
	/// Pushes on a new GameState,
	/// without popping off the previous GameState
	/// Acts like a regular stack push operation
	PushWithoutPopping,

	/// Pushes on a new GameState, and pops off the
	/// previous GameState that was pushed on the stack
	/// (if there is a previous GameState).
	PushAndPop,

	/// Pushes on a new GameState,
	/// and pops off all previous states on the stack
	PushAndPopAllPreviousStates,

	/// Pushes on a new GameState, without popping off the last GameState
	/// Unlike `PushWithoutPopping`, this enumeration makes it so that
	/// the previous GameState is still updated, whilst the new GameState is updated
	PushWithoutPoppingSilenty
};

class GameStateStackListener
{
public:
	virtual inline ~GameStateStackListener()
	{ }

	virtual void on_gamestate_will_be_pushed(class GameStateStack& sender, GameState& state) = 0;

	virtual void on_gamestate_was_pushed(class GameStateStack& sender, GameState& state) = 0;

	virtual void on_gamestate_will_be_removed(class GameStateStack& sender, GameState& state) = 0;

	virtual void on_stack_will_be_popped(class GameStateStack& sender) = 0;

	virtual void on_stack_will_be_cleared(class GameStateStack& sender) = 0;
};

class GameStateStack
{
public:
	inline GameStateStack(Game* game) : _game(game)
	{ }

	inline ~GameStateStack()
	{ clear(); }

	GameStateStack(GameStateStack const& other) = default;

	GameStateStack(GameStateStack&& other) = default;

	GameStateStack& operator=(GameStateStack const& other) = default;

	GameStateStack& operator=(GameStateStack&& other) = default;

	template<class StateT, PushType Push, class... Args>
	inline void push(Args&&... args)
	{
		push(new StateT{std::forward<Args>(args)...}, Push);
	}

	void push(GameState* state, PushType pushType = PushType::PushWithoutPopping);

	void pop();

	void update(Seconds delta_time);

	void render();

	void clear();

	void remove(GameState* state);

	Game& game() const { return *_game; }

	void add_listener(GameStateStackListener* listener);

	void remove_listener(GameStateStackListener* listener);

private:
	template <typename F>
	inline void perform_f_on_stack(F f)
	{
		// we're going to loop through the stack backwards
		// if the top is silently pushed on, we will iterate again
		for(size_t i = _stack.size(); i-- > 0;)
		{
			f(_stack[i].first.get());

			// if we no longer need to continue to iterate
			if(_stack[i].second != PushType::PushWithoutPoppingSilenty)
				break;
		}
	}

	struct GameStateDeleter
	{
		inline void operator()(GameState* state) const
		{
			state->unload_resources();
			delete state;
		}
	};

	typedef std::unique_ptr<GameState, GameStateDeleter> GameStatePtrImpl;
	typedef std::pair<GameStatePtrImpl, PushType> GameStatePair;
	typedef std::vector<GameStatePair> StackImpl;
	typedef std::vector<GameStateStackListener*> ListenerArray;

	ListenerArray _listeners;
	StackImpl _stack;
	Game* _game;
};

template<class GameType>
static inline int run(int argc, char** argv)
{
	static_assert(std::is_base_of<Game, GameType>::value, "GameType must be a Game");
	GameType app;
	app.init(argc, argv);

	Seconds last_time = time_now();
	while (app.is_running())
	{
		Seconds current = time_now();
		Seconds frame_time = current - last_time;
		last_time = current;

		app.frame_start();
		app.update(frame_time);
		app.frame_end();
	}

	return app.error_state();
}
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2000-2002 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 "Xalan" 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) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#include "ICUBridgeCollationCompareFunctorImpl.hpp"
#include "ICUBridge.hpp"

#include <algorithm>
#include <cstdlib>

#include <Include/XalanAutoPtr.hpp>

#include <PlatformSupport/DOMStringHelper.hpp>
#include <PlatformSupport/XalanUnicode.hpp>

XALAN_CPP_NAMESPACE_BEGIN

const StylesheetExecutionContextDefault::DefaultCollationCompareFunctor		ICUBridgeCollationCompareFunctorImpl::s_defaultFunctor;

inline ICUBridgeCollationCompareFunctorImpl::CollatorType*
createCollator(
			UErrorCode&			theStatus,
			const Locale&		theLocale,
			XalanDOMString*		theLocaleName = 0)
{
	typedef ICUBridgeCollationCompareFunctorImpl::CollatorType	CollatorType;

	if (theLocaleName != 0)
	{
		*theLocaleName = theLocale.getName();

		// Replace _ with -, since that's what xml:lang specifies...
		XalanDOMString::size_type	theIndex;

		while((theIndex = indexOf(*theLocaleName, XalanUnicode::charLowLine)) != theLocaleName->length())
		{
			(*theLocaleName)[theIndex] = XalanUnicode::charHyphenMinus;
		}
	}

	return CollatorType::createInstance(theLocale, theStatus);
}

inline ICUBridgeCollationCompareFunctorImpl::CollatorType*
createCollator(
			UErrorCode&			theStatus,
			XalanDOMString*		theLocaleName = 0)
{
	const char*		theLang =
#if defined(XALAN_STRICT_ANSI_HEADERS)
			std::getenv("LANG");
#else
			getenv("LANG");
#endif

	if (theLang == 0)
	{
#if defined(XALAN_ICU_DEFAULT_LOCALE_PROBLEM)
		return createCollator(theStatus, Locale::US, theLocaleName);
#else
		return createCollator(theStatus, Locale::getDefault(), theLocaleName);
#endif
	}
	else
	{
		return createCollator(theStatus, Locale(theLang), theLocaleName);
	}
}

ICUBridgeCollationCompareFunctorImpl::ICUBridgeCollationCompareFunctorImpl(bool		fCacheCollators) :
	m_isValid(false),
	m_defaultCollator(0),
	m_defaultCollatorLocaleName(),
	m_cacheCollators(fCacheCollators),
	m_collatorCache()
{
	UErrorCode	theStatus = U_ZERO_ERROR;

	m_defaultCollator = createCollator(theStatus, &m_defaultCollatorLocaleName);

	if (U_SUCCESS(theStatus))
	{
		m_isValid = true;
	}
}

ICUBridgeCollationCompareFunctorImpl::~ICUBridgeCollationCompareFunctorImpl()
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::for_each;
#endif

	delete m_defaultCollator;

	for_each(
			m_collatorCache.begin(),
			m_collatorCache.end(),
			CollationCacheStruct::CollatorDeleteFunctor());
}

int
ICUBridgeCollationCompareFunctorImpl::doCompare(
			const CollatorType&		theCollator,
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS) const
{
#if defined(XALAN_USE_WCHAR_CAST_HACK)
	return theCollator.compare(
				(const wchar_t*)theLHS,
				length(theLHS),
				(const wchar_t*)theRHS,
				length(theRHS));
#else
	return theCollator.compare(
				theLHS,
				length(theLHS),
				theRHS,
				length(theRHS));
#endif
}

inline UColAttributeValue
caseOrderConvert(ICUBridgeCollationCompareFunctorImpl::eCaseOrder	theCaseOrder)
{
	switch(theCaseOrder)
	{
	case StylesheetExecutionContext::eLowerFirst:
		return UCOL_LOWER_FIRST;
		break;

	case StylesheetExecutionContext::eUpperFirst:
		return UCOL_UPPER_FIRST;
		break;

	case StylesheetExecutionContext::eDefault:
		break;

	default:
		assert(false);
		break;
	}

	return UCOL_DEFAULT;
}

int
ICUBridgeCollationCompareFunctorImpl::doDefaultCompare(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS) const
{
	if (isValid() == false)
	{
		return s_defaultFunctor(theLHS, theRHS, StylesheetExecutionContext::eDefault);
	}
	else
	{
		assert(m_defaultCollator != 0);

		return doCompare(*m_defaultCollator, theLHS, theRHS);
	}
}

inline ICUBridgeCollationCompareFunctorImpl::CollatorType*
createCollator(
			const XalanDOMChar*		theLocale,
			UErrorCode&				theStatus)
{
	assert(theLocale != 0);

	const XalanDOMString::size_type		theLength = length(theLocale);

	if (theLength >= ULOC_FULLNAME_CAPACITY)
	{
		theStatus = U_ILLEGAL_ARGUMENT_ERROR;

		return 0;
	}
	else
	{
#if defined(XALAN_NON_ASCII_PLATFORM)
		CharVectorType	theVector;

		TranscodeToLocalCodePage(theLocale, theVector, true);

		const char* const	theBuffer = c_str(theVector);
#else
		char	theBuffer[ULOC_FULLNAME_CAPACITY];

		// Since language names must be ASCII, this
		// is the cheapest way to "transcode"...
		for (unsigned int i = 0; i <= theLength; ++i)
		{
			theBuffer[i] = char(theLocale[i]);
		}
#endif
		return ICUBridgeCollationCompareFunctorImpl::CollatorType::createInstance(
					Locale::createFromName(theBuffer),
					theStatus);
	}
}

int
ICUBridgeCollationCompareFunctorImpl::doCompare(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			const XalanDOMChar*		theLocale,
			eCaseOrder				theCaseOrder) const
{
	UErrorCode	theStatus = U_ZERO_ERROR;

	XalanAutoPtr<CollatorType>	theCollator(createCollator(theLocale, theStatus));

	if (U_SUCCESS(theStatus))
	{
		assert(theCollator.get() != 0);

		return doCompare(
				*theCollator.get(),
				theLHS,
				theRHS,
				theCaseOrder);
	}
	else
	{
		return s_defaultFunctor(theLHS, theRHS, theCaseOrder);
	}
}

int
ICUBridgeCollationCompareFunctorImpl::doCompareCached(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			const XalanDOMChar*		theLocale,
			eCaseOrder				theCaseOrder) const
{
	CollatorType*	theCollator = getCachedCollator(theLocale);

	if (theCollator != 0)
	{
		return doCompare(*theCollator, theLHS, theRHS, theCaseOrder);
	}
	else
	{
		UErrorCode	theStatus = U_ZERO_ERROR;

		XalanAutoPtr<CollatorType>	theCollatorGuard(createCollator(theLocale, theStatus));

		if (U_SUCCESS(theStatus))
		{
			assert(theCollatorGuard.get() != 0);

			// OK, there was no error, so cache the instance...
			cacheCollator(theCollatorGuard.get(), theLocale);

			// Release the collator, since it's in the cache and
			// will be controlled by the cache...
			theCollator = theCollatorGuard.release();

			return doCompare(
					*theCollator,
					theLHS,
					theRHS,
					theCaseOrder);
		}
		else
		{
			return s_defaultFunctor(theLHS, theRHS, theCaseOrder);
		}
	}
}

int
ICUBridgeCollationCompareFunctorImpl::doCompare(
			CollatorType&			theCollator,
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			eCaseOrder				theCaseOrder) const
{
	UErrorCode	theStatus = U_ZERO_ERROR;

	theCollator.setAttribute(
				UCOL_CASE_FIRST,
				caseOrderConvert(theCaseOrder),
				theStatus);

#if defined(XALAN_USE_WCHAR_CAST_HACK)
	return theCollator.compare(
					(const wchar_t*)theLHS,
					length(theLHS),
					(const wchar_t*)theRHS,
					length(theRHS));
#else
	return theCollator.compare(
					theLHS,
					length(theLHS),
					theRHS,
					length(theRHS));
#endif
}

int
ICUBridgeCollationCompareFunctorImpl::operator()(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			eCaseOrder				theCaseOrder) const
{
	if (theCaseOrder == StylesheetExecutionContext::eDefault)
	{
		return doDefaultCompare(theLHS, theRHS);
	}
	else
	{
		return doCompare(
				theLHS,
				theRHS,
				c_wstr(m_defaultCollatorLocaleName),
				theCaseOrder);
	}
}

int
ICUBridgeCollationCompareFunctorImpl::operator()(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			const XalanDOMChar*		theLocale,
			eCaseOrder				theCaseOrder) const
{
	if (theCaseOrder == StylesheetExecutionContext::eDefault &&
		XalanDOMString::equals(m_defaultCollatorLocaleName, theLocale) == true)
	{
		return doDefaultCompare(theLHS, theRHS);
	}
	else if (m_cacheCollators == true)
	{
		return doCompareCached(theLHS, theRHS, theLocale, theCaseOrder);
	}
	else
	{
		return doCompare(theLHS, theRHS, theLocale, theCaseOrder);
	};
}

ICUBridgeCollationCompareFunctorImpl::CollatorType*
ICUBridgeCollationCompareFunctorImpl::getCachedCollator(const XalanDOMChar*		theLocale) const
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::find_if;
#endif

	CollatorCacheListType&		theNonConstCache =
#if defined(XALAN_NO_MUTABLE)
		(CollatorCacheListType*)m_collatorCache;
#else
		m_collatorCache;
#endif

	CollatorCacheListType::iterator	i =
		find_if(
			theNonConstCache.begin(),
			theNonConstCache.end(),
			CollationCacheStruct::CollatorFindFunctor(theLocale));

	if (i == theNonConstCache.end())
	{
		return 0;
	}
	else
	{
		// Let's do a quick check to see if we found the first entry.
		// If so, we don't have to update the cache, so just return the
		// appropriate value...
		const CollatorCacheListType::iterator	theBegin =
			theNonConstCache.begin();

		if (i == theBegin)
		{
			return (*i).m_collator;
		}
		else
		{
			// Save the collator, because splice() may invalidate
			// i.
			CollatorType* const		theCollator = (*i).m_collator;

			// Move the entry to the beginning the cache
			theNonConstCache.splice(theBegin, theNonConstCache, i);

			return theCollator;
		}
	}
}

void
ICUBridgeCollationCompareFunctorImpl::cacheCollator(
			CollatorType*			theCollator,
			const XalanDOMChar*		theLocale) const
{
	assert(theCollator != 0);
	assert(theLocale != 0);

	CollatorCacheListType&		theNonConstCache =
#if defined(XALAN_NO_MUTABLE)
		(CollatorCacheListType*)m_collatorCache;
#else
		m_collatorCache;
#endif

	// Is the cache full?
	if (theNonConstCache.size() == eCacheMax)
	{
		// Yes, so guard the collator instance, in case pop_back() throws...
		XalanAutoPtr<CollatorType>	theCollatorGuard(theNonConstCache.back().m_collator);

		theNonConstCache.pop_back();
	}

	theNonConstCache.push_front(CollatorCacheListType::value_type());

	CollatorCacheListType::value_type&		theEntry =
		theNonConstCache.front();

	// Set the locale first, since that might throw an exception...
	theEntry.m_locale = theLocale;

	theEntry.m_collator = theCollator;
}

XALAN_CPP_NAMESPACE_END
<commit_msg>New ifdef for 64-bit AIX 5.1.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2000-2002 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 "Xalan" 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) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#include "ICUBridgeCollationCompareFunctorImpl.hpp"
#include "ICUBridge.hpp"

#include <algorithm>
#include <cstdlib>

#include <Include/XalanAutoPtr.hpp>

#include <PlatformSupport/DOMStringHelper.hpp>
#include <PlatformSupport/XalanUnicode.hpp>

XALAN_CPP_NAMESPACE_BEGIN

const StylesheetExecutionContextDefault::DefaultCollationCompareFunctor		ICUBridgeCollationCompareFunctorImpl::s_defaultFunctor;

inline ICUBridgeCollationCompareFunctorImpl::CollatorType*
createCollator(
			UErrorCode&			theStatus,
			const Locale&		theLocale,
			XalanDOMString*		theLocaleName = 0)
{
	typedef ICUBridgeCollationCompareFunctorImpl::CollatorType	CollatorType;

	if (theLocaleName != 0)
	{
		*theLocaleName = theLocale.getName();

		// Replace _ with -, since that's what xml:lang specifies...
		XalanDOMString::size_type	theIndex;

		while((theIndex = indexOf(*theLocaleName, XalanUnicode::charLowLine)) != theLocaleName->length())
		{
			(*theLocaleName)[theIndex] = XalanUnicode::charHyphenMinus;
		}
	}

	return CollatorType::createInstance(theLocale, theStatus);
}

inline ICUBridgeCollationCompareFunctorImpl::CollatorType*
createCollator(
			UErrorCode&			theStatus,
			XalanDOMString*		theLocaleName = 0)
{
	const char*		theLang =
#if defined(XALAN_STRICT_ANSI_HEADERS)
			std::getenv("LANG");
#else
			getenv("LANG");
#endif

	if (theLang == 0)
	{
#if defined(XALAN_ICU_DEFAULT_LOCALE_PROBLEM)
		return createCollator(theStatus, Locale::US, theLocaleName);
#else
		return createCollator(theStatus, Locale::getDefault(), theLocaleName);
#endif
	}
	else
	{
		return createCollator(theStatus, Locale(theLang), theLocaleName);
	}
}

ICUBridgeCollationCompareFunctorImpl::ICUBridgeCollationCompareFunctorImpl(bool		fCacheCollators) :
	m_isValid(false),
	m_defaultCollator(0),
	m_defaultCollatorLocaleName(),
	m_cacheCollators(fCacheCollators),
	m_collatorCache()
{
	UErrorCode	theStatus = U_ZERO_ERROR;

	m_defaultCollator = createCollator(theStatus, &m_defaultCollatorLocaleName);

	if (U_SUCCESS(theStatus))
	{
		m_isValid = true;
	}
}

ICUBridgeCollationCompareFunctorImpl::~ICUBridgeCollationCompareFunctorImpl()
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::for_each;
#endif

	delete m_defaultCollator;

	for_each(
			m_collatorCache.begin(),
			m_collatorCache.end(),
			CollationCacheStruct::CollatorDeleteFunctor());
}

int
ICUBridgeCollationCompareFunctorImpl::doCompare(
			const CollatorType&		theCollator,
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS) const
{
#if defined(XALAN_USE_WCHAR_CAST_HACK) && defined(U_WCHAR_IS_UTF16)
	return theCollator.compare(
				(const wchar_t*)theLHS,
				length(theLHS),
				(const wchar_t*)theRHS,
				length(theRHS));
#else
	return theCollator.compare(
				theLHS,
				length(theLHS),
				theRHS,
				length(theRHS));
#endif
}

inline UColAttributeValue
caseOrderConvert(ICUBridgeCollationCompareFunctorImpl::eCaseOrder	theCaseOrder)
{
	switch(theCaseOrder)
	{
	case StylesheetExecutionContext::eLowerFirst:
		return UCOL_LOWER_FIRST;
		break;

	case StylesheetExecutionContext::eUpperFirst:
		return UCOL_UPPER_FIRST;
		break;

	case StylesheetExecutionContext::eDefault:
		break;

	default:
		assert(false);
		break;
	}

	return UCOL_DEFAULT;
}

int
ICUBridgeCollationCompareFunctorImpl::doDefaultCompare(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS) const
{
	if (isValid() == false)
	{
		return s_defaultFunctor(theLHS, theRHS, StylesheetExecutionContext::eDefault);
	}
	else
	{
		assert(m_defaultCollator != 0);

		return doCompare(*m_defaultCollator, theLHS, theRHS);
	}
}

inline ICUBridgeCollationCompareFunctorImpl::CollatorType*
createCollator(
			const XalanDOMChar*		theLocale,
			UErrorCode&				theStatus)
{
	assert(theLocale != 0);

	const XalanDOMString::size_type		theLength = length(theLocale);

	if (theLength >= ULOC_FULLNAME_CAPACITY)
	{
		theStatus = U_ILLEGAL_ARGUMENT_ERROR;

		return 0;
	}
	else
	{
#if defined(XALAN_NON_ASCII_PLATFORM)
		CharVectorType	theVector;

		TranscodeToLocalCodePage(theLocale, theVector, true);

		const char* const	theBuffer = c_str(theVector);
#else
		char	theBuffer[ULOC_FULLNAME_CAPACITY];

		// Since language names must be ASCII, this
		// is the cheapest way to "transcode"...
		for (unsigned int i = 0; i <= theLength; ++i)
		{
			theBuffer[i] = char(theLocale[i]);
		}
#endif
		return ICUBridgeCollationCompareFunctorImpl::CollatorType::createInstance(
					Locale::createFromName(theBuffer),
					theStatus);
	}
}

int
ICUBridgeCollationCompareFunctorImpl::doCompare(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			const XalanDOMChar*		theLocale,
			eCaseOrder				theCaseOrder) const
{
	UErrorCode	theStatus = U_ZERO_ERROR;

	XalanAutoPtr<CollatorType>	theCollator(createCollator(theLocale, theStatus));

	if (U_SUCCESS(theStatus))
	{
		assert(theCollator.get() != 0);

		return doCompare(
				*theCollator.get(),
				theLHS,
				theRHS,
				theCaseOrder);
	}
	else
	{
		return s_defaultFunctor(theLHS, theRHS, theCaseOrder);
	}
}

int
ICUBridgeCollationCompareFunctorImpl::doCompareCached(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			const XalanDOMChar*		theLocale,
			eCaseOrder				theCaseOrder) const
{
	CollatorType*	theCollator = getCachedCollator(theLocale);

	if (theCollator != 0)
	{
		return doCompare(*theCollator, theLHS, theRHS, theCaseOrder);
	}
	else
	{
		UErrorCode	theStatus = U_ZERO_ERROR;

		XalanAutoPtr<CollatorType>	theCollatorGuard(createCollator(theLocale, theStatus));

		if (U_SUCCESS(theStatus))
		{
			assert(theCollatorGuard.get() != 0);

			// OK, there was no error, so cache the instance...
			cacheCollator(theCollatorGuard.get(), theLocale);

			// Release the collator, since it's in the cache and
			// will be controlled by the cache...
			theCollator = theCollatorGuard.release();

			return doCompare(
					*theCollator,
					theLHS,
					theRHS,
					theCaseOrder);
		}
		else
		{
			return s_defaultFunctor(theLHS, theRHS, theCaseOrder);
		}
	}
}

int
ICUBridgeCollationCompareFunctorImpl::doCompare(
			CollatorType&			theCollator,
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			eCaseOrder				theCaseOrder) const
{
	UErrorCode	theStatus = U_ZERO_ERROR;

	theCollator.setAttribute(
				UCOL_CASE_FIRST,
				caseOrderConvert(theCaseOrder),
				theStatus);

#if defined(XALAN_USE_WCHAR_CAST_HACK) && defined(U_WCHAR_IS_UTF16)
	return theCollator.compare(
					(const wchar_t*)theLHS,
					length(theLHS),
					(const wchar_t*)theRHS,
					length(theRHS));
#else
	return theCollator.compare(
					theLHS,
					length(theLHS),
					theRHS,
					length(theRHS));
#endif
}

int
ICUBridgeCollationCompareFunctorImpl::operator()(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			eCaseOrder				theCaseOrder) const
{
	if (theCaseOrder == StylesheetExecutionContext::eDefault)
	{
		return doDefaultCompare(theLHS, theRHS);
	}
	else
	{
		return doCompare(
				theLHS,
				theRHS,
				c_wstr(m_defaultCollatorLocaleName),
				theCaseOrder);
	}
}

int
ICUBridgeCollationCompareFunctorImpl::operator()(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			const XalanDOMChar*		theLocale,
			eCaseOrder				theCaseOrder) const
{
	if (theCaseOrder == StylesheetExecutionContext::eDefault &&
		XalanDOMString::equals(m_defaultCollatorLocaleName, theLocale) == true)
	{
		return doDefaultCompare(theLHS, theRHS);
	}
	else if (m_cacheCollators == true)
	{
		return doCompareCached(theLHS, theRHS, theLocale, theCaseOrder);
	}
	else
	{
		return doCompare(theLHS, theRHS, theLocale, theCaseOrder);
	};
}

ICUBridgeCollationCompareFunctorImpl::CollatorType*
ICUBridgeCollationCompareFunctorImpl::getCachedCollator(const XalanDOMChar*		theLocale) const
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::find_if;
#endif

	CollatorCacheListType&		theNonConstCache =
#if defined(XALAN_NO_MUTABLE)
		(CollatorCacheListType*)m_collatorCache;
#else
		m_collatorCache;
#endif

	CollatorCacheListType::iterator	i =
		find_if(
			theNonConstCache.begin(),
			theNonConstCache.end(),
			CollationCacheStruct::CollatorFindFunctor(theLocale));

	if (i == theNonConstCache.end())
	{
		return 0;
	}
	else
	{
		// Let's do a quick check to see if we found the first entry.
		// If so, we don't have to update the cache, so just return the
		// appropriate value...
		const CollatorCacheListType::iterator	theBegin =
			theNonConstCache.begin();

		if (i == theBegin)
		{
			return (*i).m_collator;
		}
		else
		{
			// Save the collator, because splice() may invalidate
			// i.
			CollatorType* const		theCollator = (*i).m_collator;

			// Move the entry to the beginning the cache
			theNonConstCache.splice(theBegin, theNonConstCache, i);

			return theCollator;
		}
	}
}

void
ICUBridgeCollationCompareFunctorImpl::cacheCollator(
			CollatorType*			theCollator,
			const XalanDOMChar*		theLocale) const
{
	assert(theCollator != 0);
	assert(theLocale != 0);

	CollatorCacheListType&		theNonConstCache =
#if defined(XALAN_NO_MUTABLE)
		(CollatorCacheListType*)m_collatorCache;
#else
		m_collatorCache;
#endif

	// Is the cache full?
	if (theNonConstCache.size() == eCacheMax)
	{
		// Yes, so guard the collator instance, in case pop_back() throws...
		XalanAutoPtr<CollatorType>	theCollatorGuard(theNonConstCache.back().m_collator);

		theNonConstCache.pop_back();
	}

	theNonConstCache.push_front(CollatorCacheListType::value_type());

	CollatorCacheListType::value_type&		theEntry =
		theNonConstCache.front();

	// Set the locale first, since that might throw an exception...
	theEntry.m_locale = theLocale;

	theEntry.m_collator = theCollator;
}

XALAN_CPP_NAMESPACE_END
<|endoftext|>