iodine 0.7.3 → 0.7.4
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -2
- data/ext/iodine/fio.c +319 -46
- data/ext/iodine/fio.h +851 -37
- data/ext/iodine/fio_cli.c +17 -16
- data/ext/iodine/fio_json_parser.h +28 -3
- data/ext/iodine/fiobj_ary.c +44 -46
- data/ext/iodine/fiobj_data.c +12 -13
- data/ext/iodine/fiobj_hash.c +28 -27
- data/ext/iodine/fiobj_json.c +40 -33
- data/ext/iodine/fiobj_numbers.c +2 -304
- data/ext/iodine/fiobj_str.c +0 -1
- data/ext/iodine/fiobject.c +268 -38
- data/ext/iodine/iodine_json.c +13 -14
- data/ext/iodine/iodine_store.c +33 -29
- data/iodine.gemspec +1 -3
- data/lib/iodine.rb +2 -2
- data/lib/iodine/json.rb +3 -1
- data/lib/iodine/version.rb +1 -1
- metadata +5 -4
- data/ext/iodine/fio_ary.h +0 -717
data/ext/iodine/fiobj_hash.c
CHANGED
@@ -7,11 +7,13 @@ License: MIT
|
|
7
7
|
|
8
8
|
#include <assert.h>
|
9
9
|
#include <fiobj_hash.h>
|
10
|
+
|
10
11
|
#define FIO_SET_CALLOC(size, count) fio_calloc((size), (count))
|
11
12
|
#define FIO_SET_REALLOC(ptr, original_size, size, valid_data_length) \
|
12
13
|
fio_realloc2((ptr), (size), (valid_data_length))
|
13
14
|
#define FIO_SET_FREE(ptr, size) fio_free((ptr))
|
14
|
-
|
15
|
+
|
16
|
+
#define FIO_SET_NAME fio_hash__
|
15
17
|
#define FIO_SET_KEY_TYPE FIOBJ
|
16
18
|
#define FIO_SET_KEY_COMPARE(o1, o2) \
|
17
19
|
((o2) == ((FIOBJ)-1) || (o1) == ((FIOBJ)-1) || fiobj_iseq((o1), (o2)))
|
@@ -30,7 +32,6 @@ License: MIT
|
|
30
32
|
(obj) = FIOBJ_INVALID; \
|
31
33
|
} while (0)
|
32
34
|
|
33
|
-
#define FIO_OVERRIDE_MALLOC 1
|
34
35
|
#include <fio.h>
|
35
36
|
|
36
37
|
#include <errno.h>
|
@@ -40,14 +41,14 @@ Hash types
|
|
40
41
|
***************************************************************************** */
|
41
42
|
typedef struct {
|
42
43
|
fiobj_object_header_s head;
|
43
|
-
|
44
|
+
fio_hash___s hash;
|
44
45
|
} fiobj_hash_s;
|
45
46
|
|
46
47
|
#define obj2hash(o) ((fiobj_hash_s *)(FIOBJ2PTR(o)))
|
47
48
|
|
48
49
|
void fiobj_hash_rehash(FIOBJ h) {
|
49
50
|
assert(h && FIOBJ_TYPE_IS(h, FIOBJ_T_HASH));
|
50
|
-
|
51
|
+
fio_hash___rehash(&obj2hash(h)->hash);
|
51
52
|
}
|
52
53
|
|
53
54
|
/* *****************************************************************************
|
@@ -64,8 +65,8 @@ static void fiobj_hash_dealloc(FIOBJ o, void (*task)(FIOBJ, void *),
|
|
64
65
|
i->obj.obj = FIOBJ_INVALID;
|
65
66
|
}
|
66
67
|
obj2hash(o)->hash.count = 0;
|
67
|
-
|
68
|
-
|
68
|
+
fio_hash___free(&obj2hash(o)->hash);
|
69
|
+
fio_free(FIOBJ2PTR(o));
|
69
70
|
}
|
70
71
|
|
71
72
|
static __thread FIOBJ each_at_key = FIOBJ_INVALID;
|
@@ -74,7 +75,7 @@ static size_t fiobj_hash_each1(FIOBJ o, size_t start_at,
|
|
74
75
|
int (*task)(FIOBJ obj, void *arg), void *arg) {
|
75
76
|
assert(o && FIOBJ_TYPE_IS(o, FIOBJ_T_HASH));
|
76
77
|
FIOBJ old_each_at_key = each_at_key;
|
77
|
-
|
78
|
+
fio_hash___s *hash = &obj2hash(o)->hash;
|
78
79
|
size_t count = 0;
|
79
80
|
if (hash->count == hash->pos) {
|
80
81
|
/* no holes in the hash, we can work as we please. */
|
@@ -112,8 +113,8 @@ end:
|
|
112
113
|
FIOBJ fiobj_hash_key_in_loop(void) { return each_at_key; }
|
113
114
|
|
114
115
|
static size_t fiobj_hash_is_eq(const FIOBJ self, const FIOBJ other) {
|
115
|
-
if (
|
116
|
-
|
116
|
+
if (fio_hash___count(&obj2hash(self)->hash) !=
|
117
|
+
fio_hash___count(&obj2hash(other)->hash))
|
117
118
|
return 0;
|
118
119
|
return 1;
|
119
120
|
}
|
@@ -121,7 +122,7 @@ static size_t fiobj_hash_is_eq(const FIOBJ self, const FIOBJ other) {
|
|
121
122
|
/** Returns the number of elements in the Array. */
|
122
123
|
size_t fiobj_hash_count(const FIOBJ o) {
|
123
124
|
assert(o && FIOBJ_TYPE_IS(o, FIOBJ_T_HASH));
|
124
|
-
return
|
125
|
+
return fio_hash___count(&obj2hash(o)->hash);
|
125
126
|
}
|
126
127
|
|
127
128
|
intptr_t fiobj_hash2num(const FIOBJ o) { return (intptr_t)fiobj_hash_count(o); }
|
@@ -157,7 +158,7 @@ Hash API
|
|
157
158
|
* retain order of object insertion.
|
158
159
|
*/
|
159
160
|
FIOBJ fiobj_hash_new(void) {
|
160
|
-
fiobj_hash_s *h =
|
161
|
+
fiobj_hash_s *h = fio_malloc(sizeof(*h));
|
161
162
|
FIO_ASSERT_ALLOC(h);
|
162
163
|
*h = (fiobj_hash_s){.head = {.ref = 1, .type = FIOBJ_T_HASH},
|
163
164
|
.hash = FIO_SET_INIT};
|
@@ -172,11 +173,11 @@ FIOBJ fiobj_hash_new(void) {
|
|
172
173
|
* retain order of object insertion.
|
173
174
|
*/
|
174
175
|
FIOBJ fiobj_hash_new2(size_t capa) {
|
175
|
-
fiobj_hash_s *h =
|
176
|
+
fiobj_hash_s *h = fio_malloc(sizeof(*h));
|
176
177
|
FIO_ASSERT_ALLOC(h);
|
177
178
|
*h = (fiobj_hash_s){.head = {.ref = 1, .type = FIOBJ_T_HASH},
|
178
179
|
.hash = FIO_SET_INIT};
|
179
|
-
|
180
|
+
fio_hash___capa_require(&h->hash, capa);
|
180
181
|
return (FIOBJ)h | FIOBJECT_HASH_FLAG;
|
181
182
|
}
|
182
183
|
|
@@ -186,7 +187,7 @@ FIOBJ fiobj_hash_new2(size_t capa) {
|
|
186
187
|
*/
|
187
188
|
size_t fiobj_hash_capa(const FIOBJ hash) {
|
188
189
|
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
189
|
-
return
|
190
|
+
return fio_hash___capa(&obj2hash(hash)->hash);
|
190
191
|
}
|
191
192
|
|
192
193
|
/**
|
@@ -199,7 +200,7 @@ int fiobj_hash_set(FIOBJ hash, FIOBJ key, FIOBJ obj) {
|
|
199
200
|
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
200
201
|
if (FIOBJ_TYPE_IS(key, FIOBJ_T_STRING))
|
201
202
|
fiobj_str_freeze(key);
|
202
|
-
|
203
|
+
fio_hash___insert(&obj2hash(hash)->hash, fiobj_obj2hash(key), key, obj, NULL);
|
203
204
|
return 0;
|
204
205
|
}
|
205
206
|
|
@@ -216,12 +217,12 @@ int fiobj_hash_set(FIOBJ hash, FIOBJ key, FIOBJ obj) {
|
|
216
217
|
FIOBJ fiobj_hash_pop(FIOBJ hash, FIOBJ *key) {
|
217
218
|
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
218
219
|
FIOBJ old;
|
219
|
-
if (
|
220
|
+
if (fio_hash___count(&obj2hash(hash)->hash))
|
220
221
|
return FIOBJ_INVALID;
|
221
|
-
old = fiobj_dup(
|
222
|
+
old = fiobj_dup(fio_hash___last(&obj2hash(hash)->hash).obj);
|
222
223
|
if (key)
|
223
|
-
*key = fiobj_dup(
|
224
|
-
|
224
|
+
*key = fiobj_dup(fio_hash___last(&obj2hash(hash)->hash).key);
|
225
|
+
fio_hash___pop(&obj2hash(hash)->hash);
|
225
226
|
return old;
|
226
227
|
}
|
227
228
|
|
@@ -237,7 +238,7 @@ FIOBJ fiobj_hash_pop(FIOBJ hash, FIOBJ *key) {
|
|
237
238
|
FIOBJ fiobj_hash_replace(FIOBJ hash, FIOBJ key, FIOBJ obj) {
|
238
239
|
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
239
240
|
FIOBJ old = FIOBJ_INVALID;
|
240
|
-
|
241
|
+
fio_hash___insert(&obj2hash(hash)->hash, fiobj_obj2hash(key), key, obj, &old);
|
241
242
|
return old;
|
242
243
|
}
|
243
244
|
|
@@ -247,7 +248,7 @@ FIOBJ fiobj_hash_replace(FIOBJ hash, FIOBJ key, FIOBJ obj) {
|
|
247
248
|
FIOBJ fiobj_hash_remove(FIOBJ hash, FIOBJ key) {
|
248
249
|
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
249
250
|
FIOBJ old = FIOBJ_INVALID;
|
250
|
-
|
251
|
+
fio_hash___remove(&obj2hash(hash)->hash, fiobj_obj2hash(key), key, &old);
|
251
252
|
return old;
|
252
253
|
}
|
253
254
|
|
@@ -258,7 +259,7 @@ FIOBJ fiobj_hash_remove(FIOBJ hash, FIOBJ key) {
|
|
258
259
|
FIOBJ fiobj_hash_remove2(FIOBJ hash, uint64_t hash_value) {
|
259
260
|
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
260
261
|
FIOBJ old = FIOBJ_INVALID;
|
261
|
-
|
262
|
+
fio_hash___remove(&obj2hash(hash)->hash, hash_value, -1, &old);
|
262
263
|
return old;
|
263
264
|
}
|
264
265
|
|
@@ -283,7 +284,7 @@ int fiobj_hash_delete(FIOBJ hash, FIOBJ key) {
|
|
283
284
|
* Returns -1 on type error or if the object never existed.
|
284
285
|
*/
|
285
286
|
int fiobj_hash_delete2(FIOBJ hash, uint64_t key_hash) {
|
286
|
-
return
|
287
|
+
return fio_hash___remove(&obj2hash(hash)->hash, key_hash, -1, NULL);
|
287
288
|
}
|
288
289
|
|
289
290
|
/**
|
@@ -292,7 +293,7 @@ int fiobj_hash_delete2(FIOBJ hash, uint64_t key_hash) {
|
|
292
293
|
*/
|
293
294
|
FIOBJ fiobj_hash_get(const FIOBJ hash, FIOBJ key) {
|
294
295
|
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
295
|
-
return
|
296
|
+
return fio_hash___find(&obj2hash(hash)->hash, fiobj_obj2hash(key), key);
|
296
297
|
;
|
297
298
|
}
|
298
299
|
|
@@ -306,7 +307,7 @@ FIOBJ fiobj_hash_get(const FIOBJ hash, FIOBJ key) {
|
|
306
307
|
*/
|
307
308
|
FIOBJ fiobj_hash_get2(const FIOBJ hash, uint64_t key_hash) {
|
308
309
|
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
309
|
-
return
|
310
|
+
return fio_hash___find(&obj2hash(hash)->hash, key_hash, -1);
|
310
311
|
;
|
311
312
|
}
|
312
313
|
|
@@ -315,7 +316,7 @@ FIOBJ fiobj_hash_get2(const FIOBJ hash, uint64_t key_hash) {
|
|
315
316
|
*/
|
316
317
|
int fiobj_hash_haskey(const FIOBJ hash, FIOBJ key) {
|
317
318
|
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
318
|
-
return
|
319
|
+
return fio_hash___find(&obj2hash(hash)->hash, fiobj_obj2hash(key), key) !=
|
319
320
|
FIOBJ_INVALID;
|
320
321
|
}
|
321
322
|
|
@@ -324,7 +325,7 @@ int fiobj_hash_haskey(const FIOBJ hash, FIOBJ key) {
|
|
324
325
|
*/
|
325
326
|
void fiobj_hash_clear(const FIOBJ hash) {
|
326
327
|
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
327
|
-
|
328
|
+
fio_hash___free(&obj2hash(hash)->hash);
|
328
329
|
}
|
329
330
|
|
330
331
|
/* *****************************************************************************
|
data/ext/iodine/fiobj_json.c
CHANGED
@@ -2,10 +2,11 @@
|
|
2
2
|
Copyright: Boaz Segev, 2017-2018
|
3
3
|
License: MIT
|
4
4
|
*/
|
5
|
-
#include <fio.h>
|
6
5
|
#include <fiobj_json.h>
|
6
|
+
#define FIO_ARY_NAME fio_json_stack
|
7
|
+
#define FIO_ARY_TYPE FIOBJ
|
8
|
+
#include <fio.h>
|
7
9
|
|
8
|
-
#include <fio_ary.h>
|
9
10
|
#include <fio_json_parser.h>
|
10
11
|
|
11
12
|
#include <assert.h>
|
@@ -37,7 +38,7 @@ typedef struct {
|
|
37
38
|
FIOBJ key;
|
38
39
|
FIOBJ top;
|
39
40
|
FIOBJ target;
|
40
|
-
|
41
|
+
fio_json_stack_s stack;
|
41
42
|
uint8_t is_hash;
|
42
43
|
} fiobj_json_parser_s;
|
43
44
|
|
@@ -95,13 +96,13 @@ static int fio_json_on_start_object(json_parser_s *p) {
|
|
95
96
|
fiobj_json_parser_s *pr = (fiobj_json_parser_s *)p;
|
96
97
|
if (pr->target) {
|
97
98
|
/* push NULL, don't free the objects */
|
98
|
-
|
99
|
+
fio_json_stack_push(&pr->stack, pr->top);
|
99
100
|
pr->top = pr->target;
|
100
101
|
pr->target = FIOBJ_INVALID;
|
101
102
|
} else {
|
102
103
|
FIOBJ hash = fiobj_hash_new();
|
103
104
|
fiobj_json_add2parser(pr, hash);
|
104
|
-
|
105
|
+
fio_json_stack_push(&pr->stack, pr->top);
|
105
106
|
pr->top = hash;
|
106
107
|
}
|
107
108
|
pr->is_hash = 1;
|
@@ -116,7 +117,8 @@ static void fio_json_on_end_object(json_parser_s *p) {
|
|
116
117
|
fiobj_free(pr->key);
|
117
118
|
pr->key = FIOBJ_INVALID;
|
118
119
|
}
|
119
|
-
pr->top =
|
120
|
+
pr->top = FIOBJ_INVALID;
|
121
|
+
fio_json_stack_pop(&pr->stack, &pr->top);
|
120
122
|
pr->is_hash = FIOBJ_TYPE_IS(pr->top, FIOBJ_T_HASH);
|
121
123
|
}
|
122
124
|
/** an array object was detected */
|
@@ -124,9 +126,9 @@ static int fio_json_on_start_array(json_parser_s *p) {
|
|
124
126
|
fiobj_json_parser_s *pr = (fiobj_json_parser_s *)p;
|
125
127
|
if (pr->target)
|
126
128
|
return -1;
|
127
|
-
FIOBJ ary =
|
129
|
+
FIOBJ ary = fiobj_ary_new();
|
128
130
|
fiobj_json_add2parser(pr, ary);
|
129
|
-
|
131
|
+
fio_json_stack_push(&pr->stack, pr->top);
|
130
132
|
pr->top = ary;
|
131
133
|
pr->is_hash = 0;
|
132
134
|
return 0;
|
@@ -134,14 +136,15 @@ static int fio_json_on_start_array(json_parser_s *p) {
|
|
134
136
|
/** an array closure was detected */
|
135
137
|
static void fio_json_on_end_array(json_parser_s *p) {
|
136
138
|
fiobj_json_parser_s *pr = (fiobj_json_parser_s *)p;
|
137
|
-
pr->top =
|
139
|
+
pr->top = FIOBJ_INVALID;
|
140
|
+
fio_json_stack_pop(&pr->stack, &pr->top);
|
138
141
|
pr->is_hash = FIOBJ_TYPE_IS(pr->top, FIOBJ_T_HASH);
|
139
142
|
}
|
140
143
|
/** the JSON parsing is complete */
|
141
144
|
static void fio_json_on_json(json_parser_s *p) {
|
142
145
|
// fiobj_json_parser_s *pr = (fiobj_json_parser_s *)p;
|
143
146
|
// FIO_ARY_FOR(&pr->stack, pos) { fiobj_free((FIOBJ)pos.obj); }
|
144
|
-
//
|
147
|
+
// fio_json_stack_free(&pr->stack);
|
145
148
|
(void)p; /* nothing special... right? */
|
146
149
|
}
|
147
150
|
/** the JSON parsing is complete */
|
@@ -150,10 +153,9 @@ static void fio_json_on_error(json_parser_s *p) {
|
|
150
153
|
#if DEBUG
|
151
154
|
FIO_LOG_DEBUG("JSON on error called.");
|
152
155
|
#endif
|
153
|
-
fiobj_free((FIOBJ)
|
156
|
+
fiobj_free((FIOBJ)fio_json_stack_get(&pr->stack, 0));
|
154
157
|
fiobj_free(pr->key);
|
155
|
-
|
156
|
-
pr->stack = FIO_ARY_INIT;
|
158
|
+
fio_json_stack_free(&pr->stack);
|
157
159
|
*pr = (fiobj_json_parser_s){.top = FIOBJ_INVALID};
|
158
160
|
}
|
159
161
|
|
@@ -260,7 +262,7 @@ static void write_safe_str(FIOBJ dest, const FIOBJ str) {
|
|
260
262
|
typedef struct {
|
261
263
|
FIOBJ dest;
|
262
264
|
FIOBJ parent;
|
263
|
-
|
265
|
+
fio_json_stack_s *stack;
|
264
266
|
uintptr_t count;
|
265
267
|
uint8_t pretty;
|
266
268
|
} obj2json_data_s;
|
@@ -291,8 +293,8 @@ static int fiobj_obj2json_task(FIOBJ o, void *data_) {
|
|
291
293
|
|
292
294
|
case FIOBJ_T_ARRAY:
|
293
295
|
--data->count;
|
294
|
-
|
295
|
-
|
296
|
+
fio_json_stack_push(data->stack, data->parent);
|
297
|
+
fio_json_stack_push(data->stack, (FIOBJ)data->count);
|
296
298
|
data->parent = o;
|
297
299
|
data->count = fiobj_ary_count(o);
|
298
300
|
fiobj_str_write(data->dest, "[", 1);
|
@@ -301,8 +303,8 @@ static int fiobj_obj2json_task(FIOBJ o, void *data_) {
|
|
301
303
|
|
302
304
|
case FIOBJ_T_HASH:
|
303
305
|
--data->count;
|
304
|
-
|
305
|
-
|
306
|
+
fio_json_stack_push(data->stack, data->parent);
|
307
|
+
fio_json_stack_push(data->stack, (FIOBJ)data->count);
|
306
308
|
data->parent = o;
|
307
309
|
data->count = fiobj_hash_count(o);
|
308
310
|
fiobj_str_write(data->dest, "{", 1);
|
@@ -310,8 +312,9 @@ static int fiobj_obj2json_task(FIOBJ o, void *data_) {
|
|
310
312
|
break;
|
311
313
|
}
|
312
314
|
if (data->pretty) {
|
313
|
-
fiobj_str_capa_assert(data->dest,
|
314
|
-
|
315
|
+
fiobj_str_capa_assert(data->dest,
|
316
|
+
fiobj_obj2cstr(data->dest).len +
|
317
|
+
(fio_json_stack_count(data->stack) * 5));
|
315
318
|
while (!data->count && data->parent) {
|
316
319
|
if (FIOBJ_TYPE_IS(data->parent, FIOBJ_T_HASH)) {
|
317
320
|
fiobj_str_write(data->dest, "}", 1);
|
@@ -319,13 +322,15 @@ static int fiobj_obj2json_task(FIOBJ o, void *data_) {
|
|
319
322
|
fiobj_str_write(data->dest, "]", 1);
|
320
323
|
}
|
321
324
|
add_seperator = 1;
|
322
|
-
data->count =
|
323
|
-
data->
|
325
|
+
data->count = 0;
|
326
|
+
fio_json_stack_pop(data->stack, &data->count);
|
327
|
+
data->parent = FIOBJ_INVALID;
|
328
|
+
fio_json_stack_pop(data->stack, &data->parent);
|
324
329
|
}
|
325
330
|
|
326
331
|
if (add_seperator && data->parent) {
|
327
332
|
fiobj_str_write(data->dest, ",\n", 2);
|
328
|
-
uintptr_t indent =
|
333
|
+
uintptr_t indent = fio_json_stack_count(data->stack) - 1;
|
329
334
|
fiobj_str_capa_assert(data->dest,
|
330
335
|
fiobj_obj2cstr(data->dest).len + (indent * 2));
|
331
336
|
fio_str_info_s buf = fiobj_obj2cstr(data->dest);
|
@@ -336,8 +341,9 @@ static int fiobj_obj2json_task(FIOBJ o, void *data_) {
|
|
336
341
|
fiobj_str_resize(data->dest, buf.len);
|
337
342
|
}
|
338
343
|
} else {
|
339
|
-
fiobj_str_capa_assert(data->dest,
|
340
|
-
|
344
|
+
fiobj_str_capa_assert(data->dest,
|
345
|
+
fiobj_obj2cstr(data->dest).len +
|
346
|
+
(fio_json_stack_count(data->stack) << 1));
|
341
347
|
while (!data->count && data->parent) {
|
342
348
|
if (FIOBJ_TYPE_IS(data->parent, FIOBJ_T_HASH)) {
|
343
349
|
fiobj_str_write(data->dest, "}", 1);
|
@@ -345,8 +351,10 @@ static int fiobj_obj2json_task(FIOBJ o, void *data_) {
|
|
345
351
|
fiobj_str_write(data->dest, "]", 1);
|
346
352
|
}
|
347
353
|
add_seperator = 1;
|
348
|
-
data->count =
|
349
|
-
data->parent =
|
354
|
+
data->count = 0;
|
355
|
+
data->parent = FIOBJ_INVALID;
|
356
|
+
fio_json_stack_pop(data->stack, &data->count);
|
357
|
+
fio_json_stack_pop(data->stack, &data->parent);
|
350
358
|
}
|
351
359
|
|
352
360
|
if (add_seperator && data->parent) {
|
@@ -371,10 +379,10 @@ size_t fiobj_json2obj(FIOBJ *pobj, const void *data, size_t len) {
|
|
371
379
|
fiobj_json_parser_s p = {.top = FIOBJ_INVALID};
|
372
380
|
size_t consumed = fio_json_parse(&p.p, data, len);
|
373
381
|
if (!consumed || p.p.depth) {
|
374
|
-
fiobj_free((
|
382
|
+
fiobj_free(fio_json_stack_get(&p.stack, 0));
|
375
383
|
p.top = FIOBJ_INVALID;
|
376
384
|
}
|
377
|
-
|
385
|
+
fio_json_stack_free(&p.stack);
|
378
386
|
fiobj_free(p.key);
|
379
387
|
*pobj = p.top;
|
380
388
|
return consumed;
|
@@ -397,7 +405,7 @@ size_t fiobj_hash_update_json(FIOBJ hash, const void *data, size_t len) {
|
|
397
405
|
return 0;
|
398
406
|
fiobj_json_parser_s p = {.top = FIOBJ_INVALID, .target = hash};
|
399
407
|
size_t consumed = fio_json_parse(&p.p, data, len);
|
400
|
-
|
408
|
+
fio_json_stack_free(&p.stack);
|
401
409
|
fiobj_free(p.key);
|
402
410
|
if (p.top != hash)
|
403
411
|
fiobj_free(p.top);
|
@@ -414,7 +422,7 @@ FIOBJ fiobj_obj2json2(FIOBJ dest, FIOBJ o, uint8_t pretty) {
|
|
414
422
|
fiobj_str_write(dest, "null", 4);
|
415
423
|
return 0;
|
416
424
|
}
|
417
|
-
|
425
|
+
fio_json_stack_s stack = FIO_ARY_INIT;
|
418
426
|
obj2json_data_s data = {
|
419
427
|
.dest = dest,
|
420
428
|
.stack = &stack,
|
@@ -425,9 +433,8 @@ FIOBJ fiobj_obj2json2(FIOBJ dest, FIOBJ o, uint8_t pretty) {
|
|
425
433
|
fiobj_obj2json_task(o, &data);
|
426
434
|
return dest;
|
427
435
|
}
|
428
|
-
fio_ary_new(&stack, 0);
|
429
436
|
fiobj_each2(o, fiobj_obj2json_task, &data);
|
430
|
-
|
437
|
+
fio_json_stack_free(&stack);
|
431
438
|
return dest;
|
432
439
|
}
|
433
440
|
|
data/ext/iodine/fiobj_numbers.c
CHANGED
@@ -6,7 +6,6 @@ License: MIT
|
|
6
6
|
#include <fiobj_numbers.h>
|
7
7
|
#include <fiobject.h>
|
8
8
|
|
9
|
-
#define FIO_OVERRIDE_MALLOC 1
|
10
9
|
#include <fio.h>
|
11
10
|
|
12
11
|
#include <assert.h>
|
@@ -105,7 +104,7 @@ Number API
|
|
105
104
|
|
106
105
|
/** Creates a Number object. Remember to use `fiobj_free`. */
|
107
106
|
FIOBJ fiobj_num_new_bignum(intptr_t num) {
|
108
|
-
fiobj_num_s *o =
|
107
|
+
fiobj_num_s *o = fio_malloc(sizeof(*o));
|
109
108
|
if (!o) {
|
110
109
|
perror("ERROR: fiobj number couldn't allocate memory");
|
111
110
|
exit(errno);
|
@@ -143,7 +142,7 @@ Float API
|
|
143
142
|
|
144
143
|
/** Creates a Float object. Remember to use `fiobj_free`. */
|
145
144
|
FIOBJ fiobj_float_new(double num) {
|
146
|
-
fiobj_float_s *o =
|
145
|
+
fiobj_float_s *o = fio_malloc(sizeof(*o));
|
147
146
|
if (!o) {
|
148
147
|
perror("ERROR: fiobj float couldn't allocate memory");
|
149
148
|
exit(errno);
|
@@ -179,307 +178,6 @@ FIOBJ fiobj_float_tmp(double num) {
|
|
179
178
|
return (FIOBJ)&ret;
|
180
179
|
}
|
181
180
|
|
182
|
-
/* *****************************************************************************
|
183
|
-
Strings to Numbers
|
184
|
-
***************************************************************************** */
|
185
|
-
|
186
|
-
/**
|
187
|
-
* A helper function that converts between String data to a signed int64_t.
|
188
|
-
*
|
189
|
-
* Numbers are assumed to be in base 10. Octal (`0###`), Hex (`0x##`/`x##`) and
|
190
|
-
* binary (`0b##`/ `b##`) are recognized as well. For binary Most Significant
|
191
|
-
* Bit must come first.
|
192
|
-
*
|
193
|
-
* The most significant differance between this function and `strtol` (aside of
|
194
|
-
* API design), is the added support for binary representations.
|
195
|
-
*/
|
196
|
-
#pragma weak fio_atol
|
197
|
-
int64_t __attribute__((weak)) fio_atol(char **pstr) {
|
198
|
-
/* No binary representation in strtol */
|
199
|
-
char *str = *pstr;
|
200
|
-
uint64_t result = 0;
|
201
|
-
uint8_t invert = 0;
|
202
|
-
while (str[0] == '-') {
|
203
|
-
invert ^= 1;
|
204
|
-
++str;
|
205
|
-
}
|
206
|
-
if (str[0] == 'B' || str[0] == 'b' ||
|
207
|
-
(str[0] == '0' && (str[1] == 'b' || str[1] == 'B'))) {
|
208
|
-
/* base 2 */
|
209
|
-
if (str[0] == '0')
|
210
|
-
str++;
|
211
|
-
str++;
|
212
|
-
while (str[0] == '0' || str[0] == '1') {
|
213
|
-
result = (result << 1) | (str[0] == '1');
|
214
|
-
str++;
|
215
|
-
}
|
216
|
-
} else if (str[0] == 'x' || str[0] == 'X' ||
|
217
|
-
(str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))) {
|
218
|
-
/* base 16 */
|
219
|
-
uint8_t tmp;
|
220
|
-
if (str[0] == '0')
|
221
|
-
str++;
|
222
|
-
str++;
|
223
|
-
for (;;) {
|
224
|
-
if (str[0] >= '0' && str[0] <= '9')
|
225
|
-
tmp = str[0] - '0';
|
226
|
-
else if (str[0] >= 'A' && str[0] <= 'F')
|
227
|
-
tmp = str[0] - ('A' - 10);
|
228
|
-
else if (str[0] >= 'a' && str[0] <= 'f')
|
229
|
-
tmp = str[0] - ('a' - 10);
|
230
|
-
else
|
231
|
-
goto finish;
|
232
|
-
result = (result << 4) | tmp;
|
233
|
-
str++;
|
234
|
-
}
|
235
|
-
} else if (str[0] == '0') {
|
236
|
-
++str;
|
237
|
-
/* base 8 */
|
238
|
-
const char *end = str;
|
239
|
-
while (end[0] >= '0' && end[0] <= '7' && (uintptr_t)(end - str) < 22)
|
240
|
-
end++;
|
241
|
-
if ((uintptr_t)(end - str) > 21) /* TODO: fix too large for a number */
|
242
|
-
return 0;
|
243
|
-
|
244
|
-
while (str < end) {
|
245
|
-
result = (result * 8) + (str[0] - '0');
|
246
|
-
str++;
|
247
|
-
}
|
248
|
-
} else {
|
249
|
-
/* base 10 */
|
250
|
-
const char *end = str;
|
251
|
-
while (end[0] >= '0' && end[0] <= '9' && (uintptr_t)(end - str) < 22)
|
252
|
-
end++;
|
253
|
-
if ((uintptr_t)(end - str) > 21) /* too large for a number */
|
254
|
-
return 0;
|
255
|
-
|
256
|
-
while (str < end) {
|
257
|
-
result = (result * 10) + (str[0] - '0');
|
258
|
-
str++;
|
259
|
-
}
|
260
|
-
}
|
261
|
-
finish:
|
262
|
-
if (invert)
|
263
|
-
result = 0 - result;
|
264
|
-
*pstr = str;
|
265
|
-
return (int64_t)result;
|
266
|
-
}
|
267
|
-
|
268
|
-
/** A helper function that converts between String data to a signed double. */
|
269
|
-
#pragma weak fio_atof
|
270
|
-
double __attribute__((weak)) fio_atof(char **pstr) {
|
271
|
-
return strtold(*pstr, pstr);
|
272
|
-
}
|
273
|
-
|
274
|
-
/* *****************************************************************************
|
275
|
-
Numbers to Strings
|
276
|
-
***************************************************************************** */
|
277
|
-
|
278
|
-
/**
|
279
|
-
* A helper function that writes a signed int64_t to a string.
|
280
|
-
*
|
281
|
-
* No overflow guard is provided, make sure there's at least 68 bytes
|
282
|
-
* available (for base 2).
|
283
|
-
*
|
284
|
-
* Offers special support for base 2 (binary), base 8 (octal), base 10 and base
|
285
|
-
* 16 (hex). An unsupported base will silently default to base 10. Prefixes
|
286
|
-
* are automatically added (i.e., "0x" for hex and "0b" for base 2).
|
287
|
-
*
|
288
|
-
* Returns the number of bytes actually written (excluding the NUL
|
289
|
-
* terminator).
|
290
|
-
*/
|
291
|
-
#pragma weak fio_ltoa
|
292
|
-
size_t __attribute__((weak)) fio_ltoa(char *dest, int64_t num, uint8_t base) {
|
293
|
-
const char notation[] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
294
|
-
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
295
|
-
|
296
|
-
size_t len = 0;
|
297
|
-
char buf[48]; /* we only need up to 20 for base 10, but base 3 needs 41... */
|
298
|
-
|
299
|
-
if (!num)
|
300
|
-
goto zero;
|
301
|
-
|
302
|
-
switch (base) {
|
303
|
-
case 1:
|
304
|
-
case 2:
|
305
|
-
/* Base 2 */
|
306
|
-
{
|
307
|
-
uint64_t n = num; /* avoid bit shifting inconsistencies with signed bit */
|
308
|
-
uint8_t i = 0; /* counting bits */
|
309
|
-
dest[len++] = '0';
|
310
|
-
dest[len++] = 'b';
|
311
|
-
|
312
|
-
while ((i < 64) && (n & 0x8000000000000000) == 0) {
|
313
|
-
n = n << 1;
|
314
|
-
i++;
|
315
|
-
}
|
316
|
-
/* make sure the Binary representation doesn't appear signed. */
|
317
|
-
if (i) {
|
318
|
-
dest[len++] = '0';
|
319
|
-
}
|
320
|
-
/* write to dest. */
|
321
|
-
while (i < 64) {
|
322
|
-
dest[len++] = ((n & 0x8000000000000000) ? '1' : '0');
|
323
|
-
n = n << 1;
|
324
|
-
i++;
|
325
|
-
}
|
326
|
-
dest[len] = 0;
|
327
|
-
return len;
|
328
|
-
}
|
329
|
-
case 8:
|
330
|
-
/* Base 8 */
|
331
|
-
{
|
332
|
-
uint64_t l = 0;
|
333
|
-
if (num < 0) {
|
334
|
-
dest[len++] = '-';
|
335
|
-
num = 0 - num;
|
336
|
-
}
|
337
|
-
dest[len++] = '0';
|
338
|
-
|
339
|
-
while (num) {
|
340
|
-
buf[l++] = '0' + (num & 7);
|
341
|
-
num = num >> 3;
|
342
|
-
}
|
343
|
-
while (l) {
|
344
|
-
--l;
|
345
|
-
dest[len++] = buf[l];
|
346
|
-
}
|
347
|
-
dest[len] = 0;
|
348
|
-
return len;
|
349
|
-
}
|
350
|
-
|
351
|
-
case 16:
|
352
|
-
/* Base 16 */
|
353
|
-
{
|
354
|
-
uint64_t n = num; /* avoid bit shifting inconsistencies with signed bit */
|
355
|
-
uint8_t i = 0; /* counting bits */
|
356
|
-
dest[len++] = '0';
|
357
|
-
dest[len++] = 'x';
|
358
|
-
while (i < 8 && (n & 0xFF00000000000000) == 0) {
|
359
|
-
n = n << 8;
|
360
|
-
i++;
|
361
|
-
}
|
362
|
-
/* make sure the Hex representation doesn't appear signed. */
|
363
|
-
if (i && (n & 0x8000000000000000)) {
|
364
|
-
dest[len++] = '0';
|
365
|
-
dest[len++] = '0';
|
366
|
-
}
|
367
|
-
/* write the damn thing */
|
368
|
-
while (i < 8) {
|
369
|
-
uint8_t tmp = (n & 0xF000000000000000) >> 60;
|
370
|
-
dest[len++] = notation[tmp];
|
371
|
-
tmp = (n & 0x0F00000000000000) >> 56;
|
372
|
-
dest[len++] = notation[tmp];
|
373
|
-
i++;
|
374
|
-
n = n << 8;
|
375
|
-
}
|
376
|
-
dest[len] = 0;
|
377
|
-
return len;
|
378
|
-
}
|
379
|
-
case 3:
|
380
|
-
case 4:
|
381
|
-
case 5:
|
382
|
-
case 6:
|
383
|
-
case 7:
|
384
|
-
case 9:
|
385
|
-
/* rare bases */
|
386
|
-
if (num < 0) {
|
387
|
-
dest[len++] = '-';
|
388
|
-
num = 0 - num;
|
389
|
-
}
|
390
|
-
uint64_t l = 0;
|
391
|
-
while (num) {
|
392
|
-
uint64_t t = num / base;
|
393
|
-
buf[l++] = '0' + (num - (t * base));
|
394
|
-
num = t;
|
395
|
-
}
|
396
|
-
while (l) {
|
397
|
-
--l;
|
398
|
-
dest[len++] = buf[l];
|
399
|
-
}
|
400
|
-
dest[len] = 0;
|
401
|
-
return len;
|
402
|
-
|
403
|
-
default:
|
404
|
-
break;
|
405
|
-
}
|
406
|
-
/* Base 10, the default base */
|
407
|
-
|
408
|
-
if (num < 0) {
|
409
|
-
dest[len++] = '-';
|
410
|
-
num = 0 - num;
|
411
|
-
}
|
412
|
-
uint64_t l = 0;
|
413
|
-
while (num) {
|
414
|
-
uint64_t t = num / 10;
|
415
|
-
buf[l++] = '0' + (num - (t * 10));
|
416
|
-
num = t;
|
417
|
-
}
|
418
|
-
while (l) {
|
419
|
-
--l;
|
420
|
-
dest[len++] = buf[l];
|
421
|
-
}
|
422
|
-
dest[len] = 0;
|
423
|
-
return len;
|
424
|
-
|
425
|
-
zero:
|
426
|
-
switch (base) {
|
427
|
-
case 1:
|
428
|
-
case 2:
|
429
|
-
dest[len++] = '0';
|
430
|
-
dest[len++] = 'b';
|
431
|
-
case 16:
|
432
|
-
dest[len++] = '0';
|
433
|
-
dest[len++] = 'x';
|
434
|
-
dest[len++] = '0';
|
435
|
-
}
|
436
|
-
dest[len++] = '0';
|
437
|
-
dest[len] = 0;
|
438
|
-
return len;
|
439
|
-
}
|
440
|
-
|
441
|
-
/**
|
442
|
-
* A helper function that converts between a double to a string.
|
443
|
-
*
|
444
|
-
* No overflow guard is provided, make sure there's at least 130 bytes
|
445
|
-
* available (for base 2).
|
446
|
-
*
|
447
|
-
* Supports base 2, base 10 and base 16. An unsupported base will silently
|
448
|
-
* default to base 10. Prefixes aren't added (i.e., no "0x" or "0b" at the
|
449
|
-
* beginning of the string).
|
450
|
-
*
|
451
|
-
* Returns the number of bytes actually written (excluding the NUL
|
452
|
-
* terminator).
|
453
|
-
*/
|
454
|
-
#pragma weak fio_ftoa
|
455
|
-
size_t __attribute__((weak)) fio_ftoa(char *dest, double num, uint8_t base) {
|
456
|
-
if (base == 2 || base == 16) {
|
457
|
-
/* handle the binary / Hex representation the same as if it were an
|
458
|
-
* int64_t
|
459
|
-
*/
|
460
|
-
int64_t *i = (void *)#
|
461
|
-
return fio_ltoa(dest, *i, base);
|
462
|
-
}
|
463
|
-
|
464
|
-
size_t written = sprintf(dest, "%g", num);
|
465
|
-
uint8_t need_zero = 1;
|
466
|
-
char *start = dest;
|
467
|
-
while (*start) {
|
468
|
-
if (*start == ',') // locale issues?
|
469
|
-
*start = '.';
|
470
|
-
if (*start == '.' || *start == 'e') {
|
471
|
-
need_zero = 0;
|
472
|
-
break;
|
473
|
-
}
|
474
|
-
start++;
|
475
|
-
}
|
476
|
-
if (need_zero) {
|
477
|
-
dest[written++] = '.';
|
478
|
-
dest[written++] = '0';
|
479
|
-
}
|
480
|
-
return written;
|
481
|
-
}
|
482
|
-
|
483
181
|
/* *****************************************************************************
|
484
182
|
Numbers to Strings - Buffered
|
485
183
|
***************************************************************************** */
|