diff --git a/Binaries/ibc_x64 b/Binaries/ibc_x64 index 74f3404..c97a3ba 100755 Binary files a/Binaries/ibc_x64 and b/Binaries/ibc_x64 differ diff --git a/Compiler/Compiler.vcxproj b/Compiler/Compiler.vcxproj index 3f4defd..2b01011 100644 --- a/Compiler/Compiler.vcxproj +++ b/Compiler/Compiler.vcxproj @@ -120,6 +120,7 @@ true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true + MultiThreaded Console @@ -138,6 +139,7 @@ true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true + MultiThreaded Console @@ -154,6 +156,7 @@ + Create diff --git a/Compiler/inbcompiler.cpp b/Compiler/inbcompiler.cpp index 9ad591a..ade900c 100644 --- a/Compiler/inbcompiler.cpp +++ b/Compiler/inbcompiler.cpp @@ -40,48 +40,6 @@ void splitIbs(const std::string &source, std::list &splitted) splitted.emplace_back(std::move(buffer)); } -enum class kw -{ - Namespace, - Enum, - Struct, - Optional, - Int8, - Uint8, - Int16, - Uint16, - Int32, - Uint32, - Int64, - Uint64, - Float32, - Float64, - Bytes, -}; -static const std::map keywords = -{ - { "namespace", kw::Namespace }, - { "enum" , kw::Enum }, - { "struct" , kw::Struct }, - { "optional" , kw::Optional }, - { "int8" , kw::Int8 }, - { "uint8" , kw::Uint8 }, - { "int16" , kw::Int16 }, - { "uint16" , kw::Uint16 }, - { "int32" , kw::Int32 }, - { "uint32" , kw::Uint32 }, - { "int64" , kw::Int64 }, - { "uint64" , kw::Uint64 }, - { "float32" , kw::Float32 }, - { "float64" , kw::Float64 }, - { "bytes" , kw::Bytes } -}; -static const std::string tokenOpenScope("{"); -static const std::string tokenCloseScope("}"); -static const std::string tokenArray("[]"); -static const std::string tokenEquals("="); -static const std::string tokenColon(":"); -static const std::string tokenOptional("optional"); INBCompiler::INBCompiler() {} @@ -294,7 +252,9 @@ void INBCompiler::parseStruct(tokens_it &it) if (*it != tokenOpenScope) // <{> return; next(it); // ++<{> - auto &fieldsList = m_structs[structName]; + auto &fieldsList = m_structs[structName].first; + auto &optionalCount = m_structs[structName].second; + optionalCount = 0; bool isExpectType = false; while (*it != tokenCloseScope) { @@ -305,6 +265,9 @@ void INBCompiler::parseStruct(tokens_it &it) if (fieldsList.empty()) return; fieldsList.back().second.isArray = true; + if (!fieldsList.back().second.isOptional) + optionalCount++; + fieldsList.back().second.isOptional = true; if (!next(it)) return; } @@ -314,6 +277,8 @@ void INBCompiler::parseStruct(tokens_it &it) return; if (fieldsList.empty()) return; + if (!fieldsList.back().second.isOptional) + optionalCount++; fieldsList.back().second.isOptional = true; if (!next(it)) return; @@ -327,6 +292,13 @@ void INBCompiler::parseStruct(tokens_it &it) if (fieldsList.empty()) return; fieldsList.back().second.type = std::move(*it); + if (fieldsList.back().second.type == tokenBytes) + { + fieldsList.back().second.isArray = true; + if (!fieldsList.back().second.isOptional) + optionalCount++; + fieldsList.back().second.isOptional = true; + } if (!next(it)) return; isExpectType = false; diff --git a/Compiler/inbcompiler.h b/Compiler/inbcompiler.h index e498cf6..2564f2c 100644 --- a/Compiler/inbcompiler.h +++ b/Compiler/inbcompiler.h @@ -8,6 +8,50 @@ enum class Language { CPP }; +enum class kw +{ + Namespace, + Enum, + Struct, + Optional, + Int8, + Uint8, + Int16, + Uint16, + Int32, + Uint32, + Int64, + Uint64, + Float32, + Float64, + Bytes, +}; +static const std::map keywords = +{ + { "namespace", kw::Namespace }, + { "enum" , kw::Enum }, + { "struct" , kw::Struct }, + { "optional" , kw::Optional }, + { "int8" , kw::Int8 }, + { "uint8" , kw::Uint8 }, + { "int16" , kw::Int16 }, + { "uint16" , kw::Uint16 }, + { "int32" , kw::Int32 }, + { "uint32" , kw::Uint32 }, + { "int64" , kw::Int64 }, + { "uint64" , kw::Uint64 }, + { "float32" , kw::Float32 }, + { "float64" , kw::Float64 }, + { "bytes" , kw::Bytes } +}; +static const std::string tokenOpenScope("{"); +static const std::string tokenCloseScope("}"); +static const std::string tokenArray("[]"); +static const std::string tokenEquals("="); +static const std::string tokenColon(":"); +static const std::string tokenOptional("optional"); +static const std::string tokenBytes("bytes"); + class INBCompiler { @@ -42,7 +86,9 @@ class INBCompiler bool isOptional = false; bool isArray = false; }; - using StructDescr = std::list>; + using StructDescr = std::pair>, + uint32_t>; std::map m_structs; bool m_detailed = false; diff --git a/Compiler/inbcpp.cpp b/Compiler/inbcpp.cpp index 404b6a1..7763f73 100644 --- a/Compiler/inbcpp.cpp +++ b/Compiler/inbcpp.cpp @@ -21,7 +21,8 @@ static const std::map standard = { "int64" , "int64_t" }, { "uint64" , "uint64_t" }, { "float32" , "float" }, - { "float64" , "double" } + { "float64" , "double" }, + { "bytes" , "bytes" } }; void INBCompiler::genCPP(const std::string &out) @@ -88,50 +89,267 @@ void INBCompiler::genCPP(const std::string &out) file << std::endl; for (const auto &st : m_structs) { + const uint32_t optionalCount = st.second.second; + const uint32_t staticCount = st.second.first.size() - optionalCount; file << "class " << st.first << std::endl; file << "{" << std::endl; file << "public:" << std::endl; file << " void create(const uint32_t reserve = 0)" << std::endl; file << " {" << std::endl; + file << " m_from = nullptr;" << std::endl; file << " m_buffer.reserve(reserve);" << std::endl; - file << " m_buffer.resize(sizeof(_inner_::header) + sizeof(staticData));" << std::endl; + file << " m_buffer.resize(sizeof(_inner_::header) + sizeof(m_tableSize) * sizeof(uint32_t)"; + if (staticCount) + file << " + sizeof(staticData));" << std::endl; + else + file << ");" << std::endl; file << " _inner_::header *h = reinterpret_cast<_inner_::header*>(&m_buffer[0]);" << std::endl; file << " h->signature0 = 'i';" << std::endl; file << " h->signature1 = 'b';" << std::endl; file << " h->version = 1;" << std::endl; file << " h->compression = INB_NO_COMPRESSION;" << std::endl; - file << " h->tableSize = 0;" << std::endl; + file << " h->tableSize = m_tableSize;" << std::endl; + file << " if (m_tableSize)" << std::endl; + file << " {" << std::endl; + file << " uint32_t* table = reinterpret_cast(" << std::endl; + file << " &m_buffer[0] + sizeof(_inner_::header)"; + if (staticCount) + file << "+sizeof(staticData));" << std::endl; + else + file << ");" << std::endl; + file << " for (uint32_t i = 0; i < m_tableSize; i++)" << std::endl; + file << " table[i] = 0;" << std::endl; + file << " }" << std::endl; file << " }" << std::endl; file << std::endl; - for (const auto &members : st.second) + if (optionalCount) + { + file << " enum class ids" << std::endl; + file << " {" << std::endl; + for (const auto &member : st.second.first) + { + if (!member.second.isOptional) + continue; + file << " " << member.first << "," << std::endl; + } + file << " _size_" << std::endl; + file << " };" << std::endl; + file << " const char* getIdString(const ids& id) const" << std::endl; + file << " {" << std::endl; + file << " switch (id)" << std::endl; + file << " {" << std::endl; + for (const auto &member : st.second.first) + { + if (!member.second.isOptional) + continue; + file << " case ids::" << member.first << ": return \"" << member.first << "\"; " << std::endl; + } + file << " default: return \"_?unknown_id?_\";" << std::endl; + file << " }" << std::endl; + file << " }" << std::endl; + file << " void* getDataById(const ids& id)" << std::endl; + file << " {" << std::endl; + file << " uint8_t* ptr = m_from ? m_from : m_buffer.data();" << std::endl; + file << " const uint32_t* table = reinterpret_cast(" << std::endl; + file << " &ptr[0] + sizeof(_inner_::header)"; + if (staticCount) + file << " + sizeof(staticData)"; + file << ");" << std::endl; + file << " const uint32_t offset = table[static_cast(id)];" << std::endl; + file << " if (offset == 0)" << std::endl; + file << " throw std::logic_error(\"There is no field '\"" << std::endl; + file << " + std::string(getIdString(id)) + \"' in the packet\");" << std::endl; + file << " return reinterpret_cast(&ptr[0] + offset + sizeof(uint32_t));" << std::endl; + file << " }" << std::endl; + file << " uint32_t getSizeById(const ids& id) const" << std::endl; + file << " {" << std::endl; + file << " const uint8_t* ptr = m_from ? m_from : m_buffer.data();" << std::endl; + file << " const uint32_t* table = reinterpret_cast(" << std::endl; + file << " &ptr[0] + sizeof(_inner_::header)"; + if (staticCount) + file << " + sizeof(staticData)"; + file << ");" << std::endl; + file << " const uint32_t offset = table[static_cast(id)];" << std::endl; + file << " if (offset == 0)" << std::endl; + file << " return 0;" << std::endl; + file << " else" << std::endl; + file << " return *reinterpret_cast(&ptr[0] + offset);" << std::endl; + file << " }" << std::endl; + file << " void addDataById(const ids& id, const uint32_t size)" << std::endl; + file << " {" << std::endl; + file << " if (m_from)" << std::endl; + file << " throw std::logic_error(\"We cannot edit received packets\");" << std::endl; + file << " uint32_t* table = reinterpret_cast(" << std::endl; + file << " &m_buffer[0] + sizeof(_inner_::header)"; + if (staticCount) + file << " + sizeof(staticData)"; + file << ");" << std::endl; + file << " const uint32_t offset = table[static_cast(id)];" << std::endl; + file << " if (offset != 0)" << std::endl; + file << " return;" << std::endl; + file << " const uint32_t newOffset = static_cast(m_buffer.size());" << std::endl; + file << " m_buffer.resize(m_buffer.size() + sizeof(uint32_t) + size);" << std::endl; + file << " table = reinterpret_cast(" << std::endl; + file << " &m_buffer[0] + sizeof(_inner_::header)"; + if (staticCount) + file << " + sizeof(staticData)"; + file << ");" << std::endl; + file << " table[static_cast(id)] = newOffset;" << std::endl; + file << " *reinterpret_cast(&m_buffer[0] + newOffset) = size;" << std::endl; + file << " }" << std::endl; + file << std::endl; + } + for (const auto &member : st.second.first) { - const auto &stType = standard.find(members.second.type); + const auto &stType = standard.find(member.second.type); if (stType == standard.end()) { - std::cout << clr::yellow << "Warning! Unknown type: " << members.second.type << clr::default_ << std::endl; + std::cout << clr::yellow << "Warning! Unknown type: " << member.second.type << clr::default_ << std::endl; continue; } const std::string &type = stType->second; - const std::string &name = members.first; - const bool &isArray = members.second.isArray; - const bool &isOptional = members.second.isOptional; - file << " bool has_" << name << "() const" << std::endl; + const std::string &name = member.first; + const bool &isArray = member.second.isArray; + const bool &isOptional = member.second.isOptional; + + file << " uint32_t size_" << name << "() const" << std::endl; file << " {" << std::endl; - file << " return true;" << std::endl; + if (isOptional) + { + if (type == tokenBytes) + file << " return getSizeById(ids::" << name << ");" << std::endl; + else + file << " return getSizeById(ids::" << name << ") / sizeof(" << type << ");" << std::endl; + } + else + { + file << " return sizeof(" << type << ");" << std::endl; + } file << " }" << std::endl; - file << " void add_" << name << "()" << std::endl; - file << " {}" << std::endl; - file << " const " << type << "& get_" << name << "() const" << std::endl; + file << " bool has_" << name << "() const" << std::endl; file << " {" << std::endl; - file << " const staticData* data = m_from" << std::endl; - file << " ? reinterpret_cast(&m_from[sizeof(_inner_::header)])" << std::endl; - file << " : reinterpret_cast(&m_buffer[sizeof(_inner_::header)]);" << std::endl; - file << " return data->" << name << ";" << std::endl; + if (isOptional) + { + file << " return getSizeById(ids::" << name << ") != 0;" << std::endl; + } + else + { + file << " return true;" << std::endl; + } file << " }" << std::endl; - file << " void set_" << name << "(const " << type << "& " << name << ")" << std::endl; - file << " {" << std::endl; - file << " staticData* data = reinterpret_cast(&m_buffer[sizeof(_inner_::header)]);" << std::endl; - file << " data->" << name << " = " << name << ";" << std::endl; + if (isOptional) + { + if (isArray) + { + file << " void add_" << name << "(const uint32_t size)" << std::endl; + file << " {" << std::endl; + if (type == tokenBytes) + file << " addDataById(ids::" << name << ", size);" << std::endl; + else + file << " addDataById(ids::" << name << ", size * sizeof(" << type << "));" << std::endl; + } + else + { + file << " void add_" << name << "()" << std::endl; + file << " {" << std::endl; + file << " addDataById(ids::" << name << ", sizeof(" << type << "));" << std::endl; + } + } + else + { + file << " void add_" << name << "()" << std::endl; + file << " {" << std::endl; + } + file << " }" << std::endl; + if (isOptional) + { + if (isArray) + { + if (type == tokenBytes) + { + file << " const void* get_" << name << "()" << std::endl; + file << " {" << std::endl; + file << " return getDataById(ids::" << name << ");" << std::endl; + } + else + { + file << " const " << type << "* get_" << name << "()" << std::endl; + file << " {" << std::endl; + file << " return reinterpret_cast<" << type << "*>(getDataById(ids::" << name << "));" << std::endl; + file << " }" << std::endl; + file << " const " << type << "& get_" << name << "(const uint32_t index)" << std::endl; + file << " {" << std::endl; + file << " const " << type << "* ptr = reinterpret_cast<" << type << "*>(getDataById(ids::" << name << "));" << std::endl; + file << " if (!ptr)" << std::endl; + file << " throw std::logic_error(\"Nullptr\");" << std::endl; + file << " return ptr[index];" << std::endl; + } + } + else + { + file << " const " << type << "& get_" << name << "()" << std::endl; + file << " {" << std::endl; + file << " return *reinterpret_cast<" << type << "*>(getDataById(ids::" << name << "));" << std::endl; + } + } + else + { + file << " const " << type << "& get_" << name << "()" << std::endl; + file << " {" << std::endl; + file << " const staticData* data = m_from" << std::endl; + file << " ? reinterpret_cast(&m_from[sizeof(_inner_::header)])" << std::endl; + file << " : reinterpret_cast(&m_buffer[sizeof(_inner_::header)]);" << std::endl; + file << " return data->" << name << ";" << std::endl; + } + file << "}" << std::endl; + if (isOptional) + { + if (isArray) + { + if (type == tokenBytes) + { + file << " void set_" << name << "(const void* " << name << ")" << std::endl; + file << " {" << std::endl; + file << " const uint32_t size = getSizeById(ids::" << name << ");" << std::endl; + file << " if (size == 0)" << std::endl; + file << " throw std::logic_error(\"Zero size\");" << std::endl; + file << " const uint8_t* src = reinterpret_cast(" << name << ");" << std::endl; + file << " uint8_t* dst = reinterpret_cast(getDataById(ids::" << name << "));" << std::endl; + file << " for (uint32_t i = 0; i < size; i++)" << std::endl; + file << " dst[i] = src[i];" << std::endl; + } + else + { + file << " void set_" << name << "(const " << type << "* " << name << ")" << std::endl; + file << " {" << std::endl; + file << " const uint32_t size = getSizeById(ids::" << name << ");" << std::endl; + file << " const uint8_t* src = reinterpret_cast(" << name << ");" << std::endl; + file << " uint8_t* dst = reinterpret_cast(getDataById(ids::" << name << "));" << std::endl; + file << " for (uint32_t i = 0; i < size; i++)" << std::endl; + file << " dst[i] = src[i];" << std::endl; + file << " }" << std::endl; + file << " void set_" << name << "(const uint32_t index, const " << type << "& element)" << std::endl; + file << " {" << std::endl; + file << " " << type << "* ptr = reinterpret_cast<" << type << "*>(getDataById(ids::" << name << "));" << std::endl; + file << " if (!ptr)" << std::endl; + file << " throw std::logic_error(\"Nullptr\");" << std::endl; + file << " ptr[index] = element;" << std::endl; + } + } + else + { + file << " void set_" << name << "(const " << type << "& " << name << ")" << std::endl; + file << " {" << std::endl; + file << " *reinterpret_cast<" << type << "*>(getDataById(ids::" << name << ")) = " << name << ";" << std::endl; + } + } + else + { + file << " void set_" << name << "(const " << type << "& " << name << ")" << std::endl; + file << " {" << std::endl; + file << " staticData* data = reinterpret_cast(&m_buffer[sizeof(_inner_::header)]);" << std::endl; + file << " data->" << name << " = " << name << ";" << std::endl; + } file << " }" << std::endl; file << std::endl; } @@ -144,10 +362,9 @@ void INBCompiler::genCPP(const std::string &out) file << " h->signature1 != 'b' ||" << std::endl; file << " h->version != 1)" << std::endl; file << " return false;" << std::endl; - file << std::endl; file << " if (!m_buffer.empty())" << std::endl; file << " m_buffer.clear();" << std::endl; - file << " m_from = reinterpret_cast(ptr);" << std::endl; + file << " m_from = reinterpret_cast(const_cast(ptr));" << std::endl; file << " return true;" << std::endl; file << " }" << std::endl; file << " void* to()" << std::endl; @@ -181,28 +398,31 @@ void INBCompiler::genCPP(const std::string &out) file << " }" << std::endl; file << std::endl; file << "private:" << std::endl; - file << " #pragma pack(push, 1)" << std::endl; - file << " struct staticData" << std::endl; - file << " {" << std::endl; - for (const auto &members : st.second) + if (staticCount) { - const auto &stType = standard.find(members.second.type); - if (stType == standard.end()) + file << " #pragma pack(push, 1)" << std::endl; + file << " struct staticData" << std::endl; + file << " {" << std::endl; + for (const auto &member : st.second.first) { - continue; + const auto &stType = standard.find(member.second.type); + if (stType == standard.end()) + continue; + //const bool &isArray = member.second.isArray; + const bool &isOptional = member.second.isOptional; + if (isOptional) + continue; + const std::string &type = stType->second; + const std::string &name = member.first; + file << " " << type << " " << name << ";" << std::endl; } - const std::string &type = stType->second; - const std::string &name = members.first; - const bool &isArray = members.second.isArray; - const bool &isOptional = members.second.isOptional; - file << " " << type << " " << name << ";" << std::endl; + file << " };" << std::endl; + file << " #pragma pack(pop)" << std::endl; + file << std::endl; } - file << " };" << std::endl; - file << " #pragma pack(pop)" << std::endl; - file << std::endl; - file << " const uint8_t* m_from = nullptr;" << std::endl; + file << " uint8_t* m_from = nullptr;" << std::endl; file << " std::vector m_buffer;" << std::endl; - file << " uint32_t m_tableOffset = 0;" << std::endl; + file << " const uint16_t m_tableSize = " << optionalCount << ";" << std::endl; file << "};" << std::endl; file << std::endl; } diff --git a/Compiler/stdafx.h b/Compiler/stdafx.h index 9ffe4d2..6120274 100644 --- a/Compiler/stdafx.h +++ b/Compiler/stdafx.h @@ -9,6 +9,7 @@ #include #include #include +#include #ifdef _WIN32 # include diff --git a/Tests/Tests.vcxproj b/Tests/Tests.vcxproj index e7b989f..4e3213e 100644 --- a/Tests/Tests.vcxproj +++ b/Tests/Tests.vcxproj @@ -88,7 +88,7 @@ - Use + NotUsing Level3 Disabled true @@ -102,7 +102,7 @@ - Use + NotUsing Level3 Disabled true @@ -116,7 +116,7 @@ - Use + NotUsing Level3 MaxSpeed true @@ -134,7 +134,7 @@ - Use + NotUsing Level3 MaxSpeed true diff --git a/Tests/main.cpp b/Tests/main.cpp index d89c74d..fffa760 100644 --- a/Tests/main.cpp +++ b/Tests/main.cpp @@ -4,8 +4,6 @@ TEST(Vec2StaticFields, Basic) { - std::cout << "sizeof=" << sizeof(ExtNS::IntNS::_inner_::header) << std::endl; - ExtNS::IntNS::Vec2f srcPoint2f; srcPoint2f.create(); srcPoint2f.set_x(1.23f); @@ -18,6 +16,47 @@ TEST(Vec2StaticFields, Basic) EXPECT_EQ(dstPoint2f.get_y(), 45.6f); } +TEST(BytesTest, Basic) +{ + ExtNS::IntNS::ArrayTest srcArray; + srcArray.create(); + uint32_t src[5] = { 31, 42, 53, 64, 75 }; + srcArray.set_var(88); + srcArray.add_raw(5 * sizeof(uint32_t)); + srcArray.set_raw(src); + srcArray.add_arr(5); + srcArray.set_arr(src); + srcArray.set_arr(1, 21); + void* ptr = srcArray.to(); + + uint32_t dst[5]; + ExtNS::IntNS::ArrayTest dstArray; + ASSERT_EQ(dstArray.from(ptr), true); + const uint32_t size = dstArray.size_raw() / sizeof(uint32_t); + EXPECT_EQ(size, 5); + const uint32_t* srcPtr = reinterpret_cast(dstArray.get_raw()); + for (uint32_t i = 0; i < size; i++) + dst[i] = srcPtr[i]; + EXPECT_EQ(dst[0], 31); + EXPECT_EQ(dst[4], 75); + EXPECT_EQ(dstArray.get_arr(0), 31); + EXPECT_EQ(dstArray.get_arr(1), 21); +} + +TEST(Advanced, TestCases) +{ + ExtNS::IntNS::ArrayTest srcArray; + srcArray.create(); + srcArray.add_arr(4); + void* ptr = srcArray.to(); + + ExtNS::IntNS::ArrayTest dstArray; + ASSERT_EQ(dstArray.from(ptr), true); + EXPECT_EQ(dstArray.has_arr(), true); + EXPECT_EQ(dstArray.has_var(), true); + EXPECT_EQ(dstArray.has_raw(), false); +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); diff --git a/Tests/schema_generated.h b/Tests/schema_generated.h index 8b9e5da..96b2891 100644 --- a/Tests/schema_generated.h +++ b/Tests/schema_generated.h @@ -37,80 +37,425 @@ enum class Color BLUE = 4 }; +class ArrayTest; class Packet; class Vec2f; class Vec3i; +class ArrayTest +{ +public: + void create(const uint32_t reserve = 0) + { + m_from = nullptr; + m_buffer.reserve(reserve); + m_buffer.resize(sizeof(_inner_::header) + sizeof(m_tableSize) * sizeof(uint32_t) + sizeof(staticData)); + _inner_::header *h = reinterpret_cast<_inner_::header*>(&m_buffer[0]); + h->signature0 = 'i'; + h->signature1 = 'b'; + h->version = 1; + h->compression = INB_NO_COMPRESSION; + h->tableSize = m_tableSize; + if (m_tableSize) + { + uint32_t* table = reinterpret_cast( + &m_buffer[0] + sizeof(_inner_::header)+sizeof(staticData)); + for (uint32_t i = 0; i < m_tableSize; i++) + table[i] = 0; + } + } + + enum class ids + { + raw, + arr, + _size_ + }; + const char* getIdString(const ids& id) const + { + switch (id) + { + case ids::raw: return "raw"; + case ids::arr: return "arr"; + default: return "_?unknown_id?_"; + } + } + void* getDataById(const ids& id) + { + uint8_t* ptr = m_from ? m_from : m_buffer.data(); + const uint32_t* table = reinterpret_cast( + &ptr[0] + sizeof(_inner_::header) + sizeof(staticData)); + const uint32_t offset = table[static_cast(id)]; + if (offset == 0) + throw std::logic_error("There is no field '" + + std::string(getIdString(id)) + "' in the packet"); + return reinterpret_cast(&ptr[0] + offset + sizeof(uint32_t)); + } + uint32_t getSizeById(const ids& id) const + { + const uint8_t* ptr = m_from ? m_from : m_buffer.data(); + const uint32_t* table = reinterpret_cast( + &ptr[0] + sizeof(_inner_::header) + sizeof(staticData)); + const uint32_t offset = table[static_cast(id)]; + if (offset == 0) + return 0; + else + return *reinterpret_cast(&ptr[0] + offset); + } + void addDataById(const ids& id, const uint32_t size) + { + if (m_from) + throw std::logic_error("We cannot edit received packets"); + uint32_t* table = reinterpret_cast( + &m_buffer[0] + sizeof(_inner_::header) + sizeof(staticData)); + const uint32_t offset = table[static_cast(id)]; + if (offset != 0) + return; + const uint32_t newOffset = static_cast(m_buffer.size()); + m_buffer.resize(m_buffer.size() + sizeof(uint32_t) + size); + table = reinterpret_cast( + &m_buffer[0] + sizeof(_inner_::header) + sizeof(staticData)); + table[static_cast(id)] = newOffset; + *reinterpret_cast(&m_buffer[0] + newOffset) = size; + } + + uint32_t size_raw() const + { + return getSizeById(ids::raw); + } + bool has_raw() const + { + return getSizeById(ids::raw) != 0; + } + void add_raw(const uint32_t size) + { + addDataById(ids::raw, size); + } + const void* get_raw() + { + return getDataById(ids::raw); +} + void set_raw(const void* raw) + { + const uint32_t size = getSizeById(ids::raw); + if (size == 0) + throw std::logic_error("Zero size"); + const uint8_t* src = reinterpret_cast(raw); + uint8_t* dst = reinterpret_cast(getDataById(ids::raw)); + for (uint32_t i = 0; i < size; i++) + dst[i] = src[i]; + } + + uint32_t size_arr() const + { + return getSizeById(ids::arr) / sizeof(uint32_t); + } + bool has_arr() const + { + return getSizeById(ids::arr) != 0; + } + void add_arr(const uint32_t size) + { + addDataById(ids::arr, size * sizeof(uint32_t)); + } + const uint32_t* get_arr() + { + return reinterpret_cast(getDataById(ids::arr)); + } + const uint32_t& get_arr(const uint32_t index) + { + const uint32_t* ptr = reinterpret_cast(getDataById(ids::arr)); + if (!ptr) + throw std::logic_error("Nullptr"); + return ptr[index]; +} + void set_arr(const uint32_t* arr) + { + const uint32_t size = getSizeById(ids::arr); + const uint8_t* src = reinterpret_cast(arr); + uint8_t* dst = reinterpret_cast(getDataById(ids::arr)); + for (uint32_t i = 0; i < size; i++) + dst[i] = src[i]; + } + void set_arr(const uint32_t index, const uint32_t& element) + { + uint32_t* ptr = reinterpret_cast(getDataById(ids::arr)); + if (!ptr) + throw std::logic_error("Nullptr"); + ptr[index] = element; + } + + uint32_t size_var() const + { + return sizeof(uint16_t); + } + bool has_var() const + { + return true; + } + void add_var() + { + } + const uint16_t& get_var() + { + const staticData* data = m_from + ? reinterpret_cast(&m_from[sizeof(_inner_::header)]) + : reinterpret_cast(&m_buffer[sizeof(_inner_::header)]); + return data->var; +} + void set_var(const uint16_t& var) + { + staticData* data = reinterpret_cast(&m_buffer[sizeof(_inner_::header)]); + data->var = var; + } + + bool from(const void* ptr) + { + if (!ptr) + return false; + const _inner_::header* h = reinterpret_cast(ptr); + if (h->signature0 != 'i' || + h->signature1 != 'b' || + h->version != 1) + return false; + if (!m_buffer.empty()) + m_buffer.clear(); + m_from = reinterpret_cast(const_cast(ptr)); + return true; + } + void* to() + { + if (m_from) + return nullptr; + else + return m_buffer.data(); + } + std::unique_ptr to(const uint32_t compression) + { + switch (compression) + { + case INB_NO_COMPRESSION: + return nullptr; + case INB_TABLE_COMPRESSION: + return nullptr; + case INB_FULL_COMPRESSION: + return nullptr; + default: + break; + } + return nullptr; + } + uint32_t size() const + { + if (m_from) + return 0; + else + return static_cast(m_buffer.size()); + } + +private: + #pragma pack(push, 1) + struct staticData + { + uint16_t var; + }; + #pragma pack(pop) + + uint8_t* m_from = nullptr; + std::vector m_buffer; + const uint16_t m_tableSize = 2; +}; + class Packet { public: void create(const uint32_t reserve = 0) { + m_from = nullptr; m_buffer.reserve(reserve); - m_buffer.resize(sizeof(_inner_::header) + sizeof(staticData)); + m_buffer.resize(sizeof(_inner_::header) + sizeof(m_tableSize) * sizeof(uint32_t) + sizeof(staticData)); _inner_::header *h = reinterpret_cast<_inner_::header*>(&m_buffer[0]); h->signature0 = 'i'; h->signature1 = 'b'; h->version = 1; h->compression = INB_NO_COMPRESSION; - h->tableSize = 0; + h->tableSize = m_tableSize; + if (m_tableSize) + { + uint32_t* table = reinterpret_cast( + &m_buffer[0] + sizeof(_inner_::header)+sizeof(staticData)); + for (uint32_t i = 0; i < m_tableSize; i++) + table[i] = 0; + } } + enum class ids + { + vBytes, + vUint8, + point2f, + vArray, + _size_ + }; + const char* getIdString(const ids& id) const + { + switch (id) + { + case ids::vBytes: return "vBytes"; + case ids::vUint8: return "vUint8"; + case ids::point2f: return "point2f"; + case ids::vArray: return "vArray"; + default: return "_?unknown_id?_"; + } + } + void* getDataById(const ids& id) + { + uint8_t* ptr = m_from ? m_from : m_buffer.data(); + const uint32_t* table = reinterpret_cast( + &ptr[0] + sizeof(_inner_::header) + sizeof(staticData)); + const uint32_t offset = table[static_cast(id)]; + if (offset == 0) + throw std::logic_error("There is no field '" + + std::string(getIdString(id)) + "' in the packet"); + return reinterpret_cast(&ptr[0] + offset + sizeof(uint32_t)); + } + uint32_t getSizeById(const ids& id) const + { + const uint8_t* ptr = m_from ? m_from : m_buffer.data(); + const uint32_t* table = reinterpret_cast( + &ptr[0] + sizeof(_inner_::header) + sizeof(staticData)); + const uint32_t offset = table[static_cast(id)]; + if (offset == 0) + return 0; + else + return *reinterpret_cast(&ptr[0] + offset); + } + void addDataById(const ids& id, const uint32_t size) + { + if (m_from) + throw std::logic_error("We cannot edit received packets"); + uint32_t* table = reinterpret_cast( + &m_buffer[0] + sizeof(_inner_::header) + sizeof(staticData)); + const uint32_t offset = table[static_cast(id)]; + if (offset != 0) + return; + const uint32_t newOffset = static_cast(m_buffer.size()); + m_buffer.resize(m_buffer.size() + sizeof(uint32_t) + size); + table = reinterpret_cast( + &m_buffer[0] + sizeof(_inner_::header) + sizeof(staticData)); + table[static_cast(id)] = newOffset; + *reinterpret_cast(&m_buffer[0] + newOffset) = size; + } + + uint32_t size_vUint32() const + { + return sizeof(uint32_t); + } bool has_vUint32() const { return true; } void add_vUint32() - {} - const uint32_t& get_vUint32() const + { + } + const uint32_t& get_vUint32() { const staticData* data = m_from ? reinterpret_cast(&m_from[sizeof(_inner_::header)]) : reinterpret_cast(&m_buffer[sizeof(_inner_::header)]); return data->vUint32; - } +} void set_vUint32(const uint32_t& vUint32) { staticData* data = reinterpret_cast(&m_buffer[sizeof(_inner_::header)]); data->vUint32 = vUint32; } + uint32_t size_vBytes() const + { + return getSizeById(ids::vBytes); + } + bool has_vBytes() const + { + return getSizeById(ids::vBytes) != 0; + } + void add_vBytes(const uint32_t size) + { + addDataById(ids::vBytes, size); + } + const void* get_vBytes() + { + return getDataById(ids::vBytes); +} + void set_vBytes(const void* vBytes) + { + const uint32_t size = getSizeById(ids::vBytes); + if (size == 0) + throw std::logic_error("Zero size"); + const uint8_t* src = reinterpret_cast(vBytes); + uint8_t* dst = reinterpret_cast(getDataById(ids::vBytes)); + for (uint32_t i = 0; i < size; i++) + dst[i] = src[i]; + } + + uint32_t size_vUint8() const + { + return getSizeById(ids::vUint8) / sizeof(uint8_t); + } bool has_vUint8() const { - return true; + return getSizeById(ids::vUint8) != 0; } void add_vUint8() - {} - const uint8_t& get_vUint8() const { - const staticData* data = m_from - ? reinterpret_cast(&m_from[sizeof(_inner_::header)]) - : reinterpret_cast(&m_buffer[sizeof(_inner_::header)]); - return data->vUint8; + addDataById(ids::vUint8, sizeof(uint8_t)); } + const uint8_t& get_vUint8() + { + return *reinterpret_cast(getDataById(ids::vUint8)); +} void set_vUint8(const uint8_t& vUint8) { - staticData* data = reinterpret_cast(&m_buffer[sizeof(_inner_::header)]); - data->vUint8 = vUint8; + *reinterpret_cast(getDataById(ids::vUint8)) = vUint8; } + uint32_t size_vArray() const + { + return getSizeById(ids::vArray) / sizeof(int64_t); + } bool has_vArray() const { - return true; + return getSizeById(ids::vArray) != 0; } - void add_vArray() - {} - const int64_t& get_vArray() const + void add_vArray(const uint32_t size) { - const staticData* data = m_from - ? reinterpret_cast(&m_from[sizeof(_inner_::header)]) - : reinterpret_cast(&m_buffer[sizeof(_inner_::header)]); - return data->vArray; + addDataById(ids::vArray, size * sizeof(int64_t)); } - void set_vArray(const int64_t& vArray) + const int64_t* get_vArray() { - staticData* data = reinterpret_cast(&m_buffer[sizeof(_inner_::header)]); - data->vArray = vArray; + return reinterpret_cast(getDataById(ids::vArray)); + } + const int64_t& get_vArray(const uint32_t index) + { + const int64_t* ptr = reinterpret_cast(getDataById(ids::vArray)); + if (!ptr) + throw std::logic_error("Nullptr"); + return ptr[index]; +} + void set_vArray(const int64_t* vArray) + { + const uint32_t size = getSizeById(ids::vArray); + const uint8_t* src = reinterpret_cast(vArray); + uint8_t* dst = reinterpret_cast(getDataById(ids::vArray)); + for (uint32_t i = 0; i < size; i++) + dst[i] = src[i]; + } + void set_vArray(const uint32_t index, const int64_t& element) + { + int64_t* ptr = reinterpret_cast(getDataById(ids::vArray)); + if (!ptr) + throw std::logic_error("Nullptr"); + ptr[index] = element; } bool from(const void* ptr) @@ -122,10 +467,9 @@ class Packet h->signature1 != 'b' || h->version != 1) return false; - if (!m_buffer.empty()) m_buffer.clear(); - m_from = reinterpret_cast(ptr); + m_from = reinterpret_cast(const_cast(ptr)); return true; } void* to() @@ -163,14 +507,12 @@ class Packet struct staticData { uint32_t vUint32; - uint8_t vUint8; - int64_t vArray; }; #pragma pack(pop) - const uint8_t* m_from = nullptr; + uint8_t* m_from = nullptr; std::vector m_buffer; - uint32_t m_tableOffset = 0; + const uint16_t m_tableSize = 4; }; class Vec2f @@ -178,48 +520,66 @@ class Vec2f public: void create(const uint32_t reserve = 0) { + m_from = nullptr; m_buffer.reserve(reserve); - m_buffer.resize(sizeof(_inner_::header) + sizeof(staticData)); + m_buffer.resize(sizeof(_inner_::header) + sizeof(m_tableSize) * sizeof(uint32_t) + sizeof(staticData)); _inner_::header *h = reinterpret_cast<_inner_::header*>(&m_buffer[0]); h->signature0 = 'i'; h->signature1 = 'b'; h->version = 1; h->compression = INB_NO_COMPRESSION; - h->tableSize = 0; + h->tableSize = m_tableSize; + if (m_tableSize) + { + uint32_t* table = reinterpret_cast( + &m_buffer[0] + sizeof(_inner_::header)+sizeof(staticData)); + for (uint32_t i = 0; i < m_tableSize; i++) + table[i] = 0; + } } + uint32_t size_x() const + { + return sizeof(float); + } bool has_x() const { return true; } void add_x() - {} - const float& get_x() const + { + } + const float& get_x() { const staticData* data = m_from ? reinterpret_cast(&m_from[sizeof(_inner_::header)]) : reinterpret_cast(&m_buffer[sizeof(_inner_::header)]); return data->x; - } +} void set_x(const float& x) { staticData* data = reinterpret_cast(&m_buffer[sizeof(_inner_::header)]); data->x = x; } + uint32_t size_y() const + { + return sizeof(float); + } bool has_y() const { return true; } void add_y() - {} - const float& get_y() const + { + } + const float& get_y() { const staticData* data = m_from ? reinterpret_cast(&m_from[sizeof(_inner_::header)]) : reinterpret_cast(&m_buffer[sizeof(_inner_::header)]); return data->y; - } +} void set_y(const float& y) { staticData* data = reinterpret_cast(&m_buffer[sizeof(_inner_::header)]); @@ -235,10 +595,9 @@ class Vec2f h->signature1 != 'b' || h->version != 1) return false; - if (!m_buffer.empty()) m_buffer.clear(); - m_from = reinterpret_cast(ptr); + m_from = reinterpret_cast(const_cast(ptr)); return true; } void* to() @@ -280,9 +639,9 @@ class Vec2f }; #pragma pack(pop) - const uint8_t* m_from = nullptr; + uint8_t* m_from = nullptr; std::vector m_buffer; - uint32_t m_tableOffset = 0; + const uint16_t m_tableSize = 0; }; class Vec3i @@ -290,71 +649,141 @@ class Vec3i public: void create(const uint32_t reserve = 0) { + m_from = nullptr; m_buffer.reserve(reserve); - m_buffer.resize(sizeof(_inner_::header) + sizeof(staticData)); + m_buffer.resize(sizeof(_inner_::header) + sizeof(m_tableSize) * sizeof(uint32_t)); _inner_::header *h = reinterpret_cast<_inner_::header*>(&m_buffer[0]); h->signature0 = 'i'; h->signature1 = 'b'; h->version = 1; h->compression = INB_NO_COMPRESSION; - h->tableSize = 0; + h->tableSize = m_tableSize; + if (m_tableSize) + { + uint32_t* table = reinterpret_cast( + &m_buffer[0] + sizeof(_inner_::header)); + for (uint32_t i = 0; i < m_tableSize; i++) + table[i] = 0; + } + } + + enum class ids + { + x, + y, + z, + _size_ + }; + const char* getIdString(const ids& id) const + { + switch (id) + { + case ids::x: return "x"; + case ids::y: return "y"; + case ids::z: return "z"; + default: return "_?unknown_id?_"; + } + } + void* getDataById(const ids& id) + { + uint8_t* ptr = m_from ? m_from : m_buffer.data(); + const uint32_t* table = reinterpret_cast( + &ptr[0] + sizeof(_inner_::header)); + const uint32_t offset = table[static_cast(id)]; + if (offset == 0) + throw std::logic_error("There is no field '" + + std::string(getIdString(id)) + "' in the packet"); + return reinterpret_cast(&ptr[0] + offset + sizeof(uint32_t)); + } + uint32_t getSizeById(const ids& id) const + { + const uint8_t* ptr = m_from ? m_from : m_buffer.data(); + const uint32_t* table = reinterpret_cast( + &ptr[0] + sizeof(_inner_::header)); + const uint32_t offset = table[static_cast(id)]; + if (offset == 0) + return 0; + else + return *reinterpret_cast(&ptr[0] + offset); + } + void addDataById(const ids& id, const uint32_t size) + { + if (m_from) + throw std::logic_error("We cannot edit received packets"); + uint32_t* table = reinterpret_cast( + &m_buffer[0] + sizeof(_inner_::header)); + const uint32_t offset = table[static_cast(id)]; + if (offset != 0) + return; + const uint32_t newOffset = static_cast(m_buffer.size()); + m_buffer.resize(m_buffer.size() + sizeof(uint32_t) + size); + table = reinterpret_cast( + &m_buffer[0] + sizeof(_inner_::header)); + table[static_cast(id)] = newOffset; + *reinterpret_cast(&m_buffer[0] + newOffset) = size; } + uint32_t size_x() const + { + return getSizeById(ids::x) / sizeof(int32_t); + } bool has_x() const { - return true; + return getSizeById(ids::x) != 0; } void add_x() - {} - const int32_t& get_x() const { - const staticData* data = m_from - ? reinterpret_cast(&m_from[sizeof(_inner_::header)]) - : reinterpret_cast(&m_buffer[sizeof(_inner_::header)]); - return data->x; + addDataById(ids::x, sizeof(int32_t)); } + const int32_t& get_x() + { + return *reinterpret_cast(getDataById(ids::x)); +} void set_x(const int32_t& x) { - staticData* data = reinterpret_cast(&m_buffer[sizeof(_inner_::header)]); - data->x = x; + *reinterpret_cast(getDataById(ids::x)) = x; } + uint32_t size_y() const + { + return getSizeById(ids::y) / sizeof(int32_t); + } bool has_y() const { - return true; + return getSizeById(ids::y) != 0; } void add_y() - {} - const int32_t& get_y() const { - const staticData* data = m_from - ? reinterpret_cast(&m_from[sizeof(_inner_::header)]) - : reinterpret_cast(&m_buffer[sizeof(_inner_::header)]); - return data->y; + addDataById(ids::y, sizeof(int32_t)); } + const int32_t& get_y() + { + return *reinterpret_cast(getDataById(ids::y)); +} void set_y(const int32_t& y) { - staticData* data = reinterpret_cast(&m_buffer[sizeof(_inner_::header)]); - data->y = y; + *reinterpret_cast(getDataById(ids::y)) = y; } + uint32_t size_z() const + { + return getSizeById(ids::z) / sizeof(int32_t); + } bool has_z() const { - return true; + return getSizeById(ids::z) != 0; } void add_z() - {} - const int32_t& get_z() const { - const staticData* data = m_from - ? reinterpret_cast(&m_from[sizeof(_inner_::header)]) - : reinterpret_cast(&m_buffer[sizeof(_inner_::header)]); - return data->z; + addDataById(ids::z, sizeof(int32_t)); } + const int32_t& get_z() + { + return *reinterpret_cast(getDataById(ids::z)); +} void set_z(const int32_t& z) { - staticData* data = reinterpret_cast(&m_buffer[sizeof(_inner_::header)]); - data->z = z; + *reinterpret_cast(getDataById(ids::z)) = z; } bool from(const void* ptr) @@ -366,10 +795,9 @@ class Vec3i h->signature1 != 'b' || h->version != 1) return false; - if (!m_buffer.empty()) m_buffer.clear(); - m_from = reinterpret_cast(ptr); + m_from = reinterpret_cast(const_cast(ptr)); return true; } void* to() @@ -403,18 +831,9 @@ class Vec3i } private: - #pragma pack(push, 1) - struct staticData - { - int32_t x; - int32_t y; - int32_t z; - }; - #pragma pack(pop) - - const uint8_t* m_from = nullptr; + uint8_t* m_from = nullptr; std::vector m_buffer; - uint32_t m_tableOffset = 0; + const uint16_t m_tableSize = 3; }; }