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