/* Minetest-c55 Copyright (C) 2010 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef UTILITY_HEADER #define UTILITY_HEADER #include #include #include #include #include #include #include #include #include #include "common_irrlicht.h" #include "debug.h" #include "exceptions.h" #include "porting.h" #include "strfnd.h" // For trim() extern const v3s16 g_6dirs[6]; extern const v3s16 g_26dirs[26]; // 26th is (0,0,0) extern const v3s16 g_27dirs[27]; inline void writeU64(u8 *data, u64 i) { data[0] = ((i>>56)&0xff); data[1] = ((i>>48)&0xff); data[2] = ((i>>40)&0xff); data[3] = ((i>>32)&0xff); data[4] = ((i>>24)&0xff); data[5] = ((i>>16)&0xff); data[6] = ((i>> 8)&0xff); data[7] = ((i>> 0)&0xff); } inline void writeU32(u8 *data, u32 i) { data[0] = ((i>>24)&0xff); data[1] = ((i>>16)&0xff); data[2] = ((i>> 8)&0xff); data[3] = ((i>> 0)&0xff); } inline void writeU16(u8 *data, u16 i) { data[0] = ((i>> 8)&0xff); data[1] = ((i>> 0)&0xff); } inline void writeU8(u8 *data, u8 i) { data[0] = ((i>> 0)&0xff); } inline u64 readU64(u8 *data) { return ((u64)data[0]<<56) | ((u64)data[1]<<48) | ((u64)data[2]<<40) | ((u64)data[3]<<32) | ((u64)data[4]<<24) | ((u64)data[5]<<16) | ((u64)data[6]<<8) | ((u64)data[7]<<0); } inline u32 readU32(u8 *data) { return (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | (data[3]<<0); } inline u16 readU16(u8 *data) { return (data[0]<<8) | (data[1]<<0); } inline u8 readU8(u8 *data) { return (data[0]<<0); } inline void writeS32(u8 *data, s32 i){ writeU32(data, (u32)i); } inline s32 readS32(u8 *data){ return (s32)readU32(data); } inline void writeS16(u8 *data, s16 i){ writeU16(data, (u16)i); } inline s16 readS16(u8 *data){ return (s16)readU16(data); } inline void writeS8(u8 *data, s8 i){ writeU8(data, (u8)i); } inline s8 readS8(u8 *data){ return (s8)readU8(data); } inline void writeF1000(u8 *data, f32 i){ writeS32(data, i*1000); } inline f32 readF1000(u8 *data){ return (f32)readS32(data)/1000.; } inline void writeV3S32(u8 *data, v3s32 p) { writeS32(&data[0], p.X); writeS32(&data[4], p.Y); writeS32(&data[8], p.Z); } inline v3s32 readV3S32(u8 *data) { v3s32 p; p.X = readS32(&data[0]); p.Y = readS32(&data[4]); p.Z = readS32(&data[8]); return p; } inline void writeV3F1000(u8 *data, v3f p) { writeF1000(&data[0], p.X); writeF1000(&data[4], p.Y); writeF1000(&data[8], p.Z); } inline v3f readV3F1000(u8 *data) { v3f p; p.X = (float)readF1000(&data[0]); p.Y = (float)readF1000(&data[4]); p.Z = (float)readF1000(&data[8]); return p; } inline void writeV2F1000(u8 *data, v2f p) { writeF1000(&data[0], p.X); writeF1000(&data[4], p.Y); } inline v2f readV2F1000(u8 *data) { v2f p; p.X = (float)readF1000(&data[0]); p.Y = (float)readF1000(&data[4]); return p; } inline void writeV2S16(u8 *data, v2s16 p) { writeS16(&data[0], p.X); writeS16(&data[2], p.Y); } inline v2s16 readV2S16(u8 *data) { v2s16 p; p.X = readS16(&data[0]); p.Y = readS16(&data[2]); return p; } inline void writeV2S32(u8 *data, v2s32 p) { writeS32(&data[0], p.X); writeS32(&data[2], p.Y); } inline v2s32 readV2S32(u8 *data) { v2s32 p; p.X = readS32(&data[0]); p.Y = readS32(&data[2]); return p; } inline void writeV3S16(u8 *data, v3s16 p) { writeS16(&data[0], p.X); writeS16(&data[2], p.Y); writeS16(&data[4], p.Z); } inline v3s16 readV3S16(u8 *data) { v3s16 p; p.X = readS16(&data[0]); p.Y = readS16(&data[2]); p.Z = readS16(&data[4]); return p; } /* The above stuff directly interfaced to iostream */ inline void writeU8(std::ostream &os, u8 p) { char buf[1]; writeU8((u8*)buf, p); os.write(buf, 1); } inline u8 readU8(std::istream &is) { char buf[1]; is.read(buf, 1); return readU8((u8*)buf); } inline void writeU16(std::ostream &os, u16 p) { char buf[2]; writeU16((u8*)buf, p); os.write(buf, 2); } inline u16 readU16(std::istream &is) { char buf[2]; is.read(buf, 2); return readU16((u8*)buf); } inline void writeU32(std::ostream &os, u32 p) { char buf[4]; writeU32((u8*)buf, p); os.write(buf, 4); } inline u32 readU32(std::istream &is) { char buf[4]; is.read(buf, 4); return readU32((u8*)buf); } inline void writeS32(std::ostream &os, s32 p) { char buf[4]; writeS32((u8*)buf, p); os.write(buf, 4); } inline s32 readS32(std::istream &is) { char buf[4]; is.read(buf, 4); return readS32((u8*)buf); } inline void writeS16(std::ostream &os, s16 p) { char buf[2]; writeS16((u8*)buf, p); os.write(buf, 2); } inline s16 readS16(std::istream &is) { char buf[2]; is.read(buf, 2); return readS16((u8*)buf); } inline void writeS8(std::ostream &os, s8 p) { char buf[1]; writeS8((u8*)buf, p); os.write(buf, 1); } inline s8 readS8(std::istream &is) { char buf[1]; is.read(buf, 1); return readS8((u8*)buf); } inline void writeF1000(std::ostream &os, f32 p) { char buf[4]; writeF1000((u8*)buf, p); os.write(buf, 4); } inline f32 readF1000(std::istream &is) { char buf[4]; is.read(buf, 4); return readF1000((u8*)buf); } inline void writeV3F1000(std::ostream &os, v3f p) { char buf[12]; writeV3F1000((u8*)buf, p); os.write(buf, 12); } inline v3f readV3F1000(std::istream &is) { char buf[12]; is.read(buf, 12); return readV3F1000((u8*)buf); } inline void writeV2F1000(std::ostream &os, v2f p) { char buf[8]; writeV2F1000((u8*)buf, p); os.write(buf, 8); } inline v2f readV2F1000(std::istream &is) { char buf[8]; is.read(buf, 8); return readV2F1000((u8*)buf); } inline void writeV2S16(std::ostream &os, v2s16 p) { char buf[4]; writeV2S16((u8*)buf, p); os.write(buf, 4); } inline v2s16 readV2S16(std::istream &is) { char buf[4]; is.read(buf, 4); return readV2S16((u8*)buf); } inline void writeV3S16(std::ostream &os, v3s16 p) { char buf[6]; writeV3S16((u8*)buf, p); os.write(buf, 6); } inline v3s16 readV3S16(std::istream &is) { char buf[6]; is.read(buf, 6); return readV3S16((u8*)buf); } /* None of these are used at the moment */ template class SharedPtr { public: SharedPtr(T *t=NULL) { refcount = new int; *refcount = 1; ptr = t; } SharedPtr(SharedPtr &t) { //*this = t; drop(); refcount = t.refcount; (*refcount)++; ptr = t.ptr; } ~SharedPtr() { drop(); } SharedPtr & operator=(T *t) { drop(); refcount = new int; *refcount = 1; ptr = t; return *this; } SharedPtr & operator=(SharedPtr &t) { drop(); refcount = t.refcount; (*refcount)++; ptr = t.ptr; return *this; } T* operator->() { return ptr; } T & operator*() { return *ptr; } bool operator!=(T *t) { return ptr != t; } bool operator==(T *t) { return ptr == t; } T & operator[](unsigned int i) { return ptr[i]; } private: void drop() { assert((*refcount) > 0); (*refcount)--; if(*refcount == 0) { delete refcount; if(ptr != NULL) delete ptr; } } T *ptr; int *refcount; }; template class Buffer { public: Buffer() { m_size = 0; data = NULL; } Buffer(unsigned int size) { m_size = size; if(size != 0) data = new T[size]; else data = NULL; } Buffer(const Buffer &buffer) { m_size = buffer.m_size; if(m_size != 0) { data = new T[buffer.m_size]; memcpy(data, buffer.data, buffer.m_size); } else data = NULL; } Buffer(const T *t, unsigned int size) { m_size = size; if(size != 0) { data = new T[size]; memcpy(data, t, size); } else data = NULL; } ~Buffer() { drop(); } Buffer& operator=(const Buffer &buffer) { if(this == &buffer) return *this; drop(); m_size = buffer.m_size; if(m_size != 0) { data = new T[buffer.m_size]; memcpy(data, buffer.data, buffer.m_size); } else data = NULL; return *this; } T & operator[](unsigned int i) const { return data[i]; } T * operator*() const { return data; } unsigned int getSize() const { return m_size; } private: void drop() { if(data) delete[] data; } T *data; unsigned int m_size; }; template class SharedBuffer { public: SharedBuffer() { m_size = 0; data = NULL; refcount = new unsigned int; (*refcount) = 1; } SharedBuffer(unsigned int size) { m_size = size; if(m_size != 0) data = new T[m_size]; else data = NULL; refcount = new unsigned int; (*refcount) = 1; } SharedBuffer(const SharedBuffer &buffer) { //std::cout<<"SharedBuffer(const SharedBuffer &buffer)"< &buffer) { m_size = buffer.getSize(); if(m_size != 0) { data = new T[m_size]; memcpy(data, *buffer, buffer.getSize()); } else data = NULL; refcount = new unsigned int; (*refcount) = 1; } ~SharedBuffer() { drop(); } T & operator[](unsigned int i) const { //assert(i < m_size) return data[i]; } T * operator*() const { return data; } unsigned int getSize() const { return m_size; } operator Buffer() const { return Buffer(data, m_size); } private: void drop() { assert((*refcount) > 0); (*refcount)--; if(*refcount == 0) { if(data) delete[] data; delete refcount; } } T *data; unsigned int m_size; unsigned int *refcount; }; inline SharedBuffer SharedBufferFromString(const char *string) { SharedBuffer b((u8*)string, strlen(string)+1); return b; } template cl const char *getName() { return "TestAreaStore"; } void runTests(IGameDef *gamedef); void genericStoreTest(AreaStore *store); void testVectorStore(); void testSpatialStore(); void testSerialization(); }; static TestAreaStore g_test_instance; void TestAreaStore::runTests(IGameDef *gamedef) { TEST(testVectorStore); #if USE_SPATIAL TEST(testSpatialStore); #endif TEST(testSerialization); } //////////////////////////////////////////////////////////////////////////////// void TestAreaStore::testVectorStore() { VectorAreaStore store; genericStoreTest(&store); } void TestAreaStore::testSpatialStore() { #if USE_SPATIAL SpatialAreaStore store; genericStoreTest(&store); #endif } void TestAreaStore::genericStoreTest(AreaStore *store) { Area a(v3s16(-10, -3, 5), v3s16(0, 29, 7)); Area b(v3s16(-5, -2, 5), v3s16(0, 28, 6)); Area c(v3s16(-7, -3, 6), v3s16(-1, 27, 7)); std::vector<Area *> res; UASSERTEQ(size_t, store->size(), 0); store->reserve(2); // sic store->insertArea(&a); store->insertArea(&b); store->insertArea(&c); UASSERTEQ(size_t, store->size(), 3); store->getAreasForPos(&res, v3s16(-1, 0, 6)); UASSERTEQ(size_t, res.size(), 3); res.clear(); store->getAreasForPos(&res, v3s16(0, 0, 7)); UASSERTEQ(size_t, res.size(), 1); res.clear(); store->removeArea(a.id); store->getAreasForPos(&res, v3s16(0, 0, 7)); UASSERTEQ(size_t, res.size(), 0); res.clear(); store->insertArea(&a); store->getAreasForPos(&res, v3s16(0, 0, 7)); UASSERTEQ(size_t, res.size(), 1); res.clear(); store->getAreasInArea(&res, v3s16(-10, -3, 5), v3s16(0, 29, 7), false); UASSERTEQ(size_t, res.size(), 3); res.clear(); store->getAreasInArea(&res, v3s16(-100, 0, 6), v3s16(200, 0, 6), false); UASSERTEQ(size_t, res.size(), 0); res.clear(); store->getAreasInArea(&res, v3s16(-100, 0, 6), v3s16(200, 0, 6), true); UASSERTEQ(size_t, res.size(), 3); res.clear(); store->removeArea(a.id); store->removeArea(b.id); store->removeArea(c.id); Area d(v3s16(-100, -300, -200), v3s16(-50, -200, -100)); d.data = "Hi!"; store->insertArea(&d); store->getAreasForPos(&res, v3s16(-75, -250, -150)); UASSERTEQ(size_t, res.size(), 1); UASSERTEQ(u16, res[0]->data.size(), 3); UASSERT(strncmp(res[0]->data.c_str(), "Hi!", 3) == 0); res.clear(); store->removeArea(d.id); } void TestAreaStore::testSerialization() { VectorAreaStore store; Area a(v3s16(-1, 0, 1), v3s16(0, 1, 2)); a.data = "Area AA"; store.insertArea(&a); Area b(v3s16(123, 456, 789), v3s16(32000, 100, 10)); b.data = "Area BB"; store.insertArea(&b); std::ostringstream os; store.serialize(os); std::string str = os.str(); std::string str_wanted("\x00" // Version "\x00\x02" // Count "\xFF\xFF\x00\x00\x00\x01" // Area A min edge "\x00\x00\x00\x01\x00\x02" // Area A max edge "\x00\x07" // Area A data length "Area AA" // Area A data "\x00\x7B\x00\x64\x00\x0A" // Area B min edge (last two swapped with max edge for sorting) "\x7D\x00\x01\xC8\x03\x15" // Area B max edge (^) "\x00\x07" // Area B data length "Area BB" // Area B data "\x00\x00\x00\x00" // ID A = 0 "\x00\x00\x00\x01", // ID B = 1 1 + 2 + (6 + 6 + 2 + 7) * 2 + // min/max edge, length, data 2 * 4); // Area IDs UASSERTEQ(const std::string &, str, str_wanted); std::istringstream is(str);