iodine 0.7.59 → 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 -20
- 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 -146
- 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/fiobj_data.h
DELETED
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright: Boaz Segev, 2017-2019
|
|
3
|
-
License: MIT
|
|
4
|
-
*/
|
|
5
|
-
#if !defined(H_FIOBJ_IO_H) && (defined(__unix__) || defined(__APPLE__) || \
|
|
6
|
-
defined(__linux__) || defined(__CYGWIN__) || \
|
|
7
|
-
defined(__MINGW32__))
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* A dynamic type for reading / writing to a local file, a temporary file or an
|
|
11
|
-
* in-memory string.
|
|
12
|
-
*
|
|
13
|
-
* Supports basic reak, write, seek, puts and gets operations.
|
|
14
|
-
*
|
|
15
|
-
* Writing is always performed at the end of the stream / memory buffer,
|
|
16
|
-
* ignoring the current seek position.
|
|
17
|
-
*/
|
|
18
|
-
#define H_FIOBJ_IO_H
|
|
19
|
-
|
|
20
|
-
#include <fiobject.h>
|
|
21
|
-
|
|
22
|
-
#ifdef __cplusplus
|
|
23
|
-
extern "C" {
|
|
24
|
-
#endif
|
|
25
|
-
|
|
26
|
-
/* *****************************************************************************
|
|
27
|
-
Creating the Data Stream object
|
|
28
|
-
***************************************************************************** */
|
|
29
|
-
|
|
30
|
-
/** Creates a new local in-memory Data Stream object */
|
|
31
|
-
FIOBJ fiobj_data_newstr(void);
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Creates a Data object from an existing buffer. The buffer will be deallocated
|
|
35
|
-
* using the provided `dealloc` function pointer. Use a NULL `dealloc` function
|
|
36
|
-
* pointer if the buffer is static and shouldn't be freed.
|
|
37
|
-
*/
|
|
38
|
-
FIOBJ fiobj_data_newstr2(void *buffer, uintptr_t length,
|
|
39
|
-
void (*dealloc)(void *));
|
|
40
|
-
|
|
41
|
-
/** Creates a new local tempfile Data Stream object */
|
|
42
|
-
FIOBJ fiobj_data_newtmpfile(void);
|
|
43
|
-
|
|
44
|
-
/** Creates a new local file Data Stream object */
|
|
45
|
-
FIOBJ fiobj_data_newfd(int fd);
|
|
46
|
-
|
|
47
|
-
/** Creates a slice from an existing Data object. */
|
|
48
|
-
FIOBJ fiobj_data_slice(FIOBJ parent, intptr_t offset, uintptr_t length);
|
|
49
|
-
|
|
50
|
-
/* *****************************************************************************
|
|
51
|
-
Saving the Data Stream object
|
|
52
|
-
***************************************************************************** */
|
|
53
|
-
|
|
54
|
-
/** Creates a new local file Data Stream object */
|
|
55
|
-
int fiobj_data_save(FIOBJ io, const char *filename);
|
|
56
|
-
|
|
57
|
-
/* *****************************************************************************
|
|
58
|
-
Reading API
|
|
59
|
-
***************************************************************************** */
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Reads up to `length` bytes and returns a temporary(!) buffer object (not NUL
|
|
63
|
-
* terminated).
|
|
64
|
-
*
|
|
65
|
-
* If `length` is zero or negative, it will be computed from the end of the
|
|
66
|
-
* input backwards (0 == EOF).
|
|
67
|
-
*
|
|
68
|
-
* The C string object will be invalidate the next time a function call to the
|
|
69
|
-
* Data Stream object is made.
|
|
70
|
-
*/
|
|
71
|
-
fio_str_info_s fiobj_data_read(FIOBJ io, intptr_t length);
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Reads until the `token` byte is encountered or until the end of the stream.
|
|
75
|
-
*
|
|
76
|
-
* Returns a temporary(!) C string including the end of line marker.
|
|
77
|
-
*
|
|
78
|
-
* Careful when using this call on large file streams, as the whole file
|
|
79
|
-
* stream might be loaded into the memory.
|
|
80
|
-
*
|
|
81
|
-
* The C string object will be invalidate the next time a function call to the
|
|
82
|
-
* Data Stream object is made.
|
|
83
|
-
*/
|
|
84
|
-
fio_str_info_s fiobj_data_read2ch(FIOBJ io, uint8_t token);
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Reads a line (until the '\n' byte is encountered) or until the end of the
|
|
88
|
-
* available data.
|
|
89
|
-
*
|
|
90
|
-
* Returns a temporary(!) buffer object (not NUL terminated) including the end
|
|
91
|
-
* of line marker.
|
|
92
|
-
*
|
|
93
|
-
* Careful when using this call on large file streams, as the whole file stream
|
|
94
|
-
* might be loaded into the memory.
|
|
95
|
-
*
|
|
96
|
-
* The C string object will be invalidate the next time a function call to the
|
|
97
|
-
* Data Stream object is made.
|
|
98
|
-
*/
|
|
99
|
-
#define fiobj_data_gets(io) fiobj_data_read2ch((io), '\n');
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Returns the current reading position. Returns -1 on error.
|
|
103
|
-
*/
|
|
104
|
-
intptr_t fiobj_data_pos(FIOBJ io);
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Returns the length of the stream.
|
|
108
|
-
*/
|
|
109
|
-
intptr_t fiobj_data_len(FIOBJ io);
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Moves the reading position to the requested position.
|
|
113
|
-
*/
|
|
114
|
-
void fiobj_data_seek(FIOBJ io, intptr_t position);
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Reads up to `length` bytes starting at `start_at` position and returns a
|
|
118
|
-
* temporary(!) buffer object (not NUL terminated) string object. The reading
|
|
119
|
-
* position is ignored and unchanged.
|
|
120
|
-
*
|
|
121
|
-
* The C string object will be invalidate the next time a function call to the
|
|
122
|
-
* Data Stream object is made.
|
|
123
|
-
*/
|
|
124
|
-
fio_str_info_s fiobj_data_pread(FIOBJ io, intptr_t start_at, uintptr_t length);
|
|
125
|
-
|
|
126
|
-
/* *****************************************************************************
|
|
127
|
-
Writing API
|
|
128
|
-
***************************************************************************** */
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Writes `length` bytes at the end of the Data Stream stream, ignoring the
|
|
132
|
-
* reading position.
|
|
133
|
-
*
|
|
134
|
-
* Behaves and returns the same value as the system call `write`.
|
|
135
|
-
*/
|
|
136
|
-
intptr_t fiobj_data_write(FIOBJ io, void *buffer, uintptr_t length);
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Writes `length` bytes at the end of the Data Stream stream, ignoring the
|
|
140
|
-
* reading position, adding an EOL marker ("\r\n") to the end of the stream.
|
|
141
|
-
*
|
|
142
|
-
* Behaves and returns the same value as the system call `write`.
|
|
143
|
-
*/
|
|
144
|
-
intptr_t fiobj_data_puts(FIOBJ io, void *buffer, uintptr_t length);
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Makes sure the Data Stream object isn't attached to a static or external
|
|
148
|
-
* string.
|
|
149
|
-
*
|
|
150
|
-
* If the Data Stream object is attached to a static or external string, the
|
|
151
|
-
* data will be copied to a new memory block.
|
|
152
|
-
*
|
|
153
|
-
* If the Data Stream object is a slice from another Data Stream object, the
|
|
154
|
-
* data will be copied and the type of Data Stream object (memory vs. tmpfile)
|
|
155
|
-
* will be inherited.
|
|
156
|
-
*/
|
|
157
|
-
void fiobj_data_assert_dynamic(FIOBJ io);
|
|
158
|
-
|
|
159
|
-
#if DEBUG
|
|
160
|
-
void fiobj_data_test(void);
|
|
161
|
-
#endif
|
|
162
|
-
|
|
163
|
-
#ifdef __cplusplus
|
|
164
|
-
}
|
|
165
|
-
#endif
|
|
166
|
-
|
|
167
|
-
#endif
|
data/ext/iodine/fiobj_hash.c
DELETED
|
@@ -1,409 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright: Boaz Segev, 2017-2019
|
|
3
|
-
License: MIT
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
#include <fiobject.h>
|
|
7
|
-
|
|
8
|
-
#include <assert.h>
|
|
9
|
-
#include <fiobj_hash.h>
|
|
10
|
-
|
|
11
|
-
#define FIO_SET_CALLOC(size, count) fio_calloc((size), (count))
|
|
12
|
-
#define FIO_SET_REALLOC(ptr, original_size, size, valid_data_length) \
|
|
13
|
-
fio_realloc2((ptr), (size), (valid_data_length))
|
|
14
|
-
#define FIO_SET_FREE(ptr, size) fio_free((ptr))
|
|
15
|
-
|
|
16
|
-
#define FIO_SET_NAME fio_hash__
|
|
17
|
-
#define FIO_SET_KEY_TYPE FIOBJ
|
|
18
|
-
#define FIO_SET_KEY_COMPARE(o1, o2) \
|
|
19
|
-
((o2) == ((FIOBJ)-1) || (o1) == ((FIOBJ)-1) || fiobj_iseq((o1), (o2)))
|
|
20
|
-
#define FIO_SET_KEY_COPY(dest, obj) ((dest) = fiobj_dup((obj)))
|
|
21
|
-
#define FIO_SET_KEY_DESTROY(obj) \
|
|
22
|
-
do { \
|
|
23
|
-
fiobj_free((obj)); \
|
|
24
|
-
(obj) = FIOBJ_INVALID; \
|
|
25
|
-
} while (0)
|
|
26
|
-
#define FIO_SET_OBJ_TYPE FIOBJ
|
|
27
|
-
#define FIO_SET_OBJ_COMPARE(o1, o2) fiobj_iseq((o1), (o2))
|
|
28
|
-
#define FIO_SET_OBJ_COPY(dest, obj) ((dest) = fiobj_dup(obj))
|
|
29
|
-
#define FIO_SET_OBJ_DESTROY(obj) \
|
|
30
|
-
do { \
|
|
31
|
-
fiobj_free((obj)); \
|
|
32
|
-
(obj) = FIOBJ_INVALID; \
|
|
33
|
-
} while (0)
|
|
34
|
-
|
|
35
|
-
#include <fio.h>
|
|
36
|
-
|
|
37
|
-
#include <errno.h>
|
|
38
|
-
|
|
39
|
-
#include <pthread.h>
|
|
40
|
-
|
|
41
|
-
/* *****************************************************************************
|
|
42
|
-
Hash types
|
|
43
|
-
***************************************************************************** */
|
|
44
|
-
typedef struct {
|
|
45
|
-
fiobj_object_header_s head;
|
|
46
|
-
fio_hash___s hash;
|
|
47
|
-
} fiobj_hash_s;
|
|
48
|
-
|
|
49
|
-
#define obj2hash(o) ((fiobj_hash_s *)(FIOBJ2PTR(o)))
|
|
50
|
-
|
|
51
|
-
void fiobj_hash_rehash(FIOBJ h) {
|
|
52
|
-
assert(h && FIOBJ_TYPE_IS(h, FIOBJ_T_HASH));
|
|
53
|
-
fio_hash___rehash(&obj2hash(h)->hash);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/* *****************************************************************************
|
|
57
|
-
Hash alloc + VTable
|
|
58
|
-
***************************************************************************** */
|
|
59
|
-
|
|
60
|
-
static void fiobj_hash_dealloc(FIOBJ o, void (*task)(FIOBJ, void *),
|
|
61
|
-
void *arg) {
|
|
62
|
-
FIO_SET_FOR_LOOP(&obj2hash(o)->hash, i) {
|
|
63
|
-
if (i->obj.key)
|
|
64
|
-
task((FIOBJ)i->obj.obj, arg);
|
|
65
|
-
fiobj_free((FIOBJ)i->obj.key);
|
|
66
|
-
i->obj.key = FIOBJ_INVALID;
|
|
67
|
-
i->obj.obj = FIOBJ_INVALID;
|
|
68
|
-
}
|
|
69
|
-
obj2hash(o)->hash.count = 0;
|
|
70
|
-
fio_hash___free(&obj2hash(o)->hash);
|
|
71
|
-
fio_free(FIOBJ2PTR(o));
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
static pthread_key_t each_at_key;
|
|
75
|
-
static pthread_once_t each_at_key_once = PTHREAD_ONCE_INIT;
|
|
76
|
-
static void init_each_at_key(void) {
|
|
77
|
-
pthread_key_create(&each_at_key, free);
|
|
78
|
-
}
|
|
79
|
-
static void init_each_at_key_ptr(void) {
|
|
80
|
-
FIOBJ *eak = malloc(sizeof(FIOBJ));
|
|
81
|
-
FIO_ASSERT_ALLOC(eak);
|
|
82
|
-
*eak = FIOBJ_INVALID;
|
|
83
|
-
pthread_setspecific(each_at_key, eak);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
static size_t fiobj_hash_each1(FIOBJ o, size_t start_at,
|
|
87
|
-
int (*task)(FIOBJ obj, void *arg), void *arg) {
|
|
88
|
-
assert(o && FIOBJ_TYPE_IS(o, FIOBJ_T_HASH));
|
|
89
|
-
pthread_once(&each_at_key_once, init_each_at_key);
|
|
90
|
-
FIOBJ *each_at_key_ptr = (FIOBJ *)pthread_getspecific(each_at_key);
|
|
91
|
-
if (!each_at_key_ptr) {
|
|
92
|
-
init_each_at_key_ptr();
|
|
93
|
-
each_at_key_ptr = (FIOBJ *)pthread_getspecific(each_at_key);
|
|
94
|
-
}
|
|
95
|
-
FIOBJ old_each_at_key = *each_at_key_ptr;
|
|
96
|
-
fio_hash___s *hash = &obj2hash(o)->hash;
|
|
97
|
-
size_t count = 0;
|
|
98
|
-
if (hash->count == hash->pos) {
|
|
99
|
-
/* no holes in the hash, we can work as we please. */
|
|
100
|
-
for (count = start_at; count < hash->count; ++count) {
|
|
101
|
-
*each_at_key_ptr = hash->ordered[count].obj.key;
|
|
102
|
-
if (task((FIOBJ)hash->ordered[count].obj.obj, arg) == -1) {
|
|
103
|
-
++count;
|
|
104
|
-
goto end;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
} else {
|
|
108
|
-
size_t pos = 0;
|
|
109
|
-
for (; pos < start_at && pos < hash->pos; ++pos) {
|
|
110
|
-
/* counting */
|
|
111
|
-
if (hash->ordered[pos].obj.key == FIOBJ_INVALID)
|
|
112
|
-
++start_at;
|
|
113
|
-
else
|
|
114
|
-
++count;
|
|
115
|
-
}
|
|
116
|
-
for (; pos < hash->pos; ++pos) {
|
|
117
|
-
/* performing */
|
|
118
|
-
if (hash->ordered[pos].obj.key == FIOBJ_INVALID)
|
|
119
|
-
continue;
|
|
120
|
-
++count;
|
|
121
|
-
*each_at_key_ptr = hash->ordered[pos].obj.key;
|
|
122
|
-
if (task((FIOBJ)hash->ordered[pos].obj.obj, arg) == -1)
|
|
123
|
-
break;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
end:
|
|
127
|
-
*each_at_key_ptr = old_each_at_key;
|
|
128
|
-
return count;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
FIOBJ fiobj_hash_key_in_loop(void) {
|
|
132
|
-
pthread_once(&each_at_key_once, init_each_at_key);
|
|
133
|
-
FIOBJ *each_at_key_ptr = (FIOBJ *)pthread_getspecific(each_at_key);
|
|
134
|
-
if (!each_at_key_ptr) {
|
|
135
|
-
init_each_at_key_ptr();
|
|
136
|
-
each_at_key_ptr = (FIOBJ *)pthread_getspecific(each_at_key);
|
|
137
|
-
}
|
|
138
|
-
return *each_at_key_ptr;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
static size_t fiobj_hash_is_eq(const FIOBJ self, const FIOBJ other) {
|
|
142
|
-
if (fio_hash___count(&obj2hash(self)->hash) !=
|
|
143
|
-
fio_hash___count(&obj2hash(other)->hash))
|
|
144
|
-
return 0;
|
|
145
|
-
return 1;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/** Returns the number of elements in the Array. */
|
|
149
|
-
size_t fiobj_hash_count(const FIOBJ o) {
|
|
150
|
-
assert(o && FIOBJ_TYPE_IS(o, FIOBJ_T_HASH));
|
|
151
|
-
return fio_hash___count(&obj2hash(o)->hash);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
intptr_t fiobj_hash2num(const FIOBJ o) { return (intptr_t)fiobj_hash_count(o); }
|
|
155
|
-
|
|
156
|
-
static size_t fiobj_hash_is_true(const FIOBJ o) {
|
|
157
|
-
return fiobj_hash_count(o) != 0;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
fio_str_info_s fiobject___noop_to_str(const FIOBJ o);
|
|
161
|
-
intptr_t fiobject___noop_to_i(const FIOBJ o);
|
|
162
|
-
double fiobject___noop_to_f(const FIOBJ o);
|
|
163
|
-
|
|
164
|
-
const fiobj_object_vtable_s FIOBJECT_VTABLE_HASH = {
|
|
165
|
-
.class_name = "Hash",
|
|
166
|
-
.dealloc = fiobj_hash_dealloc,
|
|
167
|
-
.is_eq = fiobj_hash_is_eq,
|
|
168
|
-
.count = fiobj_hash_count,
|
|
169
|
-
.each = fiobj_hash_each1,
|
|
170
|
-
.is_true = fiobj_hash_is_true,
|
|
171
|
-
.to_str = fiobject___noop_to_str,
|
|
172
|
-
.to_i = fiobj_hash2num,
|
|
173
|
-
.to_f = fiobject___noop_to_f,
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
/* *****************************************************************************
|
|
177
|
-
Hash API
|
|
178
|
-
***************************************************************************** */
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Creates a mutable empty Hash object. Use `fiobj_free` when done.
|
|
182
|
-
*
|
|
183
|
-
* Notice that these Hash objects are designed for smaller collections and
|
|
184
|
-
* retain order of object insertion.
|
|
185
|
-
*/
|
|
186
|
-
FIOBJ fiobj_hash_new(void) {
|
|
187
|
-
fiobj_hash_s *h = fio_malloc(sizeof(*h));
|
|
188
|
-
FIO_ASSERT_ALLOC(h);
|
|
189
|
-
*h = (fiobj_hash_s){.head = {.ref = 1, .type = FIOBJ_T_HASH},
|
|
190
|
-
.hash = FIO_SET_INIT};
|
|
191
|
-
return (FIOBJ)h | FIOBJECT_HASH_FLAG;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Creates a mutable empty Hash object with an initial capacity of `capa`. Use
|
|
196
|
-
* `fiobj_free` when done.
|
|
197
|
-
*
|
|
198
|
-
* Notice that these Hash objects are designed for smaller collections and
|
|
199
|
-
* retain order of object insertion.
|
|
200
|
-
*/
|
|
201
|
-
FIOBJ fiobj_hash_new2(size_t capa) {
|
|
202
|
-
fiobj_hash_s *h = fio_malloc(sizeof(*h));
|
|
203
|
-
FIO_ASSERT_ALLOC(h);
|
|
204
|
-
*h = (fiobj_hash_s){.head = {.ref = 1, .type = FIOBJ_T_HASH},
|
|
205
|
-
.hash = FIO_SET_INIT};
|
|
206
|
-
fio_hash___capa_require(&h->hash, capa);
|
|
207
|
-
return (FIOBJ)h | FIOBJECT_HASH_FLAG;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Returns a temporary theoretical Hash map capacity.
|
|
212
|
-
* This could be used for testing performance and memory consumption.
|
|
213
|
-
*/
|
|
214
|
-
size_t fiobj_hash_capa(const FIOBJ hash) {
|
|
215
|
-
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
|
216
|
-
return fio_hash___capa(&obj2hash(hash)->hash);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Sets a key-value pair in the Hash, duplicating the Symbol and **moving**
|
|
221
|
-
* the ownership of the object to the Hash.
|
|
222
|
-
*
|
|
223
|
-
* Returns -1 on error.
|
|
224
|
-
*/
|
|
225
|
-
int fiobj_hash_set(FIOBJ hash, FIOBJ key, FIOBJ obj) {
|
|
226
|
-
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
|
227
|
-
if (FIOBJ_TYPE_IS(key, FIOBJ_T_STRING))
|
|
228
|
-
fiobj_str_freeze(key);
|
|
229
|
-
fio_hash___insert(&obj2hash(hash)->hash, fiobj_obj2hash(key), key, obj, NULL);
|
|
230
|
-
fiobj_free(obj); /* take ownership - free the user's reference. */
|
|
231
|
-
return 0;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Allows the Hash to be used as a stack.
|
|
236
|
-
*
|
|
237
|
-
* If a pointer `key` is provided, it will receive ownership of the key
|
|
238
|
-
* (remember to free).
|
|
239
|
-
*
|
|
240
|
-
* Returns FIOBJ_INVALID on error.
|
|
241
|
-
*
|
|
242
|
-
* Returns and object if successful (remember to free).
|
|
243
|
-
*/
|
|
244
|
-
FIOBJ fiobj_hash_pop(FIOBJ hash, FIOBJ *key) {
|
|
245
|
-
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
|
246
|
-
FIOBJ old;
|
|
247
|
-
if (fio_hash___count(&obj2hash(hash)->hash))
|
|
248
|
-
return FIOBJ_INVALID;
|
|
249
|
-
old = fiobj_dup(fio_hash___last(&obj2hash(hash)->hash).obj);
|
|
250
|
-
if (key)
|
|
251
|
-
*key = fiobj_dup(fio_hash___last(&obj2hash(hash)->hash).key);
|
|
252
|
-
fio_hash___pop(&obj2hash(hash)->hash);
|
|
253
|
-
return old;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* Replaces the value in a key-value pair, returning the old value (and it's
|
|
258
|
-
* ownership) to the caller.
|
|
259
|
-
*
|
|
260
|
-
* A return value of NULL indicates that no previous object existed (but a new
|
|
261
|
-
* key-value pair was created.
|
|
262
|
-
*
|
|
263
|
-
* Errors are silently ignored.
|
|
264
|
-
*/
|
|
265
|
-
FIOBJ fiobj_hash_replace(FIOBJ hash, FIOBJ key, FIOBJ obj) {
|
|
266
|
-
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
|
267
|
-
FIOBJ old = FIOBJ_INVALID;
|
|
268
|
-
fio_hash___insert(&obj2hash(hash)->hash, fiobj_obj2hash(key), key, obj, &old);
|
|
269
|
-
fiobj_free(obj); /* take ownership - free the user's reference. */
|
|
270
|
-
return old;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Removes a key-value pair from the Hash, if it exists.
|
|
275
|
-
*/
|
|
276
|
-
FIOBJ fiobj_hash_remove(FIOBJ hash, FIOBJ key) {
|
|
277
|
-
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
|
278
|
-
FIOBJ old = FIOBJ_INVALID;
|
|
279
|
-
fio_hash___remove(&obj2hash(hash)->hash, fiobj_obj2hash(key), key, &old);
|
|
280
|
-
return old;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* Removes a key-value pair from the Hash, if it exists, returning the old
|
|
285
|
-
* object (instead of freeing it).
|
|
286
|
-
*/
|
|
287
|
-
FIOBJ fiobj_hash_remove2(FIOBJ hash, uint64_t hash_value) {
|
|
288
|
-
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
|
289
|
-
FIOBJ old = FIOBJ_INVALID;
|
|
290
|
-
fio_hash___remove(&obj2hash(hash)->hash, hash_value, -1, &old);
|
|
291
|
-
return old;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Deletes a key-value pair from the Hash, if it exists, freeing the
|
|
296
|
-
* associated object.
|
|
297
|
-
*
|
|
298
|
-
* Returns -1 on type error or if the object never existed.
|
|
299
|
-
*/
|
|
300
|
-
int fiobj_hash_delete(FIOBJ hash, FIOBJ key) {
|
|
301
|
-
return fio_hash___remove(&obj2hash(hash)->hash, fiobj_obj2hash(key), key,
|
|
302
|
-
NULL);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Deletes a key-value pair from the Hash, if it exists, freeing the
|
|
307
|
-
* associated object.
|
|
308
|
-
*
|
|
309
|
-
* This function takes a `uintptr_t` Hash value (see `fio_siphash`) to
|
|
310
|
-
* perform a lookup in the HashMap, which is slightly faster than the other
|
|
311
|
-
* variations.
|
|
312
|
-
*
|
|
313
|
-
* Returns -1 on type error or if the object never existed.
|
|
314
|
-
*/
|
|
315
|
-
int fiobj_hash_delete2(FIOBJ hash, uint64_t key_hash) {
|
|
316
|
-
return fio_hash___remove(&obj2hash(hash)->hash, key_hash, -1, NULL);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* Returns a temporary handle to the object associated with the Symbol, NULL
|
|
321
|
-
* if none.
|
|
322
|
-
*/
|
|
323
|
-
FIOBJ fiobj_hash_get(const FIOBJ hash, FIOBJ key) {
|
|
324
|
-
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
|
325
|
-
return fio_hash___find(&obj2hash(hash)->hash, fiobj_obj2hash(key), key);
|
|
326
|
-
;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
/**
|
|
330
|
-
* Returns a temporary handle to the object associated hashed key value.
|
|
331
|
-
*
|
|
332
|
-
* This function takes a `uintptr_t` Hash value (see `fio_siphash`) to
|
|
333
|
-
* perform a lookup in the HashMap.
|
|
334
|
-
*
|
|
335
|
-
* Returns NULL if no object is associated with this hashed key value.
|
|
336
|
-
*/
|
|
337
|
-
FIOBJ fiobj_hash_get2(const FIOBJ hash, uint64_t key_hash) {
|
|
338
|
-
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
|
339
|
-
return fio_hash___find(&obj2hash(hash)->hash, key_hash, -1);
|
|
340
|
-
;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* Returns 1 if the key (Symbol) exists in the Hash, even if value is NULL.
|
|
345
|
-
*/
|
|
346
|
-
int fiobj_hash_haskey(const FIOBJ hash, FIOBJ key) {
|
|
347
|
-
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
|
348
|
-
return fio_hash___find(&obj2hash(hash)->hash, fiobj_obj2hash(key), key) !=
|
|
349
|
-
FIOBJ_INVALID;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Empties the Hash.
|
|
354
|
-
*/
|
|
355
|
-
void fiobj_hash_clear(const FIOBJ hash) {
|
|
356
|
-
assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
|
|
357
|
-
fio_hash___free(&obj2hash(hash)->hash);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/* *****************************************************************************
|
|
361
|
-
Simple Tests
|
|
362
|
-
***************************************************************************** */
|
|
363
|
-
|
|
364
|
-
#if DEBUG
|
|
365
|
-
void fiobj_test_hash(void) {
|
|
366
|
-
fprintf(stderr, "=== Testing Hash\n");
|
|
367
|
-
#define TEST_ASSERT(cond, ...) \
|
|
368
|
-
if (!(cond)) { \
|
|
369
|
-
fprintf(stderr, "* " __VA_ARGS__); \
|
|
370
|
-
fprintf(stderr, "Testing failed.\n"); \
|
|
371
|
-
exit(-1); \
|
|
372
|
-
}
|
|
373
|
-
FIOBJ o = fiobj_hash_new();
|
|
374
|
-
FIOBJ str_key = fiobj_str_new("Hello World!", 12);
|
|
375
|
-
TEST_ASSERT(FIOBJ_TYPE_IS(o, FIOBJ_T_HASH), "Type identification error!\n");
|
|
376
|
-
TEST_ASSERT(fiobj_hash_count(o) == 0, "Hash should be empty!\n");
|
|
377
|
-
fiobj_hash_set(o, str_key, fiobj_true());
|
|
378
|
-
TEST_ASSERT(fiobj_str_write(str_key, "should fail...", 13) == 0,
|
|
379
|
-
"wrote to frozen string?");
|
|
380
|
-
TEST_ASSERT(fiobj_obj2cstr(str_key).len == 12,
|
|
381
|
-
"String was mutated (not frozen)!\n");
|
|
382
|
-
TEST_ASSERT(fiobj_hash_get(o, str_key) == fiobj_true(),
|
|
383
|
-
"full compare didn't get value back");
|
|
384
|
-
TEST_ASSERT(fiobj_hash_get2(o, fiobj_obj2hash(str_key)) == fiobj_true(),
|
|
385
|
-
"hash compare didn't get value back");
|
|
386
|
-
|
|
387
|
-
FIOBJ o2 = fiobj_hash_new2(3);
|
|
388
|
-
TEST_ASSERT(obj2hash(o2)->hash.capa >= 3,
|
|
389
|
-
"Hash capacity should be larger than 3! %zu != 4\n",
|
|
390
|
-
(size_t)obj2hash(o2)->hash.capa);
|
|
391
|
-
fiobj_hash_set(o2, str_key, fiobj_true());
|
|
392
|
-
TEST_ASSERT(fiobj_hash_is_eq(o, o2), "Hashes not equal at core! %zu != %zu\n",
|
|
393
|
-
fiobj_hash_count(o), fiobj_hash_count(o2));
|
|
394
|
-
TEST_ASSERT(fiobj_iseq(o, o2), "Hashes not equal!\n");
|
|
395
|
-
TEST_ASSERT(obj2hash(o2)->hash.capa > 3,
|
|
396
|
-
"Hash capacity should be larger than 3! %zu != 4\n",
|
|
397
|
-
(size_t)obj2hash(o2)->hash.capa);
|
|
398
|
-
|
|
399
|
-
fiobj_hash_delete(o, str_key);
|
|
400
|
-
|
|
401
|
-
TEST_ASSERT(fiobj_hash_get2(o, fiobj_obj2hash(str_key)) == 0,
|
|
402
|
-
"item wasn't deleted!");
|
|
403
|
-
fiobj_free(
|
|
404
|
-
str_key); /* note that a copy will remain in the Hash until rehashing. */
|
|
405
|
-
fiobj_free(o);
|
|
406
|
-
fiobj_free(o2);
|
|
407
|
-
fprintf(stderr, "* passed.\n");
|
|
408
|
-
}
|
|
409
|
-
#endif
|