iodine 0.4.8 → 0.4.10
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +26 -0
- data/README.md +18 -12
- data/SPEC-Websocket-Draft.md +9 -5
- data/bin/ws-echo +3 -0
- data/examples/config.ru +0 -1
- data/examples/echo.ru +3 -1
- data/examples/redis.ru +0 -1
- data/ext/iodine/base64.c +97 -105
- data/ext/iodine/defer.c +16 -1
- data/ext/iodine/defer.h +10 -0
- data/ext/iodine/evio.c +35 -13
- data/ext/iodine/extconf.rb +1 -1
- data/ext/iodine/facil.c +12 -1
- data/ext/iodine/facil.h +3 -1
- data/ext/iodine/fio2resp.c +71 -0
- data/ext/iodine/fio2resp.h +50 -0
- data/ext/iodine/fio_cli_helper.c +404 -0
- data/ext/iodine/fio_cli_helper.h +152 -0
- data/ext/iodine/fiobj.h +631 -0
- data/ext/iodine/fiobj_alloc.c +81 -0
- data/ext/iodine/fiobj_ary.c +290 -0
- data/ext/iodine/fiobj_generic.c +260 -0
- data/ext/iodine/fiobj_hash.c +447 -0
- data/ext/iodine/fiobj_io.c +58 -0
- data/ext/iodine/fiobj_json.c +779 -0
- data/ext/iodine/fiobj_misc.c +213 -0
- data/ext/iodine/fiobj_numbers.c +113 -0
- data/ext/iodine/fiobj_primitives.c +98 -0
- data/ext/iodine/fiobj_str.c +261 -0
- data/ext/iodine/fiobj_sym.c +213 -0
- data/ext/iodine/fiobj_tests.c +474 -0
- data/ext/iodine/fiobj_types.h +290 -0
- data/ext/iodine/http1.c +54 -36
- data/ext/iodine/http1_parser.c +143 -35
- data/ext/iodine/http1_parser.h +6 -3
- data/ext/iodine/http1_response.c +0 -1
- data/ext/iodine/http_response.c +1 -1
- data/ext/iodine/iodine.c +20 -4
- data/ext/iodine/iodine_protocol.c +5 -4
- data/ext/iodine/iodine_pubsub.c +1 -1
- data/ext/iodine/random.c +5 -5
- data/ext/iodine/sha1.c +5 -8
- data/ext/iodine/sha2.c +8 -11
- data/ext/iodine/sha2.h +3 -3
- data/ext/iodine/sock.c +29 -31
- data/ext/iodine/websocket_parser.h +428 -0
- data/ext/iodine/websockets.c +112 -377
- data/ext/iodine/xor-crypt.c +16 -12
- data/lib/iodine/version.rb +1 -1
- metadata +21 -3
- data/ext/iodine/empty.h +0 -26
@@ -0,0 +1,447 @@
|
|
1
|
+
/*
|
2
|
+
Copyright: Boaz segev, 2017
|
3
|
+
License: MIT
|
4
|
+
|
5
|
+
Feel free to copy, use and enjoy according to the license provided.
|
6
|
+
*/
|
7
|
+
|
8
|
+
#include "fiobj_types.h"
|
9
|
+
|
10
|
+
/* MUST be a power of 2 */
|
11
|
+
#define HASH_INITIAL_CAPACITY 16
|
12
|
+
|
13
|
+
#include <errno.h>
|
14
|
+
/* *****************************************************************************
|
15
|
+
Internal Map Array
|
16
|
+
We avoid the fiobj_ary_s to prevent entanglement
|
17
|
+
***************************************************************************** */
|
18
|
+
|
19
|
+
static inline void fio_map_reset(fio_map_s *map, uintptr_t capa) {
|
20
|
+
/* It's better to reallocate using calloc than manually zero out memory */
|
21
|
+
/* Maybe there's enough zeroed out pages available in the system */
|
22
|
+
map->capa = capa;
|
23
|
+
free(map->data);
|
24
|
+
map->data = calloc(sizeof(*map->data), map->capa);
|
25
|
+
if (!map->data)
|
26
|
+
perror("HashMap Allocation Failed"), exit(errno);
|
27
|
+
}
|
28
|
+
|
29
|
+
/* *****************************************************************************
|
30
|
+
Internal HashMap
|
31
|
+
***************************************************************************** */
|
32
|
+
static inline uintptr_t fio_map_cuckoo_steps(uintptr_t step) {
|
33
|
+
// return ((step * (step + 1)) >> 1);
|
34
|
+
return (step * 3);
|
35
|
+
}
|
36
|
+
|
37
|
+
/* 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 */
|
40
|
+
map_info_s *pos = h->map.data + (hash & h->mask);
|
41
|
+
uintptr_t i = 0;
|
42
|
+
const uintptr_t limit = h->map.capa > FIOBJ_HASH_MAX_MAP_SEEK
|
43
|
+
? FIOBJ_HASH_MAX_MAP_SEEK
|
44
|
+
: (h->map.capa >> 1);
|
45
|
+
while (i < limit) {
|
46
|
+
if (!pos->hash || pos->hash == hash)
|
47
|
+
return pos;
|
48
|
+
pos = h->map.data +
|
49
|
+
(((hash & h->mask) + fio_map_cuckoo_steps(i++)) & h->mask);
|
50
|
+
}
|
51
|
+
return NULL;
|
52
|
+
}
|
53
|
+
|
54
|
+
/* finds an object in the map */
|
55
|
+
static void *fio_hash_find(fio_hash_s *h, uintptr_t hash) {
|
56
|
+
map_info_s *info = fio_hash_seek(h, hash);
|
57
|
+
if (!info || !info->container)
|
58
|
+
return NULL;
|
59
|
+
return info->container->obj;
|
60
|
+
}
|
61
|
+
|
62
|
+
/* inserts an object to the map, rehashing if required, returning old object.
|
63
|
+
* set obj to NULL to remove existing data.
|
64
|
+
*/
|
65
|
+
static void *fio_hash_insert(fio_hash_s *h, uintptr_t hash, void *obj) {
|
66
|
+
map_info_s *info = fio_hash_seek(h, hash);
|
67
|
+
if (!info)
|
68
|
+
return (void *)(-1);
|
69
|
+
if (!info->container) {
|
70
|
+
/* a fresh object */
|
71
|
+
if (obj == NULL)
|
72
|
+
return NULL; /* nothing to delete */
|
73
|
+
/* create container and set hash */
|
74
|
+
fio_ls_unshift(&h->items, obj);
|
75
|
+
*info = (map_info_s){.hash = hash, .container = h->items.prev};
|
76
|
+
h->count++;
|
77
|
+
return NULL;
|
78
|
+
}
|
79
|
+
/* a container object exists, this is a "replace/delete" operation */
|
80
|
+
if (!obj) {
|
81
|
+
/* delete */
|
82
|
+
h->count--;
|
83
|
+
obj = fio_ls_remove(info->container);
|
84
|
+
*info = (map_info_s){.hash = hash}; /* hash is set to seek over position */
|
85
|
+
return obj;
|
86
|
+
}
|
87
|
+
/* replace */
|
88
|
+
void *old = info->container->obj;
|
89
|
+
info->container->obj = obj;
|
90
|
+
return old;
|
91
|
+
}
|
92
|
+
|
93
|
+
/* attempts to rehash the hashmap. */
|
94
|
+
void fiobj_hash_rehash(fiobj_s *h_) {
|
95
|
+
fio_hash_s *h = obj2hash(h_);
|
96
|
+
// fprintf(stderr,
|
97
|
+
// "- Rehash with "
|
98
|
+
// "length/capacity == %lu/%lu\n",
|
99
|
+
// h->count, h->map.capa);
|
100
|
+
retry_rehashing:
|
101
|
+
h->mask = ((h->mask) << 1) | 1;
|
102
|
+
fio_map_reset(&h->map, h->mask + 1);
|
103
|
+
fio_ls_s *pos = h->items.next;
|
104
|
+
while (pos != &h->items) {
|
105
|
+
/* can't use fio_hash_insert, because we're recycling containers */
|
106
|
+
uintptr_t pos_hash = obj2sym(obj2couplet(pos->obj)->name)->hash;
|
107
|
+
map_info_s *info = fio_hash_seek(h, pos_hash);
|
108
|
+
if (!info) {
|
109
|
+
goto retry_rehashing;
|
110
|
+
}
|
111
|
+
*info = (map_info_s){.hash = pos_hash, .container = pos};
|
112
|
+
pos = pos->next;
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
116
|
+
/* *****************************************************************************
|
117
|
+
Couplet alloc + Couplet VTable
|
118
|
+
***************************************************************************** */
|
119
|
+
|
120
|
+
static void fiobj_couplet_dealloc(fiobj_s *o) {
|
121
|
+
fiobj_dealloc(obj2couplet(o)->name);
|
122
|
+
fiobj_dealloc(obj2couplet(o)->obj);
|
123
|
+
free(&OBJ2HEAD(o));
|
124
|
+
}
|
125
|
+
|
126
|
+
static size_t fiobj_couplet_each1(fiobj_s *o, size_t start_at,
|
127
|
+
int (*task)(fiobj_s *obj, void *arg),
|
128
|
+
void *arg) {
|
129
|
+
if (obj2couplet(o)->obj == NULL)
|
130
|
+
return 0;
|
131
|
+
return OBJ2HEAD(obj2couplet(o)->obj)
|
132
|
+
.vtable->each1(obj2couplet(o)->obj, start_at, task, arg);
|
133
|
+
}
|
134
|
+
|
135
|
+
static int fiobj_coup_is_eq(fiobj_s *self, fiobj_s *other) {
|
136
|
+
if (!other || other->type != FIOBJ_T_COUPLET)
|
137
|
+
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)
|
143
|
+
return 0;
|
144
|
+
return OBJ2HEAD(obj2couplet(self)->obj)
|
145
|
+
.vtable->is_eq(obj2couplet(self)->obj, obj2couplet(other)->obj);
|
146
|
+
}
|
147
|
+
|
148
|
+
/** Returns the number of elements in the Array. */
|
149
|
+
static size_t fiobj_couplet_count_items(fiobj_s *o) {
|
150
|
+
if (obj2couplet(o)->obj == NULL)
|
151
|
+
return 0;
|
152
|
+
return OBJ2HEAD(obj2couplet(o)->obj).vtable->count(obj2couplet(o)->obj);
|
153
|
+
}
|
154
|
+
|
155
|
+
static struct fiobj_vtable_s FIOBJ_VTABLE_COUPLET = {
|
156
|
+
.free = fiobj_couplet_dealloc,
|
157
|
+
.to_i = fiobj_noop_i,
|
158
|
+
.to_f = fiobj_noop_f,
|
159
|
+
.to_str = fiobj_noop_str,
|
160
|
+
.is_eq = fiobj_coup_is_eq,
|
161
|
+
.count = fiobj_couplet_count_items,
|
162
|
+
.each1 = fiobj_couplet_each1,
|
163
|
+
};
|
164
|
+
|
165
|
+
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)
|
169
|
+
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);
|
176
|
+
}
|
177
|
+
|
178
|
+
/**
|
179
|
+
* If object is a Hash couplet (occurs in `fiobj_each2`), returns the key
|
180
|
+
* (Symbol) from the key-value pair.
|
181
|
+
*
|
182
|
+
* Otherwise returns NULL.
|
183
|
+
*/
|
184
|
+
fiobj_s *fiobj_couplet2key(fiobj_s *obj) {
|
185
|
+
if (!obj || obj->type != FIOBJ_T_COUPLET)
|
186
|
+
return NULL;
|
187
|
+
return ((fio_couplet_s *)obj)->name;
|
188
|
+
}
|
189
|
+
|
190
|
+
/**
|
191
|
+
* If object is a Hash couplet (occurs in `fiobj_each2`), returns the object
|
192
|
+
* (the value) from the key-value pair.
|
193
|
+
*
|
194
|
+
* Otherwise returns NULL.
|
195
|
+
*/
|
196
|
+
fiobj_s *fiobj_couplet2obj(fiobj_s *obj) {
|
197
|
+
if (!obj || obj->type != FIOBJ_T_COUPLET)
|
198
|
+
return obj;
|
199
|
+
return ((fio_couplet_s *)obj)->obj;
|
200
|
+
}
|
201
|
+
|
202
|
+
/* *****************************************************************************
|
203
|
+
Hash alloc + VTable
|
204
|
+
***************************************************************************** */
|
205
|
+
|
206
|
+
static void fiobj_hash_dealloc(fiobj_s *h) {
|
207
|
+
while (fio_ls_pop(&obj2hash(h)->items))
|
208
|
+
;
|
209
|
+
free(obj2hash(h)->map.data);
|
210
|
+
obj2hash(h)->map.data = NULL;
|
211
|
+
obj2hash(h)->map.capa = 0;
|
212
|
+
free(&OBJ2HEAD(h));
|
213
|
+
}
|
214
|
+
|
215
|
+
static size_t fiobj_hash_each1(fiobj_s *o, const size_t start_at,
|
216
|
+
int (*task)(fiobj_s *obj, void *arg),
|
217
|
+
void *arg) {
|
218
|
+
if (start_at >= obj2hash(o)->count)
|
219
|
+
return obj2hash(o)->count;
|
220
|
+
size_t i = 0;
|
221
|
+
fio_ls_s *pos = obj2hash(o)->items.next;
|
222
|
+
while (pos != &obj2hash(o)->items && start_at > i) {
|
223
|
+
pos = pos->next;
|
224
|
+
++i;
|
225
|
+
}
|
226
|
+
while (pos != &obj2hash(o)->items) {
|
227
|
+
++i;
|
228
|
+
if (task(pos->obj, arg) == -1)
|
229
|
+
return i;
|
230
|
+
pos = pos->next;
|
231
|
+
}
|
232
|
+
return i;
|
233
|
+
}
|
234
|
+
|
235
|
+
static int fiobj_hash_is_eq(fiobj_s *self, fiobj_s *other) {
|
236
|
+
if (!other || other->type != FIOBJ_T_HASH)
|
237
|
+
return 0;
|
238
|
+
if (obj2hash(self)->count != obj2hash(other)->count)
|
239
|
+
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
|
+
}
|
247
|
+
return 1;
|
248
|
+
}
|
249
|
+
|
250
|
+
/** Returns the number of elements in the Array. */
|
251
|
+
static size_t fiobj_hash_count_items(fiobj_s *o) { return obj2hash(o)->count; }
|
252
|
+
|
253
|
+
static struct fiobj_vtable_s FIOBJ_VTABLE_HASH = {
|
254
|
+
.free = fiobj_hash_dealloc,
|
255
|
+
.to_i = fiobj_noop_i,
|
256
|
+
.to_f = fiobj_noop_f,
|
257
|
+
.to_str = fiobj_noop_str,
|
258
|
+
.is_eq = fiobj_hash_is_eq,
|
259
|
+
.count = fiobj_hash_count_items,
|
260
|
+
.each1 = fiobj_hash_each1,
|
261
|
+
};
|
262
|
+
|
263
|
+
/* *****************************************************************************
|
264
|
+
Hash API
|
265
|
+
***************************************************************************** */
|
266
|
+
|
267
|
+
/**
|
268
|
+
* Creates a mutable empty Hash object. Use `fiobj_free` when done.
|
269
|
+
*
|
270
|
+
* Notice that these Hash objects are designed for smaller collections and
|
271
|
+
* retain order of object insertion.
|
272
|
+
*/
|
273
|
+
fiobj_s *fiobj_hash_new(void) {
|
274
|
+
fiobj_head_s *head = malloc(sizeof(*head) + sizeof(fio_hash_s));
|
275
|
+
if (!head)
|
276
|
+
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,
|
282
|
+
.mask = (HASH_INITIAL_CAPACITY - 1),
|
283
|
+
.items = FIO_LS_INIT((obj2hash(HEAD2OBJ(head))->items)),
|
284
|
+
.map.data = calloc(sizeof(map_info_s), HASH_INITIAL_CAPACITY),
|
285
|
+
.map.capa = HASH_INITIAL_CAPACITY,
|
286
|
+
};
|
287
|
+
// fio_map_reset(&obj2hash(HEAD2OBJ(head))->map,
|
288
|
+
// obj2hash(HEAD2OBJ(head))->mask);
|
289
|
+
return HEAD2OBJ(head);
|
290
|
+
}
|
291
|
+
|
292
|
+
/** Returns the number of elements in the Hash. */
|
293
|
+
size_t fiobj_hash_count(fiobj_s *hash) {
|
294
|
+
if (!hash || hash->type != FIOBJ_T_HASH)
|
295
|
+
return 0;
|
296
|
+
return obj2hash(hash)->count;
|
297
|
+
}
|
298
|
+
|
299
|
+
/**
|
300
|
+
* Sets a key-value pair in the Hash, duplicating the Symbol and **moving**
|
301
|
+
* the ownership of the object to the Hash.
|
302
|
+
*
|
303
|
+
* Returns -1 on error.
|
304
|
+
*/
|
305
|
+
int fiobj_hash_set(fiobj_s *hash, fiobj_s *sym, fiobj_s *obj) {
|
306
|
+
if (hash->type != FIOBJ_T_HASH) {
|
307
|
+
fiobj_dealloc((fiobj_s *)obj);
|
308
|
+
return -1;
|
309
|
+
}
|
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);
|
319
|
+
return -1;
|
320
|
+
}
|
321
|
+
|
322
|
+
fiobj_s *coup = fiobj_couplet_alloc(sym, obj);
|
323
|
+
fiobj_s *old = fio_hash_insert((fio_hash_s *)hash, obj2sym(sym)->hash, coup);
|
324
|
+
while (old == (void *)-1) {
|
325
|
+
fiobj_hash_rehash(hash);
|
326
|
+
old = fio_hash_insert((fio_hash_s *)hash, obj2sym(sym)->hash, coup);
|
327
|
+
// fprintf(stderr, "WARN: (fiobj Hash) collision limit reached"
|
328
|
+
// " - forced rehashing\n");
|
329
|
+
}
|
330
|
+
if (old) {
|
331
|
+
fiobj_free(obj2couplet(old)->obj);
|
332
|
+
obj2couplet(old)->obj = NULL;
|
333
|
+
fiobj_dealloc(old);
|
334
|
+
}
|
335
|
+
return 0;
|
336
|
+
}
|
337
|
+
|
338
|
+
/**
|
339
|
+
* Removes a key-value pair from the Hash, if it exists, returning the old
|
340
|
+
* object (instead of freeing it).
|
341
|
+
*/
|
342
|
+
fiobj_s *fiobj_hash_remove(fiobj_s *hash, fiobj_s *sym) {
|
343
|
+
if (hash->type != FIOBJ_T_HASH) {
|
344
|
+
return 0;
|
345
|
+
}
|
346
|
+
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;
|
356
|
+
}
|
357
|
+
fiobj_s *coup = fio_hash_insert((fio_hash_s *)hash, hash_value, NULL);
|
358
|
+
if (!coup)
|
359
|
+
return NULL;
|
360
|
+
fiobj_s *ret = fiobj_couplet2obj(coup);
|
361
|
+
obj2couplet(coup)->obj = NULL;
|
362
|
+
fiobj_dealloc((fiobj_s *)coup);
|
363
|
+
return ret;
|
364
|
+
}
|
365
|
+
|
366
|
+
/**
|
367
|
+
* Deletes a key-value pair from the Hash, if it exists, freeing the
|
368
|
+
* associated object.
|
369
|
+
*
|
370
|
+
* Returns -1 on type error or if the object never existed.
|
371
|
+
*/
|
372
|
+
int fiobj_hash_delete(fiobj_s *hash, fiobj_s *sym) {
|
373
|
+
fiobj_s *obj = fiobj_hash_remove(hash, sym);
|
374
|
+
if (!obj)
|
375
|
+
return -1;
|
376
|
+
fiobj_free(obj);
|
377
|
+
return 0;
|
378
|
+
}
|
379
|
+
|
380
|
+
/**
|
381
|
+
* Returns a temporary handle to the object associated with the Symbol, NULL
|
382
|
+
* if none.
|
383
|
+
*/
|
384
|
+
fiobj_s *fiobj_hash_get(fiobj_s *hash, fiobj_s *sym) {
|
385
|
+
if (hash->type != FIOBJ_T_HASH) {
|
386
|
+
return 0;
|
387
|
+
}
|
388
|
+
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:
|
397
|
+
return 0;
|
398
|
+
}
|
399
|
+
fiobj_s *coup = fio_hash_find((fio_hash_s *)hash, hash_value);
|
400
|
+
if (!coup)
|
401
|
+
return NULL;
|
402
|
+
return fiobj_couplet2obj(coup);
|
403
|
+
}
|
404
|
+
|
405
|
+
/**
|
406
|
+
* Returns a temporary handle to the object associated with the Symbol C string.
|
407
|
+
*
|
408
|
+
* This function takes a C string instead of a Symbol, which is slower if a
|
409
|
+
* Symbol can be cached but faster if a Symbol must be created.
|
410
|
+
*
|
411
|
+
* Returns NULL if no object is asociated with this String data.
|
412
|
+
*/
|
413
|
+
fiobj_s *fiobj_hash_get2(fiobj_s *hash, const char *str, size_t len) {
|
414
|
+
if (hash->type != FIOBJ_T_HASH || str == NULL) {
|
415
|
+
return NULL;
|
416
|
+
}
|
417
|
+
uintptr_t hashed_sym = fiobj_sym_hash(str, len);
|
418
|
+
fiobj_s *coup = fio_hash_find((fio_hash_s *)hash, hashed_sym);
|
419
|
+
if (!coup)
|
420
|
+
return NULL;
|
421
|
+
return fiobj_couplet2obj(coup);
|
422
|
+
}
|
423
|
+
|
424
|
+
/**
|
425
|
+
* Returns 1 if the key (Symbol) exists in the Hash, even if value is NULL.
|
426
|
+
*/
|
427
|
+
int fiobj_hash_haskey(fiobj_s *hash, fiobj_s *sym) {
|
428
|
+
if (hash->type != FIOBJ_T_HASH) {
|
429
|
+
return 0;
|
430
|
+
}
|
431
|
+
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:
|
440
|
+
return 0;
|
441
|
+
}
|
442
|
+
|
443
|
+
fiobj_s *coup = fio_hash_find((fio_hash_s *)hash, hash_value);
|
444
|
+
if (!coup)
|
445
|
+
return 0;
|
446
|
+
return 1;
|
447
|
+
}
|
@@ -0,0 +1,58 @@
|
|
1
|
+
/*
|
2
|
+
Copyright: Boaz segev, 2017
|
3
|
+
License: MIT
|
4
|
+
|
5
|
+
Feel free to copy, use and enjoy according to the license provided.
|
6
|
+
*/
|
7
|
+
#include "fiobj_types.h"
|
8
|
+
|
9
|
+
/* *****************************************************************************
|
10
|
+
IO VTable
|
11
|
+
***************************************************************************** */
|
12
|
+
|
13
|
+
static int64_t fio_io2i(fiobj_s *io) { return (int64_t)obj2io(io)->fd; }
|
14
|
+
|
15
|
+
static int fiobj_io_is_eq(fiobj_s *self, fiobj_s *other) {
|
16
|
+
if (!other || other->type != self->type ||
|
17
|
+
obj2io(self)->fd != obj2io(other)->fd)
|
18
|
+
return 0;
|
19
|
+
return 1;
|
20
|
+
}
|
21
|
+
|
22
|
+
static struct fiobj_vtable_s FIOBJ_VTABLE_IO = {
|
23
|
+
.free = fiobj_simple_dealloc,
|
24
|
+
.to_i = fio_io2i,
|
25
|
+
.to_f = fiobj_noop_f,
|
26
|
+
.to_str = fiobj_noop_str,
|
27
|
+
.is_eq = fiobj_io_is_eq,
|
28
|
+
.count = fiobj_noop_count,
|
29
|
+
.each1 = fiobj_noop_each1,
|
30
|
+
};
|
31
|
+
|
32
|
+
/* *****************************************************************************
|
33
|
+
IO API
|
34
|
+
***************************************************************************** */
|
35
|
+
|
36
|
+
/** Wrapps a file descriptor in an IO object. Use `fiobj_free` to close. */
|
37
|
+
fiobj_s *fio_io_wrap(intptr_t fd) {
|
38
|
+
fiobj_head_s *head;
|
39
|
+
head = malloc(sizeof(*head) + sizeof(fio_io_s));
|
40
|
+
if (!head)
|
41
|
+
perror("ERROR: fiobj IO couldn't allocate memory"), exit(errno);
|
42
|
+
*head = (fiobj_head_s){
|
43
|
+
.ref = 1, .vtable = &FIOBJ_VTABLE_IO,
|
44
|
+
};
|
45
|
+
*obj2io(HEAD2OBJ(head)) = (fio_io_s){.type = FIOBJ_T_IO, .fd = fd};
|
46
|
+
return HEAD2OBJ(head);
|
47
|
+
}
|
48
|
+
|
49
|
+
/**
|
50
|
+
* Return an IO's fd.
|
51
|
+
*
|
52
|
+
* A type error results in -1.
|
53
|
+
*/
|
54
|
+
intptr_t fiobj_io_fd(fiobj_s *obj) {
|
55
|
+
if (obj->type != FIOBJ_T_IO)
|
56
|
+
return -1;
|
57
|
+
return ((fio_io_s *)obj)->fd;
|
58
|
+
}
|