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.
- 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
@@ -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
|
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
|
-
|
9
|
-
|
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 "
|
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
|
-
/*
|
29
|
-
#if defined(
|
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
|
-
|
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
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
int (*
|
243
|
-
|
244
|
-
|
245
|
-
|
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
|
-
|
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
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
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)
|
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))
|
273
|
-
#define OBJREF_REM(o) spn_sub(&OBJ2HEAD((o))
|
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
|
276
|
-
#define
|
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
|
-
|
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
|