SerializationStructCompiler.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  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. int childStructIndex = 1;
  64. for(size_t i = 0; i < elem.elements.size(); ++i)
  65. {
  66. SerializedElementDesc &e = *elem.elements[i];
  67. assert(&e);
  68. WriteMemberDefinition(e, level, out);
  69. }
  70. out << endl;
  71. }
  72. void SerializationStructCompiler::WriteNestedStructs(const SerializedElementDesc &elem, int level, std::ofstream &out)
  73. {
  74. assert(&elem && elem.type == SerialStruct);
  75. for(size_t i = 0; i < elem.elements.size(); ++i)
  76. {
  77. SerializedElementDesc &e = *elem.elements[i];
  78. assert(&e);
  79. if (e.type == SerialStruct)
  80. WriteStruct(e, level, out);
  81. }
  82. }
  83. /// The 'size_t Size() const' member function for a struct returns the size of the generated structure, in bytes.
  84. void SerializationStructCompiler::WriteStructSizeMemberFunction(const SerializedElementDesc &elem, int level, std::ofstream &out)
  85. {
  86. assert(&elem && elem.type == SerialStruct);
  87. out << Indent(level) << "inline size_t Size() const" << endl
  88. << Indent(level) << "{" << endl
  89. << Indent(level+1) << "return ";
  90. for(size_t i = 0; i < elem.elements.size(); ++i)
  91. {
  92. SerializedElementDesc &e = *elem.elements[i];
  93. assert(&e);
  94. if (i > 0)
  95. out << " + ";
  96. string memberName = ParseToValidCSymbolName(e.name.c_str());
  97. if (e.varyingCount)
  98. {
  99. 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.
  100. out << (e.count + 7) / 8 << "/* Warning: DynamicCount was " << e.count << " bits, but only full bytes are supported for now.*/ + ";
  101. else
  102. out << e.count / 8 << " + ";
  103. }
  104. /*
  105. if (e.type == SerialStruct)
  106. {
  107. if (e.varyingCount)
  108. out << "kNet::SumArray(" << memberName << ", " << memberName << ".size())";
  109. else if (e.count > 1)
  110. out << "kNet::SumArray(" << memberName << ", " << e.count << ")";
  111. else
  112. out << memberName << ".Size()";
  113. }
  114. else*/ if (e.type == SerialStruct || e.type == SerialOther || e.type == SerialString)
  115. {
  116. std::string typeSerializer = "kNet::TypeSerializer<" + e.typeString + ">";
  117. if (e.varyingCount)
  118. out << "kNet::ArraySize<" << typeSerializer << " >(" << memberName << ", " << memberName << ".size())";
  119. else if (e.count > 1)
  120. out << "kNet::ArraySize(" << typeSerializer << " >(" << memberName << ", " << e.count << ")";
  121. else
  122. out << typeSerializer << "::Size(" << memberName << ")";
  123. }
  124. else
  125. {
  126. if (e.varyingCount)
  127. out << memberName << ".size()" << "*" << SerialTypeSize(e.type);
  128. else if (e.count > 1)
  129. out << e.count << "*" << SerialTypeSize(e.type);
  130. else
  131. out << SerialTypeSize(e.type);
  132. }
  133. }
  134. if (elem.elements.size() == 0)
  135. out << "0";
  136. out << ";" << endl
  137. << Indent(level) << "}" << endl << endl;
  138. }
  139. void SerializationStructCompiler::WriteSerializeMemberFunction(/*const std::string &className, */const SerializedElementDesc &elem, int level, std::ofstream &out)
  140. {
  141. assert(&elem && elem.type == SerialStruct);
  142. out << Indent(level) << "inline void SerializeTo(kNet::DataSerializer &dst) const" << endl
  143. << Indent(level) << "{" << endl;
  144. ++level;
  145. for(size_t i = 0; i < elem.elements.size(); ++i)
  146. {
  147. SerializedElementDesc &e = *elem.elements[i];
  148. assert(&e);
  149. string memberName = ParseToValidCSymbolName(e.name.c_str());
  150. if (e.varyingCount == true)
  151. {
  152. // What type of variable will hold the varyingCount field?
  153. if (e.count != 8 && e.count != 16 && e.count != 32) ///\todo Support arbitrary bit-length varyingCounts.
  154. out << Indent(level) << "// TODO: Unsupported varyingCount field length of " << e.count << " bits used!" << endl;
  155. out << Indent(level) << "dst.Add<u" << e.count << ">(" << memberName << ".size());" << endl;
  156. }
  157. /*
  158. if (e.type == SerialStruct)
  159. {
  160. if (e.varyingCount == true)
  161. {
  162. out << Indent(level) << "for(size_t i = 0; i < " << memberName << ".size(); ++i)" << endl;
  163. out << Indent(level+1) << memberName << "[i].SerializeTo(dst);" << endl;
  164. }
  165. else if (e.count > 1)
  166. {
  167. out << Indent(level) << "for(size_t i = 0; i < " << e.count << "; ++i)" << endl;
  168. out << Indent(level+1) << memberName << "[i].SerializeTo(dst);" << endl;
  169. }
  170. else
  171. out << Indent(level) << memberName << ".SerializeTo(dst);" << endl;
  172. }
  173. else*/ if (e.type == SerialStruct || e.type == SerialOther)
  174. {
  175. std::string typeSerializer = "kNet::TypeSerializer<" + e.typeString + ">";
  176. if (e.varyingCount == true)
  177. {
  178. out << Indent(level) << "for(size_t i = 0; i < " << memberName << ".size(); ++i)" << endl;
  179. out << Indent(level+1) << typeSerializer << "::SerializeTo(dst, " << memberName << "[i]);" << endl;
  180. }
  181. else if (e.count > 1)
  182. {
  183. out << Indent(level) << "for(size_t i = 0; i < " << e.count << "; ++i)" << endl;
  184. out << Indent(level+1) << typeSerializer << "::SerializeTo(dst, " << memberName << "[i]);" << endl;
  185. }
  186. else
  187. out << Indent(level) << typeSerializer << "::SerializeTo(dst, " << memberName << ");" << endl;
  188. }
  189. else
  190. {
  191. if (e.varyingCount == true)
  192. {
  193. out << Indent(level) << "if (" << memberName << ".size() > 0)" << endl;
  194. out << Indent(level+1) << "dst.AddArray<" << SerialTypeToCTypeString(e.type) << ">(&" << memberName
  195. << "[0], " << memberName << ".size());" << endl;
  196. }
  197. else if (e.count > 1)
  198. out << Indent(level) << "dst.AddArray<" << SerialTypeToCTypeString(e.type) << ">(" << memberName
  199. << ", " << e.count << ");" << endl;
  200. else
  201. out << Indent(level) << "dst.Add<" << SerialTypeToCTypeString(e.type) << ">(" << memberName
  202. << ");" << endl;
  203. }
  204. }
  205. --level;
  206. out << Indent(level) << "}" << endl;
  207. // out << Indent(level) << "inline static void SerializeTo(knet::DataSerializer &dst, const " << className << " &src) { src.SerializeTo(dst); }"<< endl;
  208. out << endl;
  209. }
  210. void SerializationStructCompiler::WriteDeserializeMemberFunction(/*const std::string &className, */const SerializedElementDesc &elem, int level, std::ofstream &out)
  211. {
  212. assert(&elem && elem.type == SerialStruct);
  213. out << Indent(level) << "inline void DeserializeFrom(kNet::DataDeserializer &src)" << endl
  214. << Indent(level) << "{" << endl;
  215. ++level;
  216. for(size_t i = 0; i < elem.elements.size(); ++i)
  217. {
  218. SerializedElementDesc &e = *elem.elements[i];
  219. assert(&e);
  220. string memberName = ParseToValidCSymbolName(e.name.c_str());
  221. if (e.varyingCount == true)
  222. {
  223. // What type of variable will hold the varyingCount field?
  224. if (e.count != 8 && e.count != 16 && e.count != 32) ///\todo Support arbitrary bit-length varyingCounts.
  225. out << Indent(level) << "// TODO: Unsupported varyingCount field length of " << e.count << " bits used!" << endl;
  226. out << Indent(level) << memberName << ".resize(src.Read<u" << e.count << ">());" << endl;
  227. }
  228. /* if (e.type == SerialStruct)
  229. {
  230. if (e.varyingCount == true)
  231. {
  232. out << Indent(level) << "for(size_t i = 0; i < " << memberName << ".size(); ++i)" << endl;
  233. out << Indent(level+1) << memberName << "[i].DeserializeFrom(src);" << endl;
  234. }
  235. else if (e.count > 1)
  236. {
  237. out << Indent(level) << "for(size_t i = 0; i < " << e.count << "; ++i)" << endl;
  238. out << Indent(level+1) << memberName << "[i].DeserializeFrom(src);" << endl;
  239. }
  240. else
  241. out << Indent(level) << memberName << ".DeserializeFrom(src);" << endl;
  242. } */
  243. if (e.type == SerialStruct || e.type == SerialOther)
  244. {
  245. std::string typeSerializer = "kNet::TypeSerializer<" + e.typeString + ">";
  246. if (e.varyingCount == true)
  247. {
  248. out << Indent(level) << "for(size_t i = 0; i < " << memberName << ".size(); ++i)" << endl;
  249. out << Indent(level+1) << typeSerializer << "::DeserializeFrom(src, " << memberName << "[i]);" << endl;
  250. }
  251. else if (e.count > 1)
  252. {
  253. out << Indent(level) << "for(size_t i = 0; i < " << e.count << "; ++i)" << endl;
  254. out << Indent(level+1) << typeSerializer << "::DeserializeFrom(src, " << memberName << "[i]);" << endl;
  255. }
  256. else
  257. out << Indent(level) << typeSerializer << "::DeserializeFrom(src, " << memberName << ");" << endl;
  258. }
  259. else
  260. {
  261. if (e.varyingCount == true)
  262. {
  263. out << Indent(level) << "if (" << memberName << ".size() > 0)" << endl;
  264. out << Indent(level+1) << "src.ReadArray<" << SerialTypeToCTypeString(e.type) << ">(&" << memberName
  265. << "[0], " << memberName << ".size());" << endl;
  266. }
  267. else if (e.count > 1)
  268. out << Indent(level) << "src.ReadArray<" << SerialTypeToCTypeString(e.type) << ">(" << memberName
  269. << ", " << e.count << ");" << endl;
  270. else
  271. out << Indent(level) << memberName << " = src.Read<" << SerialTypeToCTypeString(e.type) << ">();" << endl;
  272. }
  273. }
  274. --level;
  275. out << Indent(level) << "}" << endl;
  276. // out << Indent(level) << "inline static void DeserializeFrom(knet::DataDeserializer &src, " << className << " &dst) { dst.DeserializeFrom(src); }"<< endl;
  277. out << endl;
  278. }
  279. void SerializationStructCompiler::WriteStruct(const SerializedElementDesc &elem, int level, std::ofstream &out)
  280. {
  281. assert(&elem && elem.type == SerialStruct);
  282. string className = string("struct S_") + ParseToValidCSymbolName(elem.name.c_str());
  283. if (level == 0)
  284. className = string("struct ") + ParseToValidCSymbolName(elem.name.c_str());
  285. out << Indent(level) << className << endl
  286. << Indent(level) << "{" << endl;
  287. WriteNestedStructs(elem, level+1, out);
  288. WriteStructMembers(elem, level+1, out);
  289. WriteStructSizeMemberFunction(elem, level+1, out);
  290. WriteSerializeMemberFunction(/*className, */elem, level+1, out);
  291. WriteDeserializeMemberFunction(/*className, */elem, level+1, out);
  292. out << Indent(level) << "};" << endl << endl;
  293. }
  294. void SerializationStructCompiler::CompileStruct(const SerializedElementDesc &structure, const char *outfile)
  295. {
  296. ofstream out(outfile);
  297. WriteFilePreamble(out);
  298. WriteStruct(structure, 0, out);
  299. }
  300. void SerializationStructCompiler::WriteMessage(const SerializedMessageDesc &message, std::ofstream &out)
  301. {
  302. string structName = string("Msg") + message.name;
  303. out << "struct " << structName << endl
  304. << "{" << endl;
  305. out << Indent(1) << structName << "()" << endl
  306. << Indent(1) << "{" << endl
  307. << Indent(2) << "InitToDefault();" << endl
  308. << Indent(1) << "}" << endl << endl;
  309. out << Indent(1) << structName << "(const char *data, size_t numBytes)" << endl
  310. << Indent(1) << "{" << endl
  311. << Indent(2) << "InitToDefault();" << endl
  312. << Indent(2) << "kNet::DataDeserializer dd(data, numBytes);" << endl
  313. << Indent(2) << "DeserializeFrom(dd);" << endl
  314. << Indent(1) << "}" << endl << endl;
  315. out << Indent(1) << "void InitToDefault()" << endl
  316. << Indent(1) << "{" << endl
  317. << Indent(2) << "reliable = defaultReliable;" << endl
  318. << Indent(2) << "inOrder = defaultInOrder;" << endl
  319. << Indent(2) << "priority = defaultPriority;" << endl
  320. << Indent(1) << "}" << endl << endl;
  321. out << Indent(1) << "enum { messageID = "<< message.id << " };" << endl;
  322. out << Indent(1) << "static inline const char * const Name() { return \"" << message.name << "\"; }" << endl << endl;
  323. out << Indent(1) << "static const bool defaultReliable = " << (message.reliable ? "true" : "false") << ";" << endl;
  324. out << Indent(1) << "static const bool defaultInOrder = " << (message.inOrder ? "true" : "false") << ";" << endl;
  325. out << Indent(1) << "static const u32 defaultPriority = " << message.priority << ";" << endl << endl;
  326. out << Indent(1) << "bool reliable;" << endl;
  327. out << Indent(1) << "bool inOrder;" << endl;
  328. out << Indent(1) << "u32 priority;" << endl << endl;
  329. WriteNestedStructs(*message.data, 1, out);
  330. WriteStructMembers(*message.data, 1, out);
  331. WriteStructSizeMemberFunction(*message.data, 1, out);
  332. WriteSerializeMemberFunction(/*structName, */*message.data, 1, out);
  333. WriteDeserializeMemberFunction(/*structName, */*message.data, 1, out);
  334. out << "};" << endl << endl;
  335. }
  336. void SerializationStructCompiler::CompileMessage(const SerializedMessageDesc &message, const char *outfile)
  337. {
  338. ofstream out(outfile);
  339. WriteFilePreamble(out);
  340. WriteMessage(message, out);
  341. }
  342. std::string SerializationStructCompiler::Indent(int level)
  343. {
  344. stringstream ss;
  345. for(int i = 0; i < level; ++i)
  346. ss << "\t";
  347. return ss.str();
  348. }
  349. } // ~kNet