iodine 0.4.14 → 0.4.15
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 +61 -33
- data/README.md +7 -5
- data/ext/iodine/base64.c +12 -0
- data/ext/iodine/defer.c +211 -108
- data/ext/iodine/defer.h +7 -0
- data/ext/iodine/facil.c +5 -1
- data/ext/iodine/facil.h +1 -1
- data/ext/iodine/fio2resp.c +19 -30
- data/ext/iodine/fio2resp.h +2 -1
- data/ext/iodine/fio_cli_helper.c +2 -2
- data/ext/iodine/fiobj.h +11 -624
- data/ext/iodine/fiobj_ary.c +65 -26
- data/ext/iodine/fiobj_ary.h +106 -0
- data/ext/iodine/fiobj_hash.c +175 -115
- data/ext/iodine/fiobj_hash.h +128 -0
- data/ext/iodine/fiobj_internal.c +189 -0
- data/ext/iodine/{fiobj_types.h → fiobj_internal.h} +126 -136
- data/ext/iodine/fiobj_json.c +161 -207
- data/ext/iodine/fiobj_json.h +43 -0
- data/ext/iodine/fiobj_numbers.c +53 -35
- data/ext/iodine/fiobj_numbers.h +49 -0
- data/ext/iodine/fiobj_primitives.c +103 -70
- data/ext/iodine/fiobj_primitives.h +55 -0
- data/ext/iodine/fiobj_str.c +171 -59
- data/ext/iodine/fiobj_str.h +113 -0
- data/ext/iodine/fiobj_sym.c +46 -124
- data/ext/iodine/fiobj_sym.h +60 -0
- data/ext/iodine/fiobject.c +589 -0
- data/ext/iodine/fiobject.h +276 -0
- data/ext/iodine/pubsub.h +1 -1
- data/ext/iodine/resp.c +2 -2
- data/ext/iodine/siphash.c +11 -0
- data/ext/iodine/spnlock.inc +7 -5
- data/ext/iodine/websocket_parser.h +44 -7
- data/lib/iodine/version.rb +1 -1
- metadata +13 -8
- data/ext/iodine/fiobj_alloc.c +0 -81
- data/ext/iodine/fiobj_generic.c +0 -260
- data/ext/iodine/fiobj_io.c +0 -58
- data/ext/iodine/fiobj_misc.c +0 -213
- data/ext/iodine/fiobj_tests.c +0 -474
data/ext/iodine/fiobj_alloc.c
DELETED
@@ -1,81 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
Copyright: Boaz segev, 2017
|
3
|
-
License: MIT
|
4
|
-
|
5
|
-
Feel free to copy, use and enjoy according to the license provided.
|
6
|
-
*/
|
7
|
-
|
8
|
-
/* *****************************************************************************
|
9
|
-
This file handles deallocation concerns.
|
10
|
-
|
11
|
-
Since Hash and Array objects will need to deallocate their children, the logic
|
12
|
-
regareding object type recorgnition and deallocation was centrelized here.
|
13
|
-
***************************************************************************** */
|
14
|
-
#include "fiobj_types.h"
|
15
|
-
|
16
|
-
/* *****************************************************************************
|
17
|
-
Object Deallocation
|
18
|
-
***************************************************************************** */
|
19
|
-
|
20
|
-
void fiobj_dealloc(fiobj_s *obj) {
|
21
|
-
if (!obj)
|
22
|
-
return;
|
23
|
-
if (OBJ2HEAD(obj).ref == 0) {
|
24
|
-
fprintf(stderr,
|
25
|
-
"ERROR: attempting to free an object that isn't a fiobj or already "
|
26
|
-
"freed (%p)\n",
|
27
|
-
(void *)obj);
|
28
|
-
kill(0, SIGABRT);
|
29
|
-
}
|
30
|
-
if (spn_sub(&OBJ2HEAD(obj).ref, 1))
|
31
|
-
return;
|
32
|
-
OBJ2HEAD(obj).vtable->free(obj);
|
33
|
-
}
|
34
|
-
|
35
|
-
/* *****************************************************************************
|
36
|
-
Deep Allocation (`fiobj_dup`)
|
37
|
-
***************************************************************************** */
|
38
|
-
|
39
|
-
/* simply increrase the reference count for each object. */
|
40
|
-
static int dup_task_callback(fiobj_s *obj, void *arg) {
|
41
|
-
if (!obj)
|
42
|
-
return 0;
|
43
|
-
spn_add(&OBJ2HEAD(obj).ref, 1);
|
44
|
-
// if (obj->type == FIOBJ_T_COUPLET)
|
45
|
-
// spn_add(&OBJ2HEAD(obj2couplet(obj)->obj).ref, 1);
|
46
|
-
return 0;
|
47
|
-
(void)arg;
|
48
|
-
}
|
49
|
-
|
50
|
-
/** Increases an object's reference count. */
|
51
|
-
fiobj_s *fiobj_dup(fiobj_s *obj) {
|
52
|
-
fiobj_each2(obj, dup_task_callback, NULL);
|
53
|
-
return obj;
|
54
|
-
}
|
55
|
-
|
56
|
-
/* *****************************************************************************
|
57
|
-
Deep Deallocation (`fiobj_free`)
|
58
|
-
***************************************************************************** */
|
59
|
-
|
60
|
-
static int dealloc_task_callback(fiobj_s *obj, void *arg) {
|
61
|
-
// if (!obj)
|
62
|
-
// return 0;
|
63
|
-
// if (obj->type == FIOBJ_T_COUPLET)
|
64
|
-
// fiobj_dealloc(obj2couplet(obj)->obj);
|
65
|
-
fiobj_dealloc(obj);
|
66
|
-
return 0;
|
67
|
-
(void)arg;
|
68
|
-
}
|
69
|
-
/**
|
70
|
-
* Decreases an object's reference count, releasing memory and
|
71
|
-
* resources.
|
72
|
-
*
|
73
|
-
* This function affects nested objects, meaning that when an Array or
|
74
|
-
* a Hashe object is passed along, it's children (nested objects) are
|
75
|
-
* also freed.
|
76
|
-
*/
|
77
|
-
void fiobj_free(fiobj_s *obj) {
|
78
|
-
if (!obj)
|
79
|
-
return;
|
80
|
-
fiobj_each2(obj, dealloc_task_callback, NULL);
|
81
|
-
}
|
data/ext/iodine/fiobj_generic.c
DELETED
@@ -1,260 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
Copyright: Boaz segev, 2017
|
3
|
-
License: MIT
|
4
|
-
|
5
|
-
Feel free to copy, use and enjoy according to the license provided.
|
6
|
-
*/
|
7
|
-
|
8
|
-
#include "fiobj_types.h"
|
9
|
-
|
10
|
-
/* *****************************************************************************
|
11
|
-
No-op for vtable
|
12
|
-
***************************************************************************** */
|
13
|
-
|
14
|
-
fio_cstr_s fiobj_noop_str(fiobj_s *obj) {
|
15
|
-
return (fio_cstr_s){.data = NULL};
|
16
|
-
(void)obj;
|
17
|
-
}
|
18
|
-
int64_t fiobj_noop_i(fiobj_s *obj) {
|
19
|
-
return 0;
|
20
|
-
(void)obj;
|
21
|
-
}
|
22
|
-
double fiobj_noop_f(fiobj_s *obj) {
|
23
|
-
return 0;
|
24
|
-
(void)obj;
|
25
|
-
}
|
26
|
-
|
27
|
-
size_t fiobj_noop_count(fiobj_s *obj) {
|
28
|
-
return 0;
|
29
|
-
(void)obj;
|
30
|
-
}
|
31
|
-
|
32
|
-
size_t fiobj_noop_each1(fiobj_s *obj, size_t start_at,
|
33
|
-
int (*task)(fiobj_s *obj, void *arg), void *arg) {
|
34
|
-
return 0;
|
35
|
-
(void)obj;
|
36
|
-
(void)start_at;
|
37
|
-
(void)task;
|
38
|
-
(void)arg;
|
39
|
-
}
|
40
|
-
|
41
|
-
void fiobj_simple_dealloc(fiobj_s *o) { free(&OBJ2HEAD(o)); }
|
42
|
-
|
43
|
-
/* *****************************************************************************
|
44
|
-
Generic Object API
|
45
|
-
***************************************************************************** */
|
46
|
-
|
47
|
-
/**
|
48
|
-
* Returns a Number's value.
|
49
|
-
*
|
50
|
-
* If a String or Symbol are passed to the function, they will be
|
51
|
-
* parsed assuming base 10 numerical data.
|
52
|
-
*
|
53
|
-
* A type error results in 0.
|
54
|
-
*/
|
55
|
-
int64_t fiobj_obj2num(fiobj_s *obj) {
|
56
|
-
if (!obj)
|
57
|
-
return 0;
|
58
|
-
return OBJ2HEAD(obj).vtable->to_i(obj);
|
59
|
-
}
|
60
|
-
|
61
|
-
/**
|
62
|
-
* Returns a Float's value.
|
63
|
-
*
|
64
|
-
* If a String or Symbol are passed to the function, they will be
|
65
|
-
* parsed assuming base 10 numerical data.
|
66
|
-
*
|
67
|
-
* A type error results in 0.
|
68
|
-
*/
|
69
|
-
double fiobj_obj2float(fiobj_s *obj) {
|
70
|
-
if (!obj)
|
71
|
-
return 0;
|
72
|
-
return OBJ2HEAD(obj).vtable->to_f(obj);
|
73
|
-
}
|
74
|
-
|
75
|
-
/**
|
76
|
-
* Returns a C String (NUL terminated) using the `fio_cstr_s` data type.
|
77
|
-
*/
|
78
|
-
fio_cstr_s fiobj_obj2cstr(fiobj_s *obj) {
|
79
|
-
if (!obj)
|
80
|
-
return (fio_cstr_s){.buffer = NULL, .len = 0};
|
81
|
-
return OBJ2HEAD(obj).vtable->to_str(obj);
|
82
|
-
}
|
83
|
-
|
84
|
-
/**
|
85
|
-
* Single layer iteration using a callback for each nested fio object.
|
86
|
-
*/
|
87
|
-
size_t fiobj_each1(fiobj_s *obj, size_t start_at,
|
88
|
-
int (*task)(fiobj_s *obj, void *arg), void *arg) {
|
89
|
-
return OBJ2HEAD(obj).vtable->each1(obj, start_at, task, arg);
|
90
|
-
}
|
91
|
-
|
92
|
-
/* *****************************************************************************
|
93
|
-
Object Iteration (`fiobj_each2`)
|
94
|
-
***************************************************************************** */
|
95
|
-
|
96
|
-
static __thread fiobj_s *fiobj_cyclic_protection = NULL;
|
97
|
-
fiobj_s *fiobj_each_get_cyclic(void) { return fiobj_cyclic_protection; }
|
98
|
-
|
99
|
-
static uint8_t already_processed(fiobj_s *nested, fiobj_s *obj) {
|
100
|
-
#if FIOBJ_NESTING_PROTECTION
|
101
|
-
size_t end = obj2ary(nested)->end;
|
102
|
-
for (size_t i = obj2ary(nested)->start; i < end; i++) {
|
103
|
-
if (obj2ary(nested)->arry[i] == obj)
|
104
|
-
return 1;
|
105
|
-
}
|
106
|
-
#endif
|
107
|
-
OBJREF_ADD(obj);
|
108
|
-
fiobj_ary_push(nested, obj);
|
109
|
-
return 0;
|
110
|
-
}
|
111
|
-
|
112
|
-
struct fiobj_each2_task_s {
|
113
|
-
fiobj_s *nested;
|
114
|
-
int (*task)(fiobj_s *obj, void *arg);
|
115
|
-
void *arg;
|
116
|
-
fiobj_s *child;
|
117
|
-
};
|
118
|
-
|
119
|
-
int fiobj_each2_task_wrapper(fiobj_s *obj, void *data_) {
|
120
|
-
struct fiobj_each2_task_s *data = data_;
|
121
|
-
if (!obj || !OBJ2HEAD(obj).vtable->count(obj))
|
122
|
-
return data->task(obj, data->arg);
|
123
|
-
|
124
|
-
data->child = obj->type == FIOBJ_T_COUPLET ? obj2couplet(obj)->obj : obj;
|
125
|
-
if (already_processed(data->nested, data->child)) {
|
126
|
-
data->child = NULL;
|
127
|
-
fiobj_cyclic_protection = obj;
|
128
|
-
int ret = data->task(NULL, data->arg);
|
129
|
-
fiobj_cyclic_protection = NULL;
|
130
|
-
return ret;
|
131
|
-
}
|
132
|
-
data->task(obj, data->arg);
|
133
|
-
return -1;
|
134
|
-
}
|
135
|
-
/**
|
136
|
-
* Deep itteration using a callback for each fio object, including the parent.
|
137
|
-
* If the callback returns -1, the loop is broken. Any other value is ignored.
|
138
|
-
*/
|
139
|
-
void fiobj_each2(fiobj_s *obj, int (*task)(fiobj_s *obj, void *arg),
|
140
|
-
void *arg) {
|
141
|
-
/* optimize simple items */
|
142
|
-
if (!obj || OBJ2HEAD(obj).vtable->count(obj) == 0) {
|
143
|
-
task(obj, arg);
|
144
|
-
return;
|
145
|
-
}
|
146
|
-
/* Prepare for layerd iteration */
|
147
|
-
uintptr_t count = 0;
|
148
|
-
fiobj_s *nested = fiobj_ary_new2(64);
|
149
|
-
fiobj_s *state = fiobj_ary_new2(128);
|
150
|
-
struct fiobj_each2_task_s data = {.task = task, .arg = arg, .nested = nested};
|
151
|
-
OBJREF_ADD(obj);
|
152
|
-
fiobj_ary_push(nested, obj);
|
153
|
-
if (task(obj, arg) == -1)
|
154
|
-
goto finish;
|
155
|
-
rebase:
|
156
|
-
/* resume ? */
|
157
|
-
data.child = NULL;
|
158
|
-
count =
|
159
|
-
OBJ2HEAD(obj).vtable->each1(obj, count, fiobj_each2_task_wrapper, &data);
|
160
|
-
if (data.child) {
|
161
|
-
fiobj_ary_push(state, obj);
|
162
|
-
fiobj_ary_push(state, (void *)count);
|
163
|
-
count = 0;
|
164
|
-
obj = data.child;
|
165
|
-
goto rebase;
|
166
|
-
}
|
167
|
-
|
168
|
-
/* any more nested layers left to handle? */
|
169
|
-
if (fiobj_ary_count(state)) {
|
170
|
-
count = (uintptr_t)fiobj_ary_pop(state);
|
171
|
-
obj = fiobj_ary_pop(state);
|
172
|
-
goto rebase;
|
173
|
-
}
|
174
|
-
|
175
|
-
finish:
|
176
|
-
while ((obj = fiobj_ary_pop(nested)))
|
177
|
-
fiobj_dealloc(obj);
|
178
|
-
fiobj_dealloc(nested);
|
179
|
-
fiobj_dealloc(state);
|
180
|
-
return;
|
181
|
-
}
|
182
|
-
|
183
|
-
/* *****************************************************************************
|
184
|
-
Object Comparison (`fiobj_iseq`)
|
185
|
-
***************************************************************************** */
|
186
|
-
|
187
|
-
static inline int fiobj_iseq_check(fiobj_s *obj1, fiobj_s *obj2) {
|
188
|
-
if (obj1 == obj2)
|
189
|
-
return 1;
|
190
|
-
if (!obj1 || !obj2)
|
191
|
-
return 0;
|
192
|
-
return OBJ2HEAD(obj1).vtable->is_eq(obj1, obj2);
|
193
|
-
}
|
194
|
-
|
195
|
-
struct fiobj_iseq_data_s {
|
196
|
-
fiobj_s *root;
|
197
|
-
fiobj_s *nested;
|
198
|
-
fiobj_s *parallel;
|
199
|
-
uintptr_t count;
|
200
|
-
uint8_t is_hash;
|
201
|
-
uint8_t err;
|
202
|
-
};
|
203
|
-
|
204
|
-
int fiobj_iseq_task(fiobj_s *obj, void *data_) {
|
205
|
-
struct fiobj_iseq_data_s *data = data_;
|
206
|
-
if (fiobj_cyclic_protection)
|
207
|
-
obj = fiobj_cyclic_protection;
|
208
|
-
|
209
|
-
if (data->root == obj)
|
210
|
-
return 0;
|
211
|
-
|
212
|
-
if (data->count >= OBJ2HEAD(data->root).vtable->count(data->root)) {
|
213
|
-
data->count = (uintptr_t)fiobj_ary_pop(data->nested);
|
214
|
-
data->parallel = fiobj_ary_pop(data->nested);
|
215
|
-
data->root = fiobj_ary_pop(data->nested);
|
216
|
-
data->is_hash = (data->root->type == FIOBJ_T_HASH);
|
217
|
-
}
|
218
|
-
|
219
|
-
fiobj_s *obj2;
|
220
|
-
if (data->is_hash) {
|
221
|
-
obj2 = fiobj_hash_get(data->parallel, fiobj_couplet2key(obj));
|
222
|
-
obj = fiobj_couplet2obj(obj);
|
223
|
-
} else {
|
224
|
-
obj2 = fiobj_ary_entry(data->parallel, data->count);
|
225
|
-
}
|
226
|
-
data->count++;
|
227
|
-
if (!fiobj_iseq_check(obj, obj2)) {
|
228
|
-
data->err = 1;
|
229
|
-
return -1;
|
230
|
-
}
|
231
|
-
if (!fiobj_cyclic_protection && OBJ2HEAD(obj).vtable->count(obj)) {
|
232
|
-
fiobj_ary_push(data->nested, data->root);
|
233
|
-
fiobj_ary_push(data->nested, data->parallel);
|
234
|
-
fiobj_ary_push(data->nested, (fiobj_s *)data->count);
|
235
|
-
data->count = 0;
|
236
|
-
data->root = obj;
|
237
|
-
data->parallel = obj2;
|
238
|
-
data->is_hash = (obj->type == FIOBJ_T_HASH);
|
239
|
-
}
|
240
|
-
return 0;
|
241
|
-
}
|
242
|
-
|
243
|
-
int fiobj_iseq(fiobj_s *obj1, fiobj_s *obj2) {
|
244
|
-
if (OBJ2HEAD(obj1).vtable->count(obj1) == 0)
|
245
|
-
return fiobj_iseq_check(obj1, obj2);
|
246
|
-
if (!fiobj_iseq_check(obj1, obj2))
|
247
|
-
return 0;
|
248
|
-
struct fiobj_iseq_data_s data = {
|
249
|
-
.root = obj1,
|
250
|
-
.nested = fiobj_ary_new2(128),
|
251
|
-
.is_hash = obj1->type == FIOBJ_T_HASH,
|
252
|
-
// .count = OBJ2HEAD(obj1).vtable->count(obj1),
|
253
|
-
.parallel = obj2,
|
254
|
-
};
|
255
|
-
// fiobj_ary_push(data.nested, obj2);
|
256
|
-
// fiobj_ary_push(data.nested, (fiobj_s *)OBJ2HEAD(obj1).vtable->count(obj1));
|
257
|
-
fiobj_each2(obj1, fiobj_iseq_task, &data);
|
258
|
-
fiobj_dealloc(data.nested);
|
259
|
-
return data.err == 0;
|
260
|
-
}
|
data/ext/iodine/fiobj_io.c
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
Copyright: Boaz segev, 2017
|
3
|
-
License: MIT
|
4
|
-
|
5
|
-
Feel free to copy, use and enjoy according to the license provided.
|
6
|
-
*/
|
7
|
-
#include "fiobj_types.h"
|
8
|
-
|
9
|
-
/* *****************************************************************************
|
10
|
-
IO VTable
|
11
|
-
***************************************************************************** */
|
12
|
-
|
13
|
-
static int64_t fio_io2i(fiobj_s *io) { return (int64_t)obj2io(io)->fd; }
|
14
|
-
|
15
|
-
static int fiobj_io_is_eq(fiobj_s *self, fiobj_s *other) {
|
16
|
-
if (!other || other->type != self->type ||
|
17
|
-
obj2io(self)->fd != obj2io(other)->fd)
|
18
|
-
return 0;
|
19
|
-
return 1;
|
20
|
-
}
|
21
|
-
|
22
|
-
static struct fiobj_vtable_s FIOBJ_VTABLE_IO = {
|
23
|
-
.free = fiobj_simple_dealloc,
|
24
|
-
.to_i = fio_io2i,
|
25
|
-
.to_f = fiobj_noop_f,
|
26
|
-
.to_str = fiobj_noop_str,
|
27
|
-
.is_eq = fiobj_io_is_eq,
|
28
|
-
.count = fiobj_noop_count,
|
29
|
-
.each1 = fiobj_noop_each1,
|
30
|
-
};
|
31
|
-
|
32
|
-
/* *****************************************************************************
|
33
|
-
IO API
|
34
|
-
***************************************************************************** */
|
35
|
-
|
36
|
-
/** Wrapps a file descriptor in an IO object. Use `fiobj_free` to close. */
|
37
|
-
fiobj_s *fio_io_wrap(intptr_t fd) {
|
38
|
-
fiobj_head_s *head;
|
39
|
-
head = malloc(sizeof(*head) + sizeof(fio_io_s));
|
40
|
-
if (!head)
|
41
|
-
perror("ERROR: fiobj IO couldn't allocate memory"), exit(errno);
|
42
|
-
*head = (fiobj_head_s){
|
43
|
-
.ref = 1, .vtable = &FIOBJ_VTABLE_IO,
|
44
|
-
};
|
45
|
-
*obj2io(HEAD2OBJ(head)) = (fio_io_s){.type = FIOBJ_T_IO, .fd = fd};
|
46
|
-
return HEAD2OBJ(head);
|
47
|
-
}
|
48
|
-
|
49
|
-
/**
|
50
|
-
* Return an IO's fd.
|
51
|
-
*
|
52
|
-
* A type error results in -1.
|
53
|
-
*/
|
54
|
-
intptr_t fiobj_io_fd(fiobj_s *obj) {
|
55
|
-
if (obj->type != FIOBJ_T_IO)
|
56
|
-
return -1;
|
57
|
-
return ((fio_io_s *)obj)->fd;
|
58
|
-
}
|
data/ext/iodine/fiobj_misc.c
DELETED
@@ -1,213 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
Copyright: Boaz segev, 2017
|
3
|
-
License: MIT
|
4
|
-
|
5
|
-
Feel free to copy, use and enjoy according to the license provided.
|
6
|
-
*/
|
7
|
-
#include "fiobj_types.h"
|
8
|
-
|
9
|
-
/* *****************************************************************************
|
10
|
-
Number and Float Helpers
|
11
|
-
***************************************************************************** */
|
12
|
-
static const char hex_notation[] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
13
|
-
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
14
|
-
|
15
|
-
/**
|
16
|
-
* A helper function that converts between String data to a signed int64_t.
|
17
|
-
*
|
18
|
-
* Numbers are assumed to be in base 10. `0x##` (or `x##`) and `0b##` (or
|
19
|
-
* `b##`) are recognized as base 16 and base 2 (binary MSB first)
|
20
|
-
* respectively.
|
21
|
-
*/
|
22
|
-
int64_t fio_atol(char **pstr) {
|
23
|
-
char *str = *pstr;
|
24
|
-
uint64_t result = 0;
|
25
|
-
uint8_t invert = 0;
|
26
|
-
while (str[0] == '0')
|
27
|
-
str++;
|
28
|
-
while (str[0] == '-') {
|
29
|
-
invert ^= 1;
|
30
|
-
str++;
|
31
|
-
}
|
32
|
-
while (str[0] == '0')
|
33
|
-
str++;
|
34
|
-
if (str[0] == 'b' || str[0] == 'B') {
|
35
|
-
/* base 2 */
|
36
|
-
str++;
|
37
|
-
while (str[0] == '0' || str[0] == '1') {
|
38
|
-
result = (result << 1) | (str[0] == '1');
|
39
|
-
str++;
|
40
|
-
}
|
41
|
-
} else if (str[0] == 'x' || str[0] == 'X') {
|
42
|
-
/* base 16 */
|
43
|
-
uint8_t tmp;
|
44
|
-
str++;
|
45
|
-
while (1) {
|
46
|
-
if (str[0] >= '0' && str[0] <= '9')
|
47
|
-
tmp = str[0] - '0';
|
48
|
-
else if (str[0] >= 'A' && str[0] <= 'F')
|
49
|
-
tmp = str[0] - ('A' - 10);
|
50
|
-
else if (str[0] >= 'a' && str[0] <= 'f')
|
51
|
-
tmp = str[0] - ('a' - 10);
|
52
|
-
else
|
53
|
-
goto finish;
|
54
|
-
result = (result << 4) | tmp;
|
55
|
-
str++;
|
56
|
-
}
|
57
|
-
} else {
|
58
|
-
/* base 10 */
|
59
|
-
const char *end = str;
|
60
|
-
while (end[0] >= '0' && end[0] <= '9' && (uintptr_t)(end - str) < 22)
|
61
|
-
end++;
|
62
|
-
if ((uintptr_t)(end - str) > 21) /* too large for a number */
|
63
|
-
return 0;
|
64
|
-
|
65
|
-
while (str < end) {
|
66
|
-
result = (result * 10) + (str[0] - '0');
|
67
|
-
str++;
|
68
|
-
}
|
69
|
-
}
|
70
|
-
finish:
|
71
|
-
if (invert)
|
72
|
-
result = 0 - result;
|
73
|
-
*pstr = str;
|
74
|
-
return (int64_t)result;
|
75
|
-
}
|
76
|
-
|
77
|
-
/** A helper function that convers between String data to a signed double. */
|
78
|
-
double fio_atof(char **pstr) { return strtold(*pstr, pstr); }
|
79
|
-
|
80
|
-
/* *****************************************************************************
|
81
|
-
String Helpers
|
82
|
-
***************************************************************************** */
|
83
|
-
|
84
|
-
/**
|
85
|
-
* A helper function that convers between a signed int64_t to a string.
|
86
|
-
*
|
87
|
-
* No overflow guard is provided, make sure there's at least 66 bytes
|
88
|
-
* available (for base 2).
|
89
|
-
*
|
90
|
-
* Supports base 2, base 10 and base 16. An unsupported base will silently
|
91
|
-
* default to base 10. Prefixes aren't added (i.e., no "0x" or "0b" at the
|
92
|
-
* beginning of the string).
|
93
|
-
*
|
94
|
-
* Returns the number of bytes actually written (excluding the NUL
|
95
|
-
* terminator).
|
96
|
-
*/
|
97
|
-
size_t fio_ltoa(char *dest, int64_t num, uint8_t base) {
|
98
|
-
if (!num) {
|
99
|
-
*(dest++) = '0';
|
100
|
-
*(dest++) = 0;
|
101
|
-
return 1;
|
102
|
-
}
|
103
|
-
|
104
|
-
size_t len = 0;
|
105
|
-
|
106
|
-
if (base == 2) {
|
107
|
-
uint64_t n = num; /* avoid bit shifting inconsistencies with signed bit */
|
108
|
-
uint8_t i = 0; /* counting bits */
|
109
|
-
|
110
|
-
while ((i < 64) && (n & 0x8000000000000000) == 0) {
|
111
|
-
n = n << 1;
|
112
|
-
i++;
|
113
|
-
}
|
114
|
-
/* make sure the Binary representation doesn't appear signed. */
|
115
|
-
if (i) {
|
116
|
-
dest[len++] = '0';
|
117
|
-
}
|
118
|
-
/* write to dest. */
|
119
|
-
while (i < 64) {
|
120
|
-
dest[len++] = ((n & 0x8000000000000000) ? '1' : '0');
|
121
|
-
n = n << 1;
|
122
|
-
i++;
|
123
|
-
}
|
124
|
-
dest[len] = 0;
|
125
|
-
return len;
|
126
|
-
|
127
|
-
} else if (base == 16) {
|
128
|
-
uint64_t n = num; /* avoid bit shifting inconsistencies with signed bit */
|
129
|
-
uint8_t i = 0; /* counting bytes */
|
130
|
-
uint8_t tmp = 0;
|
131
|
-
while (i < 8 && (n & 0xFF00000000000000) == 0) {
|
132
|
-
n = n << 8;
|
133
|
-
i++;
|
134
|
-
}
|
135
|
-
/* make sure the Hex representation doesn't appear signed. */
|
136
|
-
if (i && (n & 0x8000000000000000)) {
|
137
|
-
dest[len++] = '0';
|
138
|
-
dest[len++] = '0';
|
139
|
-
}
|
140
|
-
/* write the damn thing */
|
141
|
-
while (i < 8) {
|
142
|
-
tmp = (n & 0xF000000000000000) >> 60;
|
143
|
-
dest[len++] = hex_notation[tmp];
|
144
|
-
tmp = (n & 0x0F00000000000000) >> 56;
|
145
|
-
dest[len++] = hex_notation[tmp];
|
146
|
-
i++;
|
147
|
-
n = n << 8;
|
148
|
-
}
|
149
|
-
dest[len] = 0;
|
150
|
-
return len;
|
151
|
-
}
|
152
|
-
|
153
|
-
/* fallback to base 10 */
|
154
|
-
uint64_t rem = 0;
|
155
|
-
uint64_t factor = 1;
|
156
|
-
if (num < 0) {
|
157
|
-
dest[len++] = '-';
|
158
|
-
num = 0 - num;
|
159
|
-
}
|
160
|
-
|
161
|
-
while (num / factor)
|
162
|
-
factor *= 10;
|
163
|
-
|
164
|
-
while (factor > 1) {
|
165
|
-
factor = factor / 10;
|
166
|
-
rem = (rem * 10);
|
167
|
-
dest[len++] = '0' + ((num / factor) - rem);
|
168
|
-
rem += ((num / factor) - rem);
|
169
|
-
}
|
170
|
-
dest[len] = 0;
|
171
|
-
return len;
|
172
|
-
}
|
173
|
-
|
174
|
-
/**
|
175
|
-
* A helper function that convers between a double to a string.
|
176
|
-
*
|
177
|
-
* No overflow guard is provided, make sure there's at least 130 bytes
|
178
|
-
* available (for base 2).
|
179
|
-
*
|
180
|
-
* Supports base 2, base 10 and base 16. An unsupported base will silently
|
181
|
-
* default to base 10. Prefixes aren't added (i.e., no "0x" or "0b" at the
|
182
|
-
* beginning of the string).
|
183
|
-
*
|
184
|
-
* Returns the number of bytes actually written (excluding the NUL
|
185
|
-
* terminator).
|
186
|
-
*/
|
187
|
-
size_t fio_ftoa(char *dest, double num, uint8_t base) {
|
188
|
-
if (base == 2 || base == 16) {
|
189
|
-
/* handle the binary / Hex representation the same as if it were an
|
190
|
-
* int64_t
|
191
|
-
*/
|
192
|
-
int64_t *i = (void *)#
|
193
|
-
return fio_ltoa(dest, *i, base);
|
194
|
-
}
|
195
|
-
|
196
|
-
size_t written = sprintf(dest, "%g", num);
|
197
|
-
uint8_t need_zero = 1;
|
198
|
-
char *start = dest;
|
199
|
-
while (*start) {
|
200
|
-
if (*start == ',') // locale issues?
|
201
|
-
*start = '.';
|
202
|
-
if (*start == '.' || *start == 'e') {
|
203
|
-
need_zero = 0;
|
204
|
-
break;
|
205
|
-
}
|
206
|
-
start++;
|
207
|
-
}
|
208
|
-
if (need_zero) {
|
209
|
-
dest[written++] = '.';
|
210
|
-
dest[written++] = '0';
|
211
|
-
}
|
212
|
-
return written;
|
213
|
-
}
|