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

#include "archivefile.h"

#include <shared/system/types.h>
#include <shared/system/debug.h>
#include <shared/math/math.h>
#include <shared/components/storage.h>

#include <zlib.h>
#include <limits>

CArchiveFile::CArchiveFile()
{
	//Init
	for(int i=0; i<256; i++)
	{
		m_ItemTypes[i].m_ItemSize = 0;
		m_ItemTypes[i].m_NumItems = 0;
		m_ItemTypes[i].m_pData = NULL;
	}
}

CArchiveFile::~CArchiveFile()
{
	Close();
}

bool CArchiveFile::Open(CStorage* pStorage, const char* pFilename, int StorageType)
{
	//Open file
	debug::WarningStream("ArchiveFile") << "could not open '" << StorageType << "'" << std::endl;
	IOHANDLE File = pStorage->OpenFile(pFilename, IOFLAG_READ, StorageType);
	if(!File)
	{
		debug::WarningStream("ArchiveFile") << "could not open '" << pFilename << "'" << std::endl;
		return false;
	}

	//Get CRC
	m_Crc = crc32(0L, 0x0, 0);
	{
		enum
		{
			BUFFER_SIZE = 64*1024
		};

		unsigned char aBuffer[BUFFER_SIZE];

		while(1)
		{
			unsigned Bytes = io_read(File, aBuffer, BUFFER_SIZE);
			if(Bytes <= 0)
				break;
			m_Crc = crc32(m_Crc, aBuffer, Bytes);
		}

		io_seek(File, 0, IOSEEK_START);
	}

	//Check signature
	char aSignature[5];
	io_read(File, &aSignature, sizeof(aSignature));
	if(str_comp_num(aSignature, "TUA1", 4) != 0)
	{
		debug::WarningStream("ArchiveFile") << "wrong signature. " << aSignature[0] << " " << aSignature[1] << " " << aSignature[2] << " " << aSignature[3] << " " << std::endl;
		io_close(File);
		return false;
	}

	//Get Header
	CArchiveFile_Header StoredHeader;
	io_read(File, &StoredHeader, sizeof(StoredHeader));

	//Get items
	uint32 NumTypes = ReadUInt32(StoredHeader.m_NumTypes);
	for(uint32 i=0; i<NumTypes; i++)
	{
		CArchiveFile_ItemType StoredType;
		io_read(File, &StoredType, sizeof(StoredType));

		uint32 TypeId = ReadUInt32(StoredType.m_TypeId);
		CItemType& Type = m_ItemTypes[TypeId];
		Type.m_ItemSize = ReadUInt32(StoredType.m_ItemSize);
		Type.m_NumItems = ReadUInt32(StoredType.m_NumItems);

		Type.m_pData = new uint8[Type.m_ItemSize * Type.m_NumItems];

		io_read(File, Type.m_pData, Type.m_ItemSize * Type.m_NumItems * sizeof(uint8));
	}

	//Get raw datas
	uint32 NumRawDatas = ReadUInt32(StoredHeader.m_NumRawDatas);
	for(uint32 i=0; i<NumRawDatas; i++)
	{
		CArchiveFile_RawData StoredRawData;
		io_read(File, &StoredRawData, sizeof(StoredRawData));

		m_RawDatas.emplace_back();
		m_RawDatas.back().m_CompressedSize = ReadUInt32(StoredRawData.m_CompressedSize);
		m_RawDatas.back().m_UncompressedSize = ReadUInt32(StoredRawData.m_UncompressedSize);

		if(m_RawDatas.back().m_CompressedSize > 0)
		{
			m_RawDatas.back().m_pCompressedData = new uint8[m_RawDatas.back().m_CompressedSize];
			io_read(File, m_RawDatas.back().m_pCompressedData, m_RawDatas.back().m_CompressedSize * sizeof(uint8));
			m_RawDatas.back().m_pUncompressedData = NULL;
		}
		else
		{
			m_RawDatas.back().m_pUncompressedData = new uint8[m_RawDatas.back().m_UncompressedSize];
			io_read(File, m_RawDatas.back().m_pUncompressedData, m_RawDatas.back().m_UncompressedSize * sizeof(uint8));
			m_RawDatas.back().m_pCompressedData = NULL;
		}
	}

	//Get strings
	uint32 NumStrings = ReadUInt32(StoredHeader.m_NumStrings);
	for(uint32 i=0; i<NumStrings; i++)
	{
		tua_uint32 StoredLength;
		io_read(File, &StoredLength, sizeof(StoredLength));
		uint32 Length = ReadUInt32(StoredLength);

		m_Strings.emplace_back();
		m_Strings.back().m_pText = new char[Length+1];
		io_read(File, m_Strings.back().m_pText, sizeof(char)*(Length+1));
	}

	io_close(File);

	return true;
}

bool CArchiveFile::Write(CStorage* pStorage, fs_stream_wb* pFileStream)
{
	//Write signature
	const char aSignature[] = "TUA1";
	pFileStream->write(&aSignature, sizeof(aSignature));

	//Counte number of types
	int NumTypes = 0;
	for(int i=0; i<256; i++)
	{
		if(m_ItemTypes[i].m_NumItems > 0)
			NumTypes++;
	}

	//Write Header
	CArchiveFile_Header StoredHeader;
	StoredHeader.m_NumTypes = WriteUInt32(NumTypes);
	StoredHeader.m_NumStrings = WriteUInt32(m_Strings.size());
	StoredHeader.m_NumRawDatas = WriteUInt32(m_RawDatas.size());
	pFileStream->write(&StoredHeader, sizeof(StoredHeader));

	//Write items
	for(uint32 i=0; i<256; i++)
	{
		CItemType& Type = m_ItemTypes[i];

		if(Type.m_NumItems == 0)
			continue;

		CArchiveFile_ItemType StoredType;
		StoredType.m_ItemSize = WriteUInt32(Type.m_ItemSize);
		StoredType.m_NumItems = WriteUInt32(Type.m_NumItems);
		StoredType.m_TypeId = WriteUInt32(i);
		pFileStream->write(&StoredType, sizeof(StoredType));

		pFileStream->write(Type.m_pData, StoredType.m_NumItems * StoredType.m_ItemSize * sizeof(uint8));
	}

	//Write raw datas
	for(uint32 i=0; i<(uint32)m_RawDatas.size(); i++)
	{
		CRawData& RawData = m_RawDatas[i];
		CArchiveFile_RawData StoredRawData;
		if(RawData.m_pCompressedData)
		{
			StoredRawData.m_CompressedSize = WriteUInt32(RawData.m_CompressedSize);
			StoredRawData.m_UncompressedSize = WriteUInt32(RawData.m_UncompressedSize);
			pFileStream->write(&StoredRawData, sizeof(StoredRawData));
			pFileStream->write(RawData.m_pCompressedData, RawData.m_CompressedSize * sizeof(uint8));
		}
		else
		{
			StoredRawData.m_CompressedSize = WriteUInt32(0);
			StoredRawData.m_UncompressedSize = WriteUInt32(RawData.m_UncompressedSize);
			pFileStream->write(&StoredRawData, sizeof(StoredRawData));
			pFileStream->write(RawData.m_pUncompressedData, RawData.m_UncompressedSize * sizeof(uint8));
		}
	}

	//Write strings
	for(uint32 i=0; i<(uint32)m_Strings.size(); i++)
	{

		CString& String = m_Strings[i];
		uint32 Length = str_length(String.m_pText);
		tua_uint32 StoredLength = WriteUInt32(Length);
		pFileStream->write(&StoredLength, sizeof(StoredLength));
		pFileStream->write(String.m_pText, sizeof(char)*(Length+1));
	}

	return true;
}

bool CArchiveFile::Write(CStorage* pStorage, const char* pFilename, int Type)
{
	dynamic_string Buffer;
	pStorage->GetCompletePath(Type, pFilename, Buffer);

	fs_filestream_wb FileStream(Buffer.buffer());
	if(!FileStream.is_valid())
	{
		debug::WarningStream("ArchiveFile") << "could not open '" << pFilename << "' for writing" << std::endl;
		return false;
	}

	Write(pStorage, &FileStream);

	FileStream.close();

	return true;
}

void CArchiveFile::Close()
{
	for(int i=0; i<256; i++)
	{
		if(m_ItemTypes[i].m_pData)
		{
			delete[] m_ItemTypes[i].m_pData;
			m_ItemTypes[i].m_pData = NULL;
		}
	}

	for(unsigned int i=0; i<m_RawDatas.size(); i++)
	{
		if(m_RawDatas[i].m_pCompressedData)
			delete[] m_RawDatas[i].m_pCompressedData;
		if(m_RawDatas[i].m_pUncompressedData)
			delete[] m_RawDatas[i].m_pUncompressedData;
	}
	m_RawDatas.clear();

	for(unsigned int i=0; i<m_Strings.size(); i++)
	{
		if(m_Strings[i].m_pText)
			delete[] m_Strings[i].m_pText;
	}
	m_Strings.clear();
}

void CArchiveFile::SetItemType(uint32 Type, uint32 ItemSize, uint32 NumItems)
{
	if(m_ItemTypes[Type].m_pData)
		delete[] m_ItemTypes[Type].m_pData;

	m_ItemTypes[Type].m_ItemSize = ItemSize;
	m_ItemTypes[Type].m_NumItems = NumItems;
	m_ItemTypes[Type].m_pData = new uint8[ItemSize * NumItems];
}

uint8* CArchiveFile::GetData(tua_dataid StoredDataId)
{
	uint32 DataId = ReadDataId(StoredDataId);

	if(DataId >= (uint32)m_RawDatas.size())
	{
		debug::ErrorStream("ArchiveFile") << "can't read the data #" << DataId << std::endl;
		return NULL;
	}

	if(m_RawDatas[DataId].m_pUncompressedData)
	{
		return m_RawDatas[DataId].m_pUncompressedData;
	}
	else
	{
		unsigned long Size = m_RawDatas[DataId].m_UncompressedSize;
		m_RawDatas[DataId].m_pUncompressedData = new uint8[m_RawDatas[DataId].m_UncompressedSize];

		int Result = uncompress(
			(Bytef*)m_RawDatas[DataId].m_pUncompressedData,
			&Size,
			(Bytef*)m_RawDatas[DataId].m_pCompressedData,
			m_RawDatas[DataId].m_CompressedSize
		);

		if(Result != Z_OK)
		{
			debug::ErrorStream("ArchiveFile") << "compression error: " << zError(Result) << std::endl;
			return nullptr;
		}

		return m_RawDatas[DataId].m_pUncompressedData;
	}
}

tua_dataid CArchiveFile::AddData(uint8* pData, uint32 Size)
{
	unsigned long CompressedSize = compressBound(Size);
	m_RawDatas.emplace_back();
	m_RawDatas.back().m_UncompressedSize = Size;
	m_RawDatas.back().m_pUncompressedData = NULL;

	m_RawDatas.back().m_pCompressedData = new uint8[CompressedSize];

	int Result = compress((Bytef*)m_RawDatas.back().m_pCompressedData, &CompressedSize, (Bytef*)pData, Size);
	if(Result != Z_OK)
		debug::ErrorStream("ArchiveFile") << "compression error: " << zError(Result) << std::endl;

	if(CompressedSize >= Size)
	{
		m_RawDatas.back().m_CompressedSize = 0;
		delete[] m_RawDatas.back().m_pCompressedData;
		m_RawDatas.back().m_pCompressedData = NULL;

		m_RawDatas.back().m_pUncompressedData = new uint8[Size];
		mem_copy(m_RawDatas.back().m_pUncompressedData, pData, Size);
	}
	else
	{
		m_RawDatas.back().m_CompressedSize = CompressedSize;
	}

	return WriteDataId((uint32) m_RawDatas.size()-1);
}

const char* CArchiveFile::GetString(tua_stringid StoredStringId)
{
	if(StoredStringId == std::numeric_limits<tua_stringid>::max())
		return NULL;

	uint32 StringId = ReadStringId(StoredStringId);
	if(StringId >= (tua_stringid)m_Strings.size())
		return NULL;
	else
		return m_Strings[StringId].m_pText;
}

tua_stringid CArchiveFile::AddString(const char* pText)
{
	if(!pText)
		return -1;

	//Search if the string already exists
	for(unsigned int i=0; i<m_Strings.size(); i++)
	{
		if(str_comp(pText, m_Strings[i].m_pText) == 0)
			return WriteStringId((uint32) i);
	}

	int Length = str_length(pText);
	m_Strings.emplace_back();
	m_Strings.back().m_pText = new char[Length+1];
	str_copy(m_Strings.back().m_pText, pText, sizeof(char)*(Length+1));

	return WriteStringId((uint32) m_Strings.size()-1);
}
<commit_msg>Removes unwanted debug message<commit_after>/*
 * Copyright (C) 2016 necropotame (necropotame@gmail.com)
 *
 * This file is part of TeeUniverse.
 *
 * TeeUniverse is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * TeeUniverse is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with TeeUniverse.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "archivefile.h"

#include <shared/system/types.h>
#include <shared/system/debug.h>
#include <shared/math/math.h>
#include <shared/components/storage.h>

#include <zlib.h>
#include <limits>

CArchiveFile::CArchiveFile()
{
	//Init
	for(int i=0; i<256; i++)
	{
		m_ItemTypes[i].m_ItemSize = 0;
		m_ItemTypes[i].m_NumItems = 0;
		m_ItemTypes[i].m_pData = NULL;
	}
}

CArchiveFile::~CArchiveFile()
{
	Close();
}

bool CArchiveFile::Open(CStorage* pStorage, const char* pFilename, int StorageType)
{
	//Open file
	IOHANDLE File = pStorage->OpenFile(pFilename, IOFLAG_READ, StorageType);
	if(!File)
	{
		debug::WarningStream("ArchiveFile") << "could not open '" << pFilename << "'" << std::endl;
		return false;
	}

	//Get CRC
	m_Crc = crc32(0L, 0x0, 0);
	{
		enum
		{
			BUFFER_SIZE = 64*1024
		};

		unsigned char aBuffer[BUFFER_SIZE];

		while(1)
		{
			unsigned Bytes = io_read(File, aBuffer, BUFFER_SIZE);
			if(Bytes <= 0)
				break;
			m_Crc = crc32(m_Crc, aBuffer, Bytes);
		}

		io_seek(File, 0, IOSEEK_START);
	}

	//Check signature
	char aSignature[5];
	io_read(File, &aSignature, sizeof(aSignature));
	if(str_comp_num(aSignature, "TUA1", 4) != 0)
	{
		debug::WarningStream("ArchiveFile") << "wrong signature. " << aSignature[0] << " " << aSignature[1] << " " << aSignature[2] << " " << aSignature[3] << " " << std::endl;
		io_close(File);
		return false;
	}

	//Get Header
	CArchiveFile_Header StoredHeader;
	io_read(File, &StoredHeader, sizeof(StoredHeader));

	//Get items
	uint32 NumTypes = ReadUInt32(StoredHeader.m_NumTypes);
	for(uint32 i=0; i<NumTypes; i++)
	{
		CArchiveFile_ItemType StoredType;
		io_read(File, &StoredType, sizeof(StoredType));

		uint32 TypeId = ReadUInt32(StoredType.m_TypeId);
		CItemType& Type = m_ItemTypes[TypeId];
		Type.m_ItemSize = ReadUInt32(StoredType.m_ItemSize);
		Type.m_NumItems = ReadUInt32(StoredType.m_NumItems);

		Type.m_pData = new uint8[Type.m_ItemSize * Type.m_NumItems];

		io_read(File, Type.m_pData, Type.m_ItemSize * Type.m_NumItems * sizeof(uint8));
	}

	//Get raw datas
	uint32 NumRawDatas = ReadUInt32(StoredHeader.m_NumRawDatas);
	for(uint32 i=0; i<NumRawDatas; i++)
	{
		CArchiveFile_RawData StoredRawData;
		io_read(File, &StoredRawData, sizeof(StoredRawData));

		m_RawDatas.emplace_back();
		m_RawDatas.back().m_CompressedSize = ReadUInt32(StoredRawData.m_CompressedSize);
		m_RawDatas.back().m_UncompressedSize = ReadUInt32(StoredRawData.m_UncompressedSize);

		if(m_RawDatas.back().m_CompressedSize > 0)
		{
			m_RawDatas.back().m_pCompressedData = new uint8[m_RawDatas.back().m_CompressedSize];
			io_read(File, m_RawDatas.back().m_pCompressedData, m_RawDatas.back().m_CompressedSize * sizeof(uint8));
			m_RawDatas.back().m_pUncompressedData = NULL;
		}
		else
		{
			m_RawDatas.back().m_pUncompressedData = new uint8[m_RawDatas.back().m_UncompressedSize];
			io_read(File, m_RawDatas.back().m_pUncompressedData, m_RawDatas.back().m_UncompressedSize * sizeof(uint8));
			m_RawDatas.back().m_pCompressedData = NULL;
		}
	}

	//Get strings
	uint32 NumStrings = ReadUInt32(StoredHeader.m_NumStrings);
	for(uint32 i=0; i<NumStrings; i++)
	{
		tua_uint32 StoredLength;
		io_read(File, &StoredLength, sizeof(StoredLength));
		uint32 Length = ReadUInt32(StoredLength);

		m_Strings.emplace_back();
		m_Strings.back().m_pText = new char[Length+1];
		io_read(File, m_Strings.back().m_pText, sizeof(char)*(Length+1));
	}

	io_close(File);

	return true;
}

bool CArchiveFile::Write(CStorage* pStorage, fs_stream_wb* pFileStream)
{
	//Write signature
	const char aSignature[] = "TUA1";
	pFileStream->write(&aSignature, sizeof(aSignature));

	//Counte number of types
	int NumTypes = 0;
	for(int i=0; i<256; i++)
	{
		if(m_ItemTypes[i].m_NumItems > 0)
			NumTypes++;
	}

	//Write Header
	CArchiveFile_Header StoredHeader;
	StoredHeader.m_NumTypes = WriteUInt32(NumTypes);
	StoredHeader.m_NumStrings = WriteUInt32(m_Strings.size());
	StoredHeader.m_NumRawDatas = WriteUInt32(m_RawDatas.size());
	pFileStream->write(&StoredHeader, sizeof(StoredHeader));

	//Write items
	for(uint32 i=0; i<256; i++)
	{
		CItemType& Type = m_ItemTypes[i];

		if(Type.m_NumItems == 0)
			continue;

		CArchiveFile_ItemType StoredType;
		StoredType.m_ItemSize = WriteUInt32(Type.m_ItemSize);
		StoredType.m_NumItems = WriteUInt32(Type.m_NumItems);
		StoredType.m_TypeId = WriteUInt32(i);
		pFileStream->write(&StoredType, sizeof(StoredType));

		pFileStream->write(Type.m_pData, StoredType.m_NumItems * StoredType.m_ItemSize * sizeof(uint8));
	}

	//Write raw datas
	for(uint32 i=0; i<(uint32)m_RawDatas.size(); i++)
	{
		CRawData& RawData = m_RawDatas[i];
		CArchiveFile_RawData StoredRawData;
		if(RawData.m_pCompressedData)
		{
			StoredRawData.m_CompressedSize = WriteUInt32(RawData.m_CompressedSize);
			StoredRawData.m_UncompressedSize = WriteUInt32(RawData.m_UncompressedSize);
			pFileStream->write(&StoredRawData, sizeof(StoredRawData));
			pFileStream->write(RawData.m_pCompressedData, RawData.m_CompressedSize * sizeof(uint8));
		}
		else
		{
			StoredRawData.m_CompressedSize = WriteUInt32(0);
			StoredRawData.m_UncompressedSize = WriteUInt32(RawData.m_UncompressedSize);
			pFileStream->write(&StoredRawData, sizeof(StoredRawData));
			pFileStream->write(RawData.m_pUncompressedData, RawData.m_UncompressedSize * sizeof(uint8));
		}
	}

	//Write strings
	for(uint32 i=0; i<(uint32)m_Strings.size(); i++)
	{

		CString& String = m_Strings[i];
		uint32 Length = str_length(String.m_pText);
		tua_uint32 StoredLength = WriteUInt32(Length);
		pFileStream->write(&StoredLength, sizeof(StoredLength));
		pFileStream->write(String.m_pText, sizeof(char)*(Length+1));
	}

	return true;
}

bool CArchiveFile::Write(CStorage* pStorage, const char* pFilename, int Type)
{
	dynamic_string Buffer;
	pStorage->GetCompletePath(Type, pFilename, Buffer);

	fs_filestream_wb FileStream(Buffer.buffer());
	if(!FileStream.is_valid())
	{
		debug::WarningStream("ArchiveFile") << "could not open '" << pFilename << "' for writing" << std::endl;
		return false;
	}

	Write(pStorage, &FileStream);

	FileStream.close();

	return true;
}

void CArchiveFile::Close()
{
	for(int i=0; i<256; i++)
	{
		if(m_ItemTypes[i].m_pData)
		{
			delete[] m_ItemTypes[i].m_pData;
			m_ItemTypes[i].m_pData = NULL;
		}
	}

	for(unsigned int i=0; i<m_RawDatas.size(); i++)
	{
		if(m_RawDatas[i].m_pCompressedData)
			delete[] m_RawDatas[i].m_pCompressedData;
		if(m_RawDatas[i].m_pUncompressedData)
			delete[] m_RawDatas[i].m_pUncompressedData;
	}
	m_RawDatas.clear();

	for(unsigned int i=0; i<m_Strings.size(); i++)
	{
		if(m_Strings[i].m_pText)
			delete[] m_Strings[i].m_pText;
	}
	m_Strings.clear();
}

void CArchiveFile::SetItemType(uint32 Type, uint32 ItemSize, uint32 NumItems)
{
	if(m_ItemTypes[Type].m_pData)
		delete[] m_ItemTypes[Type].m_pData;

	m_ItemTypes[Type].m_ItemSize = ItemSize;
	m_ItemTypes[Type].m_NumItems = NumItems;
	m_ItemTypes[Type].m_pData = new uint8[ItemSize * NumItems];
}

uint8* CArchiveFile::GetData(tua_dataid StoredDataId)
{
	uint32 DataId = ReadDataId(StoredDataId);

	if(DataId >= (uint32)m_RawDatas.size())
	{
		debug::ErrorStream("ArchiveFile") << "can't read the data #" << DataId << std::endl;
		return NULL;
	}

	if(m_RawDatas[DataId].m_pUncompressedData)
	{
		return m_RawDatas[DataId].m_pUncompressedData;
	}
	else
	{
		unsigned long Size = m_RawDatas[DataId].m_UncompressedSize;
		m_RawDatas[DataId].m_pUncompressedData = new uint8[m_RawDatas[DataId].m_UncompressedSize];

		int Result = uncompress(
			(Bytef*)m_RawDatas[DataId].m_pUncompressedData,
			&Size,
			(Bytef*)m_RawDatas[DataId].m_pCompressedData,
			m_RawDatas[DataId].m_CompressedSize
		);

		if(Result != Z_OK)
		{
			debug::ErrorStream("ArchiveFile") << "compression error: " << zError(Result) << std::endl;
			return nullptr;
		}

		return m_RawDatas[DataId].m_pUncompressedData;
	}
}

tua_dataid CArchiveFile::AddData(uint8* pData, uint32 Size)
{
	unsigned long CompressedSize = compressBound(Size);
	m_RawDatas.emplace_back();
	m_RawDatas.back().m_UncompressedSize = Size;
	m_RawDatas.back().m_pUncompressedData = NULL;

	m_RawDatas.back().m_pCompressedData = new uint8[CompressedSize];

	int Result = compress((Bytef*)m_RawDatas.back().m_pCompressedData, &CompressedSize, (Bytef*)pData, Size);
	if(Result != Z_OK)
		debug::ErrorStream("ArchiveFile") << "compression error: " << zError(Result) << std::endl;

	if(CompressedSize >= Size)
	{
		m_RawDatas.back().m_CompressedSize = 0;
		delete[] m_RawDatas.back().m_pCompressedData;
		m_RawDatas.back().m_pCompressedData = NULL;

		m_RawDatas.back().m_pUncompressedData = new uint8[Size];
		mem_copy(m_RawDatas.back().m_pUncompressedData, pData, Size);
	}
	else
	{
		m_RawDatas.back().m_CompressedSize = CompressedSize;
	}

	return WriteDataId((uint32) m_RawDatas.size()-1);
}

const char* CArchiveFile::GetString(tua_stringid StoredStringId)
{
	if(StoredStringId == std::numeric_limits<tua_stringid>::max())
		return NULL;

	uint32 StringId = ReadStringId(StoredStringId);
	if(StringId >= (tua_stringid)m_Strings.size())
		return NULL;
	else
		return m_Strings[StringId].m_pText;
}

tua_stringid CArchiveFile::AddString(const char* pText)
{
	if(!pText)
		return -1;

	//Search if the string already exists
	for(unsigned int i=0; i<m_Strings.size(); i++)
	{
		if(str_comp(pText, m_Strings[i].m_pText) == 0)
			return WriteStringId((uint32) i);
	}

	int Length = str_length(pText);
	m_Strings.emplace_back();
	m_Strings.back().m_pText = new char[Length+1];
	str_copy(m_Strings.back().m_pText, pText, sizeof(char)*(Length+1));

	return WriteStringId((uint32) m_Strings.size()-1);
}
<|endoftext|>


<commit_before>#include "pch.h"
#include "UIFactory.h"

#include "Components\BoundsComponent.h"
#include "Components\ColorComponent.h"
#include "Components\DepthComponent.h"
#include "Components\FontComponent.h"
#include "Components\ScreenPositionComponent.h"
#include "Components\SpriteComponent.h"
#include "Components\TextAlignmentComponent.h"
#include "Components\TextComponent.h"
#include "Components\UIPanelComponent.h"
#include "Components\UIWidgetComponent.h"

#include "Events\EntityInitializedEvent.h"

#include "Math\Vector2F.h"

using namespace PinnedDownClient::Components;
using namespace PinnedDownClient::Events;
using namespace PinnedDownClient::Math;
using namespace PinnedDownClient::Systems::UI;

UIFactory::UIFactory(std::shared_ptr<GameInfrastructure> game)
{
	this->game = game;
}

int UIFactory::CreateLabel(std::wstring text)
{
	int entityId = this->game->entityManager->CreateEntity();

	auto boundsComponent = std::make_shared<BoundsComponent>();
	this->game->entityManager->AddComponent(entityId, boundsComponent);

	auto colorComponent = std::make_shared<ColorComponent>();
	colorComponent->color = D2D1::ColorF(D2D1::ColorF::White);
	this->game->entityManager->AddComponent(entityId, colorComponent);

	auto depthComponent = std::make_shared<DepthComponent>();
	this->game->entityManager->AddComponent(entityId, depthComponent);

	auto fontComponent = std::make_shared<FontComponent>();
	this->game->entityManager->AddComponent(entityId, fontComponent);

	auto screenPositionComponent = std::make_shared<ScreenPositionComponent>();
	this->game->entityManager->AddComponent(entityId, screenPositionComponent);

	auto textComponent = std::make_shared<TextComponent>();
	textComponent->text = text;
	this->game->entityManager->AddComponent(entityId, textComponent);

	auto textAlignmentComponent = std::make_shared<TextAlignmentComponent>();
	this->game->entityManager->AddComponent(entityId, textAlignmentComponent);

	auto anchorComponent = std::make_shared<UIAnchorComponent>();
	this->game->entityManager->AddComponent(entityId, anchorComponent);

	auto widgetComponent = std::make_shared<UIWidgetComponent>();
	this->game->entityManager->AddComponent(entityId, widgetComponent);

	return entityId;
}

int UIFactory::CreatePanel()
{
	int entityId = this->game->entityManager->CreateEntity();

	auto panelComponent = std::make_shared<UIPanelComponent>();
	this->game->entityManager->AddComponent(entityId, panelComponent);

	auto boundsComponent = std::make_shared<BoundsComponent>();
	this->game->entityManager->AddComponent(entityId, boundsComponent);

	auto screenPositionComponent = std::make_shared<ScreenPositionComponent>();
	this->game->entityManager->AddComponent(entityId, screenPositionComponent);

	auto depthComponent = std::make_shared<DepthComponent>();
	this->game->entityManager->AddComponent(entityId, depthComponent);

	return entityId;
}

int UIFactory::CreateSprite(std::wstring spriteName)
{
	int entityId = this->game->entityManager->CreateEntity();

	auto screenPositionComponent = std::make_shared<ScreenPositionComponent>();
	this->game->entityManager->AddComponent(entityId, screenPositionComponent);

	auto depthComponent = std::make_shared<DepthComponent>();
	this->game->entityManager->AddComponent(entityId, depthComponent);

	auto spriteComponent = std::make_shared<SpriteComponent>();
	spriteComponent->sprite = this->game->resourceManager->GetResource<BitmapResourceHandle>(spriteName.c_str());
	this->game->entityManager->AddComponent(entityId, spriteComponent);

	auto boundsComponent = std::make_shared<BoundsComponent>();
	auto bitmapSize = spriteComponent->sprite->bitmap->GetPixelSize();
	boundsComponent->bounds = Vector2F(static_cast<float>(bitmapSize.width), static_cast<float>(bitmapSize.height));
	this->game->entityManager->AddComponent(entityId, boundsComponent);

	auto anchorComponent = std::make_shared<UIAnchorComponent>();
	this->game->entityManager->AddComponent(entityId, anchorComponent);

	auto widgetComponent = std::make_shared<UIWidgetComponent>();
	this->game->entityManager->AddComponent(entityId, widgetComponent);

	return entityId;
}

void UIFactory::SetAnchor(int entityId, VerticalAnchor top, HorizontalAnchor left)
{
	auto anchorComponent = this->game->entityManager->GetComponent<UIAnchorComponent>(entityId, UIAnchorComponent::UIAnchorComponentType);
	anchorComponent->top = top;
	anchorComponent->left = left;
}

void UIFactory::SetAnchor(int entityId, VerticalAnchor top, HorizontalAnchor left, int anchorTarget)
{
	auto anchorComponent = this->game->entityManager->GetComponent<UIAnchorComponent>(entityId, UIAnchorComponent::UIAnchorComponentType);
	anchorComponent->top = top;
	anchorComponent->left = left;
	anchorComponent->target = anchorTarget;
}

void UIFactory::SetDepth(int entityId, int depth)
{
	auto depthComponent = this->game->entityManager->GetComponent<DepthComponent>(entityId, DepthComponent::DepthComponentType);
	depthComponent->depth = depth;
}

void UIFactory::SetPanel(int entityId, int panelId)
{
	auto widgetComponent = this->game->entityManager->GetComponent<UIWidgetComponent>(entityId, UIWidgetComponent::UIWidgetComponentType);
	widgetComponent->panel = panelId;
}

void UIFactory::FinishUIWidget(int entityId)
{
	auto entityInitializedEvent = std::shared_ptr<Events::EntityInitializedEvent>(new Events::EntityInitializedEvent(entityId));
	this->game->eventManager->QueueEvent(entityInitializedEvent);
}<commit_msg>ADDED: UI - Panels can be anchored.<commit_after>#include "pch.h"
#include "UIFactory.h"

#include "Components\BoundsComponent.h"
#include "Components\ColorComponent.h"
#include "Components\DepthComponent.h"
#include "Components\FontComponent.h"
#include "Components\ScreenPositionComponent.h"
#include "Components\SpriteComponent.h"
#include "Components\TextAlignmentComponent.h"
#include "Components\TextComponent.h"
#include "Components\UIPanelComponent.h"
#include "Components\UIWidgetComponent.h"

#include "Events\EntityInitializedEvent.h"

#include "Math\Vector2F.h"

using namespace PinnedDownClient::Components;
using namespace PinnedDownClient::Events;
using namespace PinnedDownClient::Math;
using namespace PinnedDownClient::Systems::UI;

UIFactory::UIFactory(std::shared_ptr<GameInfrastructure> game)
{
	this->game = game;
}

int UIFactory::CreateLabel(std::wstring text)
{
	int entityId = this->game->entityManager->CreateEntity();

	auto boundsComponent = std::make_shared<BoundsComponent>();
	this->game->entityManager->AddComponent(entityId, boundsComponent);

	auto colorComponent = std::make_shared<ColorComponent>();
	colorComponent->color = D2D1::ColorF(D2D1::ColorF::White);
	this->game->entityManager->AddComponent(entityId, colorComponent);

	auto depthComponent = std::make_shared<DepthComponent>();
	this->game->entityManager->AddComponent(entityId, depthComponent);

	auto fontComponent = std::make_shared<FontComponent>();
	this->game->entityManager->AddComponent(entityId, fontComponent);

	auto screenPositionComponent = std::make_shared<ScreenPositionComponent>();
	this->game->entityManager->AddComponent(entityId, screenPositionComponent);

	auto textComponent = std::make_shared<TextComponent>();
	textComponent->text = text;
	this->game->entityManager->AddComponent(entityId, textComponent);

	auto textAlignmentComponent = std::make_shared<TextAlignmentComponent>();
	this->game->entityManager->AddComponent(entityId, textAlignmentComponent);

	auto anchorComponent = std::make_shared<UIAnchorComponent>();
	this->game->entityManager->AddComponent(entityId, anchorComponent);

	auto widgetComponent = std::make_shared<UIWidgetComponent>();
	this->game->entityManager->AddComponent(entityId, widgetComponent);

	return entityId;
}

int UIFactory::CreatePanel()
{
	int entityId = this->game->entityManager->CreateEntity();

	auto panelComponent = std::make_shared<UIPanelComponent>();
	this->game->entityManager->AddComponent(entityId, panelComponent);

	auto boundsComponent = std::make_shared<BoundsComponent>();
	this->game->entityManager->AddComponent(entityId, boundsComponent);

	auto screenPositionComponent = std::make_shared<ScreenPositionComponent>();
	this->game->entityManager->AddComponent(entityId, screenPositionComponent);

	auto depthComponent = std::make_shared<DepthComponent>();
	this->game->entityManager->AddComponent(entityId, depthComponent);

	auto anchorComponent = std::make_shared<UIAnchorComponent>();
	this->game->entityManager->AddComponent(entityId, anchorComponent);

	return entityId;
}

int UIFactory::CreateSprite(std::wstring spriteName)
{
	int entityId = this->game->entityManager->CreateEntity();

	auto screenPositionComponent = std::make_shared<ScreenPositionComponent>();
	this->game->entityManager->AddComponent(entityId, screenPositionComponent);

	auto depthComponent = std::make_shared<DepthComponent>();
	this->game->entityManager->AddComponent(entityId, depthComponent);

	auto spriteComponent = std::make_shared<SpriteComponent>();
	spriteComponent->sprite = this->game->resourceManager->GetResource<BitmapResourceHandle>(spriteName.c_str());
	this->game->entityManager->AddComponent(entityId, spriteComponent);

	auto boundsComponent = std::make_shared<BoundsComponent>();
	auto bitmapSize = spriteComponent->sprite->bitmap->GetPixelSize();
	boundsComponent->bounds = Vector2F(static_cast<float>(bitmapSize.width), static_cast<float>(bitmapSize.height));
	this->game->entityManager->AddComponent(entityId, boundsComponent);

	auto anchorComponent = std::make_shared<UIAnchorComponent>();
	this->game->entityManager->AddComponent(entityId, anchorComponent);

	auto widgetComponent = std::make_shared<UIWidgetComponent>();
	this->game->entityManager->AddComponent(entityId, widgetComponent);

	return entityId;
}

void UIFactory::SetAnchor(int entityId, VerticalAnchor top, HorizontalAnchor left)
{
	auto anchorComponent = this->game->entityManager->GetComponent<UIAnchorComponent>(entityId, UIAnchorComponent::UIAnchorComponentType);
	anchorComponent->top = top;
	anchorComponent->left = left;
}

void UIFactory::SetAnchor(int entityId, VerticalAnchor top, HorizontalAnchor left, int anchorTarget)
{
	auto anchorComponent = this->game->entityManager->GetComponent<UIAnchorComponent>(entityId, UIAnchorComponent::UIAnchorComponentType);
	anchorComponent->top = top;
	anchorComponent->left = left;
	anchorComponent->target = anchorTarget;
}

void UIFactory::SetDepth(int entityId, int depth)
{
	auto depthComponent = this->game->entityManager->GetComponent<DepthComponent>(entityId, DepthComponent::DepthComponentType);
	depthComponent->depth = depth;
}

void UIFactory::SetPanel(int entityId, int panelId)
{
	auto widgetComponent = this->game->entityManager->GetComponent<UIWidgetComponent>(entityId, UIWidgetComponent::UIWidgetComponentType);
	widgetComponent->panel = panelId;
}

void UIFactory::FinishUIWidget(int entityId)
{
	auto entityInitializedEvent = std::shared_ptr<Events::EntityInitializedEvent>(new Events::EntityInitializedEvent(entityId));
	this->game->eventManager->QueueEvent(entityInitializedEvent);
}<|endoftext|>


<commit_before>#include <pthread.h>

#include <cassert>
#include <iostream>
#include <vector>
#include <algorithm>

#include "locks.hh"

template <typename T>
class Generator {
public:
    virtual ~Generator() {}
    virtual T operator()() = 0;
};

class CountDownLatch {
public:

    CountDownLatch(int n=1) : count(n) {}

    void decr(void) {
        LockHolder lh(so);
        --count;
        so.notify();
    }

    void wait(void) {
        LockHolder lh(so);
        while (count > 0) {
            so.wait();
        }
    }

private:
    int count;
    SyncObject so;

    DISALLOW_COPY_AND_ASSIGN(CountDownLatch);
};

template <typename T> class SyncTestThread;

template <typename T>
static void *launch_sync_test_thread(void *arg) {
    SyncTestThread<T> *stt = static_cast<SyncTestThread<T>*>(arg);
    stt->run();
    return stt;
}

template <typename T>
class SyncTestThread {
public:

    SyncTestThread(CountDownLatch *s, CountDownLatch *p, Generator<T> *testGen) :
        startingLine(s), pistol(p), gen(testGen) {}

    SyncTestThread(const SyncTestThread &other) :
        startingLine(other.startingLine),
        pistol(other.pistol),
        gen(other.gen) {}

    void start(void) {
        if(pthread_create(&thread, NULL, launch_sync_test_thread<T>, this) != 0) {
            throw std::runtime_error("Error initializing dispatcher thread");
        }
    }

    void run(void) {
        startingLine->decr();
        pistol->wait();
        result = (*gen)();
    }

    void join(void) {
        if (pthread_join(thread, NULL) != 0) {
            throw std::runtime_error("Failed to join.");
        }
    }

    const T getResult(void) const { return result; };

private:
    CountDownLatch *startingLine;
    CountDownLatch *pistol;
    Generator<T>   *gen;

    T         result;
    pthread_t thread;
};

template <typename T>
static void starter(SyncTestThread<T> &t) { t.start(); }

template <typename T>
static void waiter(SyncTestThread<T> &t) { t.join(); }

template <typename T>
std::vector<T> getCompletedThreads(T n, Generator<T> *gen) {
    CountDownLatch startingLine(n), pistol(1);

    SyncTestThread<T> proto(&startingLine, &pistol, gen);
    std::vector<SyncTestThread<T> > threads(n, proto);
    std::for_each(threads.begin(), threads.end(), starter<T>);

    startingLine.wait();
    pistol.decr();

    std::for_each(threads.begin(), threads.end(), waiter<T>);

    std::vector<T> results;
    typename std::vector<SyncTestThread<T> >::iterator it;
    for (it = threads.begin(); it != threads.end(); ++it) {
        results.push_back(it->getResult());
    }

    return results;
}
<commit_msg>Fix argument type bug in thread tester.<commit_after>#include <pthread.h>

#include <cassert>
#include <iostream>
#include <vector>
#include <algorithm>

#include "locks.hh"

template <typename T>
class Generator {
public:
    virtual ~Generator() {}
    virtual T operator()() = 0;
};

class CountDownLatch {
public:

    CountDownLatch(int n=1) : count(n) {}

    void decr(void) {
        LockHolder lh(so);
        --count;
        so.notify();
    }

    void wait(void) {
        LockHolder lh(so);
        while (count > 0) {
            so.wait();
        }
    }

private:
    int count;
    SyncObject so;

    DISALLOW_COPY_AND_ASSIGN(CountDownLatch);
};

template <typename T> class SyncTestThread;

template <typename T>
static void *launch_sync_test_thread(void *arg) {
    SyncTestThread<T> *stt = static_cast<SyncTestThread<T>*>(arg);
    stt->run();
    return stt;
}

template <typename T>
class SyncTestThread {
public:

    SyncTestThread(CountDownLatch *s, CountDownLatch *p, Generator<T> *testGen) :
        startingLine(s), pistol(p), gen(testGen) {}

    SyncTestThread(const SyncTestThread &other) :
        startingLine(other.startingLine),
        pistol(other.pistol),
        gen(other.gen) {}

    void start(void) {
        if(pthread_create(&thread, NULL, launch_sync_test_thread<T>, this) != 0) {
            throw std::runtime_error("Error initializing dispatcher thread");
        }
    }

    void run(void) {
        startingLine->decr();
        pistol->wait();
        result = (*gen)();
    }

    void join(void) {
        if (pthread_join(thread, NULL) != 0) {
            throw std::runtime_error("Failed to join.");
        }
    }

    const T getResult(void) const { return result; };

private:
    CountDownLatch *startingLine;
    CountDownLatch *pistol;
    Generator<T>   *gen;

    T         result;
    pthread_t thread;
};

template <typename T>
static void starter(SyncTestThread<T> &t) { t.start(); }

template <typename T>
static void waiter(SyncTestThread<T> &t) { t.join(); }

template <typename T>
std::vector<T> getCompletedThreads(size_t n, Generator<T> *gen) {
    CountDownLatch startingLine(n), pistol(1);

    SyncTestThread<T> proto(&startingLine, &pistol, gen);
    std::vector<SyncTestThread<T> > threads(n, proto);
    assert(threads.size() == n);
    std::for_each(threads.begin(), threads.end(), starter<T>);

    startingLine.wait();
    pistol.decr();

    std::for_each(threads.begin(), threads.end(), waiter<T>);

    std::vector<T> results;
    typename std::vector<SyncTestThread<T> >::iterator it;
    for (it = threads.begin(); it != threads.end(); ++it) {
        results.push_back(it->getResult());
    }

    return results;
}
<|endoftext|>


<commit_before>/*
** File Name:	variadic.hpp
** Author:	Aditya Ramesh
** Date:	08/12/2013
** Contact:	_@adityaramesh.com
*/

#ifndef Z9DCE86DF_558B_497F_B6CC_4DCDFD6070FC
#define Z9DCE86DF_558B_497F_B6CC_4DCDFD6070FC

#include <cassert>
#include <cstring>
#include <ios>
#include <iostream>
#include <sstream>
#include <string>
#include <ccbase/platform/attribute.hpp>

namespace cc
{

namespace internal
{

/*
** We do not use the `isdigit` function from `<cctype>`, because the only
** characters that we treat as digits for argument indexing purposes are those
** from 0--9.
*/

template <class T>
static CC_ALWAYS_INLINE bool
is_digit(const T t)
noexcept
{
	return T{'0'} <= t && t <= T{'9'};
}

template <class T, class Traits = std::char_traits<T>>
static CC_ALWAYS_INLINE void
write_arg(std::basic_ostream<T, Traits>& os, const std::size_t n)
noexcept
{
	os.setstate(std::ios::failbit);
}

template <class T, class Traits = std::char_traits<T>, class U, class... Us>
static CC_ALWAYS_INLINE void
write_arg(
	std::basic_ostream<T, Traits>& os,
	const std::size_t n,
	const U arg,
	const Us... args
) noexcept
{
	if (n > 0) {
		return write_arg(os, n - 1, args...);
	}
	os << arg;
}

}

template <class T, class Traits = std::char_traits<T>, class... Us>
void write(std::basic_ostream<T, Traits>& os, const T* s, const Us... args)
noexcept
{
	using internal::is_digit;
	using internal::write_arg;

	auto f = s;
	auto l = s;

	// We disallow printing the null string.
	assert(l != nullptr && "Format string is null.");
	// We disallow printing the empty string.
	assert(*l != 0 && "Format string is empty.");

	do {
		if (*l == T{'$'}) {
			if (*(l + 1) != T{'$'}) {
				os.write(f, l - f);
				++l;
				assert(is_digit(*l) && "Expected digit after $.");

				std::size_t i = 0;
				do {
					i = 10 * i + (*l++ - T{'0'});
				}
				while (is_digit(*l));

				write_arg(os, i, args...);
				f = l;
			}
			else {
				++l;
				assert(*l == T{'$'} && "Unexpected token after $.");
				os.write(f, l - f);
				++l;
				f = l;
			}
		}
		else {
			++l;
		}
	}
	while (*l != 0);
	os.write(f, l - f);
}

template <class T, class Traits = std::char_traits<T>, class... Us>
void writeln(std::basic_ostream<T, Traits>& os, const T* s, const Us... args)
noexcept
{
	write(os, s, args...);
	os << std::endl;
}

template <class T, class... Us>
CC_ALWAYS_INLINE void
print(const T* s, const Us... args)
noexcept
{
	write(std::cout, s, args...);
}

template <class T, class... Us>
CC_ALWAYS_INLINE void
println(const T* s, const Us... args)
noexcept
{
	writeln(std::cout, s, args...);
}

template <class T, class... Us>
CC_ALWAYS_INLINE auto
format(const T* s, const Us... args) noexcept ->
std::basic_string<T, std::char_traits<T>>
{
	std::basic_ostringstream<T, std::char_traits<T>> ss;
	write(ss, s, args...);
	return ss.str();
}

template <class T, class... Us>
CC_ALWAYS_INLINE auto
formatln(const T* s, const Us... args) noexcept ->
std::basic_string<T, std::char_traits<T>>
{
	std::basic_ostringstream<T, std::char_traits<T>> ss;
	writeln(ss, s, args...);
	return ss.str();
}

}

#endif
<commit_msg>Added err and errln convenience functions.<commit_after>/*
** File Name:	variadic.hpp
** Author:	Aditya Ramesh
** Date:	08/12/2013
** Contact:	_@adityaramesh.com
*/

#ifndef Z9DCE86DF_558B_497F_B6CC_4DCDFD6070FC
#define Z9DCE86DF_558B_497F_B6CC_4DCDFD6070FC

#include <cassert>
#include <cstring>
#include <ios>
#include <iostream>
#include <sstream>
#include <string>
#include <ccbase/platform/attribute.hpp>

namespace cc
{

namespace internal
{

/*
** We do not use the `isdigit` function from `<cctype>`, because the only
** characters that we treat as digits for argument indexing purposes are those
** from 0--9.
*/

template <class T>
static CC_ALWAYS_INLINE bool
is_digit(const T t)
noexcept
{
	return T{'0'} <= t && t <= T{'9'};
}

template <class T, class Traits = std::char_traits<T>>
static CC_ALWAYS_INLINE void
write_arg(std::basic_ostream<T, Traits>& os, const std::size_t n)
noexcept
{
	os.setstate(std::ios::failbit);
}

template <class T, class Traits = std::char_traits<T>, class U, class... Us>
static CC_ALWAYS_INLINE void
write_arg(
	std::basic_ostream<T, Traits>& os,
	const std::size_t n,
	const U arg,
	const Us... args
) noexcept
{
	if (n > 0) {
		return write_arg(os, n - 1, args...);
	}
	os << arg;
}

}

template <class T, class Traits = std::char_traits<T>, class... Us>
void write(std::basic_ostream<T, Traits>& os, const T* s, const Us... args)
noexcept
{
	using internal::is_digit;
	using internal::write_arg;

	auto f = s;
	auto l = s;

	// We disallow printing the null string.
	assert(l != nullptr && "Format string is null.");
	// We disallow printing the empty string.
	assert(*l != 0 && "Format string is empty.");

	do {
		if (*l == T{'$'}) {
			if (*(l + 1) != T{'$'}) {
				os.write(f, l - f);
				++l;
				assert(is_digit(*l) && "Expected digit after $.");

				std::size_t i = 0;
				do {
					i = 10 * i + (*l++ - T{'0'});
				}
				while (is_digit(*l));

				write_arg(os, i, args...);
				f = l;
			}
			else {
				++l;
				assert(*l == T{'$'} && "Unexpected token after $.");
				os.write(f, l - f);
				++l;
				f = l;
			}
		}
		else {
			++l;
		}
	}
	while (*l != 0);
	os.write(f, l - f);
}

template <class T, class Traits = std::char_traits<T>, class... Us>
void writeln(std::basic_ostream<T, Traits>& os, const T* s, const Us... args)
noexcept
{
	write(os, s, args...);
	os << std::endl;
}

template <class T, class... Us>
CC_ALWAYS_INLINE void
print(const T* s, const Us... args)
noexcept
{
	write(std::cout, s, args...);
}

template <class T, class... Us>
CC_ALWAYS_INLINE void
println(const T* s, const Us... args)
noexcept
{
	writeln(std::cout, s, args...);
}

template <class T, class... Us>
CC_ALWAYS_INLINE void
err(const T* s, const Us... args)
noexcept
{
	write(std::cerr, s, args...);
}

template <class T, class... Us>
CC_ALWAYS_INLINE void
errln(const T* s, const Us... args)
noexcept
{
	writeln(std::cerr, s, args...);
}

template <class T, class... Us>
CC_ALWAYS_INLINE auto
format(const T* s, const Us... args) noexcept ->
std::basic_string<T, std::char_traits<T>>
{
	std::basic_ostringstream<T, std::char_traits<T>> ss;
	write(ss, s, args...);
	return ss.str();
}

template <class T, class... Us>
CC_ALWAYS_INLINE auto
formatln(const T* s, const Us... args) noexcept ->
std::basic_string<T, std::char_traits<T>>
{
	std::basic_ostringstream<T, std::char_traits<T>> ss;
	writeln(ss, s, args...);
	return ss.str();
}

}

#endif
<|endoftext|>


<commit_before>// buddyicontask.cpp

// Copyright (C)  2005  Matt Rogers <mattr@kde.org>

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// 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., 51 Franklin Street, Fifth Floor, Boston, MA
// 02110-1301  USA

#include "buddyicontask.h"

#include <qstring.h>
#include <kdebug.h>
#include "buffer.h"
#include "connection.h"
#include "transfer.h"
#include "oscarutils.h"
#include <typeinfo>

BuddyIconTask::BuddyIconTask( Task* parent )
	:Task( parent )
{
	m_seq = 0;
	m_refNum = -1;
	m_iconLength = 0;
	m_iconType = 0x0001;
	m_hashType = 0;
}

void BuddyIconTask::uploadIcon( Oscar::WORD length, const QByteArray& data )
{
	m_iconLength = length;
	m_icon = data;
	m_action = Send;
}

void BuddyIconTask::requestIconFor( const QString& user )
{
	m_user = user;
	m_action = Receive;
}

void BuddyIconTask::setHash( const QByteArray& md5Hash )
{
	m_hash = md5Hash;
}

void BuddyIconTask::setIconType( Oscar::WORD iconType )
{
	m_iconType = iconType;
}

void BuddyIconTask::setHashType( Oscar::BYTE type )
{
	m_hashType = type;
}

void BuddyIconTask::onGo()
{
	if ( m_action == Send && m_icon.count() == 0 )
		return;

	if ( m_action == Receive && ( m_user.isEmpty() || m_hash.count() == 0 ) )
		return;

	if ( m_action == Receive )
	{
		if ( client()->isIcq() )
			sendICQBuddyIconRequest();
		else
			sendAIMBuddyIconRequest();
	}
	else
		sendIcon();
}

bool BuddyIconTask::forMe( const Transfer* transfer ) const
{
	const SnacTransfer* st = dynamic_cast<const SnacTransfer*>( transfer );
	if ( !st )
		return false;

	if ( st->snacRequest() != m_seq )
	{
		kDebug(OSCAR_RAW_DEBUG) << "sequences don't match";
		return false;
	}

	if ( st->snacService() == 0x0010 )
	{
		switch( st->snacSubtype() )
		{
		case 0x0003:
		case 0x0005:
		case 0x0007:
			return true;
			break;
		default:
			return false;
			break;
		}
	}

	return false;
}

bool BuddyIconTask::take( Transfer* transfer )
{
	if ( !forMe( transfer ) )
		return false;

	SnacTransfer* st = dynamic_cast<SnacTransfer*>( transfer );
	if ( !st )
		return false;

	setTransfer( transfer );
	if ( st->snacSubtype() == 0x0003 )
		handleUploadResponse();
	else if ( st->snacSubtype() == 0x0005 )
		handleAIMBuddyIconResponse();
	else
		handleICQBuddyIconResponse();

	setSuccess( 0, QString() );
	setTransfer( 0 );
	return true;
}

void BuddyIconTask::sendIcon()
{
	kDebug(OSCAR_RAW_DEBUG) << "icon length: " << m_iconLength;
	FLAP f = { 0x02, 0, 0 };
	m_seq = client()->snacSequence();
	SNAC s = { 0x0010, 0x0002, 0x0000, m_seq };
	Buffer* b = new Buffer;
	b->addWord( m_iconType ); //gaim hard codes it, so will we
	b->addWord( m_iconLength );
	b->addString( m_icon );
	Transfer* t = createTransfer( f, s, b );
	send( t );
}

void BuddyIconTask::handleUploadResponse()
{
	kDebug(OSCAR_RAW_DEBUG) << "server acked icon upload";
	Buffer* b = transfer()->buffer();
	b->skipBytes( 4 );
	Oscar::BYTE iconHashSize = b->getByte();
	QByteArray hash( b->getBlock( iconHashSize ) );
	//check the hash
	kDebug(OSCAR_RAW_DEBUG) << "hash " << hash;
	setSuccess( 0, QString() );
}

void BuddyIconTask::sendAIMBuddyIconRequest()
{
	kDebug(OSCAR_RAW_DEBUG) << "requesting buddy icon for " << m_user;
	FLAP f = { 0x02, 0, 0 };
	m_seq = client()->snacSequence();
	SNAC s = { 0x0010, 0x0004, 0x0000, m_seq };
	Buffer* b = new Buffer;

	b->addBUIN( m_user.toLatin1() ); //TODO: check encoding
	b->addByte( 0x01 );
	b->addWord( m_iconType );
	b->addByte( m_hashType );
	b->addByte( m_hash.size() ); //MD5 Hash Size
	b->addString( m_hash ); //MD5 Hash
	Transfer* t = createTransfer( f, s, b );
	send( t );
}

void BuddyIconTask::handleAIMBuddyIconResponse()
{
	Buffer* b = transfer()->buffer();
	QString user = b->getBUIN();
	kDebug(OSCAR_RAW_DEBUG) << "Receiving buddy icon for " << user;
	b->skipBytes(2); //unknown field. not used
	Oscar::BYTE iconType = b->getByte();
	Q_UNUSED( iconType );
	Oscar::BYTE hashSize = b->getByte();
	QByteArray iconHash( b->getBlock(hashSize) );
	Oscar::WORD iconSize = b->getWord();
	QByteArray icon( b->getBlock(iconSize) );
	emit haveIcon( user, icon );
	setSuccess( 0, QString() );
}

void BuddyIconTask::sendICQBuddyIconRequest()
{
	kDebug(OSCAR_RAW_DEBUG) << "requesting buddy icon for " << m_user;
	FLAP f = { 0x02, 0, 0 };
	m_seq = client()->snacSequence();
	SNAC s = { 0x0010, 0x0006, 0x0000, m_seq };
	Buffer* b = new Buffer;

	b->addBUIN( m_user.toLatin1() ); //TODO: check encoding
	b->addByte( 0x01 );
	b->addWord( m_iconType );
	b->addByte( m_hashType );
	b->addByte( m_hash.size() ); //MD5 Hash Size
	b->addString( m_hash ); //MD5 Hash
	Transfer* t = createTransfer( f, s, b );
	send( t );
}

void BuddyIconTask::handleICQBuddyIconResponse()
{
	Buffer* b = transfer()->buffer();
	QString user = b->getBUIN();
	kDebug(OSCAR_RAW_DEBUG) << "Receiving buddy icon for " << user;

	b->skipBytes(2); //not used
	Oscar::BYTE iconType = b->getByte();
	Q_UNUSED( iconType );

	Oscar::BYTE hashSize = b->getByte();
	QByteArray iconHash( b->getBlock(hashSize) );

	b->skipBytes(1); //not used
	b->skipBytes(2); //not used
	Oscar::BYTE iconType2 = b->getByte();
	Q_UNUSED( iconType2 );

	Oscar::BYTE hashSize2 = b->getByte();
	QByteArray iconHash2( b->getBlock(hashSize2) );

	Oscar::WORD iconSize = b->getWord();
	QByteArray icon( b->getBlock(iconSize) );

	emit haveIcon( user, icon );
	setSuccess( 0, QString() );
}

#include "buddyicontask.moc"

<commit_msg>Print hash as hex string.<commit_after>// buddyicontask.cpp

// Copyright (C)  2005  Matt Rogers <mattr@kde.org>

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// 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., 51 Franklin Street, Fifth Floor, Boston, MA
// 02110-1301  USA

#include "buddyicontask.h"

#include <qstring.h>
#include <kdebug.h>
#include "buffer.h"
#include "connection.h"
#include "transfer.h"
#include "oscarutils.h"
#include <typeinfo>

BuddyIconTask::BuddyIconTask( Task* parent )
	:Task( parent )
{
	m_seq = 0;
	m_refNum = -1;
	m_iconLength = 0;
	m_iconType = 0x0001;
	m_hashType = 0;
}

void BuddyIconTask::uploadIcon( Oscar::WORD length, const QByteArray& data )
{
	m_iconLength = length;
	m_icon = data;
	m_action = Send;
}

void BuddyIconTask::requestIconFor( const QString& user )
{
	m_user = user;
	m_action = Receive;
}

void BuddyIconTask::setHash( const QByteArray& md5Hash )
{
	m_hash = md5Hash;
}

void BuddyIconTask::setIconType( Oscar::WORD iconType )
{
	m_iconType = iconType;
}

void BuddyIconTask::setHashType( Oscar::BYTE type )
{
	m_hashType = type;
}

void BuddyIconTask::onGo()
{
	if ( m_action == Send && m_icon.count() == 0 )
		return;

	if ( m_action == Receive && ( m_user.isEmpty() || m_hash.count() == 0 ) )
		return;

	if ( m_action == Receive )
	{
		if ( client()->isIcq() )
			sendICQBuddyIconRequest();
		else
			sendAIMBuddyIconRequest();
	}
	else
		sendIcon();
}

bool BuddyIconTask::forMe( const Transfer* transfer ) const
{
	const SnacTransfer* st = dynamic_cast<const SnacTransfer*>( transfer );
	if ( !st )
		return false;

	if ( st->snacRequest() != m_seq )
	{
		kDebug(OSCAR_RAW_DEBUG) << "sequences don't match";
		return false;
	}

	if ( st->snacService() == 0x0010 )
	{
		switch( st->snacSubtype() )
		{
		case 0x0003:
		case 0x0005:
		case 0x0007:
			return true;
			break;
		default:
			return false;
			break;
		}
	}

	return false;
}

bool BuddyIconTask::take( Transfer* transfer )
{
	if ( !forMe( transfer ) )
		return false;

	SnacTransfer* st = dynamic_cast<SnacTransfer*>( transfer );
	if ( !st )
		return false;

	setTransfer( transfer );
	if ( st->snacSubtype() == 0x0003 )
		handleUploadResponse();
	else if ( st->snacSubtype() == 0x0005 )
		handleAIMBuddyIconResponse();
	else
		handleICQBuddyIconResponse();

	setSuccess( 0, QString() );
	setTransfer( 0 );
	return true;
}

void BuddyIconTask::sendIcon()
{
	kDebug(OSCAR_RAW_DEBUG) << "icon length: " << m_iconLength;
	FLAP f = { 0x02, 0, 0 };
	m_seq = client()->snacSequence();
	SNAC s = { 0x0010, 0x0002, 0x0000, m_seq };
	Buffer* b = new Buffer;
	b->addWord( m_iconType ); //gaim hard codes it, so will we
	b->addWord( m_iconLength );
	b->addString( m_icon );
	Transfer* t = createTransfer( f, s, b );
	send( t );
}

void BuddyIconTask::handleUploadResponse()
{
	kDebug(OSCAR_RAW_DEBUG) << "server acked icon upload";
	Buffer* b = transfer()->buffer();
	b->skipBytes( 4 );
	Oscar::BYTE iconHashSize = b->getByte();
	QByteArray hash( b->getBlock( iconHashSize ) );
	//check the hash
	kDebug(OSCAR_RAW_DEBUG) << "hash " << hash.toHex();
	setSuccess( 0, QString() );
}

void BuddyIconTask::sendAIMBuddyIconRequest()
{
	kDebug(OSCAR_RAW_DEBUG) << "requesting buddy icon for " << m_user;
	FLAP f = { 0x02, 0, 0 };
	m_seq = client()->snacSequence();
	SNAC s = { 0x0010, 0x0004, 0x0000, m_seq };
	Buffer* b = new Buffer;

	b->addBUIN( m_user.toLatin1() ); //TODO: check encoding
	b->addByte( 0x01 );
	b->addWord( m_iconType );
	b->addByte( m_hashType );
	b->addByte( m_hash.size() ); //MD5 Hash Size
	b->addString( m_hash ); //MD5 Hash
	Transfer* t = createTransfer( f, s, b );
	send( t );
}

void BuddyIconTask::handleAIMBuddyIconResponse()
{
	Buffer* b = transfer()->buffer();
	QString user = b->getBUIN();
	kDebug(OSCAR_RAW_DEBUG) << "Receiving buddy icon for " << user;
	b->skipBytes(2); //unknown field. not used
	Oscar::BYTE iconType = b->getByte();
	Q_UNUSED( iconType );
	Oscar::BYTE hashSize = b->getByte();
	QByteArray iconHash( b->getBlock(hashSize) );
	Oscar::WORD iconSize = b->getWord();
	QByteArray icon( b->getBlock(iconSize) );
	emit haveIcon( user, icon );
	setSuccess( 0, QString() );
}

void BuddyIconTask::sendICQBuddyIconRequest()
{
	kDebug(OSCAR_RAW_DEBUG) << "requesting buddy icon for " << m_user;
	FLAP f = { 0x02, 0, 0 };
	m_seq = client()->snacSequence();
	SNAC s = { 0x0010, 0x0006, 0x0000, m_seq };
	Buffer* b = new Buffer;

	b->addBUIN( m_user.toLatin1() ); //TODO: check encoding
	b->addByte( 0x01 );
	b->addWord( m_iconType );
	b->addByte( m_hashType );
	b->addByte( m_hash.size() ); //MD5 Hash Size
	b->addString( m_hash ); //MD5 Hash
	Transfer* t = createTransfer( f, s, b );
	send( t );
}

void BuddyIconTask::handleICQBuddyIconResponse()
{
	Buffer* b = transfer()->buffer();
	QString user = b->getBUIN();
	kDebug(OSCAR_RAW_DEBUG) << "Receiving buddy icon for " << user;

	b->skipBytes(2); //not used
	Oscar::BYTE iconType = b->getByte();
	Q_UNUSED( iconType );

	Oscar::BYTE hashSize = b->getByte();
	QByteArray iconHash( b->getBlock(hashSize) );

	b->skipBytes(1); //not used
	b->skipBytes(2); //not used
	Oscar::BYTE iconType2 = b->getByte();
	Q_UNUSED( iconType2 );

	Oscar::BYTE hashSize2 = b->getByte();
	QByteArray iconHash2( b->getBlock(hashSize2) );

	Oscar::WORD iconSize = b->getWord();
	QByteArray icon( b->getBlock(iconSize) );

	emit haveIcon( user, icon );
	setSuccess( 0, QString() );
}

#include "buddyicontask.moc"

<|endoftext|>


<commit_before>#ifndef _ANSICSI_HH_
#define _ANSICSI_HH_ CAN_HAS

#define CSI_CUP    'A'
#define CSI_CUD    'B'
#define CSI_CUF    'C'
#define CSI_CUB    'D'
#define CSI_CNL    'E'
#define CSI_CPL    'F'
#define CSI_CHA    'G'
// #define CSI_CUP  /* XXX: Better solution, please */
#define CSI_ED     'J'
#define CSI_EL     'K'
#define CSI_SU     'S'
#define CSI_SD     'T'
#define CSI_HVP    'f'
#define CSI_SGR    'm'
#define CSI_DSR    'n'
#define CSI_SCP    's'
#define CSI_RCP    'u'

#endif
<commit_msg>Fixing up some kruft. I messed up the CSI stuff.<commit_after>#ifndef _ANSICSI_HH_
#define _ANSICSI_HH_ CAN_HAS

#define CSI_CUU    'A'
#define CSI_CUD    'B'
#define CSI_CUF    'C'
#define CSI_CUB    'D'
#define CSI_CNL    'E'
#define CSI_CPL    'F'
#define CSI_CHA    'G'
#define CSI_CUP    'H'
#define CSI_ED     'J'
#define CSI_EL     'K'
#define CSI_SU     'S'
#define CSI_SD     'T'
#define CSI_HVP    'f'
#define CSI_SGR    'm'
#define CSI_DSR    'n'
#define CSI_SCP    's'
#define CSI_RCP    'u'

#endif
<|endoftext|>


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

#include <iosfwd>

namespace deepstream
{
	enum class Sender;
	class Message;

	namespace client
	{
		enum class State
		{
			ERROR,
			AWAIT_CONNECTION,
			CHALLENGING,
			CHALLENGING_WAIT,
			AWAIT_AUTHENTICATION,
			AUTHENTICATING,
			CONNECTED,
			DISCONNECTED
		};

		std::ostream& operator<<(std::ostream&, State);

		State transition(State s, const Message& message, Sender sender);
	}
}

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

#include <iosfwd>

namespace deepstream
{
	enum class Sender;
	struct Message;

	namespace client
	{
		enum class State
		{
			ERROR,
			AWAIT_CONNECTION,
			CHALLENGING,
			CHALLENGING_WAIT,
			AWAIT_AUTHENTICATION,
			AUTHENTICATING,
			CONNECTED,
			DISCONNECTED
		};

		std::ostream& operator<<(std::ostream&, State);

		State transition(State s, const Message& message, Sender sender);
	}
}

#endif
<|endoftext|>


<commit_before>#include "lisp_exp.h"

#include <QString>
#include <QRegExp>
#include <QList>
#include <QChar>

// convert given string to list of tokens
QList<QString> tokenize(const QString & str) {
    QList<QString> tokens;
    int i = 0;
    while (i < str.size()) {
        if (str.at(i).isSpace()) {
            ++i;
        } else if (str.at(i) == '(' || str.at(i) == ')') {
            tokens.push_back(str.at(i) == '(' ? "(" : ")");
            i++;
        } else {
            int j = i;
            while (j < str.size() && !str.at(j).isSpace() && str.at(j) != '(' && str.at(j) != ')') {
                j++;
            }
            if (j < str.size()) {
                tokens.push_back(str.mid(i, j-i));
            }
            i = j;
        }
    }
    return tokens;
}

lisp_exp parse(QList<QString> & tokens) {
    if (tokens.isEmpty()) {
        return lisp_exp(); // invalid
    }
    QString token = tokens.takeFirst();
    if (token == "(") {
        QList<lisp_exp> cells;
        while (tokens.front() != ")") {
            lisp_exp cell = parse(tokens);
            cells.push_back(cell);
        }
        tokens.pop_front();
        return lisp_exp(cells);
    } else {
        return lisp_exp(token);
    }
}

lisp_exp lisp_exp::parseString(QString str) {
    QList<QString> tokens = tokenize(str);
    lisp_exp exp = parse(tokens);
    return exp;
}

lisp_exp::lisp_exp() {
    m_valid = false;
    m_value = "";
    m_elements = QList<lisp_exp>();
}

lisp_exp::lisp_exp(QList<lisp_exp> cells) {
    m_valid = true;
    m_value = "";
    m_elements = cells;
}

lisp_exp::lisp_exp(QString token) {
    m_valid = true;
    m_value = token;
    m_elements = QList<lisp_exp>();
}

bool lisp_exp::isValid() const {
    return m_valid;
}

bool lisp_exp::isLeaf() const {
    return !m_value.isEmpty();
}

QString lisp_exp::value() const {
    return m_value;
}

int lisp_exp::size() const {
    return m_elements.size();
}

lisp_exp lisp_exp::element(int i) const {
    return m_elements[i];
}

bool lisp_exp::operator==(const lisp_exp& other) const {
    if (!m_valid && !other.m_valid) {
        return true;
    }
    if (isLeaf() && other.isLeaf()) {
        return (m_value == other.m_value);
    }
    if (!isLeaf() && !other.isLeaf()) {
        return (m_elements == other.m_elements);
    }
    return false;
}
<commit_msg>Fix failing case: list_exp handles unclosed parentheses<commit_after>#include "lisp_exp.h"

#include <QString>
#include <QRegExp>
#include <QList>
#include <QChar>

// convert given string to list of tokens
QList<QString> tokenize(const QString & str) {
    QList<QString> tokens;
    int i = 0;
    while (i < str.size()) {
        if (str.at(i).isSpace()) {
            ++i;
        } else if (str.at(i) == '(' || str.at(i) == ')') {
            tokens.push_back(str.at(i) == '(' ? "(" : ")");
            i++;
        } else {
            int j = i;
            while (j < str.size() && !str.at(j).isSpace() && str.at(j) != '(' && str.at(j) != ')') {
                j++;
            }
            if (j < str.size()) {
                tokens.push_back(str.mid(i, j-i));
            }
            i = j;
        }
    }
    return tokens;
}

lisp_exp parse(QList<QString> & tokens) {
    if (tokens.isEmpty()) {
        return lisp_exp(); // invalid
    }
    QString token = tokens.takeFirst();
    if (token == "(") {
        if (tokens.isEmpty()) {
            return lisp_exp(); // invalid
        }
        QList<lisp_exp> cells;
        while (tokens.front() != ")") {
            lisp_exp cell = parse(tokens);
            if (tokens.isEmpty()) {
                return lisp_exp(); // invalid
            }
            cells.push_back(cell);
        }
        tokens.pop_front();
        return lisp_exp(cells);
    } else {
        return lisp_exp(token);
    }
}

lisp_exp lisp_exp::parseString(QString str) {
    QList<QString> tokens = tokenize(str);
    lisp_exp exp = parse(tokens);
    return exp;
}

lisp_exp::lisp_exp() {
    m_valid = false;
    m_value = "";
    m_elements = QList<lisp_exp>();
}

lisp_exp::lisp_exp(QList<lisp_exp> cells) {
    m_valid = true;
    m_value = "";
    m_elements = cells;
}

lisp_exp::lisp_exp(QString token) {
    m_valid = true;
    m_value = token;
    m_elements = QList<lisp_exp>();
}

bool lisp_exp::isValid() const {
    return m_valid;
}

bool lisp_exp::isLeaf() const {
    return !m_value.isEmpty();
}

QString lisp_exp::value() const {
    return m_value;
}

int lisp_exp::size() const {
    return m_elements.size();
}

lisp_exp lisp_exp::element(int i) const {
    return m_elements[i];
}

bool lisp_exp::operator==(const lisp_exp& other) const {
    if (!m_valid && !other.m_valid) {
        return true;
    }
    if (isLeaf() && other.isLeaf()) {
        return (m_value == other.m_value);
    }
    if (!isLeaf() && !other.isLeaf()) {
        return (m_elements == other.m_elements);
    }
    return false;
}
<|endoftext|>


<commit_before>
#include "clay.hpp"

#include "llvm/PassManager.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/CodeGen/LinkAllAsmWriterComponents.h"
#include "llvm/CodeGen/LinkAllCodegenComponents.h"
#include "llvm/LinkAllVMCore.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/IRReader.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/StandardPasses.h"
#include "llvm/System/Host.h"
#include "llvm/System/Path.h"
#include "llvm/Target/TargetRegistry.h"

#include <iostream>
#include <cstring>

using namespace std;

static void addOptimizationPasses(llvm::PassManager &passes,
                                  llvm::FunctionPassManager &fpasses,
                                  unsigned optLevel)
{
    llvm::createStandardFunctionPasses(&fpasses, optLevel);

    llvm::Pass *inliningPass = 0;
    if (optLevel) {
        unsigned threshold = 200;
        if (optLevel > 2)
            threshold = 250;
        inliningPass = llvm::createFunctionInliningPass(threshold);
    } else {
        inliningPass = llvm::createAlwaysInlinerPass();
    }
    llvm::createStandardModulePasses(&passes,
                                     optLevel,
                                     /*OptimizeSize=*/ false,
                                     /*UnitAtATime=*/ false,
                                     /*UnrollLoops=*/ optLevel > 1,
                                     /*SimplifyLibCalls=*/ true,
                                     /*HaveExceptions=*/ true,
                                     inliningPass);
    llvm::createStandardLTOPasses(&passes,
                                  /*Internalize=*/ true,
                                  /*RunInliner=*/ true,
                                  /*VerifyEach=*/ false);
}

static void optimizeLLVM(llvm::Module *module)
{
    llvm::PassManager passes;

    string moduleDataLayout = module->getDataLayout();
    llvm::TargetData *td = new llvm::TargetData(moduleDataLayout);
    passes.add(td);

    llvm::FunctionPassManager fpasses(module);

    fpasses.add(new llvm::TargetData(*td));

    addOptimizationPasses(passes, fpasses, 3);

    fpasses.doInitialization();
    for (llvm::Module::iterator i = module->begin(), e = module->end();
         i != e; ++i)
    {
        fpasses.run(*i);
    }

    passes.add(llvm::createVerifierPass());

    passes.run(*module);
}

static void generateLLVMAssembly(llvm::Module *module,
                                 llvm::raw_ostream *out)
{
    llvm::PassManager passes;
    passes.add(llvm::createPrintModulePass(out));
    passes.run(*module);
}

static void generateNativeAssembly(llvm::Module *module,
                                   llvm::raw_ostream *out)
{
    llvm::Triple theTriple(module->getTargetTriple());
    string err;
    const llvm::Target *theTarget =
        llvm::TargetRegistry::lookupTarget(theTriple.getTriple(), err);
    assert(theTarget != NULL);
    llvm::TargetMachine *target =
        theTarget->createTargetMachine(theTriple.getTriple(), "");
    assert(target != NULL);

    llvm::CodeGenOpt::Level optLevel = llvm::CodeGenOpt::Aggressive;

    llvm::FunctionPassManager fpasses(module);

    fpasses.add(new llvm::TargetData(module));
    fpasses.add(llvm::createVerifierPass());

    target->setAsmVerbosityDefault(true);

    llvm::formatted_raw_ostream fout(*out);
    bool result =
        target->addPassesToEmitFile(fpasses,
                                    fout,
                                    llvm::TargetMachine::CGFT_AssemblyFile,
                                    optLevel);
    assert(!result);

    fpasses.doInitialization();
    for (llvm::Module::iterator i = module->begin(), e = module->end();
         i != e; ++i)
    {
        fpasses.run(*i);
    }
    fpasses.doFinalization();
}

static void usage()
{
    cerr << "usage: clay <options> <clayfile>\n";
    cerr << "options:\n";
    cerr << "  -o <file>       - specify output file\n";
    cerr << "  --unoptimized   - generate unoptimized code\n";
    cerr << "  --emit-llvm     - emit llvm assembly language\n";
    cerr << "  --emit-native   - emit native assembly language\n";
}

int main(int argc, char **argv) {
    if (argc == 1) {
        usage();
        return -1;
    }

    bool optimize = true;
    bool emitLLVM = false;
    bool emitNative = false;

    char *clayFile = NULL;
    char *outputFile = NULL;

    for (int i = 1; i < argc; ++i) {
        if (strcmp(argv[i], "--unoptimized") == 0) {
            optimize = false;
        }
        else if (strcmp(argv[i], "--emit-llvm") == 0) {
            emitLLVM = true;
        }
        else if (strcmp(argv[i], "--emit-native") == 0) {
            emitNative = true;
        }
        else if (strcmp(argv[i], "-o") == 0) {
            if (i+1 == argc) {
                cerr << "error: filename missing after -o\n";
                return -1;
            }
            if (outputFile != NULL) {
                cerr << "error: output file already specified: "
                     << outputFile
                     << ", specified again as " << argv[i] << '\n';
                return -1;
            }
            ++i;
            outputFile = argv[i];
        }
        else if (strstr(argv[i], "-") != argv[i]) {
            if (clayFile != NULL) {
                cerr << "error: clay file already specified: " << clayFile
                     << ", unrecognized parameter: " << argv[i] << '\n';
                return -1;
            }
            clayFile = argv[i];
        }
        else {
            cerr << "error: unrecognized option " << argv[i] << '\n';
            return -1;
        }
    }

    if (!clayFile) {
        cerr << "error: clay file not specified\n";
        return -1;
    }

    if (emitLLVM && emitNative) {
        cerr << "error: use either --emit-llvm or --emit-native, not both\n";
        return -1;
    }
    if (!emitLLVM && !emitNative)
        emitNative = true;

    llvm::InitializeAllTargets();
    llvm::InitializeAllAsmPrinters();
    initLLVM();
    llvmModule->setTargetTriple(llvm::sys::getHostTriple());

    initTypes();

    llvm::sys::Path clayExe =
        llvm::sys::Path::GetMainExecutable(argv[0], &main);
    llvm::sys::Path clayDir(clayExe.getDirname());
    llvm::sys::Path libDir(clayDir);
    bool result = libDir.appendComponent("lib-clay");
    assert(result);
    addSearchPath(libDir.str());

    llvm::raw_ostream *out = &llvm::outs();
    if ((outputFile != NULL) && (strcmp(outputFile, "-") != 0)) {
        llvm::sys::RemoveFileOnSignal(llvm::sys::Path(outputFile));
        string errorInfo;
        out = new llvm::raw_fd_ostream(outputFile,
                                       errorInfo,
                                       llvm::raw_fd_ostream::F_Binary);
        if (!errorInfo.empty()) {
            cerr << errorInfo << '\n';
            delete out;
            return -1;
        }
    }

    ModulePtr m = loadProgram(clayFile);
    codegenMain(m);

    if (optimize)
        optimizeLLVM(llvmModule);

    if (emitLLVM)
        generateLLVMAssembly(llvmModule, out);
    else if (emitNative)
        generateNativeAssembly(llvmModule, out);

    if (out != &llvm::outs())
        delete out;

    return 0;
}
<commit_msg>manually cast function pointer to void* to pacify g++.<commit_after>
#include "clay.hpp"

#include "llvm/PassManager.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/CodeGen/LinkAllAsmWriterComponents.h"
#include "llvm/CodeGen/LinkAllCodegenComponents.h"
#include "llvm/LinkAllVMCore.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/IRReader.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/StandardPasses.h"
#include "llvm/System/Host.h"
#include "llvm/System/Path.h"
#include "llvm/Target/TargetRegistry.h"

#include <iostream>
#include <cstring>

using namespace std;

static void addOptimizationPasses(llvm::PassManager &passes,
                                  llvm::FunctionPassManager &fpasses,
                                  unsigned optLevel)
{
    llvm::createStandardFunctionPasses(&fpasses, optLevel);

    llvm::Pass *inliningPass = 0;
    if (optLevel) {
        unsigned threshold = 200;
        if (optLevel > 2)
            threshold = 250;
        inliningPass = llvm::createFunctionInliningPass(threshold);
    } else {
        inliningPass = llvm::createAlwaysInlinerPass();
    }
    llvm::createStandardModulePasses(&passes,
                                     optLevel,
                                     /*OptimizeSize=*/ false,
                                     /*UnitAtATime=*/ false,
                                     /*UnrollLoops=*/ optLevel > 1,
                                     /*SimplifyLibCalls=*/ true,
                                     /*HaveExceptions=*/ true,
                                     inliningPass);
    llvm::createStandardLTOPasses(&passes,
                                  /*Internalize=*/ true,
                                  /*RunInliner=*/ true,
                                  /*VerifyEach=*/ false);
}

static void optimizeLLVM(llvm::Module *module)
{
    llvm::PassManager passes;

    string moduleDataLayout = module->getDataLayout();
    llvm::TargetData *td = new llvm::TargetData(moduleDataLayout);
    passes.add(td);

    llvm::FunctionPassManager fpasses(module);

    fpasses.add(new llvm::TargetData(*td));

    addOptimizationPasses(passes, fpasses, 3);

    fpasses.doInitialization();
    for (llvm::Module::iterator i = module->begin(), e = module->end();
         i != e; ++i)
    {
        fpasses.run(*i);
    }

    passes.add(llvm::createVerifierPass());

    passes.run(*module);
}

static void generateLLVMAssembly(llvm::Module *module,
                                 llvm::raw_ostream *out)
{
    llvm::PassManager passes;
    passes.add(llvm::createPrintModulePass(out));
    passes.run(*module);
}

static void generateNativeAssembly(llvm::Module *module,
                                   llvm::raw_ostream *out)
{
    llvm::Triple theTriple(module->getTargetTriple());
    string err;
    const llvm::Target *theTarget =
        llvm::TargetRegistry::lookupTarget(theTriple.getTriple(), err);
    assert(theTarget != NULL);
    llvm::TargetMachine *target =
        theTarget->createTargetMachine(theTriple.getTriple(), "");
    assert(target != NULL);

    llvm::CodeGenOpt::Level optLevel = llvm::CodeGenOpt::Aggressive;

    llvm::FunctionPassManager fpasses(module);

    fpasses.add(new llvm::TargetData(module));
    fpasses.add(llvm::createVerifierPass());

    target->setAsmVerbosityDefault(true);

    llvm::formatted_raw_ostream fout(*out);
    bool result =
        target->addPassesToEmitFile(fpasses,
                                    fout,
                                    llvm::TargetMachine::CGFT_AssemblyFile,
                                    optLevel);
    assert(!result);

    fpasses.doInitialization();
    for (llvm::Module::iterator i = module->begin(), e = module->end();
         i != e; ++i)
    {
        fpasses.run(*i);
    }
    fpasses.doFinalization();
}

static void usage()
{
    cerr << "usage: clay <options> <clayfile>\n";
    cerr << "options:\n";
    cerr << "  -o <file>       - specify output file\n";
    cerr << "  --unoptimized   - generate unoptimized code\n";
    cerr << "  --emit-llvm     - emit llvm assembly language\n";
    cerr << "  --emit-native   - emit native assembly language\n";
}

int main(int argc, char **argv) {
    if (argc == 1) {
        usage();
        return -1;
    }

    bool optimize = true;
    bool emitLLVM = false;
    bool emitNative = false;

    char *clayFile = NULL;
    char *outputFile = NULL;

    for (int i = 1; i < argc; ++i) {
        if (strcmp(argv[i], "--unoptimized") == 0) {
            optimize = false;
        }
        else if (strcmp(argv[i], "--emit-llvm") == 0) {
            emitLLVM = true;
        }
        else if (strcmp(argv[i], "--emit-native") == 0) {
            emitNative = true;
        }
        else if (strcmp(argv[i], "-o") == 0) {
            if (i+1 == argc) {
                cerr << "error: filename missing after -o\n";
                return -1;
            }
            if (outputFile != NULL) {
                cerr << "error: output file already specified: "
                     << outputFile
                     << ", specified again as " << argv[i] << '\n';
                return -1;
            }
            ++i;
            outputFile = argv[i];
        }
        else if (strstr(argv[i], "-") != argv[i]) {
            if (clayFile != NULL) {
                cerr << "error: clay file already specified: " << clayFile
                     << ", unrecognized parameter: " << argv[i] << '\n';
                return -1;
            }
            clayFile = argv[i];
        }
        else {
            cerr << "error: unrecognized option " << argv[i] << '\n';
            return -1;
        }
    }

    if (!clayFile) {
        cerr << "error: clay file not specified\n";
        return -1;
    }

    if (emitLLVM && emitNative) {
        cerr << "error: use either --emit-llvm or --emit-native, not both\n";
        return -1;
    }
    if (!emitLLVM && !emitNative)
        emitNative = true;

    llvm::InitializeAllTargets();
    llvm::InitializeAllAsmPrinters();
    initLLVM();
    llvmModule->setTargetTriple(llvm::sys::getHostTriple());

    initTypes();

    llvm::sys::Path clayExe =
        llvm::sys::Path::GetMainExecutable(argv[0], (void *)&main);
    llvm::sys::Path clayDir(clayExe.getDirname());
    llvm::sys::Path libDir(clayDir);
    bool result = libDir.appendComponent("lib-clay");
    assert(result);
    addSearchPath(libDir.str());

    llvm::raw_ostream *out = &llvm::outs();
    if ((outputFile != NULL) && (strcmp(outputFile, "-") != 0)) {
        llvm::sys::RemoveFileOnSignal(llvm::sys::Path(outputFile));
        string errorInfo;
        out = new llvm::raw_fd_ostream(outputFile,
                                       errorInfo,
                                       llvm::raw_fd_ostream::F_Binary);
        if (!errorInfo.empty()) {
            cerr << errorInfo << '\n';
            delete out;
            return -1;
        }
    }

    ModulePtr m = loadProgram(clayFile);
    codegenMain(m);

    if (optimize)
        optimizeLLVM(llvmModule);

    if (emitLLVM)
        generateLLVMAssembly(llvmModule, out);
    else if (emitNative)
        generateNativeAssembly(llvmModule, out);

    if (out != &llvm::outs())
        delete out;

    return 0;
}
<|endoftext|>


<commit_before>#pragma once

#include <algorithm>
#include <cmath>
#include <vector>

class KDBush {

    using size_t = std::size_t;

public:
    KDBush(const std::vector<double> &coords_, const uint8_t nodeSize_ = 64)
        : coords(coords_), nodeSize(nodeSize_) {

        const auto ids_size = coords.size() / 2;
        ids.reserve(ids_size);
        for (auto i = 0; i < ids_size; i++) ids.push_back(i);

        sortKD(0, ids.size() - 1, 0);
    }

    void within(const double qx,
                const double qy,
                const double r,
                std::vector<size_t> &result,
                const size_t left,
                const size_t right,
                const uint8_t axis) {

        const auto r2 = r * r;

        if (right - left <= nodeSize) {
            for (auto i = left; i <= right; i++) {
                if (sqDist(coords[2 * i], coords[2 * i + 1], qx, qy) <= r2)
                    result.push_back(ids[i]);
            }
            return;
        }

        const auto m = (left + right) >> 1;
        const auto x = coords[2 * m];
        const auto y = coords[2 * m + 1];

        if (sqDist(x, y, qx, qy) <= r2) result.push_back(ids[m]);

        if (axis == 0 ? qx - r <= x : qy - r <= y)
            within(qx, qy, r, result, left, m - 1, (axis + 1) % 2);

        if (axis == 0 ? qx + r >= x : qy + r >= y)
            within(qx, qy, r, result, m + 1, right, (axis + 1) % 2);
    }

    void within(const double qx, const double qy, const double r, std::vector<size_t> &result) {
        within(qx, qy, r, result, 0, ids.size() - 1, 0);
    }

private:
    uint8_t nodeSize;
    std::vector<size_t> ids;
    std::vector<double> coords;

    void sortKD(const size_t left, const size_t right, const uint8_t axis) {
        if (right - left <= nodeSize) return;
        const auto m = (left + right) >> 1;
        select(m, left, right, axis);
        sortKD(left, m - 1, (axis + 1) % 2);
        sortKD(m + 1, right, (axis + 1) % 2);
    }

    void select(const size_t k, size_t left, size_t right, const uint8_t axis) {

        while (right > left) {
            if (right - left > 600) {
                const auto n = right - left + 1;
                const auto m = k - left + 1;
                const auto z = log(n);
                const auto s = 0.5 * exp(2 * z / 3);
                const auto sd = 0.5 * sqrt(z * s * (n - s) / n) * (2 * m < n ? 1 : -1);
                const auto newLeft = std::max(left, size_t(k - m * s / n + sd));
                const auto newRight = std::min(right, size_t(k + (n - m) * s / n + sd));
                select(k, newLeft, newRight, axis);
            }

            const auto t = coords[2 * k + axis];
            auto i = left;
            auto j = right;

            swapItem(left, k);
            if (coords[2 * right + axis] > t) swapItem(left, right);

            while (i < j) {
                swapItem(i, j);
                i++;
                j--;
                while (coords[2 * i + axis] < t) i++;
                while (coords[2 * j + axis] > t) j--;
            }

            if (coords[2 * left + axis] == t)
                swapItem(left, j);
            else {
                j++;
                swapItem(j, right);
            }

            if (j <= k) left = j + 1;
            if (k <= j) right = j - 1;
        }
    }

    void swapItem(const size_t i, const size_t j) {
        std::iter_swap(ids.begin() + i, ids.begin() + j);
        std::iter_swap(coords.begin() + 2 * i, coords.begin() + 2 * j);
        std::iter_swap(coords.begin() + 2 * i + 1, coords.begin() + 2 * j + 1);
    }

    double sqDist(const double ax, const double ay, const double bx, const double by) {
        const auto dx = ax - bx;
        const auto dy = ay - by;
        return dx * dx + dy * dy;
    }
};
<commit_msg>revert auto everywhere<commit_after>#pragma once

#include <algorithm>
#include <cmath>
#include <vector>

class KDBush {

    using size_t = std::size_t;

public:
    KDBush(const std::vector<double> &coords_, const uint8_t nodeSize_ = 64)
        : coords(coords_), nodeSize(nodeSize_) {

        const auto ids_size = coords.size() / 2;
        ids.reserve(ids_size);
        for (size_t i = 0; i < ids_size; i++) ids.push_back(i);

        sortKD(0, ids.size() - 1, 0);
    }

    void within(const double qx,
                const double qy,
                const double r,
                std::vector<size_t> &result,
                const size_t left,
                const size_t right,
                const uint8_t axis) {

        const double r2 = r * r;

        if (right - left <= nodeSize) {
            for (auto i = left; i <= right; i++) {
                if (sqDist(coords[2 * i], coords[2 * i + 1], qx, qy) <= r2)
                    result.push_back(ids[i]);
            }
            return;
        }

        const size_t m = (left + right) >> 1;
        const double x = coords[2 * m];
        const double y = coords[2 * m + 1];

        if (sqDist(x, y, qx, qy) <= r2) result.push_back(ids[m]);

        if (axis == 0 ? qx - r <= x : qy - r <= y)
            within(qx, qy, r, result, left, m - 1, (axis + 1) % 2);

        if (axis == 0 ? qx + r >= x : qy + r >= y)
            within(qx, qy, r, result, m + 1, right, (axis + 1) % 2);
    }

    void within(const double qx, const double qy, const double r, std::vector<size_t> &result) {
        within(qx, qy, r, result, 0, ids.size() - 1, 0);
    }

private:
    uint8_t nodeSize;
    std::vector<size_t> ids;
    std::vector<double> coords;

    void sortKD(const size_t left, const size_t right, const uint8_t axis) {
        if (right - left <= nodeSize) return;
        const size_t m = (left + right) >> 1;
        select(m, left, right, axis);
        sortKD(left, m - 1, (axis + 1) % 2);
        sortKD(m + 1, right, (axis + 1) % 2);
    }

    void select(const size_t k, size_t left, size_t right, const uint8_t axis) {

        while (right > left) {
            if (right - left > 600) {
                const size_t n = right - left + 1;
                const size_t m = k - left + 1;
                const double z = log(n);
                const double s = 0.5 * exp(2 * z / 3);
                const double sd = 0.5 * sqrt(z * s * (n - s) / n) * (2 * m < n ? -1 : 1);
                const size_t newLeft = std::max(left, size_t(k - m * s / n + sd));
                const size_t newRight = std::min(right, size_t(k + (n - m) * s / n + sd));
                select(k, newLeft, newRight, axis);
            }

            const double t = coords[2 * k + axis];
            size_t i = left;
            size_t j = right;

            swapItem(left, k);
            if (coords[2 * right + axis] > t) swapItem(left, right);

            while (i < j) {
                swapItem(i, j);
                i++;
                j--;
                while (coords[2 * i + axis] < t) i++;
                while (coords[2 * j + axis] > t) j--;
            }

            if (coords[2 * left + axis] == t)
                swapItem(left, j);
            else {
                j++;
                swapItem(j, right);
            }

            if (j <= k) left = j + 1;
            if (k <= j) right = j - 1;
        }
    }

    void swapItem(const size_t i, const size_t j) {
        std::iter_swap(ids.begin() + i, ids.begin() + j);
        std::iter_swap(coords.begin() + 2 * i, coords.begin() + 2 * j);
        std::iter_swap(coords.begin() + 2 * i + 1, coords.begin() + 2 * j + 1);
    }

    double sqDist(const double ax, const double ay, const double bx, const double by) {
        const double dx = ax - bx;
        const double dy = ay - by;
        return dx * dx + dy * dy;
    }
};
<|endoftext|>


<commit_before>#pragma once

#include <algorithm>
#include <cmath>
#include <vector>

class KDBush {
    uint32_t nodeSize;
    std::vector<double> coords;

    void sortKD(uint32_t left, uint32_t right, uint8_t axis) {
        if (right - left <= nodeSize) return;
        uint32_t m = (left + right) >> 1;
        select(m, left, right, axis);
        sortKD(left, m - 1, (axis + 1) % 2);
        sortKD(m + 1, right, (axis + 1) % 2);
    }

    void select(uint32_t k, uint32_t left, uint32_t right, uint8_t axis) {

        while (right > left) {
            if (right - left > 600) {
                uint32_t n = right - left + 1;
                uint32_t m = k - left + 1;
                double z = log(n);
                double s = 0.5 * exp(2 * z / 3);
                double sd = 0.5 * sqrt(z * s * (n - s) / n);
                if (2 * m < n) sd = -sd;
                uint32_t newLeft = std::max(left, uint32_t(k - m * s / n + sd));
                uint32_t newRight = std::min(right, uint32_t(k + (n - m) * s / n + sd));
                select(k, newLeft, newRight, axis);
            }

            auto t = coords[2 * k + axis];
            uint32_t i = left;
            uint32_t j = right;

            swapItem(left, k);
            if (coords[2 * right + axis] > t) swapItem(left, right);

            while (i < j) {
                swapItem(i, j);
                i++;
                j--;
                while (coords[2 * i + axis] < t) i++;
                while (coords[2 * j + axis] > t) j--;
            }

            if (coords[2 * left + axis] == t)
                swapItem(left, j);
            else {
                j++;
                swapItem(j, right);
            }

            if (j <= k) left = j + 1;
            if (k <= j) right = j - 1;
        }
    }

    void swapItem(uint32_t i, uint32_t j) {
        std::iter_swap(ids.begin() + i, ids.begin() + j);
        std::iter_swap(coords.begin() + 2 * i, coords.begin() + 2 * j);
        std::iter_swap(coords.begin() + 2 * i + 1, coords.begin() + 2 * j + 1);
    }

    void search_within(uint32_t left,
                       uint32_t right,
                       uint8_t axis,
                       double qx,
                       double qy,
                       double r,
                       std::vector<uint32_t> *result) {

        double r2 = r * r;

        if (right - left <= nodeSize) {
            for (auto i = left; i <= right; i++) {
                if (sqDist(coords[2 * i], coords[2 * i + 1], qx, qy) <= r2)
                    result->push_back(ids[i]);
            }
            return;
        }

        uint32_t m = (left + right) >> 1;
        double x = coords[2 * m];
        double y = coords[2 * m + 1];

        if (sqDist(x, y, qx, qy) <= r2) result->push_back(ids[m]);

        if (axis == 0 ? qx - r <= x : qy - r <= y)
            search_within(left, m - 1, (axis + 1) % 2, qx, qy, r, result);

        if (axis == 0 ? qx + r >= x : qy + r >= y)
            search_within(m + 1, right, (axis + 1) % 2, qx, qy, r, result);
    }

    double sqDist(double ax, double ay, double bx, double by) {
        double dx = ax - bx;
        double dy = ay - by;
        return dx * dx + dy * dy;
    }

public:
    std::vector<uint32_t> ids;

    KDBush(std::vector<double> coords_, uint8_t nodeSize_ = 64)
        : coords(coords_), nodeSize(nodeSize_) {
        uint32_t ids_size = coords.size() / 2;
        ids.reserve(ids_size);
        for (uint32_t i = 0; i < ids_size; i++) ids.push_back(i);

        sortKD(0, ids.size() - 1, 0);
    }

    std::vector<uint32_t> within(double qx, double qy, double r) {
        std::vector<uint32_t> result;
        search_within(0, ids.size() - 1, 0, qx, qy, r, &result);
        return result;
    }
};
<commit_msg>minor fixes<commit_after>#pragma once

#include <algorithm>
#include <cmath>
#include <vector>

class KDBush {
    uint32_t nodeSize;
    std::vector<double> coords;

    void sortKD(uint32_t left, uint32_t right, uint8_t axis) {
        if (right - left <= nodeSize) return;
        uint32_t m = (left + right) >> 1;
        select(m, left, right, axis);
        sortKD(left, m - 1, (axis + 1) % 2);
        sortKD(m + 1, right, (axis + 1) % 2);
    }

    void select(uint32_t k, uint32_t left, uint32_t right, uint8_t axis) {

        while (right > left) {
            if (right - left > 600) {
                uint32_t n = right - left + 1;
                uint32_t m = k - left + 1;
                double z = log(n);
                double s = 0.5 * exp(2 * z / 3);
                double sd = 0.5 * sqrt(z * s * (n - s) / n);
                if (2 * m < n) sd = -sd;
                uint32_t newLeft = std::max(left, uint32_t(k - m * s / n + sd));
                uint32_t newRight = std::min(right, uint32_t(k + (n - m) * s / n + sd));
                select(k, newLeft, newRight, axis);
            }

            auto t = coords[2 * k + axis];
            uint32_t i = left;
            uint32_t j = right;

            swapItem(left, k);
            if (coords[2 * right + axis] > t) swapItem(left, right);

            while (i < j) {
                swapItem(i, j);
                i++;
                j--;
                while (coords[2 * i + axis] < t) i++;
                while (coords[2 * j + axis] > t) j--;
            }

            if (coords[2 * left + axis] == t)
                swapItem(left, j);
            else {
                j++;
                swapItem(j, right);
            }

            if (j <= k) left = j + 1;
            if (k <= j) right = j - 1;
        }
    }

    void swapItem(uint32_t i, uint32_t j) {
        std::iter_swap(ids.begin() + i, ids.begin() + j);
        std::iter_swap(coords.begin() + 2 * i, coords.begin() + 2 * j);
        std::iter_swap(coords.begin() + 2 * i + 1, coords.begin() + 2 * j + 1);
    }

    void search_within(uint32_t left,
                       uint32_t right,
                       uint8_t axis,
                       double qx,
                       double qy,
                       double r,
                       std::vector<uint32_t> &result) {

        double r2 = r * r;

        if (right - left <= nodeSize) {
            for (auto i = left; i <= right; i++) {
                if (sqDist(coords[2 * i], coords[2 * i + 1], qx, qy) <= r2)
                    result.push_back(ids[i]);
            }
            return;
        }

        uint32_t m = (left + right) >> 1;
        double x = coords[2 * m];
        double y = coords[2 * m + 1];

        if (sqDist(x, y, qx, qy) <= r2) result.push_back(ids[m]);

        if (axis == 0 ? qx - r <= x : qy - r <= y)
            search_within(left, m - 1, (axis + 1) % 2, qx, qy, r, result);

        if (axis == 0 ? qx + r >= x : qy + r >= y)
            search_within(m + 1, right, (axis + 1) % 2, qx, qy, r, result);
    }

    double sqDist(double ax, double ay, double bx, double by) {
        double dx = ax - bx;
        double dy = ay - by;
        return dx * dx + dy * dy;
    }

public:
    std::vector<uint32_t> ids;

    KDBush(std::vector<double> const &coords_, uint8_t nodeSize_ = 64)
        : coords(coords_), nodeSize(nodeSize_) {
        uint32_t ids_size = coords.size() / 2;
        ids.reserve(ids_size);
        for (uint32_t i = 0; i < ids_size; i++) ids.push_back(i);

        sortKD(0, ids.size() - 1, 0);
    }

    std::vector<uint32_t> within(double qx, double qy, double r) {
        std::vector<uint32_t> result;
        search_within(0, ids.size() - 1, 0, qx, qy, r, result);
        return result;
    }
};
<|endoftext|>