SerializationStructCompiler.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. /* Copyright The kNet Project.
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License. */
  11. /** @file SerializationStructCompiler.cpp
  12. @brief */
  13. #include <fstream>
  14. #include <sstream>
  15. #include <cassert>
  16. #include <cstring>
  17. #include "kNet/NetException.h"
  18. #include "kNet/DebugMemoryLeakCheck.h"
  19. #include "kNet/SerializationStructCompiler.h"
  20. using namespace std;
  21. namespace kNet
  22. {
  23. std::string SerializationStructCompiler::ParseToValidCSymbolName(const char *str)
  24. {
  25. stringstream ss;
  26. size_t len = strlen(str);
  27. for(size_t i = 0; i < len; ++i)
  28. if ((isalpha(str[i]) || (ss.str().length() > 0 && isdigit(str[i]))) && str[i] != ' ')
  29. ss << str[i];
  30. return ss.str();
  31. }
  32. void SerializationStructCompiler::WriteFilePreamble(std::ofstream &out)
  33. {
  34. // Write the preamble of the file.
  35. out << "#pragma once" << endl
  36. << endl
  37. << "#include \"kNet/DataDeserializer.h\"" << endl
  38. << "#include \"kNet/DataSerializer.h\"" << endl
  39. << endl;
  40. }
  41. void SerializationStructCompiler::WriteMemberDefinition(const SerializedElementDesc &elem, int level, std::ofstream &out)
  42. {
  43. string type;
  44. if (elem.type == SerialInvalid)
  45. throw kNet::NetException("Invalid element type for SerializationStructCompiler::WriteMemberDefinition!");
  46. string name = ParseToValidCSymbolName(elem.name.c_str());
  47. if (elem.type == SerialStruct || elem.type == SerialOther)
  48. type = elem.typeString;
  49. else
  50. type = SerialTypeToCTypeString(elem.type);
  51. if (type == "string")
  52. type = "std::string"; // Make a hardcoded fix for std::string so that the user doesn't have to specify 'std::string' into the XML, which would be clumsy.
  53. if (elem.varyingCount == true)
  54. out << Indent(level) << "std::vector<" << type << "> " << name << ";" << endl;
  55. else if (elem.count > 1)
  56. out << Indent(level) << type << " " << name << "[" << elem.count << "];" << endl;
  57. else
  58. out << Indent(level) << type << " " << name << ";" << endl;
  59. }
  60. void SerializationStructCompiler::WriteStructMembers(const SerializedElementDesc &elem, int level, std::ofstream &out)
  61. {
  62. assert(&elem && elem.type == SerialStruct);
  63. for(size_t i = 0; i < elem.elements.size(); ++i)
  64. {
  65. SerializedElementDesc &e = *elem.elements[i];
  66. assert(&e);
  67. WriteMemberDefinition(e, level, out);
  68. }
  69. out << endl;
  70. }
  71. void SerializationStructCompiler::WriteNestedStructs(const SerializedElementDesc &elem, int level, std::ofstream &out)
  72. {
  73. assert(&elem && elem.type == SerialStruct);
  74. for(size_t i = 0; i < elem.elements.size(); ++i)
  75. {
  76. SerializedElementDesc &e = *elem.elements[i];
  77. assert(&e);
  78. if (e.type == SerialStruct)
  79. WriteStruct(e, level, out);
  80. }
  81. }
  82. /// The 'size_t Size() const' member function for a struct returns the size of the generated structure, in bytes.
  83. void SerializationStructCompiler::WriteStructSizeMemberFunction(const SerializedElementDesc &elem, int level, std::ofstream &out)
  84. {
  85. assert(&elem && elem.type == SerialStruct);
  86. out << Indent(level) << "inline size_t Size() const" << endl
  87. << Indent(level) << "{" << endl
  88. << Indent(level+1) << "return ";
  89. for(size_t i = 0; i < elem.elements.size(); ++i)
  90. {
  91. SerializedElementDesc &e = *elem.elements[i];
  92. assert(&e);
  93. if (i > 0)
  94. out << " + ";
  95. string memberName = ParseToValidCSymbolName(e.name.c_str());
  96. if (e.varyingCount)
  97. {
  98. if (e.count % 8 != 0) // DynamicCount must be full bytes! In case of error, round up to full byte. ///\todo Support dynamicCounts at bit-level.
  99. out << (e.count + 7) / 8 << "/* Warning: DynamicCount was " << e.count << " bits, but only full bytes are supported for now.*/ + ";
  100. else
  101. out << e.count / 8 << " + ";
  102. }
  103. /*
  104. if (e.type == SerialStruct)
  105. {
  106. if (e.varyingCount)
  107. out << "kNet::SumArray(" << memberName << ", " << memberName << ".size())";
  108. else if (e.count > 1)
  109. out << "kNet::SumArray(" << memberName << ", " << e.count << ")";
  110. else
  111. out << memberName << ".Size()";
  112. }
  113. else*/ if (e.type == SerialStruct || e.type == SerialOther || e.type == SerialString)
  114. {
  115. std::string typeSerializer = "kNet::TypeSerializer<" + e.typeString + ">";
  116. if (e.varyingCount)
  117. out << "kNet::ArraySize<" << typeSerializer << " >(" << memberName << ", " << memberName << ".size())";
  118. else if (e.count > 1)
  119. out << "kNet::ArraySize(" << typeSerializer << " >(" << memberName << ", " << e.count << ")";
  120. else
  121. out << typeSerializer << "::Size(" << memberName << ")";
  122. }
  123. else
  124. {
  125. if (e.varyingCount)
  126. out << memberName << ".size()" << "*" << SerialTypeSize(e.type);
  127. else if (e.count > 1)
  128. out << e.count << "*" << SerialTypeSize(e.type);
  129. else
  130. out << SerialTypeSize(e.type);
  131. }
  132. }
  133. if (elem.elements.empty())
  134. out << "0";
  135. out << ";" << endl
  136. << Indent(level) << "}" << endl << endl;
  137. }
  138. void SerializationStructCompiler::WriteSerializeMemberFunction(/*const std::string &className, */const SerializedElementDesc &elem, int level, std::ofstream &out)
  139. {
  140. assert(&elem && elem.type == SerialStruct);
  141. out << Indent(level) << "inline void SerializeTo(kNet::DataSerializer &dst) const" << endl
  142. << Indent(level) << "{" << endl;
  143. ++level;
  144. for(size_t i = 0; i < elem.elements.size(); ++i)
  145. {
  146. SerializedElementDesc &e = *elem.elements[i];
  147. assert(&e);
  148. string memberName = ParseToValidCSymbolName(e.name.c_str());
  149. if (e.varyingCount == true)
  150. {
  151. // What type of variable will hold the varyingCount field?
  152. if (e.count != 8 && e.count != 16 && e.count != 32) ///\todo Support arbitrary bit-length varyingCounts.
  153. out << Indent(level) << "// TODO: Unsupported varyingCount field length of " << e.count << " bits used!" << endl;
  154. out << Indent(level) << "dst.Add<u" << e.count << ">(" << memberName << ".size());" << endl;
  155. }
  156. /*
  157. if (e.type == SerialStruct)
  158. {
  159. if (e.varyingCount == true)
  160. {
  161. out << Indent(level) << "for(size_t i = 0; i < " << memberName << ".size(); ++i)" << endl;
  162. out << Indent(level+1) << memberName << "[i].SerializeTo(dst);" << endl;
  163. }
  164. else if (e.count > 1)
  165. {
  166. out << Indent(level) << "for(size_t i = 0; i < " << e.count << "; ++i)" << endl;
  167. out << Indent(level+1) << memberName << "[i].SerializeTo(dst);" << endl;
  168. }
  169. else
  170. out << Indent(level) << memberName << ".SerializeTo(dst);" << endl;
  171. }
  172. else*/ if (e.type == SerialStruct || e.type == SerialOther)
  173. {
  174. std::string typeSerializer = "kNet::TypeSerializer<" + e.typeString + ">";
  175. if (e.varyingCount == true)
  176. {
  177. out << Indent(level) << "for(size_t i = 0; i < " << memberName << ".size(); ++i)" << endl;
  178. out << Indent(level+1) << typeSerializer << "::SerializeTo(dst, " << memberName << "[i]);" << endl;
  179. }
  180. else if (e.count > 1)
  181. {
  182. out << Indent(level) << "for(size_t i = 0; i < " << e.count << "; ++i)" << endl;
  183. out << Indent(level+1) << typeSerializer << "::SerializeTo(dst, " << memberName << "[i]);" << endl;
  184. }
  185. else
  186. out << Indent(level) << typeSerializer << "::SerializeTo(dst, " << memberName << ");" << endl;
  187. }
  188. else
  189. {
  190. if (e.varyingCount == true)
  191. {
  192. out << Indent(level) << "if (" << memberName << ".size() > 0)" << endl;
  193. out << Indent(level+1) << "dst.AddArray<" << SerialTypeToCTypeString(e.type) << ">(&" << memberName
  194. << "[0], " << memberName << ".size());" << endl;
  195. }
  196. else if (e.count > 1)
  197. out << Indent(level) << "dst.AddArray<" << SerialTypeToCTypeString(e.type) << ">(" << memberName
  198. << ", " << e.count << ");" << endl;
  199. else
  200. out << Indent(level) << "dst.Add<" << SerialTypeToCTypeString(e.type) << ">(" << memberName
  201. << ");" << endl;
  202. }
  203. }
  204. --level;
  205. out << Indent(level) << "}" << endl;
  206. // out << Indent(level) << "inline static void SerializeTo(knet::DataSerializer &dst, const " << className << " &src) { src.SerializeTo(dst); }"<< endl;
  207. out << endl;
  208. }
  209. void SerializationStructCompiler::WriteDeserializeMemberFunction(/*const std::string &className, */const SerializedElementDesc &elem, int level, std::ofstream &out)
  210. {
  211. assert(&elem && elem.type == SerialStruct);
  212. out << Indent(level) << "inline void DeserializeFrom(kNet::DataDeserializer &src)" << endl
  213. << Indent(level) << "{" << endl;
  214. ++level;
  215. for(size_t i = 0; i < elem.elements.size(); ++i)
  216. {
  217. SerializedElementDesc &e = *elem.elements[i];
  218. assert(&e);
  219. string memberName = ParseToValidCSymbolName(e.name.c_str());
  220. if (e.varyingCount == true)
  221. {
  222. // What type of variable will hold the varyingCount field?
  223. if (e.count != 8 && e.count != 16 && e.count != 32) ///\todo Support arbitrary bit-length varyingCounts.
  224. out << Indent(level) << "// TODO: Unsupported varyingCount field length of " << e.count << " bits used!" << endl;
  225. out << Indent(level) << memberName << ".resize(src.Read<u" << e.count << ">());" << endl;
  226. }
  227. /* if (e.type == SerialStruct)
  228. {
  229. if (e.varyingCount == true)
  230. {
  231. out << Indent(level) << "for(size_t i = 0; i < " << memberName << ".size(); ++i)" << endl;
  232. out << Indent(level+1) << memberName << "[i].DeserializeFrom(src);" << endl;
  233. }
  234. else if (e.count > 1)
  235. {
  236. out << Indent(level) << "for(size_t i = 0; i < " << e.count << "; ++i)" << endl;
  237. out << Indent(level+1) << memberName << "[i].DeserializeFrom(src);" << endl;
  238. }
  239. else
  240. out << Indent(level) << memberName << ".DeserializeFrom(src);" << endl;
  241. } */
  242. if (e.type == SerialStruct || e.type == SerialOther)
  243. {
  244. std::string typeSerializer = "kNet::TypeSerializer<" + e.typeString + ">";
  245. if (e.varyingCount == true)
  246. {
  247. out << Indent(level) << "for(size_t i = 0; i < " << memberName << ".size(); ++i)" << endl;
  248. out << Indent(level+1) << typeSerializer << "::DeserializeFrom(src, " << memberName << "[i]);" << endl;
  249. }
  250. else if (e.count > 1)
  251. {
  252. out << Indent(level) << "for(size_t i = 0; i < " << e.count << "; ++i)" << endl;
  253. out << Indent(level+1) << typeSerializer << "::DeserializeFrom(src, " << memberName << "[i]);" << endl;
  254. }
  255. else
  256. out << Indent(level) << typeSerializer << "::DeserializeFrom(src, " << memberName << ");" << endl;
  257. }
  258. else
  259. {
  260. if (e.varyingCount == true)
  261. {
  262. out << Indent(level) << "if (" << memberName << ".size() > 0)" << endl;
  263. out << Indent(level+1) << "src.ReadArray<" << SerialTypeToCTypeString(e.type) << ">(&" << memberName
  264. << "[0], " << memberName << ".size());" << endl;
  265. }
  266. else if (e.count > 1)
  267. out << Indent(level) << "src.ReadArray<" << SerialTypeToCTypeString(e.type) << ">(" << memberName
  268. << ", " << e.count << ");" << endl;
  269. else
  270. out << Indent(level) << memberName << " = src.Read<" << SerialTypeToCTypeString(e.type) << ">();" << endl;
  271. }
  272. }
  273. --level;
  274. out << Indent(level) << "}" << endl;
  275. // out << Indent(level) << "inline static void DeserializeFrom(knet::DataDeserializer &src, " << className << " &dst) { dst.DeserializeFrom(src); }"<< endl;
  276. out << endl;
  277. }
  278. void SerializationStructCompiler::WriteStruct(const SerializedElementDesc &elem, int level, std::ofstream &out)
  279. {
  280. assert(&elem && elem.type == SerialStruct);
  281. string className = string("struct S_") + ParseToValidCSymbolName(elem.name.c_str());
  282. if (level == 0)
  283. className = string("struct ") + ParseToValidCSymbolName(elem.name.c_str());
  284. out << Indent(level) << className << endl
  285. << Indent(level) << "{" << endl;
  286. WriteNestedStructs(elem, level+1, out);
  287. WriteStructMembers(elem, level+1, out);
  288. WriteStructSizeMemberFunction(elem, level+1, out);
  289. WriteSerializeMemberFunction(/*className, */elem, level+1, out);
  290. WriteDeserializeMemberFunction(/*className, */elem, level+1, out);
  291. out << Indent(level) << "};" << endl << endl;
  292. }
  293. void SerializationStructCompiler::CompileStruct(const SerializedElementDesc &structure, const char *outfile)
  294. {
  295. ofstream out(outfile);
  296. WriteFilePreamble(out);
  297. WriteStruct(structure, 0, out);
  298. }
  299. void SerializationStructCompiler::WriteMessage(const SerializedMessageDesc &message, std::ofstream &out)
  300. {
  301. string structName = string("Msg") + message.name;
  302. out << "struct " << structName << endl
  303. << "{" << endl;
  304. out << Indent(1) << structName << "()" << endl
  305. << Indent(1) << "{" << endl
  306. << Indent(2) << "InitToDefault();" << endl
  307. << Indent(1) << "}" << endl << endl;
  308. out << Indent(1) << structName << "(const char *data, size_t numBytes)" << endl
  309. << Indent(1) << "{" << endl
  310. << Indent(2) << "InitToDefault();" << endl
  311. << Indent(2) << "kNet::DataDeserializer dd(data, numBytes);" << endl
  312. << Indent(2) << "DeserializeFrom(dd);" << endl
  313. << Indent(1) << "}" << endl << endl;
  314. out << Indent(1) << "void InitToDefault()" << endl
  315. << Indent(1) << "{" << endl
  316. << Indent(2) << "reliable = defaultReliable;" << endl
  317. << Indent(2) << "inOrder = defaultInOrder;" << endl
  318. << Indent(2) << "priority = defaultPriority;" << endl
  319. << Indent(1) << "}" << endl << endl;
  320. out << Indent(1) << "enum { messageID = "<< message.id << " };" << endl;
  321. out << Indent(1) << "static inline const char * const Name() { return \"" << message.name << "\"; }" << endl << endl;
  322. out << Indent(1) << "static const bool defaultReliable = " << (message.reliable ? "true" : "false") << ";" << endl;
  323. out << Indent(1) << "static const bool defaultInOrder = " << (message.inOrder ? "true" : "false") << ";" << endl;
  324. out << Indent(1) << "static const u32 defaultPriority = " << message.priority << ";" << endl << endl;
  325. out << Indent(1) << "bool reliable;" << endl;
  326. out << Indent(1) << "bool inOrder;" << endl;
  327. out << Indent(1) << "u32 priority;" << endl << endl;
  328. WriteNestedStructs(*message.data, 1, out);
  329. WriteStructMembers(*message.data, 1, out);
  330. WriteStructSizeMemberFunction(*message.data, 1, out);
  331. WriteSerializeMemberFunction(/*structName, */*message.data, 1, out);
  332. WriteDeserializeMemberFunction(/*structName, */*message.data, 1, out);
  333. out << "};" << endl << endl;
  334. }
  335. void SerializationStructCompiler::CompileMessage(const SerializedMessageDesc &message, const char *outfile)
  336. {
  337. ofstream out(outfile);
  338. WriteFilePreamble(out);
  339. WriteMessage(message, out);
  340. }
  341. std::string SerializationStructCompiler::Indent(int level)
  342. {
  343. stringstream ss;
  344. for(int i = 0; i < level; ++i)
  345. ss << "\t";
  346. return ss.str();
  347. }
  348. } // ~kNet