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.

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