isomorfeus-iodine 0.7.45 → 0.7.46

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,344 +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
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