<commit_before>
#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>

#include "VFSPP/merged.hpp"

using namespace vfspp;
using namespace vfspp::merged;

using namespace boost;

namespace
{
	boost::shared_ptr<MergedEntry> getParent(MergedEntry* entry)
	{
		size_t slash = entry->getPath().find_last_of(DirectorySeparatorChar);

		if (slash != string_type::npos)
		{
			string_type parentPath = entry->getPath();
			parentPath.resize(slash);

			return static_pointer_cast<MergedEntry>(entry->parentSystem->getRootEntry()->getChild(parentPath));
		}
		else
		{
			// return null for root
			return shared_ptr<MergedEntry>();
		}
	}
}

typedef unordered_map<string_type, shared_ptr<MergedEntry> >::iterator ChildMapping;

MergedEntry::MergedEntry(MergedFileSystem* parentSystem, FileEntryPointer contained) :
IFileSystemEntry(contained ? contained->getPath() : ""), parentSystem(parentSystem), containedEntry(contained),
dirty(true)
{
}

void MergedEntry::addChildren(IFileSystemEntry* entry)
{
	if (entry->getType() != DIRECTORY)
	{
		return;
	}

	std::vector<FileEntryPointer> entries;

	entry->listChildren(entries);

	BOOST_FOREACH(FileEntryPointer& childEntry, entries)
	{
		string_type entryName = normalizePath(childEntry->getPath(), parentSystem->caseInsensitive);
		if (!isRoot())
		{
			entryName = normalizePath(entryName.substr(path.size()));
		}
		size_t slash = entryName.find_first_of(DirectorySeparatorChar);

		if (slash != string_type::npos)
		{
			entryName.resize(slash);
		}

		if (cachedChildMapping.find(entryName) == cachedChildMapping.end())
		{
			// This entry hasn't been found yet
			shared_ptr<MergedEntry> newEntry(new MergedEntry(parentSystem, childEntry));

			cachedChildMapping.insert(std::make_pair(entryName, newEntry));
			cachedChildEntries.push_back(newEntry);
		}
	}
}

void MergedEntry::cacheChildren()
{
	cachedChildEntries.clear();
	cachedChildMapping.clear();

	BOOST_FOREACH(shared_ptr<IFileSystem>& system, parentSystem->fileSystems)
	{
		if (system->supportedOperations() & OP_READ)
		{
			if (isRoot())
			{
				addChildren(system->getRootEntry());
			}
			else
			{
				FileEntryPointer entry = system->getRootEntry()->getChild(path);

				if (entry)
				{
					addChildren(entry.get());
				}
			}
		}
	}

	dirty = false;
}

boost::shared_ptr<MergedEntry> MergedEntry::getEntryInternal(const string_type& path)
{
	if (dirty)
	{
		cacheChildren();
	}

	size_t separator = path.find_first_of(DirectorySeparatorChar);

	if (separator == string_type::npos)
	{
		ChildMapping found = cachedChildMapping.find(path);

		if (found != cachedChildMapping.end())
		{
			return found->second;
		}
	}
	else
	{
		string_type thisLevel = path.substr(0, separator);

		ChildMapping found = cachedChildMapping.find(thisLevel);

		if (found != cachedChildMapping.end())
		{
			return found->second->getEntryInternal(path.substr(separator + 1));
		}
	}

	return shared_ptr<MergedEntry>();
}

FileEntryPointer MergedEntry::getChild(const string_type& path)
{
	if (getType() != DIRECTORY)
	{
		throw InvalidOperationException("Entry is no directory!");
	}

	return getEntryInternal(normalizePath(path, parentSystem->caseInsensitive));
}

size_t MergedEntry::numChildren()
{
	if (getType() != DIRECTORY)
	{
		throw InvalidOperationException("Entry is no directory!");
	}

	if (dirty)
	{
		cacheChildren();
	}

	return cachedChildEntries.size();
}

void MergedEntry::listChildren(std::vector<FileEntryPointer>& outVector)
{
	if (getType() != DIRECTORY)
	{
		throw InvalidOperationException("Entry is no directory!");
	}

	if (dirty)
	{
		cacheChildren();
	}

	outVector.clear();

	std::copy(cachedChildEntries.begin(), cachedChildEntries.end(), std::back_inserter(outVector));
}

boost::shared_ptr<std::streambuf> MergedEntry::open(int mode)
{
	int ops = modeToOperation(mode);

	if (!(parentSystem->supportedOperations() & ops))
	{
		throw InvalidOperationException("No filesystem supports the requested operations!");
	}

	if (getType() != FILE)
	{
		throw InvalidOperationException("Entry is no file!");
	}

	BOOST_FOREACH(shared_ptr<IFileSystem>& system, parentSystem->fileSystems)
	{
		if (system->supportedOperations() & ops)
		{
			shared_ptr<IFileSystemEntry> entry = system->getRootEntry()->getChild(path);

			if (entry && entry->getType() == FILE)
			{
				try
				{
					shared_ptr<std::streambuf> buffer = entry->open(mode);

					if (buffer)
					{
						// Stop if we have sucessfully opened a file
						return buffer;
					}
				}
				catch (const FileSystemException&)
				{
					// Ignore filesystem errors and continue searching
				}
			}
		}
	}

	throw FileSystemException("Failed to open file from any filesystem!");
}

EntryType MergedEntry::getType() const
{
	if (!isRoot())
	{
		return containedEntry->getType();
	}
	else
	{
		// Root directory
		return DIRECTORY;
	}
}

bool MergedEntry::deleteChild(const string_type& name)
{
	if (!(parentSystem->supportedOperations() & OP_DELETE))
	{
		throw InvalidOperationException("No filesystem supports deleting!");
	}

	if (getType() != DIRECTORY)
	{
		throw InvalidOperationException("Entry is no directory!");
	}

	string_type normalized = normalizePath(name);

	// we want to delete the entry in the directory that actually contains it to keep
	// recaching overhead as small as possible
	size_t slash = normalized.find(DirectorySeparatorStr);
	if (slash != string_type::npos)
	{
		// remove everything after the slash
		normalized.resize(slash);

		FileEntryPointer entry = getEntryInternal(normalized);

		if (entry)
		{
			return entry->deleteChild(name.substr(slash + 1, name.size() - 1));
		}
		else
		{
			return false;
		}
	}

	bool success = false;
	BOOST_FOREACH(shared_ptr<IFileSystem>& system, parentSystem->fileSystems)
	{
		if (system->supportedOperations() & OP_DELETE)
		{
			FileEntryPointer entry = system->getRootEntry()->getChild(path);

			if (entry && entry->getType() == DIRECTORY)
			{
				try
				{
					success = entry->deleteChild(name) || success;
				}
				catch (const FileSystemException&)
				{
					// Ignore filesystem errors and continue searching
				}
			}
		}
	}

	return success;
}

FileEntryPointer MergedEntry::createEntry(EntryType type, const string_type& name)
{
	if (!(parentSystem->supportedOperations() & OP_CREATE))
	{
		throw InvalidOperationException("No filesystem supports deleting!");
	}

	if (getType() != DIRECTORY)
	{
		throw InvalidOperationException("Entry is no directory!");
	}

	BOOST_FOREACH(shared_ptr<IFileSystem>& system, parentSystem->fileSystems)
	{
		if (system->supportedOperations() & OP_CREATE)
		{
			FileEntryPointer entry = system->getRootEntry()->getChild(path);

			if (entry && entry->getType() == DIRECTORY)
			{
				try
				{
					FileEntryPointer newEntry = entry->createEntry(type, name);

					if (newEntry)
					{
						// Stop if we have sucessfully created an entry
						return shared_ptr<MergedEntry>(new MergedEntry(parentSystem, newEntry));
					}
				}
				catch (const FileSystemException&)
				{
					// Ignore filesystem errors and continue searching
				}
			}
		}
	}

	return FileEntryPointer();
}

void MergedEntry::rename(const string_type& newPath)
{
	if (isRoot())
	{
		throw FileSystemException("Cannot rename root!");
	}

	containedEntry->rename(newPath);

	shared_ptr<MergedEntry> parent = getParent(this);

	if (parent)
	{
		parent->dirty = true;
	}
	else
	{
		parentSystem->getRootEntry()->dirty = true;
	}
}

time_t MergedEntry::lastWriteTime()
{
	return containedEntry->lastWriteTime();
}
<commit_msg>Try to open the contained entry first.<commit_after>
#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>

#include "VFSPP/merged.hpp"

using namespace vfspp;
using namespace vfspp::merged;

using namespace boost;

namespace
{
	boost::shared_ptr<MergedEntry> getParent(MergedEntry* entry)
	{
		size_t slash = entry->getPath().find_last_of(DirectorySeparatorChar);

		if (slash != string_type::npos)
		{
			string_type parentPath = entry->getPath();
			parentPath.resize(slash);

			return static_pointer_cast<MergedEntry>(entry->parentSystem->getRootEntry()->getChild(parentPath));
		}
		else
		{
			// return null for root
			return shared_ptr<MergedEntry>();
		}
	}
}

typedef unordered_map<string_type, shared_ptr<MergedEntry> >::iterator ChildMapping;

MergedEntry::MergedEntry(MergedFileSystem* parentSystem, FileEntryPointer contained) :
IFileSystemEntry(contained ? contained->getPath() : ""), parentSystem(parentSystem), containedEntry(contained),
dirty(true)
{
}

void MergedEntry::addChildren(IFileSystemEntry* entry)
{
	if (entry->getType() != DIRECTORY)
	{
		return;
	}

	std::vector<FileEntryPointer> entries;

	entry->listChildren(entries);

	BOOST_FOREACH(FileEntryPointer& childEntry, entries)
	{
		string_type entryName = normalizePath(childEntry->getPath(), parentSystem->caseInsensitive);
		if (!isRoot())
		{
			entryName = normalizePath(entryName.substr(path.size()));
		}
		size_t slash = entryName.find_first_of(DirectorySeparatorChar);

		if (slash != string_type::npos)
		{
			entryName.resize(slash);
		}

		if (cachedChildMapping.find(entryName) == cachedChildMapping.end())
		{
			// This entry hasn't been found yet
			shared_ptr<MergedEntry> newEntry(new MergedEntry(parentSystem, childEntry));

			cachedChildMapping.insert(std::make_pair(entryName, newEntry));
			cachedChildEntries.push_back(newEntry);
		}
	}
}

void MergedEntry::cacheChildren()
{
	cachedChildEntries.clear();
	cachedChildMapping.clear();

	BOOST_FOREACH(shared_ptr<IFileSystem>& system, parentSystem->fileSystems)
	{
		if (system->supportedOperations() & OP_READ)
		{
			if (isRoot())
			{
				addChildren(system->getRootEntry());
			}
			else
			{
				FileEntryPointer entry = system->getRootEntry()->getChild(path);

				if (entry)
				{
					addChildren(entry.get());
				}
			}
		}
	}

	dirty = false;
}

boost::shared_ptr<MergedEntry> MergedEntry::getEntryInternal(const string_type& path)
{
	if (dirty)
	{
		cacheChildren();
	}

	size_t separator = path.find_first_of(DirectorySeparatorChar);

	if (separator == string_type::npos)
	{
		ChildMapping found = cachedChildMapping.find(path);

		if (found != cachedChildMapping.end())
		{
			return found->second;
		}
	}
	else
	{
		string_type thisLevel = path.substr(0, separator);

		ChildMapping found = cachedChildMapping.find(thisLevel);

		if (found != cachedChildMapping.end())
		{
			return found->second->getEntryInternal(path.substr(separator + 1));
		}
	}

	return shared_ptr<MergedEntry>();
}

FileEntryPointer MergedEntry::getChild(const string_type& path)
{
	if (getType() != DIRECTORY)
	{
		throw InvalidOperationException("Entry is no directory!");
	}

	return getEntryInternal(normalizePath(path, parentSystem->caseInsensitive));
}

size_t MergedEntry::numChildren()
{
	if (getType() != DIRECTORY)
	{
		throw InvalidOperationException("Entry is no directory!");
	}

	if (dirty)
	{
		cacheChildren();
	}

	return cachedChildEntries.size();
}

void MergedEntry::listChildren(std::vector<FileEntryPointer>& outVector)
{
	if (getType() != DIRECTORY)
	{
		throw InvalidOperationException("Entry is no directory!");
	}

	if (dirty)
	{
		cacheChildren();
	}

	outVector.clear();

	std::copy(cachedChildEntries.begin(), cachedChildEntries.end(), std::back_inserter(outVector));
}

boost::shared_ptr<std::streambuf> MergedEntry::open(int mode)
{
	int ops = modeToOperation(mode);

	if (!(parentSystem->supportedOperations() & ops))
	{
		throw InvalidOperationException("No filesystem supports the requested operations!");
	}

	if (getType() != FILE)
	{
		throw InvalidOperationException("Entry is no file!");
	}

	try
	{
		// First try to open the contained entry
		return containedEntry->open(mode);
	}
	catch (...)
	{
		// If that fails try to open a file of another filesystem
	}

	BOOST_FOREACH(shared_ptr<IFileSystem>& system, parentSystem->fileSystems)
	{
		if (system->supportedOperations() & ops)
		{
			shared_ptr<IFileSystemEntry> entry = system->getRootEntry()->getChild(path);

			if (entry && entry->getType() == FILE)
			{
				try
				{
					shared_ptr<std::streambuf> buffer = entry->open(mode);

					if (buffer)
					{
						// Stop if we have sucessfully opened a file
						return buffer;
					}
				}
				catch (const FileSystemException&)
				{
					// Ignore filesystem errors and continue searching
				}
			}
		}
	}

	throw FileSystemException("Failed to open file from any filesystem!");
}

EntryType MergedEntry::getType() const
{
	if (!isRoot())
	{
		return containedEntry->getType();
	}
	else
	{
		// Root directory
		return DIRECTORY;
	}
}

bool MergedEntry::deleteChild(const string_type& name)
{
	if (!(parentSystem->supportedOperations() & OP_DELETE))
	{
		throw InvalidOperationException("No filesystem supports deleting!");
	}

	if (getType() != DIRECTORY)
	{
		throw InvalidOperationException("Entry is no directory!");
	}

	string_type normalized = normalizePath(name);

	// we want to delete the entry in the directory that actually contains it to keep
	// recaching overhead as small as possible
	size_t slash = normalized.find(DirectorySeparatorStr);
	if (slash != string_type::npos)
	{
		// remove everything after the slash
		normalized.resize(slash);

		FileEntryPointer entry = getEntryInternal(normalized);

		if (entry)
		{
			return entry->deleteChild(name.substr(slash + 1, name.size() - 1));
		}
		else
		{
			return false;
		}
	}

	bool success = false;
	BOOST_FOREACH(shared_ptr<IFileSystem>& system, parentSystem->fileSystems)
	{
		if (system->supportedOperations() & OP_DELETE)
		{
			FileEntryPointer entry = system->getRootEntry()->getChild(path);

			if (entry && entry->getType() == DIRECTORY)
			{
				try
				{
					success = entry->deleteChild(name) || success;
				}
				catch (const FileSystemException&)
				{
					// Ignore filesystem errors and continue searching
				}
			}
		}
	}

	return success;
}

FileEntryPointer MergedEntry::createEntry(EntryType type, const string_type& name)
{
	if (!(parentSystem->supportedOperations() & OP_CREATE))
	{
		throw InvalidOperationException("No filesystem supports deleting!");
	}

	if (getType() != DIRECTORY)
	{
		throw InvalidOperationException("Entry is no directory!");
	}

	BOOST_FOREACH(shared_ptr<IFileSystem>& system, parentSystem->fileSystems)
	{
		if (system->supportedOperations() & OP_CREATE)
		{
			FileEntryPointer entry = system->getRootEntry()->getChild(path);

			if (entry && entry->getType() == DIRECTORY)
			{
				try
				{
					FileEntryPointer newEntry = entry->createEntry(type, name);

					if (newEntry)
					{
						// Stop if we have sucessfully created an entry
						return shared_ptr<MergedEntry>(new MergedEntry(parentSystem, newEntry));
					}
				}
				catch (const FileSystemException&)
				{
					// Ignore filesystem errors and continue searching
				}
			}
		}
	}

	return FileEntryPointer();
}

void MergedEntry::rename(const string_type& newPath)
{
	if (isRoot())
	{
		throw FileSystemException("Cannot rename root!");
	}

	containedEntry->rename(newPath);

	shared_ptr<MergedEntry> parent = getParent(this);

	if (parent)
	{
		parent->dirty = true;
	}
	else
	{
		parentSystem->getRootEntry()->dirty = true;
	}
}

time_t MergedEntry::lastWriteTime()
{
	return containedEntry->lastWriteTime();
}
<|endoftext|>


<commit_before><commit_msg>GSvar: improved post-production replication (report config and variant comments).<commit_after><|endoftext|>


<commit_before>/* The MIT License:

Copyright (c) 2010-2012 Ivan Gagis

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. */

// Home page: http://morda.googlecode.com

/**
 * @author Ivan Gagis <igagis@gmail.com>
 */

#pragma once

#include <map>
#include <sstream>
#include <stdexcept>

#include "Vector2.hpp"
#include "Rectangle2.hpp"

#include <ting/types.hpp>
#include <ting/Exc.hpp>
#include <ting/fs/File.hpp>

#include "../config.hpp"

#ifdef M_MORDA_OGLES2
#	include <GLES2/gl2.h>
#else
#	include <GL/glew.h>
#endif

#include "GLTexture.hpp"
#include "../shaders/TexturingShader.hpp"

#ifdef __ANDROID__
namespace std {
	typedef basic_string<wchar_t> wstring;
}//~namespace
#endif

namespace morda{

class TexFont{
	struct Glyph{
		ting::StaticBuffer<morda::Vec2f, 4> verts;
		ting::StaticBuffer<morda::Vec2f, 4> texCoords;

		float advance;
	};

	GLTexture tex;

	typedef std::map<wchar_t, Glyph> T_GlyphsMap;
	typedef T_GlyphsMap::iterator T_GlyphsIter;
	T_GlyphsMap glyphs;

	float fontSize;

public:

private:
	//Bounding box holds the dimensions of the largest loaded glyph.
	morda::Rect2f boundingBox;

public:
	TexFont(){}

	TexFont(ting::fs::File& fi, const wchar_t* chars, unsigned size, unsigned outline = 0){
		this->Load(fi, chars, size, outline);
	}

	void Load(ting::fs::File& fi, const wchar_t* chars, unsigned size, unsigned outline = 0);

	inline float FontSize()const{
		return this->fontSize;
	}

	//renders the string, returns resulting string advance
	inline float RenderString(TexturingShader& shader, const morda::Matr4f& matrix, const wchar_t* s)const{
		return this->RenderStringInternal(shader, matrix, s);
	}

	inline float RenderString(TexturingShader& shader, const morda::Matr4f& matrix, const std::wstring& s)const{
		return this->RenderStringInternal(shader, matrix, s.c_str());
	}

	inline float RenderString(TexturingShader& shader, const morda::Matr4f& matrix, const char* s)const{
		return this->RenderStringInternal(shader, matrix, s);
	}

	inline float RenderString(TexturingShader& shader, const morda::Matr4f& matrix, const std::string& s)const{
		return this->RenderStringInternal(shader, matrix, s.c_str());
	}

	inline const morda::Rect2f& FontBoundingBox()const{
		return this->boundingBox;
	}

	inline float StringAdvance(const wchar_t* s)const{
		return this->StringAdvanceInternal(s);
	}

	inline float StringAdvance(const std::wstring& s)const{
		return this->StringAdvanceInternal(s.c_str());
	}

	inline float StringAdvance(const char* s)const{
		return this->StringAdvanceInternal(s);
	}

	inline float StringAdvance(const std::string& s)const{
		return this->StringAdvanceInternal(s.c_str());
	}

	inline morda::Rect2f StringBoundingBox(const wchar_t* s)const{
		return this->StringBoundingBoxInternal(s);
	}

	inline morda::Rect2f StringBoundingBox(const std::wstring& s)const{
		return this->StringBoundingBoxInternal(s.c_str());
	}

	inline morda::Rect2f StringBoundingBox(const char* s)const{
		return this->StringBoundingBoxInternal(s);
	}

	inline morda::Rect2f StringBoundingBox(const std::string& s)const{
		return this->StringBoundingBoxInternal(s.c_str());
	}

	DEBUG_CODE( void RenderTex(TexturingShader& shader, const morda::Matr4f& matrix)const; )

private:

	float StringAdvanceInternal(const char* s)const;

	float StringAdvanceInternal(const wchar_t* s)const;

	morda::Rect2f StringBoundingBoxInternal(const char* s)const;

	morda::Rect2f StringBoundingBoxInternal(const wchar_t* s)const;

	float RenderStringInternal(TexturingShader& shader, const morda::Matr4f& matrix, const char* s)const;

	float RenderStringInternal(TexturingShader& shader, const morda::Matr4f& matrix, const wchar_t* s)const;

	float RenderGlyphInternal(TexturingShader& shader, const morda::Matr4f& matrix, wchar_t ch)const;

};//~class TexFont

}//~namespace
<commit_msg>TODO added<commit_after>/* The MIT License:

Copyright (c) 2010-2014 Ivan Gagis

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. */

// Home page: http://morda.googlecode.com

/**
 * @author Ivan Gagis <igagis@gmail.com>
 */

#pragma once

#include <map>
#include <sstream>
#include <stdexcept>

#include "Vector2.hpp"
#include "Rectangle2.hpp"

#include <ting/types.hpp>
#include <ting/Exc.hpp>
#include <ting/fs/File.hpp>

#include "../config.hpp"

#ifdef M_MORDA_OGLES2
#	include <GLES2/gl2.h>
#else
#	include <GL/glew.h>
#endif

#include "GLTexture.hpp"
#include "../shaders/TexturingShader.hpp"

#ifdef __ANDROID__
namespace std {
	typedef basic_string<wchar_t> wstring;
}//~namespace
#endif

namespace morda{

//TODO: make Font interface
class TexFont{
	struct Glyph{
		ting::StaticBuffer<morda::Vec2f, 4> verts;
		ting::StaticBuffer<morda::Vec2f, 4> texCoords;

		float advance;
	};

	GLTexture tex;

	typedef std::map<wchar_t, Glyph> T_GlyphsMap;
	typedef T_GlyphsMap::iterator T_GlyphsIter;
	T_GlyphsMap glyphs;

	float fontSize;

public:

private:
	//Bounding box holds the dimensions of the largest loaded glyph.
	morda::Rect2f boundingBox;

public:
	TexFont(){}

	TexFont(ting::fs::File& fi, const wchar_t* chars, unsigned size, unsigned outline = 0){
		this->Load(fi, chars, size, outline);
	}

	void Load(ting::fs::File& fi, const wchar_t* chars, unsigned size, unsigned outline = 0);

	float FontSize()const{
		return this->fontSize;
	}

	//renders the string, returns resulting string advance
	float RenderString(TexturingShader& shader, const morda::Matr4f& matrix, const wchar_t* s)const{
		return this->RenderStringInternal(shader, matrix, s);
	}

	float RenderString(TexturingShader& shader, const morda::Matr4f& matrix, const std::wstring& s)const{
		return this->RenderStringInternal(shader, matrix, s.c_str());
	}

	float RenderString(TexturingShader& shader, const morda::Matr4f& matrix, const char* s)const{
		return this->RenderStringInternal(shader, matrix, s);
	}

	float RenderString(TexturingShader& shader, const morda::Matr4f& matrix, const std::string& s)const{
		return this->RenderStringInternal(shader, matrix, s.c_str());
	}

	const morda::Rect2f& FontBoundingBox()const{
		return this->boundingBox;
	}

	float StringAdvance(const wchar_t* s)const{
		return this->StringAdvanceInternal(s);
	}

	float StringAdvance(const std::wstring& s)const{
		return this->StringAdvanceInternal(s.c_str());
	}

	float StringAdvance(const char* s)const{
		return this->StringAdvanceInternal(s);
	}

	float StringAdvance(const std::string& s)const{
		return this->StringAdvanceInternal(s.c_str());
	}

	morda::Rect2f StringBoundingBox(const wchar_t* s)const{
		return this->StringBoundingBoxInternal(s);
	}

	morda::Rect2f StringBoundingBox(const std::wstring& s)const{
		return this->StringBoundingBoxInternal(s.c_str());
	}

	morda::Rect2f StringBoundingBox(const char* s)const{
		return this->StringBoundingBoxInternal(s);
	}

	morda::Rect2f StringBoundingBox(const std::string& s)const{
		return this->StringBoundingBoxInternal(s.c_str());
	}

	DEBUG_CODE( void RenderTex(TexturingShader& shader, const morda::Matr4f& matrix)const; )

private:

	float StringAdvanceInternal(const char* s)const;

	float StringAdvanceInternal(const wchar_t* s)const;

	morda::Rect2f StringBoundingBoxInternal(const char* s)const;

	morda::Rect2f StringBoundingBoxInternal(const wchar_t* s)const;

	float RenderStringInternal(TexturingShader& shader, const morda::Matr4f& matrix, const char* s)const;

	float RenderStringInternal(TexturingShader& shader, const morda::Matr4f& matrix, const wchar_t* s)const;

	float RenderGlyphInternal(TexturingShader& shader, const morda::Matr4f& matrix, wchar_t ch)const;

};//~class TexFont

}//~namespace
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <boost/graph/dominator_tree.hpp>

#include "mtac/LoopAnalysis.hpp"
#include "mtac/GlobalOptimizations.hpp"
#include "mtac/ControlFlowGraph.hpp"

using namespace eddic;

typedef mtac::ControlFlowGraph::InternalControlFlowGraph G;
typedef mtac::ControlFlowGraph::BasicBlockInfo Vertex;
typedef boost::property_map<mtac::ControlFlowGraph::InternalControlFlowGraph, boost::vertex_index_t>::type IndexMap;
typedef boost::iterator_property_map<std::vector<Vertex>::iterator, IndexMap> PredMap;

struct dfs_visitor : public boost::default_dfs_visitor {
    G& graph;

    dfs_visitor(G& graph) : graph(graph) {}

    template<typename U>
    void discover_vertex(U u, const G& g){
        auto new_vertex = add_vertex(graph);
        graph[new_vertex].block = g[u].block;
    }

    template<typename E>
    void tree_edge(E e, const G& g){
        add_edge(boost::source(e, g), boost::target(e, g), graph);
    }
};

void mtac::loop_analysis(std::shared_ptr<mtac::Program> program){
    for(auto& function : program->functions){
        auto graph = mtac::build_control_flow_graph(function);
        auto g = graph->get_graph();

        std::vector<Vertex> domTreePredVector = std::vector<Vertex>(boost::num_vertices(g), boost::graph_traits<G>::null_vertex());
        PredMap domTreePredMap = boost::make_iterator_property_map(domTreePredVector.begin(), boost::get(boost::vertex_index, g));

        boost::lengauer_tarjan_dominator_tree(g, boost::vertex(0, g), domTreePredMap);

        ControlFlowGraph::EdgeIterator it, end;
        for(boost::tie(it,end) = boost::edges(g); it != end; ++it){
            auto source = boost::source(*it, g);
            auto target = boost::target(*it, g);

            //A node dominates itself
            if(source == target){
                std::cout << "Found back edge" << std::endl;
            } else {
                if(boost::get(domTreePredMap, source) != boost::graph_traits<G>::null_vertex()){
                    auto dominator = boost::get(domTreePredMap,source);

                    if(dominator == target){
                        std::cout << "Found back edge" << std::endl;
                    }
                }
            }
        }

        /*G depth_first_tree;
        dfs_visitor visitor(depth_first_tree);

        boost::depth_first_search(g, boost::visitor(visitor));

        std::cout << "Dominators found" << std::endl;*/
    }
}
<commit_msg>Go a bit further to loop analysis<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <boost/graph/dominator_tree.hpp>

#include "mtac/LoopAnalysis.hpp"
#include "mtac/GlobalOptimizations.hpp"
#include "mtac/ControlFlowGraph.hpp"

using namespace eddic;

typedef mtac::ControlFlowGraph::InternalControlFlowGraph G;
typedef mtac::ControlFlowGraph::EdgeInfo Edge;
typedef mtac::ControlFlowGraph::BasicBlockInfo Vertex;
typedef boost::property_map<mtac::ControlFlowGraph::InternalControlFlowGraph, boost::vertex_index_t>::type IndexMap;
typedef boost::iterator_property_map<std::vector<Vertex>::iterator, IndexMap> PredMap;

void mtac::loop_analysis(std::shared_ptr<mtac::Program> program){
    for(auto& function : program->functions){
        auto graph = mtac::build_control_flow_graph(function);
        auto g = graph->get_graph();

        std::vector<Vertex> domTreePredVector = std::vector<Vertex>(boost::num_vertices(g), boost::graph_traits<G>::null_vertex());
        PredMap domTreePredMap = boost::make_iterator_property_map(domTreePredVector.begin(), boost::get(boost::vertex_index, g));

        boost::lengauer_tarjan_dominator_tree(g, boost::vertex(0, g), domTreePredMap);

        std::vector<Edge> back_edges;

        ControlFlowGraph::EdgeIterator it, end;
        for(boost::tie(it,end) = boost::edges(g); it != end; ++it){
            auto source = boost::source(*it, g);
            auto target = boost::target(*it, g);

            //A node dominates itself
            if(source == target){
                back_edges.push_back(*it);
            } else {
                if(boost::get(domTreePredMap, source) != boost::graph_traits<G>::null_vertex()){
                    auto dominator = boost::get(domTreePredMap,source);

                    if(dominator == target){
                        back_edges.push_back(*it);
                    }
                }
            }
        }

        std::vector<std::set<Vertex>> natural_loops;

        //Get all edges n -> d
        for(auto& back_edge : back_edges){
            std::set<Vertex> natural_loop;
            natural_loop.insert(boost::target(back_edge, g));

            //Add all predecessors of d in the set
            //

            natural_loops.push_back(natural_loop);
        }

        std::cout << "Found " << natural_loops.size() << " natural loops" << std::endl;
    }
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2015-2016 CNRS
//
// This file is part of Pinocchio
// Pinocchio is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// Pinocchio is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Lesser Public License for more details. You should have
// received a copy of the GNU Lesser General Public License along with
// Pinocchio If not, see
// <http://www.gnu.org/licenses/>.

#ifndef __se3_geometry_hxx__
#define __se3_geometry_hxx__

#include "pinocchio/spatial/fwd.hpp"
#include "pinocchio/spatial/se3.hpp"
#include "pinocchio/spatial/force.hpp"
#include "pinocchio/spatial/motion.hpp"
#include "pinocchio/spatial/inertia.hpp"
#include "pinocchio/spatial/fcl-pinocchio-conversions.hpp"
#include "pinocchio/multibody/model.hpp"
#include "pinocchio/multibody/joint/joint-variant.hpp"
#include <iostream>

#include <hpp/fcl/collision_object.h>
#include <hpp/fcl/collision.h>
#include <hpp/fcl/distance.h>
#include <map>
#include <list>
#include <utility>

// Read XML file with boost
#include <boost/property_tree/xml_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <fstream>
#include <boost/foreach.hpp>

/// @cond DEV

namespace se3
{

  inline GeometryModel::GeomIndex GeometryModel::addGeomObject(const JointIndex parent,
                                                               const fcl::CollisionObject & co,
                                                               const SE3 & placement,
                                                               const std::string & geoName)
  {

    Index idx = (Index) (ngeom ++);

    collision_objects    .push_back(co);
    geom_parents         .push_back(parent);
    geometryPlacement    .push_back(placement);
    geom_names           .push_back( (geoName!="")?geoName:random(8));

    addInnerObject(parent, idx);

    return idx;
  }

  inline GeometryModel::GeomIndex GeometryModel::getGeomId (const std::string & name) const
  {
    std::vector<std::string>::iterator::difference_type
      res = std::find(geom_names.begin(),geom_names.end(),name) - geom_names.begin();
    assert( (res<INT_MAX) && "Id superior to int range. Should never happen.");
    assert( (res>=0)&&(res<(long)collision_objects.size())&&"The joint name you asked does not exist" );
    return GeomIndex(res);
  }

  inline bool GeometryModel::existGeomName (const std::string & name) const
  {
    return (geom_names.end() != std::find(geom_names.begin(),geom_names.end(),name));
  }

  inline const std::string& GeometryModel::getGeomName (const GeomIndex index) const
  {
    assert( index < (GeomIndex)collision_objects.size() );
    return geom_names[index];
  }

  inline void GeometryModel::addInnerObject (const JointIndex joint_id, const GeomIndex inner_object)
  {
    if (std::find(innerObjects[joint_id].begin(), innerObjects[joint_id].end(),inner_object)==innerObjects[joint_id].end())
      innerObjects[joint_id].push_back(inner_object);
    else
      std::cout << "inner object already added" << std::endl;
  }

  inline void GeometryModel::addOutterObject (const JointIndex joint, const GeomIndex outer_object)
  {
    if (std::find(outerObjects[joint].begin(), outerObjects[joint].end(),outer_object)==outerObjects[joint].end())
      outerObjects[joint].push_back(outer_object);
    else
      std::cout << "outer object already added" << std::endl;
  }

  inline std::ostream & operator<< (std::ostream & os, const GeometryModel & model_geom)
  {
    os << "Nb collision objects = " << model_geom.ngeom << std::endl;

    for(GeometryModel::Index i=0;i<(GeometryModel::Index)(model_geom.ngeom);++i)
    {
      os  << "Collision object " << i << " : " << model_geom.geom_names[i] << ": attached to joint = " << model_geom.geom_parents[i]
          << "\nwith offset \n" << model_geom.geometryPlacement[i] <<std::endl;
    }

    return os;
  }

  inline std::ostream & operator<< (std::ostream & os, const GeometryData & data_geom)
  {

    for(GeometryData::Index i=0;i<(GeometryData::Index)(data_geom.model_geom.ngeom);++i)
    {
      os << "collision object in position " << data_geom.oMg[i] << std::endl;
    }

    return os;
  }

  inline void GeometryData::addCollisionPair (const GeomIndex co1, const GeomIndex co2)
  {
    assert ( co1 != co2);
    assert ( co2 < model_geom.ngeom);
    CollisionPair_t pair(co1, co2);

    addCollisionPair(pair);
  }

  inline void GeometryData::addCollisionPair (const CollisionPair_t & pair)
  {
    assert(pair.second < model_geom.ngeom);

    if (!existCollisionPair(pair))
    {
      collision_pairs.push_back(pair);
      nCollisionPairs++;
    }
  }

  inline void GeometryData::addAllCollisionPairs()
  {
    removeAllCollisionPairs();
    collision_pairs.reserve((model_geom.ngeom * (model_geom.ngeom-1))/2);
    for (Index i = 0; i < model_geom.ngeom; ++i)
      for (Index j = i+1; j < model_geom.ngeom; ++j)
        addCollisionPair(i,j);
  }

  inline void GeometryData::removeCollisionPair (const GeomIndex co1, const GeomIndex co2)
  {
    assert(co1 < co2);
    assert(co2 < model_geom.ngeom);
    assert(existCollisionPair(co1,co2));

    removeCollisionPair (CollisionPair_t(co1,co2));
  }

  inline void GeometryData::removeCollisionPair (const CollisionPair_t & pair)
  {
    assert(pair.second < model_geom.ngeom);

    CollisionPairsVector_t::iterator it = std::find(collision_pairs.begin(), collision_pairs.end(), pair);
    if (it != collision_pairs.end())
    {
      collision_pairs.erase(it);
      nCollisionPairs--;
    }
  }

  inline void GeometryData::removeAllCollisionPairs ()
  {
    collision_pairs.clear();
    nCollisionPairs = 0;
  }

  inline bool GeometryData::existCollisionPair (const GeomIndex co1, const GeomIndex co2) const
  {
    return existCollisionPair(CollisionPair_t(co1,co2));
  }

  inline bool GeometryData::existCollisionPair (const CollisionPair_t & pair) const
  {
    return (std::find(collision_pairs.begin(), collision_pairs.end(), pair)
            != collision_pairs.end());
  }

  inline GeometryData::Index GeometryData::findCollisionPair (const GeomIndex co1, const GeomIndex co2) const
  {
    return findCollisionPair(CollisionPair_t(co1,co2));
  }

  inline GeometryData::Index GeometryData::findCollisionPair (const CollisionPair_t & pair) const
  {
    CollisionPairsVector_t::const_iterator it = std::find(collision_pairs.begin(), collision_pairs.end(), pair);

    return (Index) distance(collision_pairs.begin(), it);
  }

//  std::vector<Index> GeometryData::findCollisionPairsSupportedBy(const JointIndex joint_id) const
//  {
////    std::vector<Index> collision_pairs;
////    for(CollisionPairsVector_t::const_iterator it = collision_pairs.begin();
////        it != collision_pairs.end(); ++it)
////    {
////      if (geom_model.it->first )
////    }
//  }

  // TODO :  give a srdf file as argument, read it, and remove corresponding
  // pairs from list collision_pairs
  inline void GeometryData::desactivateCollisionPairs()
  {

  }

  inline void GeometryData::initializeListOfCollisionPairs()
  {
    addAllCollisionPairs();
    desactivateCollisionPairs();
    assert(nCollisionPairs == collision_pairs.size());
  }

  inline CollisionResult GeometryData::computeCollision(const GeomIndex co1, const GeomIndex co2) const
  {
    return computeCollision(CollisionPair_t(co1,co2));
  }

  inline CollisionResult GeometryData::computeCollision(const CollisionPair_t & pair) const
  {
    const Index & co1 = pair.first;
    const Index & co2 = pair.second;

    fcl::CollisionRequest collisionRequest (1, false, false, 1, false, true, fcl::GST_INDEP);
    fcl::CollisionResult collisionResult;

    fcl::collide (model_geom.collision_objects[co1].collisionGeometry().get(), oMg_fcl[co1],
                  model_geom.collision_objects[co2].collisionGeometry().get(), oMg_fcl[co2],
                  collisionRequest, collisionResult);

    return CollisionResult (collisionResult, co1, co2);
  }

  inline void GeometryData::computeAllCollisions()
  {
    for(size_t i = 0; i<nCollisionPairs; ++i)
    {
      const CollisionPair_t & pair = collision_pairs[i];
      collision_results[i] = computeCollision(pair.first, pair.second);
    }
  }

  inline bool GeometryData::isColliding() const
  {
    for(CollisionPairsVector_t::const_iterator it = collision_pairs.begin(); it != collision_pairs.end(); ++it)
    {
      if (computeCollision(it->first, it->second).fcl_collision_result.isCollision())
        return true;
    }
    return false;
  }

  inline DistanceResult GeometryData::computeDistance(const GeomIndex co1, const GeomIndex co2) const
  {
    return computeDistance(CollisionPair_t(co1,co2));
  }

  inline DistanceResult GeometryData::computeDistance(const CollisionPair_t & pair) const
  {
    const Index & co1 = pair.first;
    const Index & co2 = pair.second;

    fcl::DistanceRequest distanceRequest (true, 0, 0, fcl::GST_INDEP);
    fcl::DistanceResult result;
    fcl::distance ( model_geom.collision_objects[co1].collisionGeometry().get(), oMg_fcl[co1],
                    model_geom.collision_objects[co2].collisionGeometry().get(), oMg_fcl[co2],
                    distanceRequest, result);

    return DistanceResult (result, co1, co2);
  }

  inline void GeometryData::computeAllDistances ()
  {
    for(size_t i = 0; i<nCollisionPairs; ++i)
    {
      const CollisionPair_t & pair = collision_pairs[i];
      distance_results[i] = computeDistance(pair.first, pair.second);
    }
  }

  inline void GeometryData::resetDistances()
  {
    std::fill(distance_results.begin(), distance_results.end(), DistanceResult( fcl::DistanceResult(), 0, 0) );
  }

  void GeometryData::addCollisionPairsFromSrdf(const std::string & filename,
                                               const bool verbose) throw (std::invalid_argument)
  {
    std::ifstream srdf_stream(filename);
    if (! srdf_stream.is_open())
    {
      const std::string exception_message (filename + " seems not to be a valid file.");
      throw std::invalid_argument(exception_message);
    }

    // Add all collision pairs
    addAllCollisionPairs();
    std::cout << "Num collision pairs " << nCollisionPairs << std::endl;

    // Read xml stream
    using boost::property_tree::ptree;
    ptree pt;
    read_xml(srdf_stream, pt);

    // Iterate over collision pairs
    const se3::Model & model = data_ref.model;
    BOOST_FOREACH(const ptree::value_type & v, pt.get_child("robot"))
    {
      if (v.first == "disable_collisions")
      {
        const std::string link1 = v.second.get<std::string>("<xmlattr>.link1");
        const std::string link2 = v.second.get<std::string>("<xmlattr>.link2");

        // Check first if the two bodies exist in model
        if (!model.existBodyName(link1) || !model.existBodyName(link2))
        {
          if (verbose)
            std::cout << "It seems that " << link1 << " or " << link2 << " do not exist in model. Skip." << std::endl;
          continue;
        }

        const Model::JointIndex id1 = model.getBodyId(link1);
        const Model::JointIndex id2 = model.getBodyId(link2);

        typedef GeometryModel::GeomIndexList GeomIndexList;
        const GeomIndexList & innerObject1 = model_geom.innerObjects.at(id1);
        const GeomIndexList & innerObject2 = model_geom.innerObjects.at(id2);

        for(GeomIndexList::const_iterator it1 = innerObject1.begin();
            it1 != innerObject1.end();
            ++it1)
        {
          for(GeomIndexList::const_iterator it2 = innerObject2.begin();
              it2 != innerObject2.end();
              ++it2)
          {
            removeCollisionPair(CollisionPair(*it1, *it2));
          }
        }

      } // BOOST_FOREACH
    }

    std::cout << "Num collision pairs " << nCollisionPairs << std::endl;
  }

} // namespace se3

/// @endcond

#endif // ifndef __se3_geometry_hxx__
<commit_msg>[C++] Clean the code + add checking of file extension<commit_after>//
// Copyright (c) 2015-2016 CNRS
//
// This file is part of Pinocchio
// Pinocchio is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// Pinocchio is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Lesser Public License for more details. You should have
// received a copy of the GNU Lesser General Public License along with
// Pinocchio If not, see
// <http://www.gnu.org/licenses/>.

#ifndef __se3_geometry_hxx__
#define __se3_geometry_hxx__

#include "pinocchio/spatial/fwd.hpp"
#include "pinocchio/spatial/se3.hpp"
#include "pinocchio/spatial/force.hpp"
#include "pinocchio/spatial/motion.hpp"
#include "pinocchio/spatial/inertia.hpp"
#include "pinocchio/spatial/fcl-pinocchio-conversions.hpp"
#include "pinocchio/multibody/model.hpp"
#include "pinocchio/multibody/joint/joint-variant.hpp"
#include <iostream>

#include <hpp/fcl/collision_object.h>
#include <hpp/fcl/collision.h>
#include <hpp/fcl/distance.h>
#include <map>
#include <list>
#include <utility>

// Read XML file with boost
#include <boost/property_tree/xml_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <fstream>
#include <boost/foreach.hpp>

/// @cond DEV

namespace se3
{

  inline GeometryModel::GeomIndex GeometryModel::addGeomObject(const JointIndex parent,
                                                               const fcl::CollisionObject & co,
                                                               const SE3 & placement,
                                                               const std::string & geoName)
  {

    Index idx = (Index) (ngeom ++);

    collision_objects    .push_back(co);
    geom_parents         .push_back(parent);
    geometryPlacement    .push_back(placement);
    geom_names           .push_back( (geoName!="")?geoName:random(8));

    addInnerObject(parent, idx);

    return idx;
  }

  inline GeometryModel::GeomIndex GeometryModel::getGeomId (const std::string & name) const
  {
    std::vector<std::string>::iterator::difference_type
      res = std::find(geom_names.begin(),geom_names.end(),name) - geom_names.begin();
    assert( (res<INT_MAX) && "Id superior to int range. Should never happen.");
    assert( (res>=0)&&(res<(long)collision_objects.size())&&"The joint name you asked does not exist" );
    return GeomIndex(res);
  }

  inline bool GeometryModel::existGeomName (const std::string & name) const
  {
    return (geom_names.end() != std::find(geom_names.begin(),geom_names.end(),name));
  }

  inline const std::string& GeometryModel::getGeomName (const GeomIndex index) const
  {
    assert( index < (GeomIndex)collision_objects.size() );
    return geom_names[index];
  }

  inline void GeometryModel::addInnerObject (const JointIndex joint_id, const GeomIndex inner_object)
  {
    if (std::find(innerObjects[joint_id].begin(), innerObjects[joint_id].end(),inner_object)==innerObjects[joint_id].end())
      innerObjects[joint_id].push_back(inner_object);
    else
      std::cout << "inner object already added" << std::endl;
  }

  inline void GeometryModel::addOutterObject (const JointIndex joint, const GeomIndex outer_object)
  {
    if (std::find(outerObjects[joint].begin(), outerObjects[joint].end(),outer_object)==outerObjects[joint].end())
      outerObjects[joint].push_back(outer_object);
    else
      std::cout << "outer object already added" << std::endl;
  }

  inline std::ostream & operator<< (std::ostream & os, const GeometryModel & model_geom)
  {
    os << "Nb collision objects = " << model_geom.ngeom << std::endl;

    for(GeometryModel::Index i=0;i<(GeometryModel::Index)(model_geom.ngeom);++i)
    {
      os  << "Collision object " << i << " : " << model_geom.geom_names[i] << ": attached to joint = " << model_geom.geom_parents[i]
          << "\nwith offset \n" << model_geom.geometryPlacement[i] <<std::endl;
    }

    return os;
  }

  inline std::ostream & operator<< (std::ostream & os, const GeometryData & data_geom)
  {

    for(GeometryData::Index i=0;i<(GeometryData::Index)(data_geom.model_geom.ngeom);++i)
    {
      os << "collision object in position " << data_geom.oMg[i] << std::endl;
    }

    return os;
  }

  inline void GeometryData::addCollisionPair (const GeomIndex co1, const GeomIndex co2)
  {
    assert ( co1 != co2);
    assert ( co2 < model_geom.ngeom);
    CollisionPair_t pair(co1, co2);

    addCollisionPair(pair);
  }

  inline void GeometryData::addCollisionPair (const CollisionPair_t & pair)
  {
    assert(pair.second < model_geom.ngeom);

    if (!existCollisionPair(pair))
    {
      collision_pairs.push_back(pair);
      nCollisionPairs++;
    }
  }

  inline void GeometryData::addAllCollisionPairs()
  {
    removeAllCollisionPairs();
    collision_pairs.reserve((model_geom.ngeom * (model_geom.ngeom-1))/2);
    for (Index i = 0; i < model_geom.ngeom; ++i)
      for (Index j = i+1; j < model_geom.ngeom; ++j)
        addCollisionPair(i,j);
  }

  inline void GeometryData::removeCollisionPair (const GeomIndex co1, const GeomIndex co2)
  {
    assert(co1 < co2);
    assert(co2 < model_geom.ngeom);
    assert(existCollisionPair(co1,co2));

    removeCollisionPair (CollisionPair_t(co1,co2));
  }

  inline void GeometryData::removeCollisionPair (const CollisionPair_t & pair)
  {
    assert(pair.second < model_geom.ngeom);

    CollisionPairsVector_t::iterator it = std::find(collision_pairs.begin(), collision_pairs.end(), pair);
    if (it != collision_pairs.end())
    {
      collision_pairs.erase(it);
      nCollisionPairs--;
    }
  }

  inline void GeometryData::removeAllCollisionPairs ()
  {
    collision_pairs.clear();
    nCollisionPairs = 0;
  }

  inline bool GeometryData::existCollisionPair (const GeomIndex co1, const GeomIndex co2) const
  {
    return existCollisionPair(CollisionPair_t(co1,co2));
  }

  inline bool GeometryData::existCollisionPair (const CollisionPair_t & pair) const
  {
    return (std::find(collision_pairs.begin(), collision_pairs.end(), pair)
            != collision_pairs.end());
  }

  inline GeometryData::Index GeometryData::findCollisionPair (const GeomIndex co1, const GeomIndex co2) const
  {
    return findCollisionPair(CollisionPair_t(co1,co2));
  }

  inline GeometryData::Index GeometryData::findCollisionPair (const CollisionPair_t & pair) const
  {
    CollisionPairsVector_t::const_iterator it = std::find(collision_pairs.begin(), collision_pairs.end(), pair);

    return (Index) distance(collision_pairs.begin(), it);
  }

//  std::vector<Index> GeometryData::findCollisionPairsSupportedBy(const JointIndex joint_id) const
//  {
////    std::vector<Index> collision_pairs;
////    for(CollisionPairsVector_t::const_iterator it = collision_pairs.begin();
////        it != collision_pairs.end(); ++it)
////    {
////      if (geom_model.it->first )
////    }
//  }

  // TODO :  give a srdf file as argument, read it, and remove corresponding
  // pairs from list collision_pairs
  inline void GeometryData::desactivateCollisionPairs()
  {

  }

  inline void GeometryData::initializeListOfCollisionPairs()
  {
    addAllCollisionPairs();
    desactivateCollisionPairs();
    assert(nCollisionPairs == collision_pairs.size());
  }

  inline CollisionResult GeometryData::computeCollision(const GeomIndex co1, const GeomIndex co2) const
  {
    return computeCollision(CollisionPair_t(co1,co2));
  }

  inline CollisionResult GeometryData::computeCollision(const CollisionPair_t & pair) const
  {
    const Index & co1 = pair.first;
    const Index & co2 = pair.second;

    fcl::CollisionRequest collisionRequest (1, false, false, 1, false, true, fcl::GST_INDEP);
    fcl::CollisionResult collisionResult;

    fcl::collide (model_geom.collision_objects[co1].collisionGeometry().get(), oMg_fcl[co1],
                  model_geom.collision_objects[co2].collisionGeometry().get(), oMg_fcl[co2],
                  collisionRequest, collisionResult);

    return CollisionResult (collisionResult, co1, co2);
  }

  inline void GeometryData::computeAllCollisions()
  {
    for(size_t i = 0; i<nCollisionPairs; ++i)
    {
      const CollisionPair_t & pair = collision_pairs[i];
      collision_results[i] = computeCollision(pair.first, pair.second);
    }
  }

  inline bool GeometryData::isColliding() const
  {
    for(CollisionPairsVector_t::const_iterator it = collision_pairs.begin(); it != collision_pairs.end(); ++it)
    {
      if (computeCollision(it->first, it->second).fcl_collision_result.isCollision())
        return true;
    }
    return false;
  }

  inline DistanceResult GeometryData::computeDistance(const GeomIndex co1, const GeomIndex co2) const
  {
    return computeDistance(CollisionPair_t(co1,co2));
  }

  inline DistanceResult GeometryData::computeDistance(const CollisionPair_t & pair) const
  {
    const Index & co1 = pair.first;
    const Index & co2 = pair.second;

    fcl::DistanceRequest distanceRequest (true, 0, 0, fcl::GST_INDEP);
    fcl::DistanceResult result;
    fcl::distance ( model_geom.collision_objects[co1].collisionGeometry().get(), oMg_fcl[co1],
                    model_geom.collision_objects[co2].collisionGeometry().get(), oMg_fcl[co2],
                    distanceRequest, result);

    return DistanceResult (result, co1, co2);
  }

  inline void GeometryData::computeAllDistances ()
  {
    for(size_t i = 0; i<nCollisionPairs; ++i)
    {
      const CollisionPair_t & pair = collision_pairs[i];
      distance_results[i] = computeDistance(pair.first, pair.second);
    }
  }

  inline void GeometryData::resetDistances()
  {
    std::fill(distance_results.begin(), distance_results.end(), DistanceResult( fcl::DistanceResult(), 0, 0) );
  }

  void GeometryData::addCollisionPairsFromSrdf(const std::string & filename,
                                               const bool verbose) throw (std::invalid_argument)
  {
    // Check extension
    const std::string extension = filename.substr(filename.find_last_of('.')+1);
    if (extension != "srdf")
    {
      const std::string exception_message (filename + " does not have the right extension.");
      throw std::invalid_argument(exception_message);
    }

    // Open file
    std::ifstream srdf_stream(filename);
    if (! srdf_stream.is_open())
    {
      const std::string exception_message (filename + " does not seem to be a valid file.");
      throw std::invalid_argument(exception_message);
    }

    // Add all collision pairs
    addAllCollisionPairs();

    // Read xml stream
    using boost::property_tree::ptree;
    ptree pt;
    read_xml(srdf_stream, pt);

    // Iterate over collision pairs
    const se3::Model & model = data_ref.model;
    BOOST_FOREACH(const ptree::value_type & v, pt.get_child("robot"))
    {
      if (v.first == "disable_collisions")
      {
        const std::string link1 = v.second.get<std::string>("<xmlattr>.link1");
        const std::string link2 = v.second.get<std::string>("<xmlattr>.link2");

        // Check first if the two bodies exist in model
        if (!model.existBodyName(link1) || !model.existBodyName(link2))
        {
          if (verbose)
            std::cout << "It seems that " << link1 << " or " << link2 << " do not exist in model. Skip." << std::endl;
          continue;
        }

        const Model::JointIndex id1 = model.getBodyId(link1);
        const Model::JointIndex id2 = model.getBodyId(link2);

        typedef GeometryModel::GeomIndexList GeomIndexList;
        const GeomIndexList & innerObject1 = model_geom.innerObjects.at(id1);
        const GeomIndexList & innerObject2 = model_geom.innerObjects.at(id2);

        for(GeomIndexList::const_iterator it1 = innerObject1.begin();
            it1 != innerObject1.end();
            ++it1)
        {
          for(GeomIndexList::const_iterator it2 = innerObject2.begin();
              it2 != innerObject2.end();
              ++it2)
          {
            removeCollisionPair(CollisionPair(*it1, *it2));
          }
        }

      } // BOOST_FOREACH
    }
  }

} // namespace se3

/// @endcond

#endif // ifndef __se3_geometry_hxx__
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015,2016 deipi.com LLC and contributors. All rights reserved.
 *
 * 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 "keymaker.h"

#include "../stl_serialise.h"

const dispatch_str_metric def_str_metric     = &Multi_MultiValueKeyMaker::jaro;
const dispatch_str_metric def_soundex_metric = &Multi_MultiValueKeyMaker::soundex_en;

const std::unordered_map<std::string, dispatch_str_metric> map_dispatch_soundex_metric({
	{ "english",  &Multi_MultiValueKeyMaker::soundex_en     },
	{ "en",       &Multi_MultiValueKeyMaker::soundex_en     },
	{ "french",   &Multi_MultiValueKeyMaker::soundex_fr     },
	{ "fr",       &Multi_MultiValueKeyMaker::soundex_fr     },
	{ "german",   &Multi_MultiValueKeyMaker::soundex_de     },
	{ "de",       &Multi_MultiValueKeyMaker::soundex_de     },
	{ "spanish",  &Multi_MultiValueKeyMaker::soundex_es     },
	{ "es",       &Multi_MultiValueKeyMaker::soundex_es     }
});

const std::unordered_map<std::string, dispatch_str_metric> map_dispatch_str_metric({
	{ "levenshtein",   &Multi_MultiValueKeyMaker::levenshtein     },
	{ "leven",         &Multi_MultiValueKeyMaker::levenshtein     },
	{ "jaro",          &Multi_MultiValueKeyMaker::jaro            },
	{ "jarowinkler",   &Multi_MultiValueKeyMaker::jaro_winkler    },
	{ "jarow",         &Multi_MultiValueKeyMaker::jaro_winkler    },
	{ "sorensendice",  &Multi_MultiValueKeyMaker::sorensen_dice   },
	{ "sorensen",      &Multi_MultiValueKeyMaker::sorensen_dice   },
	{ "dice",          &Multi_MultiValueKeyMaker::sorensen_dice   },
	{ "jaccard",       &Multi_MultiValueKeyMaker::jaccard         },
	{ "lcsubstr",      &Multi_MultiValueKeyMaker::lcs             },
	{ "lcs",           &Multi_MultiValueKeyMaker::lcs             },
	{ "lcsubsequence", &Multi_MultiValueKeyMaker::lcsq            },
	{ "lcsq",          &Multi_MultiValueKeyMaker::lcsq            },
	{ "soundex",       &Multi_MultiValueKeyMaker::soundex         },
	{ "sound",         &Multi_MultiValueKeyMaker::soundex         }
});

std::string
BaseKey::findSmallest(const Xapian::Document& doc) const
{
	auto multiValues = doc.get_value(_slot);
	if (multiValues.empty()) return MAX_CMPVALUE;
	StringList s;
	s.unserialise(multiValues);

	StringList::const_iterator it(s.begin());
	std::string smallest(get_cmpvalue(*it));
	const auto it_e = s.end();
	for (++it; it != it_e; ++it) {
		auto aux = get_cmpvalue(*it);
		if (smallest > aux) smallest = aux;
	}

	return smallest;
}

std::string
BaseKey::findLargest(const Xapian::Document& doc) const
{
	auto multiValues = doc.get_value(_slot);
	if (multiValues.empty()) return MAX_CMPVALUE;
	StringList s;
	s.unserialise(multiValues);

	StringList::const_iterator it(s.begin());
	std::string largest(get_cmpvalue(*it));
	const auto it_e = s.end();
	for (++it; it != it_e; ++it) {
		std::string aux(get_cmpvalue(*it));
		if (aux > largest) largest = aux;
	}

	return largest;
}

std::string
SerialiseKey::findSmallest(const Xapian::Document& doc) const
{
	auto multiValues = doc.get_value(_slot);
	if (multiValues.empty()) return STR_FOR_EMPTY;
	StringList s;
	s.unserialise(multiValues);
	return *s.cbegin();
}

std::string
SerialiseKey::findLargest(const Xapian::Document& doc) const
{
	auto multiValues = doc.get_value(_slot);
	if (multiValues.empty()) return STR_FOR_EMPTY;
	StringList s;
	s.unserialise(multiValues);
	return *s.crbegin();
}

std::string
GeoKey::get_cmpvalue(const std::string& serialise_val) const
{
	auto geo_val = Unserialise::geo(serialise_val);
	CartesianUSet centroids;
	centroids.unserialise(geo_val.second);
	double angle = M_PI;
	for (const auto& _centroid : _centroids) {
		double aux = M_PI;
		for (const auto& centroid : centroids) {
			double rad_angle = std::acos(_centroid * centroid);
			if (rad_angle < aux) aux = rad_angle;
		}
		if (aux < angle) angle = aux;
	}
	return Serialise::_float(angle);
}

void
Multi_MultiValueKeyMaker::add_value(const required_spc_t& field_spc, bool reverse, const std::string& value, const query_field_t& qf)
{
	if (value.empty()) {
		if (field_spc.get_type() != FieldType::GEO) {
			slots.push_back(std::make_unique<SerialiseKey>(field_spc.slot, reverse));
		}
	} else {
		switch (field_spc.get_type()) {
			case FieldType::FLOAT:
				slots.push_back(std::make_unique<FloatKey>(field_spc.slot, reverse, value));
				return;
			case FieldType::INTEGER:
				slots.push_back(std::make_unique<IntegerKey>(field_spc.slot, reverse, value));
				return;
			case FieldType::POSITIVE:
				slots.push_back(std::make_unique<PositiveKey>(field_spc.slot, reverse, value));
				return;
			case FieldType::DATE:
				slots.push_back(std::make_unique<DateKey>(field_spc.slot, reverse, value));
				return;
			case FieldType::BOOLEAN:
				slots.push_back(std::make_unique<BoolKey>(field_spc.slot, reverse, value));
				return;
			case FieldType::STRING:
			case FieldType::TEXT:
				try {
					auto func = map_dispatch_str_metric.at(qf.metric);
					(this->*func)(field_spc, reverse, value, qf);
				} catch (const std::out_of_range&) {
					(this->*def_str_metric)(field_spc, reverse, value, qf);
				}
				return;
			case FieldType::GEO:
				slots.push_back(std::make_unique<GeoKey>(field_spc, reverse, value));
				return;
			default:
				throw MSG_InvalidArgumentError("Type '%c' is not supported", field_spc.get_type());
		}
	}
}

std::string
Multi_MultiValueKeyMaker::operator()(const Xapian::Document& doc) const
{
	std::string result;

	// Don't crash if slots is empty.
	if (slots.empty()) {
		return result;
	}

	auto i = slots.begin();
	while (true) {
		// All values (except for the last if it's sorted forwards) need to
		// be adjusted.
		auto reverse_sort = (*i)->get_reverse();
		// Select The most representative value to create the key.
		auto v = reverse_sort ? (*i)->findLargest(doc) : (*i)->findSmallest(doc);
		// RULE: v is never empty, because if there is not value in the slot v is MAX_CMPVALUE or STR_FOR_EMPTY.

		if (++i == slots.end() && !reverse_sort) {
			// No need to adjust the last value if it's sorted forwards.
			result += v;
			break;
		}

		if (reverse_sort) {
			// For a reverse ordered value, we subtract each byte from '\xff',
			// except for '\0' which we convert to "\xff\0".  We insert
			// "\xff\xff" after the encoded value.
			for (const auto& ch_ : v) {
				unsigned char ch = static_cast<unsigned char>(ch_);
				result += char(255 - ch);
				if (ch == 0) result += '\0';
			}
			result.append("\xff\xff", 2);
			if (i == slots.end()) break;
		} else {
			// For a forward ordered value (unless it's the last value), we
			// convert any '\0' to "\0\xff".  We insert "\0\0" after the
			// encoded value.
			std::string::size_type j = 0, nul;
			while ((nul = v.find('\0', j)) != std::string::npos) {
				++nul;
				result.append(v, j, nul - j);
				result += '\xff';
				j = nul;
			}
			result.append(v, j, std::string::npos);
			result.append("\0", 2);
		}
	}

	return result;
}
<commit_msg>Add UUID type in /src/multivalue/keymaker.cc<commit_after>/*
 * Copyright (C) 2015,2016 deipi.com LLC and contributors. All rights reserved.
 *
 * 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 "keymaker.h"

#include "../stl_serialise.h"

const dispatch_str_metric def_str_metric     = &Multi_MultiValueKeyMaker::jaro;
const dispatch_str_metric def_soundex_metric = &Multi_MultiValueKeyMaker::soundex_en;

const std::unordered_map<std::string, dispatch_str_metric> map_dispatch_soundex_metric({
	{ "english",  &Multi_MultiValueKeyMaker::soundex_en     },
	{ "en",       &Multi_MultiValueKeyMaker::soundex_en     },
	{ "french",   &Multi_MultiValueKeyMaker::soundex_fr     },
	{ "fr",       &Multi_MultiValueKeyMaker::soundex_fr     },
	{ "german",   &Multi_MultiValueKeyMaker::soundex_de     },
	{ "de",       &Multi_MultiValueKeyMaker::soundex_de     },
	{ "spanish",  &Multi_MultiValueKeyMaker::soundex_es     },
	{ "es",       &Multi_MultiValueKeyMaker::soundex_es     }
});

const std::unordered_map<std::string, dispatch_str_metric> map_dispatch_str_metric({
	{ "levenshtein",   &Multi_MultiValueKeyMaker::levenshtein     },
	{ "leven",         &Multi_MultiValueKeyMaker::levenshtein     },
	{ "jaro",          &Multi_MultiValueKeyMaker::jaro            },
	{ "jarowinkler",   &Multi_MultiValueKeyMaker::jaro_winkler    },
	{ "jarow",         &Multi_MultiValueKeyMaker::jaro_winkler    },
	{ "sorensendice",  &Multi_MultiValueKeyMaker::sorensen_dice   },
	{ "sorensen",      &Multi_MultiValueKeyMaker::sorensen_dice   },
	{ "dice",          &Multi_MultiValueKeyMaker::sorensen_dice   },
	{ "jaccard",       &Multi_MultiValueKeyMaker::jaccard         },
	{ "lcsubstr",      &Multi_MultiValueKeyMaker::lcs             },
	{ "lcs",           &Multi_MultiValueKeyMaker::lcs             },
	{ "lcsubsequence", &Multi_MultiValueKeyMaker::lcsq            },
	{ "lcsq",          &Multi_MultiValueKeyMaker::lcsq            },
	{ "soundex",       &Multi_MultiValueKeyMaker::soundex         },
	{ "sound",         &Multi_MultiValueKeyMaker::soundex         }
});

std::string
BaseKey::findSmallest(const Xapian::Document& doc) const
{
	auto multiValues = doc.get_value(_slot);
	if (multiValues.empty()) return MAX_CMPVALUE;
	StringList s;
	s.unserialise(multiValues);

	StringList::const_iterator it(s.begin());
	std::string smallest(get_cmpvalue(*it));
	const auto it_e = s.end();
	for (++it; it != it_e; ++it) {
		auto aux = get_cmpvalue(*it);
		if (smallest > aux) smallest = aux;
	}

	return smallest;
}

std::string
BaseKey::findLargest(const Xapian::Document& doc) const
{
	auto multiValues = doc.get_value(_slot);
	if (multiValues.empty()) return MAX_CMPVALUE;
	StringList s;
	s.unserialise(multiValues);

	StringList::const_iterator it(s.begin());
	std::string largest(get_cmpvalue(*it));
	const auto it_e = s.end();
	for (++it; it != it_e; ++it) {
		std::string aux(get_cmpvalue(*it));
		if (aux > largest) largest = aux;
	}

	return largest;
}

std::string
SerialiseKey::findSmallest(const Xapian::Document& doc) const
{
	auto multiValues = doc.get_value(_slot);
	if (multiValues.empty()) return STR_FOR_EMPTY;
	StringList s;
	s.unserialise(multiValues);
	return *s.cbegin();
}

std::string
SerialiseKey::findLargest(const Xapian::Document& doc) const
{
	auto multiValues = doc.get_value(_slot);
	if (multiValues.empty()) return STR_FOR_EMPTY;
	StringList s;
	s.unserialise(multiValues);
	return *s.crbegin();
}

std::string
GeoKey::get_cmpvalue(const std::string& serialise_val) const
{
	auto geo_val = Unserialise::geo(serialise_val);
	CartesianUSet centroids;
	centroids.unserialise(geo_val.second);
	double angle = M_PI;
	for (const auto& _centroid : _centroids) {
		double aux = M_PI;
		for (const auto& centroid : centroids) {
			double rad_angle = std::acos(_centroid * centroid);
			if (rad_angle < aux) aux = rad_angle;
		}
		if (aux < angle) angle = aux;
	}
	return Serialise::_float(angle);
}

void
Multi_MultiValueKeyMaker::add_value(const required_spc_t& field_spc, bool reverse, const std::string& value, const query_field_t& qf)
{
	if (value.empty()) {
		if (field_spc.get_type() != FieldType::GEO) {
			slots.push_back(std::make_unique<SerialiseKey>(field_spc.slot, reverse));
		}
	} else {
		switch (field_spc.get_type()) {
			case FieldType::FLOAT:
				slots.push_back(std::make_unique<FloatKey>(field_spc.slot, reverse, value));
				return;
			case FieldType::INTEGER:
				slots.push_back(std::make_unique<IntegerKey>(field_spc.slot, reverse, value));
				return;
			case FieldType::POSITIVE:
				slots.push_back(std::make_unique<PositiveKey>(field_spc.slot, reverse, value));
				return;
			case FieldType::DATE:
				slots.push_back(std::make_unique<DateKey>(field_spc.slot, reverse, value));
				return;
			case FieldType::BOOLEAN:
				slots.push_back(std::make_unique<BoolKey>(field_spc.slot, reverse, value));
				return;
			case FieldType::UUID:
			case FieldType::STRING:
			case FieldType::TEXT:
				try {
					auto func = map_dispatch_str_metric.at(qf.metric);
					(this->*func)(field_spc, reverse, value, qf);
				} catch (const std::out_of_range&) {
					(this->*def_str_metric)(field_spc, reverse, value, qf);
				}
				return;
			case FieldType::GEO:
				slots.push_back(std::make_unique<GeoKey>(field_spc, reverse, value));
				return;
			default:
				throw MSG_InvalidArgumentError("Type '%c' is not supported", field_spc.get_type());
		}
	}
}

std::string
Multi_MultiValueKeyMaker::operator()(const Xapian::Document& doc) const
{
	std::string result;

	// Don't crash if slots is empty.
	if (slots.empty()) {
		return result;
	}

	auto i = slots.begin();
	while (true) {
		// All values (except for the last if it's sorted forwards) need to
		// be adjusted.
		auto reverse_sort = (*i)->get_reverse();
		// Select The most representative value to create the key.
		auto v = reverse_sort ? (*i)->findLargest(doc) : (*i)->findSmallest(doc);
		// RULE: v is never empty, because if there is not value in the slot v is MAX_CMPVALUE or STR_FOR_EMPTY.

		if (++i == slots.end() && !reverse_sort) {
			// No need to adjust the last value if it's sorted forwards.
			result += v;
			break;
		}

		if (reverse_sort) {
			// For a reverse ordered value, we subtract each byte from '\xff',
			// except for '\0' which we convert to "\xff\0".  We insert
			// "\xff\xff" after the encoded value.
			for (const auto& ch_ : v) {
				unsigned char ch = static_cast<unsigned char>(ch_);
				result += char(255 - ch);
				if (ch == 0) result += '\0';
			}
			result.append("\xff\xff", 2);
			if (i == slots.end()) break;
		} else {
			// For a forward ordered value (unless it's the last value), we
			// convert any '\0' to "\0\xff".  We insert "\0\0" after the
			// encoded value.
			std::string::size_type j = 0, nul;
			while ((nul = v.find('\0', j)) != std::string::npos) {
				++nul;
				result.append(v, j, nul - j);
				result += '\xff';
				j = nul;
			}
			result.append(v, j, std::string::npos);
			result.append("\0", 2);
		}
	}

	return result;
}
<|endoftext|>


<commit_before>/* ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2013, Numenta, Inc.  Unless you have an agreement
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero Public License for more details.
 *
 * You should have received a copy of the GNU Affero Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

/* @file Implementation of NuPIC init/shutdown operations */

// TODO -- thread safety
// TODO -- add license check

#include <nupic/engine/NuPIC.hpp>
#include <nupic/engine/RegionImplFactory.hpp>
#include <nupic/utils/Log.hpp>
#include <apr-1/apr_general.h>

namespace nupic
{

std::set<Network*> NuPIC::networks_;
bool NuPIC::initialized_ = false;

void NuPIC::init()
{
  if (isInitialized())
    return;

  // internal consistency check. Nonzero should be impossible.
  NTA_CHECK(networks_.size() == 0) << "Internal error in NuPIC::init()";

  // Initialize APR as a library client
  // TODO: move to OS::initialize()?
  int result = apr_initialize();
  if (result)
    NTA_THROW << "Error initializing APR (code " << result << ")";

  // TODO: license checking will be done in NuPIC::init()

  initialized_ = true;
}

void NuPIC::shutdown()
{
  if (!isInitialized())
  {
    NTA_THROW << "NuPIC::shutdown -- NuPIC has not been initialized";
  }

  if (!networks_.empty())
  {
    NTA_THROW << "NuPIC::shutdown -- cannot shut down NuPIC because "
              << networks_.size() << " networks still exist.";
  }

  RegionImplFactory::getInstance().cleanup();
  initialized_ = false;
}

void NuPIC::registerNetwork(Network* net)
{
  if (!isInitialized())
  {
    NTA_THROW << "Attempt to create a network before NuPIC has been initialized -- call NuPIC::init() before creating any networks";
  }

  auto n = networks_.find(net);
  // This should not be possible
  NTA_CHECK(n == networks_.end()) << "Internal error -- double registration of network";
  networks_.insert(net);

}

void NuPIC::unregisterNetwork(Network* net)
{
  auto n = networks_.find(net);
  NTA_CHECK(n != networks_.end()) << "Internal error -- network not registered";
  networks_.erase(n);
}

bool NuPIC::isInitialized()
{
  return initialized_;
}

}

<commit_msg>Fixes #1234<commit_after>/* ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2013, Numenta, Inc.  Unless you have an agreement
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero Public License for more details.
 *
 * You should have received a copy of the GNU Affero Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

/* @file Implementation of NuPIC init/shutdown operations */

// TODO -- thread safety

#include <nupic/engine/NuPIC.hpp>
#include <nupic/engine/RegionImplFactory.hpp>
#include <nupic/utils/Log.hpp>
#include <apr-1/apr_general.h>

namespace nupic
{

std::set<Network*> NuPIC::networks_;
bool NuPIC::initialized_ = false;

void NuPIC::init()
{
  if (isInitialized())
    return;

  // internal consistency check. Nonzero should be impossible.
  NTA_CHECK(networks_.size() == 0) << "Internal error in NuPIC::init()";

  // Initialize APR as a library client
  // TODO: move to OS::initialize()?
  int result = apr_initialize();
  if (result)
    NTA_THROW << "Error initializing APR (code " << result << ")";

  initialized_ = true;
}

void NuPIC::shutdown()
{
  if (!isInitialized())
  {
    NTA_THROW << "NuPIC::shutdown -- NuPIC has not been initialized";
  }

  if (!networks_.empty())
  {
    NTA_THROW << "NuPIC::shutdown -- cannot shut down NuPIC because "
              << networks_.size() << " networks still exist.";
  }

  RegionImplFactory::getInstance().cleanup();
  initialized_ = false;
}

void NuPIC::registerNetwork(Network* net)
{
  if (!isInitialized())
  {
    NTA_THROW << "Attempt to create a network before NuPIC has been initialized -- call NuPIC::init() before creating any networks";
  }

  auto n = networks_.find(net);
  // This should not be possible
  NTA_CHECK(n == networks_.end()) << "Internal error -- double registration of network";
  networks_.insert(net);

}

void NuPIC::unregisterNetwork(Network* net)
{
  auto n = networks_.find(net);
  NTA_CHECK(n != networks_.end()) << "Internal error -- network not registered";
  networks_.erase(n);
}

bool NuPIC::isInitialized()
{
  return initialized_;
}

}

<|endoftext|>


<commit_before>/**
 ** \file object/system-class.cc
 ** \brief Creation of the URBI object system.
 */

//#define ENABLE_DEBUG_TRACES
#include <libport/compiler.hh>

#include <memory>
#include <sstream>

#include <binder/bind.hh>

#include <kernel/userver.hh>
#include <kernel/uconnection.hh>

#include <object/alien.hh>
#include <object/system-class.hh>
#include <object/task-class.hh>

#include <parser/parse.hh>
#include <parser/parse-result.hh>

#include <runner/at-handler.hh>
#include <runner/runner.hh>
#include <runner/interpreter.hh>

#include <ast/nary.hh>

namespace object
{
  rObject system_class;

  /*--------------------.
  | System primitives.  |
  `--------------------*/

#define SERVER_FUNCTION(Function)					\
  static rObject							\
  system_class_ ## Function (runner::Runner&, objects_type args)	\
  {									\
    CHECK_ARG_COUNT (1);						\
    ::urbiserver->Function();						\
    return void_class;							\
  }

  SERVER_FUNCTION(reboot)
  SERVER_FUNCTION(shutdown)

#undef SERVER_FUNCTION

  static rObject
  system_class_sleep (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (2);
    FETCH_ARG(1, Float);
    libport::utime_t deadline;
    if (arg1->value_get() == std::numeric_limits<ufloat>::infinity())
      deadline = std::numeric_limits<libport::utime_t>::max();
    else
      deadline = r.scheduler_get().get_time() +
	static_cast<libport::utime_t>(arg1->value_get() * 1000.0);
    r.yield_until (deadline);
    return void_class;
  }

  static rObject
  system_class_time (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    return Float::fresh(r.scheduler_get().get_time() / 1000.0);
  }

  static rObject
  system_class_shiftedTime (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    return Float::fresh ((r.scheduler_get().get_time() -
			  r.time_shift_get()) / 1000.0);
  }

  static rObject
  execute_parsed (runner::Runner& r,
                  parser::parse_result_type p, UrbiException e)
  {
    ast::rNary errs = new ast::Nary();
    p->process_errors(*errs);
    dynamic_cast<runner::Interpreter&>(r)(errs);
    if (ast::rNary ast = p->ast_take())
    {
      ast = binder::bind(ast).unsafe_cast<ast::Nary>();
      assert(ast);
      return dynamic_cast<runner::Interpreter&>(r).eval(ast);
    }
    else
      throw e;
  }

  static rObject
  system_class_assert_(runner::Runner&, objects_type args)
  {
    CHECK_ARG_COUNT(3);
    FETCH_ARG(2, String);
    if (!is_true(args[1]))
      throw PrimitiveError
	("assert_",
	 "assertion `" + arg2->value_get().name_get() + "' failed");
    return void_class;
  }

  static rObject
  system_class_eval (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT(2);
    FETCH_ARG(1, String);
    parser::parse_result_type p();
    return
      execute_parsed(r,
                     parser::parse(arg1->value_get()),
                     PrimitiveError("",
                                    std::string("Error executing command.")));
  }

  static rObject
  system_class_registerAtJob (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT(4);
    runner::register_at_job(dynamic_cast<runner::Interpreter&>(r),
			    args[1], args[2], args[3]);
    return object::void_class;
  }

  static rObject
  system_class_searchFile (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (2);
    FETCH_ARG(1, String);

    UServer& s = r.lobby_get()->value_get().connection.server_get();
    try
    {
      return String::fresh(libport::Symbol(
			     s.find_file(arg1->value_get ().name_get ())));
    }
    catch (libport::file_library::Not_found&)
    {
      throw
	PrimitiveError("searchFile",
		       "Unable to find file: "
		       + arg1->value_get().name_get());
      // Never reached
      assertion(false);
      return 0;
    }
  }

  static rObject
  system_class_loadFile (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (2);
    FETCH_ARG(1, String);

    std::string filename = arg1->value_get().name_get();

    if (!libport::path (filename).exists ())
      throw PrimitiveError("loadFile",
			   "No such file: " + filename);

    return
      execute_parsed(r,
                     parser::parse_file(filename),
		     PrimitiveError("", //same message than k1
				    "Error loading file: " + filename));
  }

  static rObject
  system_class_currentRunner (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    rObject res = object::Object::fresh();
    res->proto_add (task_class);
    res->slot_set (SYMBOL (runner), box (scheduler::rJob, &r));
    return res;
  }

  static rObject
  system_class_cycle (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    return Float::fresh (r.scheduler_get ().cycle_get ());
  }

  static rObject
  system_class_fresh (runner::Runner&, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    return String::fresh(libport::Symbol::fresh());
  }

  static rObject
  system_class_lobby (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    return r.lobby_get();
  }

  static rObject
  system_class_nonInterruptible (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    r.non_interruptible_set (true);
    return void_class;
  }

  static rObject
  system_class_quit (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    r.lobby_get()->value_get().connection.close();
    return void_class;
  }

  // This should give a backtrace as an urbi object.
  static rObject
  system_class_backtrace(runner::Runner& r, objects_type args)
  {
    // FIXME: This method sucks a bit, because show_backtrace sucks a
    // bit, because our channeling/message-sending system sucks a lot.
    CHECK_ARG_COUNT (1);
    runner::Runner::backtrace_type bt = r.backtrace_get();
    bt.pop_back();
    foreach (const runner::Runner::frame_type& elt,
	     boost::make_iterator_range(boost::rbegin(bt),
					boost::rend(bt)))
      r.send_message_("backtrace", elt.first + " (" + elt.second + ")");
    return void_class;
  }

  static rObject
  system_class_jobs(runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT(1);
    List::value_type res;
    foreach(scheduler::rJob job, r.scheduler_get().jobs_get())
      res.push_back(create_task_from_job(job));
    return List::fresh(res);
  }

#define SERVER_SET_VAR(Function, Variable, Value)			\
  static rObject							\
  system_class_ ## Function (runner::Runner&, objects_type args)	\
  {									\
    CHECK_ARG_COUNT (1);						\
    ::urbiserver->Variable = Value;					\
    return void_class;							\
  }

  SERVER_SET_VAR(debugoff, debugOutput, false)
  SERVER_SET_VAR(debugon, debugOutput, true)
  SERVER_SET_VAR(stopall, stopall, true)

#undef SERVER_SET_VAR

  void
  system_class_initialize ()
  {
    /// \a Call gives the name of the C++ function, and \a Name that in Urbi.
#define DECLARE(Name)				\
    DECLARE_PRIMITIVE(system, Name)

    DECLARE(assert_);
    DECLARE(backtrace);
    DECLARE(currentRunner);
    DECLARE(cycle);
    DECLARE(debugoff);
    DECLARE(debugon);
    DECLARE(eval);
    DECLARE(fresh);
    DECLARE(jobs);
    DECLARE(loadFile);
    DECLARE(lobby);
    DECLARE(nonInterruptible);
    DECLARE(quit);
    DECLARE(reboot);
    DECLARE(registerAtJob);
    DECLARE(searchFile);
    DECLARE(shiftedTime);
    DECLARE(shutdown);
    DECLARE(sleep);
    DECLARE(stopall);
    DECLARE(time);
#undef DECLARE
  }

}; // namespace object
<commit_msg>Fix currentRunner.<commit_after>/**
 ** \file object/system-class.cc
 ** \brief Creation of the URBI object system.
 */

//#define ENABLE_DEBUG_TRACES
#include <libport/compiler.hh>

#include <memory>
#include <sstream>

#include <binder/bind.hh>

#include <kernel/userver.hh>
#include <kernel/uconnection.hh>

#include <object/alien.hh>
#include <object/system-class.hh>
#include <object/task-class.hh>

#include <parser/parse.hh>
#include <parser/parse-result.hh>

#include <runner/at-handler.hh>
#include <runner/runner.hh>
#include <runner/interpreter.hh>

#include <ast/nary.hh>

namespace object
{
  rObject system_class;

  /*--------------------.
  | System primitives.  |
  `--------------------*/

#define SERVER_FUNCTION(Function)					\
  static rObject							\
  system_class_ ## Function (runner::Runner&, objects_type args)	\
  {									\
    CHECK_ARG_COUNT (1);						\
    ::urbiserver->Function();						\
    return void_class;							\
  }

  SERVER_FUNCTION(reboot)
  SERVER_FUNCTION(shutdown)

#undef SERVER_FUNCTION

  static rObject
  system_class_sleep (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (2);
    FETCH_ARG(1, Float);
    libport::utime_t deadline;
    if (arg1->value_get() == std::numeric_limits<ufloat>::infinity())
      deadline = std::numeric_limits<libport::utime_t>::max();
    else
      deadline = r.scheduler_get().get_time() +
	static_cast<libport::utime_t>(arg1->value_get() * 1000.0);
    r.yield_until (deadline);
    return void_class;
  }

  static rObject
  system_class_time (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    return Float::fresh(r.scheduler_get().get_time() / 1000.0);
  }

  static rObject
  system_class_shiftedTime (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    return Float::fresh ((r.scheduler_get().get_time() -
			  r.time_shift_get()) / 1000.0);
  }

  static rObject
  execute_parsed (runner::Runner& r,
                  parser::parse_result_type p, UrbiException e)
  {
    ast::rNary errs = new ast::Nary();
    p->process_errors(*errs);
    dynamic_cast<runner::Interpreter&>(r)(errs);
    if (ast::rNary ast = p->ast_take())
    {
      ast = binder::bind(ast).unsafe_cast<ast::Nary>();
      assert(ast);
      return dynamic_cast<runner::Interpreter&>(r).eval(ast);
    }
    else
      throw e;
  }

  static rObject
  system_class_assert_(runner::Runner&, objects_type args)
  {
    CHECK_ARG_COUNT(3);
    FETCH_ARG(2, String);
    if (!is_true(args[1]))
      throw PrimitiveError
	("assert_",
	 "assertion `" + arg2->value_get().name_get() + "' failed");
    return void_class;
  }

  static rObject
  system_class_eval (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT(2);
    FETCH_ARG(1, String);
    parser::parse_result_type p();
    return
      execute_parsed(r,
                     parser::parse(arg1->value_get()),
                     PrimitiveError("",
                                    std::string("Error executing command.")));
  }

  static rObject
  system_class_registerAtJob (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT(4);
    runner::register_at_job(dynamic_cast<runner::Interpreter&>(r),
			    args[1], args[2], args[3]);
    return object::void_class;
  }

  static rObject
  system_class_searchFile (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (2);
    FETCH_ARG(1, String);

    UServer& s = r.lobby_get()->value_get().connection.server_get();
    try
    {
      return String::fresh(libport::Symbol(
			     s.find_file(arg1->value_get ().name_get ())));
    }
    catch (libport::file_library::Not_found&)
    {
      throw
	PrimitiveError("searchFile",
		       "Unable to find file: "
		       + arg1->value_get().name_get());
      // Never reached
      assertion(false);
      return 0;
    }
  }

  static rObject
  system_class_loadFile (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (2);
    FETCH_ARG(1, String);

    std::string filename = arg1->value_get().name_get();

    if (!libport::path (filename).exists ())
      throw PrimitiveError("loadFile",
			   "No such file: " + filename);

    return
      execute_parsed(r,
                     parser::parse_file(filename),
		     PrimitiveError("", //same message than k1
				    "Error loading file: " + filename));
  }

  static rObject
  system_class_currentRunner (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    rObject res = object::Object::fresh();
    res->proto_add (task_class);
    res->slot_set (SYMBOL (job), box (scheduler::rJob, &r));
    return res;
  }

  static rObject
  system_class_cycle (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    return Float::fresh (r.scheduler_get ().cycle_get ());
  }

  static rObject
  system_class_fresh (runner::Runner&, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    return String::fresh(libport::Symbol::fresh());
  }

  static rObject
  system_class_lobby (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    return r.lobby_get();
  }

  static rObject
  system_class_nonInterruptible (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    r.non_interruptible_set (true);
    return void_class;
  }

  static rObject
  system_class_quit (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    r.lobby_get()->value_get().connection.close();
    return void_class;
  }

  // This should give a backtrace as an urbi object.
  static rObject
  system_class_backtrace(runner::Runner& r, objects_type args)
  {
    // FIXME: This method sucks a bit, because show_backtrace sucks a
    // bit, because our channeling/message-sending system sucks a lot.
    CHECK_ARG_COUNT (1);
    runner::Runner::backtrace_type bt = r.backtrace_get();
    bt.pop_back();
    foreach (const runner::Runner::frame_type& elt,
	     boost::make_iterator_range(boost::rbegin(bt),
					boost::rend(bt)))
      r.send_message_("backtrace", elt.first + " (" + elt.second + ")");
    return void_class;
  }

  static rObject
  system_class_jobs(runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT(1);
    List::value_type res;
    foreach(scheduler::rJob job, r.scheduler_get().jobs_get())
      res.push_back(create_task_from_job(job));
    return List::fresh(res);
  }

#define SERVER_SET_VAR(Function, Variable, Value)			\
  static rObject							\
  system_class_ ## Function (runner::Runner&, objects_type args)	\
  {									\
    CHECK_ARG_COUNT (1);						\
    ::urbiserver->Variable = Value;					\
    return void_class;							\
  }

  SERVER_SET_VAR(debugoff, debugOutput, false)
  SERVER_SET_VAR(debugon, debugOutput, true)
  SERVER_SET_VAR(stopall, stopall, true)

#undef SERVER_SET_VAR

  void
  system_class_initialize ()
  {
    /// \a Call gives the name of the C++ function, and \a Name that in Urbi.
#define DECLARE(Name)				\
    DECLARE_PRIMITIVE(system, Name)

    DECLARE(assert_);
    DECLARE(backtrace);
    DECLARE(currentRunner);
    DECLARE(cycle);
    DECLARE(debugoff);
    DECLARE(debugon);
    DECLARE(eval);
    DECLARE(fresh);
    DECLARE(jobs);
    DECLARE(loadFile);
    DECLARE(lobby);
    DECLARE(nonInterruptible);
    DECLARE(quit);
    DECLARE(reboot);
    DECLARE(registerAtJob);
    DECLARE(searchFile);
    DECLARE(shiftedTime);
    DECLARE(shutdown);
    DECLARE(sleep);
    DECLARE(stopall);
    DECLARE(time);
#undef DECLARE
  }

}; // namespace object
<|endoftext|>