A collection of basic/generally desirable code I use across multiple C++ projects.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

319 lines
13 KiB

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
  1. #ifdef ULE_CONFIG_OPTION_SERIALIZATION
  2. #include <fast_float/fast_float.h>
  3. #include "types.h"
  4. #include "serialize.h"
  5. #include "string.h"
  6. #include "print.h"
  7. static inline const char* getFormatStringOut(u8 v) { ULE_TYPES_H_FTAG; return "%hu\n"; }
  8. static inline const char* getFormatStringOut(u16 v) { ULE_TYPES_H_FTAG; return "%hu\n"; }
  9. static inline const char* getFormatStringOut(u32 v) { ULE_TYPES_H_FTAG; return "%u\n"; }
  10. static inline const char* getFormatStringOut(u64 v) { ULE_TYPES_H_FTAG; return "%llu\n"; }
  11. static inline const char* getFormatStringOut(s8 v) { ULE_TYPES_H_FTAG; return "%hd\n"; }
  12. static inline const char* getFormatStringOut(s16 v) { ULE_TYPES_H_FTAG; return "%hd\n"; }
  13. static inline const char* getFormatStringOut(s32 v) { ULE_TYPES_H_FTAG; return "%d\n"; }
  14. static inline const char* getFormatStringOut(s64 v) { ULE_TYPES_H_FTAG; return "%lld\n"; }
  15. static inline const char* getFormatStringOut(float v) { ULE_TYPES_H_FTAG; return "%f\n"; }
  16. static inline const char* getFormatStringOut(double v) { ULE_TYPES_H_FTAG; return "%f\n"; }
  17. // important constraint - strings need to be wrapped in double-quotes.
  18. // the sentinel value 'null' without quotations is used to denote null values, which means
  19. // if strings were not wrapped in double quotes, you would not be able to distinguish null
  20. // values from the literal string "null".
  21. static inline const char* getFormatStringOut(char* v) { ULE_TYPES_H_FTAG; return "\"%s\"\n"; }
  22. static inline const char* getFormatStringOut(const char* v) { ULE_TYPES_H_FTAG; return "\"%s\"\n"; }
  23. #ifdef _USING_GLM_TYPES__
  24. static inline const char* getFormatStringOut(glm::vec<2, float, (glm::qualifier) 3> v) { ULE_TYPES_H_FTAG; return "%f %f\n"; }
  25. static inline const char* getFormatStringOut(glm::vec<3, float, (glm::qualifier) 3> v) { ULE_TYPES_H_FTAG; return "%f %f %f\n"; }
  26. static inline const char* getFormatStringOut(glm::vec<4, float, (glm::qualifier) 3> v) { ULE_TYPES_H_FTAG; return "%f %f %f %f\n"; }
  27. static inline const char* getFormatStringOut(glm::mat<2, 2, float, (glm::qualifier) 3> v) { ULE_TYPES_H_FTAG; return "%f %f %f %f\n"; }
  28. static inline const char* getFormatStringOut(glm::mat<3, 3, float, (glm::qualifier) 3> v) { ULE_TYPES_H_FTAG; return "%f %f %f %f %f %f %f %f %f\n"; }
  29. static inline const char* getFormatStringOut(glm::mat<4, 4, float, (glm::qualifier) 3> v) { ULE_TYPES_H_FTAG; return "%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n"; }
  30. #endif
  31. #define SERIALIZE_H_FUNC_BODY str->appendf(getFormatStringOut(v), v);
  32. void serialize(String* str, u8 v) { ULE_TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
  33. void serialize(String* str, u16 v) { ULE_TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
  34. void serialize(String* str, u32 v) { ULE_TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
  35. void serialize(String* str, u64 v) { ULE_TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
  36. void serialize(String* str, s8 v) { ULE_TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
  37. void serialize(String* str, s16 v) { ULE_TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
  38. void serialize(String* str, s32 v) { ULE_TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
  39. void serialize(String* str, s64 v) { ULE_TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
  40. void serialize(String* str, float v) { ULE_TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
  41. void serialize(String* str, double v) { ULE_TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
  42. extern template<typename T> // @TODO do not use a template for this.
  43. static inline void deserializeInteger(char** buffer, T* v) {
  44. ULE_TYPES_H_FTAG;
  45. char* _buffer = *buffer;
  46. T value = 0;
  47. // skip leading whitespace - all our functions do this, so gotta
  48. while (String::isAsciiWhitespace(*_buffer)) {
  49. _buffer++;
  50. }
  51. // check the first character for a negative sign
  52. bool negative = false;
  53. if (_buffer[0] == '-') {
  54. negative = true;
  55. _buffer++;
  56. }
  57. // parse the digits of the number. doesn't account for overflow
  58. while (String::isDigit(*_buffer)) {
  59. value = 10 * value + (*_buffer++ - '0');
  60. }
  61. // make it negative if the first character was '-'
  62. if (negative) value *= -1;
  63. // store the value back into v
  64. *v = value;
  65. // if the original pointer is the same as the current, we didn't parse anything
  66. massert(_buffer != *buffer, "tried to parse an integer, and found nothing");
  67. // report back how far we advanced the buffer
  68. *buffer = _buffer;
  69. }
  70. // just for integers, signed/unsigned including size_t
  71. #define SERIALIZE_H_DESERIALIZE_FUNC_BODY deserializeInteger(buffer, v);
  72. void deserialize(char** buffer, u8* v) { SERIALIZE_H_DESERIALIZE_FUNC_BODY }
  73. void deserialize(char** buffer, u16* v) { SERIALIZE_H_DESERIALIZE_FUNC_BODY }
  74. void deserialize(char** buffer, u32* v) { SERIALIZE_H_DESERIALIZE_FUNC_BODY }
  75. void deserialize(char** buffer, u64* v) { SERIALIZE_H_DESERIALIZE_FUNC_BODY }
  76. void deserialize(char** buffer, s8* v) { SERIALIZE_H_DESERIALIZE_FUNC_BODY }
  77. void deserialize(char** buffer, s16* v) { SERIALIZE_H_DESERIALIZE_FUNC_BODY }
  78. void deserialize(char** buffer, s32* v) { SERIALIZE_H_DESERIALIZE_FUNC_BODY }
  79. void deserialize(char** buffer, s64* v) { SERIALIZE_H_DESERIALIZE_FUNC_BODY }
  80. // base value = ceil(log10(2^64)) or ceil(log10(2^32))
  81. // is this right? lemire's paper mentions you only need 17 digits for 64 bit floats: https://lemire.me/en/publication/arxiv2101/
  82. // +1 for 'e'
  83. // +1 for '.'
  84. // +1 for '^'
  85. // +1 for '-'/'+'
  86. static const u32 BINARY32_MAX_CHARS = 14;
  87. static const u32 BINARY64_MAX_CHARS = 24;
  88. void deserialize(char** buffer, float* v) {
  89. ULE_TYPES_H_FTAG;
  90. char* _buffer = *buffer;
  91. while (String::isAsciiWhitespace(*_buffer)) _buffer++;
  92. fast_float::from_chars_result result = fast_float::from_chars(_buffer, _buffer + BINARY32_MAX_CHARS, *v);
  93. massert(result.ec == std::errc(), "failed to parse a float");
  94. *buffer = (char*) result.ptr;
  95. }
  96. void deserialize(char** buffer, double* v) {
  97. ULE_TYPES_H_FTAG;
  98. char* _buffer = *buffer;
  99. while (String::isAsciiWhitespace(*_buffer)) _buffer++;
  100. fast_float::from_chars_result result = fast_float::from_chars(_buffer, _buffer + BINARY64_MAX_CHARS, *v);
  101. massert(result.ec == std::errc(), "failed to parse a double");
  102. *buffer = (char*) result.ptr;
  103. }
  104. #ifndef _WIN32
  105. // win32 doesn't treat size_t as different than a u64, which causes ambiguous function calls
  106. static inline const char* getFormatStringOut(size_t v) { ULE_TYPES_H_FTAG; return "%lu\n"; }
  107. void serialize(String* str, size_t v) { SERIALIZE_H_FUNC_BODY }
  108. void deserialize(char** buffer, size_t* v) { SERIALIZE_H_DESERIALIZE_FUNC_BODY }
  109. #endif
  110. // STRING STUFF
  111. void serialize(String* str, char* v) {
  112. ULE_TYPES_H_FTAG;
  113. SERIALIZE_HANDLE_NULL(str, v);
  114. SERIALIZE_H_FUNC_BODY;
  115. }
  116. void serialize(String* str, const char* v) {
  117. ULE_TYPES_H_FTAG;
  118. SERIALIZE_HANDLE_NULL(str, v);
  119. SERIALIZE_H_FUNC_BODY;
  120. }
  121. #define SERIALIZE_SCRATCH_BUFFER_SIZE 2048
  122. // make this number be the largest number of bytes you can expect to deserialize when deserializing a single string, in the case when the memory allocation must be done by the deserialization code.
  123. // meaning, you don't have a pre-allocated buffer of a fixed, known size, like a char name[32] or something.
  124. //
  125. // if you call `deserialize(char** buffer, char* v)`, it's expected that you know what you're doing,
  126. // and the |buffer| won't contain more characters than you can fit in |v|.
  127. //
  128. // in the case where you call `deserialize(char** buffer, char** v)`, it's assumed the size of the string
  129. // is mostly unknown, but some buffer still must be allocated in order to be filled with the deserialized data.
  130. // we use the SERIALIZE_SCRATCH_BUFFER for this duty, and Strcpy out of it once done to avoid wasting space.
  131. //
  132. // the ideal size of this buffer is use-case dependent, and you will have to change that yourself.
  133. //
  134. // there are asserts in the codepaths that use it for overflowing it, if you are unsure.
  135. //
  136. static char SERIALIZE_SCRATCH_BUFFER[SERIALIZE_SCRATCH_BUFFER_SIZE];
  137. static s32 deserializeString(char** buffer, char* v, s32 vSize) {
  138. ULE_TYPES_H_FTAG;
  139. char* _buffer = *buffer;
  140. while (String::isAsciiWhitespace(*_buffer)) _buffer++;
  141. massert(_buffer[0] == '"', "expecting to deserialize a string, but found something other than a double quote");
  142. _buffer++; // skip over the first quote
  143. s32 i = 0;
  144. while (_buffer[i] != '"') {
  145. // @TODO handle escaped quotes?
  146. v[i] = _buffer[i];
  147. i++;
  148. massert(i <= (vSize - 1), "deserializing a string bigger than the reported size of the buffer we are trying to fill!");
  149. }
  150. v[i] = '\0';
  151. *buffer = _buffer + i + 1; // +i for the number of chars in string, +1 for final quotemark
  152. return i;
  153. }
  154. static s32 deserializeString(char** buffer, char* v) {
  155. ULE_TYPES_H_FTAG;
  156. char* _buffer = *buffer;
  157. while (String::isAsciiWhitespace(*_buffer)) _buffer++;
  158. massert(_buffer[0] == '"', "expecting to deserialize a string, but found something other than a double quote");
  159. _buffer++; // skip over the first quote
  160. s32 i = 0;
  161. while (_buffer[i] != '"') {
  162. // @TODO handle escaped quotes?
  163. v[i] = _buffer[i];
  164. i++;
  165. }
  166. v[i] = '\0';
  167. *buffer = _buffer + i + 1; // +i for the number of chars in string, +1 for final quotemark
  168. return i;
  169. }
  170. void deserialize(char** buffer, char* v) {
  171. ULE_TYPES_H_FTAG;
  172. deserializeString(buffer, v);
  173. }
  174. void deserialize(char** buffer, const char* v) {
  175. ULE_TYPES_H_FTAG;
  176. deserializeString(buffer, (char*) v);
  177. }
  178. void deserialize(char** buffer, char** v) {
  179. ULE_TYPES_H_FTAG;
  180. DESERIALIZE_HANDLE_NULL(buffer, v);
  181. s32 i = deserializeString(buffer, SERIALIZE_SCRATCH_BUFFER, SERIALIZE_SCRATCH_BUFFER_SIZE);
  182. massert(i >= 0, "didn't deserialize anything when expecting a string!");
  183. *v = String::cpy(SERIALIZE_SCRATCH_BUFFER, (u32) i);
  184. }
  185. void deserialize(char** buffer, const char** v) {
  186. ULE_TYPES_H_FTAG;
  187. DESERIALIZE_HANDLE_NULL(buffer, (char*) v); // error: readonly variable is not assignable
  188. s32 i = deserializeString(buffer, SERIALIZE_SCRATCH_BUFFER, SERIALIZE_SCRATCH_BUFFER_SIZE);
  189. massert(i >= 0, "didn't deserialize anything when expecting a string!");
  190. *v = String::cpy(SERIALIZE_SCRATCH_BUFFER, (u32) i);
  191. }
  192. #ifdef _USING_GLM_TYPES__
  193. // I have no fucking idea why, but the declarations of glm types here resolve to a type,
  194. // that has a template parameter == 0, but all other instances of those types in my program
  195. // have that template parameter == 3, so everything below becomes unresolved symbols if
  196. // I don't do the nasty template garbage here
  197. void serialize(String* str, glm::vec<2, float, (glm::qualifier) (glm::qualifier) 3> v) {
  198. ULE_TYPES_H_FTAG;
  199. str->appendf(getFormatStringOut(v), v[0], v[1]);
  200. }
  201. void serialize(String* str, glm::vec<3, float, (glm::qualifier) (glm::qualifier) 3> v) {
  202. ULE_TYPES_H_FTAG;
  203. str->appendf(getFormatStringOut(v), v[0], v[1], v[2]);
  204. }
  205. void serialize(String* str, glm::vec<4, float, (glm::qualifier) 3> v) {
  206. ULE_TYPES_H_FTAG;
  207. str->appendf(getFormatStringOut(v), v[0], v[1], v[2], v[3]);
  208. }
  209. void serialize(String* str, glm::mat<2, 2, float, (glm::qualifier) 3> v) {
  210. ULE_TYPES_H_FTAG;
  211. str->appendf(getFormatStringOut(v)
  212. , v[0][0], v[0][1]
  213. , v[1][0], v[1][1]);
  214. }
  215. void serialize(String* str, glm::mat<3, 3, float, (glm::qualifier) 3> v) {
  216. ULE_TYPES_H_FTAG;
  217. str->appendf(getFormatStringOut(v)
  218. , v[0][0], v[0][1], v[0][2]
  219. , v[1][0], v[1][1], v[1][2]
  220. , v[2][0], v[2][1], v[2][2]);
  221. }
  222. void serialize(String* str, glm::mat<4, 4, float, (glm::qualifier) 3> v) {
  223. ULE_TYPES_H_FTAG;
  224. str->appendf(getFormatStringOut(v)
  225. , v[0][0], v[0][1], v[0][2], v[0][3]
  226. , v[1][0], v[1][1], v[1][2], v[1][3]
  227. , v[2][0], v[2][1], v[2][2], v[2][3]
  228. , v[3][0], v[3][1], v[3][2], v[3][3]);
  229. }
  230. void deserialize(char** buffer, glm::vec<2, float, (glm::qualifier) 3>* v) {
  231. ULE_TYPES_H_FTAG;
  232. float* _v = (float*) v;
  233. for (u32 i = 0; i < 2; i++) {
  234. deserialize(buffer, _v + i);
  235. }
  236. }
  237. void deserialize(char** buffer, glm::vec<3, float, (glm::qualifier) 3>* v) {
  238. ULE_TYPES_H_FTAG;
  239. float* _v = (float*) v;
  240. for (u32 i = 0; i < 3; i++) {
  241. deserialize(buffer, _v + i);
  242. }
  243. }
  244. void deserialize(char** buffer, glm::vec<4, float, (glm::qualifier) 3>* v) {
  245. ULE_TYPES_H_FTAG;
  246. float* _v = (float*) v;
  247. for (u32 i = 0; i < 4; i++) {
  248. deserialize(buffer, _v + i);
  249. }
  250. }
  251. void deserialize(char** buffer, glm::mat<2, 2, float, (glm::qualifier) 3>* v) {
  252. ULE_TYPES_H_FTAG;
  253. float* m = (float*) v;
  254. for (u32 i = 0; i < 4; i++) {
  255. deserialize(buffer, m + i);
  256. }
  257. }
  258. void deserialize(char** buffer, glm::mat<3, 3, float, (glm::qualifier) 3>* v) {
  259. ULE_TYPES_H_FTAG;
  260. float* m = (float*) v;
  261. for (u32 i = 0; i < 9; i++) {
  262. deserialize(buffer, m + i);
  263. }
  264. }
  265. void deserialize(char** buffer, glm::mat<4, 4, float, (glm::qualifier) 3>* v) {
  266. ULE_TYPES_H_FTAG;
  267. float* m = (float*) v;
  268. for (u32 i = 0; i < 16; i++) {
  269. deserialize(buffer, m + i);
  270. }
  271. }
  272. #undef SERIALIZE_H_FUNC_BODY
  273. #undef SERIALIZE_H_DESERIALIZE_FUNC_BODY
  274. #endif
  275. #endif