iodine 0.7.60 → 0.8.0
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.
- checksums.yaml +4 -4
- data/.clang-format +15 -0
- data/.rspec +1 -0
- data/.yardopts +1 -3
- data/CHANGELOG.md +132 -12
- data/Gemfile +5 -7
- data/LICENSE.txt +1 -1
- data/README.md +147 -671
- data/Rakefile +9 -16
- data/examples/chatroom.nru +9 -0
- data/examples/client +74 -0
- data/examples/config-hello.nru +9 -0
- data/examples/config-hello.ru +11 -0
- data/examples/config-hijack.ru +13 -0
- data/examples/config-shootout.ru +43 -0
- data/examples/config.nru +120 -0
- data/examples/config.rb +37 -0
- data/examples/config.ru +42 -53
- data/examples/fake +24 -0
- data/examples/hello_neorack +137 -0
- data/examples/routes.nru +29 -0
- data/examples/routes.ru +42 -0
- data/exe/iodine +218 -258
- data/ext/iodine/extconf.rb +27 -100
- data/ext/iodine/fio-stl.h +128336 -0
- data/ext/iodine/fio-stl.md +26396 -0
- data/ext/iodine/iodine.c +213 -1393
- data/ext/iodine/iodine.h +250 -55
- data/ext/iodine/iodine_arg_helper.h +329 -0
- data/ext/iodine/iodine_caller.h +234 -25
- data/ext/iodine/iodine_cli.h +434 -0
- data/ext/iodine/iodine_compression.h +312 -0
- data/ext/iodine/iodine_connection.h +3484 -34
- data/ext/iodine/iodine_core.h +363 -0
- data/ext/iodine/iodine_crypto.h +1441 -0
- data/ext/iodine/iodine_defer.h +225 -4
- data/ext/iodine/iodine_json.h +738 -4
- data/ext/iodine/iodine_listener.h +263 -0
- data/ext/iodine/iodine_log.h +297 -0
- data/ext/iodine/iodine_minimap.h +543 -0
- data/ext/iodine/iodine_mustache.h +461 -4
- data/ext/iodine/iodine_pubsub_eng.h +729 -0
- data/ext/iodine/iodine_pubsub_history.h +547 -0
- data/ext/iodine/iodine_pubsub_msg.h +228 -0
- data/ext/iodine/iodine_redis.h +322 -0
- data/ext/iodine/iodine_store.h +418 -16
- data/ext/iodine/iodine_threads.h +279 -0
- data/ext/iodine/iodine_tls.h +515 -6
- data/ext/iodine/iodine_utils.h +923 -0
- data/iodine.gemspec +37 -42
- data/lib/iodine/benchmark.rb +1690 -0
- data/lib/iodine/documentation.rb +3085 -0
- data/lib/iodine/version.rb +17 -1
- data/lib/iodine.rb +54 -255
- data/logo.svg +36 -0
- data/mustache.md +55 -0
- data/sig/iodine.rbs +4 -0
- metadata +58 -184
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
- data/.github/workflows/ruby.yml +0 -42
- data/.gitignore +0 -21
- data/LIMITS.md +0 -41
- data/SPEC-PubSub-Draft.md +0 -159
- data/SPEC-WebSocket-Draft.md +0 -239
- data/bin/console +0 -22
- data/bin/info.md +0 -353
- data/bin/mustache_bench.rb +0 -100
- data/bin/poc/Gemfile.lock +0 -23
- data/bin/poc/README.md +0 -37
- data/bin/poc/config.ru +0 -66
- data/bin/poc/gemfile +0 -1
- data/bin/poc/www/index.html +0 -57
- data/examples/async_task.ru +0 -92
- data/examples/bates/README.md +0 -3
- data/examples/bates/config.ru +0 -342
- data/examples/bates/david+bold.pdf +0 -0
- data/examples/bates/public/drop-pdf.png +0 -0
- data/examples/bates/public/index.html +0 -600
- data/examples/echo.ru +0 -59
- data/examples/etag.ru +0 -16
- data/examples/hello.ru +0 -29
- data/examples/pubsub_engine.ru +0 -81
- data/examples/rack3.ru +0 -12
- data/examples/redis.ru +0 -70
- data/examples/shootout.ru +0 -73
- data/examples/sub-protocols.ru +0 -90
- data/examples/tcp_client.rb +0 -66
- data/examples/x-sendfile.ru +0 -14
- data/ext/iodine/fio.c +0 -11995
- data/ext/iodine/fio.h +0 -6371
- data/ext/iodine/fio_cli.c +0 -431
- data/ext/iodine/fio_cli.h +0 -189
- data/ext/iodine/fio_json_parser.h +0 -688
- data/ext/iodine/fio_siphash.c +0 -157
- data/ext/iodine/fio_siphash.h +0 -37
- data/ext/iodine/fio_tls.h +0 -129
- data/ext/iodine/fio_tls_missing.c +0 -649
- data/ext/iodine/fio_tls_openssl.c +0 -1106
- data/ext/iodine/fio_tmpfile.h +0 -50
- data/ext/iodine/fiobj.h +0 -44
- data/ext/iodine/fiobj4fio.h +0 -21
- data/ext/iodine/fiobj_ary.c +0 -333
- data/ext/iodine/fiobj_ary.h +0 -139
- data/ext/iodine/fiobj_data.c +0 -1187
- data/ext/iodine/fiobj_data.h +0 -167
- data/ext/iodine/fiobj_hash.c +0 -409
- data/ext/iodine/fiobj_hash.h +0 -176
- data/ext/iodine/fiobj_json.c +0 -622
- data/ext/iodine/fiobj_json.h +0 -68
- data/ext/iodine/fiobj_mem.h +0 -71
- data/ext/iodine/fiobj_mustache.c +0 -317
- data/ext/iodine/fiobj_mustache.h +0 -62
- data/ext/iodine/fiobj_numbers.c +0 -344
- data/ext/iodine/fiobj_numbers.h +0 -127
- data/ext/iodine/fiobj_str.c +0 -433
- data/ext/iodine/fiobj_str.h +0 -172
- data/ext/iodine/fiobject.c +0 -620
- data/ext/iodine/fiobject.h +0 -655
- data/ext/iodine/hpack.h +0 -1923
- data/ext/iodine/http.c +0 -2743
- data/ext/iodine/http.h +0 -1002
- data/ext/iodine/http1.c +0 -910
- data/ext/iodine/http1.h +0 -29
- data/ext/iodine/http1_parser.h +0 -878
- data/ext/iodine/http_internal.c +0 -1279
- data/ext/iodine/http_internal.h +0 -237
- data/ext/iodine/http_mime_parser.h +0 -350
- data/ext/iodine/iodine_caller.c +0 -230
- data/ext/iodine/iodine_connection.c +0 -941
- data/ext/iodine/iodine_defer.c +0 -420
- data/ext/iodine/iodine_fiobj2rb.h +0 -120
- data/ext/iodine/iodine_helpers.c +0 -282
- data/ext/iodine/iodine_helpers.h +0 -12
- data/ext/iodine/iodine_http.c +0 -1181
- data/ext/iodine/iodine_http.h +0 -23
- data/ext/iodine/iodine_json.c +0 -302
- data/ext/iodine/iodine_mustache.c +0 -567
- data/ext/iodine/iodine_pubsub.c +0 -580
- data/ext/iodine/iodine_pubsub.h +0 -26
- data/ext/iodine/iodine_rack_io.c +0 -273
- data/ext/iodine/iodine_rack_io.h +0 -20
- data/ext/iodine/iodine_store.c +0 -148
- data/ext/iodine/iodine_tcp.c +0 -346
- data/ext/iodine/iodine_tcp.h +0 -13
- data/ext/iodine/iodine_tls.c +0 -261
- data/ext/iodine/mustache_parser.h +0 -1546
- data/ext/iodine/redis_engine.c +0 -957
- data/ext/iodine/redis_engine.h +0 -79
- data/ext/iodine/resp_parser.h +0 -317
- data/ext/iodine/websocket_parser.h +0 -506
- data/ext/iodine/websockets.c +0 -743
- data/ext/iodine/websockets.h +0 -185
- data/lib/iodine/connection.rb +0 -61
- data/lib/iodine/json.rb +0 -42
- data/lib/iodine/mustache.rb +0 -113
- data/lib/iodine/pubsub.rb +0 -55
- data/lib/iodine/rack_utils.rb +0 -43
- data/lib/iodine/tls.rb +0 -16
- data/lib/rack/handler/iodine.rb +0 -33
- data/logo.png +0 -0
data/ext/iodine/fiobject.h
DELETED
|
@@ -1,655 +0,0 @@
|
|
|
1
|
-
#ifndef H_FIOBJECT_H
|
|
2
|
-
/*
|
|
3
|
-
Copyright: Boaz Segev, 2017-2019
|
|
4
|
-
License: MIT
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
This facil.io core library provides wrappers around complex and (or) dynamic
|
|
9
|
-
types, abstracting some complexity and making dynamic type related tasks easier.
|
|
10
|
-
*/
|
|
11
|
-
#define H_FIOBJECT_H
|
|
12
|
-
|
|
13
|
-
#ifndef _GNU_SOURCE
|
|
14
|
-
#define _GNU_SOURCE
|
|
15
|
-
#endif
|
|
16
|
-
|
|
17
|
-
#include <stdarg.h>
|
|
18
|
-
#include <stdint.h>
|
|
19
|
-
#include <stdio.h>
|
|
20
|
-
#include <stdlib.h>
|
|
21
|
-
|
|
22
|
-
#include <limits.h>
|
|
23
|
-
#include <stdarg.h>
|
|
24
|
-
#include <stdint.h>
|
|
25
|
-
#include <stdio.h>
|
|
26
|
-
#include <stdlib.h>
|
|
27
|
-
|
|
28
|
-
#include <fio_siphash.h>
|
|
29
|
-
|
|
30
|
-
#include <fio.h>
|
|
31
|
-
|
|
32
|
-
#if !defined(__GNUC__) && !defined(__clang__) && !defined(FIO_GNUC_BYPASS)
|
|
33
|
-
#define __attribute__(...)
|
|
34
|
-
#define __has_include(...) 0
|
|
35
|
-
#define __has_builtin(...) 0
|
|
36
|
-
#define FIO_GNUC_BYPASS 1
|
|
37
|
-
#elif !defined(__clang__) && !defined(__has_builtin)
|
|
38
|
-
#define __has_builtin(...) 0
|
|
39
|
-
#define FIO_GNUC_BYPASS 1
|
|
40
|
-
#endif
|
|
41
|
-
|
|
42
|
-
#ifdef __cplusplus
|
|
43
|
-
extern "C" {
|
|
44
|
-
#endif
|
|
45
|
-
|
|
46
|
-
/* *****************************************************************************
|
|
47
|
-
Core Types
|
|
48
|
-
***************************************************************************** */
|
|
49
|
-
|
|
50
|
-
typedef enum __attribute__((packed)) {
|
|
51
|
-
FIOBJ_T_NUMBER = 0x01,
|
|
52
|
-
FIOBJ_T_NULL = 0x06,
|
|
53
|
-
FIOBJ_T_TRUE = 0x16,
|
|
54
|
-
FIOBJ_T_FALSE = 0x26,
|
|
55
|
-
FIOBJ_T_FLOAT,
|
|
56
|
-
FIOBJ_T_STRING,
|
|
57
|
-
FIOBJ_T_ARRAY,
|
|
58
|
-
FIOBJ_T_HASH,
|
|
59
|
-
FIOBJ_T_DATA,
|
|
60
|
-
FIOBJ_T_UNKNOWN
|
|
61
|
-
} fiobj_type_enum;
|
|
62
|
-
|
|
63
|
-
typedef uintptr_t FIOBJ;
|
|
64
|
-
|
|
65
|
-
/** a Macro retriving an object's type. Use FIOBJ_TYPE_IS(x) for testing. */
|
|
66
|
-
#define FIOBJ_TYPE(obj) fiobj_type((obj))
|
|
67
|
-
#define FIOBJ_TYPE_IS(obj, type) fiobj_type_is((obj), (type))
|
|
68
|
-
#define FIOBJ_IS_NULL(obj) (!obj || obj == (FIOBJ)FIOBJ_T_NULL)
|
|
69
|
-
#define FIOBJ_INVALID 0
|
|
70
|
-
|
|
71
|
-
#ifndef FIO_STR_INFO_TYPE
|
|
72
|
-
/** A String information type, reports information about a C string. */
|
|
73
|
-
typedef struct fio_str_info_s {
|
|
74
|
-
size_t capa; /* Buffer capacity, if the string is writable. */
|
|
75
|
-
size_t len; /* String length. */
|
|
76
|
-
char *data; /* String's first byte. */
|
|
77
|
-
} fio_str_info_s;
|
|
78
|
-
#define FIO_STR_INFO_TYPE
|
|
79
|
-
#endif
|
|
80
|
-
|
|
81
|
-
/* *****************************************************************************
|
|
82
|
-
Primitives
|
|
83
|
-
***************************************************************************** */
|
|
84
|
-
|
|
85
|
-
#define FIO_INLINE static inline __attribute__((unused))
|
|
86
|
-
|
|
87
|
-
FIO_INLINE FIOBJ fiobj_null(void) { return (FIOBJ)FIOBJ_T_NULL; }
|
|
88
|
-
FIO_INLINE FIOBJ fiobj_true(void) { return (FIOBJ)FIOBJ_T_TRUE; }
|
|
89
|
-
FIO_INLINE FIOBJ fiobj_false(void) { return (FIOBJ)FIOBJ_T_FALSE; }
|
|
90
|
-
|
|
91
|
-
/* *****************************************************************************
|
|
92
|
-
Generic Object API
|
|
93
|
-
***************************************************************************** */
|
|
94
|
-
|
|
95
|
-
/** Returns a C string naming the objects dynamic type. */
|
|
96
|
-
FIO_INLINE const char *fiobj_type_name(const FIOBJ obj);
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Heuristic copy with a preference for copy reference(!) to minimize
|
|
100
|
-
* allocations.
|
|
101
|
-
*
|
|
102
|
-
* Always returns the value passed along.
|
|
103
|
-
*/
|
|
104
|
-
FIO_INLINE FIOBJ fiobj_dup(FIOBJ);
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Frees the object and any of it's "children".
|
|
108
|
-
*
|
|
109
|
-
* This function affects nested objects, meaning that when an Array or
|
|
110
|
-
* a Hash object is passed along, it's children (nested objects) are
|
|
111
|
-
* also freed.
|
|
112
|
-
*/
|
|
113
|
-
FIO_INLINE void fiobj_free(FIOBJ);
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Tests if an object evaluates as TRUE.
|
|
117
|
-
*
|
|
118
|
-
* This is object type specific. For example, empty strings might evaluate as
|
|
119
|
-
* FALSE, even though they aren't a boolean type.
|
|
120
|
-
*/
|
|
121
|
-
FIO_INLINE int fiobj_is_true(const FIOBJ);
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Returns an Object's numerical value.
|
|
125
|
-
*
|
|
126
|
-
* If a String is passed to the function, it will be parsed assuming base 10
|
|
127
|
-
* numerical data.
|
|
128
|
-
*
|
|
129
|
-
* Hashes and Arrays return their object count.
|
|
130
|
-
*
|
|
131
|
-
* IO objects return the length of their data.
|
|
132
|
-
*
|
|
133
|
-
* A type error results in 0.
|
|
134
|
-
*/
|
|
135
|
-
FIO_INLINE intptr_t fiobj_obj2num(const FIOBJ obj);
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Returns a Float's value.
|
|
139
|
-
*
|
|
140
|
-
* If a String is passed to the function, they will benparsed assuming base 10
|
|
141
|
-
* numerical data.
|
|
142
|
-
*
|
|
143
|
-
* A type error results in 0.
|
|
144
|
-
*/
|
|
145
|
-
FIO_INLINE double fiobj_obj2float(const FIOBJ obj);
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Returns a C String (NUL terminated) using the `fio_str_info_s` data type.
|
|
149
|
-
*
|
|
150
|
-
* The String is binary safe and might contain NUL bytes in the middle as well
|
|
151
|
-
* as a terminating NUL.
|
|
152
|
-
*
|
|
153
|
-
* If a Number or a Float are passed to the function, they
|
|
154
|
-
* will be parsed as a *temporary*, thread-safe, String.
|
|
155
|
-
*
|
|
156
|
-
* Numbers will be represented in base 10 numerical data.
|
|
157
|
-
*
|
|
158
|
-
* A type error results in NULL (i.e. object isn't a String).
|
|
159
|
-
*/
|
|
160
|
-
FIO_INLINE fio_str_info_s fiobj_obj2cstr(const FIOBJ obj);
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Calculates an Objects's SipHash value for possible use as a HashMap key.
|
|
164
|
-
*
|
|
165
|
-
* The Object MUST answer to the fiobj_obj2cstr, or the result is unusable. In
|
|
166
|
-
* other words, Hash Objects and Arrays can NOT be used for Hash keys.
|
|
167
|
-
*/
|
|
168
|
-
FIO_INLINE uint64_t fiobj_obj2hash(const FIOBJ o);
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Single layer iteration using a callback for each nested fio object.
|
|
172
|
-
*
|
|
173
|
-
* Accepts any `FIOBJ ` type but only collections (Arrays and Hashes) are
|
|
174
|
-
* processed. The container itself (the Array or the Hash) is **not** processed
|
|
175
|
-
* (unlike `fiobj_each2`).
|
|
176
|
-
*
|
|
177
|
-
* The callback task function must accept an object and an opaque user pointer.
|
|
178
|
-
*
|
|
179
|
-
* Hash objects pass along only the value object. The keys can be accessed using
|
|
180
|
-
* the `fiobj_hash_key_in_loop` function.
|
|
181
|
-
*
|
|
182
|
-
* If the callback returns -1, the loop is broken. Any other value is ignored.
|
|
183
|
-
*
|
|
184
|
-
* Returns the "stop" position, i.e., the number of items processed + the
|
|
185
|
-
* starting point.
|
|
186
|
-
*/
|
|
187
|
-
FIO_INLINE size_t fiobj_each1(FIOBJ, size_t start_at,
|
|
188
|
-
int (*task)(FIOBJ obj, void *arg), void *arg);
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Deep iteration using a callback for each fio object, including the parent.
|
|
192
|
-
*
|
|
193
|
-
* Accepts any `FIOBJ ` type.
|
|
194
|
-
*
|
|
195
|
-
* Collections (Arrays, Hashes) are deeply probed and shouldn't be edited
|
|
196
|
-
* during an `fiobj_each2` call (or weird things may happen).
|
|
197
|
-
*
|
|
198
|
-
* The callback task function must accept an object and an opaque user pointer.
|
|
199
|
-
*
|
|
200
|
-
* Hash objects keys are available using the `fiobj_hash_key_in_loop` function.
|
|
201
|
-
*
|
|
202
|
-
* Notice that when passing collections to the function, the collection itself
|
|
203
|
-
* is sent to the callback followed by it's children (if any). This is true also
|
|
204
|
-
* for nested collections (a nested Hash will be sent first, followed by the
|
|
205
|
-
* nested Hash's children and then followed by the rest of it's siblings.
|
|
206
|
-
*
|
|
207
|
-
* If the callback returns -1, the loop is broken. Any other value is ignored.
|
|
208
|
-
*/
|
|
209
|
-
size_t fiobj_each2(FIOBJ, int (*task)(FIOBJ obj, void *arg), void *arg);
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Deeply compare two objects. No hashing or recursive function calls are
|
|
213
|
-
* involved.
|
|
214
|
-
*
|
|
215
|
-
* Uses a similar algorithm to `fiobj_each2`, except adjusted to two objects.
|
|
216
|
-
*
|
|
217
|
-
* Hash objects are order sensitive. To be equal, Hash keys must match in order.
|
|
218
|
-
*
|
|
219
|
-
* Returns 1 if true and 0 if false.
|
|
220
|
-
*/
|
|
221
|
-
FIO_INLINE int fiobj_iseq(const FIOBJ obj1, const FIOBJ obj2);
|
|
222
|
-
|
|
223
|
-
/* *****************************************************************************
|
|
224
|
-
Object Type Identification
|
|
225
|
-
***************************************************************************** */
|
|
226
|
-
|
|
227
|
-
#define FIOBJECT_NUMBER_FLAG 1
|
|
228
|
-
|
|
229
|
-
#if UINTPTR_MAX < 0xFFFFFFFFFFFFFFFF
|
|
230
|
-
#define FIOBJECT_PRIMITIVE_FLAG 2
|
|
231
|
-
#define FIOBJECT_STRING_FLAG 0
|
|
232
|
-
#define FIOBJECT_HASH_FLAG 0
|
|
233
|
-
#define FIOBJECT_TYPE_MASK (~(uintptr_t)3)
|
|
234
|
-
#else
|
|
235
|
-
#define FIOBJECT_PRIMITIVE_FLAG 6
|
|
236
|
-
#define FIOBJECT_STRING_FLAG 2
|
|
237
|
-
#define FIOBJECT_HASH_FLAG 4
|
|
238
|
-
#define FIOBJECT_TYPE_MASK (~(uintptr_t)7)
|
|
239
|
-
#endif
|
|
240
|
-
|
|
241
|
-
#define FIOBJ_NUMBER_SIGN_MASK ((~((uintptr_t)0)) >> 1)
|
|
242
|
-
#define FIOBJ_NUMBER_SIGN_BIT (~FIOBJ_NUMBER_SIGN_MASK)
|
|
243
|
-
#define FIOBJ_NUMBER_SIGN_EXCLUDE_BIT (FIOBJ_NUMBER_SIGN_BIT >> 1)
|
|
244
|
-
|
|
245
|
-
#define FIOBJ_IS_ALLOCATED(o) \
|
|
246
|
-
((o) && ((o)&FIOBJECT_NUMBER_FLAG) == 0 && \
|
|
247
|
-
((o)&FIOBJECT_PRIMITIVE_FLAG) != FIOBJECT_PRIMITIVE_FLAG)
|
|
248
|
-
#define FIOBJ2PTR(o) ((void *)((o)&FIOBJECT_TYPE_MASK))
|
|
249
|
-
|
|
250
|
-
FIO_INLINE fiobj_type_enum fiobj_type(FIOBJ o) {
|
|
251
|
-
if (!o)
|
|
252
|
-
return FIOBJ_T_NULL;
|
|
253
|
-
if (o & FIOBJECT_NUMBER_FLAG)
|
|
254
|
-
return FIOBJ_T_NUMBER;
|
|
255
|
-
if ((o & FIOBJECT_PRIMITIVE_FLAG) == FIOBJECT_PRIMITIVE_FLAG)
|
|
256
|
-
return (fiobj_type_enum)o;
|
|
257
|
-
if (FIOBJECT_STRING_FLAG &&
|
|
258
|
-
(o & FIOBJECT_PRIMITIVE_FLAG) == FIOBJECT_STRING_FLAG)
|
|
259
|
-
return FIOBJ_T_STRING;
|
|
260
|
-
if (FIOBJECT_HASH_FLAG && (o & FIOBJECT_PRIMITIVE_FLAG) == FIOBJECT_HASH_FLAG)
|
|
261
|
-
return FIOBJ_T_HASH;
|
|
262
|
-
return ((fiobj_type_enum *)FIOBJ2PTR(o))[0];
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* This is faster than getting the type, since the switch statement is
|
|
267
|
-
* optimized away (it's calculated during compile time).
|
|
268
|
-
*/
|
|
269
|
-
FIO_INLINE size_t fiobj_type_is(FIOBJ o, fiobj_type_enum type) {
|
|
270
|
-
switch (type) {
|
|
271
|
-
case FIOBJ_T_NUMBER:
|
|
272
|
-
return (o & FIOBJECT_NUMBER_FLAG) ||
|
|
273
|
-
(o && !(o & FIOBJECT_PRIMITIVE_FLAG) &&
|
|
274
|
-
((fiobj_type_enum *)o)[0] == FIOBJ_T_NUMBER);
|
|
275
|
-
case FIOBJ_T_NULL:
|
|
276
|
-
return !o || o == fiobj_null();
|
|
277
|
-
case FIOBJ_T_TRUE:
|
|
278
|
-
return o == fiobj_true();
|
|
279
|
-
case FIOBJ_T_FALSE:
|
|
280
|
-
return o == fiobj_false();
|
|
281
|
-
case FIOBJ_T_STRING:
|
|
282
|
-
return (FIOBJECT_STRING_FLAG && (o & FIOBJECT_NUMBER_FLAG) == 0 &&
|
|
283
|
-
(o & FIOBJECT_PRIMITIVE_FLAG) == FIOBJECT_STRING_FLAG) ||
|
|
284
|
-
(FIOBJECT_STRING_FLAG == 0 && FIOBJ_IS_ALLOCATED(o) &&
|
|
285
|
-
((fiobj_type_enum *)FIOBJ2PTR(o))[0] == FIOBJ_T_STRING);
|
|
286
|
-
case FIOBJ_T_HASH:
|
|
287
|
-
if (FIOBJECT_HASH_FLAG) {
|
|
288
|
-
return ((o & FIOBJECT_NUMBER_FLAG) == 0 &&
|
|
289
|
-
(o & FIOBJECT_PRIMITIVE_FLAG) == FIOBJECT_HASH_FLAG);
|
|
290
|
-
}
|
|
291
|
-
/* fallthrough */
|
|
292
|
-
case FIOBJ_T_FLOAT:
|
|
293
|
-
case FIOBJ_T_ARRAY:
|
|
294
|
-
case FIOBJ_T_DATA:
|
|
295
|
-
case FIOBJ_T_UNKNOWN:
|
|
296
|
-
return FIOBJ_IS_ALLOCATED(o) &&
|
|
297
|
-
((fiobj_type_enum *)FIOBJ2PTR(o))[0] == type;
|
|
298
|
-
}
|
|
299
|
-
return FIOBJ_IS_ALLOCATED(o) && ((fiobj_type_enum *)FIOBJ2PTR(o))[0] == type;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/* *****************************************************************************
|
|
303
|
-
Object Header
|
|
304
|
-
***************************************************************************** */
|
|
305
|
-
|
|
306
|
-
typedef struct {
|
|
307
|
-
/* a String allowing logging type data. */
|
|
308
|
-
const char *class_name;
|
|
309
|
-
/* deallocate root object's memory, perform task for each nested object. */
|
|
310
|
-
void (*const dealloc)(FIOBJ, void (*task)(FIOBJ, void *), void *);
|
|
311
|
-
/* return the number of normal nested object */
|
|
312
|
-
uintptr_t (*const count)(const FIOBJ);
|
|
313
|
-
/* tests the object for truthfulness. */
|
|
314
|
-
size_t (*const is_true)(const FIOBJ);
|
|
315
|
-
/* tests if two objects are equal. */
|
|
316
|
-
size_t (*const is_eq)(const FIOBJ, const FIOBJ);
|
|
317
|
-
/* iterates through the normal nested objects (ignore deep nesting) */
|
|
318
|
-
size_t (*const each)(FIOBJ, size_t start_at, int (*task)(FIOBJ, void *),
|
|
319
|
-
void *);
|
|
320
|
-
/* object value as String */
|
|
321
|
-
fio_str_info_s (*const to_str)(const FIOBJ);
|
|
322
|
-
/* object value as Integer */
|
|
323
|
-
intptr_t (*const to_i)(const FIOBJ);
|
|
324
|
-
/* object value as Float */
|
|
325
|
-
double (*const to_f)(const FIOBJ);
|
|
326
|
-
} fiobj_object_vtable_s;
|
|
327
|
-
|
|
328
|
-
typedef struct {
|
|
329
|
-
/* must be first */
|
|
330
|
-
fiobj_type_enum type;
|
|
331
|
-
/* reference counter */
|
|
332
|
-
uint32_t ref;
|
|
333
|
-
} fiobj_object_header_s;
|
|
334
|
-
|
|
335
|
-
extern const fiobj_object_vtable_s FIOBJECT_VTABLE_NUMBER;
|
|
336
|
-
extern const fiobj_object_vtable_s FIOBJECT_VTABLE_FLOAT;
|
|
337
|
-
extern const fiobj_object_vtable_s FIOBJECT_VTABLE_STRING;
|
|
338
|
-
extern const fiobj_object_vtable_s FIOBJECT_VTABLE_ARRAY;
|
|
339
|
-
extern const fiobj_object_vtable_s FIOBJECT_VTABLE_HASH;
|
|
340
|
-
extern const fiobj_object_vtable_s FIOBJECT_VTABLE_DATA;
|
|
341
|
-
|
|
342
|
-
#define FIOBJECT2VTBL(o) fiobj_type_vtable(o)
|
|
343
|
-
#define FIOBJECT2HEAD(o) (((fiobj_object_header_s *)FIOBJ2PTR((o))))
|
|
344
|
-
|
|
345
|
-
FIO_INLINE const fiobj_object_vtable_s *fiobj_type_vtable(FIOBJ o) {
|
|
346
|
-
switch (FIOBJ_TYPE(o)) {
|
|
347
|
-
case FIOBJ_T_NUMBER:
|
|
348
|
-
return &FIOBJECT_VTABLE_NUMBER;
|
|
349
|
-
case FIOBJ_T_FLOAT:
|
|
350
|
-
return &FIOBJECT_VTABLE_FLOAT;
|
|
351
|
-
case FIOBJ_T_STRING:
|
|
352
|
-
return &FIOBJECT_VTABLE_STRING;
|
|
353
|
-
case FIOBJ_T_ARRAY:
|
|
354
|
-
return &FIOBJECT_VTABLE_ARRAY;
|
|
355
|
-
case FIOBJ_T_HASH:
|
|
356
|
-
return &FIOBJECT_VTABLE_HASH;
|
|
357
|
-
case FIOBJ_T_DATA:
|
|
358
|
-
return &FIOBJECT_VTABLE_DATA;
|
|
359
|
-
case FIOBJ_T_NULL:
|
|
360
|
-
case FIOBJ_T_TRUE:
|
|
361
|
-
case FIOBJ_T_FALSE:
|
|
362
|
-
case FIOBJ_T_UNKNOWN:
|
|
363
|
-
return NULL;
|
|
364
|
-
}
|
|
365
|
-
return NULL;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
/* *****************************************************************************
|
|
369
|
-
Atomic reference counting
|
|
370
|
-
***************************************************************************** */
|
|
371
|
-
|
|
372
|
-
/* C11 Atomics are defined? */
|
|
373
|
-
#if defined(__ATOMIC_RELAXED)
|
|
374
|
-
/** An atomic addition operation */
|
|
375
|
-
#define fiobj_ref_inc(o) \
|
|
376
|
-
__atomic_add_fetch(&FIOBJECT2HEAD(o)->ref, 1, __ATOMIC_SEQ_CST)
|
|
377
|
-
/** An atomic subtraction operation */
|
|
378
|
-
#define fiobj_ref_dec(o) \
|
|
379
|
-
__atomic_sub_fetch(&FIOBJECT2HEAD(o)->ref, 1, __ATOMIC_SEQ_CST)
|
|
380
|
-
|
|
381
|
-
/* Select the correct compiler builtin method. */
|
|
382
|
-
#elif defined(__has_builtin) && !FIO_GNUC_BYPASS
|
|
383
|
-
|
|
384
|
-
#if __has_builtin(__sync_fetch_and_or)
|
|
385
|
-
/** An atomic addition operation */
|
|
386
|
-
#define fiobj_ref_inc(o) __sync_add_and_fetch(&FIOBJECT2HEAD(o)->ref, 1)
|
|
387
|
-
/** An atomic subtraction operation */
|
|
388
|
-
#define fiobj_ref_dec(o) __sync_sub_and_fetch(&FIOBJECT2HEAD(o)->ref, 1)
|
|
389
|
-
|
|
390
|
-
#else
|
|
391
|
-
#error missing required atomic options.
|
|
392
|
-
#endif /* defined(__has_builtin) */
|
|
393
|
-
|
|
394
|
-
#elif __GNUC__ > 3
|
|
395
|
-
/** An atomic addition operation */
|
|
396
|
-
#define fiobj_ref_inc(o) __sync_add_and_fetch(&FIOBJECT2HEAD(o)->ref, 1)
|
|
397
|
-
/** An atomic subtraction operation */
|
|
398
|
-
#define fiobj_ref_dec(o) __sync_sub_and_fetch(&FIOBJECT2HEAD(o)->ref, 1)
|
|
399
|
-
|
|
400
|
-
#else
|
|
401
|
-
#error missing required atomic options.
|
|
402
|
-
#endif
|
|
403
|
-
|
|
404
|
-
#define OBJREF_ADD(o) fiobj_ref_inc(o)
|
|
405
|
-
#define OBJREF_REM(o) fiobj_ref_dec(o)
|
|
406
|
-
|
|
407
|
-
/* *****************************************************************************
|
|
408
|
-
Inlined Functions
|
|
409
|
-
***************************************************************************** */
|
|
410
|
-
|
|
411
|
-
/** Returns a C string naming the objects dynamic type. */
|
|
412
|
-
FIO_INLINE const char *fiobj_type_name(const FIOBJ o) {
|
|
413
|
-
if (o & FIOBJECT_NUMBER_FLAG)
|
|
414
|
-
return "Number";
|
|
415
|
-
if (FIOBJ_IS_ALLOCATED(o))
|
|
416
|
-
return FIOBJECT2VTBL(o)->class_name;
|
|
417
|
-
if (!o)
|
|
418
|
-
return "NULL";
|
|
419
|
-
return "Primitive";
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
/** used internally to free objects with nested objects. */
|
|
423
|
-
void fiobj_free_complex_object(FIOBJ o);
|
|
424
|
-
|
|
425
|
-
/**
|
|
426
|
-
* Copy by reference(!) - increases an object's (and any nested object's)
|
|
427
|
-
* reference count.
|
|
428
|
-
*
|
|
429
|
-
* Always returns the value passed along.
|
|
430
|
-
*/
|
|
431
|
-
FIO_INLINE FIOBJ fiobj_dup(FIOBJ o) {
|
|
432
|
-
if (FIOBJ_IS_ALLOCATED(o))
|
|
433
|
-
OBJREF_ADD(o);
|
|
434
|
-
return o;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
/**
|
|
438
|
-
* Decreases an object's reference count, releasing memory and
|
|
439
|
-
* resources.
|
|
440
|
-
*
|
|
441
|
-
* This function affects nested objects, meaning that when an Array or
|
|
442
|
-
* a Hash object is passed along, it's children (nested objects) are
|
|
443
|
-
* also freed.
|
|
444
|
-
*
|
|
445
|
-
* Returns the number of existing references or zero if memory was released.
|
|
446
|
-
*/
|
|
447
|
-
FIO_INLINE void fiobj_free(FIOBJ o) {
|
|
448
|
-
if (!FIOBJ_IS_ALLOCATED(o))
|
|
449
|
-
return;
|
|
450
|
-
if (fiobj_ref_dec(o))
|
|
451
|
-
return;
|
|
452
|
-
if (FIOBJECT2VTBL(o)->each && FIOBJECT2VTBL(o)->count(o))
|
|
453
|
-
fiobj_free_complex_object(o);
|
|
454
|
-
else
|
|
455
|
-
FIOBJECT2VTBL(o)->dealloc(o, NULL, NULL);
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
/**
|
|
459
|
-
* Tests if an object evaluates as TRUE.
|
|
460
|
-
*
|
|
461
|
-
* This is object type specific. For example, empty strings might evaluate as
|
|
462
|
-
* FALSE, even though they aren't a boolean type.
|
|
463
|
-
*/
|
|
464
|
-
FIO_INLINE int fiobj_is_true(const FIOBJ o) {
|
|
465
|
-
if (o & FIOBJECT_NUMBER_FLAG)
|
|
466
|
-
return ((uintptr_t)o >> 1) != 0;
|
|
467
|
-
if ((o & FIOBJECT_PRIMITIVE_FLAG) == FIOBJECT_PRIMITIVE_FLAG)
|
|
468
|
-
return o == FIOBJ_T_TRUE;
|
|
469
|
-
return (int)(FIOBJECT2VTBL(o)->is_true(o));
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
/**
|
|
473
|
-
* Returns an object's numerical value.
|
|
474
|
-
*
|
|
475
|
-
* If a String or Symbol are passed to the function, they will be
|
|
476
|
-
* parsed assuming base 10 numerical data.
|
|
477
|
-
*
|
|
478
|
-
* Hashes and Arrays return their object count.
|
|
479
|
-
*
|
|
480
|
-
* IO and File objects return their underlying file descriptor.
|
|
481
|
-
*
|
|
482
|
-
* A type error results in 0.
|
|
483
|
-
*/
|
|
484
|
-
FIO_INLINE intptr_t fiobj_obj2num(const FIOBJ o) {
|
|
485
|
-
if (o & FIOBJECT_NUMBER_FLAG) {
|
|
486
|
-
const uintptr_t sign =
|
|
487
|
-
(o & FIOBJ_NUMBER_SIGN_BIT)
|
|
488
|
-
? (FIOBJ_NUMBER_SIGN_BIT | FIOBJ_NUMBER_SIGN_EXCLUDE_BIT)
|
|
489
|
-
: 0;
|
|
490
|
-
return (intptr_t)(((o & FIOBJ_NUMBER_SIGN_MASK) >> 1) | sign);
|
|
491
|
-
}
|
|
492
|
-
if (!o || !FIOBJ_IS_ALLOCATED(o))
|
|
493
|
-
return o == FIOBJ_T_TRUE;
|
|
494
|
-
return FIOBJECT2VTBL(o)->to_i(o);
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
/** Converts a number to a temporary, thread safe, C string object */
|
|
498
|
-
fio_str_info_s fio_ltocstr(long);
|
|
499
|
-
|
|
500
|
-
/** Converts a float to a temporary, thread safe, C string object */
|
|
501
|
-
fio_str_info_s fio_ftocstr(double);
|
|
502
|
-
|
|
503
|
-
/**
|
|
504
|
-
* Returns a C String (NUL terminated) using the `fio_str_info_s` data type.
|
|
505
|
-
*
|
|
506
|
-
* The String is binary safe and might contain NUL bytes in the middle as well as
|
|
507
|
-
* a terminating NUL.
|
|
508
|
-
*
|
|
509
|
-
* If a a Number or a Float are passed to the function, they
|
|
510
|
-
* will be parsed as a *temporary*, thread-safe, String.
|
|
511
|
-
*
|
|
512
|
-
* Numbers will be represented in base 10 numerical data.
|
|
513
|
-
*
|
|
514
|
-
* A type error results in NULL (i.e. object isn't a String).
|
|
515
|
-
*/
|
|
516
|
-
FIO_INLINE fio_str_info_s fiobj_obj2cstr(const FIOBJ o) {
|
|
517
|
-
if (!o) {
|
|
518
|
-
fio_str_info_s ret = {0, 4, (char *)"null"};
|
|
519
|
-
return ret;
|
|
520
|
-
}
|
|
521
|
-
if (o & FIOBJECT_NUMBER_FLAG)
|
|
522
|
-
return fio_ltocstr(((intptr_t)o) >> 1);
|
|
523
|
-
if ((o & FIOBJECT_PRIMITIVE_FLAG) == FIOBJECT_PRIMITIVE_FLAG) {
|
|
524
|
-
switch ((fiobj_type_enum)o) {
|
|
525
|
-
case FIOBJ_T_NULL: {
|
|
526
|
-
fio_str_info_s ret = {0, 4, (char *)"null"};
|
|
527
|
-
return ret;
|
|
528
|
-
}
|
|
529
|
-
case FIOBJ_T_FALSE: {
|
|
530
|
-
fio_str_info_s ret = {0, 5, (char *)"false"};
|
|
531
|
-
return ret;
|
|
532
|
-
}
|
|
533
|
-
case FIOBJ_T_TRUE: {
|
|
534
|
-
fio_str_info_s ret = {0, 4, (char *)"true"};
|
|
535
|
-
return ret;
|
|
536
|
-
}
|
|
537
|
-
default:
|
|
538
|
-
break;
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
return FIOBJECT2VTBL(o)->to_str(o);
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
/* referenced here */
|
|
545
|
-
uint64_t fiobj_str_hash(FIOBJ o);
|
|
546
|
-
/**
|
|
547
|
-
* Calculates an Objects's SipHash value for possible use as a HashMap key.
|
|
548
|
-
*
|
|
549
|
-
* The Object MUST answer to the fiobj_obj2cstr, or the result is unusable. In
|
|
550
|
-
* other words, Hash Objects and Arrays can NOT be used for Hash keys.
|
|
551
|
-
*/
|
|
552
|
-
FIO_INLINE uint64_t fiobj_obj2hash(const FIOBJ o) {
|
|
553
|
-
if (FIOBJ_TYPE_IS(o, FIOBJ_T_STRING))
|
|
554
|
-
return fiobj_str_hash(o);
|
|
555
|
-
if (!FIOBJ_IS_ALLOCATED(o))
|
|
556
|
-
return (uint64_t)o;
|
|
557
|
-
fio_str_info_s s = fiobj_obj2cstr(o);
|
|
558
|
-
return FIO_HASH_FN(s.data, s.len, (uintptr_t)&fiobj_each2,
|
|
559
|
-
(uintptr_t)&fiobj_free_complex_object);
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
FIO_INLINE uint64_t fiobj_hash_string(const void *data, size_t len) {
|
|
563
|
-
return FIO_HASH_FN(data, len, (uintptr_t)&fiobj_each2,
|
|
564
|
-
(uintptr_t)&fiobj_free_complex_object);
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
/**
|
|
568
|
-
* Returns a Float's value.
|
|
569
|
-
*
|
|
570
|
-
* If a String or Symbol are passed to the function, they will be
|
|
571
|
-
* parsed assuming base 10 numerical data.
|
|
572
|
-
*
|
|
573
|
-
* Hashes and Arrays return their object count.
|
|
574
|
-
*
|
|
575
|
-
* IO and File objects return their underlying file descriptor.
|
|
576
|
-
*
|
|
577
|
-
* A type error results in 0.
|
|
578
|
-
*/
|
|
579
|
-
FIO_INLINE double fiobj_obj2float(const FIOBJ o) {
|
|
580
|
-
if (o & FIOBJECT_NUMBER_FLAG)
|
|
581
|
-
return (double)(fiobj_obj2num(o));
|
|
582
|
-
if (!o || (o & FIOBJECT_PRIMITIVE_FLAG) == FIOBJECT_PRIMITIVE_FLAG)
|
|
583
|
-
return (double)(o == FIOBJ_T_TRUE);
|
|
584
|
-
return FIOBJECT2VTBL(o)->to_f(o);
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
/** used internally for complext nested tests (Array / Hash types) */
|
|
588
|
-
int fiobj_iseq____internal_complex__(FIOBJ o, FIOBJ o2);
|
|
589
|
-
/**
|
|
590
|
-
* Deeply compare two objects. No hashing or recursive function calls are
|
|
591
|
-
* involved.
|
|
592
|
-
*
|
|
593
|
-
* Uses a similar algorithm to `fiobj_each2`, except adjusted to two objects.
|
|
594
|
-
*
|
|
595
|
-
* Hash order will be tested when comapring Hashes.
|
|
596
|
-
*
|
|
597
|
-
* KNOWN ISSUES:
|
|
598
|
-
*
|
|
599
|
-
* * Temporarily broken for collections (Arrays / Hashes).
|
|
600
|
-
*
|
|
601
|
-
* * Hash order will be tested as well as the Hash content, which means that
|
|
602
|
-
* equal Hashes might be considered unequal if their order doesn't match.
|
|
603
|
-
*
|
|
604
|
-
* Returns 1 if true and 0 if false.
|
|
605
|
-
*/
|
|
606
|
-
FIO_INLINE int fiobj_iseq(const FIOBJ o, const FIOBJ o2) {
|
|
607
|
-
if (o == o2)
|
|
608
|
-
return 1;
|
|
609
|
-
if (!o || !o2)
|
|
610
|
-
return 0; /* they should have compared equal before. */
|
|
611
|
-
if (!FIOBJ_IS_ALLOCATED(o) || !FIOBJ_IS_ALLOCATED(o2))
|
|
612
|
-
return 0; /* they should have compared equal before. */
|
|
613
|
-
if (FIOBJECT2HEAD(o)->type != FIOBJECT2HEAD(o2)->type)
|
|
614
|
-
return 0; /* non-type equality is a barriar to equality. */
|
|
615
|
-
if (!FIOBJECT2VTBL(o)->is_eq(o, o2))
|
|
616
|
-
return 0;
|
|
617
|
-
if (FIOBJECT2VTBL(o)->each && FIOBJECT2VTBL(o)->count(o))
|
|
618
|
-
return fiobj_iseq____internal_complex__((FIOBJ)o, (FIOBJ)o2);
|
|
619
|
-
return 1;
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
/**
|
|
623
|
-
* Single layer iteration using a callback for each nested fio object.
|
|
624
|
-
*
|
|
625
|
-
* Accepts any `FIOBJ ` type but only collections (Arrays and Hashes) are
|
|
626
|
-
* processed. The container itself (the Array or the Hash) is **not** processed
|
|
627
|
-
* (unlike `fiobj_each2`).
|
|
628
|
-
*
|
|
629
|
-
* The callback task function must accept an object and an opaque user pointer.
|
|
630
|
-
*
|
|
631
|
-
* Hash objects pass along a `FIOBJ_T_COUPLET` object, containing
|
|
632
|
-
* references for both the key and the object. Keys shouldn't be altered once
|
|
633
|
-
* placed as a key (or the Hash will break). Collections (Arrays / Hashes) can't
|
|
634
|
-
* be used as keeys.
|
|
635
|
-
*
|
|
636
|
-
* If the callback returns -1, the loop is broken. Any other value is ignored.
|
|
637
|
-
*
|
|
638
|
-
* Returns the "stop" position, i.e., the number of items processed + the
|
|
639
|
-
* starting point.
|
|
640
|
-
*/
|
|
641
|
-
FIO_INLINE size_t fiobj_each1(FIOBJ o, size_t start_at,
|
|
642
|
-
int (*task)(FIOBJ obj, void *arg), void *arg) {
|
|
643
|
-
if (FIOBJ_IS_ALLOCATED(o) && FIOBJECT2VTBL(o)->each)
|
|
644
|
-
return FIOBJECT2VTBL(o)->each(o, start_at, task, arg);
|
|
645
|
-
return 0;
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
#if DEBUG
|
|
649
|
-
void fiobj_test_core(void);
|
|
650
|
-
#endif
|
|
651
|
-
|
|
652
|
-
#ifdef __cplusplus
|
|
653
|
-
} /* closing brace for extern "C" */
|
|
654
|
-
#endif
|
|
655
|
-
#endif
|