rage-iodine 1.7.58
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
- data/.github/workflows/ruby.yml +42 -0
- data/.gitignore +20 -0
- data/.rspec +2 -0
- data/.yardopts +8 -0
- data/CHANGELOG.md +1098 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +21 -0
- data/LIMITS.md +41 -0
- data/README.md +782 -0
- data/Rakefile +23 -0
- data/SPEC-PubSub-Draft.md +159 -0
- data/SPEC-WebSocket-Draft.md +239 -0
- data/bin/console +22 -0
- data/bin/info.md +353 -0
- data/bin/mustache_bench.rb +100 -0
- data/bin/poc/Gemfile.lock +23 -0
- data/bin/poc/README.md +37 -0
- data/bin/poc/config.ru +66 -0
- data/bin/poc/gemfile +1 -0
- data/bin/poc/www/index.html +57 -0
- data/examples/async_task.ru +92 -0
- data/examples/bates/README.md +3 -0
- data/examples/bates/config.ru +342 -0
- data/examples/bates/david+bold.pdf +0 -0
- data/examples/bates/public/drop-pdf.png +0 -0
- data/examples/bates/public/index.html +600 -0
- data/examples/config.ru +59 -0
- data/examples/echo.ru +59 -0
- data/examples/etag.ru +16 -0
- data/examples/hello.ru +29 -0
- data/examples/pubsub_engine.ru +81 -0
- data/examples/rack3.ru +12 -0
- data/examples/redis.ru +70 -0
- data/examples/shootout.ru +73 -0
- data/examples/sub-protocols.ru +90 -0
- data/examples/tcp_client.rb +66 -0
- data/examples/x-sendfile.ru +14 -0
- data/exe/iodine +280 -0
- data/ext/iodine/extconf.rb +110 -0
- data/ext/iodine/fio.c +12096 -0
- data/ext/iodine/fio.h +6390 -0
- data/ext/iodine/fio_cli.c +431 -0
- data/ext/iodine/fio_cli.h +189 -0
- data/ext/iodine/fio_json_parser.h +687 -0
- data/ext/iodine/fio_siphash.c +157 -0
- data/ext/iodine/fio_siphash.h +37 -0
- data/ext/iodine/fio_tls.h +129 -0
- data/ext/iodine/fio_tls_missing.c +649 -0
- data/ext/iodine/fio_tls_openssl.c +1056 -0
- data/ext/iodine/fio_tmpfile.h +50 -0
- data/ext/iodine/fiobj.h +44 -0
- data/ext/iodine/fiobj4fio.h +21 -0
- data/ext/iodine/fiobj_ary.c +333 -0
- data/ext/iodine/fiobj_ary.h +139 -0
- data/ext/iodine/fiobj_data.c +1185 -0
- data/ext/iodine/fiobj_data.h +167 -0
- data/ext/iodine/fiobj_hash.c +409 -0
- data/ext/iodine/fiobj_hash.h +176 -0
- data/ext/iodine/fiobj_json.c +622 -0
- data/ext/iodine/fiobj_json.h +68 -0
- data/ext/iodine/fiobj_mem.h +71 -0
- data/ext/iodine/fiobj_mustache.c +317 -0
- data/ext/iodine/fiobj_mustache.h +62 -0
- data/ext/iodine/fiobj_numbers.c +344 -0
- data/ext/iodine/fiobj_numbers.h +127 -0
- data/ext/iodine/fiobj_str.c +433 -0
- data/ext/iodine/fiobj_str.h +172 -0
- data/ext/iodine/fiobject.c +620 -0
- data/ext/iodine/fiobject.h +654 -0
- data/ext/iodine/hpack.h +1923 -0
- data/ext/iodine/http.c +2736 -0
- data/ext/iodine/http.h +1019 -0
- data/ext/iodine/http1.c +825 -0
- data/ext/iodine/http1.h +29 -0
- data/ext/iodine/http1_parser.h +1835 -0
- data/ext/iodine/http_internal.c +1279 -0
- data/ext/iodine/http_internal.h +248 -0
- data/ext/iodine/http_mime_parser.h +350 -0
- data/ext/iodine/iodine.c +1433 -0
- data/ext/iodine/iodine.h +64 -0
- data/ext/iodine/iodine_caller.c +218 -0
- data/ext/iodine/iodine_caller.h +27 -0
- data/ext/iodine/iodine_connection.c +941 -0
- data/ext/iodine/iodine_connection.h +55 -0
- data/ext/iodine/iodine_defer.c +420 -0
- data/ext/iodine/iodine_defer.h +6 -0
- data/ext/iodine/iodine_fiobj2rb.h +120 -0
- data/ext/iodine/iodine_helpers.c +282 -0
- data/ext/iodine/iodine_helpers.h +12 -0
- data/ext/iodine/iodine_http.c +1280 -0
- data/ext/iodine/iodine_http.h +23 -0
- data/ext/iodine/iodine_json.c +302 -0
- data/ext/iodine/iodine_json.h +6 -0
- data/ext/iodine/iodine_mustache.c +567 -0
- data/ext/iodine/iodine_mustache.h +6 -0
- data/ext/iodine/iodine_pubsub.c +580 -0
- data/ext/iodine/iodine_pubsub.h +26 -0
- data/ext/iodine/iodine_rack_io.c +273 -0
- data/ext/iodine/iodine_rack_io.h +20 -0
- data/ext/iodine/iodine_store.c +142 -0
- data/ext/iodine/iodine_store.h +20 -0
- data/ext/iodine/iodine_tcp.c +346 -0
- data/ext/iodine/iodine_tcp.h +13 -0
- data/ext/iodine/iodine_tls.c +261 -0
- data/ext/iodine/iodine_tls.h +13 -0
- data/ext/iodine/mustache_parser.h +1546 -0
- data/ext/iodine/redis_engine.c +957 -0
- data/ext/iodine/redis_engine.h +79 -0
- data/ext/iodine/resp_parser.h +317 -0
- data/ext/iodine/scheduler.c +173 -0
- data/ext/iodine/scheduler.h +6 -0
- data/ext/iodine/websocket_parser.h +506 -0
- data/ext/iodine/websockets.c +752 -0
- data/ext/iodine/websockets.h +185 -0
- data/iodine.gemspec +50 -0
- data/lib/iodine/connection.rb +61 -0
- data/lib/iodine/json.rb +42 -0
- data/lib/iodine/mustache.rb +113 -0
- data/lib/iodine/pubsub.rb +55 -0
- data/lib/iodine/rack_utils.rb +43 -0
- data/lib/iodine/tls.rb +16 -0
- data/lib/iodine/version.rb +3 -0
- data/lib/iodine.rb +274 -0
- data/lib/rack/handler/iodine.rb +33 -0
- data/logo.png +0 -0
- 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
|