<commit_before>#include "Win32FileSystem.hpp"
#include "Win32Handle.hpp"
#include "../File.hpp"
#include "../InputStream.hpp"
#include "../OutputStream.hpp"
#include "../EmptyFile.hpp"
#include "../PartFile.hpp"
#include "../Strings.hpp"
#include "../Exception.hpp"
#include <algorithm>

BEGIN_INANITY_PLATFORM

class Win32File : public File
{
private:
	void* data;
	size_t size;

public:
	Win32File(void* data, size_t size)
	: data(data), size(size) {}

	~Win32File()
	{
		UnmapViewOfFile(data);
	}

	void* GetData() const
	{
		return data;
	}

	size_t GetSize() const
	{
		return size;
	}
};

class Win32InputStream : public InputStream
{
private:
	ptr<Win32Handle> handle;
	mutable bigsize_t fileSize;

	bigsize_t GetFileSize() const
	{
		if(fileSize == (bigsize_t)-1)
		{
			LARGE_INTEGER size;
			if(!GetFileSizeEx(*handle, &size))
				THROW("Error getting file size");
			fileSize = (bigsize_t)size.QuadPart;
		}
		return fileSize;
	}

public:
	Win32InputStream(ptr<Win32Handle> handle)
	: handle(handle), fileSize(-1) {}

	size_t Read(void* data, size_t size)
	{
		if((DWORD)size != size)
			THROW("So big reading size is not supported");
		DWORD read;
		ReadFile(*handle, data, (DWORD)size, &read, NULL);
		return read;
	}

	bigsize_t Skip(bigsize_t size)
	{
		LARGE_INTEGER distance, oldFilePointer, newFilePointer;

		// determine current file pointer
		distance.QuadPart = (LONGLONG)0;
		if(!SetFilePointerEx(*handle, distance, &oldFilePointer, FILE_CURRENT))
			THROW("Can't determine current file pointer");

		// get file size
		bigsize_t fileSize = GetFileSize();

		// fix distance to move (because Windows allows
		// setting file pointer beyond the end of file)
		size = std::min((bigsize_t)oldFilePointer.QuadPart + size, fileSize) - (bigsize_t)oldFilePointer.QuadPart;

		// move
		distance.QuadPart = (LONGLONG)size;
		if(!SetFilePointerEx(*handle, distance, &newFilePointer, FILE_CURRENT))
			THROW("Can't move file pointer");

		return size;
	}
};

class Win32OutputStream : public OutputStream
{
private:
	ptr<Win32Handle> handle;

public:
	Win32OutputStream(ptr<Win32Handle> handle)
	: handle(handle) {}

	void Write(const void* data, size_t size)
	{
		if((DWORD)size != size)
			THROW("So big write size is not supported");
		DWORD written;
		if(!WriteFile(*handle, data, (DWORD)size, &written, NULL) || written != size)
			THROW("Disk write error");
	}
};

Win32FileSystem::Win32FileSystem(const String& userFolderName)
{
	//если имя абсолютное
	if(userFolderName.length() >= 2 && userFolderName[1] == ':')
		folderName = userFolderName;
	//иначе относительное
	else
	{
		//получить полное имя текущего каталога
		DWORD length = GetCurrentDirectory(0, NULL);
		wchar_t* buffer = new wchar_t[length];
		if(!GetCurrentDirectory(length, buffer))
		{
			delete [] buffer;
			THROW("Can't get current directory");
		}
		folderName = Strings::Unicode2UTF8(buffer);
		delete [] buffer;

		//прибавить к нему заданное имя каталога, и получить таким образом полный каталог
		if(userFolderName.length())
		{
			folderName += '\\';
			folderName += userFolderName;
		}
	}

	//убедиться, что имя каталога поддерживает длинные имена
	if(this->folderName.compare(0, 4, "\\\\?\\") != 0)
		this->folderName = "\\\\?\\" + this->folderName;
}

Win32FileSystem::Win32FileSystem()
{
	//создать абсолютную файловую систему, то есть ничего не делать;
	//folderName - пустая строка
}

String Win32FileSystem::GetFullName(String fileName) const
{
	if(folderName.length() && fileName.length() && fileName.front() == '/')
		fileName = fileName.substr(1);
	String result = folderName.length() ? (folderName + "\\" + fileName) : fileName;
	size_t length = result.length();
	for(size_t i = 0; i < length; ++i)
		if(result[i] == '/')
			result[i] = '\\';
	return result;
}

size_t Win32FileSystem::GetFileSize(const String& fileName)
{
	Win32Handle hFile = CreateFile(Strings::UTF82Unicode(GetFullName(fileName)).c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
	if(!hFile.IsValid())
		THROW("Can't open file to determine file size");

	LARGE_INTEGER size;
	if(!::GetFileSizeEx(hFile, &size))
		THROW("Can't get file size");

	size_t resultSize = (size_t)size.QuadPart;
	if(resultSize != size.QuadPart)
		THROW("File is too big");

	return resultSize;
}

ptr<File> Win32FileSystem::LoadPartOfFile(const String& fileName, long long mappingStart, size_t mappingSize)
{
	String name = GetFullName(fileName);
	try
	{
		Win32Handle hFile = CreateFile(Strings::UTF82Unicode(name).c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, NULL);
		if(!hFile.IsValid())
			THROW_SECONDARY("Can't open file", Exception::SystemError());
		size_t size;
		if(mappingSize)
			size = mappingSize;
		else
		{
			LARGE_INTEGER li;
			::GetFileSizeEx(hFile, &li);
			size = (size_t)li.QuadPart;
			if(size != li.QuadPart)
				THROW("File too long to map");
		}
		if(!size)
			return NEW(EmptyFile());
		Win32Handle hMapping = CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, 0);
		if(!hMapping)
			THROW_SECONDARY("Can't create file mapping", Exception::SystemError());

		//получить гранулярность выделения памяти
		static unsigned allocationGranularity = 0;
		if(!allocationGranularity)
		{
			SYSTEM_INFO systemInfo;
			GetSystemInfo(&systemInfo);
			allocationGranularity = systemInfo.dwAllocationGranularity;
		}

		//округлить начало проекции вниз на гранулярность
		long long realMappingStart = mappingStart & ~(long long)(allocationGranularity - 1);
		//вычислить реальный размер
		size_t realMappingSize = mappingSize + (size_t)(mappingStart - realMappingStart);
		//спроецировать файл с учетом этого сдвига
		void* data = MapViewOfFile(hMapping, FILE_MAP_READ, realMappingStart >> 32, realMappingStart & ((1LL << 32) - 1), realMappingSize);
		if(!data)
			THROW_SECONDARY("Can't map view of file", Exception::SystemError());

		//если сдвиг был
		if(realMappingStart < mappingStart)
			//вернуть указатель на частичный файл, с учетом сдвига
			return NEW(PartFile(NEW(Win32File(data, realMappingSize)), (char*)data + (size_t)(mappingStart - realMappingStart), size));
		//иначе сдвига не было, просто вернуть файл
		return NEW(Win32File(data, size));
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY("Can't load file \"" + fileName + "\" as \"" + name + "\"", exception);
	}
}

void Win32FileSystem::SaveFile(ptr<File> file, const String& fileName)
{
	String name = GetFullName(fileName);
	try
	{
		Win32Handle hFile = CreateFile(Strings::UTF82Unicode(name).c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, NULL);
		if(!hFile.IsValid())
			THROW_SECONDARY("Can't create file", Exception::SystemError());
		DWORD written;
		size_t size = file->GetSize();
		if((DWORD)size != size)
			THROW("So big files is not supported");
		if(!WriteFile(hFile, file->GetData(), (DWORD)size, &written, NULL) || written != size)
			THROW_SECONDARY("Can't write file", Exception::SystemError());
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY(String("Can't save file \"") + fileName + "\" as \"" + name + "\"", exception);
	}
}

ptr<InputStream> Win32FileSystem::LoadStream(const String& fileName)
{
	String name = GetFullName(fileName);
	try
	{
		ptr<Win32Handle> file = NEW(Win32Handle(CreateFile(Strings::UTF82Unicode(name).c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL)));
		if(!file->IsValid())
			THROW_SECONDARY("Can't open file", Exception::SystemError());
		return NEW(Win32InputStream(file));
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY(String("Can't load file \"") + fileName + "\" as \"" + name + "\" as stream", exception);
	}
}

ptr<OutputStream> Win32FileSystem::SaveStream(const String& fileName)
{
	String name = GetFullName(fileName);
	try
	{
		ptr<Win32Handle> file = NEW(Win32Handle(CreateFile(Strings::UTF82Unicode(name).c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, NULL)));
		if(!file->IsValid())
			THROW_SECONDARY("Can't open file", Exception::SystemError());
		return NEW(Win32OutputStream(file));
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY(String("Can't save file \"") + fileName + "\" as \"" + name + "\" as stream", exception);
	}
}

time_t Win32FileSystem::GetFileMTime(const String& fileName)
{
	String name = GetFullName(fileName);
	try
	{
		Win32Handle hFile = CreateFile(Strings::UTF82Unicode(name).c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, NULL);
		if(!file.IsValid())
			THROW_SECONDARY("Can't open file", Exception::SystemError());

		FILETIME t;
		if(!GetFileTime(hFile, NULL, NULL, &t))
			THROW_SECONDARY("Can't get file's mtime", Exception::SystemError());

		ULARGE_INTEGER ull;
		ull.LowPart = t.LowPart;
		ull.HighPart = t.HighPart;

		return (time_t)(ull.QuadPart / 10000000ULL - 11644473600ULL);
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY(String("Can't get mtime of \"") + fileName + "\"", exception);
	}
}

void Win32FileSystem::GetDirectoryEntries(const String& directoryName, std::vector<String>& entries) const
{
	WIN32_FIND_DATA find;
	HANDLE hFind = FindFirstFile(Strings::UTF82Unicode(GetFullName(directoryName) + "*").c_str(), &find);
	if(hFind == INVALID_HANDLE_VALUE) return;
	do
	{
		String fileTitle(Strings::Unicode2UTF8(find.cFileName));
		if(!fileTitle.length() || fileTitle[0] == '.' || (find.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
			continue;
		if(find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
			fileTitle += '/';
		entries.push_back(fileTitle);
	}
	while(FindNextFile(hFind, &find));
	FindClose(hFind);
}

ptr<File> Win32FileSystem::LoadFile(const String& fileName)
{
	return LoadPartOfFile(fileName, 0, 0);
}

ptr<Win32FileSystem> Win32FileSystem::GetNativeFileSystem()
{
	//этот метод сделан просто для лучшей понятности
	return NEW(Win32FileSystem());
}

void Win32FileSystem::GetFileNames(std::vector<String>& fileNames) const
{
	//только если файловая система не абсолютная
	if(folderName.length())
		GetAllDirectoryEntries("/", fileNames);
}

END_INANITY_PLATFORM
<commit_msg>build fix on windows<commit_after>#include "Win32FileSystem.hpp"
#include "Win32Handle.hpp"
#include "../File.hpp"
#include "../InputStream.hpp"
#include "../OutputStream.hpp"
#include "../EmptyFile.hpp"
#include "../PartFile.hpp"
#include "../Strings.hpp"
#include "../Exception.hpp"
#include <algorithm>

BEGIN_INANITY_PLATFORM

class Win32File : public File
{
private:
	void* data;
	size_t size;

public:
	Win32File(void* data, size_t size)
	: data(data), size(size) {}

	~Win32File()
	{
		UnmapViewOfFile(data);
	}

	void* GetData() const
	{
		return data;
	}

	size_t GetSize() const
	{
		return size;
	}
};

class Win32InputStream : public InputStream
{
private:
	ptr<Win32Handle> handle;
	mutable bigsize_t fileSize;

	bigsize_t GetFileSize() const
	{
		if(fileSize == (bigsize_t)-1)
		{
			LARGE_INTEGER size;
			if(!GetFileSizeEx(*handle, &size))
				THROW("Error getting file size");
			fileSize = (bigsize_t)size.QuadPart;
		}
		return fileSize;
	}

public:
	Win32InputStream(ptr<Win32Handle> handle)
	: handle(handle), fileSize(-1) {}

	size_t Read(void* data, size_t size)
	{
		if((DWORD)size != size)
			THROW("So big reading size is not supported");
		DWORD read;
		ReadFile(*handle, data, (DWORD)size, &read, NULL);
		return read;
	}

	bigsize_t Skip(bigsize_t size)
	{
		LARGE_INTEGER distance, oldFilePointer, newFilePointer;

		// determine current file pointer
		distance.QuadPart = (LONGLONG)0;
		if(!SetFilePointerEx(*handle, distance, &oldFilePointer, FILE_CURRENT))
			THROW("Can't determine current file pointer");

		// get file size
		bigsize_t fileSize = GetFileSize();

		// fix distance to move (because Windows allows
		// setting file pointer beyond the end of file)
		size = std::min((bigsize_t)oldFilePointer.QuadPart + size, fileSize) - (bigsize_t)oldFilePointer.QuadPart;

		// move
		distance.QuadPart = (LONGLONG)size;
		if(!SetFilePointerEx(*handle, distance, &newFilePointer, FILE_CURRENT))
			THROW("Can't move file pointer");

		return size;
	}
};

class Win32OutputStream : public OutputStream
{
private:
	ptr<Win32Handle> handle;

public:
	Win32OutputStream(ptr<Win32Handle> handle)
	: handle(handle) {}

	void Write(const void* data, size_t size)
	{
		if((DWORD)size != size)
			THROW("So big write size is not supported");
		DWORD written;
		if(!WriteFile(*handle, data, (DWORD)size, &written, NULL) || written != size)
			THROW("Disk write error");
	}
};

Win32FileSystem::Win32FileSystem(const String& userFolderName)
{
	//если имя абсолютное
	if(userFolderName.length() >= 2 && userFolderName[1] == ':')
		folderName = userFolderName;
	//иначе относительное
	else
	{
		//получить полное имя текущего каталога
		DWORD length = GetCurrentDirectory(0, NULL);
		wchar_t* buffer = new wchar_t[length];
		if(!GetCurrentDirectory(length, buffer))
		{
			delete [] buffer;
			THROW("Can't get current directory");
		}
		folderName = Strings::Unicode2UTF8(buffer);
		delete [] buffer;

		//прибавить к нему заданное имя каталога, и получить таким образом полный каталог
		if(userFolderName.length())
		{
			folderName += '\\';
			folderName += userFolderName;
		}
	}

	//убедиться, что имя каталога поддерживает длинные имена
	if(this->folderName.compare(0, 4, "\\\\?\\") != 0)
		this->folderName = "\\\\?\\" + this->folderName;
}

Win32FileSystem::Win32FileSystem()
{
	//создать абсолютную файловую систему, то есть ничего не делать;
	//folderName - пустая строка
}

String Win32FileSystem::GetFullName(String fileName) const
{
	if(folderName.length() && fileName.length() && fileName.front() == '/')
		fileName = fileName.substr(1);
	String result = folderName.length() ? (folderName + "\\" + fileName) : fileName;
	size_t length = result.length();
	for(size_t i = 0; i < length; ++i)
		if(result[i] == '/')
			result[i] = '\\';
	return result;
}

size_t Win32FileSystem::GetFileSize(const String& fileName)
{
	Win32Handle hFile = CreateFile(Strings::UTF82Unicode(GetFullName(fileName)).c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
	if(!hFile.IsValid())
		THROW("Can't open file to determine file size");

	LARGE_INTEGER size;
	if(!::GetFileSizeEx(hFile, &size))
		THROW("Can't get file size");

	size_t resultSize = (size_t)size.QuadPart;
	if(resultSize != size.QuadPart)
		THROW("File is too big");

	return resultSize;
}

ptr<File> Win32FileSystem::LoadPartOfFile(const String& fileName, long long mappingStart, size_t mappingSize)
{
	String name = GetFullName(fileName);
	try
	{
		Win32Handle hFile = CreateFile(Strings::UTF82Unicode(name).c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, NULL);
		if(!hFile.IsValid())
			THROW_SECONDARY("Can't open file", Exception::SystemError());
		size_t size;
		if(mappingSize)
			size = mappingSize;
		else
		{
			LARGE_INTEGER li;
			::GetFileSizeEx(hFile, &li);
			size = (size_t)li.QuadPart;
			if(size != li.QuadPart)
				THROW("File too long to map");
		}
		if(!size)
			return NEW(EmptyFile());
		Win32Handle hMapping = CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, 0);
		if(!hMapping)
			THROW_SECONDARY("Can't create file mapping", Exception::SystemError());

		//получить гранулярность выделения памяти
		static unsigned allocationGranularity = 0;
		if(!allocationGranularity)
		{
			SYSTEM_INFO systemInfo;
			GetSystemInfo(&systemInfo);
			allocationGranularity = systemInfo.dwAllocationGranularity;
		}

		//округлить начало проекции вниз на гранулярность
		long long realMappingStart = mappingStart & ~(long long)(allocationGranularity - 1);
		//вычислить реальный размер
		size_t realMappingSize = mappingSize + (size_t)(mappingStart - realMappingStart);
		//спроецировать файл с учетом этого сдвига
		void* data = MapViewOfFile(hMapping, FILE_MAP_READ, realMappingStart >> 32, realMappingStart & ((1LL << 32) - 1), realMappingSize);
		if(!data)
			THROW_SECONDARY("Can't map view of file", Exception::SystemError());

		//если сдвиг был
		if(realMappingStart < mappingStart)
			//вернуть указатель на частичный файл, с учетом сдвига
			return NEW(PartFile(NEW(Win32File(data, realMappingSize)), (char*)data + (size_t)(mappingStart - realMappingStart), size));
		//иначе сдвига не было, просто вернуть файл
		return NEW(Win32File(data, size));
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY("Can't load file \"" + fileName + "\" as \"" + name + "\"", exception);
	}
}

void Win32FileSystem::SaveFile(ptr<File> file, const String& fileName)
{
	String name = GetFullName(fileName);
	try
	{
		Win32Handle hFile = CreateFile(Strings::UTF82Unicode(name).c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, NULL);
		if(!hFile.IsValid())
			THROW_SECONDARY("Can't create file", Exception::SystemError());
		DWORD written;
		size_t size = file->GetSize();
		if((DWORD)size != size)
			THROW("So big files is not supported");
		if(!WriteFile(hFile, file->GetData(), (DWORD)size, &written, NULL) || written != size)
			THROW_SECONDARY("Can't write file", Exception::SystemError());
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY(String("Can't save file \"") + fileName + "\" as \"" + name + "\"", exception);
	}
}

ptr<InputStream> Win32FileSystem::LoadStream(const String& fileName)
{
	String name = GetFullName(fileName);
	try
	{
		ptr<Win32Handle> file = NEW(Win32Handle(CreateFile(Strings::UTF82Unicode(name).c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL)));
		if(!file->IsValid())
			THROW_SECONDARY("Can't open file", Exception::SystemError());
		return NEW(Win32InputStream(file));
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY(String("Can't load file \"") + fileName + "\" as \"" + name + "\" as stream", exception);
	}
}

ptr<OutputStream> Win32FileSystem::SaveStream(const String& fileName)
{
	String name = GetFullName(fileName);
	try
	{
		ptr<Win32Handle> file = NEW(Win32Handle(CreateFile(Strings::UTF82Unicode(name).c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, NULL)));
		if(!file->IsValid())
			THROW_SECONDARY("Can't open file", Exception::SystemError());
		return NEW(Win32OutputStream(file));
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY(String("Can't save file \"") + fileName + "\" as \"" + name + "\" as stream", exception);
	}
}

time_t Win32FileSystem::GetFileMTime(const String& fileName)
{
	String name = GetFullName(fileName);
	try
	{
		Win32Handle hFile = CreateFile(Strings::UTF82Unicode(name).c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, NULL);
		if(!hFile.IsValid())
			THROW_SECONDARY("Can't open file", Exception::SystemError());

		FILETIME t;
		if(!GetFileTime(hFile, NULL, NULL, &t))
			THROW_SECONDARY("Can't get file's mtime", Exception::SystemError());

		ULARGE_INTEGER ull;
		ull.LowPart = t.dwLowDateTime;
		ull.HighPart = t.dwHighDateTime;

		return (time_t)(ull.QuadPart / 10000000ULL - 11644473600ULL);
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY(String("Can't get mtime of \"") + fileName + "\"", exception);
	}
}

void Win32FileSystem::GetDirectoryEntries(const String& directoryName, std::vector<String>& entries) const
{
	WIN32_FIND_DATA find;
	HANDLE hFind = FindFirstFile(Strings::UTF82Unicode(GetFullName(directoryName) + "*").c_str(), &find);
	if(hFind == INVALID_HANDLE_VALUE) return;
	do
	{
		String fileTitle(Strings::Unicode2UTF8(find.cFileName));
		if(!fileTitle.length() || fileTitle[0] == '.' || (find.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
			continue;
		if(find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
			fileTitle += '/';
		entries.push_back(fileTitle);
	}
	while(FindNextFile(hFind, &find));
	FindClose(hFind);
}

ptr<File> Win32FileSystem::LoadFile(const String& fileName)
{
	return LoadPartOfFile(fileName, 0, 0);
}

ptr<Win32FileSystem> Win32FileSystem::GetNativeFileSystem()
{
	//этот метод сделан просто для лучшей понятности
	return NEW(Win32FileSystem());
}

void Win32FileSystem::GetFileNames(std::vector<String>& fileNames) const
{
	//только если файловая система не абсолютная
	if(folderName.length())
		GetAllDirectoryEntries("/", fileNames);
}

END_INANITY_PLATFORM
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: calendarwrapper.hxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: obo $ $Date: 2005-04-13 12:23:10 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _UNOTOOLS_CALENDARWRAPPER_HXX
#define _UNOTOOLS_CALENDARWRAPPER_HXX

#ifndef _DATETIME_HXX
#include <tools/datetime.hxx>
#endif
#ifndef _STRING_HXX
#include <tools/string.hxx>
#endif

#ifndef _COM_SUN_STAR_UNO_REFERENCE_HXX_
#include <com/sun/star/uno/Reference.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include <com/sun/star/uno/Sequence.hxx>
#endif
#ifndef _COM_SUN_STAR_I18N_CALENDAR_HPP_
#include <com/sun/star/i18n/Calendar.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_LOCALE_HPP_
#include <com/sun/star/lang/Locale.hpp>
#endif
#ifndef INCLUDED_UNOTOOLSDLLAPI_H
#include "unotools/unotoolsdllapi.h"
#endif

namespace com { namespace sun { namespace star {
    namespace lang {
        class XMultiServiceFactory;
    }
}}}

namespace com { namespace sun { namespace star {
    namespace i18n {
        class XExtendedCalendar;
    }
}}}

class UNOTOOLS_DLLPUBLIC CalendarWrapper
{
    ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xSMgr;
    ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XExtendedCalendar >   xC;

            DateTime            aEpochStart;        // 1Jan1970

public:
                                CalendarWrapper(
                                    const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & xSF
                                    );
                                ~CalendarWrapper();

    // wrapper implementations of XCalendar

    void loadDefaultCalendar( const ::com::sun::star::lang::Locale& rLocale );
    void loadCalendar( const ::rtl::OUString& rUniqueID, const ::com::sun::star::lang::Locale& rLocale );
    ::com::sun::star::i18n::Calendar getLoadedCalendar() const;
    ::com::sun::star::uno::Sequence< ::rtl::OUString > getAllCalendars( const ::com::sun::star::lang::Locale& rLocale ) const;
    ::rtl::OUString getUniqueID() const;
    /// set UTC date/time
    void setDateTime( double nTimeInDays );
    /// get UTC date/time
    double getDateTime() const;
    /// convenience method to set local date/time
    void setLocalDateTime( double nTimeInDays );
    /// convenience method to get local date/time
    double getLocalDateTime() const;
    void setValue( sal_Int16 nFieldIndex, sal_Int16 nValue );
    sal_Bool isValid() const;
    sal_Int16 getValue( sal_Int16 nFieldIndex ) const;
    void addValue( sal_Int16 nFieldIndex, sal_Int32 nAmount );
    sal_Int16 getFirstDayOfWeek() const;
    void setFirstDayOfWeek( sal_Int16 nDay );
    void setMinimumNumberOfDaysForFirstWeek( sal_Int16 nDays );
    sal_Int16 getMinimumNumberOfDaysForFirstWeek() const;
    sal_Int16 getNumberOfMonthsInYear() const;
    sal_Int16 getNumberOfDaysInWeek() const;
    ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > getMonths() const;
    ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > getDays() const;
    String getDisplayName( sal_Int16 nCalendarDisplayIndex, sal_Int16 nIdx, sal_Int16 nNameType ) const;

    // wrapper implementations of XExtendedCalendar

    String getDisplayString( sal_Int32 nCalendarDisplayCode, sal_Int16 nNativeNumberMode ) const;

    // convenience methods

    /// get epoch start (should be 01Jan1970)
    inline  const DateTime&     getEpochStart() const
                                    { return aEpochStart; }

    /// set a local (!) Gregorian DateTime
    inline  void                setGregorianDateTime( const DateTime& rDateTime )
                                    { setLocalDateTime( rDateTime - aEpochStart ); }

    /// get the DateTime as a local (!) Gregorian DateTime
    inline  DateTime            getGregorianDateTime() const
                                    { return aEpochStart + getLocalDateTime(); }

};

#endif
<commit_msg>INTEGRATION: CWS ooo19126 (1.8.34); FILE MERGED 2005/09/05 14:00:49 rt 1.8.34.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: calendarwrapper.hxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 09:27:31 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _UNOTOOLS_CALENDARWRAPPER_HXX
#define _UNOTOOLS_CALENDARWRAPPER_HXX

#ifndef _DATETIME_HXX
#include <tools/datetime.hxx>
#endif
#ifndef _STRING_HXX
#include <tools/string.hxx>
#endif

#ifndef _COM_SUN_STAR_UNO_REFERENCE_HXX_
#include <com/sun/star/uno/Reference.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include <com/sun/star/uno/Sequence.hxx>
#endif
#ifndef _COM_SUN_STAR_I18N_CALENDAR_HPP_
#include <com/sun/star/i18n/Calendar.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_LOCALE_HPP_
#include <com/sun/star/lang/Locale.hpp>
#endif
#ifndef INCLUDED_UNOTOOLSDLLAPI_H
#include "unotools/unotoolsdllapi.h"
#endif

namespace com { namespace sun { namespace star {
    namespace lang {
        class XMultiServiceFactory;
    }
}}}

namespace com { namespace sun { namespace star {
    namespace i18n {
        class XExtendedCalendar;
    }
}}}

class UNOTOOLS_DLLPUBLIC CalendarWrapper
{
    ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xSMgr;
    ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XExtendedCalendar >   xC;

            DateTime            aEpochStart;        // 1Jan1970

public:
                                CalendarWrapper(
                                    const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & xSF
                                    );
                                ~CalendarWrapper();

    // wrapper implementations of XCalendar

    void loadDefaultCalendar( const ::com::sun::star::lang::Locale& rLocale );
    void loadCalendar( const ::rtl::OUString& rUniqueID, const ::com::sun::star::lang::Locale& rLocale );
    ::com::sun::star::i18n::Calendar getLoadedCalendar() const;
    ::com::sun::star::uno::Sequence< ::rtl::OUString > getAllCalendars( const ::com::sun::star::lang::Locale& rLocale ) const;
    ::rtl::OUString getUniqueID() const;
    /// set UTC date/time
    void setDateTime( double nTimeInDays );
    /// get UTC date/time
    double getDateTime() const;
    /// convenience method to set local date/time
    void setLocalDateTime( double nTimeInDays );
    /// convenience method to get local date/time
    double getLocalDateTime() const;
    void setValue( sal_Int16 nFieldIndex, sal_Int16 nValue );
    sal_Bool isValid() const;
    sal_Int16 getValue( sal_Int16 nFieldIndex ) const;
    void addValue( sal_Int16 nFieldIndex, sal_Int32 nAmount );
    sal_Int16 getFirstDayOfWeek() const;
    void setFirstDayOfWeek( sal_Int16 nDay );
    void setMinimumNumberOfDaysForFirstWeek( sal_Int16 nDays );
    sal_Int16 getMinimumNumberOfDaysForFirstWeek() const;
    sal_Int16 getNumberOfMonthsInYear() const;
    sal_Int16 getNumberOfDaysInWeek() const;
    ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > getMonths() const;
    ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > getDays() const;
    String getDisplayName( sal_Int16 nCalendarDisplayIndex, sal_Int16 nIdx, sal_Int16 nNameType ) const;

    // wrapper implementations of XExtendedCalendar

    String getDisplayString( sal_Int32 nCalendarDisplayCode, sal_Int16 nNativeNumberMode ) const;

    // convenience methods

    /// get epoch start (should be 01Jan1970)
    inline  const DateTime&     getEpochStart() const
                                    { return aEpochStart; }

    /// set a local (!) Gregorian DateTime
    inline  void                setGregorianDateTime( const DateTime& rDateTime )
                                    { setLocalDateTime( rDateTime - aEpochStart ); }

    /// get the DateTime as a local (!) Gregorian DateTime
    inline  DateTime            getGregorianDateTime() const
                                    { return aEpochStart + getLocalDateTime(); }

};

#endif
<|endoftext|>


<commit_before>#pragma once
#include "internal/message.hpp"
#include "macros.hpp"
#include "../std/algorithm.hpp"
#include "../std/exception.hpp"
#include "../std/string.hpp"

class RootException : public exception
{
public:
  RootException(char const * what, string const & msg) : m_What(what), m_Msg(msg)
  {
  }

  virtual ~RootException() throw()
  {
  }

  virtual char const * what() const throw()
  {
    string asciiMsg;
    for (size_t i = 0; i < m_Msg.size(); ++i)
    {
      if (static_cast<unsigned char>(m_Msg[i]) < 128)
      {
        asciiMsg += char(m_Msg[i]);
      } else
      {
        asciiMsg += '?';
      }
    }
    static string msg = string(m_What) + ", \"" + asciiMsg + "\"";
    return msg.c_str();
  }

  string const & Msg() const throw()
  {
    return m_Msg;
  }

private:
  char const * m_What;
  string m_Msg;
};

#define DECLARE_EXCEPTION(exception_name, base_exception) \
  class exception_name : public base_exception \
  { \
  public: \
    exception_name(char const * what, string const & msg) : base_exception(what, msg) {} \
  }

// TODO: Use SRC_LOGGING macro.
#define MYTHROW(exception_name, msg) throw exception_name( \
  #exception_name " " __FILE__ ":" TO_STRING(__LINE__), ::my::impl::Message msg)

#define MYTHROW1(exception_name, param1, msg) throw exception_name(param1, \
  #exception_name " " __FILE__ ":" TO_STRING(__LINE__), ::my::impl::Message msg)
<commit_msg>Fix RootException message formatting.<commit_after>#pragma once
#include "internal/message.hpp"
#include "macros.hpp"

#include "../std/exception.hpp"
#include "../std/string.hpp"

class RootException : public exception
{
public:
  RootException(char const * what, string const & msg) : m_What(what), m_Msg(msg)
  {
  }

  virtual ~RootException() throw()
  {
  }

  virtual char const * what() const throw()
  {
    size_t const count = m_Msg.size();

    string asciiMsg;
    asciiMsg.resize(count);

    for (size_t i = 0; i < count; ++i)
    {
      if (static_cast<unsigned char>(m_Msg[i]) < 128)
        asciiMsg[i] = char(m_Msg[i]);
      else
        asciiMsg[i] = '?';
    }

    static string msg;
    msg = string(m_What) + ", \"" + asciiMsg + "\"";
    return msg.c_str();
  }

  string const & Msg() const throw()
  {
    return m_Msg;
  }

private:
  char const * m_What;
  string m_Msg;
};

#define DECLARE_EXCEPTION(exception_name, base_exception) \
  class exception_name : public base_exception \
  { \
  public: \
    exception_name(char const * what, string const & msg) : base_exception(what, msg) {} \
  }

// TODO: Use SRC_LOGGING macro.
#define MYTHROW(exception_name, msg) throw exception_name( \
  #exception_name " " __FILE__ ":" TO_STRING(__LINE__), ::my::impl::Message msg)

#define MYTHROW1(exception_name, param1, msg) throw exception_name(param1, \
  #exception_name " " __FILE__ ":" TO_STRING(__LINE__), ::my::impl::Message msg)
<|endoftext|>


<commit_before>
#include "ReadFileManager.h"        // Own interface
#include "ReadFile.h"               // engine::ReadFile

namespace engine {

    ReadFileManager::ReadFileManager()
    {
        // Default number of open files
        max_open_files = 10;
    }

    ReadFile *ReadFileManager::getReadFile( std::string fileName )
    {
        ReadFile *f = read_files.extractFromMap( fileName );

        // Remove non-valid ReadFiles
        if( f && !f->isValid() )
        {
            delete f;
            f = NULL;
        }

        if( !f )
            f = new ReadFile( fileName );

        // Insert at front ( remove the last used at the  back )
        read_files.insertAtFront( fileName , f );

        // Remove old File descriptors if necessary
        while( (int)read_files.size() > max_open_files )
        {

            ReadFile *rf = read_files.extractFromBack();

            if( rf == f )
                LM_X(1, ("Internal error"));

            rf->close();
            delete rf;
        }

        return f;
    }

}<commit_msg>Fix wrong number of max open files<commit_after>
#include "ReadFileManager.h"        // Own interface
#include "ReadFile.h"               // engine::ReadFile

namespace engine {

    ReadFileManager::ReadFileManager()
    {
        // Default number of open files
        max_open_files = 100;
    }

    ReadFile *ReadFileManager::getReadFile( std::string fileName )
    {
        ReadFile *f = read_files.extractFromMap( fileName );

        // Remove non-valid ReadFiles
        if( f && !f->isValid() )
        {
            delete f;
            f = NULL;
        }

        if( !f )
            f = new ReadFile( fileName );

        // Insert at front ( remove the last used at the  back )
        read_files.insertAtFront( fileName , f );

        // Remove old File descriptors if necessary
        while( (int)read_files.size() > max_open_files )
        {

            ReadFile *rf = read_files.extractFromBack();

            if( rf == f )
                LM_X(1, ("Internal error"));

            rf->close();
            delete rf;
        }

        return f;
    }

}
<|endoftext|>


<commit_before>/*=============================================================================
	Copyright (c) 2012-2013 Richard Otis

    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)
=============================================================================*/

// phase.cpp -- parser for PHASE command

#include "libtdb/include/libtdb_pch.hpp"
#include "libtdb/include/database_tdb.hpp"
#include "libtdb/include/utils/match_keyword.hpp"
#include <boost/lexical_cast.hpp>

// TODO: add support for the optional auxillary info string (comes after last sublattice argument)
void Database::DatabaseTDB::Phase(std::string &argstr) {
	std::string name; // phase name
	std::string codes, phase_code; // character codes for the phase
	int num_subl; // number of sublattices
	Sublattice_Collection subls; // sublattices, we only init stoi_coef in this parser
	std::vector<std::string> splitargs, init_commands;

	boost::split(splitargs, argstr, boost::is_any_of(" "));
	if (splitargs.size() < 4) { // we have the wrong number of arguments
		std::string argnum (boost::lexical_cast<std::string>(splitargs.size())); // convert number to string
		std::string err_msg("Wrong number of arguments (" + argnum + ")");
		BOOST_THROW_EXCEPTION(parse_error() << specific_errinfo(err_msg));
	}
	auto i = splitargs.begin(); // generate an iterator
	// the first few arguments are not in a loop
	// we increment the iterator manually
	// now evaluating the name argument
	auto iter_range = boost::find_first(*i, ":");
	name = std::string((*i).begin(),iter_range.begin()); // name is everything before the (optional) colon
	phase_code = std::string(iter_range.end(),(*i).end()); // TODO: check for GES phase-type codes after the colon

	if (phase_code.length() > 1) { // can be one character or zero characters
		std::string err_msg("Phase name incorrectly formatted");
		BOOST_THROW_EXCEPTION(parse_error() << specific_errinfo(err_msg));
	}
	if (phases.find(name) != phases.end()) { // the phase already exists
		std::string err_msg("Phase \"" + name + "\" already defined");
		BOOST_THROW_EXCEPTION(parse_error() << specific_errinfo(err_msg));
	}

	++i;
	// now at phase character code argument

	codes = *i;
	++i;
	// now at number of sublattices argument

	try {
		num_subl = boost::lexical_cast<int>(*i);
		++i;
		// now at first site stoi_coef argument
	}
	catch (boost::bad_lexical_cast &) {
		std::string err_msg ("Non-integer input for integer parameter");
		BOOST_THROW_EXCEPTION(parse_error() << specific_errinfo(err_msg));
	}
	if (splitargs.size() != (num_subl+3)) { // we have the wrong number of arguments
		std::string argnum (boost::lexical_cast<std::string>(splitargs.size())); // convert number to string
		std::string err_msg("Wrong number of arguments (" + argnum + ") for " + *i + " sublattice" + ((num_subl != 1) ? "s" : ""));
		BOOST_THROW_EXCEPTION(parse_error() << specific_errinfo(err_msg));
	}
	// collect all of the site occupancies
	try {
		while (i != splitargs.end()) {
			double stoi_coef = boost::lexical_cast<double>(*i);
			if (stoi_coef == 0) {
				std::cout << "0 stoi_coef, original was: " << *i << std::endl;
			}
			Sublattice s(stoi_coef); // init sublattice with site stoi_coef
			subls.push_back(s); // add sublattice to collection
			++i;
		}
	}
	catch (boost::bad_lexical_cast &) {
		std::string err_msg ("Non-numeric input for numeric parameter");
		BOOST_THROW_EXCEPTION(parse_error() << specific_errinfo(err_msg));
	}
	// Ensure that the type definitions for the phase have been defined
	for (auto j = codes.cbegin(); j != codes.cend(); ++j) {
		const std::string type(j, j+1);
		auto typefind = type_definitions.find(type);
		if (typefind == type_definitions.end()) {
			// undefined type definition
			std::string err_msg ("Undefined type definition: ");
			BOOST_THROW_EXCEPTION(parse_error() << specific_errinfo(err_msg + type));
		}
		else {
			init_commands.push_back(typefind->second); // add command to list
		}
	}
	phases[name] = ::Phase(name, subls, init_commands); // add Phase to the Database
}

void Phase::modify_phase(const std::string &command) {
	std::set<std::string> keywords = {
			"AMEND_PHASE_DESCRIPTION",
			"DISORDERED_PART",
			"MAGNETIC_ORDERING"
	};
	std::vector<std::string> words;
	std::string matching_command;
	boost::split(words, command, boost::is_any_of(" "), boost::token_compress_on);

	matching_command = match_keyword(words[0], keywords);

	if (matching_command == "AMEND_PHASE_DESCRIPTION") {
		// Modify a phase description
		if (words.size() >= 3) {
			auto words_iter = words.begin(); // on A_P_D command
			++words_iter; // name of phase
			if (*words_iter != phase_name) {
				// phase name mismatch
				std::string errmsg
				("Phase name mismatch in AMEND_PHASE_DESCRIPTION type definition for phase " + phase_name);
				BOOST_THROW_EXCEPTION(syntax_error() << specific_errinfo(errmsg));
			}
			++words_iter; // specific amendment to make
			std::string matching_subcommand = match_keyword(*words_iter, keywords);
			if (matching_subcommand == "MAGNETIC_ORDERING") {
				if (words.size() >= 5) {
					++words_iter; // AFM factor
					double afm_factor = boost::lexical_cast<double>(*words_iter);
					++words_iter; // SRO enthalpy factor
					double sro_factor = boost::lexical_cast<double>(*words_iter);

					// Modify the phase's magnetic settings
					magnetic_afm_factor = afm_factor;
					magnetic_sro_enthalpy_order_fraction = sro_factor;
					return;
				}
			}
			else if (matching_subcommand == "DISORDERED_PART") {
				// TODO: Atomic ordering model not yet implemented
				return;
			}
			BOOST_THROW_EXCEPTION(syntax_error() << specific_errinfo("Not implemented: " + command));
		}

	}
	BOOST_THROW_EXCEPTION(syntax_error() << specific_errinfo("Improper syntax for AMEND_PHASE_DESCRIPTION type definition in " + phase_name));
}

void Phase::process_type_definition(const std::string &command) {
	std::set<std::string> keywords = {
			"GES",
			"SEQ"
	};
	std::string test_command = std::string(command.begin(), boost::find_first(command, " ").begin());
	std::string matching_command = match_keyword(test_command, keywords);

	if (matching_command == "GES") {
		std::string remaining_command(boost::find_first(command, " ").end(), command.end());
		modify_phase(remaining_command);
	}
	else if (matching_command == "SEQ") {
		// we don't implement any of the optimizations provided by this command
	}
	else BOOST_THROW_EXCEPTION(syntax_error() << specific_errinfo("Unknown command in type definition for phase " + phase_name));
}

Phase::Phase (std::string phasename, Sublattice_Collection s, std::vector<std::string> init_commands) {
	phase_name = phasename;
	subls = s;
	magnetic_afm_factor = 0;
	magnetic_sro_enthalpy_order_fraction = 0;
	init_cmds = init_commands;
	// Apply all of this phase's type definitions
	for (auto i = init_cmds.begin(); i != init_cmds.end(); ++i) process_type_definition(*i);
}
<commit_msg>Token compression for string splitting<commit_after>/*=============================================================================
	Copyright (c) 2012-2013 Richard Otis

    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)
=============================================================================*/

// phase.cpp -- parser for PHASE command

#include "libtdb/include/libtdb_pch.hpp"
#include "libtdb/include/database_tdb.hpp"
#include "libtdb/include/utils/match_keyword.hpp"
#include <boost/lexical_cast.hpp>

// TODO: add support for the optional auxillary info string (comes after last sublattice argument)
void Database::DatabaseTDB::Phase(std::string &argstr) {
	std::string name; // phase name
	std::string codes, phase_code; // character codes for the phase
	int num_subl; // number of sublattices
	Sublattice_Collection subls; // sublattices, we only init stoi_coef in this parser
	std::vector<std::string> splitargs, init_commands;

	boost::split(splitargs, argstr, boost::is_any_of(" "), boost::token_compress_on);
	if (splitargs.size() < 4) { // we have the wrong number of arguments
		std::string argnum (boost::lexical_cast<std::string>(splitargs.size())); // convert number to string
		std::string err_msg("Wrong number of arguments (" + argnum + ")");
		BOOST_THROW_EXCEPTION(parse_error() << specific_errinfo(err_msg));
	}
	auto i = splitargs.begin(); // generate an iterator
	// the first few arguments are not in a loop
	// we increment the iterator manually
	// now evaluating the name argument
	auto iter_range = boost::find_first(*i, ":");
	name = std::string((*i).begin(),iter_range.begin()); // name is everything before the (optional) colon
	phase_code = std::string(iter_range.end(),(*i).end()); // TODO: check for GES phase-type codes after the colon

	if (phase_code.length() > 1) { // can be one character or zero characters
		std::string err_msg("Phase name incorrectly formatted");
		BOOST_THROW_EXCEPTION(parse_error() << specific_errinfo(err_msg));
	}
	if (phases.find(name) != phases.end()) { // the phase already exists
		std::string err_msg("Phase \"" + name + "\" already defined");
		BOOST_THROW_EXCEPTION(parse_error() << specific_errinfo(err_msg));
	}

	++i;
	// now at phase character code argument

	codes = *i;
	++i;
	// now at number of sublattices argument

	try {
		num_subl = boost::lexical_cast<int>(*i);
		++i;
		// now at first site stoi_coef argument
	}
	catch (boost::bad_lexical_cast &) {
		std::string err_msg ("Non-integer input for integer parameter");
		BOOST_THROW_EXCEPTION(parse_error() << specific_errinfo(err_msg));
	}
	if (splitargs.size() != (num_subl+3)) { // we have the wrong number of arguments
		std::string argnum (boost::lexical_cast<std::string>(splitargs.size())); // convert number to string
		std::string err_msg("Wrong number of arguments (" + argnum + ") for " + *i + " sublattice" + ((num_subl != 1) ? "s" : ""));
		BOOST_THROW_EXCEPTION(parse_error() << specific_errinfo(err_msg));
	}
	// collect all of the site occupancies
	try {
		while (i != splitargs.end()) {
			double stoi_coef = boost::lexical_cast<double>(*i);
			if (stoi_coef == 0) {
				std::cout << "0 stoi_coef, original was: " << *i << std::endl;
			}
			Sublattice s(stoi_coef); // init sublattice with site stoi_coef
			subls.push_back(s); // add sublattice to collection
			++i;
		}
	}
	catch (boost::bad_lexical_cast &) {
		std::string err_msg ("Non-numeric input for numeric parameter");
		BOOST_THROW_EXCEPTION(parse_error() << specific_errinfo(err_msg));
	}
	// Ensure that the type definitions for the phase have been defined
	for (auto j = codes.cbegin(); j != codes.cend(); ++j) {
		const std::string type(j, j+1);
		auto typefind = type_definitions.find(type);
		if (typefind == type_definitions.end()) {
			// undefined type definition
			std::string err_msg ("Undefined type definition: ");
			BOOST_THROW_EXCEPTION(parse_error() << specific_errinfo(err_msg + type));
		}
		else {
			init_commands.push_back(typefind->second); // add command to list
		}
	}
	phases[name] = ::Phase(name, subls, init_commands); // add Phase to the Database
}

void Phase::modify_phase(const std::string &command) {
	std::set<std::string> keywords = {
			"AMEND_PHASE_DESCRIPTION",
			"DISORDERED_PART",
			"MAGNETIC_ORDERING"
	};
	std::vector<std::string> words;
	std::string matching_command;
	boost::split(words, command, boost::is_any_of(" "), boost::token_compress_on);

	matching_command = match_keyword(words[0], keywords);

	if (matching_command == "AMEND_PHASE_DESCRIPTION") {
		// Modify a phase description
		if (words.size() >= 3) {
			auto words_iter = words.begin(); // on A_P_D command
			++words_iter; // name of phase
			if (*words_iter != phase_name) {
				// phase name mismatch
				std::string errmsg
				("Phase name mismatch in AMEND_PHASE_DESCRIPTION type definition for phase " + phase_name);
				BOOST_THROW_EXCEPTION(syntax_error() << specific_errinfo(errmsg));
			}
			++words_iter; // specific amendment to make
			std::string matching_subcommand = match_keyword(*words_iter, keywords);
			if (matching_subcommand == "MAGNETIC_ORDERING") {
				if (words.size() >= 5) {
					++words_iter; // AFM factor
					double afm_factor = boost::lexical_cast<double>(*words_iter);
					++words_iter; // SRO enthalpy factor
					double sro_factor = boost::lexical_cast<double>(*words_iter);

					// Modify the phase's magnetic settings
					magnetic_afm_factor = afm_factor;
					magnetic_sro_enthalpy_order_fraction = sro_factor;
					return;
				}
			}
			else if (matching_subcommand == "DISORDERED_PART") {
				// TODO: Atomic ordering model not yet implemented
				return;
			}
			BOOST_THROW_EXCEPTION(syntax_error() << specific_errinfo("Not implemented: " + command));
		}

	}
	BOOST_THROW_EXCEPTION(syntax_error() << specific_errinfo("Improper syntax for AMEND_PHASE_DESCRIPTION type definition in " + phase_name));
}

void Phase::process_type_definition(const std::string &command) {
	std::set<std::string> keywords = {
			"GES",
			"SEQ"
	};
	std::string test_command = std::string(command.begin(), boost::find_first(command, " ").begin());
	std::string matching_command = match_keyword(test_command, keywords);

	if (matching_command == "GES") {
		std::string remaining_command(boost::find_first(command, " ").end(), command.end());
		modify_phase(remaining_command);
	}
	else if (matching_command == "SEQ") {
		// we don't implement any of the optimizations provided by this command
	}
	else BOOST_THROW_EXCEPTION(syntax_error() << specific_errinfo("Unknown command in type definition for phase " + phase_name));
}

Phase::Phase (std::string phasename, Sublattice_Collection s, std::vector<std::string> init_commands) {
	phase_name = phasename;
	subls = s;
	magnetic_afm_factor = 0;
	magnetic_sro_enthalpy_order_fraction = 0;
	init_cmds = init_commands;
	// Apply all of this phase's type definitions
	for (auto i = init_cmds.begin(); i != init_cmds.end(); ++i) process_type_definition(*i);
}
<|endoftext|>


<commit_before>// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.

#include "precomp.hpp"
#include <opencv2/imgproc.hpp>
#include <algorithm>

using namespace cv;

namespace
{
class ROISelector
{
  public:
    Rect select(const String &windowName, Mat img, bool showCrossair = true, bool fromCenter = true)
    {
        // show notice to user
        printf("Select a ROI and then press SPACE or ENTER button!\n");
        printf("Cancel the selection process by pressing c button!\n");

        key = 0;
        imageSize = img.size();

        // set the drawing mode
        selectorParams.drawFromCenter = fromCenter;

        // show the image and give feedback to user
        imshow(windowName, img);

        // copy the data, rectangle should be drawn in the fresh image
        selectorParams.image = img.clone();

        // select the object
        setMouseCallback(windowName, mouseHandler, (void*)this);

        // end selection process on SPACE (32) ESC (27) or ENTER (13)
        while (!(key == 32 || key == 27 || key == 13))
        {
            // draw the selected object
            rectangle(selectorParams.image, selectorParams.box, Scalar(255, 0, 0), 2, 1);

            // draw cross air in the middle of bounding box
            if (showCrossair)
            {
                // horizontal line
                line(selectorParams.image,
                     Point((int)selectorParams.box.x,
                           (int)(selectorParams.box.y + selectorParams.box.height / 2)),
                     Point((int)(selectorParams.box.x + selectorParams.box.width),
                           (int)(selectorParams.box.y + selectorParams.box.height / 2)),
                     Scalar(255, 0, 0), 2, 1);

                // vertical line
                line(selectorParams.image,
                     Point((int)(selectorParams.box.x + selectorParams.box.width / 2),
                           (int)selectorParams.box.y),
                     Point((int)(selectorParams.box.x + selectorParams.box.width / 2),
                           (int)(selectorParams.box.y + selectorParams.box.height)),
                     Scalar(255, 0, 0), 2, 1);
            }

            // show the image bounding box
            imshow(windowName, selectorParams.image);

            // reset the image
            selectorParams.image = img.clone();

            // get keyboard event
            key = waitKey(30);

            if (key == 'c' || key == 'C')//cancel selection
            {
                selectorParams.box = Rect();
                break;
            }
        }

        //cleanup callback
        setMouseCallback(windowName, emptyMouseHandler, NULL);

        return selectorParams.box;
    }

    void select(const String &windowName, Mat img, std::vector<Rect> &boundingBoxes,
                bool showCrosshair = true, bool fromCenter = true)
    {
        printf("Finish the selection process by pressing ESC button!\n");
        boundingBoxes.clear();
        key = 0;

        // while key is not ESC (27)
        for (;;)
        {
            Rect temp = select(windowName, img, showCrosshair, fromCenter);
            if (key == 27)
                break;
            if (temp.width > 0 && temp.height > 0)
                boundingBoxes.push_back(temp);
        }
    }

    struct handlerT
    {
        // basic parameters
        bool isDrawing;
        Rect2d box;
        Mat image;

        // parameters for drawing from the center
        bool drawFromCenter;
        Point2f center;

        // initializer list
        handlerT() : isDrawing(false), drawFromCenter(true){};
    } selectorParams;

  private:
    static void emptyMouseHandler(int, int, int, int, void*)
    {
    }

    static void mouseHandler(int event, int x, int y, int flags, void *param)
    {
        ROISelector *self = static_cast<ROISelector *>(param);
        self->opencv_mouse_callback(event, x, y, flags);
    }

    void opencv_mouse_callback(int event, int x, int y, int)
    {
        switch (event)
        {
        // update the selected bounding box
        case EVENT_MOUSEMOVE:
            if (selectorParams.isDrawing)
            {
                if (selectorParams.drawFromCenter)
                {
                    selectorParams.box.width = 2 * (x - selectorParams.center.x);
                    selectorParams.box.height = 2 * (y - selectorParams.center.y);
                    selectorParams.box.x = std::min(
                                std::max(selectorParams.center.x - selectorParams.box.width / 2.0, 0.), (double)imageSize.width);
                    selectorParams.box.y = std::min(
                                std::max(selectorParams.center.y - selectorParams.box.height / 2.0, 0.), (double)imageSize.height);
                }
                else
                {
                    selectorParams.box.width = std::max(
                                std::min(x - selectorParams.box.x, (double)imageSize.width - selectorParams.box.x), - selectorParams.box.x);
                    selectorParams.box.height = std::max(
                                std::min(y - selectorParams.box.y, (double)imageSize.height - selectorParams.box.y), - selectorParams.box.y);
                }
            }
            break;

        // start to select the bounding box
        case EVENT_LBUTTONDOWN:
            selectorParams.isDrawing = true;
            selectorParams.box = Rect2d(x, y, 0, 0);
            selectorParams.center = Point2f((float)x, (float)y);
            break;

        // cleaning up the selected bounding box
        case EVENT_LBUTTONUP:
            selectorParams.isDrawing = false;
            if (selectorParams.box.width < 0)
            {
                selectorParams.box.x += selectorParams.box.width;
                selectorParams.box.width *= -1;
            }
            if (selectorParams.box.height < 0)
            {
                selectorParams.box.y += selectorParams.box.height;
                selectorParams.box.height *= -1;
            }
            break;
        }
    }

    // save the keypressed character
    int key;
    Size imageSize;
};
}

Rect cv::selectROI(InputArray img, bool showCrosshair, bool fromCenter)
{
    ROISelector selector;
    return selector.select("ROI selector", img.getMat(), showCrosshair, fromCenter);
}

Rect cv::selectROI(const String& windowName, InputArray img, bool showCrosshair, bool fromCenter)
{
    ROISelector selector;
    return selector.select(windowName, img.getMat(), showCrosshair, fromCenter);
}

void cv::selectROIs(const String& windowName, InputArray img,
                             std::vector<Rect>& boundingBox, bool showCrosshair, bool fromCenter)
{
    ROISelector selector;
    selector.select(windowName, img.getMat(), boundingBox, showCrosshair, fromCenter);
}
<commit_msg>Fix cv::selectROI rectangle rendering issue<commit_after>// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.

#include "precomp.hpp"
#include <opencv2/imgproc.hpp>
#include <algorithm>

using namespace cv;

namespace
{
class ROISelector
{
  public:
    Rect select(const String &windowName, Mat img, bool showCrossair = true, bool fromCenter = true)
    {
        // show notice to user
        printf("Select a ROI and then press SPACE or ENTER button!\n");
        printf("Cancel the selection process by pressing c button!\n");

        key = 0;
        imageSize = img.size();

        // set the drawing mode
        selectorParams.drawFromCenter = fromCenter;

        // show the image and give feedback to user
        imshow(windowName, img);

        // copy the data, rectangle should be drawn in the fresh image
        selectorParams.image = img.clone();

        // select the object
        setMouseCallback(windowName, mouseHandler, (void*)this);

        // end selection process on SPACE (32) ESC (27) or ENTER (13)
        while (!(key == 32 || key == 27 || key == 13))
        {
            // draw the selected object
            rectangle(selectorParams.image, selectorParams.box, Scalar(255, 0, 0), 2, 1);

            // draw cross air in the middle of bounding box
            if (showCrossair)
            {
                // horizontal line
                line(selectorParams.image,
                     Point((int)selectorParams.box.x,
                           (int)(selectorParams.box.y + selectorParams.box.height / 2)),
                     Point((int)(selectorParams.box.x + selectorParams.box.width),
                           (int)(selectorParams.box.y + selectorParams.box.height / 2)),
                     Scalar(255, 0, 0), 2, 1);

                // vertical line
                line(selectorParams.image,
                     Point((int)(selectorParams.box.x + selectorParams.box.width / 2),
                           (int)selectorParams.box.y),
                     Point((int)(selectorParams.box.x + selectorParams.box.width / 2),
                           (int)(selectorParams.box.y + selectorParams.box.height)),
                     Scalar(255, 0, 0), 2, 1);
            }

            // show the image bounding box
            imshow(windowName, selectorParams.image);

            // reset the image
            selectorParams.image = img.clone();

            // get keyboard event
            key = waitKey(30);

            if (key == 'c' || key == 'C')//cancel selection
            {
                selectorParams.box = Rect();
                break;
            }
        }

        //cleanup callback
        setMouseCallback(windowName, emptyMouseHandler, NULL);

        return selectorParams.box;
    }

    void select(const String &windowName, Mat img, std::vector<Rect> &boundingBoxes,
                bool showCrosshair = true, bool fromCenter = true)
    {
        printf("Finish the selection process by pressing ESC button!\n");
        boundingBoxes.clear();
        key = 0;

        // while key is not ESC (27)
        for (;;)
        {
            Rect temp = select(windowName, img, showCrosshair, fromCenter);
            if (key == 27)
                break;
            if (temp.width > 0 && temp.height > 0)
                boundingBoxes.push_back(temp);
        }
    }

    struct handlerT
    {
        // basic parameters
        bool isDrawing;
        Rect2d box;
        Mat image;
        Point2f startPos;

        // parameters for drawing from the center
        bool drawFromCenter;

        // initializer list
        handlerT() : isDrawing(false), drawFromCenter(true){};
    } selectorParams;

  private:
    static void emptyMouseHandler(int, int, int, int, void*)
    {
    }

    static void mouseHandler(int event, int x, int y, int flags, void *param)
    {
        ROISelector *self = static_cast<ROISelector *>(param);
        self->opencv_mouse_callback(event, x, y, flags);
    }

    void opencv_mouse_callback(int event, int x, int y, int)
    {
        switch (event)
        {
        // update the selected bounding box
        case EVENT_MOUSEMOVE:
            if (selectorParams.isDrawing)
            {
                if (selectorParams.drawFromCenter)
                {
                    // limit half extends to imageSize
                    float halfWidth = std::min(std::min(
                            std::abs(x - selectorParams.startPos.x),
                            selectorParams.startPos.x),
                            imageSize.width - selectorParams.startPos.x);
                    float halfHeight = std::min(std::min(
                            std::abs(y - selectorParams.startPos.y),
                            selectorParams.startPos.y),
                            imageSize.height - selectorParams.startPos.y);

                    selectorParams.box.width = halfWidth * 2;
                    selectorParams.box.height = halfHeight * 2;
                    selectorParams.box.x = selectorParams.startPos.x - halfWidth;
                    selectorParams.box.y = selectorParams.startPos.y - halfHeight;

                }
                else
                {
                    // limit x and y to imageSize
                    int lx = std::min(std::max(x, 0), imageSize.width);
                    int by = std::min(std::max(y, 0), imageSize.height);
                    selectorParams.box.width = std::abs(lx - selectorParams.startPos.x);
                    selectorParams.box.height = std::abs(by - selectorParams.startPos.y);
                    selectorParams.box.x = std::min((float)lx, selectorParams.startPos.x);
                    selectorParams.box.y = std::min((float)by, selectorParams.startPos.y);
                }
            }
            break;

        // start to select the bounding box
        case EVENT_LBUTTONDOWN:
            selectorParams.isDrawing = true;
            selectorParams.box = Rect2d(x, y, 0, 0);
            selectorParams.startPos = Point2f((float)x, (float)y);
            break;

        // cleaning up the selected bounding box
        case EVENT_LBUTTONUP:
            selectorParams.isDrawing = false;
            if (selectorParams.box.width < 0)
            {
                selectorParams.box.x += selectorParams.box.width;
                selectorParams.box.width *= -1;
            }
            if (selectorParams.box.height < 0)
            {
                selectorParams.box.y += selectorParams.box.height;
                selectorParams.box.height *= -1;
            }
            break;
        }
    }

    // save the keypressed character
    int key;
    Size imageSize;
};
}

Rect cv::selectROI(InputArray img, bool showCrosshair, bool fromCenter)
{
    ROISelector selector;
    return selector.select("ROI selector", img.getMat(), showCrosshair, fromCenter);
}

Rect cv::selectROI(const String& windowName, InputArray img, bool showCrosshair, bool fromCenter)
{
    ROISelector selector;
    return selector.select(windowName, img.getMat(), showCrosshair, fromCenter);
}

void cv::selectROIs(const String& windowName, InputArray img,
                             std::vector<Rect>& boundingBox, bool showCrosshair, bool fromCenter)
{
    ROISelector selector;
    selector.select(windowName, img.getMat(), boundingBox, showCrosshair, fromCenter);
}
<|endoftext|>


<commit_before>/*
 *
 */
#include <stdio.h>
#include "sync.h"
#include "topo.h"
#include "mp.h"
#include "measurement_framework.h"
#include <pthread.h>
#include <unistd.h>
#include <vector>

#include "model_defs.h"

//#define SEND7

#ifdef BARRELFISH
#include <barrelfish/barrelfish.h>
#include <posixcompat.h>
#endif

__thread struct sk_measurement m;
__thread struct sk_measurement m2;

unsigned num_threads;
#define NUM_RUNS 10000 //50 // 10000 // Tested up to 1.000.000
#define NUM_RESULTS 1000

pthread_barrier_t ab_barrier;

#define TOPO_NAME(x,y) sprintf(x, "%s_%s", y, topo_get_name());

/**
 * \brief Message ping-pong between topo_last_node() and get_sequentializer()
 */
extern __thread uint64_t ump_num_acks_sent;
static void* pingpong(void* a)
{
    char outname[1024];
    char outname2[1024];

     coreid_t tid = *((int*) a);
    __thread_init(tid, num_threads);

    // Setup buffer for measurements
    cycles_t *buf = (cycles_t*) malloc(sizeof(cycles_t)*NUM_RESULTS);
    cycles_t *buf2 = (cycles_t*) malloc(sizeof(cycles_t)*NUM_RESULTS);

    uintptr_t* v = (uintptr_t*) malloc(sizeof(uintptr_t)*8);
    v[0] = 0;

    TOPO_NAME(outname, "pingpong");
    TOPO_NAME(outname2, "pingpong_receive");
    sk_m_init(&m, NUM_RESULTS, outname, buf);
    sk_m_init(&m2, NUM_RESULTS, outname2, buf2);

    if (get_thread_id()==topo_last_node()) {

        mp_binding *b = get_binding(get_sequentializer(), get_thread_id());

        for (unsigned epoch=0; epoch<NUM_RUNS; epoch++) {
            sk_m_restart_tsc(&m);
            debug_printff("send %d\n", epoch);
#ifdef SEND7
            mp_send7(get_sequentializer(), epoch, 1, 2, 3, 4,
             	     5, 6);

            mp_send7(get_sequentializer(), epoch, 1, 2, 3, 4,
             	     5, 6);
#else
            mp_send(get_sequentializer(), epoch);
            mp_send(get_sequentializer(), epoch);
#endif
            debug_printff("receive %d\n", epoch);
            sk_m_restart_tsc(&m2);
#ifdef SEND7
            mp_receive_raw7(b, v);
            assert(v[0]==epoch);
            assert(v[1]==1);
            assert(v[2]==2);
            assert(v[3]==3);
            assert(v[4]==4);
            assert(v[5]==5);
            assert(v[6]==6);

            mp_receive_raw7(b, v);
            assert(v[0]==epoch);
            assert(v[1]==1);
            assert(v[2]==2);
            assert(v[3]==3);
            assert(v[4]==4);
            assert(v[5]==5);
            assert(v[6]==6);
#else
            if (mp_receive_raw(b) !=epoch) {
                printf("mp_receive_raw(b) != epoch");
                exit(1);
            }
            if (mp_receive_raw(b) !=epoch) {
                printf("mp_receive_raw(b) != epoch");
                exit(1);
            }
#endif
            sk_m_add(&m2);
            sk_m_add(&m);
        }

    }
    if (get_thread_id()==get_sequentializer()) {

        for (unsigned epoch=0; epoch<NUM_RUNS; epoch++) {
            mp_binding *b = get_binding(topo_last_node(), get_thread_id());

            debug_printff("receive %d\n", epoch);
            sk_m_restart_tsc(&m);
            sk_m_restart_tsc(&m2);
#ifdef SEND7
            mp_receive_raw7(b, v);
            assert(v[0]==epoch);
            assert(v[1]==1);
            assert(v[2]==2);
            assert(v[3]==3);
            assert(v[4]==4);
            assert(v[5]==5);
            assert(v[6]==6);

            mp_receive_raw7(b, v);
            assert(v[0]==epoch);
            assert(v[1]==1);
            assert(v[2]==2);
            assert(v[3]==3);
            assert(v[4]==4);
            assert(v[5]==5);
            assert(v[6]==6);
#else
            if (mp_receive_raw(b) != epoch) {
                printf("mp_receive_raw(b) != epoch");
                exit(1);
            }

            if (mp_receive_raw(b) != epoch) {
                printf("mp_receive_raw(b) != epoch");
                exit(1);
            }
#endif
            sk_m_add(&m2);

            debug_printff("send %d\n", epoch);
#ifdef SEND7
            mp_send7(topo_last_node(), epoch,
                    1,
                    2,
                    3,
                    4,
                    5,
                    6);
            mp_send7(topo_last_node(), epoch,
                    1,
                    2,
                    3,
                    4,
                    5,
                    6);
#else
            mp_send(topo_last_node(), epoch);
            mp_send(topo_last_node(), epoch);
#endif
            sk_m_add(&m);
        }
    }

    if (get_thread_id() == topo_last_node() ||
        get_thread_id() == get_sequentializer()) {

        sk_m_print(&m);
        sk_m_print(&m2);
    }

    __thread_end();
    return NULL;
}

/**
 * \brief Broadcast trigger by topo_last_node() until back to LAST_NODE
 */
static void* ab(void* a)
{
    char outname[1024];

   coreid_t tid = *((int*) a);
    __thread_init(tid, num_threads);

    // Setup buffer for measurements
    cycles_t *buf = (cycles_t*) malloc(sizeof(cycles_t)*NUM_RESULTS);
    uintptr_t* v = (uintptr_t*) malloc(sizeof(uintptr_t)*8);
    v[0] = 0;

    TOPO_NAME(outname, "ab");
    sk_m_init(&m, NUM_RESULTS, outname, buf);

    std::vector<int> *leafs = topo_all_leaf_nodes()[0];

    for (std::vector<int>::iterator i=leafs->begin(); i!=leafs->end(); ++i) {

        coreid_t last_node = (coreid_t) *i;
        sk_m_reset(&m);

        for (int epoch=0; epoch<NUM_RUNS; epoch++) {

            sk_m_restart_tsc(&m);

            if (get_thread_id()==last_node) {
#ifdef SEND7
                mp_send7(get_sequentializer(), 1, 2, 3, 4, 5, 6, 7);
#else
                mp_send(get_sequentializer(), 0);
#endif
            }

            if (get_thread_id()==get_sequentializer()) {
#ifdef SEND7
		        mp_receive7(last_node, v);
		        mp_send_ab7(v[0], v[1], v[2], v[3], v[4],
			                v[5], v[6]);
#else
                mp_send_ab(mp_receive(last_node));
#endif
            }
            else {
#ifdef SEND7
                mp_receive_forward7(v);
#else
                mp_receive_forward(0);
#endif
            }

            sk_m_add(&m);
/*
            if (get_thread_id() == last_node) {
                printf("Round %d finished \n", epoch);
            }
*/
        }

        if (get_thread_id() == last_node) {
            sk_m_print(&m);
        }
    }

    __thread_end();
    return NULL;
}

extern void shl_barrier_shm(int b_count);

/**
 * \brief
 */
static void* reduction(void* a)
{
    char outname[1024];

    coreid_t tid = *((int*) a);
    __thread_init(tid, num_threads);

    // Setup buffer for measurements
    cycles_t *buf = (cycles_t*) malloc(sizeof(cycles_t)*NUM_RESULTS);
    uintptr_t* v = (uintptr_t*) malloc(sizeof(uintptr_t)*8);

    TOPO_NAME(outname, "reduction");
    sk_m_init(&m, NUM_RESULTS, outname, buf);

    std::vector<int> *leafs = topo_all_leaf_nodes()[0];

    for (std::vector<int>::iterator i=leafs->begin(); i!=leafs->end(); ++i) {

        coreid_t last_node = (coreid_t) *i;
        sk_m_reset(&m);

        for (int epoch=0; epoch<NUM_RUNS; epoch++) {

            sk_m_restart_tsc(&m);
#ifdef SEND7
            mp_reduce7(v,
                       1, 1, 1, 1, 1, 1, 1);
#else
            mp_reduce(tid);
#endif

            if (tid==get_sequentializer()) {
#ifdef SEND7
                mp_send7(last_node, 0, 1, 2, 3, 4, 5, 6);
#else
                mp_send(last_node, 0);
#endif
            } else if (tid==last_node) {
#ifdef SEND7
                mp_receive7(get_sequentializer(), v);
#else
                v[0] = mp_receive(get_sequentializer());
#endif
                sk_m_add(&m);
            }
        }

        if (get_thread_id() == last_node) {
            sk_m_print(&m);
        }

    }

    __thread_end();
    return NULL;
}

static void* barrier(void* a)
{
    // XXX Perhaps we also want all leaf nodes here?

    char outname[1024];

    coreid_t tid = *((int*) a);
    __thread_init(tid, num_threads);

    // Setup buffer for measurements
    cycles_t *buf = (cycles_t*) malloc(sizeof(cycles_t)*NUM_RESULTS);

    TOPO_NAME(outname, "barriers");
    sk_m_init(&m, NUM_RESULTS, outname, buf);

    for (int epoch=0; epoch<NUM_RUNS; epoch++) {

        mp_barrier(NULL);

        if (tid==topo_last_node()) sk_m_add(&m);
    }

    if (get_thread_id()==get_sequentializer() ||
        get_thread_id()==topo_last_node()) {

        sk_m_print(&m);
    }

    __thread_end();
    return NULL;
}

static void* agreement(void* a)
{
    char outname[1024];

    coreid_t tid = *((int*) a);
    __thread_init(tid, num_threads);

    // Setup buffer for measurements
    cycles_t *buf = (cycles_t*) malloc(sizeof(cycles_t)*NUM_RESULTS);
    uintptr_t* v = (uintptr_t*) malloc(sizeof(uintptr_t)*8);
    v[0] = 0;

    TOPO_NAME(outname, "agreement");
    sk_m_init(&m, NUM_RESULTS, outname, buf);

    uintptr_t payload = 7;

    std::vector<int> *_leaf_nodes = topo_all_leaf_nodes()[0];

    for (std::vector<int>::iterator i=_leaf_nodes->begin();
         i!=_leaf_nodes->end(); ++i) {

        coreid_t last_node = (coreid_t) *i;
        assert (last_node>=0 && last_node<=num_threads);

        sk_m_reset(&m);

        for (int epoch =0; epoch < NUM_RUNS; epoch++) {

            /*
             * Phase one of 2PC is a broadcast followed by
             * a reduction
             */
            sk_m_restart_tsc(&m);

            //Synchronize
#ifndef SEND7
            uintptr_t val = 0;
#endif
            if (get_thread_id() == last_node) {
#ifdef SEND7
               mp_send7(get_sequentializer(), 0, 0, 0, 0, 0, 0, payload);
#else
               mp_send(get_sequentializer(), payload);
#endif
            }

            // broadcast to all

            if (tid == get_sequentializer()) {
#ifdef SEND7
                mp_receive7(last_node, v);
                mp_send_ab7(v[0], v[1], v[2], v[3], v[4], v[5], v[6]);
#else
                mp_send_ab(mp_receive(last_node));
#endif
            } else {
#ifdef SEND7
                mp_receive_forward7(v);
#else
                val = mp_receive_forward(0);
#endif
            }
            // Reduction
#ifdef SEND7
            mp_reduce7(v, v[0], v[1], v[2], v[3], v[4], v[5], v[6]);
#else
            mp_reduce(val);
#endif

            /*
             * Phase two of 2PC is a broadcast to inform
             * of the commit
             */
            //Broadcast to all
            if (tid == get_sequentializer()) {
#ifdef SEND7
                mp_send_ab7(0, 0, 0, 0, 0, 0, payload);
#else
                mp_send_ab(val);
#endif
            } else {
#ifdef SEND7
                mp_receive_forward7(v);
#else
                val = mp_receive_forward(0);
#endif
            }

            sk_m_add(&m);

        }
        if (get_thread_id() == last_node) {
            sk_m_print(&m);
        }
    }
    __thread_end();
    return NULL;
}

#define NUM_EXP 5

#ifdef BARRELFISH
static void domain_init_done(void *arg, errval_t err)
{
    debug_printf("SPANNED!\n");
}
#endif

int main(int argc, char **argv)
{
    unsigned nthreads = sysconf(_SC_NPROCESSORS_CONF);

    __sync_init(nthreads, true);

    num_threads = get_num_threads();

    pthread_barrier_init(&ab_barrier, NULL, num_threads);

    typedef void* (worker_func_t)(void*);
    worker_func_t* workers[NUM_EXP] = {
        &pingpong,
        &ab,
        &reduction,
        &barrier,
        &agreement,
    };

    const char *labels[NUM_EXP] = {
        "Ping pong",
        "Atomic broadcast",
        "Reduction",
        "barrier",
        "Agreement",
    };

    pthread_t ptds[num_threads];
    int tids[num_threads];

#ifdef BARRELFISH
    cpu_set_t *cpuset = CPU_ALLOC(num_threads);

    for (unsigned i=1; i<num_threads; i++) {
        //for (int i = my_core_id + BOMP_DEFAULT_CORE_STRIDE; i < nos_threads + my_core_id; i++) {
        coreid_t core = i;
        errval_t err = domain_new_dispatcher(core, domain_init_done, NULL);
        if (err_is_fail(err)) {
            DEBUG_ERR(err, "failed to span domain");
            printf("Failed to span domain to %d\n", i);
            assert(err_is_ok(err));
        }
    }

#endif
    for (unsigned e=0; e<(topo_num_topos()); e++) {
        for (int j=0; j<NUM_EXP; j++) {
            printf("----------------------------------------\n");
            printf("Executing experiment %d - %s\n", (j+1), labels[j]);
            printf("----------------------------------------\n");

#ifdef BARRELFISH
            thread_yield();
#else
            // Yield to reduce the risk of getting de-scheduled later
            sched_yield();
#endif
            // Create
            for (unsigned i=1; i<num_threads; i++) {
                tids[i] = i;

#ifdef BARRELFISH
                pthread_attr_t attr;
                pthread_attr_init(&attr);

                CPU_ZERO(cpuset);
                CPU_SET(i, cpuset);
                pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), cpuset);

                pthread_create(ptds+i, &attr, workers[j], (void*) (tids+i));
#else
                pthread_create(ptds+i, NULL, workers[j], (void*) (tids+i));
#endif
            }
            // Master thread executes work for node 0
            tids[0] = 0;
            workers[j]((void*) (tids+0));

            // Join
            for (unsigned i=1; i<num_threads; i++) {
                pthread_join(ptds[i], NULL);
            }
        }

        if( e<topo_num_topos()-1) switch_topo();
    }

    pthread_barrier_destroy(&ab_barrier);

#ifdef SEND7
    printf("Send7 defined \n");
#endif

#ifdef BARRELFISH
    debug_printf("done!");
    while(1)
        ;
#endif
}
<commit_msg>bench: removed old unused ab-bench<commit_after><|endoftext|>


<commit_before>#include <iostream>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <sstream>
#include <getopt.h>
#include <memory>

#include "jsoncpp/json/json.h"
#include <mosquittopp.h>
#include <curl/curl.h>

#include "common/utils.h"
#include "common/mqtt_wrapper.h"
#include "http_helper.h"
#include "cloud_connection.h"
#include "local_connection.h"

using namespace std;

TMQTTNinjaBridgeHandler::TMQTTNinjaBridgeHandler(const TMQTTNinjaBridgeHandler::TConfig& mqtt_config)
    : TMQTTWrapper(mqtt_config)
    , VarDirectory("/var/lib/wirenboard/")
    , Activated(false)
    , ControlsCache()
{
    ReadBlockId();
    cout << "Ninja BlockId: " << BlockId << endl;

	Connect();
};

void TMQTTNinjaBridgeHandler::ReadBlockId()
{
    string serial_fname = VarDirectory + "serial.conf";
    ifstream serial_stream(serial_fname.c_str());

    if (not serial_stream.is_open()) {
        serial_stream.close();
        throw TBaseException("Cannot read serial from "  + serial_fname);
    }

    string wb_serial;
    serial_stream >> wb_serial;

    if (wb_serial.empty()) {
        throw TBaseException("Empty serial");
    }

    BlockId = string("Wb") + StringReplace(wb_serial,":","");
    StringUpper(BlockId);
}

string TMQTTNinjaBridgeHandler::GetTokenFilename() const
{
    return VarDirectory + BlockId + ".token";
}

bool TMQTTNinjaBridgeHandler::TryReadToken()
{
    const string & token_fname = GetTokenFilename();
    ifstream token_stream(token_fname.c_str());

    if (not token_stream.is_open()){
        cerr << "ERROR: Cannot read token from " << token_fname << endl;
        token_stream.close();
        return false;
    }

    token_stream >> Token;
    token_stream.close();

    if (not Token.empty()) {
        return true;
    }

    return false;
}

void TMQTTNinjaBridgeHandler::WriteToken()
{
    const string & token_fname = GetTokenFilename();
    ofstream token_stream(token_fname.c_str());

    if (not token_stream.is_open()){
        token_stream.close();
        throw TBaseException("Cannot write token to  " + token_fname);
    }

    token_stream << Token;
    token_stream.close();
}

bool TMQTTNinjaBridgeHandler::TryActivateBlock()
{

    string url = "http://wakai.ninja.is/rest/v0/block/";
    url += BlockId + "/activate";

	std::ostringstream oss;
    CURLcode rc = GetHttpUrl(url, oss, 10);
	if(rc == CURLE_OK) {
		std::string html = oss.str();
        cerr << "DEBUG: got response: " << html << endl;

        Json::Value root;
        Json::Reader reader;

        if(!reader.parse(html, root, false))  {
            cerr << "ERROR: Failed to parse Ninja activation response" << endl
               << reader.getFormatedErrorMessages() << endl;
            return false;
        }
        if (root.isMember("token")) {
            Token = root["token"].asString();
            cout << "Got token: " << Token << endl;
            return true;
        }

    }

    //~ cerr << "rc: " << rc << endl;
    return false;
}

int TMQTTNinjaBridgeHandler::PublishStatus(const string& status)
{
    return Publish(NULL, string("/devices/") + MQTTConfig.Id + "/controls/status", status, 0, true);
}

void TMQTTNinjaBridgeHandler::OnConnect(int rc)
{
	printf("Connected with code %d.\n", rc);

	if(rc == 0){
        string prefix = string("/devices/") + MQTTConfig.Id;
        Publish(NULL, prefix + "/meta/name", "NinjaBlocks bridge", 0, true);

        Publish(NULL, prefix + "/controls/block id", BlockId, 0, true);
        Publish(NULL, prefix + "/controls/block id/meta/type", "text", 0, true);
        Publish(NULL, prefix + "/controls/status/meta/type", "text", 0, true);
        PublishStatus("Waiting for activation");

        Subscribe(NULL, "/devices/+/controls/+");
        Subscribe(NULL, "/devices/+/controls/+/meta/type");
        Subscribe(NULL, "/devices/+/controls/+/meta/export");

	}
}

void TMQTTNinjaBridgeHandler::OnCloudConnect(int rc)
{
	printf("Connected to cloud with code %d.\n", rc);

	if(rc == 0) {
        PublishStatus("Connected");

        // Send data of all controls known so far
        for (auto & item : ControlsCache) {
            SendDeviceDataToCloud(item.second);
        }

    } else {
        PublishStatus("Connection error " + to_string(rc));
    }

}

void TMQTTNinjaBridgeHandler::SendDeviceDataToCloud(const TControlDesc& control_desc)
{
    // ...unless exporting was explicitly disabled
    if (not control_desc.Export) return;

    if (NinjaCloudMqttHandler) {
        NinjaCloudMqttHandler->SendDeviceData(control_desc);
    }
}

void TMQTTNinjaBridgeHandler::WaitForActivation()
{
    if (Activated) return;

    if (not TryReadToken()) {
        cout << "Waiting for activation..." << endl;

        while (not TryActivateBlock()) {
            cerr << ".";
        }
        cerr << endl;

        cout << "Block is activated!" << endl;
        WriteToken();
    }

    Activated = true;

    cout << "Block token is " << Token << endl;
    PublishStatus("Activated");
}

void TMQTTNinjaBridgeHandler::ConnectToCloud()
{

    TMQTTWrapper::TConfig ninja_mqtt_config;
    ninja_mqtt_config.Host = "mqttbeta.ninjablocks.co";
    ninja_mqtt_config.Port = 8883;
    ninja_mqtt_config.Id =  BlockId;

    NinjaCloudMqttHandler.reset(new TMQTTNinjaCloudHandler(ninja_mqtt_config, this));

    //~ PublishStatus("Connected");

}

TControlDesc& TMQTTNinjaBridgeHandler::GetOrAddControlDesc(const string& device_id, const string& control_id)
{
    auto key = decltype(ControlsCache)::key_type(device_id, control_id);
    if (ControlsCache.find(key) == ControlsCache.end()) {
        // not found
        TControlDesc desc;
        desc.DeviceId = device_id;
        desc.Id = control_id;

        ControlsCache[key] = desc;
    }

    return ControlsCache[key];

}

void TMQTTNinjaBridgeHandler::OnMessage(const struct mosquitto_message *message)
{
    // ignore zero-length payload
    if (message->payload == 0) return;

    string topic = message->topic;
    string payload = static_cast<const char *>(message->payload);
    const vector<string>& tokens = StringSplit(topic, '/');
    bool match;

    if (mosquitto_topic_matches_sub("/devices/+/controls/+/meta/type", message->topic, &match) != MOSQ_ERR_SUCCESS) return;
    if (match) {
        const string& device_id = tokens[2];
        const string& control_id = tokens[4];

        TControlDesc & control = GetOrAddControlDesc(device_id, control_id);
        control.Type = payload;
    }

    if (mosquitto_topic_matches_sub("/devices/+/controls/+/meta/export", message->topic, &match) != MOSQ_ERR_SUCCESS) return;
    if (match) {
        const string& device_id = tokens[2];
        const string& control_id = tokens[4];

        TControlDesc & control = GetOrAddControlDesc(device_id, control_id);
        control.DeviceId = device_id;

        // control exporting is enabled by default
        control.Export = (payload == "0") ? false : true;
    }

    if (mosquitto_topic_matches_sub("/devices/+/controls/+", message->topic, &match) != MOSQ_ERR_SUCCESS) return;
    if (match) {
        const string& device_id = tokens[2];
        const string& control_id = tokens[4];

        if (device_id != MQTTConfig.Id) {
            TControlDesc & control = GetOrAddControlDesc(device_id, control_id);
            control.Value = payload;
            //~ cout << "upd for " << control.DeviceId << ":" << control.Id << ":" << control.Type << "=" << control.Value << endl;

            SendDeviceDataToCloud(control);
        }
    }
}

void TMQTTNinjaBridgeHandler::OnCloudControlUpdate(const string& device_id, const string& control_id, const string& value)
{
    auto iter = ControlsCache.find(make_pair(device_id, control_id));

    if (iter != ControlsCache.end()) {
        TControlDesc & control = iter->second;
        control.Value = value;

        Publish(NULL, "/devices/" + control.DeviceId + "/controls/" + control.Id + "/on", control.Value);
    }
}

void TMQTTNinjaBridgeHandler::OnSubscribe(int mid, int qos_count, const int *granted_qos)
{
}

//~ string TMQTTNinjaBridgeHandler::GetChannelTopic(const TSysfsOnewireDevice& device) {
    //~ static string controls_prefix = string("/devices/") + MQTTConfig.Id + "/controls/";
    //~ return (controls_prefix + device.GetDeviceId());
//~ }

//~ void TMQTTNinjaBridgeHandler::UpdateChannelValues() {
//~
    //~ for (const TSysfsOnewireDevice& device: Channels) {
        //~ auto result = device.ReadTemperature();
        //~ if (result.Defined()) {
            //~ Publish(NULL, GetChannelTopic(device), to_string(*result), 0, true); // Publish current value (make retained)
            //~ Publish(NULL, GetChannelTopic(device) + "/meta/type", "text", 0, true);
        //~ }
//~
    //~ }
//~ }

//~

<commit_msg>move to System room<commit_after>#include <iostream>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <sstream>
#include <getopt.h>
#include <memory>

#include "jsoncpp/json/json.h"
#include <mosquittopp.h>
#include <curl/curl.h>

#include "common/utils.h"
#include "common/mqtt_wrapper.h"
#include "http_helper.h"
#include "cloud_connection.h"
#include "local_connection.h"

using namespace std;

TMQTTNinjaBridgeHandler::TMQTTNinjaBridgeHandler(const TMQTTNinjaBridgeHandler::TConfig& mqtt_config)
    : TMQTTWrapper(mqtt_config)
    , VarDirectory("/var/lib/wirenboard/")
    , Activated(false)
    , ControlsCache()
{
    ReadBlockId();
    cout << "Ninja BlockId: " << BlockId << endl;

	Connect();
};

void TMQTTNinjaBridgeHandler::ReadBlockId()
{
    string serial_fname = VarDirectory + "serial.conf";
    ifstream serial_stream(serial_fname.c_str());

    if (not serial_stream.is_open()) {
        serial_stream.close();
        throw TBaseException("Cannot read serial from "  + serial_fname);
    }

    string wb_serial;
    serial_stream >> wb_serial;

    if (wb_serial.empty()) {
        throw TBaseException("Empty serial");
    }

    BlockId = string("Wb") + StringReplace(wb_serial,":","");
    StringUpper(BlockId);
}

string TMQTTNinjaBridgeHandler::GetTokenFilename() const
{
    return VarDirectory + BlockId + ".token";
}

bool TMQTTNinjaBridgeHandler::TryReadToken()
{
    const string & token_fname = GetTokenFilename();
    ifstream token_stream(token_fname.c_str());

    if (not token_stream.is_open()){
        cerr << "ERROR: Cannot read token from " << token_fname << endl;
        token_stream.close();
        return false;
    }

    token_stream >> Token;
    token_stream.close();

    if (not Token.empty()) {
        return true;
    }

    return false;
}

void TMQTTNinjaBridgeHandler::WriteToken()
{
    const string & token_fname = GetTokenFilename();
    ofstream token_stream(token_fname.c_str());

    if (not token_stream.is_open()){
        token_stream.close();
        throw TBaseException("Cannot write token to  " + token_fname);
    }

    token_stream << Token;
    token_stream.close();
}

bool TMQTTNinjaBridgeHandler::TryActivateBlock()
{

    string url = "http://wakai.ninja.is/rest/v0/block/";
    url += BlockId + "/activate";

	std::ostringstream oss;
    CURLcode rc = GetHttpUrl(url, oss, 10);
	if(rc == CURLE_OK) {
		std::string html = oss.str();
        cerr << "DEBUG: got response: " << html << endl;

        Json::Value root;
        Json::Reader reader;

        if(!reader.parse(html, root, false))  {
            cerr << "ERROR: Failed to parse Ninja activation response" << endl
               << reader.getFormatedErrorMessages() << endl;
            return false;
        }
        if (root.isMember("token")) {
            Token = root["token"].asString();
            cout << "Got token: " << Token << endl;
            return true;
        }

    }

    //~ cerr << "rc: " << rc << endl;
    return false;
}

int TMQTTNinjaBridgeHandler::PublishStatus(const string& status)
{
    return Publish(NULL, string("/devices/") + MQTTConfig.Id + "/controls/status", status, 0, true);
}

void TMQTTNinjaBridgeHandler::OnConnect(int rc)
{
	printf("Connected with code %d.\n", rc);

	if(rc == 0){
        string prefix = string("/devices/") + MQTTConfig.Id;
        Publish(NULL, prefix + "/meta/name", "NinjaBlocks bridge", 0, true);
        Publish(NULL, prefix + "/meta/room", "System", 0, true);

        Publish(NULL, prefix + "/controls/block id", BlockId, 0, true);
        Publish(NULL, prefix + "/controls/block id/meta/type", "text", 0, true);
        Publish(NULL, prefix + "/controls/status/meta/type", "text", 0, true);
        PublishStatus("Waiting for activation");

        Subscribe(NULL, "/devices/+/controls/+");
        Subscribe(NULL, "/devices/+/controls/+/meta/type");
        Subscribe(NULL, "/devices/+/controls/+/meta/export");

	}
}

void TMQTTNinjaBridgeHandler::OnCloudConnect(int rc)
{
	printf("Connected to cloud with code %d.\n", rc);

	if(rc == 0) {
        PublishStatus("Connected");

        // Send data of all controls known so far
        for (auto & item : ControlsCache) {
            SendDeviceDataToCloud(item.second);
        }

    } else {
        PublishStatus("Connection error " + to_string(rc));
    }

}

void TMQTTNinjaBridgeHandler::SendDeviceDataToCloud(const TControlDesc& control_desc)
{
    // ...unless exporting was explicitly disabled
    if (not control_desc.Export) return;

    if (NinjaCloudMqttHandler) {
        NinjaCloudMqttHandler->SendDeviceData(control_desc);
    }
}

void TMQTTNinjaBridgeHandler::WaitForActivation()
{
    if (Activated) return;

    if (not TryReadToken()) {
        cout << "Waiting for activation..." << endl;

        while (not TryActivateBlock()) {
            cerr << ".";
        }
        cerr << endl;

        cout << "Block is activated!" << endl;
        WriteToken();
    }

    Activated = true;

    cout << "Block token is " << Token << endl;
    PublishStatus("Activated");
}

void TMQTTNinjaBridgeHandler::ConnectToCloud()
{

    TMQTTWrapper::TConfig ninja_mqtt_config;
    ninja_mqtt_config.Host = "mqttbeta.ninjablocks.co";
    ninja_mqtt_config.Port = 8883;
    ninja_mqtt_config.Id =  BlockId;

    NinjaCloudMqttHandler.reset(new TMQTTNinjaCloudHandler(ninja_mqtt_config, this));

    //~ PublishStatus("Connected");

}

TControlDesc& TMQTTNinjaBridgeHandler::GetOrAddControlDesc(const string& device_id, const string& control_id)
{
    auto key = decltype(ControlsCache)::key_type(device_id, control_id);
    if (ControlsCache.find(key) == ControlsCache.end()) {
        // not found
        TControlDesc desc;
        desc.DeviceId = device_id;
        desc.Id = control_id;

        ControlsCache[key] = desc;
    }

    return ControlsCache[key];

}

void TMQTTNinjaBridgeHandler::OnMessage(const struct mosquitto_message *message)
{
    // ignore zero-length payload
    if (message->payload == 0) return;

    string topic = message->topic;
    string payload = static_cast<const char *>(message->payload);
    const vector<string>& tokens = StringSplit(topic, '/');
    bool match;

    if (mosquitto_topic_matches_sub("/devices/+/controls/+/meta/type", message->topic, &match) != MOSQ_ERR_SUCCESS) return;
    if (match) {
        const string& device_id = tokens[2];
        const string& control_id = tokens[4];

        TControlDesc & control = GetOrAddControlDesc(device_id, control_id);
        control.Type = payload;
    }

    if (mosquitto_topic_matches_sub("/devices/+/controls/+/meta/export", message->topic, &match) != MOSQ_ERR_SUCCESS) return;
    if (match) {
        const string& device_id = tokens[2];
        const string& control_id = tokens[4];

        TControlDesc & control = GetOrAddControlDesc(device_id, control_id);
        control.DeviceId = device_id;

        // control exporting is enabled by default
        control.Export = (payload == "0") ? false : true;
    }

    if (mosquitto_topic_matches_sub("/devices/+/controls/+", message->topic, &match) != MOSQ_ERR_SUCCESS) return;
    if (match) {
        const string& device_id = tokens[2];
        const string& control_id = tokens[4];

        if (device_id != MQTTConfig.Id) {
            TControlDesc & control = GetOrAddControlDesc(device_id, control_id);
            control.Value = payload;
            //~ cout << "upd for " << control.DeviceId << ":" << control.Id << ":" << control.Type << "=" << control.Value << endl;

            SendDeviceDataToCloud(control);
        }
    }
}

void TMQTTNinjaBridgeHandler::OnCloudControlUpdate(const string& device_id, const string& control_id, const string& value)
{
    auto iter = ControlsCache.find(make_pair(device_id, control_id));

    if (iter != ControlsCache.end()) {
        TControlDesc & control = iter->second;
        control.Value = value;

        Publish(NULL, "/devices/" + control.DeviceId + "/controls/" + control.Id + "/on", control.Value);
    }
}

void TMQTTNinjaBridgeHandler::OnSubscribe(int mid, int qos_count, const int *granted_qos)
{
}

//~ string TMQTTNinjaBridgeHandler::GetChannelTopic(const TSysfsOnewireDevice& device) {
    //~ static string controls_prefix = string("/devices/") + MQTTConfig.Id + "/controls/";
    //~ return (controls_prefix + device.GetDeviceId());
//~ }

//~ void TMQTTNinjaBridgeHandler::UpdateChannelValues() {
//~
    //~ for (const TSysfsOnewireDevice& device: Channels) {
        //~ auto result = device.ReadTemperature();
        //~ if (result.Defined()) {
            //~ Publish(NULL, GetChannelTopic(device), to_string(*result), 0, true); // Publish current value (make retained)
            //~ Publish(NULL, GetChannelTopic(device) + "/meta/type", "text", 0, true);
        //~ }
//~
    //~ }
//~ }

//~

<|endoftext|>