iodine 0.6.5 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of iodine might be problematic. Click here for more details.

Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/README.md +4 -4
  4. data/SPEC-Websocket-Draft.md +3 -6
  5. data/bin/mustache.rb +128 -0
  6. data/examples/test_template.mustache +16 -0
  7. data/ext/iodine/fio.c +9397 -0
  8. data/ext/iodine/fio.h +4723 -0
  9. data/ext/iodine/fio_ary.h +353 -54
  10. data/ext/iodine/fio_cli.c +351 -361
  11. data/ext/iodine/fio_cli.h +84 -105
  12. data/ext/iodine/fio_hashmap.h +70 -16
  13. data/ext/iodine/fio_json_parser.h +35 -24
  14. data/ext/iodine/fio_siphash.c +104 -4
  15. data/ext/iodine/fio_siphash.h +18 -2
  16. data/ext/iodine/fio_str.h +1218 -0
  17. data/ext/iodine/fio_tmpfile.h +1 -1
  18. data/ext/iodine/fiobj.h +13 -8
  19. data/ext/iodine/fiobj4sock.h +6 -8
  20. data/ext/iodine/fiobj_ary.c +107 -17
  21. data/ext/iodine/fiobj_ary.h +36 -4
  22. data/ext/iodine/fiobj_data.c +146 -127
  23. data/ext/iodine/fiobj_data.h +25 -23
  24. data/ext/iodine/fiobj_hash.c +7 -7
  25. data/ext/iodine/fiobj_hash.h +6 -5
  26. data/ext/iodine/fiobj_json.c +20 -17
  27. data/ext/iodine/fiobj_json.h +5 -5
  28. data/ext/iodine/fiobj_mem.h +71 -0
  29. data/ext/iodine/fiobj_mustache.c +310 -0
  30. data/ext/iodine/fiobj_mustache.h +40 -0
  31. data/ext/iodine/fiobj_numbers.c +199 -94
  32. data/ext/iodine/fiobj_numbers.h +7 -7
  33. data/ext/iodine/fiobj_str.c +142 -333
  34. data/ext/iodine/fiobj_str.h +65 -55
  35. data/ext/iodine/fiobject.c +49 -11
  36. data/ext/iodine/fiobject.h +40 -39
  37. data/ext/iodine/http.c +382 -190
  38. data/ext/iodine/http.h +124 -80
  39. data/ext/iodine/http1.c +99 -127
  40. data/ext/iodine/http1.h +5 -5
  41. data/ext/iodine/http1_parser.c +3 -2
  42. data/ext/iodine/http1_parser.h +2 -2
  43. data/ext/iodine/http_internal.c +14 -12
  44. data/ext/iodine/http_internal.h +25 -19
  45. data/ext/iodine/iodine.c +37 -18
  46. data/ext/iodine/iodine.h +4 -0
  47. data/ext/iodine/iodine_caller.c +9 -2
  48. data/ext/iodine/iodine_caller.h +2 -0
  49. data/ext/iodine/iodine_connection.c +82 -117
  50. data/ext/iodine/iodine_defer.c +57 -50
  51. data/ext/iodine/iodine_defer.h +0 -1
  52. data/ext/iodine/iodine_fiobj2rb.h +4 -2
  53. data/ext/iodine/iodine_helpers.c +4 -4
  54. data/ext/iodine/iodine_http.c +25 -32
  55. data/ext/iodine/iodine_json.c +2 -1
  56. data/ext/iodine/iodine_mustache.c +423 -0
  57. data/ext/iodine/iodine_mustache.h +6 -0
  58. data/ext/iodine/iodine_pubsub.c +48 -153
  59. data/ext/iodine/iodine_pubsub.h +5 -4
  60. data/ext/iodine/iodine_rack_io.c +7 -5
  61. data/ext/iodine/iodine_store.c +16 -13
  62. data/ext/iodine/iodine_tcp.c +26 -34
  63. data/ext/iodine/mustache_parser.h +1085 -0
  64. data/ext/iodine/redis_engine.c +740 -646
  65. data/ext/iodine/redis_engine.h +13 -15
  66. data/ext/iodine/resp_parser.h +11 -5
  67. data/ext/iodine/websocket_parser.h +13 -13
  68. data/ext/iodine/websockets.c +240 -393
  69. data/ext/iodine/websockets.h +52 -113
  70. data/lib/iodine.rb +1 -1
  71. data/lib/iodine/mustache.rb +140 -0
  72. data/lib/iodine/version.rb +1 -1
  73. metadata +15 -28
  74. data/ext/iodine/defer.c +0 -566
  75. data/ext/iodine/defer.h +0 -148
  76. data/ext/iodine/evio.c +0 -26
  77. data/ext/iodine/evio.h +0 -161
  78. data/ext/iodine/evio_callbacks.c +0 -26
  79. data/ext/iodine/evio_epoll.c +0 -251
  80. data/ext/iodine/evio_kqueue.c +0 -194
  81. data/ext/iodine/facil.c +0 -2325
  82. data/ext/iodine/facil.h +0 -616
  83. data/ext/iodine/fio_base64.c +0 -277
  84. data/ext/iodine/fio_base64.h +0 -71
  85. data/ext/iodine/fio_llist.h +0 -257
  86. data/ext/iodine/fio_mem.c +0 -675
  87. data/ext/iodine/fio_mem.h +0 -143
  88. data/ext/iodine/fio_random.c +0 -248
  89. data/ext/iodine/fio_random.h +0 -45
  90. data/ext/iodine/fio_sha1.c +0 -362
  91. data/ext/iodine/fio_sha1.h +0 -107
  92. data/ext/iodine/fio_sha2.c +0 -842
  93. data/ext/iodine/fio_sha2.h +0 -169
  94. data/ext/iodine/pubsub.c +0 -867
  95. data/ext/iodine/pubsub.h +0 -221
  96. data/ext/iodine/sock.c +0 -1366
  97. data/ext/iodine/sock.h +0 -566
  98. data/ext/iodine/spnlock.inc +0 -111
@@ -5,7 +5,7 @@ Copyright: Boaz Segev, 2017-2018
5
5
  License: MIT
6
6
  */
7
7
 
8
- #include "fiobject.h"
8
+ #include <fiobject.h>
9
9
 
10
10
  #ifdef __cplusplus
11
11
  extern "C" {
@@ -48,13 +48,13 @@ Numerical Helpers: not FIOBJ specific, but included as part of the library
48
48
  *
49
49
  * The pointer will be updated to point to the first byte after the number.
50
50
  */
51
- intptr_t fio_atol(char **pstr);
51
+ int64_t fio_atol(char **pstr);
52
52
 
53
- /** A helper function that convers between String data to a signed double. */
53
+ /** A helper function that converts between String data to a signed double. */
54
54
  double fio_atof(char **pstr);
55
55
 
56
56
  /**
57
- * A helper function that convers between a signed int64_t to a string.
57
+ * A helper function that converts between a signed int64_t to a string.
58
58
  *
59
59
  * No overflow guard is provided, make sure there's at least 66 bytes available
60
60
  * (for base 2).
@@ -68,7 +68,7 @@ double fio_atof(char **pstr);
68
68
  size_t fio_ltoa(char *dest, int64_t num, uint8_t base);
69
69
 
70
70
  /**
71
- * A helper function that convers between a double to a string.
71
+ * A helper function that converts between a double to a string.
72
72
  *
73
73
  * No overflow guard is provided, make sure there's at least 130 bytes available
74
74
  * (for base 2).
@@ -82,10 +82,10 @@ size_t fio_ltoa(char *dest, int64_t num, uint8_t base);
82
82
  size_t fio_ftoa(char *dest, double num, uint8_t base);
83
83
 
84
84
  /** Converts a number to a temporary, thread safe, C string object */
85
- fio_cstr_s fio_ltocstr(long);
85
+ fio_str_info_s fio_ltocstr(long);
86
86
 
87
87
  /** Converts a float to a temporary, thread safe, C string object */
88
- fio_cstr_s fio_ftocstr(double);
88
+ fio_str_info_s fio_ftocstr(double);
89
89
 
90
90
  /* *****************************************************************************
91
91
  Pointer Wrapping Helper MACROs (uses integers)
@@ -16,11 +16,11 @@ License: MIT
16
16
  #define PAGE_SIZE 4096
17
17
  #endif
18
18
 
19
- #include "fiobject.h"
19
+ #include <fiobject.h>
20
20
 
21
- #include "fio_siphash.h"
22
- #include "fiobj_numbers.h"
23
- #include "fiobj_str.h"
21
+ #include <fio_siphash.h>
22
+ #include <fiobj_numbers.h>
23
+ #include <fiobj_str.h>
24
24
 
25
25
  #include <assert.h>
26
26
  #include <errno.h>
@@ -30,7 +30,9 @@ License: MIT
30
30
  #include <sys/stat.h>
31
31
 
32
32
  #define FIO_OVERRIDE_MALLOC 1
33
- #include "fio_mem.h"
33
+ #include <fiobj_mem.h>
34
+
35
+ #include <fio_str.h>
34
36
 
35
37
  #ifndef PATH_MAX
36
38
  #define PATH_MAX PAGE_SIZE
@@ -43,86 +45,46 @@ String Type
43
45
  typedef struct {
44
46
  fiobj_object_header_s head;
45
47
  uint64_t hash;
46
- uint8_t is_small;
47
- uint8_t frozen;
48
- uint8_t slen;
49
- intptr_t len;
50
- uintptr_t capa;
51
- char *str;
48
+ fio_str_s str;
52
49
  } fiobj_str_s;
53
50
 
54
51
  #define obj2str(o) ((fiobj_str_s *)(FIOBJ2PTR(o)))
55
52
 
56
- #define STR_INTENAL_OFFSET ((uintptr_t)(&(((fiobj_str_s *)0)->slen) + 1))
57
- #define STR_INTENAL_CAPA ((uintptr_t)(sizeof(fiobj_str_s) - STR_INTENAL_OFFSET))
58
- #define STR_INTENAL_STR(o) \
59
- ((char *)((uintptr_t)FIOBJ2PTR(o) + STR_INTENAL_OFFSET))
60
- #define STR_INTENAL_LEN(o) (((fiobj_str_s *)FIOBJ2PTR(o))->slen)
61
-
62
- static inline char *fiobj_str_mem_addr(FIOBJ o) {
63
- if (obj2str(o)->is_small)
64
- return STR_INTENAL_STR(o);
65
- return obj2str(o)->str;
66
- }
67
- static inline size_t fiobj_str_getlen(FIOBJ o) {
68
- if (obj2str(o)->is_small)
69
- return obj2str(o)->slen;
70
- return obj2str(o)->len;
71
- }
72
- static inline size_t fiobj_str_getcapa(FIOBJ o) {
73
- if (obj2str(o)->is_small)
74
- return STR_INTENAL_CAPA;
75
- return obj2str(o)->capa;
76
- }
77
- static inline void fiobj_str_setlen(FIOBJ o, size_t len) {
78
- if (obj2str(o)->is_small) {
79
- obj2str(o)->slen = len;
80
- STR_INTENAL_STR(o)[len] = 0;
81
- } else {
82
- obj2str(o)->len = len;
83
- obj2str(o)->str[len] = 0;
84
- obj2str(o)->hash = 0;
85
- }
86
- }
87
- static inline fio_cstr_s fiobj_str_get_cstr(const FIOBJ o) {
88
- if (obj2str(o)->is_small)
89
- return (fio_cstr_s){.buffer = STR_INTENAL_STR(o),
90
- .len = STR_INTENAL_LEN(o)};
91
- ;
92
- return (fio_cstr_s){.buffer = obj2str(o)->str, .len = obj2str(o)->len};
53
+ static inline fio_str_info_s fiobj_str_get_cstr(const FIOBJ o) {
54
+ return fio_str_state(&obj2str(o)->str);
93
55
  }
94
56
 
95
57
  /* *****************************************************************************
96
58
  String VTables
97
59
  ***************************************************************************** */
98
60
 
99
- static fio_cstr_s fio_str2str(const FIOBJ o) { return fiobj_str_get_cstr(o); }
61
+ static fio_str_info_s fio_str2str(const FIOBJ o) {
62
+ return fiobj_str_get_cstr(o);
63
+ }
100
64
 
101
65
  static void fiobj_str_dealloc(FIOBJ o, void (*task)(FIOBJ, void *), void *arg) {
102
- if (obj2str(o)->is_small == 0 && obj2str(o)->capa)
103
- fio_free(obj2str(o)->str);
66
+ fio_str_free(&obj2str(o)->str);
104
67
  fio_free(FIOBJ2PTR(o));
105
68
  (void)task;
106
69
  (void)arg;
107
70
  }
108
71
 
109
72
  static size_t fiobj_str_is_eq(const FIOBJ self, const FIOBJ other) {
110
- fio_cstr_s o1 = fiobj_str_get_cstr(self);
111
- fio_cstr_s o2 = fiobj_str_get_cstr(other);
112
- return (o1.len == o2.len &&
113
- (o1.data == o2.data || !memcmp(o1.data, o2.data, o1.len)));
73
+ return fio_str_iseq(&obj2str(self)->str, &obj2str(other)->str);
114
74
  }
115
75
 
116
76
  static intptr_t fio_str2i(const FIOBJ o) {
117
- char *pos = fiobj_str_mem_addr(o);
77
+ char *pos = fio_str_data(&obj2str(o)->str);
118
78
  return fio_atol(&pos);
119
79
  }
120
80
  static double fio_str2f(const FIOBJ o) {
121
- char *pos = fiobj_str_mem_addr(o);
81
+ char *pos = fio_str_data(&obj2str(o)->str);
122
82
  return fio_atof(&pos);
123
83
  }
124
84
 
125
- static size_t fio_str2bool(const FIOBJ o) { return fiobj_str_getlen(o) != 0; }
85
+ static size_t fio_str2bool(const FIOBJ o) {
86
+ return fio_str_len(&obj2str(o)->str) != 0;
87
+ }
126
88
 
127
89
  uintptr_t fiobject___noop_count(const FIOBJ o);
128
90
 
@@ -153,50 +115,22 @@ FIOBJ fiobj_str_buf(size_t capa) {
153
115
  perror("ERROR: fiobj string couldn't allocate memory");
154
116
  exit(errno);
155
117
  }
156
-
157
- if (capa <= STR_INTENAL_CAPA) {
158
- *s = (fiobj_str_s){
159
- .head =
160
- {
161
- .ref = 1, .type = FIOBJ_T_STRING,
162
- },
163
- .is_small = 1,
164
- .slen = 0,
165
- };
166
- } else {
167
- *s = (fiobj_str_s){
168
- .head =
169
- {
170
- .ref = 1, .type = FIOBJ_T_STRING,
171
- },
172
- .len = 0,
173
- .capa = capa,
174
- .str = fio_malloc(capa),
175
- };
176
- if (!s->str) {
177
- perror("ERROR: fiobj string couldn't allocate buffer memory");
178
- exit(errno);
179
- }
118
+ *s = (fiobj_str_s){
119
+ .head =
120
+ {
121
+ .ref = 1,
122
+ .type = FIOBJ_T_STRING,
123
+ },
124
+ .str = FIO_STR_INIT,
125
+ };
126
+ if (capa) {
127
+ fio_str_capa_assert(&s->str, capa);
180
128
  }
181
129
  return ((uintptr_t)s | FIOBJECT_STRING_FLAG);
182
130
  }
183
131
 
184
132
  /** Creates a String object. Remember to use `fiobj_free`. */
185
133
  FIOBJ fiobj_str_new(const char *str, size_t len) {
186
- FIOBJ s = fiobj_str_buf(len);
187
- char *mem = fiobj_str_mem_addr(s);
188
- memcpy(mem, str, len);
189
- fiobj_str_setlen(s, len);
190
- return s;
191
- }
192
-
193
- /**
194
- * Creates a String object. Remember to use `fiobj_free`.
195
- *
196
- * The ownership of the memory indicated by `str` will now "move" to the
197
- * object, so `free` will be called by the `fiobj` library as needed.
198
- */
199
- FIOBJ fiobj_str_move(char *str, size_t len, size_t capacity) {
200
134
  fiobj_str_s *s = fio_malloc(sizeof(*s));
201
135
  if (!s) {
202
136
  perror("ERROR: fiobj string couldn't allocate memory");
@@ -205,31 +139,28 @@ FIOBJ fiobj_str_move(char *str, size_t len, size_t capacity) {
205
139
  *s = (fiobj_str_s){
206
140
  .head =
207
141
  {
208
- .ref = 1, .type = FIOBJ_T_STRING,
142
+ .ref = 1,
143
+ .type = FIOBJ_T_STRING,
209
144
  },
210
- .len = len,
211
- .capa = (capacity < len ? len : capacity),
212
- .str = str,
145
+ .str = FIO_STR_INIT,
213
146
  };
147
+ if (str && len) {
148
+ fio_str_write(&s->str, str, len);
149
+ }
214
150
  return ((uintptr_t)s | FIOBJECT_STRING_FLAG);
215
151
  }
216
152
 
217
153
  /**
218
- * Creates a static String object from a static C string. Remember
219
- * `fiobj_free`.
220
- *
221
- * This variation avoids allocating memory for an existing static String.
154
+ * Creates a String object. Remember to use `fiobj_free`.
222
155
  *
223
- * The object still needs to be frees, but the string isn't copied and isn't
224
- * freed.
156
+ * It's possible to wrap a previosly allocated memory block in a FIOBJ String
157
+ * object, as long as it was allocated using `fio_malloc`.
225
158
  *
226
- * NOTICE: static strings can't be written to.
159
+ * The ownership of the memory indicated by `str` will "move" to the object and
160
+ * will be freed (using `fio_free`) once the object's reference count drops to
161
+ * zero.
227
162
  */
228
- FIOBJ fiobj_str_static(const char *str, size_t len) {
229
- #if !FIOBJ_DONT_COPY_SMALL_STATIC_STRINGS
230
- if (len < STR_INTENAL_CAPA)
231
- return fiobj_str_new(str, len);
232
- #endif
163
+ FIOBJ fiobj_str_move(char *str, size_t len, size_t capacity) {
233
164
  fiobj_str_s *s = fio_malloc(sizeof(*s));
234
165
  if (!s) {
235
166
  perror("ERROR: fiobj string couldn't allocate memory");
@@ -238,42 +169,14 @@ FIOBJ fiobj_str_static(const char *str, size_t len) {
238
169
  *s = (fiobj_str_s){
239
170
  .head =
240
171
  {
241
- .ref = 1, .type = FIOBJ_T_STRING,
172
+ .ref = 1,
173
+ .type = FIOBJ_T_STRING,
242
174
  },
243
- .len = len,
244
- .capa = 0,
245
- .str = (char *)str,
175
+ .str = FIO_STR_INIT_EXISTING(str, len, capacity),
246
176
  };
247
177
  return ((uintptr_t)s | FIOBJECT_STRING_FLAG);
248
178
  }
249
179
 
250
- /** Creates a String object using a printf like interface. */
251
- __attribute__((format(printf, 1, 0))) FIOBJ fiobj_strvprintf(const char *format,
252
- va_list argv) {
253
- FIOBJ str = 0;
254
- va_list argv_cpy;
255
- va_copy(argv_cpy, argv);
256
- int len = vsnprintf(NULL, 0, format, argv_cpy);
257
- va_end(argv_cpy);
258
- if (len == 0)
259
- str = fiobj_str_new("", 0);
260
- if (len <= 0)
261
- return str;
262
- str = fiobj_str_buf(len);
263
- char *mem = FIOBJECT2VTBL(str)->to_str(str).data;
264
- vsnprintf(mem, len + 1, format, argv);
265
- fiobj_str_setlen(str, len);
266
- return str;
267
- }
268
- __attribute__((format(printf, 1, 2))) FIOBJ fiobj_strprintf(const char *format,
269
- ...) {
270
- va_list argv;
271
- va_start(argv, format);
272
- FIOBJ str = fiobj_strvprintf(format, argv);
273
- va_end(argv);
274
- return str;
275
- }
276
-
277
180
  /**
278
181
  * Returns a thread-static temporary string. Avoid calling `fiobj_dup` or
279
182
  * `fiobj_free`.
@@ -282,179 +185,58 @@ FIOBJ fiobj_str_tmp(void) {
282
185
  static __thread fiobj_str_s tmp = {
283
186
  .head =
284
187
  {
285
- .ref = ((~(uint32_t)0) >> 4), .type = FIOBJ_T_STRING,
188
+ .ref = ((~(uint32_t)0) >> 4),
189
+ .type = FIOBJ_T_STRING,
286
190
  },
287
- .is_small = 1,
288
- .slen = 0,
191
+ .str = {.small = 1},
289
192
  };
290
- tmp.len = 0;
291
- tmp.slen = 0;
193
+ tmp.str.frozen = 0;
194
+ fio_str_resize(&tmp.str, 0);
292
195
  return ((uintptr_t)&tmp | FIOBJECT_STRING_FLAG);
293
196
  }
294
197
 
295
- /** Dumps the `filename` file's contents into a new String. If `limit == 0`,
296
- * than the data will be read until EOF.
297
- *
298
- * If the file can't be located, opened or read, or if `start_at` is beyond
299
- * the EOF position, NULL is returned.
300
- *
301
- * Remember to use `fiobj_free`.
302
- */
303
- FIOBJ fiobj_str_readfile(const char *filename, intptr_t start_at,
304
- intptr_t limit) {
305
- #if defined(__unix__) || defined(__linux__) || defined(__APPLE__)
306
- /* POSIX implementations. */
307
- if (filename == NULL)
308
- return FIOBJ_INVALID;
309
- struct stat f_data;
310
- int file = -1;
311
- size_t file_path_len = strlen(filename);
312
- if (file_path_len == 0 || file_path_len >= PATH_MAX)
313
- return FIOBJ_INVALID;
314
-
315
- char real_public_path[PATH_MAX];
316
- real_public_path[PATH_MAX - 1] = 0;
317
-
318
- if (filename[0] == '~' && getenv("HOME") && file_path_len < PATH_MAX) {
319
- strcpy(real_public_path, getenv("HOME"));
320
- memcpy(real_public_path + strlen(real_public_path), filename + 1,
321
- file_path_len);
322
- filename = real_public_path;
323
- }
324
-
325
- if (stat(filename, &f_data) || f_data.st_size <= 0)
326
- return FIOBJ_INVALID;
327
-
328
- if (start_at < 0)
329
- start_at = f_data.st_size + start_at;
330
-
331
- if (start_at < 0 || start_at >= f_data.st_size)
332
- return FIOBJ_INVALID;
333
-
334
- if (limit <= 0 || f_data.st_size < (limit + start_at))
335
- limit = f_data.st_size - start_at;
336
- FIOBJ str = fiobj_str_buf(limit + 1);
337
- if (!str)
338
- return FIOBJ_INVALID;
339
- file = open(filename, O_RDONLY);
340
- if (file < 0) {
341
- FIOBJECT2VTBL(str)->dealloc(str, NULL, NULL);
342
- return FIOBJ_INVALID;
343
- }
344
- if (pread(file, fiobj_str_mem_addr(str), limit, start_at) != (ssize_t)limit) {
345
- FIOBJECT2VTBL(str)->dealloc(str, NULL, NULL);
346
- close(file);
347
- return FIOBJ_INVALID;
348
- }
349
- close(file);
350
- fiobj_str_setlen(str, limit);
351
- return str;
352
- #else
353
- /* TODO: consider adding non POSIX implementations. */
354
- return FIOBJ_INVALID;
355
- #endif
356
- }
357
-
358
198
  /** Prevents the String object from being changed. */
359
199
  void fiobj_str_freeze(FIOBJ str) {
360
200
  if (FIOBJ_TYPE_IS(str, FIOBJ_T_STRING))
361
- obj2str(str)->frozen = 1;
201
+ fio_str_freeze(&obj2str(str)->str);
362
202
  }
363
203
 
364
204
  /** Confirms the requested capacity is available and allocates as required. */
365
205
  size_t fiobj_str_capa_assert(FIOBJ str, size_t size) {
366
206
 
367
207
  assert(FIOBJ_TYPE_IS(str, FIOBJ_T_STRING));
368
- if (obj2str(str)->frozen)
208
+ if (obj2str(str)->str.frozen)
369
209
  return 0;
370
- size += 1;
371
- if (obj2str(str)->is_small) {
372
- if (size <= STR_INTENAL_CAPA)
373
- return STR_INTENAL_CAPA;
374
- if (size >> 12)
375
- size = ((size >> 12) + 1) << 12;
376
- char *mem = fio_malloc(size);
377
- if (!mem) {
378
- perror("FATAL ERROR: Couldn't allocate larger String memory");
379
- exit(errno);
380
- }
381
- memcpy(mem, STR_INTENAL_STR(str), obj2str(str)->slen + 1);
382
- *obj2str(str) = (fiobj_str_s){
383
- .head =
384
- {
385
- .ref = obj2str(str)->head.ref, .type = FIOBJ_T_STRING,
386
- },
387
- .len = obj2str(str)->slen,
388
- .capa = size,
389
- .str = mem,
390
- };
391
- return obj2str(str)->capa;
392
- }
393
- if (obj2str(str)->capa >= size)
394
- return obj2str(str)->capa;
395
-
396
- /* large strings should increase memory by page size (assumes 4096 pages) */
397
- if (size >> 12)
398
- size = ((size >> 12) + 1) << 12;
399
- else if (size < (obj2str(str)->capa << 1))
400
- size = obj2str(str)->capa << 1; /* grow in steps */
401
-
402
- if (obj2str(str)->capa == 0) {
403
- /* a static string */
404
- char *mem = fio_malloc(size);
405
- if (!mem) {
406
- perror("FATAL ERROR: Couldn't allocate new String memory");
407
- exit(errno);
408
- }
409
- memcpy(mem, obj2str(str)->str, obj2str(str)->len + 1);
410
- obj2str(str)->str = mem;
411
- } else {
412
- /* it's better to crash than live without memory... */
413
- obj2str(str)->str =
414
- fio_realloc2(obj2str(str)->str, size, obj2str(str)->len + 1);
415
- if (!obj2str(str)->str) {
416
- perror("FATAL ERROR: Couldn't (re)allocate String memory");
417
- exit(errno);
418
- }
419
- }
420
- obj2str(str)->capa = size;
421
- return obj2str(str)->capa - 1;
210
+ fio_str_info_s state = fio_str_capa_assert(&obj2str(str)->str, size);
211
+ return state.capa;
422
212
  }
423
213
 
424
214
  /** Return's a String's capacity, if any. */
425
215
  size_t fiobj_str_capa(FIOBJ str) {
426
216
  assert(FIOBJ_TYPE_IS(str, FIOBJ_T_STRING));
427
- if (obj2str(str)->frozen)
428
- return 0;
429
- return fiobj_str_getcapa(str) - 1;
217
+ return fio_str_capa(&obj2str(str)->str);
430
218
  }
431
219
 
432
220
  /** Resizes a String object, allocating more memory if required. */
433
221
  void fiobj_str_resize(FIOBJ str, size_t size) {
434
222
  assert(FIOBJ_TYPE_IS(str, FIOBJ_T_STRING));
435
- if (obj2str(str)->frozen)
436
- return;
437
- fiobj_str_capa_assert(str, size);
438
- fiobj_str_setlen(str, size);
223
+ fio_str_resize(&obj2str(str)->str, size);
224
+ obj2str(str)->hash = 0;
439
225
  return;
440
226
  }
441
227
 
442
228
  /** Deallocates any unnecessary memory (if supported by OS). */
443
- void fiobj_str_minimize(FIOBJ str) {
229
+ void fiobj_str_compact(FIOBJ str) {
444
230
  assert(FIOBJ_TYPE_IS(str, FIOBJ_T_STRING));
445
- if (obj2str(str)->frozen || obj2str(str)->is_small || obj2str(str)->capa == 0)
446
- return;
447
- obj2str(str)->capa = obj2str(str)->len + 1;
448
- obj2str(str)->str = fio_realloc(obj2str(str)->str, obj2str(str)->capa);
231
+ fio_str_compact(&obj2str(str)->str);
449
232
  return;
450
233
  }
451
234
 
452
235
  /** Empties a String's data. */
453
236
  void fiobj_str_clear(FIOBJ str) {
454
237
  assert(FIOBJ_TYPE_IS(str, FIOBJ_T_STRING));
455
- if (obj2str(str)->frozen)
456
- return;
457
- fiobj_str_setlen(str, 0);
238
+ fio_str_resize(&obj2str(str)->str, 0);
239
+ obj2str(str)->hash = 0;
458
240
  }
459
241
 
460
242
  /**
@@ -463,47 +245,78 @@ void fiobj_str_clear(FIOBJ str) {
463
245
  */
464
246
  size_t fiobj_str_write(FIOBJ dest, const char *data, size_t len) {
465
247
  assert(FIOBJ_TYPE_IS(dest, FIOBJ_T_STRING));
466
- if (obj2str(dest)->frozen)
248
+ if (obj2str(dest)->str.frozen)
249
+ return 0;
250
+ obj2str(dest)->hash = 0;
251
+ return fio_str_write(&obj2str(dest)->str, data, len).len;
252
+ }
253
+
254
+ /**
255
+ * Writes a number at the end of the String using normal base 10 notation.
256
+ *
257
+ * Returns the new length of the String
258
+ */
259
+ size_t fiobj_str_write_i(FIOBJ dest, int64_t num) {
260
+ assert(FIOBJ_TYPE_IS(dest, FIOBJ_T_STRING));
261
+ if (obj2str(dest)->str.frozen)
467
262
  return 0;
468
- fiobj_str_resize(dest, fiobj_str_getlen(dest) + len);
469
- fio_cstr_s s = fiobj_str_get_cstr(dest);
470
- memcpy(s.data + s.len - len, data, len);
471
- return s.len;
263
+ obj2str(dest)->hash = 0;
264
+ return fio_str_write_i(&obj2str(dest)->str, num).len;
472
265
  }
266
+
473
267
  /**
474
268
  * Writes data at the end of the string, resizing the string as required.
475
269
  * Returns the new length of the String
476
270
  */
477
- size_t fiobj_str_write2(FIOBJ dest, const char *format, ...) {
271
+ size_t fiobj_str_printf(FIOBJ dest, const char *format, ...) {
478
272
  assert(FIOBJ_TYPE_IS(dest, FIOBJ_T_STRING));
479
- if (obj2str(dest)->frozen)
273
+ if (obj2str(dest)->str.frozen)
480
274
  return 0;
275
+ obj2str(dest)->hash = 0;
481
276
  va_list argv;
482
277
  va_start(argv, format);
483
- int len = vsnprintf(NULL, 0, format, argv);
278
+ fio_str_info_s state = fio_str_vprintf(&obj2str(dest)->str, format, argv);
484
279
  va_end(argv);
485
- if (len <= 0)
486
- return obj2str(dest)->len;
487
- fiobj_str_resize(dest, fiobj_str_getlen(dest) + len);
488
- va_start(argv, format);
489
- fio_cstr_s s = fiobj_str_get_cstr(dest);
490
- vsnprintf(s.data + s.len - len, len + 1, format, argv);
491
- va_end(argv);
492
- // ((fio_str_s *)dest)->str[((fio_str_s *)dest)->len] = 0; // see str_resize
493
- return s.len;
280
+ return state.len;
494
281
  }
282
+
283
+ size_t fiobj_str_vprintf(FIOBJ dest, const char *format, va_list argv) {
284
+ assert(FIOBJ_TYPE_IS(dest, FIOBJ_T_STRING));
285
+ if (obj2str(dest)->str.frozen)
286
+ return 0;
287
+ obj2str(dest)->hash = 0;
288
+ fio_str_info_s state = fio_str_vprintf(&obj2str(dest)->str, format, argv);
289
+ return state.len;
290
+ }
291
+
292
+ /** Dumps the `filename` file's contents at the end of a String. If `limit ==
293
+ * 0`, than the data will be read until EOF.
294
+ *
295
+ * If the file can't be located, opened or read, or if `start_at` is beyond
296
+ * the EOF position, NULL is returned.
297
+ *
298
+ * Remember to use `fiobj_free`.
299
+ */
300
+ size_t fiobj_str_readfile(FIOBJ dest, const char *filename, intptr_t start_at,
301
+ intptr_t limit) {
302
+ fio_str_info_s state =
303
+ fio_str_readfile(&obj2str(dest)->str, filename, start_at, limit);
304
+ return state.len;
305
+ }
306
+
495
307
  /**
496
308
  * Writes data at the end of the string, resizing the string as required.
497
309
  * Returns the new length of the String
498
310
  */
499
- size_t fiobj_str_join(FIOBJ dest, FIOBJ obj) {
311
+ size_t fiobj_str_concat(FIOBJ dest, FIOBJ obj) {
500
312
  assert(FIOBJ_TYPE_IS(dest, FIOBJ_T_STRING));
501
- if (obj2str(dest)->frozen)
313
+ if (obj2str(dest)->str.frozen)
502
314
  return 0;
503
- fio_cstr_s o = fiobj_obj2cstr(obj);
315
+ obj2str(dest)->hash = 0;
316
+ fio_str_info_s o = fiobj_obj2cstr(obj);
504
317
  if (o.len == 0)
505
- return obj2str(dest)->len;
506
- return fiobj_str_write(dest, o.data, o.len);
318
+ return fio_str_len(&obj2str(dest)->str);
319
+ return fio_str_write(&obj2str(dest)->str, o.data, o.len).len;
507
320
  }
508
321
 
509
322
  /**
@@ -517,11 +330,8 @@ uint64_t fiobj_str_hash(FIOBJ o) {
517
330
  if (obj2str(o)->hash) {
518
331
  return obj2str(o)->hash;
519
332
  }
520
- if (obj2str(o)->is_small) {
521
- obj2str(o)->hash = fio_siphash(STR_INTENAL_STR(o), STR_INTENAL_LEN(o));
522
- } else {
523
- obj2str(o)->hash = fio_siphash(obj2str(o)->str, obj2str(o)->len);
524
- }
333
+ fio_str_info_s state = fio_str_state(&obj2str(o)->str);
334
+ obj2str(o)->hash = fio_siphash(state.data, state.len);
525
335
  return obj2str(o)->hash;
526
336
  }
527
337
 
@@ -532,8 +342,8 @@ Tests
532
342
  #if DEBUG
533
343
  void fiobj_test_string(void) {
534
344
  fprintf(stderr, "=== Testing Strings\n");
535
- fprintf(stderr, "* Internal String Capacity %u with offset, %u\n",
536
- (unsigned int)STR_INTENAL_CAPA, (unsigned int)STR_INTENAL_OFFSET);
345
+ fprintf(stderr, "* Internal String Capacity %u \n",
346
+ (unsigned int)FIO_STR_SMALL_CAPA);
537
347
  #define TEST_ASSERT(cond, ...) \
538
348
  if (!(cond)) { \
539
349
  fprintf(stderr, "* " __VA_ARGS__); \
@@ -546,31 +356,31 @@ void fiobj_test_string(void) {
546
356
  "String not equal to " str)
547
357
  FIOBJ o = fiobj_str_new("Hello", 5);
548
358
  TEST_ASSERT(FIOBJ_TYPE_IS(o, FIOBJ_T_STRING), "Small String isn't string!\n");
549
- TEST_ASSERT(obj2str(o)->is_small, "Hello isn't small\n");
359
+ TEST_ASSERT(obj2str(o)->str.small, "Hello isn't small\n");
550
360
  fiobj_str_write(o, " World", 6);
551
361
  TEST_ASSERT(FIOBJ_TYPE_IS(o, FIOBJ_T_STRING),
552
362
  "Hello World String isn't string!\n");
553
- TEST_ASSERT(obj2str(o)->is_small, "Hello World isn't small\n");
363
+ TEST_ASSERT(obj2str(o)->str.small, "Hello World isn't small\n");
554
364
  TEST_ASSERT(fiobj_obj2cstr(o).len == 11,
555
365
  "Invalid small string length (%u != 11)!\n",
556
366
  (unsigned int)fiobj_obj2cstr(o).len)
557
367
  fiobj_str_write(o, " World, you crazy longer sleep loving person :-)", 48);
558
- TEST_ASSERT(!obj2str(o)->is_small, "Crazier shouldn't be small\n");
368
+ TEST_ASSERT(!obj2str(o)->str.small, "Crazier shouldn't be small\n");
559
369
  fiobj_free(o);
560
370
 
561
371
  o = fiobj_str_new(
562
372
  "hello my dear friend, I hope that your are well and happy.", 58);
563
373
  TEST_ASSERT(FIOBJ_TYPE_IS(o, FIOBJ_T_STRING), "Long String isn't string!\n");
564
- TEST_ASSERT(!obj2str(o)->is_small,
565
- "Long String is small! (capa: %lu, len: %lu)\n", obj2str(o)->capa,
566
- obj2str(o)->len);
374
+ TEST_ASSERT(!obj2str(o)->str.small,
375
+ "Long String is small! (capa: %lu, len: %lu)\n",
376
+ fio_str_capa(&obj2str(o)->str), fio_str_len(&obj2str(o)->str));
567
377
  TEST_ASSERT(fiobj_obj2cstr(o).len == 58,
568
378
  "Invalid long string length (%lu != 58)!\n",
569
379
  fiobj_obj2cstr(o).len)
570
380
  uint64_t hash = fiobj_str_hash(o);
571
- TEST_ASSERT(!obj2str(o)->frozen, "String forzen when only hashing!\n");
381
+ TEST_ASSERT(!obj2str(o)->str.frozen, "String forzen when only hashing!\n");
572
382
  fiobj_str_freeze(o);
573
- TEST_ASSERT(obj2str(o)->frozen, "String not forzen!\n");
383
+ TEST_ASSERT(obj2str(o)->str.frozen, "String not forzen!\n");
574
384
  fiobj_str_write(o, " World", 6);
575
385
  TEST_ASSERT(hash == fiobj_str_hash(o),
576
386
  "String hash changed after hashing - not frozen?\n");
@@ -579,20 +389,10 @@ void fiobj_test_string(void) {
579
389
  (unsigned long)fiobj_obj2cstr(o).len, fiobj_obj2cstr(o).data);
580
390
  fiobj_free(o);
581
391
 
582
- o = fiobj_str_static("Hello", 5);
583
- TEST_ASSERT(obj2str(o)->is_small,
584
- "Small Static should be converted to dynamic.\n");
585
- fiobj_free(o);
586
-
587
- o = fiobj_str_static(
588
- "hello my dear friend, I hope that your are well and happy.", 58);
589
- fiobj_str_write(o, " World", 6);
590
- STR_EQ(o, "hello my dear friend, I hope that your are well and happy."
591
- " World");
592
- fiobj_free(o);
593
-
594
- o = fiobj_strprintf("%u", 42);
595
- TEST_ASSERT(fiobj_str_getlen(o) == 2, "fiobj_strprintf length error.\n");
392
+ o = fiobj_str_buf(1);
393
+ fiobj_str_printf(o, "%u", 42);
394
+ TEST_ASSERT(fio_str_len(&obj2str(o)->str) == 2,
395
+ "fiobj_strprintf length error.\n");
596
396
  TEST_ASSERT(fiobj_obj2num(o), "fiobj_strprintf integer error.\n");
597
397
  TEST_ASSERT(!memcmp(fiobj_obj2cstr(o).data, "42", 2),
598
398
  "fiobj_strprintf string error.\n");
@@ -602,11 +402,20 @@ void fiobj_test_string(void) {
602
402
  for (int i = 0; i < 16000; ++i) {
603
403
  fiobj_str_write(o, "a", 1);
604
404
  }
605
- TEST_ASSERT(obj2str(o)->len == 16000, "16K fiobj_str_write not 16K.\n");
606
- TEST_ASSERT(obj2str(o)->capa > 16001,
405
+ TEST_ASSERT(fio_str_len(&obj2str(o)->str) == 16000,
406
+ "16K fiobj_str_write not 16K.\n");
407
+ TEST_ASSERT(fio_str_capa(&obj2str(o)->str) >= 16000,
607
408
  "16K fiobj_str_write capa not enough.\n");
608
409
  fiobj_free(o);
609
410
 
411
+ o = fiobj_str_buf(0);
412
+ TEST_ASSERT(fiobj_str_readfile(o, __FILE__, 0, 0),
413
+ "`fiobj_str_readfile` - file wasn't read!");
414
+ TEST_ASSERT(!memcmp(fiobj_obj2cstr(o).data, "/*", 2),
415
+ "`fiobj_str_readfile` error, start of file doesn't match:\n%s",
416
+ fiobj_obj2cstr(o).data);
417
+ fiobj_free(o);
418
+
610
419
  fprintf(stderr, "* passed.\n");
611
420
  }
612
421
  #endif