iodine 0.7.59 → 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.
- checksums.yaml +4 -4
- data/.clang-format +15 -0
- data/.rspec +1 -0
- data/.yardopts +1 -3
- data/CHANGELOG.md +132 -12
- data/Gemfile +5 -7
- data/LICENSE.txt +1 -1
- data/README.md +147 -671
- data/Rakefile +9 -16
- data/examples/chatroom.nru +9 -0
- data/examples/client +74 -0
- data/examples/config-hello.nru +9 -0
- data/examples/config-hello.ru +11 -0
- data/examples/config-hijack.ru +13 -0
- data/examples/config-shootout.ru +43 -0
- data/examples/config.nru +120 -0
- data/examples/config.rb +37 -0
- data/examples/config.ru +42 -53
- data/examples/fake +24 -0
- data/examples/hello_neorack +137 -0
- data/examples/routes.nru +29 -0
- data/examples/routes.ru +42 -0
- data/exe/iodine +218 -258
- data/ext/iodine/extconf.rb +27 -100
- data/ext/iodine/fio-stl.h +128336 -0
- data/ext/iodine/fio-stl.md +26396 -0
- data/ext/iodine/iodine.c +213 -1393
- data/ext/iodine/iodine.h +250 -55
- data/ext/iodine/iodine_arg_helper.h +329 -0
- data/ext/iodine/iodine_caller.h +234 -25
- data/ext/iodine/iodine_cli.h +434 -0
- data/ext/iodine/iodine_compression.h +312 -0
- data/ext/iodine/iodine_connection.h +3484 -34
- data/ext/iodine/iodine_core.h +363 -0
- data/ext/iodine/iodine_crypto.h +1441 -0
- data/ext/iodine/iodine_defer.h +225 -4
- data/ext/iodine/iodine_json.h +738 -4
- data/ext/iodine/iodine_listener.h +263 -0
- data/ext/iodine/iodine_log.h +297 -0
- data/ext/iodine/iodine_minimap.h +543 -0
- data/ext/iodine/iodine_mustache.h +461 -4
- data/ext/iodine/iodine_pubsub_eng.h +729 -0
- data/ext/iodine/iodine_pubsub_history.h +547 -0
- data/ext/iodine/iodine_pubsub_msg.h +228 -0
- data/ext/iodine/iodine_redis.h +322 -0
- data/ext/iodine/iodine_store.h +418 -16
- data/ext/iodine/iodine_threads.h +279 -0
- data/ext/iodine/iodine_tls.h +515 -6
- data/ext/iodine/iodine_utils.h +923 -0
- data/iodine.gemspec +37 -42
- data/lib/iodine/benchmark.rb +1690 -0
- data/lib/iodine/documentation.rb +3085 -0
- data/lib/iodine/version.rb +17 -1
- data/lib/iodine.rb +54 -255
- data/logo.svg +36 -0
- data/mustache.md +55 -0
- data/sig/iodine.rbs +4 -0
- metadata +58 -184
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
- data/.github/workflows/ruby.yml +0 -42
- data/.gitignore +0 -20
- data/LIMITS.md +0 -41
- data/SPEC-PubSub-Draft.md +0 -159
- data/SPEC-WebSocket-Draft.md +0 -239
- data/bin/console +0 -22
- data/bin/info.md +0 -353
- data/bin/mustache_bench.rb +0 -100
- data/bin/poc/Gemfile.lock +0 -23
- data/bin/poc/README.md +0 -37
- data/bin/poc/config.ru +0 -66
- data/bin/poc/gemfile +0 -1
- data/bin/poc/www/index.html +0 -57
- data/examples/async_task.ru +0 -92
- data/examples/bates/README.md +0 -3
- data/examples/bates/config.ru +0 -342
- data/examples/bates/david+bold.pdf +0 -0
- data/examples/bates/public/drop-pdf.png +0 -0
- data/examples/bates/public/index.html +0 -600
- data/examples/echo.ru +0 -59
- data/examples/etag.ru +0 -16
- data/examples/hello.ru +0 -29
- data/examples/pubsub_engine.ru +0 -81
- data/examples/rack3.ru +0 -12
- data/examples/redis.ru +0 -70
- data/examples/shootout.ru +0 -73
- data/examples/sub-protocols.ru +0 -90
- data/examples/tcp_client.rb +0 -66
- data/examples/x-sendfile.ru +0 -14
- data/ext/iodine/fio.c +0 -11995
- data/ext/iodine/fio.h +0 -6371
- data/ext/iodine/fio_cli.c +0 -431
- data/ext/iodine/fio_cli.h +0 -189
- data/ext/iodine/fio_json_parser.h +0 -688
- data/ext/iodine/fio_siphash.c +0 -157
- data/ext/iodine/fio_siphash.h +0 -37
- data/ext/iodine/fio_tls.h +0 -129
- data/ext/iodine/fio_tls_missing.c +0 -649
- data/ext/iodine/fio_tls_openssl.c +0 -1106
- data/ext/iodine/fio_tmpfile.h +0 -50
- data/ext/iodine/fiobj.h +0 -44
- data/ext/iodine/fiobj4fio.h +0 -21
- data/ext/iodine/fiobj_ary.c +0 -333
- data/ext/iodine/fiobj_ary.h +0 -139
- data/ext/iodine/fiobj_data.c +0 -1187
- data/ext/iodine/fiobj_data.h +0 -167
- data/ext/iodine/fiobj_hash.c +0 -409
- data/ext/iodine/fiobj_hash.h +0 -176
- data/ext/iodine/fiobj_json.c +0 -622
- data/ext/iodine/fiobj_json.h +0 -68
- data/ext/iodine/fiobj_mem.h +0 -71
- data/ext/iodine/fiobj_mustache.c +0 -317
- data/ext/iodine/fiobj_mustache.h +0 -62
- data/ext/iodine/fiobj_numbers.c +0 -344
- data/ext/iodine/fiobj_numbers.h +0 -127
- data/ext/iodine/fiobj_str.c +0 -433
- data/ext/iodine/fiobj_str.h +0 -172
- data/ext/iodine/fiobject.c +0 -620
- data/ext/iodine/fiobject.h +0 -655
- data/ext/iodine/hpack.h +0 -1923
- data/ext/iodine/http.c +0 -2743
- data/ext/iodine/http.h +0 -1002
- data/ext/iodine/http1.c +0 -910
- data/ext/iodine/http1.h +0 -29
- data/ext/iodine/http1_parser.h +0 -878
- data/ext/iodine/http_internal.c +0 -1279
- data/ext/iodine/http_internal.h +0 -237
- data/ext/iodine/http_mime_parser.h +0 -350
- data/ext/iodine/iodine_caller.c +0 -230
- data/ext/iodine/iodine_connection.c +0 -941
- data/ext/iodine/iodine_defer.c +0 -420
- data/ext/iodine/iodine_fiobj2rb.h +0 -120
- data/ext/iodine/iodine_helpers.c +0 -282
- data/ext/iodine/iodine_helpers.h +0 -12
- data/ext/iodine/iodine_http.c +0 -1181
- data/ext/iodine/iodine_http.h +0 -23
- data/ext/iodine/iodine_json.c +0 -302
- data/ext/iodine/iodine_mustache.c +0 -567
- data/ext/iodine/iodine_pubsub.c +0 -580
- data/ext/iodine/iodine_pubsub.h +0 -26
- data/ext/iodine/iodine_rack_io.c +0 -273
- data/ext/iodine/iodine_rack_io.h +0 -20
- data/ext/iodine/iodine_store.c +0 -146
- data/ext/iodine/iodine_tcp.c +0 -346
- data/ext/iodine/iodine_tcp.h +0 -13
- data/ext/iodine/iodine_tls.c +0 -261
- data/ext/iodine/mustache_parser.h +0 -1546
- data/ext/iodine/redis_engine.c +0 -957
- data/ext/iodine/redis_engine.h +0 -79
- data/ext/iodine/resp_parser.h +0 -317
- data/ext/iodine/websocket_parser.h +0 -506
- data/ext/iodine/websockets.c +0 -743
- data/ext/iodine/websockets.h +0 -185
- data/lib/iodine/connection.rb +0 -61
- data/lib/iodine/json.rb +0 -42
- data/lib/iodine/mustache.rb +0 -113
- data/lib/iodine/pubsub.rb +0 -55
- data/lib/iodine/rack_utils.rb +0 -43
- data/lib/iodine/tls.rb +0 -16
- data/lib/rack/handler/iodine.rb +0 -33
- data/logo.png +0 -0
data/ext/iodine/fiobject.c
DELETED
|
@@ -1,620 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright: Boaz Segev, 2017-2019
|
|
3
|
-
License: MIT
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
This facil.io core library provides wrappers around complex and (or) dynamic
|
|
8
|
-
types, abstracting some complexity and making dynamic type related tasks easier.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
#include <fiobject.h>
|
|
12
|
-
|
|
13
|
-
#define FIO_ARY_NAME fiobj_stack
|
|
14
|
-
#define FIO_ARY_TYPE FIOBJ
|
|
15
|
-
#define FIO_ARY_INVALID FIOBJ_INVALID
|
|
16
|
-
/* don't free or compare objects, this stack shouldn't have side-effects */
|
|
17
|
-
#include <fio.h>
|
|
18
|
-
|
|
19
|
-
#include <stdarg.h>
|
|
20
|
-
#include <stdint.h>
|
|
21
|
-
#include <stdio.h>
|
|
22
|
-
#include <stdlib.h>
|
|
23
|
-
#include <string.h>
|
|
24
|
-
|
|
25
|
-
/* *****************************************************************************
|
|
26
|
-
Use the facil.io features when available, but override when missing.
|
|
27
|
-
***************************************************************************** */
|
|
28
|
-
#ifndef fd_data /* defined in fio.c */
|
|
29
|
-
|
|
30
|
-
#pragma weak fio_malloc
|
|
31
|
-
void *fio_malloc(size_t size) {
|
|
32
|
-
void *m = malloc(size);
|
|
33
|
-
if (m)
|
|
34
|
-
memset(m, 0, size);
|
|
35
|
-
return m;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
#pragma weak fio_calloc
|
|
39
|
-
void *__attribute__((weak)) fio_calloc(size_t size, size_t count) {
|
|
40
|
-
return calloc(size, count);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
#pragma weak fio_free
|
|
44
|
-
void __attribute__((weak)) fio_free(void *ptr) { free(ptr); }
|
|
45
|
-
|
|
46
|
-
#pragma weak fio_realloc
|
|
47
|
-
void *__attribute__((weak)) fio_realloc(void *ptr, size_t new_size) {
|
|
48
|
-
return realloc(ptr, new_size);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
#pragma weak fio_realloc2
|
|
52
|
-
void *__attribute__((weak))
|
|
53
|
-
fio_realloc2(void *ptr, size_t new_size, size_t valid_len) {
|
|
54
|
-
return realloc(ptr, new_size);
|
|
55
|
-
(void)valid_len;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
#pragma weak fio_mmap
|
|
59
|
-
void *__attribute__((weak)) fio_mmap(size_t size) { return fio_malloc(size); }
|
|
60
|
-
|
|
61
|
-
/** The logging level */
|
|
62
|
-
#if DEBUG
|
|
63
|
-
#pragma weak FIO_LOG_LEVEL
|
|
64
|
-
int __attribute__((weak)) FIO_LOG_LEVEL = FIO_LOG_LEVEL_DEBUG;
|
|
65
|
-
#else
|
|
66
|
-
#pragma weak FIO_LOG_LEVEL
|
|
67
|
-
int __attribute__((weak)) FIO_LOG_LEVEL = FIO_LOG_LEVEL_INFO;
|
|
68
|
-
#endif
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* We include this in case the parser is used outside of facil.io.
|
|
72
|
-
*/
|
|
73
|
-
int64_t __attribute__((weak)) fio_atol(char **pstr) {
|
|
74
|
-
return strtoll(*pstr, pstr, 0);
|
|
75
|
-
}
|
|
76
|
-
#pragma weak fio_atol
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* We include this in case the parser is used outside of facil.io.
|
|
80
|
-
*/
|
|
81
|
-
double __attribute__((weak)) fio_atof(char **pstr) {
|
|
82
|
-
return strtod(*pstr, pstr);
|
|
83
|
-
}
|
|
84
|
-
#pragma weak fio_atof
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* A helper function that writes a signed int64_t to a string.
|
|
88
|
-
*
|
|
89
|
-
* No overflow guard is provided, make sure there's at least 68 bytes
|
|
90
|
-
* available (for base 2).
|
|
91
|
-
*
|
|
92
|
-
* Offers special support for base 2 (binary), base 8 (octal), base 10 and base
|
|
93
|
-
* 16 (hex). An unsupported base will silently default to base 10. Prefixes
|
|
94
|
-
* are automatically added (i.e., "0x" for hex and "0b" for base 2).
|
|
95
|
-
*
|
|
96
|
-
* Returns the number of bytes actually written (excluding the NUL
|
|
97
|
-
* terminator).
|
|
98
|
-
*/
|
|
99
|
-
#pragma weak fio_ltoa
|
|
100
|
-
size_t __attribute__((weak)) fio_ltoa(char *dest, int64_t num, uint8_t base) {
|
|
101
|
-
const char notation[] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
|
102
|
-
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
|
103
|
-
|
|
104
|
-
size_t len = 0;
|
|
105
|
-
char buf[48] = {0}; /* we only need up to 20 for base 10, but base 3 needs 41... */
|
|
106
|
-
|
|
107
|
-
if (!num)
|
|
108
|
-
goto zero;
|
|
109
|
-
|
|
110
|
-
switch (base) {
|
|
111
|
-
case 1: /* fallthrough */
|
|
112
|
-
case 2:
|
|
113
|
-
/* Base 2 */
|
|
114
|
-
{
|
|
115
|
-
uint64_t n = num; /* avoid bit shifting inconsistencies with signed bit */
|
|
116
|
-
uint8_t i = 0; /* counting bits */
|
|
117
|
-
dest[len++] = '0';
|
|
118
|
-
dest[len++] = 'b';
|
|
119
|
-
|
|
120
|
-
while ((i < 64) && (n & 0x8000000000000000) == 0) {
|
|
121
|
-
n = n << 1;
|
|
122
|
-
i++;
|
|
123
|
-
}
|
|
124
|
-
/* make sure the Binary representation doesn't appear signed. */
|
|
125
|
-
if (i) {
|
|
126
|
-
dest[len++] = '0';
|
|
127
|
-
}
|
|
128
|
-
/* write to dest. */
|
|
129
|
-
while (i < 64) {
|
|
130
|
-
dest[len++] = ((n & 0x8000000000000000) ? '1' : '0');
|
|
131
|
-
n = n << 1;
|
|
132
|
-
i++;
|
|
133
|
-
}
|
|
134
|
-
dest[len] = 0;
|
|
135
|
-
return len;
|
|
136
|
-
}
|
|
137
|
-
case 8:
|
|
138
|
-
/* Base 8 */
|
|
139
|
-
{
|
|
140
|
-
uint64_t l = 0;
|
|
141
|
-
if (num < 0) {
|
|
142
|
-
dest[len++] = '-';
|
|
143
|
-
num = 0 - num;
|
|
144
|
-
}
|
|
145
|
-
dest[len++] = '0';
|
|
146
|
-
|
|
147
|
-
while (num) {
|
|
148
|
-
buf[l++] = '0' + (num & 7);
|
|
149
|
-
num = num >> 3;
|
|
150
|
-
}
|
|
151
|
-
while (l) {
|
|
152
|
-
--l;
|
|
153
|
-
dest[len++] = buf[l];
|
|
154
|
-
}
|
|
155
|
-
dest[len] = 0;
|
|
156
|
-
return len;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
case 16:
|
|
160
|
-
/* Base 16 */
|
|
161
|
-
{
|
|
162
|
-
uint64_t n = num; /* avoid bit shifting inconsistencies with signed bit */
|
|
163
|
-
uint8_t i = 0; /* counting bits */
|
|
164
|
-
dest[len++] = '0';
|
|
165
|
-
dest[len++] = 'x';
|
|
166
|
-
while (i < 8 && (n & 0xFF00000000000000) == 0) {
|
|
167
|
-
n = n << 8;
|
|
168
|
-
i++;
|
|
169
|
-
}
|
|
170
|
-
/* make sure the Hex representation doesn't appear signed. */
|
|
171
|
-
if (i && (n & 0x8000000000000000)) {
|
|
172
|
-
dest[len++] = '0';
|
|
173
|
-
dest[len++] = '0';
|
|
174
|
-
}
|
|
175
|
-
/* write the damn thing */
|
|
176
|
-
while (i < 8) {
|
|
177
|
-
uint8_t tmp = (n & 0xF000000000000000) >> 60;
|
|
178
|
-
dest[len++] = notation[tmp];
|
|
179
|
-
tmp = (n & 0x0F00000000000000) >> 56;
|
|
180
|
-
dest[len++] = notation[tmp];
|
|
181
|
-
i++;
|
|
182
|
-
n = n << 8;
|
|
183
|
-
}
|
|
184
|
-
dest[len] = 0;
|
|
185
|
-
return len;
|
|
186
|
-
}
|
|
187
|
-
case 3: /* fallthrough */
|
|
188
|
-
case 4: /* fallthrough */
|
|
189
|
-
case 5: /* fallthrough */
|
|
190
|
-
case 6: /* fallthrough */
|
|
191
|
-
case 7: /* fallthrough */
|
|
192
|
-
case 9: /* fallthrough */
|
|
193
|
-
/* rare bases */
|
|
194
|
-
if (num < 0) {
|
|
195
|
-
dest[len++] = '-';
|
|
196
|
-
num = 0 - num;
|
|
197
|
-
}
|
|
198
|
-
uint64_t l = 0;
|
|
199
|
-
while (num) {
|
|
200
|
-
uint64_t t = num / base;
|
|
201
|
-
buf[l++] = '0' + (num - (t * base));
|
|
202
|
-
num = t;
|
|
203
|
-
}
|
|
204
|
-
while (l) {
|
|
205
|
-
--l;
|
|
206
|
-
dest[len++] = buf[l];
|
|
207
|
-
}
|
|
208
|
-
dest[len] = 0;
|
|
209
|
-
return len;
|
|
210
|
-
|
|
211
|
-
default:
|
|
212
|
-
break;
|
|
213
|
-
}
|
|
214
|
-
/* Base 10, the default base */
|
|
215
|
-
|
|
216
|
-
if (num < 0) {
|
|
217
|
-
dest[len++] = '-';
|
|
218
|
-
num = 0 - num;
|
|
219
|
-
}
|
|
220
|
-
uint64_t l = 0;
|
|
221
|
-
while (num) {
|
|
222
|
-
uint64_t t = num / 10;
|
|
223
|
-
buf[l++] = '0' + (num - (t * 10));
|
|
224
|
-
num = t;
|
|
225
|
-
}
|
|
226
|
-
while (l) {
|
|
227
|
-
--l;
|
|
228
|
-
dest[len++] = buf[l];
|
|
229
|
-
}
|
|
230
|
-
dest[len] = 0;
|
|
231
|
-
return len;
|
|
232
|
-
|
|
233
|
-
zero:
|
|
234
|
-
switch (base) {
|
|
235
|
-
case 1: /* fallthrough */
|
|
236
|
-
case 2:
|
|
237
|
-
dest[len++] = '0';
|
|
238
|
-
dest[len++] = 'b';
|
|
239
|
-
/* fallthrough */
|
|
240
|
-
case 16:
|
|
241
|
-
dest[len++] = '0';
|
|
242
|
-
dest[len++] = 'x';
|
|
243
|
-
dest[len++] = '0';
|
|
244
|
-
}
|
|
245
|
-
dest[len++] = '0';
|
|
246
|
-
dest[len] = 0;
|
|
247
|
-
return len;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* A helper function that converts between a double to a string.
|
|
252
|
-
*
|
|
253
|
-
* No overflow guard is provided, make sure there's at least 130 bytes
|
|
254
|
-
* available (for base 2).
|
|
255
|
-
*
|
|
256
|
-
* Supports base 2, base 10 and base 16. An unsupported base will silently
|
|
257
|
-
* default to base 10. Prefixes aren't added (i.e., no "0x" or "0b" at the
|
|
258
|
-
* beginning of the string).
|
|
259
|
-
*
|
|
260
|
-
* Returns the number of bytes actually written (excluding the NUL
|
|
261
|
-
* terminator).
|
|
262
|
-
*/
|
|
263
|
-
#pragma weak fio_ftoa
|
|
264
|
-
size_t __attribute__((weak)) fio_ftoa(char *dest, double num, uint8_t base) {
|
|
265
|
-
if (base == 2 || base == 16) {
|
|
266
|
-
/* handle the binary / Hex representation the same as if it were an
|
|
267
|
-
* int64_t
|
|
268
|
-
*/
|
|
269
|
-
int64_t *i = (void *)#
|
|
270
|
-
return fio_ltoa(dest, *i, base);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
size_t written = sprintf(dest, "%g", num);
|
|
274
|
-
uint8_t need_zero = 1;
|
|
275
|
-
char *start = dest;
|
|
276
|
-
while (*start) {
|
|
277
|
-
if (*start == ',') // locale issues?
|
|
278
|
-
*start = '.';
|
|
279
|
-
if (*start == '.' || *start == 'e') {
|
|
280
|
-
need_zero = 0;
|
|
281
|
-
break;
|
|
282
|
-
}
|
|
283
|
-
start++;
|
|
284
|
-
}
|
|
285
|
-
if (need_zero) {
|
|
286
|
-
dest[written++] = '.';
|
|
287
|
-
dest[written++] = '0';
|
|
288
|
-
}
|
|
289
|
-
return written;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
#endif
|
|
293
|
-
/* *****************************************************************************
|
|
294
|
-
the `fiobj_each2` function
|
|
295
|
-
***************************************************************************** */
|
|
296
|
-
|
|
297
|
-
struct task_packet_s {
|
|
298
|
-
int (*task)(FIOBJ obj, void *arg);
|
|
299
|
-
void *arg;
|
|
300
|
-
fiobj_stack_s *stack;
|
|
301
|
-
FIOBJ next;
|
|
302
|
-
uintptr_t counter;
|
|
303
|
-
uint8_t stop;
|
|
304
|
-
uint8_t incomplete;
|
|
305
|
-
};
|
|
306
|
-
|
|
307
|
-
static int fiobj_task_wrapper(FIOBJ o, void *p_) {
|
|
308
|
-
struct task_packet_s *p = p_;
|
|
309
|
-
++p->counter;
|
|
310
|
-
int ret = p->task(o, p->arg);
|
|
311
|
-
if (ret == -1) {
|
|
312
|
-
p->stop = 1;
|
|
313
|
-
return -1;
|
|
314
|
-
}
|
|
315
|
-
if (FIOBJ_IS_ALLOCATED(o) && FIOBJECT2VTBL(o)->each) {
|
|
316
|
-
p->incomplete = 1;
|
|
317
|
-
p->next = o;
|
|
318
|
-
return -1;
|
|
319
|
-
}
|
|
320
|
-
return 0;
|
|
321
|
-
}
|
|
322
|
-
/**
|
|
323
|
-
* Single layer iteration using a callback for each nested fio object.
|
|
324
|
-
*
|
|
325
|
-
* Accepts any `FIOBJ ` type but only collections (Arrays and Hashes) are
|
|
326
|
-
* processed. The container itself (the Array or the Hash) is **not** processed
|
|
327
|
-
* (unlike `fiobj_each2`).
|
|
328
|
-
*
|
|
329
|
-
* The callback task function must accept an object and an opaque user pointer.
|
|
330
|
-
*
|
|
331
|
-
* Hash objects pass along a `FIOBJ_T_COUPLET` object, containing
|
|
332
|
-
* references for both the key and the object. Keys shouldn't be altered once
|
|
333
|
-
* placed as a key (or the Hash will break). Collections (Arrays / Hashes) can't
|
|
334
|
-
* be used as keeys.
|
|
335
|
-
*
|
|
336
|
-
* If the callback returns -1, the loop is broken. Any other value is ignored.
|
|
337
|
-
*
|
|
338
|
-
* Returns the "stop" position, i.e., the number of items processed + the
|
|
339
|
-
* starting point.
|
|
340
|
-
*/
|
|
341
|
-
size_t fiobj_each2(FIOBJ o, int (*task)(FIOBJ obj, void *arg), void *arg) {
|
|
342
|
-
if (!o || !FIOBJ_IS_ALLOCATED(o) || (FIOBJECT2VTBL(o)->each == NULL)) {
|
|
343
|
-
task(o, arg);
|
|
344
|
-
return 1;
|
|
345
|
-
}
|
|
346
|
-
/* run task for root object */
|
|
347
|
-
if (task(o, arg) == -1)
|
|
348
|
-
return 1;
|
|
349
|
-
uintptr_t pos = 0;
|
|
350
|
-
fiobj_stack_s stack = FIO_ARY_INIT;
|
|
351
|
-
struct task_packet_s packet = {
|
|
352
|
-
.task = task,
|
|
353
|
-
.arg = arg,
|
|
354
|
-
.stack = &stack,
|
|
355
|
-
.counter = 1,
|
|
356
|
-
};
|
|
357
|
-
do {
|
|
358
|
-
if (!pos)
|
|
359
|
-
packet.next = 0;
|
|
360
|
-
packet.incomplete = 0;
|
|
361
|
-
pos = FIOBJECT2VTBL(o)->each(o, pos, fiobj_task_wrapper, &packet);
|
|
362
|
-
if (packet.stop)
|
|
363
|
-
goto finish;
|
|
364
|
-
if (packet.incomplete) {
|
|
365
|
-
fiobj_stack_push(&stack, pos);
|
|
366
|
-
fiobj_stack_push(&stack, o);
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
if (packet.next) {
|
|
370
|
-
fiobj_stack_push(&stack, (FIOBJ)0);
|
|
371
|
-
fiobj_stack_push(&stack, packet.next);
|
|
372
|
-
}
|
|
373
|
-
o = FIOBJ_INVALID;
|
|
374
|
-
fiobj_stack_pop(&stack, &o);
|
|
375
|
-
fiobj_stack_pop(&stack, &pos);
|
|
376
|
-
} while (o);
|
|
377
|
-
finish:
|
|
378
|
-
fiobj_stack_free(&stack);
|
|
379
|
-
return packet.counter;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/* *****************************************************************************
|
|
383
|
-
Free complex objects (objects with nesting)
|
|
384
|
-
***************************************************************************** */
|
|
385
|
-
|
|
386
|
-
static void fiobj_dealloc_task(FIOBJ o, void *stack_) {
|
|
387
|
-
// if (!o)
|
|
388
|
-
// fprintf(stderr, "* WARN: freeing a NULL no-object\n");
|
|
389
|
-
// else
|
|
390
|
-
// fprintf(stderr, "* freeing object %s\n", fiobj_obj2cstr(o).data);
|
|
391
|
-
if (!o || !FIOBJ_IS_ALLOCATED(o))
|
|
392
|
-
return;
|
|
393
|
-
if (OBJREF_REM(o))
|
|
394
|
-
return;
|
|
395
|
-
if (!FIOBJECT2VTBL(o)->each || !FIOBJECT2VTBL(o)->count(o)) {
|
|
396
|
-
FIOBJECT2VTBL(o)->dealloc(o, NULL, NULL);
|
|
397
|
-
return;
|
|
398
|
-
}
|
|
399
|
-
fiobj_stack_s *s = stack_;
|
|
400
|
-
fiobj_stack_push(s, o);
|
|
401
|
-
}
|
|
402
|
-
/**
|
|
403
|
-
* Decreases an object's reference count, releasing memory and
|
|
404
|
-
* resources.
|
|
405
|
-
*
|
|
406
|
-
* This function affects nested objects, meaning that when an Array or
|
|
407
|
-
* a Hash object is passed along, it's children (nested objects) are
|
|
408
|
-
* also freed.
|
|
409
|
-
*/
|
|
410
|
-
void fiobj_free_complex_object(FIOBJ o) {
|
|
411
|
-
fiobj_stack_s stack = FIO_ARY_INIT;
|
|
412
|
-
do {
|
|
413
|
-
FIOBJECT2VTBL(o)->dealloc(o, fiobj_dealloc_task, &stack);
|
|
414
|
-
} while (!fiobj_stack_pop(&stack, &o));
|
|
415
|
-
fiobj_stack_free(&stack);
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
/* *****************************************************************************
|
|
419
|
-
Is Equal?
|
|
420
|
-
***************************************************************************** */
|
|
421
|
-
#include <fiobj_hash.h>
|
|
422
|
-
|
|
423
|
-
static inline int fiobj_iseq_simple(const FIOBJ o, const FIOBJ o2) {
|
|
424
|
-
if (o == o2)
|
|
425
|
-
return 1;
|
|
426
|
-
if (!o || !o2)
|
|
427
|
-
return 0; /* they should have compared equal before. */
|
|
428
|
-
if (!FIOBJ_IS_ALLOCATED(o) || !FIOBJ_IS_ALLOCATED(o2))
|
|
429
|
-
return 0; /* they should have compared equal before. */
|
|
430
|
-
if (FIOBJECT2HEAD(o)->type != FIOBJECT2HEAD(o2)->type)
|
|
431
|
-
return 0; /* non-type equality is a barriar to equality. */
|
|
432
|
-
if (!FIOBJECT2VTBL(o)->is_eq(o, o2))
|
|
433
|
-
return 0;
|
|
434
|
-
return 1;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
static int fiobj_iseq____internal_complex__task(FIOBJ o, void *ary_) {
|
|
438
|
-
fiobj_stack_s *ary = ary_;
|
|
439
|
-
fiobj_stack_push(ary, o);
|
|
440
|
-
if (fiobj_hash_key_in_loop())
|
|
441
|
-
fiobj_stack_push(ary, fiobj_hash_key_in_loop());
|
|
442
|
-
return 0;
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
/** used internally for complext nested tests (Array / Hash types) */
|
|
446
|
-
int fiobj_iseq____internal_complex__(FIOBJ o, FIOBJ o2) {
|
|
447
|
-
// if (FIOBJECT2VTBL(o)->each && FIOBJECT2VTBL(o)->count(o))
|
|
448
|
-
// return int fiobj_iseq____internal_complex__(const FIOBJ o, const FIOBJ
|
|
449
|
-
// o2);
|
|
450
|
-
fiobj_stack_s left = FIO_ARY_INIT, right = FIO_ARY_INIT, queue = FIO_ARY_INIT;
|
|
451
|
-
do {
|
|
452
|
-
fiobj_each1(o, 0, fiobj_iseq____internal_complex__task, &left);
|
|
453
|
-
fiobj_each1(o2, 0, fiobj_iseq____internal_complex__task, &right);
|
|
454
|
-
while (fiobj_stack_count(&left)) {
|
|
455
|
-
o = FIOBJ_INVALID;
|
|
456
|
-
o2 = FIOBJ_INVALID;
|
|
457
|
-
fiobj_stack_pop(&left, &o);
|
|
458
|
-
fiobj_stack_pop(&right, &o2);
|
|
459
|
-
if (!fiobj_iseq_simple(o, o2))
|
|
460
|
-
goto unequal;
|
|
461
|
-
if (FIOBJ_IS_ALLOCATED(o) && FIOBJECT2VTBL(o)->each &&
|
|
462
|
-
FIOBJECT2VTBL(o)->count(o)) {
|
|
463
|
-
fiobj_stack_push(&queue, o);
|
|
464
|
-
fiobj_stack_push(&queue, o2);
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
o = FIOBJ_INVALID;
|
|
468
|
-
o2 = FIOBJ_INVALID;
|
|
469
|
-
fiobj_stack_pop(&queue, &o2);
|
|
470
|
-
fiobj_stack_pop(&queue, &o);
|
|
471
|
-
if (!fiobj_iseq_simple(o, o2))
|
|
472
|
-
goto unequal;
|
|
473
|
-
} while (o);
|
|
474
|
-
fiobj_stack_free(&left);
|
|
475
|
-
fiobj_stack_free(&right);
|
|
476
|
-
fiobj_stack_free(&queue);
|
|
477
|
-
return 1;
|
|
478
|
-
unequal:
|
|
479
|
-
fiobj_stack_free(&left);
|
|
480
|
-
fiobj_stack_free(&right);
|
|
481
|
-
fiobj_stack_free(&queue);
|
|
482
|
-
return 0;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
/* *****************************************************************************
|
|
486
|
-
Defaults / NOOPs
|
|
487
|
-
***************************************************************************** */
|
|
488
|
-
|
|
489
|
-
void fiobject___noop_dealloc(FIOBJ o, void (*task)(FIOBJ, void *), void *arg) {
|
|
490
|
-
(void)o;
|
|
491
|
-
(void)task;
|
|
492
|
-
(void)arg;
|
|
493
|
-
}
|
|
494
|
-
void fiobject___simple_dealloc(FIOBJ o, void (*task)(FIOBJ, void *),
|
|
495
|
-
void *arg) {
|
|
496
|
-
fio_free(FIOBJ2PTR(o));
|
|
497
|
-
(void)task;
|
|
498
|
-
(void)arg;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
uintptr_t fiobject___noop_count(const FIOBJ o) {
|
|
502
|
-
(void)o;
|
|
503
|
-
return 0;
|
|
504
|
-
}
|
|
505
|
-
size_t fiobject___noop_is_eq(const FIOBJ o1, const FIOBJ o2) {
|
|
506
|
-
(void)o1;
|
|
507
|
-
(void)o2;
|
|
508
|
-
return 0;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
fio_str_info_s fiobject___noop_to_str(const FIOBJ o) {
|
|
512
|
-
(void)o;
|
|
513
|
-
return (fio_str_info_s){.len = 0, .data = NULL};
|
|
514
|
-
}
|
|
515
|
-
intptr_t fiobject___noop_to_i(const FIOBJ o) {
|
|
516
|
-
(void)o;
|
|
517
|
-
return 0;
|
|
518
|
-
}
|
|
519
|
-
double fiobject___noop_to_f(const FIOBJ o) {
|
|
520
|
-
(void)o;
|
|
521
|
-
return 0;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
#if DEBUG
|
|
525
|
-
|
|
526
|
-
#include <fiobj_ary.h>
|
|
527
|
-
#include <fiobj_numbers.h>
|
|
528
|
-
|
|
529
|
-
static int fiobject_test_task(FIOBJ o, void *arg) {
|
|
530
|
-
++((uintptr_t *)arg)[0];
|
|
531
|
-
if (!o)
|
|
532
|
-
fprintf(stderr, "* WARN: counting a NULL no-object\n");
|
|
533
|
-
// else
|
|
534
|
-
// fprintf(stderr, "* counting object %s\n", fiobj_obj2cstr(o).data);
|
|
535
|
-
return 0;
|
|
536
|
-
(void)o;
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
void fiobj_test_core(void) {
|
|
540
|
-
#define TEST_ASSERT(cond, ...) \
|
|
541
|
-
if (!(cond)) { \
|
|
542
|
-
fprintf(stderr, __VA_ARGS__); \
|
|
543
|
-
fprintf(stderr, "Testing failed.\n"); \
|
|
544
|
-
exit(-1); \
|
|
545
|
-
}
|
|
546
|
-
fprintf(stderr, "=== Testing Primitives\n");
|
|
547
|
-
FIOBJ o = fiobj_null();
|
|
548
|
-
TEST_ASSERT(o == (FIOBJ)FIOBJ_T_NULL, "fiobj_null isn't NULL!\n");
|
|
549
|
-
TEST_ASSERT(FIOBJ_TYPE(0) == FIOBJ_T_NULL, "NULL isn't NULL!\n");
|
|
550
|
-
TEST_ASSERT(FIOBJ_TYPE_IS(0, FIOBJ_T_NULL), "NULL isn't NULL! (2)\n");
|
|
551
|
-
TEST_ASSERT(!FIOBJ_IS_ALLOCATED(fiobj_null()),
|
|
552
|
-
"fiobj_null claims to be allocated!\n");
|
|
553
|
-
TEST_ASSERT(!FIOBJ_IS_ALLOCATED(fiobj_true()),
|
|
554
|
-
"fiobj_true claims to be allocated!\n");
|
|
555
|
-
TEST_ASSERT(!FIOBJ_IS_ALLOCATED(fiobj_false()),
|
|
556
|
-
"fiobj_false claims to be allocated!\n");
|
|
557
|
-
TEST_ASSERT(FIOBJ_TYPE(fiobj_true()) == FIOBJ_T_TRUE,
|
|
558
|
-
"fiobj_true isn't FIOBJ_T_TRUE!\n");
|
|
559
|
-
TEST_ASSERT(FIOBJ_TYPE_IS(fiobj_true(), FIOBJ_T_TRUE),
|
|
560
|
-
"fiobj_true isn't FIOBJ_T_TRUE! (2)\n");
|
|
561
|
-
TEST_ASSERT(FIOBJ_TYPE(fiobj_false()) == FIOBJ_T_FALSE,
|
|
562
|
-
"fiobj_false isn't FIOBJ_T_TRUE!\n");
|
|
563
|
-
TEST_ASSERT(FIOBJ_TYPE_IS(fiobj_false(), FIOBJ_T_FALSE),
|
|
564
|
-
"fiobj_false isn't FIOBJ_T_TRUE! (2)\n");
|
|
565
|
-
fiobj_free(o); /* testing for crash*/
|
|
566
|
-
fprintf(stderr, "* passed.\n");
|
|
567
|
-
fprintf(stderr, "=== Testing fioj_each2\n");
|
|
568
|
-
o = fiobj_ary_new2(4);
|
|
569
|
-
FIOBJ tmp = fiobj_ary_new();
|
|
570
|
-
fiobj_ary_push(o, tmp);
|
|
571
|
-
fiobj_ary_push(o, fiobj_true());
|
|
572
|
-
fiobj_ary_push(o, fiobj_null());
|
|
573
|
-
fiobj_ary_push(o, fiobj_num_new(10));
|
|
574
|
-
fiobj_ary_push(tmp, fiobj_num_new(13));
|
|
575
|
-
fiobj_ary_push(tmp, fiobj_hash_new());
|
|
576
|
-
FIOBJ key = fiobj_str_new("my key", 6);
|
|
577
|
-
fiobj_hash_set(fiobj_ary_entry(tmp, -1), key, fiobj_true());
|
|
578
|
-
fiobj_free(key);
|
|
579
|
-
/* we have root array + 4 children (w/ array) + 2 children (w/ hash) + 1 */
|
|
580
|
-
uintptr_t count = 0;
|
|
581
|
-
size_t each_ret = 0;
|
|
582
|
-
TEST_ASSERT(fiobj_each2(o, fiobject_test_task, (void *)&count) == 8,
|
|
583
|
-
"fiobj_each1 didn't count everything... (%d != %d)", (int)count,
|
|
584
|
-
(int)each_ret);
|
|
585
|
-
TEST_ASSERT(count == 8, "Something went wrong with the counter task... (%d)",
|
|
586
|
-
(int)count)
|
|
587
|
-
fprintf(stderr, "* passed.\n");
|
|
588
|
-
fprintf(stderr, "=== Testing fioj_iseq with nested items\n");
|
|
589
|
-
FIOBJ o2 = fiobj_ary_new2(4);
|
|
590
|
-
tmp = fiobj_ary_new();
|
|
591
|
-
fiobj_ary_push(o2, tmp);
|
|
592
|
-
fiobj_ary_push(o2, fiobj_true());
|
|
593
|
-
fiobj_ary_push(o2, fiobj_null());
|
|
594
|
-
fiobj_ary_push(o2, fiobj_num_new(10));
|
|
595
|
-
fiobj_ary_push(tmp, fiobj_num_new(13));
|
|
596
|
-
fiobj_ary_push(tmp, fiobj_hash_new());
|
|
597
|
-
key = fiobj_str_new("my key", 6);
|
|
598
|
-
fiobj_hash_set(fiobj_ary_entry(tmp, -1), key, fiobj_true());
|
|
599
|
-
fiobj_free(key);
|
|
600
|
-
TEST_ASSERT(!fiobj_iseq(o, FIOBJ_INVALID),
|
|
601
|
-
"Array and FIOBJ_INVALID can't be equal!");
|
|
602
|
-
TEST_ASSERT(!fiobj_iseq(o, fiobj_null()),
|
|
603
|
-
"Array and fiobj_null can't be equal!");
|
|
604
|
-
TEST_ASSERT(fiobj_iseq(o, o2), "Arrays aren't euqal!");
|
|
605
|
-
fiobj_free(o);
|
|
606
|
-
fiobj_free(o2);
|
|
607
|
-
TEST_ASSERT(fiobj_iseq(fiobj_null(), fiobj_null()),
|
|
608
|
-
"fiobj_null() not equal to self!");
|
|
609
|
-
TEST_ASSERT(fiobj_iseq(fiobj_false(), fiobj_false()),
|
|
610
|
-
"fiobj_false() not equal to self!");
|
|
611
|
-
TEST_ASSERT(fiobj_iseq(fiobj_true(), fiobj_true()),
|
|
612
|
-
"fiobj_true() not equal to self!");
|
|
613
|
-
TEST_ASSERT(!fiobj_iseq(fiobj_null(), fiobj_false()),
|
|
614
|
-
"fiobj_null eqal to fiobj_false!");
|
|
615
|
-
TEST_ASSERT(!fiobj_iseq(fiobj_null(), fiobj_true()),
|
|
616
|
-
"fiobj_null eqal to fiobj_true!");
|
|
617
|
-
fprintf(stderr, "* passed.\n");
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
#endif
|