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.

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