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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +61 -33
- data/README.md +7 -5
- data/ext/iodine/base64.c +12 -0
- data/ext/iodine/defer.c +211 -108
- data/ext/iodine/defer.h +7 -0
- data/ext/iodine/facil.c +5 -1
- data/ext/iodine/facil.h +1 -1
- data/ext/iodine/fio2resp.c +19 -30
- data/ext/iodine/fio2resp.h +2 -1
- data/ext/iodine/fio_cli_helper.c +2 -2
- data/ext/iodine/fiobj.h +11 -624
- data/ext/iodine/fiobj_ary.c +65 -26
- data/ext/iodine/fiobj_ary.h +106 -0
- data/ext/iodine/fiobj_hash.c +175 -115
- data/ext/iodine/fiobj_hash.h +128 -0
- data/ext/iodine/fiobj_internal.c +189 -0
- data/ext/iodine/{fiobj_types.h → fiobj_internal.h} +126 -136
- data/ext/iodine/fiobj_json.c +161 -207
- data/ext/iodine/fiobj_json.h +43 -0
- data/ext/iodine/fiobj_numbers.c +53 -35
- data/ext/iodine/fiobj_numbers.h +49 -0
- data/ext/iodine/fiobj_primitives.c +103 -70
- data/ext/iodine/fiobj_primitives.h +55 -0
- data/ext/iodine/fiobj_str.c +171 -59
- data/ext/iodine/fiobj_str.h +113 -0
- data/ext/iodine/fiobj_sym.c +46 -124
- data/ext/iodine/fiobj_sym.h +60 -0
- data/ext/iodine/fiobject.c +589 -0
- data/ext/iodine/fiobject.h +276 -0
- data/ext/iodine/pubsub.h +1 -1
- data/ext/iodine/resp.c +2 -2
- data/ext/iodine/siphash.c +11 -0
- data/ext/iodine/spnlock.inc +7 -5
- data/ext/iodine/websocket_parser.h +44 -7
- data/lib/iodine/version.rb +1 -1
- metadata +13 -8
- data/ext/iodine/fiobj_alloc.c +0 -81
- data/ext/iodine/fiobj_generic.c +0 -260
- data/ext/iodine/fiobj_io.c +0 -58
- data/ext/iodine/fiobj_misc.c +0 -213
- data/ext/iodine/fiobj_tests.c +0 -474
data/ext/iodine/fiobj_ary.c
CHANGED
@@ -1,11 +1,23 @@
|
|
1
1
|
/*
|
2
|
-
Copyright: Boaz
|
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 "
|
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
|
-
|
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
|
-
|
96
|
-
|
97
|
-
|
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
|
-
|
120
|
-
|
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
|
-
*
|
124
|
-
.
|
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
|
-
|
127
|
-
|
128
|
-
|
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
|
-
|
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 *
|
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
|
data/ext/iodine/fiobj_hash.c
CHANGED
@@ -1,16 +1,49 @@
|
|
1
1
|
/*
|
2
|
-
Copyright: Boaz
|
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 "
|
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
|
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(
|
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(
|
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(
|
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
|
-
|
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 =
|
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
|
-
|
122
|
-
|
123
|
-
|
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
|
132
|
-
|
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
|
-
|
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
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
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
|
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
|
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
|
-
|
167
|
-
|
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
|
-
*
|
171
|
-
.
|
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 (
|
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 (
|
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
|
-
|
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 (
|
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
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
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) {
|
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
|
-
|
275
|
-
if (!
|
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
|
-
*
|
278
|
-
.
|
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(
|
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
|
-
|
288
|
-
|
289
|
-
return
|
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
|
-
|
368
|
+
fiobj_free(obj);
|
308
369
|
return -1;
|
309
370
|
}
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
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((
|
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((
|
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
|
-
|
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
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
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((
|
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
|
-
|
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
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
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((
|
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((
|
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
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
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; }
|