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.

316 lines
13 KiB

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