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

#include "../ComObject.h"
#include "../DataStream.h"

#include "Direct3D9Exception.h"

#include "Device.h"
#include "Mesh.h"
#include "UVAtlas.h"

using namespace System;
using namespace System::Runtime::InteropServices;

namespace SlimDX
{
namespace Direct3D9
{
	HRESULT WINAPI NativeAtlasCallback( FLOAT fPercentDone, LPVOID lpUserContext )
	{
		GCHandle handle = GCHandle::FromIntPtr( IntPtr( lpUserContext ) );
		Predicate<float>^ callback = safe_cast<Predicate<float>^>( handle.Target );
		HRESULT result;

		try
		{
			result = callback( fPercentDone ) ? S_OK : E_FAIL;
		}
		catch( Exception^ )
		{
			result = E_FAIL;
		}

		return result;
	}

	UVAtlasOutput^ UVAtlas::Create( Mesh^ mesh, int maxChartCount, float maxStretch, int width, int height, float gutter, int textureIndex,
				array<int>^ falseEdges, array<float>^ integratedMetricTensors, UVAtlasQuality quality )
	{
		return Create( mesh, maxChartCount, maxStretch, width, height, gutter, textureIndex, falseEdges, integratedMetricTensors, quality, nullptr, 0.0001f );
	}

	UVAtlasOutput^ UVAtlas::Create( Mesh^ mesh, int maxChartCount, float maxStretch, int width, int height, float gutter, int textureIndex,
				array<int>^ falseEdges, array<float>^ integratedMetricTensors, UVAtlasQuality quality, System::Predicate<float>^ callback, float callbackFrequency )
	{
		ID3DXMesh *meshOut;
		ID3DXBuffer *facePartitioning;
		ID3DXBuffer *vertexRemap;
		FLOAT maxStretchOut;
		UINT numChartsOut;
		HRESULT hr;

		pin_ptr<int> pinnedAdj;
		pin_ptr<int> pinnedFalseEdges;
		pin_ptr<float> pinnedIMTs;

		DWORD *inputAdjacencyPtr = NULL;
		DWORD *falseEdgesPtr = NULL;
		FLOAT *imtPtr = NULL;

		array<int>^ adj = mesh->GetAdjacency();

		if( adj != nullptr )
		{
			pinnedAdj = &adj[0];
			inputAdjacencyPtr = reinterpret_cast<DWORD*>( pinnedAdj );
		}

		if( falseEdges != nullptr )
		{
			pinnedFalseEdges = &falseEdges[0];
			falseEdgesPtr = reinterpret_cast<DWORD*>( pinnedFalseEdges );
		}

		if( integratedMetricTensors != nullptr )
		{
			pinnedIMTs = &integratedMetricTensors[0];
			imtPtr = pinnedIMTs;
		}

		if( callback != nullptr )
		{
			GCHandle handle = GCHandle::Alloc(callback);

			hr = D3DXUVAtlasCreate( mesh->InternalPointer, maxChartCount, maxStretch, width, height, gutter, textureIndex,
				inputAdjacencyPtr, falseEdgesPtr, imtPtr, NativeAtlasCallback, callbackFrequency, Marshal::GetFunctionPointerForDelegate(callback).ToPointer(),
				static_cast<DWORD>( quality ), &meshOut, &facePartitioning, &vertexRemap, &maxStretchOut, &numChartsOut );

			handle.Free();
		}
		else
		{
			hr = D3DXUVAtlasCreate( mesh->InternalPointer, maxChartCount, maxStretch, width, height, gutter, textureIndex,
				inputAdjacencyPtr, falseEdgesPtr, imtPtr, NULL, callbackFrequency, NULL, static_cast<DWORD>( quality ), &meshOut,
				&facePartitioning, &vertexRemap, &maxStretchOut, &numChartsOut );
		}

		if( RECORD_D3D9( hr ).IsFailure )
			return nullptr;

		return gcnew UVAtlasOutput( Mesh::FromPointer( meshOut ), gcnew DataStream( facePartitioning ), gcnew DataStream( vertexRemap ),
			maxStretchOut, numChartsOut );
	}

	UVAtlasOutput^ UVAtlas::Partition( Mesh^ mesh, int maxChartCount, float maxStretch, int textureIndex,
				array<int>^ falseEdges, array<float>^ integratedMetricTensors, UVAtlasQuality quality, [Out] DataStream^% partitionAdjacency )
	{
		return Partition( mesh, maxChartCount, maxStretch, textureIndex, falseEdges, integratedMetricTensors, quality,
			partitionAdjacency, nullptr, 0.0001f );
	}

	UVAtlasOutput^ UVAtlas::Partition( Mesh^ mesh, int maxChartCount, float maxStretch, int textureIndex,
				array<int>^ falseEdges, array<float>^ integratedMetricTensors, UVAtlasQuality quality, [Out] DataStream^% partitionAdjacency,
				System::Predicate<float>^ callback, float callbackFrequency )
	{
		ID3DXMesh *meshOut;
		ID3DXBuffer *facePartitioning;
		ID3DXBuffer *vertexRemap;
		ID3DXBuffer *partitionResult;
		FLOAT maxStretchOut;
		UINT numChartsOut;
		HRESULT hr;

		pin_ptr<int> pinnedAdj;
		pin_ptr<int> pinnedFalseEdges;
		pin_ptr<float> pinnedIMTs;

		DWORD *inputAdjacencyPtr = NULL;
		DWORD *falseEdgesPtr = NULL;
		FLOAT *imtPtr = NULL;

		array<int>^ adj = mesh->GetAdjacency();

		if( adj != nullptr )
		{
			pinnedAdj = &adj[0];
			inputAdjacencyPtr = reinterpret_cast<DWORD*>( pinnedAdj );
		}

		if( falseEdges != nullptr )
		{
			pinnedFalseEdges = &falseEdges[0];
			falseEdgesPtr = reinterpret_cast<DWORD*>( pinnedFalseEdges );
		}

		if( integratedMetricTensors != nullptr )
		{
			pinnedIMTs = &integratedMetricTensors[0];
			imtPtr = pinnedIMTs;
		}

		if( callback != nullptr )
		{
			GCHandle handle = GCHandle::Alloc(callback);

			hr = D3DXUVAtlasPartition( mesh->InternalPointer, maxChartCount, maxStretch, textureIndex,
				inputAdjacencyPtr, falseEdgesPtr, imtPtr, NativeAtlasCallback, callbackFrequency, Marshal::GetFunctionPointerForDelegate(callback).ToPointer(),
				static_cast<DWORD>( quality ), &meshOut, &facePartitioning, &vertexRemap, &partitionResult, &maxStretchOut, &numChartsOut );

			handle.Free();
		}
		else
		{
			hr = D3DXUVAtlasPartition( mesh->InternalPointer, maxChartCount, maxStretch, textureIndex,
				inputAdjacencyPtr, falseEdgesPtr, imtPtr, NULL, callbackFrequency, NULL, static_cast<DWORD>( quality ), &meshOut,
				&facePartitioning, &vertexRemap, &partitionResult, &maxStretchOut, &numChartsOut );
		}

		if( RECORD_D3D9( hr ).IsFailure )
		{
			partitionAdjacency = nullptr;
			return nullptr;
		}

		partitionAdjacency = gcnew DataStream( partitionResult );

		return gcnew UVAtlasOutput( Mesh::FromPointer( meshOut ), gcnew DataStream( facePartitioning ), gcnew DataStream( vertexRemap ),
			maxStretchOut, numChartsOut );
	}

	Result UVAtlas::Pack( Mesh^ mesh, int width, int height, float gutter, int textureIndex, array<int>^ partitionAdjacency, UVAtlasQuality quality, DataStream^ facePartitioning )
	{
		return Pack( mesh, width, height, gutter, textureIndex, partitionAdjacency, quality, facePartitioning, nullptr, 0.0001f );
	}

	Result UVAtlas::Pack( Mesh^ mesh, int width, int height, float gutter, int textureIndex, array<int>^ partitionAdjacency,
		UVAtlasQuality quality, DataStream^ facePartitioning, System::Predicate<float>^ callback, float callbackFrequency )
	{
		HRESULT hr;
		pin_ptr<int> pinnedAdj = &partitionAdjacency[0];

		if( callback != nullptr )
		{
			GCHandle handle = GCHandle::Alloc(callback);

			hr = D3DXUVAtlasPack( mesh->InternalPointer, width, height, gutter, textureIndex,
				reinterpret_cast<DWORD*>( pinnedAdj ), NativeAtlasCallback, callbackFrequency, Marshal::GetFunctionPointerForDelegate(callback).ToPointer(),
				static_cast<DWORD>( quality ), facePartitioning->GetD3DBuffer() );

			handle.Free();
		}
		else
		{
			hr = D3DXUVAtlasPack( mesh->InternalPointer, width, height, gutter, textureIndex,
				reinterpret_cast<DWORD*>( pinnedAdj ), NULL, callbackFrequency, NULL,
				static_cast<DWORD>( quality ), facePartitioning->GetD3DBuffer() );
		}

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

#include "../ComObject.h"
#include "../DataStream.h"

#include "Direct3D9Exception.h"

#include "Device.h"
#include "Mesh.h"
#include "UVAtlas.h"

using namespace System;
using namespace System::Runtime::InteropServices;

namespace SlimDX
{
namespace Direct3D9
{
	HRESULT WINAPI NativeAtlasCallback( FLOAT fPercentDone, LPVOID lpUserContext )
	{
		GCHandle handle = GCHandle::FromIntPtr( IntPtr( lpUserContext ) );
		Predicate<float>^ callback = safe_cast<Predicate<float>^>( handle.Target );
		HRESULT result;

		try
		{
			result = callback( fPercentDone ) ? S_OK : E_FAIL;
		}
		catch( Exception^ )
		{
			result = E_FAIL;
		}

		return result;
	}

	UVAtlasOutput^ UVAtlas::Create( Mesh^ mesh, int maxChartCount, float maxStretch, int width, int height, float gutter, int textureIndex,
				array<int>^ falseEdges, array<float>^ integratedMetricTensors, UVAtlasQuality quality )
	{
		return Create( mesh, maxChartCount, maxStretch, width, height, gutter, textureIndex, falseEdges, integratedMetricTensors, quality, nullptr, 0.0001f );
	}

	UVAtlasOutput^ UVAtlas::Create( Mesh^ mesh, int maxChartCount, float maxStretch, int width, int height, float gutter, int textureIndex,
				array<int>^ falseEdges, array<float>^ integratedMetricTensors, UVAtlasQuality quality, System::Predicate<float>^ callback, float callbackFrequency )
	{
		ID3DXMesh *meshOut;
		ID3DXBuffer *facePartitioning;
		ID3DXBuffer *vertexRemap;
		FLOAT maxStretchOut;
		UINT numChartsOut;
		HRESULT hr;

		pin_ptr<int> pinnedAdj;
		pin_ptr<int> pinnedFalseEdges;
		pin_ptr<float> pinnedIMTs;

		DWORD *inputAdjacencyPtr = NULL;
		DWORD *falseEdgesPtr = NULL;
		FLOAT *imtPtr = NULL;

		array<int>^ adj = mesh->GetAdjacency();

		if( adj != nullptr )
		{
			pinnedAdj = &adj[0];
			inputAdjacencyPtr = reinterpret_cast<DWORD*>( pinnedAdj );
		}

		if( falseEdges != nullptr )
		{
			pinnedFalseEdges = &falseEdges[0];
			falseEdgesPtr = reinterpret_cast<DWORD*>( pinnedFalseEdges );
		}

		if( integratedMetricTensors != nullptr )
		{
			pinnedIMTs = &integratedMetricTensors[0];
			imtPtr = pinnedIMTs;
		}

		if( callback != nullptr )
		{
			GCHandle handle = GCHandle::Alloc(callback);

			hr = D3DXUVAtlasCreate( mesh->InternalPointer, maxChartCount, maxStretch, width, height, gutter, textureIndex,
				inputAdjacencyPtr, falseEdgesPtr, imtPtr, NativeAtlasCallback, callbackFrequency, GCHandle::ToIntPtr(handle).ToPointer(),
				static_cast<DWORD>( quality ), &meshOut, &facePartitioning, &vertexRemap, &maxStretchOut, &numChartsOut );

			handle.Free();
		}
		else
		{
			hr = D3DXUVAtlasCreate( mesh->InternalPointer, maxChartCount, maxStretch, width, height, gutter, textureIndex,
				inputAdjacencyPtr, falseEdgesPtr, imtPtr, NULL, callbackFrequency, NULL, static_cast<DWORD>( quality ), &meshOut,
				&facePartitioning, &vertexRemap, &maxStretchOut, &numChartsOut );
		}

		if( RECORD_D3D9( hr ).IsFailure )
			return nullptr;

		return gcnew UVAtlasOutput( Mesh::FromPointer( meshOut ), gcnew DataStream( facePartitioning ), gcnew DataStream( vertexRemap ),
			maxStretchOut, numChartsOut );
	}

	UVAtlasOutput^ UVAtlas::Partition( Mesh^ mesh, int maxChartCount, float maxStretch, int textureIndex,
				array<int>^ falseEdges, array<float>^ integratedMetricTensors, UVAtlasQuality quality, [Out] DataStream^% partitionAdjacency )
	{
		return Partition( mesh, maxChartCount, maxStretch, textureIndex, falseEdges, integratedMetricTensors, quality,
			partitionAdjacency, nullptr, 0.0001f );
	}

	UVAtlasOutput^ UVAtlas::Partition( Mesh^ mesh, int maxChartCount, float maxStretch, int textureIndex,
				array<int>^ falseEdges, array<float>^ integratedMetricTensors, UVAtlasQuality quality, [Out] DataStream^% partitionAdjacency,
				System::Predicate<float>^ callback, float callbackFrequency )
	{
		ID3DXMesh *meshOut;
		ID3DXBuffer *facePartitioning;
		ID3DXBuffer *vertexRemap;
		ID3DXBuffer *partitionResult;
		FLOAT maxStretchOut;
		UINT numChartsOut;
		HRESULT hr;

		pin_ptr<int> pinnedAdj;
		pin_ptr<int> pinnedFalseEdges;
		pin_ptr<float> pinnedIMTs;

		DWORD *inputAdjacencyPtr = NULL;
		DWORD *falseEdgesPtr = NULL;
		FLOAT *imtPtr = NULL;

		array<int>^ adj = mesh->GetAdjacency();

		if( adj != nullptr )
		{
			pinnedAdj = &adj[0];
			inputAdjacencyPtr = reinterpret_cast<DWORD*>( pinnedAdj );
		}

		if( falseEdges != nullptr )
		{
			pinnedFalseEdges = &falseEdges[0];
			falseEdgesPtr = reinterpret_cast<DWORD*>( pinnedFalseEdges );
		}

		if( integratedMetricTensors != nullptr )
		{
			pinnedIMTs = &integratedMetricTensors[0];
			imtPtr = pinnedIMTs;
		}

		if( callback != nullptr )
		{
			GCHandle handle = GCHandle::Alloc(callback);

			hr = D3DXUVAtlasPartition( mesh->InternalPointer, maxChartCount, maxStretch, textureIndex,
				inputAdjacencyPtr, falseEdgesPtr, imtPtr, NativeAtlasCallback, callbackFrequency, GCHandle::ToIntPtr(handle).ToPointer(),
				static_cast<DWORD>( quality ), &meshOut, &facePartitioning, &vertexRemap, &partitionResult, &maxStretchOut, &numChartsOut );

			handle.Free();
		}
		else
		{
			hr = D3DXUVAtlasPartition( mesh->InternalPointer, maxChartCount, maxStretch, textureIndex,
				inputAdjacencyPtr, falseEdgesPtr, imtPtr, NULL, callbackFrequency, NULL, static_cast<DWORD>( quality ), &meshOut,
				&facePartitioning, &vertexRemap, &partitionResult, &maxStretchOut, &numChartsOut );
		}

		if( RECORD_D3D9( hr ).IsFailure )
		{
			partitionAdjacency = nullptr;
			return nullptr;
		}

		partitionAdjacency = gcnew DataStream( partitionResult );

		return gcnew UVAtlasOutput( Mesh::FromPointer( meshOut ), gcnew DataStream( facePartitioning ), gcnew DataStream( vertexRemap ),
			maxStretchOut, numChartsOut );
	}

	Result UVAtlas::Pack( Mesh^ mesh, int width, int height, float gutter, int textureIndex, array<int>^ partitionAdjacency, UVAtlasQuality quality, DataStream^ facePartitioning )
	{
		return Pack( mesh, width, height, gutter, textureIndex, partitionAdjacency, quality, facePartitioning, nullptr, 0.0001f );
	}

	Result UVAtlas::Pack( Mesh^ mesh, int width, int height, float gutter, int textureIndex, array<int>^ partitionAdjacency,
		UVAtlasQuality quality, DataStream^ facePartitioning, System::Predicate<float>^ callback, float callbackFrequency )
	{
		HRESULT hr;
		pin_ptr<int> pinnedAdj = &partitionAdjacency[0];

		if( callback != nullptr )
		{
			GCHandle handle = GCHandle::Alloc(callback);

			hr = D3DXUVAtlasPack( mesh->InternalPointer, width, height, gutter, textureIndex,
				reinterpret_cast<DWORD*>( pinnedAdj ), NativeAtlasCallback, callbackFrequency, GCHandle::ToIntPtr(handle).ToPointer(),
				static_cast<DWORD>( quality ), facePartitioning->GetD3DBuffer() );

			handle.Free();
		}
		else
		{
			hr = D3DXUVAtlasPack( mesh->InternalPointer, width, height, gutter, textureIndex,
				reinterpret_cast<DWORD*>( pinnedAdj ), NULL, callbackFrequency, NULL,
				static_cast<DWORD>( quality ), facePartitioning->GetD3DBuffer() );
		}

		return RECORD_D3D9( hr );
	}
}
}<|endoftext|>


<commit_before>#include "PlayerEntity.h"

#include "EntityFactory.h"

#include <SceneNode.h>
#include <LeakReport.h>
#include <Sprite.h>
#include "GameScene.h"

#include <Box2D/Common/b2Math.h>

ENTITY_CREATOR("Player", PlayerEntity)

PlayerEntity::PlayerEntity():
	SpriteEntity("Player", "Player"),
	eItem(ItemTypes::NONE),
	fpMove(0),
	fpLandTime(0),
	pIcon(NULL)
{
	//empty
}

PlayerEntity::~PlayerEntity()
{
	gScene->Remove(pIcon);
	Delete(pIcon);

	pInput->RemoveKeyboardListener(this);
	gPhysics->DestroyBody(pBody);
}

void PlayerEntity::Load(Seed::IMetadataObject &metadata, Seed::SceneNode *sprites)
{
	SpriteEntity::Load(metadata, sprites);
	pSprite->SetZ(-10);

	pIcon = New(Sprite(*static_cast<Sprite *>(sprites->GetChildByName("Heart"))));
	pIcon->SetPosition(0, 0);
	pIcon->SetVisible(false);
	gScene->Add(pIcon);

	b2Vec2 customSize(40, 46);

	pBody = gPhysics->CreateBody(pSprite, &customSize);
	pBody->SetFixedRotation(true);
	pBody->GetFixtureList()->SetUserData(this);

	pInput->AddKeyboardListener(this);
	fVelocity = 5.0f;
	vPlayerVectorDirection = VECTOR_ZERO;
}

Vector3f PlayerEntity::GetPosition()
{
	return pSprite->GetPosition();
}

b2Vec2 PlayerEntity::GetBodyPosition() const
{
	return pBody->GetPosition();
}

Sprite *PlayerEntity::GetSprite() const
{
	return pSprite;
}

void PlayerEntity::Update(f32 dt)
{
	pIcon->SetPosition(pSprite->GetPosition() + Vector3f(0, -40, 0));

	b2Vec2 vel = pBody->GetLinearVelocity();

	bool ground = this->CheckGround();

	if(fpMove != 0)
	{
		vel.x = 5 * fpMove;
		pBody->SetLinearVelocity(vel);
	}

	if (iPreviousState ==JUMP && ground)
	{
		SetState(LAND);
		fpLandTime = 0.3f;
	}

	if(iCurrentState != JUMP && !ground)
	{
		this->SetState(JUMP);
	}

	if(fpLandTime > 0 && iCurrentState == LAND)
	{
		fpLandTime -= dt;
		if(fpLandTime <= 0)
		{
			if(fpMove != 0)
				this->SetState(RUN);
			else
				this->SetState(IDLE);
		}
	}

	if (iCurrentState == iPreviousState)
		return;

	if (iCurrentState == JUMP)
	{
		pSprite->SetAnimation("Jump");
	}
	else if (iCurrentState == LAND)
	{
		pSprite->SetAnimation("Land");
	}
	else if (iCurrentState == RUN)
	{
		pSprite->SetAnimation("Run");
	}
	else
	{
		pSprite->SetAnimation("Idle");
	}

	iPreviousState = iCurrentState;
}

void PlayerEntity::OnInputKeyboardPress(const EventInputKeyboard *ev)
{
	Key k = ev->GetKey();

	b2Vec2 vel = pBody->GetLinearVelocity();

	if ((k == Seed::KeyUp || k == Seed::KeyW) && iCurrentState != JUMP)
	{
		SetState(JUMP);
		pBody->ApplyForce(b2Vec2(0,500), pBody->GetWorldCenter());
	}

	if (k == Seed::KeyLeft || k == Seed::KeyA)
	{
		SetState(RUN);

		fpMove = -1;

		// Change the scale to turn the player sprite
		if (pSprite->GetScaleX() > 0)
			pSprite->SetScaleX(pSprite->GetScaleX() * -1);
	}

	if (k == Seed::KeyRight || k == Seed::KeyD)
	{
		SetState(RUN);

		fpMove = 1;

		// Change the scale to turn the player sprite
		if (pSprite->GetScaleX() < 0)
			pSprite->SetScaleX(pSprite->GetScaleX() * -1);
	}

	if (k == Seed::KeyDown || k == Seed::KeyS)
	{
		// Sum the normalized vector down with the current vector
		// Maybe later, maybe if the player can duck
	}

	//pSprite->AddPosition(vPlayerVectorDirection * fVelocity);
}

void PlayerEntity::OnInputKeyboardRelease(const EventInputKeyboard *ev)
{
	Key k = ev->GetKey();

	b2Vec2 vel = pBody->GetLinearVelocity();
	vel.x = 0;

	// Remove the directions
	if (k == Seed::KeyUp|| k == Seed::KeyW)
	{

	}

	if (k == Seed::KeyLeft|| k == Seed::KeyA)
	{
		pBody->SetLinearVelocity(vel);
		fpMove = 0;

		if (CheckGround())
			SetState(IDLE);
		else
			SetState(JUMP);
	}

	if (k == Seed::KeyRight|| k == Seed::KeyD)
	{
		pBody->SetLinearVelocity(vel);
		fpMove = 0;

		if (CheckGround())
			SetState(IDLE);
		else
			SetState(JUMP);
	}

	if (k == Seed::KeyDown|| k == Seed::KeyS)
	{
		vPlayerVectorDirection -= VECTOR_DOWN;
	}
}

bool PlayerEntity::CheckGround()
{
	if(gPhysics->RayCast(pBody, b2Vec2(0, 0.32f)))
		return true;
	if(gPhysics->RayCast(pBody, b2Vec2(16, 0.32f)))
		return true;
	if(gPhysics->RayCast(pBody, b2Vec2(-16, 0.32f)))
		return true;

	return false;
}

void PlayerEntity::SetItem(ItemTypes::Enum item)
{
	eItem = item;
	pIcon->SetVisible(eItem == ItemTypes::HEART);
}

ItemTypes::Enum PlayerEntity::GetItem() const
{
	return eItem;
}

void PlayerEntity::SetState(int newState)
{
	iPreviousState = iCurrentState;
	iCurrentState = newState;
}

<commit_msg>Fixed animation<commit_after>#include "PlayerEntity.h"

#include "EntityFactory.h"

#include <SceneNode.h>
#include <LeakReport.h>
#include <Sprite.h>
#include "GameScene.h"

#include <Box2D/Common/b2Math.h>

ENTITY_CREATOR("Player", PlayerEntity)

PlayerEntity::PlayerEntity():
	SpriteEntity("Player", "Player"),
	eItem(ItemTypes::NONE),
	fpMove(0),
	fpLandTime(0),
	pIcon(NULL)
{
	//empty
}

PlayerEntity::~PlayerEntity()
{
	gScene->Remove(pIcon);
	Delete(pIcon);

	pInput->RemoveKeyboardListener(this);
	gPhysics->DestroyBody(pBody);
}

void PlayerEntity::Load(Seed::IMetadataObject &metadata, Seed::SceneNode *sprites)
{
	SpriteEntity::Load(metadata, sprites);
	pSprite->SetZ(-10);

	pIcon = New(Sprite(*static_cast<Sprite *>(sprites->GetChildByName("Heart"))));
	pIcon->SetPosition(0, 0);
	pIcon->SetVisible(false);
	gScene->Add(pIcon);

	b2Vec2 customSize(40, 46);

	pBody = gPhysics->CreateBody(pSprite, &customSize);
	pBody->SetFixedRotation(true);
	pBody->GetFixtureList()->SetUserData(this);

	pInput->AddKeyboardListener(this);
	fVelocity = 5.0f;
	vPlayerVectorDirection = VECTOR_ZERO;
}

Vector3f PlayerEntity::GetPosition()
{
	return pSprite->GetPosition();
}

b2Vec2 PlayerEntity::GetBodyPosition() const
{
	return pBody->GetPosition();
}

Sprite *PlayerEntity::GetSprite() const
{
	return pSprite;
}

void PlayerEntity::Update(f32 dt)
{
	pIcon->SetPosition(pSprite->GetPosition() + Vector3f(0, -40, 0));

	b2Vec2 vel = pBody->GetLinearVelocity();

	bool ground = this->CheckGround();

	if(fpMove != 0)
	{
		vel.x = 5 * fpMove;
		pBody->SetLinearVelocity(vel);
	}

	if (iPreviousState ==JUMP && ground)
	{
		SetState(LAND);
		fpLandTime = 0.3f;
	}

	if(iCurrentState != JUMP && !ground)
	{
		this->SetState(JUMP);
	}

	if(fpLandTime > 0 && iCurrentState == LAND)
	{
		fpLandTime -= dt;
		if(fpLandTime <= 0)
		{
			if(fpMove != 0)
				this->SetState(RUN);
			else
				this->SetState(IDLE);
		}
	}

	if (iCurrentState == iPreviousState)
		return;

	if (iCurrentState == JUMP)
	{
		pSprite->SetAnimation("Jump");
	}
	else if (iCurrentState == LAND)
	{
		pSprite->SetAnimation("Land");
	}
	else if (iCurrentState == RUN)
	{
		pSprite->SetAnimation("Run");
	}
	else
	{
		pSprite->SetAnimation("Idle");
	}

	iPreviousState = iCurrentState;
}

void PlayerEntity::OnInputKeyboardPress(const EventInputKeyboard *ev)
{
	Key k = ev->GetKey();

	b2Vec2 vel = pBody->GetLinearVelocity();

	if ((k == Seed::KeyUp || k == Seed::KeyW) && iCurrentState != JUMP)
	{
		SetState(JUMP);
		pBody->ApplyForce(b2Vec2(0,500), pBody->GetWorldCenter());
	}

	if (k == Seed::KeyLeft || k == Seed::KeyA)
	{
		SetState(RUN);

		fpMove = -1;

		// Change the scale to turn the player sprite
		if (pSprite->GetScaleX() > 0)
			pSprite->SetScaleX(pSprite->GetScaleX() * -1);
	}

	if (k == Seed::KeyRight || k == Seed::KeyD)
	{
		SetState(RUN);

		fpMove = 1;

		// Change the scale to turn the player sprite
		if (pSprite->GetScaleX() < 0)
			pSprite->SetScaleX(pSprite->GetScaleX() * -1);
	}

	if (k == Seed::KeyDown || k == Seed::KeyS)
	{
		// Sum the normalized vector down with the current vector
		// Maybe later, maybe if the player can duck
	}

	//pSprite->AddPosition(vPlayerVectorDirection * fVelocity);
}

void PlayerEntity::OnInputKeyboardRelease(const EventInputKeyboard *ev)
{
	Key k = ev->GetKey();

	b2Vec2 vel = pBody->GetLinearVelocity();
	vel.x = 0;

	// Remove the directions
	if (k == Seed::KeyUp|| k == Seed::KeyW)
	{

	}

	if (k == Seed::KeyLeft|| k == Seed::KeyA)
	{
		pBody->SetLinearVelocity(vel);
		fpMove = 0;

		if (CheckGround())
			SetState(IDLE);
		else
			SetState(JUMP);
	}

	if (k == Seed::KeyRight|| k == Seed::KeyD)
	{
		pBody->SetLinearVelocity(vel);
		fpMove = 0;

		if (CheckGround())
			SetState(IDLE);
		else
			SetState(JUMP);
	}

	if (k == Seed::KeyDown|| k == Seed::KeyS)
	{
		vPlayerVectorDirection -= VECTOR_DOWN;
	}
}

bool PlayerEntity::CheckGround()
{
	if(gPhysics->RayCast(pBody, b2Vec2(0, 0.32f)))
		return true;
	if(gPhysics->RayCast(pBody, b2Vec2(0.16f, 0.32f)))
		return true;
	if(gPhysics->RayCast(pBody, b2Vec2(-0.16f, 0.32f)))
		return true;

	return false;
}

void PlayerEntity::SetItem(ItemTypes::Enum item)
{
	eItem = item;
	pIcon->SetVisible(eItem == ItemTypes::HEART);
}

ItemTypes::Enum PlayerEntity::GetItem() const
{
	return eItem;
}

void PlayerEntity::SetState(int newState)
{
	iPreviousState = iCurrentState;
	iCurrentState = newState;
}

<|endoftext|>


<commit_before>#include "parameter_acceptor.h"
#include "utilities.h"

#include <deal.II/base/point.h>

// Static empty class list
std::vector<SmartPointer<ParameterAcceptor> > ParameterAcceptor::class_list;
// Static parameter handler
ParameterHandler ParameterAcceptor::prm;

ParameterAcceptor::ParameterAcceptor(const std::string name) :
  acceptor_id(class_list.size()),
  section_name(name)
{
  SmartPointer<ParameterAcceptor> pt(this, type(*this).c_str());
  class_list.push_back(pt);
}

ParameterAcceptor::~ParameterAcceptor()
{
  class_list[acceptor_id] = 0;
}

std::string ParameterAcceptor::get_section_name() const
{
  return (section_name != "" ? section_name : type(*this));
}

void
ParameterAcceptor::initialize(const std::string filename)
{
  prm.clear();
  declare_all_parameters(prm);
  if (filename != "")
    prm.read_input(filename);
  parse_all_parameters(prm);
}

void ParameterAcceptor::parse_all_parameters(ParameterHandler &prm)
{
  for (unsigned int i=0; i< class_list.size(); ++i)
    {
      prm.enter_subsection(class_list[i]->get_section_name());
      class_list[i]->parse_parameters(prm);
      prm.leave_subsection();
    }
}

void ParameterAcceptor::declare_all_parameters(ParameterHandler &prm)
{
  for (unsigned int i=0; i< class_list.size(); ++i)
    {
      prm.enter_subsection(class_list[i]->get_section_name());
      class_list[i]->declare_parameters(prm);
      prm.leave_subsection();
    }
}

void ParameterAcceptor::parse_parameters(ParameterHandler &prm)
{
  for (auto it = parameters.begin(); it != parameters.end(); ++it)
    {
      if (it->second.type() == typeid(std::string *))
        {
          *(boost::any_cast<std::string *>(it->second)) = prm.get(it->first);
        }
      else if (it->second.type() == typeid(double *))
        {
          *(boost::any_cast<double *>(it->second)) = prm.get_double(it->first);
        }
      else if (it->second.type() == typeid(int *))
        {
          *(boost::any_cast<int *>(it->second)) = prm.get_integer(it->first);
        }
      else if (it->second.type() == typeid(unsigned int *))
        {
          *(boost::any_cast<unsigned int *>(it->second)) = prm.get_integer(it->first);
        }
      else if (it->second.type() == typeid(bool *))
        {
          *(boost::any_cast<bool *>(it->second)) = prm.get_bool(it->first);
        }
      // Here we have the difficult types...
      // First all point types.
      else if (it->second.type() == typeid(Point<2> *))
        {
          std::vector<double> p =
            Utilities::string_to_double(Utilities::split_string_list(prm.get(it->first)));
          AssertDimension(p.size(), 2);

          Point<2> &pp = *(boost::any_cast<Point<2>*>(it->second));
          pp[0] = p[0];
          pp[1] = p[1];
        }
      else if (it->second.type() == typeid(Point<3> *))
        {
          std::vector<double> p =
            Utilities::string_to_double(Utilities::split_string_list(prm.get(it->first)));
          AssertDimension(p.size(), 3);

          Point<3> &pp = *(boost::any_cast<Point<3>*>(it->second));
          pp[0] = p[0];
          pp[1] = p[1];
          pp[2] = p[2];
        }
      else if (it->second.type() == typeid(std::vector<std::string> *))
        {
          std::vector<std::string> &string_list = *(boost::any_cast<std::vector<std::string>*>(it->second));
          string_list = Utilities::split_string_list(prm.get(it->first));
        }
      else
        {
          AssertThrow(false, ExcNotImplemented());
        }
    }
}

void ParameterAcceptor::parse_parameters_call_back() {};

<commit_msg>Fixed bug in Point<1> conversion.<commit_after>#include "parameter_acceptor.h"
#include "utilities.h"

#include <deal.II/base/point.h>

// Static empty class list
std::vector<SmartPointer<ParameterAcceptor> > ParameterAcceptor::class_list;
// Static parameter handler
ParameterHandler ParameterAcceptor::prm;

ParameterAcceptor::ParameterAcceptor(const std::string name) :
  acceptor_id(class_list.size()),
  section_name(name)
{
  SmartPointer<ParameterAcceptor> pt(this, type(*this).c_str());
  class_list.push_back(pt);
}

ParameterAcceptor::~ParameterAcceptor()
{
  class_list[acceptor_id] = 0;
}

std::string ParameterAcceptor::get_section_name() const
{
  return (section_name != "" ? section_name : type(*this));
}

void
ParameterAcceptor::initialize(const std::string filename)
{
  prm.clear();
  declare_all_parameters(prm);
  if (filename != "")
    prm.read_input(filename);
  parse_all_parameters(prm);
}

void ParameterAcceptor::parse_all_parameters(ParameterHandler &prm)
{
  for (unsigned int i=0; i< class_list.size(); ++i)
    {
      prm.enter_subsection(class_list[i]->get_section_name());
      class_list[i]->parse_parameters(prm);
      prm.leave_subsection();
    }
}

void ParameterAcceptor::declare_all_parameters(ParameterHandler &prm)
{
  for (unsigned int i=0; i< class_list.size(); ++i)
    {
      prm.enter_subsection(class_list[i]->get_section_name());
      class_list[i]->declare_parameters(prm);
      prm.leave_subsection();
    }
}

void ParameterAcceptor::parse_parameters(ParameterHandler &prm)
{
  for (auto it = parameters.begin(); it != parameters.end(); ++it)
    {
      if (it->second.type() == typeid(std::string *))
        {
          *(boost::any_cast<std::string *>(it->second)) = prm.get(it->first);
        }
      else if (it->second.type() == typeid(double *))
        {
          *(boost::any_cast<double *>(it->second)) = prm.get_double(it->first);
        }
      else if (it->second.type() == typeid(int *))
        {
          *(boost::any_cast<int *>(it->second)) = prm.get_integer(it->first);
        }
      else if (it->second.type() == typeid(unsigned int *))
        {
          *(boost::any_cast<unsigned int *>(it->second)) = prm.get_integer(it->first);
        }
      else if (it->second.type() == typeid(bool *))
        {
          *(boost::any_cast<bool *>(it->second)) = prm.get_bool(it->first);
        }
      // Here we have the difficult types...
      // First all point types.
      else if (it->second.type() == typeid(Point<1> *))
        {
          std::vector<double> p =
            Utilities::string_to_double(Utilities::split_string_list(prm.get(it->first)));
          AssertDimension(p.size(), 1);

          Point<1> &pp = *(boost::any_cast<Point<1>*>(it->second));
          pp[0] = p[0];
        }
      else if (it->second.type() == typeid(Point<2> *))
        {
          std::vector<double> p =
            Utilities::string_to_double(Utilities::split_string_list(prm.get(it->first)));
          AssertDimension(p.size(), 2);

          Point<2> &pp = *(boost::any_cast<Point<2>*>(it->second));
          pp[0] = p[0];
          pp[1] = p[1];
        }
      else if (it->second.type() == typeid(Point<3> *))
        {
          std::vector<double> p =
            Utilities::string_to_double(Utilities::split_string_list(prm.get(it->first)));
          AssertDimension(p.size(), 3);

          Point<3> &pp = *(boost::any_cast<Point<3>*>(it->second));
          pp[0] = p[0];
          pp[1] = p[1];
          pp[2] = p[2];
        }
      else if (it->second.type() == typeid(std::vector<std::string> *))
        {
          std::vector<std::string> &string_list = *(boost::any_cast<std::vector<std::string>*>(it->second));
          string_list = Utilities::split_string_list(prm.get(it->first));
        }
      else
        {
          AssertThrow(false, ExcNotImplemented());
        }
    }
}

void ParameterAcceptor::parse_parameters_call_back() {};

<|endoftext|>


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

#include "tcmalloc/transfer_cache.h"

#include <string.h>

#include <algorithm>
#include <atomic>

#include "tcmalloc/common.h"
#include "tcmalloc/experiment.h"
#include "tcmalloc/internal/linked_list.h"
#include "tcmalloc/internal/logging.h"
#include "tcmalloc/static_vars.h"
#include "tcmalloc/tracking.h"

namespace tcmalloc {
#ifndef TCMALLOC_SMALL_BUT_SLOW
void TransferCache::Init(size_t cl) {
  absl::base_internal::SpinLockHolder h(&lock_);
  freelist_.Init(cl);

  // We need at least 2 slots to store list head and tail.
  ASSERT(kMinObjectsToMove >= 2);

  // Cache this value, for performance.
  arbitrary_transfer_ =
      IsExperimentActive(Experiment::TCMALLOC_ARBITRARY_TRANSFER_CACHE);

  slots_ = nullptr;
  max_cache_slots_ = 0;
  int32_t cache_slots = 0;

  if (cl > 0) {
    // Limit the maximum size of the cache based on the size class.  If this
    // is not done, large size class objects will consume a lot of memory if
    // they just sit in the transfer cache.
    size_t bytes = Static::sizemap()->class_to_size(cl);
    size_t objs_to_move = Static::sizemap()->num_objects_to_move(cl);
    ASSERT(objs_to_move > 0 && bytes > 0);

    // Starting point for the maximum number of entries in the transfer cache.
    // This actual maximum for a given size class may be lower than this
    // maximum value.
    max_cache_slots_ = 64 * objs_to_move;
    // A transfer cache freelist can have anywhere from 0 to
    // max_cache_slots_ slots to put link list chains into.
    cache_slots = 16 * objs_to_move;

    // Limit each size class cache to at most 1MB of objects or one entry,
    // whichever is greater. Total transfer cache memory used across all
    // size classes then can't be greater than approximately
    // 1MB * kMaxNumTransferEntries.
    max_cache_slots_ = std::min<size_t>(
        max_cache_slots_,
        std::max<size_t>(objs_to_move, (1024 * 1024) / (bytes * objs_to_move) *
                                           objs_to_move));
    cache_slots = std::min(cache_slots, max_cache_slots_);
    slots_ = reinterpret_cast<void **>(
        Static::arena()->Alloc(max_cache_slots_ * sizeof(void *)));
  }
  used_slots_.store(0, std::memory_order_relaxed);
  cache_slots_.store(cache_slots, std::memory_order_relaxed);
  ASSERT(cache_slots <= max_cache_slots_);
}

bool TransferCache::EvictRandomSizeClass(int locked_size_class, bool force) {
  static std::atomic<int32_t> race_counter{1};
  int t = race_counter.load(std::memory_order_relaxed);
  race_counter.store(t + 1, std::memory_order_relaxed);
  if (t >= kNumClasses) {
    while (t >= kNumClasses) {
      t -= kNumClasses - 1;  // Don't want t == 0
    }
    race_counter.store(t, std::memory_order_relaxed);
  }
  ASSERT(t > 0);
  ASSERT(t < kNumClasses);
  if (t == locked_size_class) return false;
  return Static::transfer_cache()[t].ShrinkCache(locked_size_class, force);
}

bool TransferCache::MakeCacheSpace(int N) {
  int32_t used_slots = used_slots_.load(std::memory_order_relaxed);
  int32_t cache_slots = cache_slots_.load(std::memory_order_relaxed);
  // Is there room in the cache?
  if (used_slots + N <= cache_slots) return true;
  // Check if we can expand this cache?
  if (cache_slots + N > max_cache_slots_) return false;
  // Ok, we'll try to grab an entry from some other size class.
  if (EvictRandomSizeClass(freelist_.size_class(), false) ||
      EvictRandomSizeClass(freelist_.size_class(), true)) {
    // Succeeded in evicting, we're going to make our cache larger.  However, we
    // may have dropped and re-acquired the lock in EvictRandomSizeClass (via
    // ShrinkCache), so the cache_size may have changed.  Therefore, check and
    // verify that it is still OK to increase the cache_size.
    cache_slots = cache_slots_.load(std::memory_order_relaxed);
    if (cache_slots + N <= max_cache_slots_) {
      cache_slots += N;
      cache_slots_.store(cache_slots, std::memory_order_relaxed);
      return true;
    }
  }
  return false;
}

bool TransferCache::ShrinkCache(int locked_size_class, bool force) {
  int32_t used_slots = used_slots_.load(std::memory_order_relaxed);
  int32_t cache_slots = cache_slots_.load(std::memory_order_relaxed);

  // Start with a quick check without taking a lock.
  if (cache_slots == 0) return false;

  int N = Static::sizemap()->num_objects_to_move(freelist_.size_class());

  // We don't evict from a full cache unless we are 'forcing'.
  if (!force && used_slots + N >= cache_slots) return false;

  // Release the other held lock before acquiring the current lock to avoid a
  // dead lock.
  struct SpinLockReleaser {
    absl::base_internal::SpinLock *lock_;

    SpinLockReleaser(absl::base_internal::SpinLock *lock) : lock_(lock) {
      lock_->Unlock();
    }
    ~SpinLockReleaser() { lock_->Lock(); }
  };
  SpinLockReleaser unlocker(&Static::transfer_cache()[locked_size_class].lock_);
  void *to_free[kMaxObjectsToMove];
  int num_to_free;
  {
    absl::base_internal::SpinLockHolder h(&lock_);

    // Fetch while holding the lock in case they changed.
    cache_slots = cache_slots_.load(std::memory_order_relaxed);
    used_slots = used_slots_.load(std::memory_order_relaxed);
    ASSERT(0 <= used_slots && used_slots <= cache_slots);

    if (cache_slots == 0) return false;
    if (!arbitrary_transfer_ && cache_slots < N) return false;

    N = std::min(N, cache_slots);
    int unused = cache_slots - used_slots;
    if (N <= unused) {
      cache_slots -= N;
      cache_slots_.store(cache_slots, std::memory_order_relaxed);
      return true;
    }
    if (!force) return false;

    num_to_free = N - unused;
    cache_slots -= N;
    used_slots -= num_to_free;
    cache_slots_.store(cache_slots, std::memory_order_relaxed);
    used_slots_.store(used_slots, std::memory_order_relaxed);
    // Our internal slot array may get overwritten as soon as we drop the lock,
    // so copy the items to free to an on stack buffer.
    memcpy(to_free, GetSlot(used_slots), sizeof(void *) * num_to_free);
  }
  // Access the freelist while holding *neither* lock.
  freelist_.InsertRange(to_free, num_to_free);
  return true;
}

void TransferCache::InsertRange(absl::Span<void *> batch, int N) {
  const int B = Static::sizemap()->num_objects_to_move(freelist_.size_class());
  ASSERT(0 < N && N <= B);
  int32_t used_slots = used_slots_.load(std::memory_order_relaxed);
  if (N == B && used_slots + N <= max_cache_slots_) {
    absl::base_internal::SpinLockHolder h(&lock_);
    if (MakeCacheSpace(N)) {
      // MakeCacheSpace can drop the lock, so refetch
      used_slots = used_slots_.load(std::memory_order_relaxed);
      ASSERT(0 <= used_slots && used_slots + N <= max_cache_slots_);
      used_slots_.store(used_slots + N, std::memory_order_relaxed);

      void **entry = GetSlot(used_slots);
      memcpy(entry, batch.data(), sizeof(void *) * N);
      tracking::Report(kTCInsertHit, freelist_.size_class(), 1);
      return;
    }
  } else if (arbitrary_transfer_) {
    absl::base_internal::SpinLockHolder h(&lock_);
    MakeCacheSpace(N);
    // MakeCacheSpace can drop the lock, so refetch
    int32_t used_slots = used_slots_.load(std::memory_order_relaxed);
    int32_t cache_slots = cache_slots_.load(std::memory_order_relaxed);
    int unused = cache_slots - used_slots;
    if (N < unused) {
      used_slots_.store(used_slots + N, std::memory_order_relaxed);
      ASSERT(0 <= used_slots && used_slots + N <= max_cache_slots_);
      void **entry = GetSlot(used_slots);
      memcpy(entry, batch.data(), sizeof(void *) * N);
      tracking::Report(kTCInsertHit, freelist_.size_class(), 1);
      return;
    }
    // We could not fit the entire batch into the transfer cache
    // so send the batch to the freelist and also take some elements from
    // the transfer cache so that we amortise the cost of accessing spans
    // in the freelist. Only do this if caller has sufficient space in
    // batch.
    // First of all fill up the rest of the batch with elements from the
    // transfer cache.
    int extra = B - N;
    if (N > 1 && extra > 0 && used_slots > 0 && batch.size() >= B) {
      // Take at most all the objects present
      extra = std::min(extra, used_slots);
      ASSERT(extra + N <= kMaxObjectsToMove);
      used_slots -= extra;
      used_slots_.store(used_slots, std::memory_order_relaxed);

      void **entry = GetSlot(used_slots);
      memcpy(batch.data() + N, entry, sizeof(void *) * extra);
      N += extra;
#ifndef NDEBUG
      int rest = batch.size() - N - 1;
      if (rest > 0) {
        memset(batch.data() + N, 0x3f, rest * sizeof(void *));
      }
#endif
    }
  }
  tracking::Report(kTCInsertMiss, freelist_.size_class(), 1);
  freelist_.InsertRange(batch.data(), N);
}

int TransferCache::RemoveRange(void **batch, int N) {
  ASSERT(N > 0);
  const int B = Static::sizemap()->num_objects_to_move(freelist_.size_class());
  int fetch = 0;
  int32_t used_slots = used_slots_.load(std::memory_order_relaxed);
  if (N == B && used_slots >= N) {
    absl::base_internal::SpinLockHolder h(&lock_);
    // Refetch with the lock
    used_slots = used_slots_.load(std::memory_order_relaxed);
    if (used_slots >= N) {
      used_slots -= N;
      used_slots_.store(used_slots, std::memory_order_relaxed);
      ASSERT(0 <= used_slots);
      void **entry = GetSlot(used_slots);
      memcpy(batch, entry, sizeof(void *) * N);
      tracking::Report(kTCRemoveHit, freelist_.size_class(), 1);
      return N;
    }
  } else if (arbitrary_transfer_ && used_slots >= 0) {
    absl::base_internal::SpinLockHolder h(&lock_);
    // Refetch with the lock
    used_slots = used_slots_.load(std::memory_order_relaxed);

    fetch = std::min(N, used_slots);
    used_slots -= fetch;
    ASSERT(0 <= used_slots);
    used_slots_.store(used_slots, std::memory_order_relaxed);
    void **entry = GetSlot(used_slots);
    memcpy(batch, entry, sizeof(void *) * fetch);
    tracking::Report(kTCRemoveHit, freelist_.size_class(), 1);
    if (fetch == N) return N;
  }
  tracking::Report(kTCRemoveMiss, freelist_.size_class(), 1);
  return freelist_.RemoveRange(batch + fetch, N - fetch) + fetch;
}

size_t TransferCache::tc_length() {
  return static_cast<size_t>(used_slots_.load(std::memory_order_relaxed));
}

#endif
}  // namespace tcmalloc
<commit_msg>Make overflow in evict simpler and consistent with non-overflow.<commit_after>// Copyright 2019 The TCMalloc Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "tcmalloc/transfer_cache.h"

#include <string.h>

#include <algorithm>
#include <atomic>

#include "tcmalloc/common.h"
#include "tcmalloc/experiment.h"
#include "tcmalloc/internal/linked_list.h"
#include "tcmalloc/internal/logging.h"
#include "tcmalloc/static_vars.h"
#include "tcmalloc/tracking.h"

namespace tcmalloc {
#ifndef TCMALLOC_SMALL_BUT_SLOW
void TransferCache::Init(size_t cl) {
  absl::base_internal::SpinLockHolder h(&lock_);
  freelist_.Init(cl);

  // We need at least 2 slots to store list head and tail.
  ASSERT(kMinObjectsToMove >= 2);

  // Cache this value, for performance.
  arbitrary_transfer_ =
      IsExperimentActive(Experiment::TCMALLOC_ARBITRARY_TRANSFER_CACHE);

  slots_ = nullptr;
  max_cache_slots_ = 0;
  int32_t cache_slots = 0;

  if (cl > 0) {
    // Limit the maximum size of the cache based on the size class.  If this
    // is not done, large size class objects will consume a lot of memory if
    // they just sit in the transfer cache.
    size_t bytes = Static::sizemap()->class_to_size(cl);
    size_t objs_to_move = Static::sizemap()->num_objects_to_move(cl);
    ASSERT(objs_to_move > 0 && bytes > 0);

    // Starting point for the maximum number of entries in the transfer cache.
    // This actual maximum for a given size class may be lower than this
    // maximum value.
    max_cache_slots_ = 64 * objs_to_move;
    // A transfer cache freelist can have anywhere from 0 to
    // max_cache_slots_ slots to put link list chains into.
    cache_slots = 16 * objs_to_move;

    // Limit each size class cache to at most 1MB of objects or one entry,
    // whichever is greater. Total transfer cache memory used across all
    // size classes then can't be greater than approximately
    // 1MB * kMaxNumTransferEntries.
    max_cache_slots_ = std::clamp<size_t>(
        objs_to_move, max_cache_slots_,
        (1024 * 1024) / (bytes * objs_to_move) * objs_to_move);
    cache_slots = std::min(cache_slots, max_cache_slots_);
    slots_ = reinterpret_cast<void **>(
        Static::arena()->Alloc(max_cache_slots_ * sizeof(void *)));
  }
  used_slots_.store(0, std::memory_order_relaxed);
  cache_slots_.store(cache_slots, std::memory_order_relaxed);
  ASSERT(cache_slots <= max_cache_slots_);
}

bool TransferCache::EvictRandomSizeClass(int locked_size_class, bool force) {
  // t == 0 is never valid, hence starting at/reseting to 1
  static std::atomic<int32_t> race_counter{1};
  int t = race_counter.load(std::memory_order_relaxed);
  if (t >= kNumClasses) t = 1;
  race_counter.store(t + 1, std::memory_order_relaxed);
  ASSERT(0 < t && t < kNumClasses);
  if (t == locked_size_class) return false;
  return Static::transfer_cache()[t].ShrinkCache(locked_size_class, force);
}

bool TransferCache::MakeCacheSpace(int N) {
  int32_t used_slots = used_slots_.load(std::memory_order_relaxed);
  int32_t cache_slots = cache_slots_.load(std::memory_order_relaxed);
  // Is there room in the cache?
  if (used_slots + N <= cache_slots) return true;
  // Check if we can expand this cache?
  if (cache_slots + N > max_cache_slots_) return false;
  // Ok, we'll try to grab an entry from some other size class.
  if (EvictRandomSizeClass(freelist_.size_class(), false) ||
      EvictRandomSizeClass(freelist_.size_class(), true)) {
    // Succeeded in evicting, we're going to make our cache larger.  However, we
    // may have dropped and re-acquired the lock in EvictRandomSizeClass (via
    // ShrinkCache), so the cache_size may have changed.  Therefore, check and
    // verify that it is still OK to increase the cache_size.
    cache_slots = cache_slots_.load(std::memory_order_relaxed);
    if (cache_slots + N <= max_cache_slots_) {
      cache_slots += N;
      cache_slots_.store(cache_slots, std::memory_order_relaxed);
      return true;
    }
  }
  return false;
}

bool TransferCache::ShrinkCache(int locked_size_class, bool force) {
  int32_t used_slots = used_slots_.load(std::memory_order_relaxed);
  int32_t cache_slots = cache_slots_.load(std::memory_order_relaxed);

  // Start with a quick check without taking a lock.
  if (cache_slots == 0) return false;

  int N = Static::sizemap()->num_objects_to_move(freelist_.size_class());

  // We don't evict from a full cache unless we are 'forcing'.
  if (!force && used_slots + N >= cache_slots) return false;

  // Release the other held lock before acquiring the current lock to avoid a
  // dead lock.
  struct SpinLockReleaser {
    absl::base_internal::SpinLock *lock_;

    SpinLockReleaser(absl::base_internal::SpinLock *lock) : lock_(lock) {
      lock_->Unlock();
    }
    ~SpinLockReleaser() { lock_->Lock(); }
  };
  SpinLockReleaser unlocker(&Static::transfer_cache()[locked_size_class].lock_);
  void *to_free[kMaxObjectsToMove];
  int num_to_free;
  {
    absl::base_internal::SpinLockHolder h(&lock_);

    // Fetch while holding the lock in case they changed.
    cache_slots = cache_slots_.load(std::memory_order_relaxed);
    used_slots = used_slots_.load(std::memory_order_relaxed);
    ASSERT(0 <= used_slots && used_slots <= cache_slots);

    if (cache_slots == 0) return false;
    if (!arbitrary_transfer_ && cache_slots < N) return false;

    N = std::min(N, cache_slots);
    int unused = cache_slots - used_slots;
    if (N <= unused) {
      cache_slots -= N;
      cache_slots_.store(cache_slots, std::memory_order_relaxed);
      return true;
    }
    if (!force) return false;

    num_to_free = N - unused;
    cache_slots -= N;
    used_slots -= num_to_free;
    cache_slots_.store(cache_slots, std::memory_order_relaxed);
    used_slots_.store(used_slots, std::memory_order_relaxed);
    // Our internal slot array may get overwritten as soon as we drop the lock,
    // so copy the items to free to an on stack buffer.
    memcpy(to_free, GetSlot(used_slots), sizeof(void *) * num_to_free);
  }
  // Access the freelist while holding *neither* lock.
  freelist_.InsertRange(to_free, num_to_free);
  return true;
}

void TransferCache::InsertRange(absl::Span<void *> batch, int N) {
  const int B = Static::sizemap()->num_objects_to_move(freelist_.size_class());
  ASSERT(0 < N && N <= B);
  int32_t used_slots = used_slots_.load(std::memory_order_relaxed);
  if (N == B && used_slots + N <= max_cache_slots_) {
    absl::base_internal::SpinLockHolder h(&lock_);
    if (MakeCacheSpace(N)) {
      // MakeCacheSpace can drop the lock, so refetch
      used_slots = used_slots_.load(std::memory_order_relaxed);
      ASSERT(0 <= used_slots && used_slots + N <= max_cache_slots_);
      used_slots_.store(used_slots + N, std::memory_order_relaxed);

      void **entry = GetSlot(used_slots);
      memcpy(entry, batch.data(), sizeof(void *) * N);
      tracking::Report(kTCInsertHit, freelist_.size_class(), 1);
      return;
    }
  } else if (arbitrary_transfer_) {
    absl::base_internal::SpinLockHolder h(&lock_);
    MakeCacheSpace(N);
    // MakeCacheSpace can drop the lock, so refetch
    int32_t used_slots = used_slots_.load(std::memory_order_relaxed);
    int32_t cache_slots = cache_slots_.load(std::memory_order_relaxed);
    int unused = cache_slots - used_slots;
    if (N < unused) {
      used_slots_.store(used_slots + N, std::memory_order_relaxed);
      ASSERT(0 <= used_slots && used_slots + N <= max_cache_slots_);
      void **entry = GetSlot(used_slots);
      memcpy(entry, batch.data(), sizeof(void *) * N);
      tracking::Report(kTCInsertHit, freelist_.size_class(), 1);
      return;
    }
    // We could not fit the entire batch into the transfer cache
    // so send the batch to the freelist and also take some elements from
    // the transfer cache so that we amortise the cost of accessing spans
    // in the freelist. Only do this if caller has sufficient space in
    // batch.
    // First of all fill up the rest of the batch with elements from the
    // transfer cache.
    int extra = B - N;
    if (N > 1 && extra > 0 && used_slots > 0 && batch.size() >= B) {
      // Take at most all the objects present
      extra = std::min(extra, used_slots);
      ASSERT(extra + N <= kMaxObjectsToMove);
      used_slots -= extra;
      used_slots_.store(used_slots, std::memory_order_relaxed);

      void **entry = GetSlot(used_slots);
      memcpy(batch.data() + N, entry, sizeof(void *) * extra);
      N += extra;
#ifndef NDEBUG
      int rest = batch.size() - N - 1;
      if (rest > 0) {
        memset(batch.data() + N, 0x3f, rest * sizeof(void *));
      }
#endif
    }
  }
  tracking::Report(kTCInsertMiss, freelist_.size_class(), 1);
  freelist_.InsertRange(batch.data(), N);
}

int TransferCache::RemoveRange(void **batch, int N) {
  ASSERT(N > 0);
  const int B = Static::sizemap()->num_objects_to_move(freelist_.size_class());
  int fetch = 0;
  int32_t used_slots = used_slots_.load(std::memory_order_relaxed);
  if (N == B && used_slots >= N) {
    absl::base_internal::SpinLockHolder h(&lock_);
    // Refetch with the lock
    used_slots = used_slots_.load(std::memory_order_relaxed);
    if (used_slots >= N) {
      used_slots -= N;
      used_slots_.store(used_slots, std::memory_order_relaxed);
      ASSERT(0 <= used_slots);
      void **entry = GetSlot(used_slots);
      memcpy(batch, entry, sizeof(void *) * N);
      tracking::Report(kTCRemoveHit, freelist_.size_class(), 1);
      return N;
    }
  } else if (arbitrary_transfer_ && used_slots >= 0) {
    absl::base_internal::SpinLockHolder h(&lock_);
    // Refetch with the lock
    used_slots = used_slots_.load(std::memory_order_relaxed);

    fetch = std::min(N, used_slots);
    used_slots -= fetch;
    ASSERT(0 <= used_slots);
    used_slots_.store(used_slots, std::memory_order_relaxed);
    void **entry = GetSlot(used_slots);
    memcpy(batch, entry, sizeof(void *) * fetch);
    tracking::Report(kTCRemoveHit, freelist_.size_class(), 1);
    if (fetch == N) return N;
  }
  tracking::Report(kTCRemoveMiss, freelist_.size_class(), 1);
  return freelist_.RemoveRange(batch + fetch, N - fetch) + fetch;
}

size_t TransferCache::tc_length() {
  return static_cast<size_t>(used_slots_.load(std::memory_order_relaxed));
}

#endif
}  // namespace tcmalloc
<|endoftext|>


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

#include "libs/tpu/edgetpu_manager.h"

#include <cstdio>

#include "libs/base/check.h"
#include "libs/base/mutex.h"
#include "libs/tpu/edgetpu_task.h"
#include "third_party/flatbuffers/include/flatbuffers/flatbuffers.h"
#include "third_party/flatbuffers/include/flatbuffers/flexbuffers.h"
#include "third_party/nxp/rt1176-sdk/components/osa/fsl_os_abstraction.h"

namespace coralmicro {
namespace {
constexpr char kKeyVersion[] = "1";
constexpr char kKeyChipName[] = "2";
constexpr char kKeyParamCache_DEPRECATED[] = "3";
constexpr char kKeyExecutable[] = "4";
}  // namespace

EdgeTpuContext::EdgeTpuContext() {
  EdgeTpuTask::GetSingleton()->SetPower(true);
}

EdgeTpuContext::~EdgeTpuContext() {
  EdgeTpuTask::GetSingleton()->SetPower(false);
}

EdgeTpuManager::EdgeTpuManager() : mutex_(xSemaphoreCreateMutex()) {
  CHECK(mutex_);
}

void EdgeTpuManager::NotifyConnected(
    usb_host_edgetpu_instance_t* usb_instance) {
  usb_instance_ = usb_instance;
}

std::shared_ptr<EdgeTpuContext> EdgeTpuManager::OpenDevice(
    PerformanceMode mode) {
  MutexLock lock(mutex_);

  auto context = context_.lock();
  if (context) return context;

  context = std::make_shared<EdgeTpuContext>();

  while (!usb_instance_) {
    vTaskDelay(pdMS_TO_TICKS(200));
  }
  if (!tpu_driver_.Initialize(usb_instance_, mode)) {
    return nullptr;
  }

  context_ = context;
  return context;
}

EdgeTpuPackage* EdgeTpuManager::RegisterPackage(const char* package_content,
                                                size_t length) {
  MutexLock lock(mutex_);
  auto package_ptr = (uintptr_t)package_content;

  if (packages_.find(package_ptr) != packages_.end()) {
    return packages_[package_ptr];
  }

  auto flexbuffer_map =
      flexbuffers::GetRoot((const uint8_t*)package_ptr, length).AsMap();
  auto package_binary = flexbuffer_map[kKeyExecutable].AsString();
  flatbuffers::Verifier package_verifier((const uint8_t*)package_binary.c_str(),
                                         package_binary.length());
  if (!package_verifier.VerifyBuffer<platforms::darwinn::Package>()) {
    printf("Package verification failed.\r\n");
    return nullptr;
  }

  auto* package =
      flatbuffers::GetRoot<platforms::darwinn::Package>(package_binary.c_str());
  if (flatbuffers::VectorLength(package->serialized_multi_executable()) == 0) {
    printf("No executables to register.\r\n");
    return nullptr;
  }

  auto* multi_executable =
      flatbuffers::GetRoot<platforms::darwinn::MultiExecutable>(
          package->serialized_multi_executable()->data());
  flatbuffers::Verifier multi_executable_verifier(
      package->serialized_multi_executable()->data(),
      flatbuffers::VectorLength(package->serialized_multi_executable()));
  if (!multi_executable_verifier
           .VerifyBuffer<platforms::darwinn::MultiExecutable>()) {
    printf("MultiExecutable verification failed.\r\n");
    return nullptr;
  }

  const platforms::darwinn::Executable* inference_exe = nullptr;
  const platforms::darwinn::Executable* parameter_caching_exe = nullptr;

  for (const auto* executable_serialized :
       *(multi_executable->serialized_executables())) {
    flatbuffers::Verifier verifier(
        (const uint8_t*)executable_serialized->c_str(),
        executable_serialized->size());
    if (!verifier.VerifyBuffer<platforms::darwinn::Executable>()) {
      printf("Executable verification failed.\r\n");
      return nullptr;
    }

    const auto* executable =
        flatbuffers::GetRoot<platforms::darwinn::Executable>(
            (const uint8_t*)executable_serialized->c_str());
    if (executable->type() ==
            platforms::darwinn::ExecutableType_EXECUTION_ONLY ||
        executable->type() == platforms::darwinn::ExecutableType_STAND_ALONE) {
      inference_exe = executable;
    } else if (executable->type() ==
               platforms::darwinn::ExecutableType_PARAMETER_CACHING) {
      parameter_caching_exe = executable;
    }
  }

  if (inference_exe == nullptr) {
    printf("Package does not have inference executable.\r\n");
    return nullptr;
  }

  auto* edgetpu_package =
      new EdgeTpuPackage(inference_exe, parameter_caching_exe);
  packages_[package_ptr] = edgetpu_package;

  return edgetpu_package;
}

TfLiteStatus EdgeTpuManager::Invoke(EdgeTpuPackage* package,
                                    TfLiteContext* context, TfLiteNode* node) {
  MutexLock lock(mutex_);
  if (package->parameter_caching_exe()) {
    auto token = package->parameter_caching_exe()->ParameterCachingToken();
    if (token != current_parameter_caching_token_) {
      cached_packages_.fill(nullptr);
      package->parameter_caching_exe()->Invoke(tpu_driver_, context, node);
      current_parameter_caching_token_ = token;
      cached_packages_[0] = package;
    } else {
      for (auto& cached_package : cached_packages_) {
        if (cached_package == package) {
          break;
        } else if (cached_package == nullptr) {
          package->parameter_caching_exe()->Invoke(tpu_driver_, context, node);
          cached_package = package;
        }
      }
    }
  } else {
    current_parameter_caching_token_ = 0;
  }

  return package->inference_exe()->Invoke(tpu_driver_, context, node);
}

std::optional<float> EdgeTpuManager::GetTemperature() {
  MutexLock lock(mutex_);
  // Only attempt to read the temperature if the device has been opened.
  auto context = context_.lock();
  if (context) return tpu_driver_.GetTemperature();
  return std::nullopt;
}

}  // namespace coralmicro
<commit_msg>Clean up state after TPU power is removed<commit_after>/*
 * Copyright 2022 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "libs/tpu/edgetpu_manager.h"

#include <cstdio>

#include "libs/base/check.h"
#include "libs/base/mutex.h"
#include "libs/tpu/edgetpu_task.h"
#include "third_party/flatbuffers/include/flatbuffers/flatbuffers.h"
#include "third_party/flatbuffers/include/flatbuffers/flexbuffers.h"
#include "third_party/nxp/rt1176-sdk/components/osa/fsl_os_abstraction.h"

namespace coralmicro {
namespace {
constexpr char kKeyVersion[] = "1";
constexpr char kKeyChipName[] = "2";
constexpr char kKeyParamCache_DEPRECATED[] = "3";
constexpr char kKeyExecutable[] = "4";
}  // namespace

EdgeTpuContext::EdgeTpuContext() {
  EdgeTpuTask::GetSingleton()->SetPower(true);
}

EdgeTpuContext::~EdgeTpuContext() {
  EdgeTpuTask::GetSingleton()->SetPower(false);
}

EdgeTpuManager::EdgeTpuManager() : mutex_(xSemaphoreCreateMutex()) {
  CHECK(mutex_);
}

void EdgeTpuManager::NotifyConnected(
    usb_host_edgetpu_instance_t* usb_instance) {
  usb_instance_ = usb_instance;

  // The EdgeTPU has left the USB bus -- clean up state.
  if (!usb_instance_) {
    current_parameter_caching_token_ = 0;
  }
}

std::shared_ptr<EdgeTpuContext> EdgeTpuManager::OpenDevice(
    PerformanceMode mode) {
  MutexLock lock(mutex_);

  auto context = context_.lock();
  if (context) return context;

  context = std::make_shared<EdgeTpuContext>();

  while (!usb_instance_) {
    vTaskDelay(pdMS_TO_TICKS(200));
  }
  if (!tpu_driver_.Initialize(usb_instance_, mode)) {
    return nullptr;
  }

  context_ = context;
  return context;
}

EdgeTpuPackage* EdgeTpuManager::RegisterPackage(const char* package_content,
                                                size_t length) {
  MutexLock lock(mutex_);
  auto package_ptr = (uintptr_t)package_content;

  if (packages_.find(package_ptr) != packages_.end()) {
    return packages_[package_ptr];
  }

  auto flexbuffer_map =
      flexbuffers::GetRoot((const uint8_t*)package_ptr, length).AsMap();
  auto package_binary = flexbuffer_map[kKeyExecutable].AsString();
  flatbuffers::Verifier package_verifier((const uint8_t*)package_binary.c_str(),
                                         package_binary.length());
  if (!package_verifier.VerifyBuffer<platforms::darwinn::Package>()) {
    printf("Package verification failed.\r\n");
    return nullptr;
  }

  auto* package =
      flatbuffers::GetRoot<platforms::darwinn::Package>(package_binary.c_str());
  if (flatbuffers::VectorLength(package->serialized_multi_executable()) == 0) {
    printf("No executables to register.\r\n");
    return nullptr;
  }

  auto* multi_executable =
      flatbuffers::GetRoot<platforms::darwinn::MultiExecutable>(
          package->serialized_multi_executable()->data());
  flatbuffers::Verifier multi_executable_verifier(
      package->serialized_multi_executable()->data(),
      flatbuffers::VectorLength(package->serialized_multi_executable()));
  if (!multi_executable_verifier
           .VerifyBuffer<platforms::darwinn::MultiExecutable>()) {
    printf("MultiExecutable verification failed.\r\n");
    return nullptr;
  }

  const platforms::darwinn::Executable* inference_exe = nullptr;
  const platforms::darwinn::Executable* parameter_caching_exe = nullptr;

  for (const auto* executable_serialized :
       *(multi_executable->serialized_executables())) {
    flatbuffers::Verifier verifier(
        (const uint8_t*)executable_serialized->c_str(),
        executable_serialized->size());
    if (!verifier.VerifyBuffer<platforms::darwinn::Executable>()) {
      printf("Executable verification failed.\r\n");
      return nullptr;
    }

    const auto* executable =
        flatbuffers::GetRoot<platforms::darwinn::Executable>(
            (const uint8_t*)executable_serialized->c_str());
    if (executable->type() ==
            platforms::darwinn::ExecutableType_EXECUTION_ONLY ||
        executable->type() == platforms::darwinn::ExecutableType_STAND_ALONE) {
      inference_exe = executable;
    } else if (executable->type() ==
               platforms::darwinn::ExecutableType_PARAMETER_CACHING) {
      parameter_caching_exe = executable;
    }
  }

  if (inference_exe == nullptr) {
    printf("Package does not have inference executable.\r\n");
    return nullptr;
  }

  auto* edgetpu_package =
      new EdgeTpuPackage(inference_exe, parameter_caching_exe);
  packages_[package_ptr] = edgetpu_package;

  return edgetpu_package;
}

TfLiteStatus EdgeTpuManager::Invoke(EdgeTpuPackage* package,
                                    TfLiteContext* context, TfLiteNode* node) {
  MutexLock lock(mutex_);
  if (package->parameter_caching_exe()) {
    auto token = package->parameter_caching_exe()->ParameterCachingToken();
    if (token != current_parameter_caching_token_) {
      cached_packages_.fill(nullptr);
      package->parameter_caching_exe()->Invoke(tpu_driver_, context, node);
      current_parameter_caching_token_ = token;
      cached_packages_[0] = package;
    } else {
      for (auto& cached_package : cached_packages_) {
        if (cached_package == package) {
          break;
        } else if (cached_package == nullptr) {
          package->parameter_caching_exe()->Invoke(tpu_driver_, context, node);
          cached_package = package;
        }
      }
    }
  } else {
    current_parameter_caching_token_ = 0;
  }

  return package->inference_exe()->Invoke(tpu_driver_, context, node);
}

std::optional<float> EdgeTpuManager::GetTemperature() {
  MutexLock lock(mutex_);
  // Only attempt to read the temperature if the device has been opened.
  auto context = context_.lock();
  if (context) return tpu_driver_.GetTemperature();
  return std::nullopt;
}

}  // namespace coralmicro
<|endoftext|>


<commit_before>/** @file
    @brief Test Implementation

    @date 2014

    @author
    Ryan Pavlik
    <ryan@sensics.com>
    <http://sensics.com>

*/

// Copyright 2014 Sensics, Inc.
//
// All rights reserved.
//
// (Final version intended to be licensed under
// the Apache License, Version 2.0)

// Internal Includes
#include <osvr/Routing/PathTreeFull.h>
#include <osvr/Routing/PathElementTools.h>
#include <osvr/Routing/PathElementTypes.h>

// Library/third-party includes
#include "gtest/gtest.h"

// Standard includes
// - none

using std::string;
using namespace osvr::routing;
// using osvr::routing::PathTree;
// namespace elements = osvr::routing::elements;

#if 0
// These didn't work for some reason...
#include <boost/variant/get.hpp>
template <typename ElementType>
inline bool isElementType(elements::PathElement const &elt) {
    return (boost::get<ElementType const *>(&elt) != NULL);
}

template <typename ElementType> inline bool isNodeType(PathNode const &node) {
    return isElementType<ElementType>(node.value());
}
#endif

TEST(PathTree, create) { ASSERT_NO_THROW(PathTree()); }

TEST(PathElement, getTypeName) {
    ASSERT_STREQ(elements::getTypeName<elements::NullElement>(), "NullElement");
}

TEST(PathTree, getPathRoot) {
    PathTree tree;
    PathNode *result = NULL;
    ASSERT_NO_THROW(result = &tree.getNodeByPath("/")) << "Get the root.";
    ASSERT_TRUE(result->isRoot());
}

TEST(PathTree, getPathSingleLevel) {
    PathTree tree;
    PathNode *result = NULL;
    ASSERT_NO_THROW(result = &tree.getNodeByPath("/test"))
        << "Get a new node just a single level in";
    ASSERT_STREQ(getTypeName(*result), "NullElement")
        << "Check the type of the new node.";
#if 0
    ASSERT_FALSE(isNodeType<elements::DeviceElement>(*result))
        << "Check the type of the new node.";
    ASSERT_TRUE(isNodeType<elements::NullElement>(*result))
        << "Check the type of the new node.";
#endif
    ASSERT_EQ(result->getName(), "test") << "Check the name of the new node";

    ASSERT_NO_THROW(tree.getNodeByPath("/test")) << "Get the same node again.";
    ASSERT_EQ(tree.getNodeByPath("/test"), *result)
        << "Ensure we're actually getting the same identity.";
    ASSERT_EQ(tree.getNodeByPath("/test/"), *result)
        << "Ensure trailing slashes don't matter.";
}

TEST(PathTree, getPathTwoLevel) {
    PathTree tree;
    PathNode *test2 = NULL;
    ASSERT_NO_THROW(test2 = &tree.getNodeByPath("/test1/test2"))
        << "Get a node two new levels in";
    // Check test2
    ASSERT_EQ(test2->getName(), "test2");
    ASSERT_FALSE(test2->hasChildren()) << "Make sure it has no children.";
    ASSERT_STREQ(getTypeName(*test2), "NullElement") << "Check type";
    ASSERT_FALSE(!test2->getParent()) << "Make sure it has a parent.";

    // Check test1
    PathNodePtr test1 = test2->getParent();
    ASSERT_EQ(test1->getName(), "test1");
    ASSERT_STREQ(getTypeName(*test1), "NullElement");
    ASSERT_FALSE(!test1->getParent()) << "Make sure it has a parent.";
    PathNodePtr root = test1->getParent();

    ASSERT_TRUE(root->isRoot());
    ASSERT_EQ(tree.getNodeByPath("/"), *root)
        << "Root identity should be preserved";
    ASSERT_EQ(tree.getNodeByPath("/test1/test2"), *test2)
        << "Identity should be preserved";
}

TEST(PathTree, addDevice) {
    PathTree tree;

    PathNode *dev = NULL;
    ASSERT_NO_THROW(dev = &addDevice(tree, "/org_opengoggles_sample/MyDevice"));

    // Check Device
    ASSERT_EQ(dev->getName(), "MyDevice");
    ASSERT_FALSE(dev->hasChildren()) << "Make sure it has no children.";
    ASSERT_STREQ(getTypeName(*dev), "DeviceElement") << "Check type";
    ASSERT_FALSE(!dev->getParent()) << "Make sure it has a parent.";

    // Check test1
    PathNodePtr plugin = dev->getParent();
    ASSERT_EQ(plugin->getName(), "org_opengoggles_sample");
    ASSERT_STREQ(getTypeName(*plugin), "PluginElement");
    ASSERT_FALSE(!plugin->getParent()) << "Make sure it has a parent.";
    PathNodePtr root = plugin->getParent();

    ASSERT_TRUE(root->isRoot());
    ASSERT_EQ(tree.getNodeByPath("/"), *root)
        << "Root identity should be preserved";
    ASSERT_EQ(tree.getNodeByPath("/org_opengoggles_sample/MyDevice"), *dev)
        << "Identity should be preserved";
}<commit_msg>Fixed my better element type tester, and use it all over now.<commit_after>/** @file
    @brief Test Implementation

    @date 2014

    @author
    Ryan Pavlik
    <ryan@sensics.com>
    <http://sensics.com>

*/

// Copyright 2014 Sensics, Inc.
//
// All rights reserved.
//
// (Final version intended to be licensed under
// the Apache License, Version 2.0)

// Internal Includes
#include <osvr/Routing/PathTreeFull.h>
#include <osvr/Routing/PathElementTools.h>
#include <osvr/Routing/PathElementTypes.h>

// Library/third-party includes
#include <boost/variant/get.hpp>
#include "gtest/gtest.h"

// Standard includes
// - none

using std::string;
using namespace osvr::routing;
// using osvr::routing::PathTree;
// namespace elements = osvr::routing::elements;

template <typename ElementType>
inline bool isElementType(elements::PathElement const &elt) {
    return (boost::get<ElementType const>(&elt) != NULL);
}

template <typename ElementType> inline bool isNodeType(PathNode const &node) {
    return isElementType<ElementType>(node.value());
}

TEST(PathTree, create) { ASSERT_NO_THROW(PathTree()); }

TEST(PathElement, getTypeName) {
    ASSERT_STREQ(elements::getTypeName<elements::NullElement>(), "NullElement");
}

TEST(PathElement, isElementType) {
    ASSERT_TRUE(isElementType<elements::NullElement>(elements::NullElement()));
    ASSERT_FALSE(
        isElementType<elements::DeviceElement>(elements::NullElement()));
}

TEST(PathTree, getPathRoot) {
    PathTree tree;
    PathNode *result = NULL;
    ASSERT_NO_THROW(result = &tree.getNodeByPath("/")) << "Get the root.";
    ASSERT_TRUE(result->isRoot());
}

TEST(PathTree, getPathSingleLevel) {
    PathTree tree;
    PathNode *result = NULL;
    ASSERT_NO_THROW(result = &tree.getNodeByPath("/test"))
        << "Get a new node just a single level in";
    ASSERT_TRUE(isNodeType<elements::NullElement>(*result))
        << "Check the type of the new node.";
    ASSERT_EQ(result->getName(), "test") << "Check the name of the new node";

    ASSERT_NO_THROW(tree.getNodeByPath("/test")) << "Get the same node again.";
    ASSERT_EQ(tree.getNodeByPath("/test"), *result)
        << "Ensure we're actually getting the same identity.";
    ASSERT_EQ(tree.getNodeByPath("/test/"), *result)
        << "Ensure trailing slashes don't matter.";
}

TEST(PathTree, getPathTwoLevel) {
    PathTree tree;
    PathNode *test2 = NULL;
    ASSERT_NO_THROW(test2 = &tree.getNodeByPath("/test1/test2"))
        << "Get a node two new levels in";
    // Check test2
    ASSERT_EQ(test2->getName(), "test2");
    ASSERT_FALSE(test2->hasChildren()) << "Make sure it has no children.";
    ASSERT_TRUE(isNodeType<elements::NullElement>(*test2)) << "Check type";
    ASSERT_FALSE(!test2->getParent()) << "Make sure it has a parent.";

    // Check test1
    PathNodePtr test1 = test2->getParent();
    ASSERT_EQ(test1->getName(), "test1");
    ASSERT_TRUE(isNodeType<elements::NullElement>(*test1));
    ASSERT_FALSE(!test1->getParent()) << "Make sure it has a parent.";
    PathNodePtr root = test1->getParent();

    ASSERT_TRUE(root->isRoot());
    ASSERT_EQ(tree.getNodeByPath("/"), *root)
        << "Root identity should be preserved";
    ASSERT_EQ(tree.getNodeByPath("/test1/test2"), *test2)
        << "Identity should be preserved";
}

TEST(PathTree, addDevice) {
    PathTree tree;

    PathNode *dev = NULL;
    ASSERT_NO_THROW(dev = &addDevice(tree, "/org_opengoggles_sample/MyDevice"));

    // Check Device
    ASSERT_EQ(dev->getName(), "MyDevice");
    ASSERT_FALSE(dev->hasChildren()) << "Make sure it has no children.";
    ASSERT_TRUE(isNodeType<elements::DeviceElement>(*dev)) << "Check type";
    ASSERT_FALSE(!dev->getParent()) << "Make sure it has a parent.";

    // Check test1
    PathNodePtr plugin = dev->getParent();
    ASSERT_EQ(plugin->getName(), "org_opengoggles_sample");
    ASSERT_TRUE(isNodeType<elements::PluginElement>(*plugin)) << "Check type";
    ASSERT_FALSE(!plugin->getParent()) << "Make sure it has a parent.";
    PathNodePtr root = plugin->getParent();

    ASSERT_TRUE(root->isRoot());
    ASSERT_EQ(tree.getNodeByPath("/"), *root)
        << "Root identity should be preserved";
    ASSERT_EQ(tree.getNodeByPath("/org_opengoggles_sample/MyDevice"), *dev)
        << "Identity should be preserved";
}<|endoftext|>


<commit_before>/* This file is part of Strigi Desktop Search
 *
 * Copyright (C) 2007 Jos van den Oever <jos@vandenoever.info>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "daemondbustest.h"

#include <algorithm>
#include <fstream>
#include <set>

#include <unistd.h>
#include "config.h"

#include <QtCore/QDebug>
#include <QtCore/QTime>
#include <QtCore/QDir>
#include <QtTest/QTest>

/**
   This test tests the dbus capabilities of strigidaemon.
   The script starts the daemon with a non-standard configuration file.
   This non-standard configuration file lets the daemon index only one
   directory. It uses ':memory:' as the directory to store the index.
   The ':memory:' directory is a virtual directory that exists only in the
   memory of the daemon.
   The daemon will also be started under a non-standard dbus service name.
   This ensures that the daemon does no interfere with a possible production
   strigidaemon that might be running.
 **/

using namespace std;
using namespace strigiunittest;

// Registers the fixture into the 'registry'
CPPUNIT_TEST_SUITE_REGISTRATION( DaemonDBusTest );

void
DaemonDBusTest::setUp() {
    qDebug() << "== DaemonDBusTest::setUp() ==";
    waitForStatusIdle(10000);
}

void
DaemonDBusTest::tearDown() {
    qDebug() << "== DaemonDBusTest::tearDown() ==";
}

bool
DaemonDBusTest::waitForStatusIdle(int milliseconds) {
    QTime timer;
    timer.start();
    QString status = strigiclient.getStatus()["Status"];
    while (status != "idling" && timer.elapsed() < milliseconds) {
        // sleep for 10 milliseconds
        strigi_nanosleep(10000000);
        status = strigiclient.getStatus()["Status"];
    }
    qDebug() << "Waited " << timer.elapsed() << " milliseconds for strigidaemon to start.";
    return status == "idling";
}

void
DaemonDBusTest::testProcess() {
    qDebug() << "== DaemonDBusTest::testProcess() ==";
}

void
DaemonDBusTest::testStatusOfEmptyIndex() {
    qDebug() << "== DaemonDBusTest::testStatusOfEmptyIndex() ==";
    // clear out the index
    QStringList sl = strigiclient.getIndexedDirectories();
    strigiclient.setIndexedDirectories(QStringList());
    strigiclient.startIndexing();
    waitForStatusIdle(1000);
    QMap<QString, QString> status = strigiclient.getStatus();
    qDebug() << "Status: '" << status << "'" << endl;
    CPPUNIT_ASSERT_MESSAGE("Daemon status is too short.", status.size() > 1);
    bool ok;
    int numIndexed = status["Documents indexed"].toInt(&ok);
    CPPUNIT_ASSERT_MESSAGE("Number of documents indexed cannot be determined.", ok);
    CPPUNIT_ASSERT_MESSAGE("Not exactly 0 documents in the index.", numIndexed == 0);

    // reindex the original files
    strigiclient.setIndexedDirectories(sl);
    strigiclient.startIndexing();
}
void
DaemonDBusTest::testStopDaemon() {
    qDebug() << "== DaemonDBusTest::testStopDaemon() ==";
}
void
DaemonDBusTest::testIndexing() {
    qDebug() << "== DaemonDBusTest::testIndexing() ==";
    // count the files in the indexing dir
    int docsfound = 0;
    // check how many files are listed in the data dir
    foreach (const QString&d, strigiclient.getIndexedDirectories()) {
        QDir dir(d);
        docsfound += dir.entryList(QDir::Files).size();
    }
    for (int i=0; i<5; ++i) {
        // start the indexing
        strigiclient.startIndexing();
        waitForStatusIdle(1000);
        QMap<QString, QString> status = strigiclient.getStatus();
        int ndocs = status.value("Documents indexed").toUInt();
        CPPUNIT_ASSERT_MESSAGE("Not the right amount of documents indexed.",
            ndocs == docsfound);
    }
}
void
DaemonDBusTest::testSimpleQuery() {
    qDebug() << "== DaemonDBusTest::testSimpleQuery() ==";
    int nhits = strigiclient.countHits("hello");
    cerr << "nhits hello: " << nhits << endl;
    CPPUNIT_ASSERT(nhits == 2);
    nhits = strigiclient.countHits("world");
    cerr << "nhits world: " << nhits << endl;
    CPPUNIT_ASSERT(nhits == 1);
}
<commit_msg>increase maximum allowed waiting time<commit_after>/* This file is part of Strigi Desktop Search
 *
 * Copyright (C) 2007 Jos van den Oever <jos@vandenoever.info>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "daemondbustest.h"

#include <algorithm>
#include <fstream>
#include <set>

#include <unistd.h>
#include "config.h"

#include <QtCore/QDebug>
#include <QtCore/QTime>
#include <QtCore/QDir>
#include <QtTest/QTest>

/**
   This test tests the dbus capabilities of strigidaemon.
   The script starts the daemon with a non-standard configuration file.
   This non-standard configuration file lets the daemon index only one
   directory. It uses ':memory:' as the directory to store the index.
   The ':memory:' directory is a virtual directory that exists only in the
   memory of the daemon.
   The daemon will also be started under a non-standard dbus service name.
   This ensures that the daemon does no interfere with a possible production
   strigidaemon that might be running.
 **/

using namespace std;
using namespace strigiunittest;

// Registers the fixture into the 'registry'
CPPUNIT_TEST_SUITE_REGISTRATION( DaemonDBusTest );

void
DaemonDBusTest::setUp() {
    qDebug() << "== DaemonDBusTest::setUp() ==";
    waitForStatusIdle(10000);
}

void
DaemonDBusTest::tearDown() {
    qDebug() << "== DaemonDBusTest::tearDown() ==";
}

bool
DaemonDBusTest::waitForStatusIdle(int milliseconds) {
    QTime timer;
    timer.start();
    QString status = strigiclient.getStatus()["Status"];
    while (status != "idling" && timer.elapsed() < milliseconds) {
        // sleep for 10 milliseconds
        strigi_nanosleep(10000000);
        status = strigiclient.getStatus()["Status"];
    }
    qDebug() << "Waited " << timer.elapsed() << " milliseconds for strigidaemon to start.";
    return status == "idling";
}

void
DaemonDBusTest::testProcess() {
    qDebug() << "== DaemonDBusTest::testProcess() ==";
}

void
DaemonDBusTest::testStatusOfEmptyIndex() {
    qDebug() << "== DaemonDBusTest::testStatusOfEmptyIndex() ==";
    // clear out the index
    QStringList sl = strigiclient.getIndexedDirectories();
    strigiclient.setIndexedDirectories(QStringList());
    strigiclient.startIndexing();
    waitForStatusIdle(10000);
    QMap<QString, QString> status = strigiclient.getStatus();
    qDebug() << "Status: '" << status << "'" << endl;
    CPPUNIT_ASSERT_MESSAGE("Daemon status is too short.", status.size() > 1);
    bool ok;
    int numIndexed = status["Documents indexed"].toInt(&ok);
    CPPUNIT_ASSERT_MESSAGE("Number of documents indexed cannot be determined.", ok);
    CPPUNIT_ASSERT_MESSAGE("Not exactly 0 documents in the index.", numIndexed == 0);

    // reindex the original files
    strigiclient.setIndexedDirectories(sl);
    strigiclient.startIndexing();
}
void
DaemonDBusTest::testStopDaemon() {
    qDebug() << "== DaemonDBusTest::testStopDaemon() ==";
}
void
DaemonDBusTest::testIndexing() {
    qDebug() << "== DaemonDBusTest::testIndexing() ==";
    // count the files in the indexing dir
    int docsfound = 0;
    // check how many files are listed in the data dir
    foreach (const QString&d, strigiclient.getIndexedDirectories()) {
        QDir dir(d);
        docsfound += dir.entryList(QDir::Files).size();
    }
    for (int i=0; i<5; ++i) {
        // start the indexing
        strigiclient.startIndexing();
        waitForStatusIdle(10000);
        QMap<QString, QString> status = strigiclient.getStatus();
        int ndocs = status.value("Documents indexed").toUInt();
        CPPUNIT_ASSERT_MESSAGE("Not the right amount of documents indexed.",
            ndocs == docsfound);
    }
}
void
DaemonDBusTest::testSimpleQuery() {
    qDebug() << "== DaemonDBusTest::testSimpleQuery() ==";
    int nhits = strigiclient.countHits("hello");
    cerr << "nhits hello: " << nhits << endl;
    CPPUNIT_ASSERT(nhits == 2);
    nhits = strigiclient.countHits("world");
    cerr << "nhits world: " << nhits << endl;
    CPPUNIT_ASSERT(nhits == 1);
}
<|endoftext|>


<commit_before>// -----------------------------------------------------------------------------
// Local search optimization clustering
// By Twan van Laarhoven
// License: BSD style, see file LICENSE
// -----------------------------------------------------------------------------

#include "lso_cluster.hpp"
#include "argument_parser.hpp"
#include <vector>
#include <map>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <cstring>
#include <boost/lexical_cast.hpp>

#define OCTAVE_QUIT do{}while(0)
#include "lso_cluster_impl.hpp"

using namespace std;
using namespace lso_cluster;
using boost::lexical_cast;

// -----------------------------------------------------------------------------
// File formats
// -----------------------------------------------------------------------------

template <typename T>
struct LabeledGraph {
	map<T,map<T,double> > nodes;
	void add_nodes(int i) {
		for (int k = (int)nodes.size() ; k <= i ; ++k) {
			nodes[k]; // make it exist
		}
	}
	void add(T i, T j, double w) {
		add_nodes(i);
		add_nodes(j);
		if (w != 0.0) {
			nodes[i][j] = w;
			nodes[j][i] = w; // symmetric
		}
	}
	int size() const {
		return (int)nodes.size();
	}
	int nnz() const {
		size_t nnz = 0;
		for (typename map<T,map<T,double> >::const_iterator it = nodes.begin() ; it != nodes.end() ; ++it) {
			nnz += it->second.size();
		}
		return (int)nnz;
	}
	SparseMatrix to_sparse_matrix() const {
		// find unique ids
		int id = 0;
		map<T,int> ids;
		for (typename map<T,map<T,double> >::const_iterator it = nodes.begin() ; it != nodes.end() ; ++it) {
			ids[it->first] = id++;
		}
		// to graph
		SparseMatrix out(size(), size(), nnz());
		int k = 0;
		for (typename map<T,map<T,double> >::const_iterator it = nodes.begin() ; it != nodes.end() ; ++it) {
			out.cidx(ids[it->first]) = k;
			for (typename map<T,double>::const_iterator jt = it->second.begin() ; jt != it->second.end() ; ++jt) {
				out.ridx(k) = ids[jt->first];
				out.data(k) = jt->second;
				k++;
			}
		}
		out.cidx(size()) = k;
		return out;
	}
};
SparseMatrix load_graph(istream& in) {
	LabeledGraph<int> graph;
	while (in) {
		int i = -1, j = -1;
		double w = -1;
		in >> i >> j >> w;
		if (i != -1 && j != -1 && w != -1) {
			graph.add(i,j,w);
		}
	}
	return graph.to_sparse_matrix();
}
vector<clus_t> load_clustering(istream& in) {
	vector<string> labels;
	while (in) {
		string str;
		getline(in, str);
		if (!str.empty()) {
			labels.push_back(str);
		}
	}
	return clustering_from_array(&labels[0], labels.size());
}

SparseMatrix load_graph(string const& fn) {
	if (fn == "-") {
		return load_graph(cin);
	} else {
		ifstream fs(fn.c_str());
		if (!fs.good()) {
			throw std::runtime_error("Unable to open file: " + fn);
		}
		return load_graph(fs);
	}
}
vector<clus_t> load_clustering(string const& fn) {
	if (fn == "-") {
		return load_clustering(cin);
	} else {
		ifstream fs(fn.c_str());
		if (!fs.good()) {
			throw std::runtime_error("Unable to open file: " + fn);
		}
		return load_clustering(fs);
	}
}

void print_clustering(ostream& out, vector<clus_t> const& clustering) {
	for (size_t i = 0 ; i < clustering.size() ; ++i) {
		out << clustering[i] << endl;
	}
}
void print_clustering(std::string const& fn, vector<clus_t> const& clustering) {
	if (fn == "-" || fn.empty()) {
		print_clustering(cout, clustering);
	} else {
		ofstream fs(fn.c_str());
		if (!fs.good()) {
			throw std::runtime_error("Unable to open file: " + fn);
		}
		print_clustering(fs, clustering);
	}
}

// -----------------------------------------------------------------------------
// Command line parsing
// -----------------------------------------------------------------------------

struct ParamSourceCommandline : ParamSource {
  private:
	int argc, i;
	char const** argv;
	const char* next() {
		if (i < argc) {
			return argv[i++];
		} else {
			throw std::invalid_argument("Expected an additional argument");
		}
	}
  public:
	ParamSourceCommandline(int argc, const char** argv)
		: argc(argc), i(0), argv(argv)
	{}
	virtual bool end() {
		return i >= argc;
	}
	virtual string get_parameter_name() {
		// parameters are indicated by "--OPT"
		const char* opt = next();
		if (opt[0] == '-' && opt[1] == '-') {
			// negated boolean flags
			if (opt[2] == 'n' && opt[3] == 'o' && opt[4] == '-') {
				return opt+5;
			}
			// normal arguments
			return opt+2;
		} else if (opt[0] == '-' && opt[1] == 'o' && opt[2] == 0) {
			return "out";
		} else if (opt[0] == '-' && opt[1] == 'q' && opt[2] == 0) {
			return "quiet";
		} else {
			throw std::invalid_argument("Expected an optional parameter name ('--something')");
		}
	}
	virtual string get_string_argument(vector<double>* more_out = 0) {
		return next();
	}
	virtual int get_int_argument() {
		return lexical_cast<int>(next());
	}
	virtual bool get_bool_argument() {
		if (i >= argc || argv[i][0] == '-') {
			if (i > 0 && i+1 < argc && argv[i-1][0] == '-' && argv[i-1][0] == '-' && argv[i-1][0] == 'n' && argv[i-1][0] == 'o') {
				return false;
			} else {
				return true;
			}
		}
		char const* arg = next();
		if (strcmp(arg,"yes") == 0 || strcmp(arg,"true") == 0 || strcmp(arg,"1") == 0) return true;
		if (strcmp(arg,"no") == 0 || strcmp(arg,"false") == 0 || strcmp(arg,"0") == 0) return false;
		throw std::invalid_argument("Expected a boolean value");
	}
	virtual double get_double_argument() {
		return lexical_cast<double>(next());
	}
	virtual vector<clus_t> get_1dvec_argument() {
		return load_clustering(next());
	}
	virtual SparseMatrix get_matrix_argument() {
		return load_graph(next());
	}
};

struct LsoMainFunctionCommandLine : LsoMainFunction {
	// extra options
	string output_file;
	bool quiet;

	LsoMainFunctionCommandLine()
		: LsoMainFunction(cerr)
		, quiet(false)
	{}

	virtual void add_parameter(string const& key, ArgSource& args) {
		if (key == "out") {
			output_file = args.get_string_argument();
		} else if (key == "quiet") {
			quiet = true;
		} else {
			LsoMainFunction::add_parameter(key,args);
		}
	}
};

// -----------------------------------------------------------------------------
// Implementation
// -----------------------------------------------------------------------------

void print_usage(char const* argv0) {
	cout << "Usage: " << argv0 << " <FILE> [OPTIONS]" << endl;
}

int main(int argc, char const** argv) {
	if (argc == 1) {
		print_usage(argv[0]);
		return EXIT_SUCCESS;
	}
	try {
		// parse arguments, and run the clustering algorithm
		ParamSourceCommandline param_source(argc-1,argv+1);
		LsoMainFunctionCommandLine runner;
		runner.add_all_parameters(param_source);
		runner.run();

		// store outputs
		if (!runner.quiet) {
			cerr << "loss: " << runner.loss << endl;
			cerr << "num clusters: " << runner.num_clusters << endl;
		}
		print_clustering(runner.output_file, runner.clustering);

	} catch (std::exception const& e) {
		cerr << e.what() << endl;
		return EXIT_FAILURE;
	} catch (...) {
		cerr << "Unexpected error" << endl;
		return EXIT_FAILURE;
	}
	return EXIT_SUCCESS;
}
<commit_msg>enable passing function parameters for standalone version<commit_after>// -----------------------------------------------------------------------------
// Local search optimization clustering
// By Twan van Laarhoven
// License: BSD style, see file LICENSE
// -----------------------------------------------------------------------------

#include "lso_cluster.hpp"
#include "argument_parser.hpp"
#include <vector>
#include <map>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <cstring>
#include <boost/lexical_cast.hpp>
#include <cstdlib>

#define OCTAVE_QUIT do{}while(0)
#include "lso_cluster_impl.hpp"

using namespace std;
using namespace lso_cluster;
using boost::lexical_cast;

// -----------------------------------------------------------------------------
// File formats
// -----------------------------------------------------------------------------

template <typename T>
struct LabeledGraph {
	map<T,map<T,double> > nodes;
	void add_nodes(int i) {
		for (int k = (int)nodes.size() ; k <= i ; ++k) {
			nodes[k]; // make it exist
		}
	}
	void add(T i, T j, double w) {
		add_nodes(i);
		add_nodes(j);
		if (w != 0.0) {
			nodes[i][j] = w;
			nodes[j][i] = w; // symmetric
		}
	}
	int size() const {
		return (int)nodes.size();
	}
	int nnz() const {
		size_t nnz = 0;
		for (typename map<T,map<T,double> >::const_iterator it = nodes.begin() ; it != nodes.end() ; ++it) {
			nnz += it->second.size();
		}
		return (int)nnz;
	}
	SparseMatrix to_sparse_matrix() const {
		// find unique ids
		int id = 0;
		map<T,int> ids;
		for (typename map<T,map<T,double> >::const_iterator it = nodes.begin() ; it != nodes.end() ; ++it) {
			ids[it->first] = id++;
		}
		// to graph
		SparseMatrix out(size(), size(), nnz());
		int k = 0;
		for (typename map<T,map<T,double> >::const_iterator it = nodes.begin() ; it != nodes.end() ; ++it) {
			out.cidx(ids[it->first]) = k;
			for (typename map<T,double>::const_iterator jt = it->second.begin() ; jt != it->second.end() ; ++jt) {
				out.ridx(k) = ids[jt->first];
				out.data(k) = jt->second;
				k++;
			}
		}
		out.cidx(size()) = k;
		return out;
	}
};
SparseMatrix load_graph(istream& in) {
	LabeledGraph<int> graph;
	while (in) {
		int i = -1, j = -1;
		double w = -1;
		in >> i >> j >> w;
		if (i != -1 && j != -1 && w != -1) {
			graph.add(i,j,w);
		}
	}
	return graph.to_sparse_matrix();
}
vector<clus_t> load_clustering(istream& in) {
	vector<string> labels;
	while (in) {
		string str;
		getline(in, str);
		if (!str.empty()) {
			labels.push_back(str);
		}
	}
	return clustering_from_array(&labels[0], labels.size());
}

SparseMatrix load_graph(string const& fn) {
	if (fn == "-") {
		return load_graph(cin);
	} else {
		ifstream fs(fn.c_str());
		if (!fs.good()) {
			throw std::runtime_error("Unable to open file: " + fn);
		}
		return load_graph(fs);
	}
}
vector<clus_t> load_clustering(string const& fn) {
	if (fn == "-") {
		return load_clustering(cin);
	} else {
		ifstream fs(fn.c_str());
		if (!fs.good()) {
			throw std::runtime_error("Unable to open file: " + fn);
		}
		return load_clustering(fs);
	}
}

void print_clustering(ostream& out, vector<clus_t> const& clustering) {
	for (size_t i = 0 ; i < clustering.size() ; ++i) {
		out << clustering[i] << endl;
	}
}
void print_clustering(std::string const& fn, vector<clus_t> const& clustering) {
	if (fn == "-" || fn.empty()) {
		print_clustering(cout, clustering);
	} else {
		ofstream fs(fn.c_str());
		if (!fs.good()) {
			throw std::runtime_error("Unable to open file: " + fn);
		}
		print_clustering(fs, clustering);
	}
}

// -----------------------------------------------------------------------------
// Command line parsing
// -----------------------------------------------------------------------------

struct ParamSourceCommandline : ParamSource {
  private:
	int argc, i;
	char const** argv;
	const char* next() {
		if (i < argc) {
			return argv[i++];
		} else {
			throw std::invalid_argument("Expected an additional argument");
		}
	}
  public:
	ParamSourceCommandline(int argc, const char** argv)
		: argc(argc), i(0), argv(argv)
	{}
	virtual bool end() {
		return i >= argc;
	}
	virtual string get_parameter_name() {
		// parameters are indicated by "--OPT"
		const char* opt = next();
		if (opt[0] == '-' && opt[1] == '-') {
			// negated boolean flags
			if (opt[2] == 'n' && opt[3] == 'o' && opt[4] == '-') {
				return opt+5;
			}
			// normal arguments
			return opt+2;
		} else if (opt[0] == '-' && opt[1] == 'o' && opt[2] == 0) {
			return "out";
		} else if (opt[0] == '-' && opt[1] == 'q' && opt[2] == 0) {
			return "quiet";
		} else {
			throw std::invalid_argument("Expected an optional parameter name ('--something')");
		}
	}
	virtual string get_string_argument(vector<double>* more_out = 0) {
		const char* s = next();
		if (i + 1 < argc) {
			// grab extra string data
			more_out->clear();
			for (int j = i; j < argc && argv[j][0] != '-'; ++j) {
				more_out->push_back(atof(argv[j]));
			}
			i += more_out->size();
		}
		return s;
	}
	virtual int get_int_argument() {
		return lexical_cast<int>(next());
	}
	virtual bool get_bool_argument() {
		if (i >= argc || argv[i][0] == '-') {
			if (i > 0 && i+1 < argc && argv[i-1][0] == '-' && argv[i-1][0] == '-' && argv[i-1][0] == 'n' && argv[i-1][0] == 'o') {
				return false;
			} else {
				return true;
			}
		}
		char const* arg = next();
		if (strcmp(arg,"yes") == 0 || strcmp(arg,"true") == 0 || strcmp(arg,"1") == 0) return true;
		if (strcmp(arg,"no") == 0 || strcmp(arg,"false") == 0 || strcmp(arg,"0") == 0) return false;
		throw std::invalid_argument("Expected a boolean value");
	}
	virtual double get_double_argument() {
		return lexical_cast<double>(next());
	}
	virtual vector<clus_t> get_1dvec_argument() {
		return load_clustering(next());
	}
	virtual SparseMatrix get_matrix_argument() {
		return load_graph(next());
	}
};

struct LsoMainFunctionCommandLine : LsoMainFunction {
	// extra options
	string output_file;
	bool quiet;

	LsoMainFunctionCommandLine()
		: LsoMainFunction(cerr)
		, quiet(false)
	{}

	virtual void add_parameter(string const& key, ArgSource& args) {
		if (key == "out") {
			output_file = args.get_string_argument();
		} else if (key == "quiet") {
			quiet = true;
		} else {
			LsoMainFunction::add_parameter(key,args);
		}
	}
};

// -----------------------------------------------------------------------------
// Implementation
// -----------------------------------------------------------------------------

void print_usage(char const* argv0) {
	cout << "Usage: " << argv0 << " <FILE> [OPTIONS]" << endl;
}

int main(int argc, char const** argv) {
	if (argc == 1) {
		print_usage(argv[0]);
		return EXIT_SUCCESS;
	}
	try {
		// parse arguments, and run the clustering algorithm
		ParamSourceCommandline param_source(argc-1,argv+1);
		LsoMainFunctionCommandLine runner;
		runner.add_all_parameters(param_source);
		runner.run();

		// store outputs
		if (!runner.quiet) {
			cerr << "loss: " << runner.loss << endl;
			cerr << "num clusters: " << runner.num_clusters << endl;
		}
		print_clustering(runner.output_file, runner.clustering);

	} catch (std::exception const& e) {
		cerr << e.what() << endl;
		return EXIT_FAILURE;
	} catch (...) {
		cerr << "Unexpected error" << endl;
		return EXIT_FAILURE;
	}
	return EXIT_SUCCESS;
}
<|endoftext|>