iodine 0.7.60 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/.clang-format +15 -0
  3. data/.rspec +1 -0
  4. data/.yardopts +1 -3
  5. data/CHANGELOG.md +132 -12
  6. data/Gemfile +5 -7
  7. data/LICENSE.txt +1 -1
  8. data/README.md +147 -671
  9. data/Rakefile +9 -16
  10. data/examples/chatroom.nru +9 -0
  11. data/examples/client +74 -0
  12. data/examples/config-hello.nru +9 -0
  13. data/examples/config-hello.ru +11 -0
  14. data/examples/config-hijack.ru +13 -0
  15. data/examples/config-shootout.ru +43 -0
  16. data/examples/config.nru +120 -0
  17. data/examples/config.rb +37 -0
  18. data/examples/config.ru +42 -53
  19. data/examples/fake +24 -0
  20. data/examples/hello_neorack +137 -0
  21. data/examples/routes.nru +29 -0
  22. data/examples/routes.ru +42 -0
  23. data/exe/iodine +218 -258
  24. data/ext/iodine/extconf.rb +27 -100
  25. data/ext/iodine/fio-stl.h +128336 -0
  26. data/ext/iodine/fio-stl.md +26396 -0
  27. data/ext/iodine/iodine.c +213 -1393
  28. data/ext/iodine/iodine.h +250 -55
  29. data/ext/iodine/iodine_arg_helper.h +329 -0
  30. data/ext/iodine/iodine_caller.h +234 -25
  31. data/ext/iodine/iodine_cli.h +434 -0
  32. data/ext/iodine/iodine_compression.h +312 -0
  33. data/ext/iodine/iodine_connection.h +3484 -34
  34. data/ext/iodine/iodine_core.h +363 -0
  35. data/ext/iodine/iodine_crypto.h +1441 -0
  36. data/ext/iodine/iodine_defer.h +225 -4
  37. data/ext/iodine/iodine_json.h +738 -4
  38. data/ext/iodine/iodine_listener.h +263 -0
  39. data/ext/iodine/iodine_log.h +297 -0
  40. data/ext/iodine/iodine_minimap.h +543 -0
  41. data/ext/iodine/iodine_mustache.h +461 -4
  42. data/ext/iodine/iodine_pubsub_eng.h +729 -0
  43. data/ext/iodine/iodine_pubsub_history.h +547 -0
  44. data/ext/iodine/iodine_pubsub_msg.h +228 -0
  45. data/ext/iodine/iodine_redis.h +322 -0
  46. data/ext/iodine/iodine_store.h +418 -16
  47. data/ext/iodine/iodine_threads.h +279 -0
  48. data/ext/iodine/iodine_tls.h +515 -6
  49. data/ext/iodine/iodine_utils.h +923 -0
  50. data/iodine.gemspec +37 -42
  51. data/lib/iodine/benchmark.rb +1690 -0
  52. data/lib/iodine/documentation.rb +3085 -0
  53. data/lib/iodine/version.rb +17 -1
  54. data/lib/iodine.rb +54 -255
  55. data/logo.svg +36 -0
  56. data/mustache.md +55 -0
  57. data/sig/iodine.rbs +4 -0
  58. metadata +58 -184
  59. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
  60. data/.github/workflows/ruby.yml +0 -42
  61. data/.gitignore +0 -21
  62. data/LIMITS.md +0 -41
  63. data/SPEC-PubSub-Draft.md +0 -159
  64. data/SPEC-WebSocket-Draft.md +0 -239
  65. data/bin/console +0 -22
  66. data/bin/info.md +0 -353
  67. data/bin/mustache_bench.rb +0 -100
  68. data/bin/poc/Gemfile.lock +0 -23
  69. data/bin/poc/README.md +0 -37
  70. data/bin/poc/config.ru +0 -66
  71. data/bin/poc/gemfile +0 -1
  72. data/bin/poc/www/index.html +0 -57
  73. data/examples/async_task.ru +0 -92
  74. data/examples/bates/README.md +0 -3
  75. data/examples/bates/config.ru +0 -342
  76. data/examples/bates/david+bold.pdf +0 -0
  77. data/examples/bates/public/drop-pdf.png +0 -0
  78. data/examples/bates/public/index.html +0 -600
  79. data/examples/echo.ru +0 -59
  80. data/examples/etag.ru +0 -16
  81. data/examples/hello.ru +0 -29
  82. data/examples/pubsub_engine.ru +0 -81
  83. data/examples/rack3.ru +0 -12
  84. data/examples/redis.ru +0 -70
  85. data/examples/shootout.ru +0 -73
  86. data/examples/sub-protocols.ru +0 -90
  87. data/examples/tcp_client.rb +0 -66
  88. data/examples/x-sendfile.ru +0 -14
  89. data/ext/iodine/fio.c +0 -11995
  90. data/ext/iodine/fio.h +0 -6371
  91. data/ext/iodine/fio_cli.c +0 -431
  92. data/ext/iodine/fio_cli.h +0 -189
  93. data/ext/iodine/fio_json_parser.h +0 -688
  94. data/ext/iodine/fio_siphash.c +0 -157
  95. data/ext/iodine/fio_siphash.h +0 -37
  96. data/ext/iodine/fio_tls.h +0 -129
  97. data/ext/iodine/fio_tls_missing.c +0 -649
  98. data/ext/iodine/fio_tls_openssl.c +0 -1106
  99. data/ext/iodine/fio_tmpfile.h +0 -50
  100. data/ext/iodine/fiobj.h +0 -44
  101. data/ext/iodine/fiobj4fio.h +0 -21
  102. data/ext/iodine/fiobj_ary.c +0 -333
  103. data/ext/iodine/fiobj_ary.h +0 -139
  104. data/ext/iodine/fiobj_data.c +0 -1187
  105. data/ext/iodine/fiobj_data.h +0 -167
  106. data/ext/iodine/fiobj_hash.c +0 -409
  107. data/ext/iodine/fiobj_hash.h +0 -176
  108. data/ext/iodine/fiobj_json.c +0 -622
  109. data/ext/iodine/fiobj_json.h +0 -68
  110. data/ext/iodine/fiobj_mem.h +0 -71
  111. data/ext/iodine/fiobj_mustache.c +0 -317
  112. data/ext/iodine/fiobj_mustache.h +0 -62
  113. data/ext/iodine/fiobj_numbers.c +0 -344
  114. data/ext/iodine/fiobj_numbers.h +0 -127
  115. data/ext/iodine/fiobj_str.c +0 -433
  116. data/ext/iodine/fiobj_str.h +0 -172
  117. data/ext/iodine/fiobject.c +0 -620
  118. data/ext/iodine/fiobject.h +0 -655
  119. data/ext/iodine/hpack.h +0 -1923
  120. data/ext/iodine/http.c +0 -2743
  121. data/ext/iodine/http.h +0 -1002
  122. data/ext/iodine/http1.c +0 -910
  123. data/ext/iodine/http1.h +0 -29
  124. data/ext/iodine/http1_parser.h +0 -878
  125. data/ext/iodine/http_internal.c +0 -1279
  126. data/ext/iodine/http_internal.h +0 -237
  127. data/ext/iodine/http_mime_parser.h +0 -350
  128. data/ext/iodine/iodine_caller.c +0 -230
  129. data/ext/iodine/iodine_connection.c +0 -941
  130. data/ext/iodine/iodine_defer.c +0 -420
  131. data/ext/iodine/iodine_fiobj2rb.h +0 -120
  132. data/ext/iodine/iodine_helpers.c +0 -282
  133. data/ext/iodine/iodine_helpers.h +0 -12
  134. data/ext/iodine/iodine_http.c +0 -1181
  135. data/ext/iodine/iodine_http.h +0 -23
  136. data/ext/iodine/iodine_json.c +0 -302
  137. data/ext/iodine/iodine_mustache.c +0 -567
  138. data/ext/iodine/iodine_pubsub.c +0 -580
  139. data/ext/iodine/iodine_pubsub.h +0 -26
  140. data/ext/iodine/iodine_rack_io.c +0 -273
  141. data/ext/iodine/iodine_rack_io.h +0 -20
  142. data/ext/iodine/iodine_store.c +0 -148
  143. data/ext/iodine/iodine_tcp.c +0 -346
  144. data/ext/iodine/iodine_tcp.h +0 -13
  145. data/ext/iodine/iodine_tls.c +0 -261
  146. data/ext/iodine/mustache_parser.h +0 -1546
  147. data/ext/iodine/redis_engine.c +0 -957
  148. data/ext/iodine/redis_engine.h +0 -79
  149. data/ext/iodine/resp_parser.h +0 -317
  150. data/ext/iodine/websocket_parser.h +0 -506
  151. data/ext/iodine/websockets.c +0 -743
  152. data/ext/iodine/websockets.h +0 -185
  153. data/lib/iodine/connection.rb +0 -61
  154. data/lib/iodine/json.rb +0 -42
  155. data/lib/iodine/mustache.rb +0 -113
  156. data/lib/iodine/pubsub.rb +0 -55
  157. data/lib/iodine/rack_utils.rb +0 -43
  158. data/lib/iodine/tls.rb +0 -16
  159. data/lib/rack/handler/iodine.rb +0 -33
  160. data/logo.png +0 -0
@@ -1,655 +0,0 @@
1
- #ifndef H_FIOBJECT_H
2
- /*
3
- Copyright: Boaz Segev, 2017-2019
4
- License: MIT
5
- */
6
-
7
- /**
8
- This facil.io core library provides wrappers around complex and (or) dynamic
9
- types, abstracting some complexity and making dynamic type related tasks easier.
10
- */
11
- #define H_FIOBJECT_H
12
-
13
- #ifndef _GNU_SOURCE
14
- #define _GNU_SOURCE
15
- #endif
16
-
17
- #include <stdarg.h>
18
- #include <stdint.h>
19
- #include <stdio.h>
20
- #include <stdlib.h>
21
-
22
- #include <limits.h>
23
- #include <stdarg.h>
24
- #include <stdint.h>
25
- #include <stdio.h>
26
- #include <stdlib.h>
27
-
28
- #include <fio_siphash.h>
29
-
30
- #include <fio.h>
31
-
32
- #if !defined(__GNUC__) && !defined(__clang__) && !defined(FIO_GNUC_BYPASS)
33
- #define __attribute__(...)
34
- #define __has_include(...) 0
35
- #define __has_builtin(...) 0
36
- #define FIO_GNUC_BYPASS 1
37
- #elif !defined(__clang__) && !defined(__has_builtin)
38
- #define __has_builtin(...) 0
39
- #define FIO_GNUC_BYPASS 1
40
- #endif
41
-
42
- #ifdef __cplusplus
43
- extern "C" {
44
- #endif
45
-
46
- /* *****************************************************************************
47
- Core Types
48
- ***************************************************************************** */
49
-
50
- typedef enum __attribute__((packed)) {
51
- FIOBJ_T_NUMBER = 0x01,
52
- FIOBJ_T_NULL = 0x06,
53
- FIOBJ_T_TRUE = 0x16,
54
- FIOBJ_T_FALSE = 0x26,
55
- FIOBJ_T_FLOAT,
56
- FIOBJ_T_STRING,
57
- FIOBJ_T_ARRAY,
58
- FIOBJ_T_HASH,
59
- FIOBJ_T_DATA,
60
- FIOBJ_T_UNKNOWN
61
- } fiobj_type_enum;
62
-
63
- typedef uintptr_t FIOBJ;
64
-
65
- /** a Macro retriving an object's type. Use FIOBJ_TYPE_IS(x) for testing. */
66
- #define FIOBJ_TYPE(obj) fiobj_type((obj))
67
- #define FIOBJ_TYPE_IS(obj, type) fiobj_type_is((obj), (type))
68
- #define FIOBJ_IS_NULL(obj) (!obj || obj == (FIOBJ)FIOBJ_T_NULL)
69
- #define FIOBJ_INVALID 0
70
-
71
- #ifndef FIO_STR_INFO_TYPE
72
- /** A String information type, reports information about a C string. */
73
- typedef struct fio_str_info_s {
74
- size_t capa; /* Buffer capacity, if the string is writable. */
75
- size_t len; /* String length. */
76
- char *data; /* String's first byte. */
77
- } fio_str_info_s;
78
- #define FIO_STR_INFO_TYPE
79
- #endif
80
-
81
- /* *****************************************************************************
82
- Primitives
83
- ***************************************************************************** */
84
-
85
- #define FIO_INLINE static inline __attribute__((unused))
86
-
87
- FIO_INLINE FIOBJ fiobj_null(void) { return (FIOBJ)FIOBJ_T_NULL; }
88
- FIO_INLINE FIOBJ fiobj_true(void) { return (FIOBJ)FIOBJ_T_TRUE; }
89
- FIO_INLINE FIOBJ fiobj_false(void) { return (FIOBJ)FIOBJ_T_FALSE; }
90
-
91
- /* *****************************************************************************
92
- Generic Object API
93
- ***************************************************************************** */
94
-
95
- /** Returns a C string naming the objects dynamic type. */
96
- FIO_INLINE const char *fiobj_type_name(const FIOBJ obj);
97
-
98
- /**
99
- * Heuristic copy with a preference for copy reference(!) to minimize
100
- * allocations.
101
- *
102
- * Always returns the value passed along.
103
- */
104
- FIO_INLINE FIOBJ fiobj_dup(FIOBJ);
105
-
106
- /**
107
- * Frees the object and any of it's "children".
108
- *
109
- * This function affects nested objects, meaning that when an Array or
110
- * a Hash object is passed along, it's children (nested objects) are
111
- * also freed.
112
- */
113
- FIO_INLINE void fiobj_free(FIOBJ);
114
-
115
- /**
116
- * Tests if an object evaluates as TRUE.
117
- *
118
- * This is object type specific. For example, empty strings might evaluate as
119
- * FALSE, even though they aren't a boolean type.
120
- */
121
- FIO_INLINE int fiobj_is_true(const FIOBJ);
122
-
123
- /**
124
- * Returns an Object's numerical value.
125
- *
126
- * If a String is passed to the function, it will be parsed assuming base 10
127
- * numerical data.
128
- *
129
- * Hashes and Arrays return their object count.
130
- *
131
- * IO objects return the length of their data.
132
- *
133
- * A type error results in 0.
134
- */
135
- FIO_INLINE intptr_t fiobj_obj2num(const FIOBJ obj);
136
-
137
- /**
138
- * Returns a Float's value.
139
- *
140
- * If a String is passed to the function, they will benparsed assuming base 10
141
- * numerical data.
142
- *
143
- * A type error results in 0.
144
- */
145
- FIO_INLINE double fiobj_obj2float(const FIOBJ obj);
146
-
147
- /**
148
- * Returns a C String (NUL terminated) using the `fio_str_info_s` data type.
149
- *
150
- * The String is binary safe and might contain NUL bytes in the middle as well
151
- * as a terminating NUL.
152
- *
153
- * If a Number or a Float are passed to the function, they
154
- * will be parsed as a *temporary*, thread-safe, String.
155
- *
156
- * Numbers will be represented in base 10 numerical data.
157
- *
158
- * A type error results in NULL (i.e. object isn't a String).
159
- */
160
- FIO_INLINE fio_str_info_s fiobj_obj2cstr(const FIOBJ obj);
161
-
162
- /**
163
- * Calculates an Objects's SipHash value for possible use as a HashMap key.
164
- *
165
- * The Object MUST answer to the fiobj_obj2cstr, or the result is unusable. In
166
- * other words, Hash Objects and Arrays can NOT be used for Hash keys.
167
- */
168
- FIO_INLINE uint64_t fiobj_obj2hash(const FIOBJ o);
169
-
170
- /**
171
- * Single layer iteration using a callback for each nested fio object.
172
- *
173
- * Accepts any `FIOBJ ` type but only collections (Arrays and Hashes) are
174
- * processed. The container itself (the Array or the Hash) is **not** processed
175
- * (unlike `fiobj_each2`).
176
- *
177
- * The callback task function must accept an object and an opaque user pointer.
178
- *
179
- * Hash objects pass along only the value object. The keys can be accessed using
180
- * the `fiobj_hash_key_in_loop` function.
181
- *
182
- * If the callback returns -1, the loop is broken. Any other value is ignored.
183
- *
184
- * Returns the "stop" position, i.e., the number of items processed + the
185
- * starting point.
186
- */
187
- FIO_INLINE size_t fiobj_each1(FIOBJ, size_t start_at,
188
- int (*task)(FIOBJ obj, void *arg), void *arg);
189
-
190
- /**
191
- * Deep iteration using a callback for each fio object, including the parent.
192
- *
193
- * Accepts any `FIOBJ ` type.
194
- *
195
- * Collections (Arrays, Hashes) are deeply probed and shouldn't be edited
196
- * during an `fiobj_each2` call (or weird things may happen).
197
- *
198
- * The callback task function must accept an object and an opaque user pointer.
199
- *
200
- * Hash objects keys are available using the `fiobj_hash_key_in_loop` function.
201
- *
202
- * Notice that when passing collections to the function, the collection itself
203
- * is sent to the callback followed by it's children (if any). This is true also
204
- * for nested collections (a nested Hash will be sent first, followed by the
205
- * nested Hash's children and then followed by the rest of it's siblings.
206
- *
207
- * If the callback returns -1, the loop is broken. Any other value is ignored.
208
- */
209
- size_t fiobj_each2(FIOBJ, int (*task)(FIOBJ obj, void *arg), void *arg);
210
-
211
- /**
212
- * Deeply compare two objects. No hashing or recursive function calls are
213
- * involved.
214
- *
215
- * Uses a similar algorithm to `fiobj_each2`, except adjusted to two objects.
216
- *
217
- * Hash objects are order sensitive. To be equal, Hash keys must match in order.
218
- *
219
- * Returns 1 if true and 0 if false.
220
- */
221
- FIO_INLINE int fiobj_iseq(const FIOBJ obj1, const FIOBJ obj2);
222
-
223
- /* *****************************************************************************
224
- Object Type Identification
225
- ***************************************************************************** */
226
-
227
- #define FIOBJECT_NUMBER_FLAG 1
228
-
229
- #if UINTPTR_MAX < 0xFFFFFFFFFFFFFFFF
230
- #define FIOBJECT_PRIMITIVE_FLAG 2
231
- #define FIOBJECT_STRING_FLAG 0
232
- #define FIOBJECT_HASH_FLAG 0
233
- #define FIOBJECT_TYPE_MASK (~(uintptr_t)3)
234
- #else
235
- #define FIOBJECT_PRIMITIVE_FLAG 6
236
- #define FIOBJECT_STRING_FLAG 2
237
- #define FIOBJECT_HASH_FLAG 4
238
- #define FIOBJECT_TYPE_MASK (~(uintptr_t)7)
239
- #endif
240
-
241
- #define FIOBJ_NUMBER_SIGN_MASK ((~((uintptr_t)0)) >> 1)
242
- #define FIOBJ_NUMBER_SIGN_BIT (~FIOBJ_NUMBER_SIGN_MASK)
243
- #define FIOBJ_NUMBER_SIGN_EXCLUDE_BIT (FIOBJ_NUMBER_SIGN_BIT >> 1)
244
-
245
- #define FIOBJ_IS_ALLOCATED(o) \
246
- ((o) && ((o)&FIOBJECT_NUMBER_FLAG) == 0 && \
247
- ((o)&FIOBJECT_PRIMITIVE_FLAG) != FIOBJECT_PRIMITIVE_FLAG)
248
- #define FIOBJ2PTR(o) ((void *)((o)&FIOBJECT_TYPE_MASK))
249
-
250
- FIO_INLINE fiobj_type_enum fiobj_type(FIOBJ o) {
251
- if (!o)
252
- return FIOBJ_T_NULL;
253
- if (o & FIOBJECT_NUMBER_FLAG)
254
- return FIOBJ_T_NUMBER;
255
- if ((o & FIOBJECT_PRIMITIVE_FLAG) == FIOBJECT_PRIMITIVE_FLAG)
256
- return (fiobj_type_enum)o;
257
- if (FIOBJECT_STRING_FLAG &&
258
- (o & FIOBJECT_PRIMITIVE_FLAG) == FIOBJECT_STRING_FLAG)
259
- return FIOBJ_T_STRING;
260
- if (FIOBJECT_HASH_FLAG && (o & FIOBJECT_PRIMITIVE_FLAG) == FIOBJECT_HASH_FLAG)
261
- return FIOBJ_T_HASH;
262
- return ((fiobj_type_enum *)FIOBJ2PTR(o))[0];
263
- }
264
-
265
- /**
266
- * This is faster than getting the type, since the switch statement is
267
- * optimized away (it's calculated during compile time).
268
- */
269
- FIO_INLINE size_t fiobj_type_is(FIOBJ o, fiobj_type_enum type) {
270
- switch (type) {
271
- case FIOBJ_T_NUMBER:
272
- return (o & FIOBJECT_NUMBER_FLAG) ||
273
- (o && !(o & FIOBJECT_PRIMITIVE_FLAG) &&
274
- ((fiobj_type_enum *)o)[0] == FIOBJ_T_NUMBER);
275
- case FIOBJ_T_NULL:
276
- return !o || o == fiobj_null();
277
- case FIOBJ_T_TRUE:
278
- return o == fiobj_true();
279
- case FIOBJ_T_FALSE:
280
- return o == fiobj_false();
281
- case FIOBJ_T_STRING:
282
- return (FIOBJECT_STRING_FLAG && (o & FIOBJECT_NUMBER_FLAG) == 0 &&
283
- (o & FIOBJECT_PRIMITIVE_FLAG) == FIOBJECT_STRING_FLAG) ||
284
- (FIOBJECT_STRING_FLAG == 0 && FIOBJ_IS_ALLOCATED(o) &&
285
- ((fiobj_type_enum *)FIOBJ2PTR(o))[0] == FIOBJ_T_STRING);
286
- case FIOBJ_T_HASH:
287
- if (FIOBJECT_HASH_FLAG) {
288
- return ((o & FIOBJECT_NUMBER_FLAG) == 0 &&
289
- (o & FIOBJECT_PRIMITIVE_FLAG) == FIOBJECT_HASH_FLAG);
290
- }
291
- /* fallthrough */
292
- case FIOBJ_T_FLOAT:
293
- case FIOBJ_T_ARRAY:
294
- case FIOBJ_T_DATA:
295
- case FIOBJ_T_UNKNOWN:
296
- return FIOBJ_IS_ALLOCATED(o) &&
297
- ((fiobj_type_enum *)FIOBJ2PTR(o))[0] == type;
298
- }
299
- return FIOBJ_IS_ALLOCATED(o) && ((fiobj_type_enum *)FIOBJ2PTR(o))[0] == type;
300
- }
301
-
302
- /* *****************************************************************************
303
- Object Header
304
- ***************************************************************************** */
305
-
306
- typedef struct {
307
- /* a String allowing logging type data. */
308
- const char *class_name;
309
- /* deallocate root object's memory, perform task for each nested object. */
310
- void (*const dealloc)(FIOBJ, void (*task)(FIOBJ, void *), void *);
311
- /* return the number of normal nested object */
312
- uintptr_t (*const count)(const FIOBJ);
313
- /* tests the object for truthfulness. */
314
- size_t (*const is_true)(const FIOBJ);
315
- /* tests if two objects are equal. */
316
- size_t (*const is_eq)(const FIOBJ, const FIOBJ);
317
- /* iterates through the normal nested objects (ignore deep nesting) */
318
- size_t (*const each)(FIOBJ, size_t start_at, int (*task)(FIOBJ, void *),
319
- void *);
320
- /* object value as String */
321
- fio_str_info_s (*const to_str)(const FIOBJ);
322
- /* object value as Integer */
323
- intptr_t (*const to_i)(const FIOBJ);
324
- /* object value as Float */
325
- double (*const to_f)(const FIOBJ);
326
- } fiobj_object_vtable_s;
327
-
328
- typedef struct {
329
- /* must be first */
330
- fiobj_type_enum type;
331
- /* reference counter */
332
- uint32_t ref;
333
- } fiobj_object_header_s;
334
-
335
- extern const fiobj_object_vtable_s FIOBJECT_VTABLE_NUMBER;
336
- extern const fiobj_object_vtable_s FIOBJECT_VTABLE_FLOAT;
337
- extern const fiobj_object_vtable_s FIOBJECT_VTABLE_STRING;
338
- extern const fiobj_object_vtable_s FIOBJECT_VTABLE_ARRAY;
339
- extern const fiobj_object_vtable_s FIOBJECT_VTABLE_HASH;
340
- extern const fiobj_object_vtable_s FIOBJECT_VTABLE_DATA;
341
-
342
- #define FIOBJECT2VTBL(o) fiobj_type_vtable(o)
343
- #define FIOBJECT2HEAD(o) (((fiobj_object_header_s *)FIOBJ2PTR((o))))
344
-
345
- FIO_INLINE const fiobj_object_vtable_s *fiobj_type_vtable(FIOBJ o) {
346
- switch (FIOBJ_TYPE(o)) {
347
- case FIOBJ_T_NUMBER:
348
- return &FIOBJECT_VTABLE_NUMBER;
349
- case FIOBJ_T_FLOAT:
350
- return &FIOBJECT_VTABLE_FLOAT;
351
- case FIOBJ_T_STRING:
352
- return &FIOBJECT_VTABLE_STRING;
353
- case FIOBJ_T_ARRAY:
354
- return &FIOBJECT_VTABLE_ARRAY;
355
- case FIOBJ_T_HASH:
356
- return &FIOBJECT_VTABLE_HASH;
357
- case FIOBJ_T_DATA:
358
- return &FIOBJECT_VTABLE_DATA;
359
- case FIOBJ_T_NULL:
360
- case FIOBJ_T_TRUE:
361
- case FIOBJ_T_FALSE:
362
- case FIOBJ_T_UNKNOWN:
363
- return NULL;
364
- }
365
- return NULL;
366
- }
367
-
368
- /* *****************************************************************************
369
- Atomic reference counting
370
- ***************************************************************************** */
371
-
372
- /* C11 Atomics are defined? */
373
- #if defined(__ATOMIC_RELAXED)
374
- /** An atomic addition operation */
375
- #define fiobj_ref_inc(o) \
376
- __atomic_add_fetch(&FIOBJECT2HEAD(o)->ref, 1, __ATOMIC_SEQ_CST)
377
- /** An atomic subtraction operation */
378
- #define fiobj_ref_dec(o) \
379
- __atomic_sub_fetch(&FIOBJECT2HEAD(o)->ref, 1, __ATOMIC_SEQ_CST)
380
-
381
- /* Select the correct compiler builtin method. */
382
- #elif defined(__has_builtin) && !FIO_GNUC_BYPASS
383
-
384
- #if __has_builtin(__sync_fetch_and_or)
385
- /** An atomic addition operation */
386
- #define fiobj_ref_inc(o) __sync_add_and_fetch(&FIOBJECT2HEAD(o)->ref, 1)
387
- /** An atomic subtraction operation */
388
- #define fiobj_ref_dec(o) __sync_sub_and_fetch(&FIOBJECT2HEAD(o)->ref, 1)
389
-
390
- #else
391
- #error missing required atomic options.
392
- #endif /* defined(__has_builtin) */
393
-
394
- #elif __GNUC__ > 3
395
- /** An atomic addition operation */
396
- #define fiobj_ref_inc(o) __sync_add_and_fetch(&FIOBJECT2HEAD(o)->ref, 1)
397
- /** An atomic subtraction operation */
398
- #define fiobj_ref_dec(o) __sync_sub_and_fetch(&FIOBJECT2HEAD(o)->ref, 1)
399
-
400
- #else
401
- #error missing required atomic options.
402
- #endif
403
-
404
- #define OBJREF_ADD(o) fiobj_ref_inc(o)
405
- #define OBJREF_REM(o) fiobj_ref_dec(o)
406
-
407
- /* *****************************************************************************
408
- Inlined Functions
409
- ***************************************************************************** */
410
-
411
- /** Returns a C string naming the objects dynamic type. */
412
- FIO_INLINE const char *fiobj_type_name(const FIOBJ o) {
413
- if (o & FIOBJECT_NUMBER_FLAG)
414
- return "Number";
415
- if (FIOBJ_IS_ALLOCATED(o))
416
- return FIOBJECT2VTBL(o)->class_name;
417
- if (!o)
418
- return "NULL";
419
- return "Primitive";
420
- }
421
-
422
- /** used internally to free objects with nested objects. */
423
- void fiobj_free_complex_object(FIOBJ o);
424
-
425
- /**
426
- * Copy by reference(!) - increases an object's (and any nested object's)
427
- * reference count.
428
- *
429
- * Always returns the value passed along.
430
- */
431
- FIO_INLINE FIOBJ fiobj_dup(FIOBJ o) {
432
- if (FIOBJ_IS_ALLOCATED(o))
433
- OBJREF_ADD(o);
434
- return o;
435
- }
436
-
437
- /**
438
- * Decreases an object's reference count, releasing memory and
439
- * resources.
440
- *
441
- * This function affects nested objects, meaning that when an Array or
442
- * a Hash object is passed along, it's children (nested objects) are
443
- * also freed.
444
- *
445
- * Returns the number of existing references or zero if memory was released.
446
- */
447
- FIO_INLINE void fiobj_free(FIOBJ o) {
448
- if (!FIOBJ_IS_ALLOCATED(o))
449
- return;
450
- if (fiobj_ref_dec(o))
451
- return;
452
- if (FIOBJECT2VTBL(o)->each && FIOBJECT2VTBL(o)->count(o))
453
- fiobj_free_complex_object(o);
454
- else
455
- FIOBJECT2VTBL(o)->dealloc(o, NULL, NULL);
456
- }
457
-
458
- /**
459
- * Tests if an object evaluates as TRUE.
460
- *
461
- * This is object type specific. For example, empty strings might evaluate as
462
- * FALSE, even though they aren't a boolean type.
463
- */
464
- FIO_INLINE int fiobj_is_true(const FIOBJ o) {
465
- if (o & FIOBJECT_NUMBER_FLAG)
466
- return ((uintptr_t)o >> 1) != 0;
467
- if ((o & FIOBJECT_PRIMITIVE_FLAG) == FIOBJECT_PRIMITIVE_FLAG)
468
- return o == FIOBJ_T_TRUE;
469
- return (int)(FIOBJECT2VTBL(o)->is_true(o));
470
- }
471
-
472
- /**
473
- * Returns an object's numerical value.
474
- *
475
- * If a String or Symbol are passed to the function, they will be
476
- * parsed assuming base 10 numerical data.
477
- *
478
- * Hashes and Arrays return their object count.
479
- *
480
- * IO and File objects return their underlying file descriptor.
481
- *
482
- * A type error results in 0.
483
- */
484
- FIO_INLINE intptr_t fiobj_obj2num(const FIOBJ o) {
485
- if (o & FIOBJECT_NUMBER_FLAG) {
486
- const uintptr_t sign =
487
- (o & FIOBJ_NUMBER_SIGN_BIT)
488
- ? (FIOBJ_NUMBER_SIGN_BIT | FIOBJ_NUMBER_SIGN_EXCLUDE_BIT)
489
- : 0;
490
- return (intptr_t)(((o & FIOBJ_NUMBER_SIGN_MASK) >> 1) | sign);
491
- }
492
- if (!o || !FIOBJ_IS_ALLOCATED(o))
493
- return o == FIOBJ_T_TRUE;
494
- return FIOBJECT2VTBL(o)->to_i(o);
495
- }
496
-
497
- /** Converts a number to a temporary, thread safe, C string object */
498
- fio_str_info_s fio_ltocstr(long);
499
-
500
- /** Converts a float to a temporary, thread safe, C string object */
501
- fio_str_info_s fio_ftocstr(double);
502
-
503
- /**
504
- * Returns a C String (NUL terminated) using the `fio_str_info_s` data type.
505
- *
506
- * The String is binary safe and might contain NUL bytes in the middle as well as
507
- * a terminating NUL.
508
- *
509
- * If a a Number or a Float are passed to the function, they
510
- * will be parsed as a *temporary*, thread-safe, String.
511
- *
512
- * Numbers will be represented in base 10 numerical data.
513
- *
514
- * A type error results in NULL (i.e. object isn't a String).
515
- */
516
- FIO_INLINE fio_str_info_s fiobj_obj2cstr(const FIOBJ o) {
517
- if (!o) {
518
- fio_str_info_s ret = {0, 4, (char *)"null"};
519
- return ret;
520
- }
521
- if (o & FIOBJECT_NUMBER_FLAG)
522
- return fio_ltocstr(((intptr_t)o) >> 1);
523
- if ((o & FIOBJECT_PRIMITIVE_FLAG) == FIOBJECT_PRIMITIVE_FLAG) {
524
- switch ((fiobj_type_enum)o) {
525
- case FIOBJ_T_NULL: {
526
- fio_str_info_s ret = {0, 4, (char *)"null"};
527
- return ret;
528
- }
529
- case FIOBJ_T_FALSE: {
530
- fio_str_info_s ret = {0, 5, (char *)"false"};
531
- return ret;
532
- }
533
- case FIOBJ_T_TRUE: {
534
- fio_str_info_s ret = {0, 4, (char *)"true"};
535
- return ret;
536
- }
537
- default:
538
- break;
539
- }
540
- }
541
- return FIOBJECT2VTBL(o)->to_str(o);
542
- }
543
-
544
- /* referenced here */
545
- uint64_t fiobj_str_hash(FIOBJ o);
546
- /**
547
- * Calculates an Objects's SipHash value for possible use as a HashMap key.
548
- *
549
- * The Object MUST answer to the fiobj_obj2cstr, or the result is unusable. In
550
- * other words, Hash Objects and Arrays can NOT be used for Hash keys.
551
- */
552
- FIO_INLINE uint64_t fiobj_obj2hash(const FIOBJ o) {
553
- if (FIOBJ_TYPE_IS(o, FIOBJ_T_STRING))
554
- return fiobj_str_hash(o);
555
- if (!FIOBJ_IS_ALLOCATED(o))
556
- return (uint64_t)o;
557
- fio_str_info_s s = fiobj_obj2cstr(o);
558
- return FIO_HASH_FN(s.data, s.len, (uintptr_t)&fiobj_each2,
559
- (uintptr_t)&fiobj_free_complex_object);
560
- }
561
-
562
- FIO_INLINE uint64_t fiobj_hash_string(const void *data, size_t len) {
563
- return FIO_HASH_FN(data, len, (uintptr_t)&fiobj_each2,
564
- (uintptr_t)&fiobj_free_complex_object);
565
- }
566
-
567
- /**
568
- * Returns a Float's value.
569
- *
570
- * If a String or Symbol are passed to the function, they will be
571
- * parsed assuming base 10 numerical data.
572
- *
573
- * Hashes and Arrays return their object count.
574
- *
575
- * IO and File objects return their underlying file descriptor.
576
- *
577
- * A type error results in 0.
578
- */
579
- FIO_INLINE double fiobj_obj2float(const FIOBJ o) {
580
- if (o & FIOBJECT_NUMBER_FLAG)
581
- return (double)(fiobj_obj2num(o));
582
- if (!o || (o & FIOBJECT_PRIMITIVE_FLAG) == FIOBJECT_PRIMITIVE_FLAG)
583
- return (double)(o == FIOBJ_T_TRUE);
584
- return FIOBJECT2VTBL(o)->to_f(o);
585
- }
586
-
587
- /** used internally for complext nested tests (Array / Hash types) */
588
- int fiobj_iseq____internal_complex__(FIOBJ o, FIOBJ o2);
589
- /**
590
- * Deeply compare two objects. No hashing or recursive function calls are
591
- * involved.
592
- *
593
- * Uses a similar algorithm to `fiobj_each2`, except adjusted to two objects.
594
- *
595
- * Hash order will be tested when comapring Hashes.
596
- *
597
- * KNOWN ISSUES:
598
- *
599
- * * Temporarily broken for collections (Arrays / Hashes).
600
- *
601
- * * Hash order will be tested as well as the Hash content, which means that
602
- * equal Hashes might be considered unequal if their order doesn't match.
603
- *
604
- * Returns 1 if true and 0 if false.
605
- */
606
- FIO_INLINE int fiobj_iseq(const FIOBJ o, const FIOBJ o2) {
607
- if (o == o2)
608
- return 1;
609
- if (!o || !o2)
610
- return 0; /* they should have compared equal before. */
611
- if (!FIOBJ_IS_ALLOCATED(o) || !FIOBJ_IS_ALLOCATED(o2))
612
- return 0; /* they should have compared equal before. */
613
- if (FIOBJECT2HEAD(o)->type != FIOBJECT2HEAD(o2)->type)
614
- return 0; /* non-type equality is a barriar to equality. */
615
- if (!FIOBJECT2VTBL(o)->is_eq(o, o2))
616
- return 0;
617
- if (FIOBJECT2VTBL(o)->each && FIOBJECT2VTBL(o)->count(o))
618
- return fiobj_iseq____internal_complex__((FIOBJ)o, (FIOBJ)o2);
619
- return 1;
620
- }
621
-
622
- /**
623
- * Single layer iteration using a callback for each nested fio object.
624
- *
625
- * Accepts any `FIOBJ ` type but only collections (Arrays and Hashes) are
626
- * processed. The container itself (the Array or the Hash) is **not** processed
627
- * (unlike `fiobj_each2`).
628
- *
629
- * The callback task function must accept an object and an opaque user pointer.
630
- *
631
- * Hash objects pass along a `FIOBJ_T_COUPLET` object, containing
632
- * references for both the key and the object. Keys shouldn't be altered once
633
- * placed as a key (or the Hash will break). Collections (Arrays / Hashes) can't
634
- * be used as keeys.
635
- *
636
- * If the callback returns -1, the loop is broken. Any other value is ignored.
637
- *
638
- * Returns the "stop" position, i.e., the number of items processed + the
639
- * starting point.
640
- */
641
- FIO_INLINE size_t fiobj_each1(FIOBJ o, size_t start_at,
642
- int (*task)(FIOBJ obj, void *arg), void *arg) {
643
- if (FIOBJ_IS_ALLOCATED(o) && FIOBJECT2VTBL(o)->each)
644
- return FIOBJECT2VTBL(o)->each(o, start_at, task, arg);
645
- return 0;
646
- }
647
-
648
- #if DEBUG
649
- void fiobj_test_core(void);
650
- #endif
651
-
652
- #ifdef __cplusplus
653
- } /* closing brace for extern "C" */
654
- #endif
655
- #endif