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.

Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +61 -33
  3. data/README.md +7 -5
  4. data/ext/iodine/base64.c +12 -0
  5. data/ext/iodine/defer.c +211 -108
  6. data/ext/iodine/defer.h +7 -0
  7. data/ext/iodine/facil.c +5 -1
  8. data/ext/iodine/facil.h +1 -1
  9. data/ext/iodine/fio2resp.c +19 -30
  10. data/ext/iodine/fio2resp.h +2 -1
  11. data/ext/iodine/fio_cli_helper.c +2 -2
  12. data/ext/iodine/fiobj.h +11 -624
  13. data/ext/iodine/fiobj_ary.c +65 -26
  14. data/ext/iodine/fiobj_ary.h +106 -0
  15. data/ext/iodine/fiobj_hash.c +175 -115
  16. data/ext/iodine/fiobj_hash.h +128 -0
  17. data/ext/iodine/fiobj_internal.c +189 -0
  18. data/ext/iodine/{fiobj_types.h → fiobj_internal.h} +126 -136
  19. data/ext/iodine/fiobj_json.c +161 -207
  20. data/ext/iodine/fiobj_json.h +43 -0
  21. data/ext/iodine/fiobj_numbers.c +53 -35
  22. data/ext/iodine/fiobj_numbers.h +49 -0
  23. data/ext/iodine/fiobj_primitives.c +103 -70
  24. data/ext/iodine/fiobj_primitives.h +55 -0
  25. data/ext/iodine/fiobj_str.c +171 -59
  26. data/ext/iodine/fiobj_str.h +113 -0
  27. data/ext/iodine/fiobj_sym.c +46 -124
  28. data/ext/iodine/fiobj_sym.h +60 -0
  29. data/ext/iodine/fiobject.c +589 -0
  30. data/ext/iodine/fiobject.h +276 -0
  31. data/ext/iodine/pubsub.h +1 -1
  32. data/ext/iodine/resp.c +2 -2
  33. data/ext/iodine/siphash.c +11 -0
  34. data/ext/iodine/spnlock.inc +7 -5
  35. data/ext/iodine/websocket_parser.h +44 -7
  36. data/lib/iodine/version.rb +1 -1
  37. metadata +13 -8
  38. data/ext/iodine/fiobj_alloc.c +0 -81
  39. data/ext/iodine/fiobj_generic.c +0 -260
  40. data/ext/iodine/fiobj_io.c +0 -58
  41. data/ext/iodine/fiobj_misc.c +0 -213
  42. data/ext/iodine/fiobj_tests.c +0 -474
@@ -0,0 +1,128 @@
1
+ #ifndef H_FIOBJ_HASH_H
2
+ #define H_FIOBJ_HASH_H
3
+ /*
4
+ Copyright: Boaz Segev, 2017
5
+ License: MIT
6
+ */
7
+
8
+ #include "fiobj_str.h"
9
+ #include "fiobj_sym.h"
10
+
11
+ #ifdef __cplusplus
12
+ extern "C" {
13
+ #endif
14
+
15
+ /* MUST be a power of 2 */
16
+ #define HASH_INITIAL_CAPACITY 16
17
+
18
+ #include <errno.h>
19
+
20
+ /** attempts to rehash the hashmap. */
21
+ void fiobj_hash_rehash(fiobj_s *h);
22
+
23
+ /* *****************************************************************************
24
+ Couplets API - the Key-Value pair, created by the Hash object
25
+ ***************************************************************************** */
26
+
27
+ /** Couplet type identifier. */
28
+ extern const uintptr_t FIOBJ_T_COUPLET;
29
+
30
+ /**
31
+ * If object is a Hash couplet (occurs in `fiobj_each2`), returns the key
32
+ * (Symbol) from the key-value pair.
33
+ *
34
+ * Otherwise returns NULL.
35
+ */
36
+ fiobj_s *fiobj_couplet2key(const fiobj_s *obj);
37
+
38
+ /**
39
+ * If object is a Hash couplet (occurs in `fiobj_each2`), returns the object
40
+ * (the value) from the key-value pair.
41
+ *
42
+ * Otherwise returns NULL.
43
+ */
44
+ fiobj_s *fiobj_couplet2obj(const fiobj_s *obj);
45
+
46
+ /* *****************************************************************************
47
+ Hash API
48
+ ***************************************************************************** */
49
+
50
+ /** Hash type identifier.
51
+
52
+ The facil.io Hash object is, by default, an insecure (non-collision resistant)
53
+ ordered Hash Table implementation.
54
+
55
+ By being non-collision resistant (comparing only the Hash data), memory
56
+ comparison can be avoided and performance increased.
57
+
58
+ By being ordered it's possible to iterate over key-value pairs in the order in
59
+ which they were added to the Hash table, making it possible to output JSON in a
60
+ controlled manner.
61
+ */
62
+ extern const uintptr_t FIOBJ_T_HASH;
63
+
64
+ /**
65
+ * Creates a mutable empty Hash object. Use `fiobj_free` when done.
66
+ *
67
+ * Notice that these Hash objects are optimized for smaller collections and
68
+ * retain order of object insertion.
69
+ */
70
+ fiobj_s *fiobj_hash_new(void);
71
+
72
+ /** Returns the number of elements in the Hash. */
73
+ size_t fiobj_hash_count(const fiobj_s *hash);
74
+
75
+ /**
76
+ * Sets a key-value pair in the Hash, duplicating the Symbol and **moving**
77
+ * the ownership of the object to the Hash.
78
+ *
79
+ * Returns -1 on error.
80
+ */
81
+ int fiobj_hash_set(fiobj_s *hash, fiobj_s *sym, fiobj_s *obj);
82
+
83
+ /**
84
+ * Removes a key-value pair from the Hash, if it exists, returning the old
85
+ * object (instead of freeing it).
86
+ */
87
+ fiobj_s *fiobj_hash_remove(fiobj_s *hash, fiobj_s *sym);
88
+
89
+ /**
90
+ * Deletes a key-value pair from the Hash, if it exists, freeing the
91
+ * associated object.
92
+ *
93
+ * Returns -1 on type error or if the object never existed.
94
+ */
95
+ int fiobj_hash_delete(fiobj_s *hash, fiobj_s *sym);
96
+
97
+ /**
98
+ * Returns a temporary handle to the object associated with the Symbol, NULL
99
+ * if none.
100
+ */
101
+ fiobj_s *fiobj_hash_get(const fiobj_s *hash, fiobj_s *sym);
102
+
103
+ /**
104
+ * Returns a temporary handle to the object associated with the Symbol C string.
105
+ *
106
+ * This function takes a C string instead of a Symbol, which is slower if a
107
+ * Symbol can be cached but faster if a Symbol must be created.
108
+ *
109
+ * Returns NULL if no object is asociated with this String data.
110
+ */
111
+ fiobj_s *fiobj_hash_get2(const fiobj_s *hash, const char *str, size_t len);
112
+
113
+ /**
114
+ * Returns 1 if the key (Symbol) exists in the Hash, even if it's value is NULL.
115
+ */
116
+ int fiobj_hash_haskey(const fiobj_s *hash, fiobj_s *sym);
117
+
118
+ /**
119
+ * Returns a temporary theoretical Hash map capacity.
120
+ * This could be used for testig performance and memory consumption.
121
+ */
122
+ size_t fiobj_hash_capa(const fiobj_s *hash);
123
+
124
+ #ifdef __cplusplus
125
+ } /* extern "C" */
126
+ #endif
127
+
128
+ #endif
@@ -0,0 +1,189 @@
1
+ /*
2
+ Copyright: Boaz Segev, 2017
3
+ License: MIT
4
+ */
5
+ #include "fiobj_internal.h"
6
+
7
+ #include <errno.h>
8
+ #include <math.h>
9
+ #include <signal.h>
10
+ #include <stdarg.h>
11
+ #include <stdio.h>
12
+ #include <stdlib.h>
13
+ #include <string.h>
14
+ #include <sys/types.h>
15
+
16
+ /* *****************************************************************************
17
+ Internal API required across the board
18
+ ***************************************************************************** */
19
+
20
+ void fiobj_simple_dealloc(fiobj_s *o) { fiobj_dealloc(o); }
21
+
22
+ void fiobj_noop_free(fiobj_s *obj) { OBJ2HEAD(obj)->ref = (uintptr_t)-1; }
23
+
24
+ int fiobj_noop_true(const fiobj_s *obj) {
25
+ return 1;
26
+ (void)obj;
27
+ }
28
+ int fiobj_noop_false(const fiobj_s *obj) {
29
+ return 0;
30
+ (void)obj;
31
+ }
32
+ fio_cstr_s fiobj_noop_str(const fiobj_s *obj) {
33
+ return (fio_cstr_s){.length = 0, .data = ""};
34
+ (void)obj;
35
+ }
36
+ int64_t fiobj_noop_i(const fiobj_s *obj) {
37
+ return 0;
38
+ (void)obj;
39
+ }
40
+ double fiobj_noop_f(const fiobj_s *obj) {
41
+ return 0;
42
+ (void)obj;
43
+ }
44
+
45
+ /** always 0. */
46
+ int fiobj_noop_is_eq(const fiobj_s *self, const fiobj_s *other) {
47
+ return 0;
48
+ (void)self;
49
+ (void)other;
50
+ }
51
+
52
+ size_t fiobj_noop_count(const fiobj_s *obj) {
53
+ return 0;
54
+ (void)obj;
55
+ }
56
+ fiobj_s *fiobj_noop_unwrap(const fiobj_s *obj) {
57
+ return (fiobj_s *)obj;
58
+ (void)obj;
59
+ }
60
+ size_t fiobj_noop_each1(fiobj_s *obj, size_t start_at,
61
+ int (*task)(fiobj_s *obj, void *arg), void *arg) {
62
+ return 0;
63
+ (void)obj;
64
+ (void)start_at;
65
+ (void)task;
66
+ (void)arg;
67
+ }
68
+
69
+ /* *****************************************************************************
70
+ Invalid Object VTable - unused, still considering...
71
+ ***************************************************************************** */
72
+
73
+ // static void fiobj_noop_free_invalid(fiobj_s *obj) { (void)obj; }
74
+ // static int64_t fiobj_noop_i_invalid(const fiobj_s *obj) {
75
+ // return ((int64_t)(obj) ^ 3);
76
+ // }
77
+ // struct fiobj_vtable_s FIOBJ_VTABLE_INVALID = {
78
+ // .name = "Invalid Class - not a facil.io Object",
79
+ // .free = fiobj_noop_free_invalid,
80
+ // .is_true = fiobj_noop_false,
81
+ // .to_str = fiobj_noop_str,
82
+ // .to_i = fiobj_noop_i_invalid,
83
+ // .to_f = fiobj_noop_f,
84
+ // .is_eq = fiobj_noop_is_eq,
85
+ // .count = fiobj_noop_count,
86
+ // .unwrap = fiobj_noop_unwrap,
87
+ // .each1 = fiobj_noop_each1,
88
+ // };
89
+
90
+ /* *****************************************************************************
91
+ Internal API required across the board
92
+ ***************************************************************************** */
93
+
94
+ /* *****************************************************************************
95
+ Hashing (SipHash copy)
96
+ ***************************************************************************** */
97
+
98
+ #if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) && \
99
+ __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
100
+ /* the algorithm was designed as little endian... so, byte swap 64 bit. */
101
+ #define sip_local64(i) \
102
+ (((i)&0xFFULL) << 56) | (((i)&0xFF00ULL) << 40) | \
103
+ (((i)&0xFF0000ULL) << 24) | (((i)&0xFF000000ULL) << 8) | \
104
+ (((i)&0xFF00000000ULL) >> 8) | (((i)&0xFF0000000000ULL) >> 24) | \
105
+ (((i)&0xFF000000000000ULL) >> 40) | (((i)&0xFF00000000000000ULL) >> 56)
106
+ #else
107
+ /* no need */
108
+ #define sip_local64(i) (i)
109
+ #endif
110
+
111
+ /* 64Bit left rotation, inlined. */
112
+ #define lrot64(i, bits) \
113
+ (((uint64_t)(i) << (bits)) | ((uint64_t)(i) >> (64 - (bits))))
114
+
115
+ uint64_t fiobj_sym_hash(const void *data, size_t len) {
116
+ /* initialize the 4 words */
117
+ uint64_t v0 = (0x0706050403020100ULL ^ 0x736f6d6570736575ULL);
118
+ uint64_t v1 = (0x0f0e0d0c0b0a0908ULL ^ 0x646f72616e646f6dULL);
119
+ uint64_t v2 = (0x0706050403020100ULL ^ 0x6c7967656e657261ULL);
120
+ uint64_t v3 = (0x0f0e0d0c0b0a0908ULL ^ 0x7465646279746573ULL);
121
+ const uint64_t *w64 = data;
122
+ uint8_t len_mod = len & 255;
123
+ union {
124
+ uint64_t i;
125
+ uint8_t str[8];
126
+ } word;
127
+
128
+ #define hash_map_SipRound \
129
+ do { \
130
+ v2 += v3; \
131
+ v3 = lrot64(v3, 16) ^ v2; \
132
+ v0 += v1; \
133
+ v1 = lrot64(v1, 13) ^ v0; \
134
+ v0 = lrot64(v0, 32); \
135
+ v2 += v1; \
136
+ v0 += v3; \
137
+ v1 = lrot64(v1, 17) ^ v2; \
138
+ v3 = lrot64(v3, 21) ^ v0; \
139
+ v2 = lrot64(v2, 32); \
140
+ } while (0);
141
+
142
+ while (len >= 8) {
143
+ word.i = sip_local64(*w64);
144
+ v3 ^= word.i;
145
+ /* Sip Rounds */
146
+ hash_map_SipRound;
147
+ hash_map_SipRound;
148
+ v0 ^= word.i;
149
+ w64 += 1;
150
+ len -= 8;
151
+ }
152
+ word.i = 0;
153
+ uint8_t *pos = word.str;
154
+ uint8_t *w8 = (void *)w64;
155
+ switch (len) { /* fallthrough is intentional */
156
+ case 7:
157
+ pos[6] = w8[6];
158
+ case 6:
159
+ pos[5] = w8[5];
160
+ case 5:
161
+ pos[4] = w8[4];
162
+ case 4:
163
+ pos[3] = w8[3];
164
+ case 3:
165
+ pos[2] = w8[2];
166
+ case 2:
167
+ pos[1] = w8[1];
168
+ case 1:
169
+ pos[0] = w8[0];
170
+ }
171
+ word.str[7] = len_mod;
172
+
173
+ /* last round */
174
+ v3 ^= word.i;
175
+ hash_map_SipRound;
176
+ hash_map_SipRound;
177
+ v0 ^= word.i;
178
+ /* Finalization */
179
+ v2 ^= 0xff;
180
+ /* d iterations of SipRound */
181
+ hash_map_SipRound;
182
+ hash_map_SipRound;
183
+ hash_map_SipRound;
184
+ hash_map_SipRound;
185
+ /* XOR it all together */
186
+ v0 ^= v1 ^ v2 ^ v3;
187
+ #undef hash_map_SipRound
188
+ return v0;
189
+ }
@@ -1,23 +1,27 @@
1
+ #ifndef FIOBJECT_INTERNAL_H
1
2
  /*
2
- Copyright: Boaz segev, 2017
3
+ Copyright: Boaz Segev, 2017
3
4
  License: MIT
4
-
5
- Feel free to copy, use and enjoy according to the license provided.
6
5
  */
7
6
 
8
- #ifndef H_FIOBJ_TYPES_INTERNAL_H
9
- #define H_FIOBJ_TYPES_INTERNAL_H
7
+ /**
8
+ This header includes all the internal rescources / data and types required to
9
+ create object types.
10
+ */
11
+ #define FIOBJECT_INTERNAL_H
10
12
 
11
13
  #ifndef _GNU_SOURCE
12
14
  #define _GNU_SOURCE
13
15
  #endif
14
16
 
15
- #include "fiobj.h"
17
+ #include "fiobject.h"
16
18
 
17
19
  #include <errno.h>
18
20
  #include <math.h>
19
21
  #include <signal.h>
20
22
  #include <stdarg.h>
23
+ #include <stdio.h>
24
+ #include <stdlib.h>
21
25
  #include <string.h>
22
26
  #include <sys/types.h>
23
27
 
@@ -25,17 +29,18 @@ Feel free to copy, use and enjoy according to the license provided.
25
29
  Atomic add / subtract
26
30
  ***************************************************************************** */
27
31
 
28
- /* Select the correct compiler builtin method. */
29
- #if defined(__has_builtin)
30
-
31
- #if __has_builtin(__atomic_exchange_n)
32
+ /* C11 Atomics are defined? */
33
+ #if defined(__ATOMIC_RELAXED)
32
34
  #define SPN_LOCK_BUILTIN(...) __atomic_exchange_n(__VA_ARGS__, __ATOMIC_ACQ_REL)
33
35
  /** An atomic addition operation */
34
36
  #define spn_add(...) __atomic_add_fetch(__VA_ARGS__, __ATOMIC_ACQ_REL)
35
37
  /** An atomic subtraction operation */
36
38
  #define spn_sub(...) __atomic_sub_fetch(__VA_ARGS__, __ATOMIC_ACQ_REL)
37
39
 
38
- #elif __has_builtin(__sync_fetch_and_or)
40
+ /* Select the correct compiler builtin method. */
41
+ #elif defined(__has_builtin)
42
+
43
+ #if __has_builtin(__sync_fetch_and_or)
39
44
  #define SPN_LOCK_BUILTIN(...) __sync_fetch_and_or(__VA_ARGS__)
40
45
  /** An atomic addition operation */
41
46
  #define spn_add(...) __sync_add_and_fetch(__VA_ARGS__)
@@ -64,7 +69,7 @@ Simple List - Used for fiobj_s * objects, but can be used for anything really.
64
69
  typedef struct fio_ls_s {
65
70
  struct fio_ls_s *prev;
66
71
  struct fio_ls_s *next;
67
- fiobj_s *obj;
72
+ const fiobj_s *obj;
68
73
  } fio_ls_s;
69
74
 
70
75
  #define FIO_LS_INIT(name) \
@@ -72,7 +77,7 @@ typedef struct fio_ls_s {
72
77
 
73
78
  /** Adds an object to the list's head. */
74
79
  static inline __attribute__((unused)) void fio_ls_push(fio_ls_s *pos,
75
- fiobj_s *obj) {
80
+ const fiobj_s *obj) {
76
81
  /* prepare item */
77
82
  fio_ls_s *item = (fio_ls_s *)malloc(sizeof(*item));
78
83
  if (!item)
@@ -85,7 +90,7 @@ static inline __attribute__((unused)) void fio_ls_push(fio_ls_s *pos,
85
90
 
86
91
  /** Adds an object to the list's tail. */
87
92
  static inline __attribute__((unused)) void fio_ls_unshift(fio_ls_s *pos,
88
- fiobj_s *obj) {
93
+ const fiobj_s *obj) {
89
94
  pos = pos->prev;
90
95
  fio_ls_push(pos, obj);
91
96
  }
@@ -95,11 +100,11 @@ static inline __attribute__((unused)) fiobj_s *fio_ls_pop(fio_ls_s *list) {
95
100
  if (list->next == list)
96
101
  return NULL;
97
102
  fio_ls_s *item = list->next;
98
- fiobj_s *ret = item->obj;
103
+ const fiobj_s *ret = item->obj;
99
104
  list->next = item->next;
100
105
  list->next->prev = list;
101
106
  free(item);
102
- return ret;
107
+ return (fiobj_s *)ret;
103
108
  }
104
109
 
105
110
  /** Removes an object from the list's tail. */
@@ -107,20 +112,20 @@ static inline __attribute__((unused)) fiobj_s *fio_ls_shift(fio_ls_s *list) {
107
112
  if (list->prev == list)
108
113
  return NULL;
109
114
  fio_ls_s *item = list->prev;
110
- fiobj_s *ret = item->obj;
115
+ const fiobj_s *ret = item->obj;
111
116
  list->prev = item->prev;
112
117
  list->prev->next = list;
113
118
  free(item);
114
- return ret;
119
+ return (fiobj_s *)ret;
115
120
  }
116
121
 
117
122
  /** Removes an object from the containing node. */
118
123
  static inline __attribute__((unused)) fiobj_s *fio_ls_remove(fio_ls_s *node) {
119
- fiobj_s *ret = node->obj;
124
+ const fiobj_s *ret = node->obj;
120
125
  node->next->prev = node->prev->next;
121
126
  node->prev->next = node->next->prev;
122
127
  free(node);
123
- return ret;
128
+ return (fiobj_s *)ret;
124
129
  }
125
130
 
126
131
  /* *****************************************************************************
@@ -145,146 +150,131 @@ size_t __attribute__((weak)) fiobj_memory_page_size(void) {
145
150
  #define fiobj_memory_page_size() 4096
146
151
 
147
152
  #endif
148
- /* *****************************************************************************
149
- Object types
150
- ***************************************************************************** */
151
-
152
- /* Number */
153
- typedef struct {
154
- fiobj_type_en type;
155
- int64_t i;
156
- } fio_num_s;
157
-
158
- /* Float */
159
- typedef struct {
160
- fiobj_type_en type;
161
- double f;
162
- } fio_float_s;
163
-
164
- /* String */
165
- typedef struct {
166
- fiobj_type_en type;
167
- uint64_t capa;
168
- uint64_t len;
169
- uint8_t is_static;
170
- char *str;
171
- } fio_str_s;
172
-
173
- /* Symbol */
174
- typedef struct {
175
- fiobj_type_en type;
176
- uintptr_t hash;
177
- uint64_t len;
178
- char str[];
179
- } fio_sym_s;
180
-
181
- /* IO */
182
- typedef struct {
183
- fiobj_type_en type;
184
- intptr_t fd;
185
- } fio_io_s;
186
-
187
- /* Array */
188
- typedef struct {
189
- fiobj_type_en type;
190
- uint64_t start;
191
- uint64_t end;
192
- uint64_t capa;
193
- fiobj_s **arry;
194
- } fio_ary_s;
195
-
196
- /* *****************************************************************************
197
- Hash types
198
- ***************************************************************************** */
199
- /* MUST be a power of 2 */
200
- #define FIOBJ_HASH_MAX_MAP_SEEK (256)
201
-
202
- typedef struct {
203
- uintptr_t hash;
204
- fio_ls_s *container;
205
- } map_info_s;
206
-
207
- typedef struct {
208
- uintptr_t capa;
209
- map_info_s *data;
210
- } fio_map_s;
211
-
212
- typedef struct {
213
- fiobj_type_en type;
214
- uintptr_t count;
215
- uintptr_t mask;
216
- fio_ls_s items;
217
- fio_map_s map;
218
- } fio_hash_s;
219
-
220
- /* Hash node */
221
- typedef struct {
222
- fiobj_type_en type;
223
- fiobj_s *name;
224
- fiobj_s *obj;
225
- } fio_couplet_s;
226
-
227
- void fiobj_hash_rehash(fiobj_s *h);
228
153
 
229
154
  /* *****************************************************************************
230
155
  Type VTable (virtual function table)
231
156
  ***************************************************************************** */
157
+
158
+ /**
159
+ * Each type must define a complete virtual function table and point to the
160
+ * table from it's topmost element in it's `struct`.
161
+ */
232
162
  struct fiobj_vtable_s {
233
- /* deallocate an object */
234
- void (*free)(fiobj_s *);
235
- /* object value as String */
236
- fio_cstr_s (*to_str)(fiobj_s *);
237
- /* object value as Integer */
238
- int64_t (*to_i)(fiobj_s *);
239
- /* object value as Float */
240
- double (*to_f)(fiobj_s *);
241
- /* true if object is equal. nested objects must be ignored (test container) */
242
- int (*is_eq)(fiobj_s *self, fiobj_s *other);
243
- /* return the number of nested object */
244
- size_t (*count)(fiobj_s *);
245
- /* perform a task for the object's children (-1 stops iteration)
163
+ /** class name as a C string */
164
+ const char *name;
165
+ /** deallocate an object - should deallocate parent only
166
+ *
167
+ * Note that nested objects, such as contained by Arrays and Hash maps, are
168
+ * handled using `each1` and handled accoring to their reference count.
169
+ */
170
+ void (*const free)(fiobj_s *);
171
+ /** object should evaluate as true/false? */
172
+ int (*const is_true)(const fiobj_s *);
173
+ /** object value as String */
174
+ fio_cstr_s (*const to_str)(const fiobj_s *);
175
+ /** object value as Integer */
176
+ int64_t (*const to_i)(const fiobj_s *);
177
+ /** object value as Float */
178
+ double (*const to_f)(const fiobj_s *);
179
+ /**
180
+ * returns 1 if objects are equal, 0 if unequal.
181
+ *
182
+ * `self` and `other` are never NULL.
183
+ *
184
+ * objects that enumerate (`count > 0`) should only test
185
+ * themselves (not their children). any nested objects will be tested
186
+ * seperately.
187
+ *
188
+ * wrapping objects should forward the function call to the wrapped objectd
189
+ * (similar to `count` and `each1`) after completing any internal testing.
190
+ */
191
+ int (*const is_eq)(const fiobj_s *self, const fiobj_s *other);
192
+ /**
193
+ * return the number of nested object
194
+ *
195
+ * wrapping objects should forward the function call to the wrapped objectd
196
+ * (similar to `each1`).
197
+ */
198
+ size_t (*const count)(const fiobj_s *o);
199
+ /**
200
+ * return either `self` or a wrapped object.
201
+ * (if object wrapping exists, i.e. Hash couplet, return nested object)
202
+ */
203
+ fiobj_s *(*const unwrap)(const fiobj_s *obj);
204
+ /**
205
+ * perform a task for the object's children (-1 stops iteration)
246
206
  * returns the number of items processed + `start_at`.
207
+ *
208
+ * wrapping objects should forward the function call to the wrapped objectd
209
+ * (similar to `count`).
247
210
  */
248
- size_t (*each1)(fiobj_s *, size_t start_at,
249
- int (*task)(fiobj_s *obj, void *arg), void *arg);
211
+ size_t (*const each1)(fiobj_s *, size_t start_at,
212
+ int (*task)(fiobj_s *obj, void *arg), void *arg);
250
213
  };
251
214
 
252
- fio_cstr_s fiobj_noop_str(fiobj_s *obj);
253
- int64_t fiobj_noop_i(fiobj_s *obj);
254
- double fiobj_noop_f(fiobj_s *obj);
255
- size_t fiobj_noop_count(fiobj_s *obj);
215
+ // extern struct fiobj_vtable_s FIOBJ_VTABLE_INVALID; // unused just yet
216
+ /* *****************************************************************************
217
+ VTable (virtual function table) common implememntations
218
+ ***************************************************************************** */
219
+
220
+ /** simple deallocation (`free`). */
221
+ void fiobj_simple_dealloc(fiobj_s *o);
222
+ /** no deallocation (eternal objects). */
223
+ void fiobj_noop_free(fiobj_s *obj);
224
+ /** always true. */
225
+ int fiobj_noop_true(const fiobj_s *obj);
226
+ /** always false. */
227
+ int fiobj_noop_false(const fiobj_s *obj);
228
+ /** NULL C string. */
229
+ fio_cstr_s fiobj_noop_str(const fiobj_s *obj);
230
+ /** always 0. */
231
+ int64_t fiobj_noop_i(const fiobj_s *obj);
232
+ /** always 0. */
233
+ double fiobj_noop_f(const fiobj_s *obj);
234
+ /** always 0. */
235
+ size_t fiobj_noop_count(const fiobj_s *obj);
236
+ /** always 0. */
237
+ int fiobj_noop_is_eq(const fiobj_s *self, const fiobj_s *other);
238
+ /** always self. */
239
+ fiobj_s *fiobj_noop_unwrap(const fiobj_s *obj);
240
+ /** always 0. */
256
241
  size_t fiobj_noop_each1(fiobj_s *obj, size_t start_at,
257
242
  int (*task)(fiobj_s *obj, void *arg), void *arg);
258
- void fiobj_simple_dealloc(fiobj_s *o);
259
243
 
260
244
  /* *****************************************************************************
261
245
  The Object type head and management
262
246
  ***************************************************************************** */
263
247
 
264
- typedef struct {
265
- uint64_t ref;
266
- struct fiobj_vtable_s *vtable;
267
- } fiobj_head_s;
248
+ typedef struct { uintptr_t ref; } fiobj_head_s;
268
249
 
269
- #define OBJ2HEAD(o) (((fiobj_head_s *)(o)) - 1)[0]
250
+ #define OBJ2HEAD(o) (((fiobj_head_s *)(o)) - 1)
270
251
  #define HEAD2OBJ(o) ((fiobj_s *)(((fiobj_head_s *)(o)) + 1))
271
252
 
272
- #define OBJREF_ADD(o) spn_add(&OBJ2HEAD((o)).ref, 1)
273
- #define OBJREF_REM(o) spn_sub(&OBJ2HEAD((o)).ref, 1)
253
+ #define OBJREF_ADD(o) spn_add(&(OBJ2HEAD((o))->ref), 1)
254
+ #define OBJREF_REM(o) spn_sub(&(OBJ2HEAD((o))->ref), 1)
255
+
256
+ #define OBJVTBL(o) ((struct fiobj_vtable_s *)(((fiobj_s *)(o))->type))
274
257
 
275
- #define obj2io(o) ((fio_io_s *)(o))
276
- #define obj2ary(o) ((fio_ary_s *)(o))
277
- #define obj2str(o) ((fio_str_s *)(o))
278
- #define obj2sym(o) ((fio_sym_s *)(o))
279
- #define obj2num(o) ((fio_num_s *)(o))
280
- #define obj2hash(o) ((fio_hash_s *)(o))
281
- #define obj2float(o) ((fio_float_s *)(o))
282
- #define obj2couplet(o) ((fio_couplet_s *)(o))
258
+ // #define PTR2OBJ(o) (((o) << 1) | 1)
259
+ // #define OBJ2PTR(o) (((o)&1) ? ((o) >> 1) : (o))
283
260
 
284
261
  /* *****************************************************************************
285
262
  Internal API required across the board
286
263
  ***************************************************************************** */
287
- void fiobj_dealloc(fiobj_s *obj);
264
+
265
+ /** Allocates memory for the fiobj_s's data structure */
266
+ static inline fiobj_s *fiobj_alloc(size_t size) {
267
+ fiobj_head_s *head = (fiobj_head_s *)malloc(size + sizeof(head));
268
+ if (!head)
269
+ return NULL;
270
+ *head = (fiobj_head_s){.ref = 1};
271
+ return HEAD2OBJ(head);
272
+ };
273
+
274
+ /** Deallocates the fiobj_s's data structure. */
275
+ static inline void fiobj_dealloc(fiobj_s *obj) { free(OBJ2HEAD(obj)); }
276
+
277
+ /** The Hashing function used by dynamic facil.io objects. */
288
278
  uint64_t fiobj_sym_hash(const void *data, size_t len);
289
279
 
290
280
  #endif