iodine 0.4.14 → 0.4.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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
@@ -1,11 +1,23 @@
1
1
  /*
2
- Copyright: Boaz segev, 2017
2
+ Copyright: Boaz Segev, 2017
3
3
  License: MIT
4
-
5
- Feel free to copy, use and enjoy according to the license provided.
6
4
  */
7
5
 
8
- #include "fiobj_types.h"
6
+ #include "fiobj_internal.h"
7
+
8
+ /* *****************************************************************************
9
+ Array Type
10
+ ***************************************************************************** */
11
+
12
+ typedef struct {
13
+ struct fiobj_vtable_s *vtable;
14
+ uint64_t start;
15
+ uint64_t end;
16
+ uint64_t capa;
17
+ fiobj_s **arry;
18
+ } fiobj_ary_s;
19
+
20
+ #define obj2ary(o) ((fiobj_ary_s *)(o))
9
21
 
10
22
  /* *****************************************************************************
11
23
  Array memory management
@@ -76,9 +88,11 @@ static void fiobj_ary_getmem(fiobj_s *ary, int64_t needed) {
76
88
  VTable
77
89
  ***************************************************************************** */
78
90
 
91
+ const uintptr_t FIOBJ_T_ARRAY;
92
+
79
93
  static void fiobj_ary_dealloc(fiobj_s *a) {
80
94
  free(obj2ary(a)->arry);
81
- free(&OBJ2HEAD(a));
95
+ fiobj_dealloc(a);
82
96
  }
83
97
 
84
98
  static size_t fiobj_ary_each1(fiobj_s *o, size_t start_at,
@@ -91,45 +105,53 @@ static size_t fiobj_ary_each1(fiobj_s *o, size_t start_at,
91
105
  return start_at - start_pos;
92
106
  }
93
107
 
94
- static int fiobj_ary_is_eq(fiobj_s *self, fiobj_s *other) {
95
- return (other && other->type == FIOBJ_T_ARRAY &&
96
- obj2ary(self)->end - obj2ary(self)->start ==
97
- obj2ary(other)->end - obj2ary(other)->start);
108
+ static int fiobj_ary_is_eq(const fiobj_s *self, const fiobj_s *other) {
109
+ if (self == other)
110
+ return 1;
111
+ if (!other || other->type != FIOBJ_T_ARRAY ||
112
+ (obj2ary(self)->end - obj2ary(self)->start) !=
113
+ (obj2ary(other)->end - obj2ary(other)->start))
114
+ return 0;
115
+ return 1;
98
116
  }
99
117
 
100
118
  /** Returns the number of elements in the Array. */
101
- static size_t fiobj_ary_count_items(fiobj_s *ary) {
119
+ static size_t fiobj_ary_count_items(const fiobj_s *ary) {
102
120
  return (obj2ary(ary)->end - obj2ary(ary)->start);
103
121
  }
104
122
 
105
123
  static struct fiobj_vtable_s FIOBJ_VTABLE_ARRAY = {
124
+ .name = "Array",
106
125
  .free = fiobj_ary_dealloc,
107
126
  .to_i = fiobj_noop_i,
108
127
  .to_f = fiobj_noop_f,
109
128
  .to_str = fiobj_noop_str,
110
129
  .is_eq = fiobj_ary_is_eq,
111
130
  .count = fiobj_ary_count_items,
131
+ .unwrap = fiobj_noop_unwrap,
112
132
  .each1 = fiobj_ary_each1,
113
133
  };
134
+
135
+ const uintptr_t FIOBJ_T_ARRAY = (uintptr_t)(&FIOBJ_VTABLE_ARRAY);
136
+
114
137
  /* *****************************************************************************
115
138
  Allocation
116
139
  ***************************************************************************** */
117
140
 
118
141
  static fiobj_s *fiobj_ary_alloc(size_t capa, size_t start_at) {
119
- fiobj_head_s *head;
120
- head = malloc(sizeof(*head) + sizeof(fio_ary_s));
121
- if (!head)
142
+ fiobj_s *ary = fiobj_alloc(sizeof(fiobj_ary_s));
143
+ if (!ary)
122
144
  perror("ERROR: fiobj array couldn't allocate memory"), exit(errno);
123
- *head = (fiobj_head_s){
124
- .ref = 1, .vtable = &FIOBJ_VTABLE_ARRAY,
145
+ *(obj2ary(ary)) = (fiobj_ary_s){
146
+ .vtable = &FIOBJ_VTABLE_ARRAY,
147
+ .start = start_at,
148
+ .end = start_at,
149
+ .capa = capa,
150
+ .arry = malloc(sizeof(fiobj_s *) * capa),
125
151
  };
126
- *((fio_ary_s *)HEAD2OBJ(head)) =
127
- (fio_ary_s){.start = start_at,
128
- .end = start_at,
129
- .capa = capa,
130
- .arry = malloc(sizeof(fiobj_s *) * capa),
131
- .type = FIOBJ_T_ARRAY};
132
- return HEAD2OBJ(head);
152
+ if (capa && !obj2ary(ary)->capa)
153
+ perror("ERROR: fiobj array couldn't allocate memory"), exit(errno);
154
+ return ary;
133
155
  }
134
156
 
135
157
  /** Creates a mutable empty Array object. Use `fiobj_free` when done. */
@@ -137,6 +159,10 @@ fiobj_s *fiobj_ary_new(void) { return fiobj_ary_alloc(32, 8); }
137
159
  /** Creates a mutable empty Array object with the requested capacity. */
138
160
  fiobj_s *fiobj_ary_new2(size_t capa) { return fiobj_ary_alloc(capa, 0); }
139
161
 
162
+ /* *****************************************************************************
163
+ Array direct entry access API
164
+ ***************************************************************************** */
165
+
140
166
  /** Returns the number of elements in the Array. */
141
167
  size_t fiobj_ary_count(fiobj_s *ary) {
142
168
  if (!ary)
@@ -144,9 +170,22 @@ size_t fiobj_ary_count(fiobj_s *ary) {
144
170
  return (obj2ary(ary)->end - obj2ary(ary)->start);
145
171
  }
146
172
 
147
- /* *****************************************************************************
148
- Array direct entry access API
149
- ***************************************************************************** */
173
+ /** Returns the current, temporary, array capacity (it's dynamic). */
174
+ size_t fiobj_ary_capa(fiobj_s *ary) {
175
+ if (!ary)
176
+ return 0;
177
+ return obj2ary(ary)->capa;
178
+ }
179
+
180
+ /**
181
+ * Returns a TEMPORARY pointer to the begining of the array.
182
+ *
183
+ * This pointer can be used for sorting and other direct access operations as
184
+ * long as no other actions (insertion/deletion) are performed on the array.
185
+ */
186
+ fiobj_s **fiobj_ary2prt(fiobj_s *ary) {
187
+ return obj2ary(ary)->arry + obj2ary(ary)->start;
188
+ }
150
189
 
151
190
  /**
152
191
  * Returns a temporary object owned by the Array.
@@ -154,7 +193,7 @@ Array direct entry access API
154
193
  * Negative values are retrived from the end of the array. i.e., `-1`
155
194
  * is the last item.
156
195
  */
157
- fiobj_s *fiobj_ary_entry(fiobj_s *ary, int64_t pos) {
196
+ fiobj_s *fiobj_ary_index(fiobj_s *ary, int64_t pos) {
158
197
  if (!ary || ary->type != FIOBJ_T_ARRAY)
159
198
  return NULL;
160
199
  /* position is relative to `start`*/
@@ -0,0 +1,106 @@
1
+ #ifndef FIOBJ_ARRAY_H
2
+ /*
3
+ Copyright: Boaz Segev, 2017
4
+ License: MIT
5
+ */
6
+
7
+ /**
8
+ A dynamic Array type for the fiobj_s dynamic type system.
9
+ */
10
+ #define FIOBJ_ARRAY_H
11
+
12
+ #include "fiobject.h"
13
+
14
+ #ifdef __cplusplus
15
+ extern "C" {
16
+ #endif
17
+
18
+ /** The Array type indentifier. */
19
+ extern const uintptr_t FIOBJ_T_ARRAY;
20
+
21
+ /* *****************************************************************************
22
+ Array creation API
23
+ ***************************************************************************** */
24
+
25
+ /** Creates a mutable empty Array object. Use `fiobj_free` when done. */
26
+ fiobj_s *fiobj_ary_new(void);
27
+
28
+ /** Creates a mutable empty Array object with the requested capacity. */
29
+ fiobj_s *fiobj_ary_new2(size_t capa);
30
+
31
+ /* *****************************************************************************
32
+ Array direct entry access API
33
+ ***************************************************************************** */
34
+
35
+ /** Returns the number of elements in the Array. */
36
+ size_t fiobj_ary_count(fiobj_s *ary);
37
+
38
+ /** Returns the current, temporary, array capacity (it's dynamic). */
39
+ size_t fiobj_ary_capa(fiobj_s *ary);
40
+
41
+ /**
42
+ * Returns a TEMPORARY pointer to the begining of the array.
43
+ *
44
+ * This pointer can be used for sorting and other direct access operations as
45
+ * long as no other actions (insertion/deletion) are performed on the array.
46
+ */
47
+ fiobj_s **fiobj_ary2prt(fiobj_s *ary);
48
+
49
+ /**
50
+ * Returns a temporary object owned by the Array.
51
+ *
52
+ * Wrap this function call within `fiobj_dup` to get a persistent handle. i.e.:
53
+ *
54
+ * fiobj_dup(fiobj_ary_index(array, 0));
55
+ *
56
+ * Negative values are retrived from the end of the array. i.e., `-1`
57
+ * is the last item.
58
+ */
59
+ fiobj_s *fiobj_ary_index(fiobj_s *ary, int64_t pos);
60
+ /** alias for `fiobj_ary_index` */
61
+ #define fiobj_ary_entry(a, p) fiobj_ary_index((a), (p))
62
+
63
+ /**
64
+ * Sets an object at the requested position.
65
+ */
66
+ void fiobj_ary_set(fiobj_s *ary, fiobj_s *obj, int64_t pos);
67
+
68
+ /* *****************************************************************************
69
+ Array push / shift API
70
+ ***************************************************************************** */
71
+
72
+ /**
73
+ * Pushes an object to the end of the Array.
74
+ */
75
+ void fiobj_ary_push(fiobj_s *ary, fiobj_s *obj);
76
+
77
+ /** Pops an object from the end of the Array. */
78
+ fiobj_s *fiobj_ary_pop(fiobj_s *ary);
79
+
80
+ /**
81
+ * Unshifts an object to the begining of the Array. This could be
82
+ * expensive.
83
+ */
84
+ void fiobj_ary_unshift(fiobj_s *ary, fiobj_s *obj);
85
+
86
+ /** Shifts an object from the beginning of the Array. */
87
+ fiobj_s *fiobj_ary_shift(fiobj_s *ary);
88
+
89
+ /* *****************************************************************************
90
+ Array compacting (untested)
91
+ ***************************************************************************** */
92
+
93
+ /**
94
+ * Removes any NULL *pointers* from an Array, keeping all Objects (including
95
+ * explicit NULL objects) in the array.
96
+ *
97
+ * This action is O(n) where n in the length of the array.
98
+ * It could get expensive.
99
+ */
100
+ void fiobj_ary_compact(fiobj_s *ary);
101
+
102
+ #ifdef __cplusplus
103
+ } /* extern "C" */
104
+ #endif
105
+
106
+ #endif
@@ -1,16 +1,49 @@
1
1
  /*
2
- Copyright: Boaz segev, 2017
2
+ Copyright: Boaz Segev, 2017
3
3
  License: MIT
4
-
5
- Feel free to copy, use and enjoy according to the license provided.
6
4
  */
7
5
 
8
- #include "fiobj_types.h"
6
+ #include "fiobj_hash.h"
7
+ #include "fiobj_internal.h"
8
+
9
+ #include <errno.h>
9
10
 
11
+ /* *****************************************************************************
12
+ Hash types
13
+ ***************************************************************************** */
10
14
  /* MUST be a power of 2 */
11
- #define HASH_INITIAL_CAPACITY 16
15
+ #define FIOBJ_HASH_MAX_MAP_SEEK (256)
16
+
17
+ typedef struct {
18
+ uintptr_t hash;
19
+ fio_ls_s *container;
20
+ } map_info_s;
21
+
22
+ typedef struct {
23
+ uintptr_t capa;
24
+ map_info_s *data;
25
+ } fio_map_s;
26
+
27
+ typedef struct {
28
+ struct fiobj_vtable_s *vtable;
29
+ uintptr_t count;
30
+ uintptr_t mask;
31
+ fio_ls_s items;
32
+ fio_map_s map;
33
+ } fiobj_hash_s;
34
+
35
+ /* Hash node */
36
+ typedef struct {
37
+ struct fiobj_vtable_s *vtable;
38
+ fiobj_s *name;
39
+ fiobj_s *obj;
40
+ } fiobj_couplet_s;
41
+
42
+ void fiobj_hash_rehash(fiobj_s *h);
43
+
44
+ #define obj2hash(o) ((fiobj_hash_s *)(o))
45
+ #define obj2couplet(o) ((fiobj_couplet_s *)(o))
12
46
 
13
- #include <errno.h>
14
47
  /* *****************************************************************************
15
48
  Internal Map Array
16
49
  We avoid the fiobj_ary_s to prevent code entanglement
@@ -35,8 +68,8 @@ static inline uintptr_t fio_map_cuckoo_steps(uintptr_t step) {
35
68
  }
36
69
 
37
70
  /* seeks the hash's position in the map */
38
- static map_info_s *fio_hash_seek(fio_hash_s *h, uintptr_t hash) {
39
- /* TODO: consider implementing Robing Hood reordering during seek */
71
+ static map_info_s *fio_hash_seek(fiobj_hash_s *h, uintptr_t hash) {
72
+ /* TODO: consider implementing Robing Hood reordering during seek? */
40
73
  map_info_s *pos = h->map.data + (hash & h->mask);
41
74
  uintptr_t i = 0;
42
75
  const uintptr_t limit = h->map.capa > FIOBJ_HASH_MAX_MAP_SEEK
@@ -51,18 +84,40 @@ static map_info_s *fio_hash_seek(fio_hash_s *h, uintptr_t hash) {
51
84
  return NULL;
52
85
  }
53
86
 
87
+ /* seeks the hash's position in the map while actually comparing key data */
88
+ // static map_info_s *fio_hash_seek_secure(fiobj_hash_s *h, uintptr_t hash,
89
+ // fiobj_s *key) {
90
+ // /* TODO: consider implementing Robing Hood reordering during seek? */
91
+ // map_info_s *pos = h->map.data + (hash & h->mask);
92
+ // uintptr_t i = 0;
93
+ // const uintptr_t limit = h->map.capa > FIOBJ_HASH_MAX_MAP_SEEK
94
+ // ? FIOBJ_HASH_MAX_MAP_SEEK
95
+ // : (h->map.capa >> 1);
96
+ // while (i < limit) {
97
+ // if (!pos->hash ||
98
+ // (pos->hash == hash &&
99
+ // (!pos->container || !pos->container->obj ||
100
+ // obj2couplet(pos->container->obj)->name == key ||
101
+ // fiobj_iseq(obj2couplet(pos->container->obj)->name, key))))
102
+ // return pos;
103
+ // pos = h->map.data +
104
+ // (((hash & h->mask) + fio_map_cuckoo_steps(i++)) & h->mask);
105
+ // }
106
+ // return NULL;
107
+ // }
108
+
54
109
  /* finds an object in the map */
55
- static void *fio_hash_find(fio_hash_s *h, uintptr_t hash) {
110
+ static void *fio_hash_find(fiobj_hash_s *h, uintptr_t hash) {
56
111
  map_info_s *info = fio_hash_seek(h, hash);
57
112
  if (!info || !info->container)
58
113
  return NULL;
59
- return info->container->obj;
114
+ return (void *)info->container->obj;
60
115
  }
61
116
 
62
117
  /* inserts an object to the map, rehashing if required, returning old object.
63
118
  * set obj to NULL to remove existing data.
64
119
  */
65
- static void *fio_hash_insert(fio_hash_s *h, uintptr_t hash, void *obj) {
120
+ static void *fio_hash_insert(fiobj_hash_s *h, uintptr_t hash, void *obj) {
66
121
  map_info_s *info = fio_hash_seek(h, hash);
67
122
  if (!info)
68
123
  return (void *)(-1);
@@ -85,14 +140,14 @@ static void *fio_hash_insert(fio_hash_s *h, uintptr_t hash, void *obj) {
85
140
  return obj;
86
141
  }
87
142
  /* replace */
88
- void *old = info->container->obj;
143
+ void *old = (void *)info->container->obj;
89
144
  info->container->obj = obj;
90
145
  return old;
91
146
  }
92
147
 
93
148
  /* attempts to rehash the hashmap. */
94
149
  void fiobj_hash_rehash(fiobj_s *h_) {
95
- fio_hash_s *h = obj2hash(h_);
150
+ fiobj_hash_s *h = obj2hash(h_);
96
151
  // fprintf(stderr,
97
152
  // "- Rehash with "
98
153
  // "length/capacity == %lu/%lu\n",
@@ -103,7 +158,7 @@ retry_rehashing:
103
158
  fio_ls_s *pos = h->items.next;
104
159
  while (pos != &h->items) {
105
160
  /* can't use fio_hash_insert, because we're recycling containers */
106
- uintptr_t pos_hash = obj2sym(obj2couplet(pos->obj)->name)->hash;
161
+ uintptr_t pos_hash = fiobj_sym_id(obj2couplet(pos->obj)->name);
107
162
  map_info_s *info = fio_hash_seek(h, pos_hash);
108
163
  if (!info) {
109
164
  goto retry_rehashing;
@@ -117,10 +172,12 @@ retry_rehashing:
117
172
  Couplet alloc + Couplet VTable
118
173
  ***************************************************************************** */
119
174
 
175
+ const uintptr_t FIOBJ_T_COUPLET;
176
+
120
177
  static void fiobj_couplet_dealloc(fiobj_s *o) {
121
- fiobj_dealloc(obj2couplet(o)->name);
122
- fiobj_dealloc(obj2couplet(o)->obj);
123
- free(&OBJ2HEAD(o));
178
+ if (OBJREF_REM(obj2couplet(o)->name) == 0)
179
+ OBJVTBL(obj2couplet(o)->name)->free(obj2couplet(o)->name);
180
+ fiobj_dealloc(o);
124
181
  }
125
182
 
126
183
  static size_t fiobj_couplet_each1(fiobj_s *o, size_t start_at,
@@ -128,30 +185,31 @@ static size_t fiobj_couplet_each1(fiobj_s *o, size_t start_at,
128
185
  void *arg) {
129
186
  if (obj2couplet(o)->obj == NULL)
130
187
  return 0;
131
- return OBJ2HEAD(obj2couplet(o)->obj)
132
- .vtable->each1(obj2couplet(o)->obj, start_at, task, arg);
188
+ return OBJVTBL(obj2couplet(o)->obj)
189
+ ->each1(obj2couplet(o)->obj, start_at, task, arg);
133
190
  }
134
191
 
135
- static int fiobj_coup_is_eq(fiobj_s *self, fiobj_s *other) {
136
- if (!other || other->type != FIOBJ_T_COUPLET)
192
+ static int fiobj_coup_is_eq(const fiobj_s *self, const fiobj_s *other) {
193
+
194
+ if (other->type != FIOBJ_T_COUPLET)
137
195
  return 0;
138
- OBJ2HEAD(obj2couplet(self)->name)
139
- .vtable->is_eq(obj2couplet(self)->name, obj2couplet(other)->name);
140
- if (obj2couplet(self)->obj == obj2couplet(other)->obj)
141
- return 1;
142
- if (!obj2couplet(self)->obj || !obj2couplet(other)->obj)
196
+ if (obj2couplet(self)->name != obj2couplet(other)->name &&
197
+ (!obj2couplet(other)->name || !obj2couplet(self)->name ||
198
+ !OBJVTBL(obj2couplet(self)->name)
199
+ ->is_eq(obj2couplet(self)->name, obj2couplet(other)->name)))
143
200
  return 0;
144
- return OBJ2HEAD(obj2couplet(self)->obj)
145
- .vtable->is_eq(obj2couplet(self)->obj, obj2couplet(other)->obj);
201
+ return fiobj_iseq(obj2couplet(self)->obj, obj2couplet(other)->obj);
146
202
  }
147
203
 
148
204
  /** Returns the number of elements in the Array. */
149
- static size_t fiobj_couplet_count_items(fiobj_s *o) {
205
+ static size_t fiobj_couplet_count_items(const fiobj_s *o) {
150
206
  if (obj2couplet(o)->obj == NULL)
151
207
  return 0;
152
- return OBJ2HEAD(obj2couplet(o)->obj).vtable->count(obj2couplet(o)->obj);
208
+ return OBJVTBL(obj2couplet(o)->obj)->count(obj2couplet(o)->obj);
153
209
  }
154
210
 
211
+ fiobj_s *fiobj_couplet2obj(const fiobj_s *obj);
212
+
155
213
  static struct fiobj_vtable_s FIOBJ_VTABLE_COUPLET = {
156
214
  .free = fiobj_couplet_dealloc,
157
215
  .to_i = fiobj_noop_i,
@@ -159,20 +217,19 @@ static struct fiobj_vtable_s FIOBJ_VTABLE_COUPLET = {
159
217
  .to_str = fiobj_noop_str,
160
218
  .is_eq = fiobj_coup_is_eq,
161
219
  .count = fiobj_couplet_count_items,
220
+ .unwrap = fiobj_couplet2obj,
162
221
  .each1 = fiobj_couplet_each1,
163
222
  };
164
223
 
224
+ const uintptr_t FIOBJ_T_COUPLET = (uintptr_t)(&FIOBJ_VTABLE_COUPLET);
225
+
165
226
  static inline fiobj_s *fiobj_couplet_alloc(void *sym, void *obj) {
166
- fiobj_head_s *head;
167
- head = malloc(sizeof(*head) + sizeof(fio_couplet_s));
168
- if (!head)
227
+ fiobj_s *o = fiobj_alloc(sizeof(fiobj_couplet_s));
228
+ if (!o)
169
229
  perror("ERROR: fiobj hash couldn't allocate couplet"), exit(errno);
170
- *head = (fiobj_head_s){
171
- .ref = 1, .vtable = &FIOBJ_VTABLE_COUPLET,
172
- };
173
- *(fio_couplet_s *)(HEAD2OBJ(head)) =
174
- (fio_couplet_s){.type = FIOBJ_T_COUPLET, .name = sym, .obj = obj};
175
- return HEAD2OBJ(head);
230
+ *(obj2couplet(o)) = (fiobj_couplet_s){
231
+ .vtable = &FIOBJ_VTABLE_COUPLET, .name = fiobj_dup(sym), .obj = obj};
232
+ return o;
176
233
  }
177
234
 
178
235
  /**
@@ -181,10 +238,10 @@ static inline fiobj_s *fiobj_couplet_alloc(void *sym, void *obj) {
181
238
  *
182
239
  * Otherwise returns NULL.
183
240
  */
184
- fiobj_s *fiobj_couplet2key(fiobj_s *obj) {
241
+ fiobj_s *fiobj_couplet2key(const fiobj_s *obj) {
185
242
  if (!obj || obj->type != FIOBJ_T_COUPLET)
186
243
  return NULL;
187
- return ((fio_couplet_s *)obj)->name;
244
+ return obj2couplet(obj)->name;
188
245
  }
189
246
 
190
247
  /**
@@ -193,23 +250,25 @@ fiobj_s *fiobj_couplet2key(fiobj_s *obj) {
193
250
  *
194
251
  * Otherwise returns NULL.
195
252
  */
196
- fiobj_s *fiobj_couplet2obj(fiobj_s *obj) {
253
+ fiobj_s *fiobj_couplet2obj(const fiobj_s *obj) {
197
254
  if (!obj || obj->type != FIOBJ_T_COUPLET)
198
- return obj;
199
- return ((fio_couplet_s *)obj)->obj;
255
+ return (fiobj_s *)obj;
256
+ return obj2couplet(obj)->obj;
200
257
  }
201
258
 
202
259
  /* *****************************************************************************
203
260
  Hash alloc + VTable
204
261
  ***************************************************************************** */
205
262
 
263
+ const uintptr_t FIOBJ_T_HASH;
264
+
206
265
  static void fiobj_hash_dealloc(fiobj_s *h) {
207
266
  while (fio_ls_pop(&obj2hash(h)->items))
208
267
  ;
209
268
  free(obj2hash(h)->map.data);
210
269
  obj2hash(h)->map.data = NULL;
211
270
  obj2hash(h)->map.capa = 0;
212
- free(&OBJ2HEAD(h));
271
+ fiobj_dealloc(h);
213
272
  }
214
273
 
215
274
  static size_t fiobj_hash_each1(fiobj_s *o, const size_t start_at,
@@ -225,30 +284,32 @@ static size_t fiobj_hash_each1(fiobj_s *o, const size_t start_at,
225
284
  }
226
285
  while (pos != &obj2hash(o)->items) {
227
286
  ++i;
228
- if (task(pos->obj, arg) == -1)
287
+ if (task((fiobj_s *)pos->obj, arg) == -1)
229
288
  return i;
230
289
  pos = pos->next;
231
290
  }
232
291
  return i;
233
292
  }
234
293
 
235
- static int fiobj_hash_is_eq(fiobj_s *self, fiobj_s *other) {
236
- if (!other || other->type != FIOBJ_T_HASH)
294
+ static int fiobj_hash_is_eq(const fiobj_s *self, const fiobj_s *other) {
295
+ if (other->type != FIOBJ_T_HASH)
237
296
  return 0;
238
297
  if (obj2hash(self)->count != obj2hash(other)->count)
239
298
  return 0;
240
- fio_ls_s *pos = obj2hash(self)->items.next;
241
- while (pos != &obj2hash(self)->items) {
242
- if (!fio_hash_find((fio_hash_s *)other,
243
- obj2sym(obj2couplet(pos->obj)->name)->hash))
244
- return 0;
245
- pos = pos->next;
246
- }
299
+ // fio_ls_s *pos = obj2hash(self)->items.next;
300
+ // while (pos != &obj2hash(self)->items) {
301
+ // if (!fio_hash_find((fiobj_hash_s *)other,
302
+ // fiobj_sym_id(obj2couplet(pos->obj)->name)))
303
+ // return 0;
304
+ // pos = pos->next;
305
+ // }
247
306
  return 1;
248
307
  }
249
308
 
250
309
  /** Returns the number of elements in the Array. */
251
- static size_t fiobj_hash_count_items(fiobj_s *o) { return obj2hash(o)->count; }
310
+ static size_t fiobj_hash_count_items(const fiobj_s *o) {
311
+ return obj2hash(o)->count;
312
+ }
252
313
 
253
314
  static struct fiobj_vtable_s FIOBJ_VTABLE_HASH = {
254
315
  .free = fiobj_hash_dealloc,
@@ -257,9 +318,12 @@ static struct fiobj_vtable_s FIOBJ_VTABLE_HASH = {
257
318
  .to_str = fiobj_noop_str,
258
319
  .is_eq = fiobj_hash_is_eq,
259
320
  .count = fiobj_hash_count_items,
321
+ .unwrap = fiobj_noop_unwrap,
260
322
  .each1 = fiobj_hash_each1,
261
323
  };
262
324
 
325
+ const uintptr_t FIOBJ_T_HASH = (uintptr_t)(&FIOBJ_VTABLE_HASH);
326
+
263
327
  /* *****************************************************************************
264
328
  Hash API
265
329
  ***************************************************************************** */
@@ -271,26 +335,23 @@ Hash API
271
335
  * retain order of object insertion.
272
336
  */
273
337
  fiobj_s *fiobj_hash_new(void) {
274
- fiobj_head_s *head = malloc(sizeof(*head) + sizeof(fio_hash_s));
275
- if (!head)
338
+ fiobj_s *o = fiobj_alloc(sizeof(fiobj_hash_s));
339
+ if (!o)
276
340
  perror("ERROR: fiobj hash couldn't allocate memory"), exit(errno);
277
- *head = (fiobj_head_s){
278
- .ref = 1, .vtable = &FIOBJ_VTABLE_HASH,
279
- };
280
- *obj2hash(HEAD2OBJ(head)) = (fio_hash_s){
281
- .type = FIOBJ_T_HASH,
341
+ *obj2hash(o) = (fiobj_hash_s){
342
+ .vtable = &FIOBJ_VTABLE_HASH,
282
343
  .mask = (HASH_INITIAL_CAPACITY - 1),
283
- .items = FIO_LS_INIT((obj2hash(HEAD2OBJ(head))->items)),
344
+ .items = FIO_LS_INIT((obj2hash(o)->items)),
284
345
  .map.data = calloc(sizeof(map_info_s), HASH_INITIAL_CAPACITY),
285
346
  .map.capa = HASH_INITIAL_CAPACITY,
286
347
  };
287
- // fio_map_reset(&obj2hash(HEAD2OBJ(head))->map,
288
- // obj2hash(HEAD2OBJ(head))->mask);
289
- return HEAD2OBJ(head);
348
+ if (!obj2hash(o)->map.data)
349
+ perror("ERROR: fiobj hash couldn't allocate memory"), exit(errno);
350
+ return o;
290
351
  }
291
352
 
292
353
  /** Returns the number of elements in the Hash. */
293
- size_t fiobj_hash_count(fiobj_s *hash) {
354
+ size_t fiobj_hash_count(const fiobj_s *hash) {
294
355
  if (!hash || hash->type != FIOBJ_T_HASH)
295
356
  return 0;
296
357
  return obj2hash(hash)->count;
@@ -304,33 +365,32 @@ size_t fiobj_hash_count(fiobj_s *hash) {
304
365
  */
305
366
  int fiobj_hash_set(fiobj_s *hash, fiobj_s *sym, fiobj_s *obj) {
306
367
  if (hash->type != FIOBJ_T_HASH) {
307
- fiobj_dealloc((fiobj_s *)obj);
368
+ fiobj_free(obj);
308
369
  return -1;
309
370
  }
310
- switch (sym->type) {
311
- case FIOBJ_T_SYMBOL:
312
- sym = fiobj_dup(sym);
313
- break;
314
- case FIOBJ_T_STRING:
315
- sym = fiobj_sym_new(obj2str(sym)->str, obj2str(sym)->len);
316
- break;
317
- default:
318
- fiobj_dealloc((fiobj_s *)obj);
371
+ uintptr_t hash_value = 0;
372
+ if (sym->type == FIOBJ_T_SYMBOL) {
373
+ hash_value = fiobj_sym_id(sym);
374
+ } else if (FIOBJ_IS_STRING(sym)) {
375
+ fio_cstr_s str = fiobj_obj2cstr(sym);
376
+ hash_value = fiobj_sym_hash(str.value, str.len);
377
+ } else {
378
+ fiobj_free((fiobj_s *)obj);
319
379
  return -1;
320
380
  }
321
381
 
322
382
  fiobj_s *coup = fiobj_couplet_alloc(sym, obj);
323
- fiobj_s *old = fio_hash_insert((fio_hash_s *)hash, obj2sym(sym)->hash, coup);
383
+ fiobj_s *old = fio_hash_insert(obj2hash(hash), hash_value, coup);
324
384
  while (old == (void *)-1) {
325
385
  fiobj_hash_rehash(hash);
326
- old = fio_hash_insert((fio_hash_s *)hash, obj2sym(sym)->hash, coup);
386
+ old = fio_hash_insert(obj2hash(hash), hash_value, coup);
327
387
  // fprintf(stderr, "WARN: (fiobj Hash) collision limit reached"
328
388
  // " - forced rehashing\n");
329
389
  }
330
390
  if (old) {
331
391
  fiobj_free(obj2couplet(old)->obj);
332
392
  obj2couplet(old)->obj = NULL;
333
- fiobj_dealloc(old);
393
+ fiobj_couplet_dealloc(old);
334
394
  }
335
395
  return 0;
336
396
  }
@@ -344,22 +404,21 @@ fiobj_s *fiobj_hash_remove(fiobj_s *hash, fiobj_s *sym) {
344
404
  return 0;
345
405
  }
346
406
  uintptr_t hash_value = 0;
347
- switch (sym->type) {
348
- case FIOBJ_T_SYMBOL:
349
- hash_value = obj2sym(sym)->hash;
350
- break;
351
- case FIOBJ_T_STRING:
352
- hash_value = fiobj_sym_hash(obj2str(sym)->str, obj2str(sym)->len);
353
- break;
354
- default:
355
- return 0;
407
+ if (sym->type == FIOBJ_T_SYMBOL) {
408
+ hash_value = fiobj_sym_id(sym);
409
+ } else if (FIOBJ_IS_STRING(sym)) {
410
+ fio_cstr_s str = fiobj_obj2cstr(sym);
411
+ hash_value = fiobj_sym_hash(str.value, str.len);
412
+ } else {
413
+ return NULL;
356
414
  }
357
- fiobj_s *coup = fio_hash_insert((fio_hash_s *)hash, hash_value, NULL);
415
+ fiobj_s *coup = fio_hash_insert(obj2hash(hash), hash_value, NULL);
358
416
  if (!coup)
359
417
  return NULL;
360
418
  fiobj_s *ret = fiobj_couplet2obj(coup);
361
419
  obj2couplet(coup)->obj = NULL;
362
- fiobj_dealloc((fiobj_s *)coup);
420
+
421
+ fiobj_couplet_dealloc((fiobj_s *)coup);
363
422
  return ret;
364
423
  }
365
424
 
@@ -381,22 +440,20 @@ int fiobj_hash_delete(fiobj_s *hash, fiobj_s *sym) {
381
440
  * Returns a temporary handle to the object associated with the Symbol, NULL
382
441
  * if none.
383
442
  */
384
- fiobj_s *fiobj_hash_get(fiobj_s *hash, fiobj_s *sym) {
443
+ fiobj_s *fiobj_hash_get(const fiobj_s *hash, fiobj_s *sym) {
385
444
  if (hash->type != FIOBJ_T_HASH) {
386
445
  return 0;
387
446
  }
388
447
  uintptr_t hash_value = 0;
389
- switch (sym->type) {
390
- case FIOBJ_T_SYMBOL:
391
- hash_value = obj2sym(sym)->hash;
392
- break;
393
- case FIOBJ_T_STRING:
394
- hash_value = fiobj_sym_hash(obj2str(sym)->str, obj2str(sym)->len);
395
- break;
396
- default:
448
+ if (sym->type == FIOBJ_T_SYMBOL) {
449
+ hash_value = fiobj_sym_id(sym);
450
+ } else if (FIOBJ_IS_STRING(sym)) {
451
+ fio_cstr_s str = fiobj_obj2cstr(sym);
452
+ hash_value = fiobj_sym_hash(str.value, str.len);
453
+ } else {
397
454
  return 0;
398
455
  }
399
- fiobj_s *coup = fio_hash_find((fio_hash_s *)hash, hash_value);
456
+ fiobj_s *coup = fio_hash_find(obj2hash(hash), hash_value);
400
457
  if (!coup)
401
458
  return NULL;
402
459
  return fiobj_couplet2obj(coup);
@@ -410,12 +467,12 @@ fiobj_s *fiobj_hash_get(fiobj_s *hash, fiobj_s *sym) {
410
467
  *
411
468
  * Returns NULL if no object is asociated with this String data.
412
469
  */
413
- fiobj_s *fiobj_hash_get2(fiobj_s *hash, const char *str, size_t len) {
470
+ fiobj_s *fiobj_hash_get2(const fiobj_s *hash, const char *str, size_t len) {
414
471
  if (hash->type != FIOBJ_T_HASH || str == NULL) {
415
472
  return NULL;
416
473
  }
417
474
  uintptr_t hashed_sym = fiobj_sym_hash(str, len);
418
- fiobj_s *coup = fio_hash_find((fio_hash_s *)hash, hashed_sym);
475
+ fiobj_s *coup = fio_hash_find(obj2hash(hash), hashed_sym);
419
476
  if (!coup)
420
477
  return NULL;
421
478
  return fiobj_couplet2obj(coup);
@@ -424,24 +481,27 @@ fiobj_s *fiobj_hash_get2(fiobj_s *hash, const char *str, size_t len) {
424
481
  /**
425
482
  * Returns 1 if the key (Symbol) exists in the Hash, even if value is NULL.
426
483
  */
427
- int fiobj_hash_haskey(fiobj_s *hash, fiobj_s *sym) {
484
+ int fiobj_hash_haskey(const fiobj_s *hash, fiobj_s *sym) {
428
485
  if (hash->type != FIOBJ_T_HASH) {
429
486
  return 0;
430
487
  }
431
488
  uintptr_t hash_value = 0;
432
- switch (sym->type) {
433
- case FIOBJ_T_SYMBOL:
434
- hash_value = obj2sym(sym)->hash;
435
- break;
436
- case FIOBJ_T_STRING:
437
- hash_value = fiobj_sym_hash(obj2str(sym)->str, obj2str(sym)->len);
438
- break;
439
- default:
489
+ if (sym->type == FIOBJ_T_SYMBOL) {
490
+ hash_value = fiobj_sym_id(sym);
491
+ } else if (FIOBJ_IS_STRING(sym)) {
492
+ fio_cstr_s str = fiobj_obj2cstr(sym);
493
+ hash_value = fiobj_sym_hash(str.value, str.len);
494
+ } else {
440
495
  return 0;
441
496
  }
442
-
443
- fiobj_s *coup = fio_hash_find((fio_hash_s *)hash, hash_value);
497
+ fiobj_s *coup = fio_hash_find(obj2hash(hash), hash_value);
444
498
  if (!coup)
445
499
  return 0;
446
500
  return 1;
447
501
  }
502
+
503
+ /**
504
+ * Returns a temporary theoretical Hash map capacity.
505
+ * This could be used for testig performance and memory consumption.
506
+ */
507
+ size_t fiobj_hash_capa(const fiobj_s *hash) { return obj2hash(hash)->map.capa; }