rage-iodine 1.7.58

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
  3. data/.github/workflows/ruby.yml +42 -0
  4. data/.gitignore +20 -0
  5. data/.rspec +2 -0
  6. data/.yardopts +8 -0
  7. data/CHANGELOG.md +1098 -0
  8. data/Gemfile +11 -0
  9. data/LICENSE.txt +21 -0
  10. data/LIMITS.md +41 -0
  11. data/README.md +782 -0
  12. data/Rakefile +23 -0
  13. data/SPEC-PubSub-Draft.md +159 -0
  14. data/SPEC-WebSocket-Draft.md +239 -0
  15. data/bin/console +22 -0
  16. data/bin/info.md +353 -0
  17. data/bin/mustache_bench.rb +100 -0
  18. data/bin/poc/Gemfile.lock +23 -0
  19. data/bin/poc/README.md +37 -0
  20. data/bin/poc/config.ru +66 -0
  21. data/bin/poc/gemfile +1 -0
  22. data/bin/poc/www/index.html +57 -0
  23. data/examples/async_task.ru +92 -0
  24. data/examples/bates/README.md +3 -0
  25. data/examples/bates/config.ru +342 -0
  26. data/examples/bates/david+bold.pdf +0 -0
  27. data/examples/bates/public/drop-pdf.png +0 -0
  28. data/examples/bates/public/index.html +600 -0
  29. data/examples/config.ru +59 -0
  30. data/examples/echo.ru +59 -0
  31. data/examples/etag.ru +16 -0
  32. data/examples/hello.ru +29 -0
  33. data/examples/pubsub_engine.ru +81 -0
  34. data/examples/rack3.ru +12 -0
  35. data/examples/redis.ru +70 -0
  36. data/examples/shootout.ru +73 -0
  37. data/examples/sub-protocols.ru +90 -0
  38. data/examples/tcp_client.rb +66 -0
  39. data/examples/x-sendfile.ru +14 -0
  40. data/exe/iodine +280 -0
  41. data/ext/iodine/extconf.rb +110 -0
  42. data/ext/iodine/fio.c +12096 -0
  43. data/ext/iodine/fio.h +6390 -0
  44. data/ext/iodine/fio_cli.c +431 -0
  45. data/ext/iodine/fio_cli.h +189 -0
  46. data/ext/iodine/fio_json_parser.h +687 -0
  47. data/ext/iodine/fio_siphash.c +157 -0
  48. data/ext/iodine/fio_siphash.h +37 -0
  49. data/ext/iodine/fio_tls.h +129 -0
  50. data/ext/iodine/fio_tls_missing.c +649 -0
  51. data/ext/iodine/fio_tls_openssl.c +1056 -0
  52. data/ext/iodine/fio_tmpfile.h +50 -0
  53. data/ext/iodine/fiobj.h +44 -0
  54. data/ext/iodine/fiobj4fio.h +21 -0
  55. data/ext/iodine/fiobj_ary.c +333 -0
  56. data/ext/iodine/fiobj_ary.h +139 -0
  57. data/ext/iodine/fiobj_data.c +1185 -0
  58. data/ext/iodine/fiobj_data.h +167 -0
  59. data/ext/iodine/fiobj_hash.c +409 -0
  60. data/ext/iodine/fiobj_hash.h +176 -0
  61. data/ext/iodine/fiobj_json.c +622 -0
  62. data/ext/iodine/fiobj_json.h +68 -0
  63. data/ext/iodine/fiobj_mem.h +71 -0
  64. data/ext/iodine/fiobj_mustache.c +317 -0
  65. data/ext/iodine/fiobj_mustache.h +62 -0
  66. data/ext/iodine/fiobj_numbers.c +344 -0
  67. data/ext/iodine/fiobj_numbers.h +127 -0
  68. data/ext/iodine/fiobj_str.c +433 -0
  69. data/ext/iodine/fiobj_str.h +172 -0
  70. data/ext/iodine/fiobject.c +620 -0
  71. data/ext/iodine/fiobject.h +654 -0
  72. data/ext/iodine/hpack.h +1923 -0
  73. data/ext/iodine/http.c +2736 -0
  74. data/ext/iodine/http.h +1019 -0
  75. data/ext/iodine/http1.c +825 -0
  76. data/ext/iodine/http1.h +29 -0
  77. data/ext/iodine/http1_parser.h +1835 -0
  78. data/ext/iodine/http_internal.c +1279 -0
  79. data/ext/iodine/http_internal.h +248 -0
  80. data/ext/iodine/http_mime_parser.h +350 -0
  81. data/ext/iodine/iodine.c +1433 -0
  82. data/ext/iodine/iodine.h +64 -0
  83. data/ext/iodine/iodine_caller.c +218 -0
  84. data/ext/iodine/iodine_caller.h +27 -0
  85. data/ext/iodine/iodine_connection.c +941 -0
  86. data/ext/iodine/iodine_connection.h +55 -0
  87. data/ext/iodine/iodine_defer.c +420 -0
  88. data/ext/iodine/iodine_defer.h +6 -0
  89. data/ext/iodine/iodine_fiobj2rb.h +120 -0
  90. data/ext/iodine/iodine_helpers.c +282 -0
  91. data/ext/iodine/iodine_helpers.h +12 -0
  92. data/ext/iodine/iodine_http.c +1280 -0
  93. data/ext/iodine/iodine_http.h +23 -0
  94. data/ext/iodine/iodine_json.c +302 -0
  95. data/ext/iodine/iodine_json.h +6 -0
  96. data/ext/iodine/iodine_mustache.c +567 -0
  97. data/ext/iodine/iodine_mustache.h +6 -0
  98. data/ext/iodine/iodine_pubsub.c +580 -0
  99. data/ext/iodine/iodine_pubsub.h +26 -0
  100. data/ext/iodine/iodine_rack_io.c +273 -0
  101. data/ext/iodine/iodine_rack_io.h +20 -0
  102. data/ext/iodine/iodine_store.c +142 -0
  103. data/ext/iodine/iodine_store.h +20 -0
  104. data/ext/iodine/iodine_tcp.c +346 -0
  105. data/ext/iodine/iodine_tcp.h +13 -0
  106. data/ext/iodine/iodine_tls.c +261 -0
  107. data/ext/iodine/iodine_tls.h +13 -0
  108. data/ext/iodine/mustache_parser.h +1546 -0
  109. data/ext/iodine/redis_engine.c +957 -0
  110. data/ext/iodine/redis_engine.h +79 -0
  111. data/ext/iodine/resp_parser.h +317 -0
  112. data/ext/iodine/scheduler.c +173 -0
  113. data/ext/iodine/scheduler.h +6 -0
  114. data/ext/iodine/websocket_parser.h +506 -0
  115. data/ext/iodine/websockets.c +752 -0
  116. data/ext/iodine/websockets.h +185 -0
  117. data/iodine.gemspec +50 -0
  118. data/lib/iodine/connection.rb +61 -0
  119. data/lib/iodine/json.rb +42 -0
  120. data/lib/iodine/mustache.rb +113 -0
  121. data/lib/iodine/pubsub.rb +55 -0
  122. data/lib/iodine/rack_utils.rb +43 -0
  123. data/lib/iodine/tls.rb +16 -0
  124. data/lib/iodine/version.rb +3 -0
  125. data/lib/iodine.rb +274 -0
  126. data/lib/rack/handler/iodine.rb +33 -0
  127. data/logo.png +0 -0
  128. metadata +284 -0
@@ -0,0 +1,344 @@
1
+ /*
2
+ Copyright: Boaz Segev, 2017-2019
3
+ License: MIT
4
+ */
5
+
6
+ #include <fiobj_numbers.h>
7
+ #include <fiobject.h>
8
+
9
+ #include <fio.h>
10
+
11
+ #include <assert.h>
12
+ #include <errno.h>
13
+ #include <math.h>
14
+
15
+ #include <pthread.h>
16
+
17
+ /* *****************************************************************************
18
+ Numbers Type
19
+ ***************************************************************************** */
20
+
21
+ typedef struct {
22
+ fiobj_object_header_s head;
23
+ intptr_t i;
24
+ } fiobj_num_s;
25
+
26
+ typedef struct {
27
+ fiobj_object_header_s head;
28
+ double f;
29
+ } fiobj_float_s;
30
+
31
+ #define obj2num(o) ((fiobj_num_s *)FIOBJ2PTR(o))
32
+ #define obj2float(o) ((fiobj_float_s *)FIOBJ2PTR(o))
33
+
34
+ /* *****************************************************************************
35
+ Numbers VTable
36
+ ***************************************************************************** */
37
+
38
+ static pthread_key_t num_vt_buffer_key;
39
+ static pthread_once_t num_vt_buffer_once = PTHREAD_ONCE_INIT;
40
+ static void init_num_vt_buffer_key(void) {
41
+ pthread_key_create(&num_vt_buffer_key, free);
42
+ }
43
+ static void init_num_vt_buffer_ptr(void) {
44
+ char *num_vt_buffer = malloc(sizeof(char)*512);
45
+ FIO_ASSERT_ALLOC(num_vt_buffer);
46
+ memset(num_vt_buffer, 0, sizeof(char)*512);
47
+ pthread_setspecific(num_vt_buffer_key, num_vt_buffer);
48
+ }
49
+
50
+ static intptr_t fio_i2i(const FIOBJ o) { return obj2num(o)->i; }
51
+ static intptr_t fio_f2i(const FIOBJ o) {
52
+ return (intptr_t)floorl(obj2float(o)->f);
53
+ }
54
+ static double fio_i2f(const FIOBJ o) { return (double)obj2num(o)->i; }
55
+ static double fio_f2f(const FIOBJ o) { return obj2float(o)->f; }
56
+
57
+ static size_t fio_itrue(const FIOBJ o) { return (obj2num(o)->i != 0); }
58
+ static size_t fio_ftrue(const FIOBJ o) { return (obj2float(o)->f != 0); }
59
+
60
+ static fio_str_info_s fio_i2str(const FIOBJ o) {
61
+ pthread_once(&num_vt_buffer_once, init_num_vt_buffer_key);
62
+ char *num_buffer = pthread_getspecific(num_vt_buffer_key);
63
+ if (!num_buffer) {
64
+ init_num_vt_buffer_ptr();
65
+ num_buffer = pthread_getspecific(num_vt_buffer_key);
66
+ }
67
+ return (fio_str_info_s){
68
+ .data = num_buffer,
69
+ .len = fio_ltoa(num_buffer, obj2num(o)->i, 10),
70
+ };
71
+ }
72
+ static fio_str_info_s fio_f2str(const FIOBJ o) {
73
+ if (isnan(obj2float(o)->f))
74
+ return (fio_str_info_s){.data = (char *)"NaN", .len = 3};
75
+ else if (isinf(obj2float(o)->f)) {
76
+ if (obj2float(o)->f > 0)
77
+ return (fio_str_info_s){.data = (char *)"Infinity", .len = 8};
78
+ else
79
+ return (fio_str_info_s){.data = (char *)"-Infinity", .len = 9};
80
+ }
81
+ pthread_once(&num_vt_buffer_once, init_num_vt_buffer_key);
82
+ char *num_buffer = pthread_getspecific(num_vt_buffer_key);
83
+ if (!num_buffer) {
84
+ init_num_vt_buffer_ptr();
85
+ num_buffer = pthread_getspecific(num_vt_buffer_key);
86
+ }
87
+ return (fio_str_info_s){
88
+ .data = num_buffer,
89
+ .len = fio_ftoa(num_buffer, obj2float(o)->f, 10),
90
+ };
91
+ }
92
+
93
+ static size_t fiobj_i_is_eq(const FIOBJ self, const FIOBJ other) {
94
+ return obj2num(self)->i == obj2num(other)->i;
95
+ }
96
+ static size_t fiobj_f_is_eq(const FIOBJ self, const FIOBJ other) {
97
+ return obj2float(self)->f == obj2float(other)->f;
98
+ }
99
+
100
+ void fiobject___simple_dealloc(FIOBJ o, void (*task)(FIOBJ, void *), void *arg);
101
+ uintptr_t fiobject___noop_count(FIOBJ o);
102
+
103
+ const fiobj_object_vtable_s FIOBJECT_VTABLE_NUMBER = {
104
+ .class_name = "Number",
105
+ .to_i = fio_i2i,
106
+ .to_f = fio_i2f,
107
+ .to_str = fio_i2str,
108
+ .is_true = fio_itrue,
109
+ .is_eq = fiobj_i_is_eq,
110
+ .count = fiobject___noop_count,
111
+ .dealloc = fiobject___simple_dealloc,
112
+ };
113
+
114
+ const fiobj_object_vtable_s FIOBJECT_VTABLE_FLOAT = {
115
+ .class_name = "Float",
116
+ .to_i = fio_f2i,
117
+ .to_f = fio_f2f,
118
+ .is_true = fio_ftrue,
119
+ .to_str = fio_f2str,
120
+ .is_eq = fiobj_f_is_eq,
121
+ .count = fiobject___noop_count,
122
+ .dealloc = fiobject___simple_dealloc,
123
+ };
124
+
125
+ /* *****************************************************************************
126
+ Number API
127
+ ***************************************************************************** */
128
+
129
+ /** Creates a Number object. Remember to use `fiobj_free`. */
130
+ FIOBJ fiobj_num_new_bignum(intptr_t num) {
131
+ fiobj_num_s *o = fio_malloc(sizeof(*o));
132
+ if (!o) {
133
+ perror("ERROR: fiobj number couldn't allocate memory");
134
+ exit(errno);
135
+ }
136
+ *o = (fiobj_num_s){
137
+ .head =
138
+ {
139
+ .type = FIOBJ_T_NUMBER,
140
+ .ref = 1,
141
+ },
142
+ .i = num,
143
+ };
144
+ return (FIOBJ)o;
145
+ }
146
+
147
+ /** Mutates a Big Number object's value. Effects every object's reference! */
148
+ // void fiobj_num_set(FIOBJ target, intptr_t num) {
149
+ // assert(FIOBJ_TYPE_IS(target, FIOBJ_T_NUMBER) &&
150
+ // FIOBJ_IS_ALLOCATED(target)); obj2num(target)->i = num;
151
+ // }
152
+
153
+ static pthread_key_t num_ret_key;
154
+ static pthread_once_t num_ret_once = PTHREAD_ONCE_INIT;
155
+ static void init_num_ret_key(void) {
156
+ pthread_key_create(&num_ret_key, free);
157
+ }
158
+ static void init_num_ret_ptr(void) {
159
+ fiobj_num_s *ret = malloc(sizeof(fiobj_num_s));
160
+ FIO_ASSERT_ALLOC(ret);
161
+ memset(ret, 0, sizeof(fiobj_num_s));
162
+ pthread_setspecific(num_ret_key, ret);
163
+ }
164
+ /** Creates a temporary Number object. This ignores `fiobj_free`. */
165
+ FIOBJ fiobj_num_tmp(intptr_t num) {
166
+ pthread_once(&num_ret_once, init_num_ret_key);
167
+ fiobj_num_s *ret = pthread_getspecific(num_ret_key);
168
+ if (!ret) {
169
+ init_num_ret_ptr();
170
+ ret = pthread_getspecific(num_ret_key);
171
+ }
172
+ *ret = (fiobj_num_s){
173
+ .head = {.type = FIOBJ_T_NUMBER, .ref = ((~(uint32_t)0) >> 4)},
174
+ .i = num,
175
+ };
176
+ return (FIOBJ)ret;
177
+ }
178
+
179
+ /* *****************************************************************************
180
+ Float API
181
+ ***************************************************************************** */
182
+
183
+ /** Creates a Float object. Remember to use `fiobj_free`. */
184
+ FIOBJ fiobj_float_new(double num) {
185
+ fiobj_float_s *o = fio_malloc(sizeof(*o));
186
+ if (!o) {
187
+ perror("ERROR: fiobj float couldn't allocate memory");
188
+ exit(errno);
189
+ }
190
+ *o = (fiobj_float_s){
191
+ .head =
192
+ {
193
+ .type = FIOBJ_T_FLOAT,
194
+ .ref = 1,
195
+ },
196
+ .f = num,
197
+ };
198
+ return (FIOBJ)o;
199
+ }
200
+
201
+ /** Mutates a Float object's value. Effects every object's reference! */
202
+ void fiobj_float_set(FIOBJ obj, double num) {
203
+ assert(FIOBJ_TYPE_IS(obj, FIOBJ_T_FLOAT));
204
+ obj2float(obj)->f = num;
205
+ }
206
+
207
+ static pthread_key_t float_ret_key;
208
+ static pthread_once_t float_ret_once = PTHREAD_ONCE_INIT;
209
+ static void init_float_ret_key(void) {
210
+ pthread_key_create(&float_ret_key, free);
211
+ }
212
+ static void init_float_ret_ptr(void) {
213
+ fiobj_float_s *ret = malloc(sizeof(fiobj_float_s));
214
+ FIO_ASSERT_ALLOC(ret);
215
+ memset(ret, 0, sizeof(fiobj_float_s));
216
+ pthread_setspecific(float_ret_key, ret);
217
+ }
218
+ /** Creates a temporary Number object. This ignores `fiobj_free`. */
219
+ FIOBJ fiobj_float_tmp(double num) {
220
+ pthread_once(&float_ret_once, init_float_ret_key);
221
+ fiobj_float_s *ret = pthread_getspecific(float_ret_key);
222
+ if (!ret) {
223
+ init_float_ret_ptr();
224
+ ret = pthread_getspecific(float_ret_key);
225
+ }
226
+ *ret = (fiobj_float_s){
227
+ .head =
228
+ {
229
+ .type = FIOBJ_T_FLOAT,
230
+ .ref = ((~(uint32_t)0) >> 4),
231
+ },
232
+ .f = num,
233
+ };
234
+ return (FIOBJ)ret;
235
+ }
236
+
237
+ /* *****************************************************************************
238
+ Numbers to Strings - Buffered
239
+ ***************************************************************************** */
240
+
241
+ static pthread_key_t num_str_buffer_key;
242
+ static pthread_once_t num_str_buffer_once = PTHREAD_ONCE_INIT;
243
+ static void init_num_str_buffer_key(void) {
244
+ pthread_key_create(&num_str_buffer_key, free);
245
+ }
246
+ static void init_num_str_buffer_ptr(void) {
247
+ char *num_str_buffer = malloc(sizeof(char)*512);
248
+ FIO_ASSERT_ALLOC(num_str_buffer);
249
+ memset(num_str_buffer, 0, sizeof(char)*512);
250
+ pthread_setspecific(num_str_buffer_key, num_str_buffer);
251
+ }
252
+
253
+ fio_str_info_s fio_ltocstr(long i) {
254
+ pthread_once(&num_str_buffer_once, init_num_str_buffer_key);
255
+ char *num_buffer = pthread_getspecific(num_str_buffer_key);
256
+ if (!num_buffer) {
257
+ init_num_str_buffer_ptr();
258
+ num_buffer = pthread_getspecific(num_str_buffer_key);
259
+ }
260
+ return (fio_str_info_s){.data = num_buffer,
261
+ .len = fio_ltoa(num_buffer, i, 10)};
262
+ }
263
+ fio_str_info_s fio_ftocstr(double f) {
264
+ pthread_once(&num_str_buffer_once, init_num_str_buffer_key);
265
+ char *num_buffer = pthread_getspecific(num_str_buffer_key);
266
+ if (!num_buffer) {
267
+ init_num_str_buffer_ptr();
268
+ num_buffer = pthread_getspecific(num_str_buffer_key);
269
+ }
270
+ return (fio_str_info_s){.data = num_buffer,
271
+ .len = fio_ftoa(num_buffer, f, 10)};
272
+ }
273
+
274
+ /* *****************************************************************************
275
+ Tests
276
+ ***************************************************************************** */
277
+
278
+ #if DEBUG
279
+ void fiobj_test_numbers(void) {
280
+ #define NUMTEST_ASSERT(cond, ...) \
281
+ if (!(cond)) { \
282
+ fprintf(stderr, __VA_ARGS__); \
283
+ fprintf(stderr, "Testing failed.\n"); \
284
+ exit(-1); \
285
+ }
286
+ FIOBJ i = fiobj_num_new(8);
287
+ fprintf(stderr, "=== Testing Numbers\n");
288
+ fprintf(stderr, "* FIOBJ_NUMBER_SIGN_MASK == %p\n",
289
+ (void *)FIOBJ_NUMBER_SIGN_MASK);
290
+ fprintf(stderr, "* FIOBJ_NUMBER_SIGN_BIT == %p\n",
291
+ (void *)FIOBJ_NUMBER_SIGN_BIT);
292
+ fprintf(stderr, "* FIOBJ_NUMBER_SIGN_EXCLUDE_BIT == %p\n",
293
+ (void *)FIOBJ_NUMBER_SIGN_EXCLUDE_BIT);
294
+ NUMTEST_ASSERT(FIOBJ_TYPE_IS(i, FIOBJ_T_NUMBER),
295
+ "* FIOBJ_TYPE_IS failed to return true.");
296
+ NUMTEST_ASSERT((FIOBJ_TYPE(i) == FIOBJ_T_NUMBER),
297
+ "* FIOBJ_TYPE failed to return type.");
298
+ NUMTEST_ASSERT(!FIOBJ_TYPE_IS(i, FIOBJ_T_NULL),
299
+ "* FIOBJ_TYPE_IS failed to return false.");
300
+ NUMTEST_ASSERT((i & FIOBJECT_NUMBER_FLAG),
301
+ "* Number 8 was dynamically allocated?! %p\n", (void *)i);
302
+ NUMTEST_ASSERT((fiobj_obj2num(i) == 8), "* Number 8 was not returned! %p\n",
303
+ (void *)i);
304
+ fiobj_free(i);
305
+ i = fiobj_num_new(-1);
306
+ NUMTEST_ASSERT((i & FIOBJECT_NUMBER_FLAG),
307
+ "* Number -1 was dynamically allocated?! %p\n", (void *)i);
308
+ NUMTEST_ASSERT((fiobj_obj2num(i) == -1), "* Number -1 was not returned! %p\n",
309
+ (void *)i);
310
+ fiobj_free(i);
311
+ i = fiobj_num_new(INTPTR_MAX);
312
+ NUMTEST_ASSERT((i & FIOBJECT_NUMBER_FLAG) == 0,
313
+ "* INTPTR_MAX was statically allocated?! %p\n", (void *)i);
314
+ NUMTEST_ASSERT((fiobj_obj2num(i) == INTPTR_MAX),
315
+ "* INTPTR_MAX was not returned! %p\n", (void *)i);
316
+ NUMTEST_ASSERT(
317
+ FIOBJ_TYPE_IS(i, FIOBJ_T_NUMBER),
318
+ "* FIOBJ_TYPE_IS failed to return true for dynamic allocation.");
319
+ NUMTEST_ASSERT((FIOBJ_TYPE(i) == FIOBJ_T_NUMBER),
320
+ "* FIOBJ_TYPE failed to return type for dynamic allocation.");
321
+ fiobj_free(i);
322
+ i = fiobj_num_new(INTPTR_MIN);
323
+ NUMTEST_ASSERT((i & FIOBJECT_NUMBER_FLAG) == 0,
324
+ "* INTPTR_MIN was statically allocated?! %p\n", (void *)i);
325
+ NUMTEST_ASSERT((fiobj_obj2num(i) == INTPTR_MIN),
326
+ "* INTPTR_MIN was not returned! %p\n", (void *)i);
327
+ fiobj_free(i);
328
+ fprintf(stderr, "* passed.\n");
329
+ fprintf(stderr, "=== Testing Floats\n");
330
+ i = fiobj_float_new(1.0);
331
+ NUMTEST_ASSERT(((i & FIOBJECT_NUMBER_FLAG) == 0),
332
+ "* float 1 was statically allocated?! %p\n", (void *)i);
333
+ NUMTEST_ASSERT((fiobj_obj2float(i) == 1.0),
334
+ "* Float 1.0 was not returned! %p\n", (void *)i);
335
+ fiobj_free(i);
336
+ i = fiobj_float_new(-1.0);
337
+ NUMTEST_ASSERT((i & FIOBJECT_NUMBER_FLAG) == 0,
338
+ "* Float -1 was statically allocated?! %p\n", (void *)i);
339
+ NUMTEST_ASSERT((fiobj_obj2float(i) == -1.0),
340
+ "* Float -1 was not returned! %p\n", (void *)i);
341
+ fiobj_free(i);
342
+ fprintf(stderr, "* passed.\n");
343
+ }
344
+ #endif
@@ -0,0 +1,127 @@
1
+ #ifndef H_FIOBJ_NUMBERS_H
2
+ #define H_FIOBJ_NUMBERS_H
3
+ /*
4
+ Copyright: Boaz Segev, 2017-2019
5
+ License: MIT
6
+ */
7
+
8
+ #include <fiobject.h>
9
+
10
+ #ifdef __cplusplus
11
+ extern "C" {
12
+ #endif
13
+
14
+ /* *****************************************************************************
15
+ Numbers API (Integers)
16
+ ***************************************************************************** */
17
+
18
+ /** Creates a Number object. Remember to use `fiobj_free`. */
19
+ FIO_INLINE FIOBJ fiobj_num_new(intptr_t num);
20
+
21
+ /** Creates a temporary Number object. Avoid using `fiobj_free`. */
22
+ FIOBJ fiobj_num_tmp(intptr_t num);
23
+
24
+ /* *****************************************************************************
25
+ Float API (Double)
26
+ ***************************************************************************** */
27
+
28
+ /** Creates a Float object. Remember to use `fiobj_free`. */
29
+ FIOBJ fiobj_float_new(double num);
30
+
31
+ /** Mutates a Float object's value. Effects every object's reference! */
32
+ void fiobj_float_set(FIOBJ obj, double num);
33
+
34
+ /** Creates a temporary Float object. Avoid using `fiobj_free`. */
35
+ FIOBJ fiobj_float_tmp(double num);
36
+
37
+ /* *****************************************************************************
38
+ Numerical Helpers: not FIOBJ specific, but included as part of the library
39
+ ***************************************************************************** */
40
+
41
+ /**
42
+ * A helper function that converts between String data to a signed int64_t.
43
+ *
44
+ * Numbers are assumed to be in base 10.
45
+ *
46
+ * The `0x##` (or `x##`) and `0b##` (or `b##`) are recognized as base 16 and
47
+ * base 2 (binary MSB first) respectively.
48
+ *
49
+ * The pointer will be updated to point to the first byte after the number.
50
+ */
51
+ int64_t fio_atol(char **pstr);
52
+
53
+ /** A helper function that converts between String data to a signed double. */
54
+ double fio_atof(char **pstr);
55
+
56
+ /**
57
+ * A helper function that converts between a signed int64_t to a string.
58
+ *
59
+ * No overflow guard is provided, make sure there's at least 66 bytes available
60
+ * (for base 2).
61
+ *
62
+ * Supports base 2, base 10 and base 16. An unsupported base will silently
63
+ * default to base 10. Prefixes aren't added (i.e., no "0x" or "0b" at the
64
+ * beginning of the string).
65
+ *
66
+ * Returns the number of bytes actually written (excluding the NUL terminator).
67
+ */
68
+ size_t fio_ltoa(char *dest, int64_t num, uint8_t base);
69
+
70
+ /**
71
+ * A helper function that converts between a double to a string.
72
+ *
73
+ * No overflow guard is provided, make sure there's at least 130 bytes available
74
+ * (for base 2).
75
+ *
76
+ * Supports base 2, base 10 and base 16. An unsupported base will silently
77
+ * default to base 10. Prefixes aren't added (i.e., no "0x" or "0b" at the
78
+ * beginning of the string).
79
+ *
80
+ * Returns the number of bytes actually written (excluding the NUL terminator).
81
+ */
82
+ size_t fio_ftoa(char *dest, double num, uint8_t base);
83
+
84
+ /** Converts a number to a temporary, thread safe, C string object */
85
+ fio_str_info_s __attribute__((deprecated("use local buffer with fio_ltoa")))
86
+ fio_ltocstr(long);
87
+
88
+ /** Converts a float to a temporary, thread safe, C string object */
89
+ fio_str_info_s __attribute__((deprecated("use local buffer with fio_ftoa")))
90
+ fio_ftocstr(double);
91
+
92
+ /* *****************************************************************************
93
+ Pointer Wrapping Helper MACROs (uses integers)
94
+ ***************************************************************************** */
95
+
96
+ #define fiobj_ptr_wrap(ptr) fiobj_num_new((uintptr_t)(ptr))
97
+ #define fiobj_ptr_unwrap(obj) ((void *)fiobj_obj2num((obj)))
98
+
99
+ /* *****************************************************************************
100
+ Inline Number Initialization
101
+ ***************************************************************************** */
102
+
103
+ FIOBJ fiobj_num_new_bignum(intptr_t num);
104
+
105
+ /** Creates a Number object. Remember to use `fiobj_free`. */
106
+ FIO_INLINE FIOBJ fiobj_num_new(intptr_t num) {
107
+ if ((((uintptr_t)num &
108
+ (FIOBJ_NUMBER_SIGN_BIT | FIOBJ_NUMBER_SIGN_EXCLUDE_BIT)) == 0) ||
109
+ (((uintptr_t)num &
110
+ (FIOBJ_NUMBER_SIGN_BIT | FIOBJ_NUMBER_SIGN_EXCLUDE_BIT)) ==
111
+ (FIOBJ_NUMBER_SIGN_BIT | FIOBJ_NUMBER_SIGN_EXCLUDE_BIT))) {
112
+ const uintptr_t num_abs = (uintptr_t)num & FIOBJ_NUMBER_SIGN_MASK;
113
+ const uintptr_t num_sign = (uintptr_t)num & FIOBJ_NUMBER_SIGN_BIT;
114
+ return ((num_abs << 1) | num_sign | FIOBJECT_NUMBER_FLAG);
115
+ }
116
+ return fiobj_num_new_bignum(num);
117
+ }
118
+
119
+ #if DEBUG
120
+ void fiobj_test_numbers(void);
121
+ #endif
122
+
123
+ #ifdef __cplusplus
124
+ } /* extern "C" */
125
+ #endif
126
+
127
+ #endif