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.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/.clang-format +15 -0
  3. data/.rspec +1 -0
  4. data/.yardopts +1 -3
  5. data/CHANGELOG.md +132 -12
  6. data/Gemfile +5 -7
  7. data/LICENSE.txt +1 -1
  8. data/README.md +147 -671
  9. data/Rakefile +9 -16
  10. data/examples/chatroom.nru +9 -0
  11. data/examples/client +74 -0
  12. data/examples/config-hello.nru +9 -0
  13. data/examples/config-hello.ru +11 -0
  14. data/examples/config-hijack.ru +13 -0
  15. data/examples/config-shootout.ru +43 -0
  16. data/examples/config.nru +120 -0
  17. data/examples/config.rb +37 -0
  18. data/examples/config.ru +42 -53
  19. data/examples/fake +24 -0
  20. data/examples/hello_neorack +137 -0
  21. data/examples/routes.nru +29 -0
  22. data/examples/routes.ru +42 -0
  23. data/exe/iodine +218 -258
  24. data/ext/iodine/extconf.rb +27 -100
  25. data/ext/iodine/fio-stl.h +128336 -0
  26. data/ext/iodine/fio-stl.md +26396 -0
  27. data/ext/iodine/iodine.c +213 -1393
  28. data/ext/iodine/iodine.h +250 -55
  29. data/ext/iodine/iodine_arg_helper.h +329 -0
  30. data/ext/iodine/iodine_caller.h +234 -25
  31. data/ext/iodine/iodine_cli.h +434 -0
  32. data/ext/iodine/iodine_compression.h +312 -0
  33. data/ext/iodine/iodine_connection.h +3484 -34
  34. data/ext/iodine/iodine_core.h +363 -0
  35. data/ext/iodine/iodine_crypto.h +1441 -0
  36. data/ext/iodine/iodine_defer.h +225 -4
  37. data/ext/iodine/iodine_json.h +738 -4
  38. data/ext/iodine/iodine_listener.h +263 -0
  39. data/ext/iodine/iodine_log.h +297 -0
  40. data/ext/iodine/iodine_minimap.h +543 -0
  41. data/ext/iodine/iodine_mustache.h +461 -4
  42. data/ext/iodine/iodine_pubsub_eng.h +729 -0
  43. data/ext/iodine/iodine_pubsub_history.h +547 -0
  44. data/ext/iodine/iodine_pubsub_msg.h +228 -0
  45. data/ext/iodine/iodine_redis.h +322 -0
  46. data/ext/iodine/iodine_store.h +418 -16
  47. data/ext/iodine/iodine_threads.h +279 -0
  48. data/ext/iodine/iodine_tls.h +515 -6
  49. data/ext/iodine/iodine_utils.h +923 -0
  50. data/iodine.gemspec +37 -42
  51. data/lib/iodine/benchmark.rb +1690 -0
  52. data/lib/iodine/documentation.rb +3085 -0
  53. data/lib/iodine/version.rb +17 -1
  54. data/lib/iodine.rb +54 -255
  55. data/logo.svg +36 -0
  56. data/mustache.md +55 -0
  57. data/sig/iodine.rbs +4 -0
  58. metadata +58 -184
  59. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
  60. data/.github/workflows/ruby.yml +0 -42
  61. data/.gitignore +0 -20
  62. data/LIMITS.md +0 -41
  63. data/SPEC-PubSub-Draft.md +0 -159
  64. data/SPEC-WebSocket-Draft.md +0 -239
  65. data/bin/console +0 -22
  66. data/bin/info.md +0 -353
  67. data/bin/mustache_bench.rb +0 -100
  68. data/bin/poc/Gemfile.lock +0 -23
  69. data/bin/poc/README.md +0 -37
  70. data/bin/poc/config.ru +0 -66
  71. data/bin/poc/gemfile +0 -1
  72. data/bin/poc/www/index.html +0 -57
  73. data/examples/async_task.ru +0 -92
  74. data/examples/bates/README.md +0 -3
  75. data/examples/bates/config.ru +0 -342
  76. data/examples/bates/david+bold.pdf +0 -0
  77. data/examples/bates/public/drop-pdf.png +0 -0
  78. data/examples/bates/public/index.html +0 -600
  79. data/examples/echo.ru +0 -59
  80. data/examples/etag.ru +0 -16
  81. data/examples/hello.ru +0 -29
  82. data/examples/pubsub_engine.ru +0 -81
  83. data/examples/rack3.ru +0 -12
  84. data/examples/redis.ru +0 -70
  85. data/examples/shootout.ru +0 -73
  86. data/examples/sub-protocols.ru +0 -90
  87. data/examples/tcp_client.rb +0 -66
  88. data/examples/x-sendfile.ru +0 -14
  89. data/ext/iodine/fio.c +0 -11995
  90. data/ext/iodine/fio.h +0 -6371
  91. data/ext/iodine/fio_cli.c +0 -431
  92. data/ext/iodine/fio_cli.h +0 -189
  93. data/ext/iodine/fio_json_parser.h +0 -688
  94. data/ext/iodine/fio_siphash.c +0 -157
  95. data/ext/iodine/fio_siphash.h +0 -37
  96. data/ext/iodine/fio_tls.h +0 -129
  97. data/ext/iodine/fio_tls_missing.c +0 -649
  98. data/ext/iodine/fio_tls_openssl.c +0 -1106
  99. data/ext/iodine/fio_tmpfile.h +0 -50
  100. data/ext/iodine/fiobj.h +0 -44
  101. data/ext/iodine/fiobj4fio.h +0 -21
  102. data/ext/iodine/fiobj_ary.c +0 -333
  103. data/ext/iodine/fiobj_ary.h +0 -139
  104. data/ext/iodine/fiobj_data.c +0 -1187
  105. data/ext/iodine/fiobj_data.h +0 -167
  106. data/ext/iodine/fiobj_hash.c +0 -409
  107. data/ext/iodine/fiobj_hash.h +0 -176
  108. data/ext/iodine/fiobj_json.c +0 -622
  109. data/ext/iodine/fiobj_json.h +0 -68
  110. data/ext/iodine/fiobj_mem.h +0 -71
  111. data/ext/iodine/fiobj_mustache.c +0 -317
  112. data/ext/iodine/fiobj_mustache.h +0 -62
  113. data/ext/iodine/fiobj_numbers.c +0 -344
  114. data/ext/iodine/fiobj_numbers.h +0 -127
  115. data/ext/iodine/fiobj_str.c +0 -433
  116. data/ext/iodine/fiobj_str.h +0 -172
  117. data/ext/iodine/fiobject.c +0 -620
  118. data/ext/iodine/fiobject.h +0 -655
  119. data/ext/iodine/hpack.h +0 -1923
  120. data/ext/iodine/http.c +0 -2743
  121. data/ext/iodine/http.h +0 -1002
  122. data/ext/iodine/http1.c +0 -910
  123. data/ext/iodine/http1.h +0 -29
  124. data/ext/iodine/http1_parser.h +0 -878
  125. data/ext/iodine/http_internal.c +0 -1279
  126. data/ext/iodine/http_internal.h +0 -237
  127. data/ext/iodine/http_mime_parser.h +0 -350
  128. data/ext/iodine/iodine_caller.c +0 -230
  129. data/ext/iodine/iodine_connection.c +0 -941
  130. data/ext/iodine/iodine_defer.c +0 -420
  131. data/ext/iodine/iodine_fiobj2rb.h +0 -120
  132. data/ext/iodine/iodine_helpers.c +0 -282
  133. data/ext/iodine/iodine_helpers.h +0 -12
  134. data/ext/iodine/iodine_http.c +0 -1181
  135. data/ext/iodine/iodine_http.h +0 -23
  136. data/ext/iodine/iodine_json.c +0 -302
  137. data/ext/iodine/iodine_mustache.c +0 -567
  138. data/ext/iodine/iodine_pubsub.c +0 -580
  139. data/ext/iodine/iodine_pubsub.h +0 -26
  140. data/ext/iodine/iodine_rack_io.c +0 -273
  141. data/ext/iodine/iodine_rack_io.h +0 -20
  142. data/ext/iodine/iodine_store.c +0 -146
  143. data/ext/iodine/iodine_tcp.c +0 -346
  144. data/ext/iodine/iodine_tcp.h +0 -13
  145. data/ext/iodine/iodine_tls.c +0 -261
  146. data/ext/iodine/mustache_parser.h +0 -1546
  147. data/ext/iodine/redis_engine.c +0 -957
  148. data/ext/iodine/redis_engine.h +0 -79
  149. data/ext/iodine/resp_parser.h +0 -317
  150. data/ext/iodine/websocket_parser.h +0 -506
  151. data/ext/iodine/websockets.c +0 -743
  152. data/ext/iodine/websockets.h +0 -185
  153. data/lib/iodine/connection.rb +0 -61
  154. data/lib/iodine/json.rb +0 -42
  155. data/lib/iodine/mustache.rb +0 -113
  156. data/lib/iodine/pubsub.rb +0 -55
  157. data/lib/iodine/rack_utils.rb +0 -43
  158. data/lib/iodine/tls.rb +0 -16
  159. data/lib/rack/handler/iodine.rb +0 -33
  160. data/logo.png +0 -0
@@ -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
@@ -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