rage-iodine 1.7.58

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
  3. data/.github/workflows/ruby.yml +42 -0
  4. data/.gitignore +20 -0
  5. data/.rspec +2 -0
  6. data/.yardopts +8 -0
  7. data/CHANGELOG.md +1098 -0
  8. data/Gemfile +11 -0
  9. data/LICENSE.txt +21 -0
  10. data/LIMITS.md +41 -0
  11. data/README.md +782 -0
  12. data/Rakefile +23 -0
  13. data/SPEC-PubSub-Draft.md +159 -0
  14. data/SPEC-WebSocket-Draft.md +239 -0
  15. data/bin/console +22 -0
  16. data/bin/info.md +353 -0
  17. data/bin/mustache_bench.rb +100 -0
  18. data/bin/poc/Gemfile.lock +23 -0
  19. data/bin/poc/README.md +37 -0
  20. data/bin/poc/config.ru +66 -0
  21. data/bin/poc/gemfile +1 -0
  22. data/bin/poc/www/index.html +57 -0
  23. data/examples/async_task.ru +92 -0
  24. data/examples/bates/README.md +3 -0
  25. data/examples/bates/config.ru +342 -0
  26. data/examples/bates/david+bold.pdf +0 -0
  27. data/examples/bates/public/drop-pdf.png +0 -0
  28. data/examples/bates/public/index.html +600 -0
  29. data/examples/config.ru +59 -0
  30. data/examples/echo.ru +59 -0
  31. data/examples/etag.ru +16 -0
  32. data/examples/hello.ru +29 -0
  33. data/examples/pubsub_engine.ru +81 -0
  34. data/examples/rack3.ru +12 -0
  35. data/examples/redis.ru +70 -0
  36. data/examples/shootout.ru +73 -0
  37. data/examples/sub-protocols.ru +90 -0
  38. data/examples/tcp_client.rb +66 -0
  39. data/examples/x-sendfile.ru +14 -0
  40. data/exe/iodine +280 -0
  41. data/ext/iodine/extconf.rb +110 -0
  42. data/ext/iodine/fio.c +12096 -0
  43. data/ext/iodine/fio.h +6390 -0
  44. data/ext/iodine/fio_cli.c +431 -0
  45. data/ext/iodine/fio_cli.h +189 -0
  46. data/ext/iodine/fio_json_parser.h +687 -0
  47. data/ext/iodine/fio_siphash.c +157 -0
  48. data/ext/iodine/fio_siphash.h +37 -0
  49. data/ext/iodine/fio_tls.h +129 -0
  50. data/ext/iodine/fio_tls_missing.c +649 -0
  51. data/ext/iodine/fio_tls_openssl.c +1056 -0
  52. data/ext/iodine/fio_tmpfile.h +50 -0
  53. data/ext/iodine/fiobj.h +44 -0
  54. data/ext/iodine/fiobj4fio.h +21 -0
  55. data/ext/iodine/fiobj_ary.c +333 -0
  56. data/ext/iodine/fiobj_ary.h +139 -0
  57. data/ext/iodine/fiobj_data.c +1185 -0
  58. data/ext/iodine/fiobj_data.h +167 -0
  59. data/ext/iodine/fiobj_hash.c +409 -0
  60. data/ext/iodine/fiobj_hash.h +176 -0
  61. data/ext/iodine/fiobj_json.c +622 -0
  62. data/ext/iodine/fiobj_json.h +68 -0
  63. data/ext/iodine/fiobj_mem.h +71 -0
  64. data/ext/iodine/fiobj_mustache.c +317 -0
  65. data/ext/iodine/fiobj_mustache.h +62 -0
  66. data/ext/iodine/fiobj_numbers.c +344 -0
  67. data/ext/iodine/fiobj_numbers.h +127 -0
  68. data/ext/iodine/fiobj_str.c +433 -0
  69. data/ext/iodine/fiobj_str.h +172 -0
  70. data/ext/iodine/fiobject.c +620 -0
  71. data/ext/iodine/fiobject.h +654 -0
  72. data/ext/iodine/hpack.h +1923 -0
  73. data/ext/iodine/http.c +2736 -0
  74. data/ext/iodine/http.h +1019 -0
  75. data/ext/iodine/http1.c +825 -0
  76. data/ext/iodine/http1.h +29 -0
  77. data/ext/iodine/http1_parser.h +1835 -0
  78. data/ext/iodine/http_internal.c +1279 -0
  79. data/ext/iodine/http_internal.h +248 -0
  80. data/ext/iodine/http_mime_parser.h +350 -0
  81. data/ext/iodine/iodine.c +1433 -0
  82. data/ext/iodine/iodine.h +64 -0
  83. data/ext/iodine/iodine_caller.c +218 -0
  84. data/ext/iodine/iodine_caller.h +27 -0
  85. data/ext/iodine/iodine_connection.c +941 -0
  86. data/ext/iodine/iodine_connection.h +55 -0
  87. data/ext/iodine/iodine_defer.c +420 -0
  88. data/ext/iodine/iodine_defer.h +6 -0
  89. data/ext/iodine/iodine_fiobj2rb.h +120 -0
  90. data/ext/iodine/iodine_helpers.c +282 -0
  91. data/ext/iodine/iodine_helpers.h +12 -0
  92. data/ext/iodine/iodine_http.c +1280 -0
  93. data/ext/iodine/iodine_http.h +23 -0
  94. data/ext/iodine/iodine_json.c +302 -0
  95. data/ext/iodine/iodine_json.h +6 -0
  96. data/ext/iodine/iodine_mustache.c +567 -0
  97. data/ext/iodine/iodine_mustache.h +6 -0
  98. data/ext/iodine/iodine_pubsub.c +580 -0
  99. data/ext/iodine/iodine_pubsub.h +26 -0
  100. data/ext/iodine/iodine_rack_io.c +273 -0
  101. data/ext/iodine/iodine_rack_io.h +20 -0
  102. data/ext/iodine/iodine_store.c +142 -0
  103. data/ext/iodine/iodine_store.h +20 -0
  104. data/ext/iodine/iodine_tcp.c +346 -0
  105. data/ext/iodine/iodine_tcp.h +13 -0
  106. data/ext/iodine/iodine_tls.c +261 -0
  107. data/ext/iodine/iodine_tls.h +13 -0
  108. data/ext/iodine/mustache_parser.h +1546 -0
  109. data/ext/iodine/redis_engine.c +957 -0
  110. data/ext/iodine/redis_engine.h +79 -0
  111. data/ext/iodine/resp_parser.h +317 -0
  112. data/ext/iodine/scheduler.c +173 -0
  113. data/ext/iodine/scheduler.h +6 -0
  114. data/ext/iodine/websocket_parser.h +506 -0
  115. data/ext/iodine/websockets.c +752 -0
  116. data/ext/iodine/websockets.h +185 -0
  117. data/iodine.gemspec +50 -0
  118. data/lib/iodine/connection.rb +61 -0
  119. data/lib/iodine/json.rb +42 -0
  120. data/lib/iodine/mustache.rb +113 -0
  121. data/lib/iodine/pubsub.rb +55 -0
  122. data/lib/iodine/rack_utils.rb +43 -0
  123. data/lib/iodine/tls.rb +16 -0
  124. data/lib/iodine/version.rb +3 -0
  125. data/lib/iodine.rb +274 -0
  126. data/lib/rack/handler/iodine.rb +33 -0
  127. data/logo.png +0 -0
  128. metadata +284 -0
@@ -0,0 +1,50 @@
1
+ /*
2
+ Copyright: Boaz Segev, 2018-2019
3
+ License: MIT
4
+ */
5
+ #ifndef H_FIO_TMPFILE_H
6
+ /** a simple helper to create temporary files and file names */
7
+ #define H_FIO_TMPFILE_H
8
+
9
+ #ifndef _GNU_SOURCE
10
+ #define _GNU_SOURCE
11
+ #endif
12
+
13
+ #include <stdio.h>
14
+ #include <stdlib.h>
15
+
16
+ #include <fcntl.h>
17
+ #include <sys/stat.h>
18
+ #include <sys/types.h>
19
+ #include <unistd.h>
20
+
21
+ #ifdef __MINGW32__
22
+ #include <fileapi.h>
23
+ #endif
24
+
25
+ static inline int fio_tmpfile(void) {
26
+ // create a temporary file to contain the data.
27
+ int fd = 0;
28
+ #ifdef __MINGW32__
29
+ char name_template[] = "fio";
30
+ TCHAR temp_path[(MAX_PATH-14)];
31
+ TCHAR temp_filename[MAX_PATH];
32
+ GetTempPath(MAX_PATH - 14, temp_path);
33
+ GetTempFileNameA(temp_path, name_template, 0, temp_filename);
34
+ fd = _open(temp_filename, _O_CREAT | _O_RDWR);
35
+ _chmod(temp_filename, _S_IREAD | _S_IWRITE);
36
+ #elif defined(P_tmpdir)
37
+ if (P_tmpdir[sizeof(P_tmpdir) - 1] == '/') {
38
+ char name_template[] = P_tmpdir "facil_io_tmpfile_XXXXXXXX";
39
+ fd = mkstemp(name_template);
40
+ } else {
41
+ char name_template[] = P_tmpdir "/facil_io_tmpfile_XXXXXXXX";
42
+ fd = mkstemp(name_template);
43
+ }
44
+ #else
45
+ char name_template[] = "/tmp/facil_io_tmpfile_XXXXXXXX";
46
+ fd = mkstemp(name_template);
47
+ #endif
48
+ return fd;
49
+ }
50
+ #endif
@@ -0,0 +1,44 @@
1
+ /*
2
+ Copyright: Boaz Segev, 2017-2019
3
+ License: MIT
4
+ */
5
+ #ifndef H_FIOBJ_H
6
+ #define H_FIOBJ_H
7
+
8
+ #include <fiobj_ary.h>
9
+ #include <fiobj_data.h>
10
+ #include <fiobj_hash.h>
11
+ #include <fiobj_json.h>
12
+ #include <fiobj_mustache.h>
13
+ #include <fiobj_numbers.h>
14
+ #include <fiobj_str.h>
15
+ #include <fiobject.h>
16
+
17
+ #include <fio_siphash.h>
18
+
19
+ #ifdef H_FACIL_IO_H
20
+ #include <fiobj4fio.h>
21
+ #endif
22
+
23
+ #if DEBUG
24
+ FIO_INLINE void fiobj_test(void) {
25
+ fprintf(stderr, "\n=== FIOBJ Tests ===\n\n");
26
+ fiobj_test_string();
27
+ fiobj_test_numbers();
28
+ fiobj_test_array();
29
+ fiobj_test_hash();
30
+ fiobj_test_core();
31
+ fiobj_data_test();
32
+ fiobj_test_json();
33
+ fiobj_mustache_test();
34
+ fiobj_siphash_test();
35
+ fprintf(stderr, "=== FIOBJ Done ===\n\n");
36
+ }
37
+ #else
38
+ FIO_INLINE void fiobj_test(void) {
39
+ fprintf(stderr, "ERROR: tesing functions only defined with DEBUG=1\n");
40
+ exit(-1);
41
+ }
42
+ #endif
43
+ #undef FIO_INLINE
44
+ #endif
@@ -0,0 +1,21 @@
1
+ #ifndef H_FIOBJ4SOCK_H
2
+ #define H_FIOBJ4SOCK_H
3
+ /**
4
+ * Defines a helper for using fiobj with the sock library.
5
+ */
6
+
7
+ #include <fio.h>
8
+ #include <fiobj.h>
9
+
10
+ static void fiobj4sock_dealloc(void *o) { fiobj_free((FIOBJ)o); }
11
+
12
+ /** send a FIOBJ object through a socket. */
13
+ static inline __attribute__((unused)) ssize_t fiobj_send_free(intptr_t uuid,
14
+ FIOBJ o) {
15
+ fio_str_info_s s = fiobj_obj2cstr(o);
16
+ return fio_write2(uuid, .data.buffer = (void *)(o),
17
+ .offset = (uintptr_t)(((intptr_t)s.data) - ((intptr_t)(o))),
18
+ .length = s.len, .after.dealloc = fiobj4sock_dealloc);
19
+ }
20
+
21
+ #endif
@@ -0,0 +1,333 @@
1
+ /*
2
+ Copyright: Boaz Segev, 2017-2019
3
+ License: MIT
4
+ */
5
+ #include <fio.h>
6
+ #include <fiobject.h>
7
+
8
+ #define FIO_ARY_NAME fio_ary__
9
+ #define FIO_ARY_TYPE FIOBJ
10
+ #define FIO_ARY_TYPE_INVALID FIOBJ_INVALID
11
+ #define FIO_ARY_TYPE_COMPARE(a, b) (fiobj_iseq((a), (b)))
12
+ #define FIO_ARY_INVALID FIOBJ_INVALID
13
+ #include <fio.h>
14
+
15
+ #include <assert.h>
16
+
17
+ /* *****************************************************************************
18
+ Array Type
19
+ ***************************************************************************** */
20
+
21
+ typedef struct {
22
+ fiobj_object_header_s head;
23
+ fio_ary___s ary;
24
+ } fiobj_ary_s;
25
+
26
+ #define obj2ary(o) ((fiobj_ary_s *)(o))
27
+
28
+ /* *****************************************************************************
29
+ VTable
30
+ ***************************************************************************** */
31
+
32
+ static void fiobj_ary_dealloc(FIOBJ o, void (*task)(FIOBJ, void *), void *arg) {
33
+ FIO_ARY_FOR((&obj2ary(o)->ary), i) { task(*i, arg); }
34
+ fio_ary___free(&obj2ary(o)->ary);
35
+ fio_free(FIOBJ2PTR(o));
36
+ }
37
+
38
+ static size_t fiobj_ary_each1(FIOBJ o, size_t start_at,
39
+ int (*task)(FIOBJ obj, void *arg), void *arg) {
40
+ return fio_ary___each(&obj2ary(o)->ary, start_at, task, arg);
41
+ }
42
+
43
+ static size_t fiobj_ary_is_eq(const FIOBJ self, const FIOBJ other) {
44
+ fio_ary___s *a = &obj2ary(self)->ary;
45
+ fio_ary___s *b = &obj2ary(other)->ary;
46
+ if (fio_ary___count(a) != fio_ary___count(b))
47
+ return 0;
48
+ return 1;
49
+ }
50
+
51
+ /** Returns the number of elements in the Array. */
52
+ size_t fiobj_ary_count(const FIOBJ ary) {
53
+ assert(FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
54
+ return fio_ary___count(&obj2ary(ary)->ary);
55
+ }
56
+
57
+ static size_t fiobj_ary_is_true(const FIOBJ ary) {
58
+ return fiobj_ary_count(ary) > 0;
59
+ }
60
+
61
+ fio_str_info_s fiobject___noop_to_str(const FIOBJ o);
62
+ intptr_t fiobject___noop_to_i(const FIOBJ o);
63
+ double fiobject___noop_to_f(const FIOBJ o);
64
+
65
+ const fiobj_object_vtable_s FIOBJECT_VTABLE_ARRAY = {
66
+ .class_name = "Array",
67
+ .dealloc = fiobj_ary_dealloc,
68
+ .is_eq = fiobj_ary_is_eq,
69
+ .is_true = fiobj_ary_is_true,
70
+ .count = fiobj_ary_count,
71
+ .each = fiobj_ary_each1,
72
+ .to_i = fiobject___noop_to_i,
73
+ .to_f = fiobject___noop_to_f,
74
+ .to_str = fiobject___noop_to_str,
75
+ };
76
+
77
+ /* *****************************************************************************
78
+ Allocation
79
+ ***************************************************************************** */
80
+
81
+ static inline FIOBJ fiobj_ary_alloc(size_t capa) {
82
+ fiobj_ary_s *ary = fio_malloc(sizeof(*ary));
83
+ if (!ary) {
84
+ perror("ERROR: fiobj array couldn't allocate memory");
85
+ exit(errno);
86
+ }
87
+ *ary = (fiobj_ary_s){
88
+ .head =
89
+ {
90
+ .ref = 1,
91
+ .type = FIOBJ_T_ARRAY,
92
+ },
93
+ };
94
+ if (capa)
95
+ fio_ary_____require_on_top(&ary->ary, capa);
96
+ return (FIOBJ)ary;
97
+ }
98
+
99
+ /** Creates a mutable empty Array object. Use `fiobj_free` when done. */
100
+ FIOBJ fiobj_ary_new(void) { return fiobj_ary_alloc(0); }
101
+ /** Creates a mutable empty Array object with the requested capacity. */
102
+ FIOBJ fiobj_ary_new2(size_t capa) { return fiobj_ary_alloc(capa); }
103
+
104
+ /* *****************************************************************************
105
+ Array direct entry access API
106
+ ***************************************************************************** */
107
+
108
+ /** Returns the current, temporary, array capacity (it's dynamic). */
109
+ size_t fiobj_ary_capa(FIOBJ ary) {
110
+ assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
111
+ return fio_ary___capa(&obj2ary(ary)->ary);
112
+ }
113
+
114
+ /**
115
+ * Returns a TEMPORARY pointer to the beginning of the array.
116
+ *
117
+ * This pointer can be used for sorting and other direct access operations as
118
+ * long as no other actions (insertion/deletion) are performed on the array.
119
+ */
120
+ FIOBJ *fiobj_ary2ptr(FIOBJ ary) {
121
+ assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
122
+ return (FIOBJ *)(obj2ary(ary)->ary.arry + obj2ary(ary)->ary.start);
123
+ }
124
+
125
+ /**
126
+ * Returns a temporary object owned by the Array.
127
+ *
128
+ * Negative values are retrieved from the end of the array. i.e., `-1`
129
+ * is the last item.
130
+ */
131
+ FIOBJ fiobj_ary_index(FIOBJ ary, int64_t pos) {
132
+ assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
133
+ return fio_ary___get(&obj2ary(ary)->ary, pos);
134
+ }
135
+
136
+ /**
137
+ * Sets an object at the requested position.
138
+ */
139
+ void fiobj_ary_set(FIOBJ ary, FIOBJ obj, int64_t pos) {
140
+ assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
141
+ FIOBJ old = FIOBJ_INVALID;
142
+ fio_ary___set(&obj2ary(ary)->ary, pos, obj, &old);
143
+ fiobj_free(old);
144
+ }
145
+
146
+ /* *****************************************************************************
147
+ Array push / shift API
148
+ ***************************************************************************** */
149
+
150
+ /**
151
+ * Pushes an object to the end of the Array.
152
+ */
153
+ void fiobj_ary_push(FIOBJ ary, FIOBJ obj) {
154
+ assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
155
+ fio_ary___push(&obj2ary(ary)->ary, obj);
156
+ }
157
+
158
+ /** Pops an object from the end of the Array. */
159
+ FIOBJ fiobj_ary_pop(FIOBJ ary) {
160
+ assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
161
+ FIOBJ ret = FIOBJ_INVALID;
162
+ fio_ary___pop(&obj2ary(ary)->ary, &ret);
163
+ return ret;
164
+ }
165
+
166
+ /**
167
+ * Unshifts an object to the beginning of the Array. This could be
168
+ * expensive.
169
+ */
170
+ void fiobj_ary_unshift(FIOBJ ary, FIOBJ obj) {
171
+ assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
172
+ fio_ary___unshift(&obj2ary(ary)->ary, obj);
173
+ }
174
+
175
+ /** Shifts an object from the beginning of the Array. */
176
+ FIOBJ fiobj_ary_shift(FIOBJ ary) {
177
+ assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
178
+ FIOBJ ret = FIOBJ_INVALID;
179
+ fio_ary___shift(&obj2ary(ary)->ary, &ret);
180
+ return ret;
181
+ }
182
+
183
+ /* *****************************************************************************
184
+ Array Find / Remove / Replace
185
+ ***************************************************************************** */
186
+
187
+ /**
188
+ * Replaces the object at a specific position, returning the old object -
189
+ * remember to `fiobj_free` the old object.
190
+ */
191
+ FIOBJ fiobj_ary_replace(FIOBJ ary, FIOBJ obj, int64_t pos) {
192
+ assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
193
+ FIOBJ old = fiobj_ary_index(ary, pos);
194
+ fiobj_ary_set(ary, obj, pos);
195
+ return old;
196
+ }
197
+
198
+ /**
199
+ * Finds the index of a specifide object (if any). Returns -1 if the object
200
+ * isn't found.
201
+ */
202
+ int64_t fiobj_ary_find(FIOBJ ary, FIOBJ data) {
203
+ assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
204
+ return (int64_t)fio_ary___find(&obj2ary(ary)->ary, data);
205
+ }
206
+
207
+ /**
208
+ * Removes the object at the index (if valid), changing the index of any
209
+ * following objects.
210
+ *
211
+ * Returns 0 on success or -1 (if no object or out of bounds).
212
+ */
213
+ int fiobj_ary_remove(FIOBJ ary, int64_t pos) {
214
+ assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
215
+ FIOBJ old = FIOBJ_INVALID;
216
+ if (fio_ary___remove(&obj2ary(ary)->ary, (intptr_t)pos, &old)) {
217
+ return -1;
218
+ }
219
+ fiobj_free(old);
220
+ return 0;
221
+ }
222
+
223
+ /**
224
+ * Removes the first instance of an object from the Array (if any), changing the
225
+ * index of any following objects.
226
+ *
227
+ * Returns 0 on success or -1 (if the object wasn't found).
228
+ */
229
+ int fiobj_ary_remove2(FIOBJ ary, FIOBJ data) {
230
+ assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
231
+ if (-1 == fio_ary___remove2(&obj2ary(ary)->ary, data, &data)) {
232
+ return -1;
233
+ }
234
+ fiobj_free(data);
235
+ return 0;
236
+ }
237
+
238
+ /* *****************************************************************************
239
+ Array compacting (untested)
240
+ ***************************************************************************** */
241
+
242
+ /**
243
+ * Removes any NULL *pointers* from an Array, keeping all Objects (including
244
+ * explicit NULL objects) in the array.
245
+ *
246
+ * This action is O(n) where n in the length of the array.
247
+ * It could get expensive.
248
+ */
249
+ void fiobj_ary_compact(FIOBJ ary) {
250
+ assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
251
+ fio_ary___compact(&obj2ary(ary)->ary);
252
+ }
253
+
254
+ /* *****************************************************************************
255
+ Simple Tests
256
+ ***************************************************************************** */
257
+
258
+ #if DEBUG
259
+ void fiobj_test_array(void) {
260
+ fprintf(stderr, "=== Testing Array\n");
261
+ #define TEST_ASSERT(cond, ...) \
262
+ if (!(cond)) { \
263
+ fprintf(stderr, "* " __VA_ARGS__); \
264
+ fprintf(stderr, "Testing failed.\n"); \
265
+ exit(-1); \
266
+ }
267
+ FIOBJ a = fiobj_ary_new2(4);
268
+ TEST_ASSERT(FIOBJ_TYPE_IS(a, FIOBJ_T_ARRAY), "Array type isn't an array!\n");
269
+ TEST_ASSERT(fiobj_ary_capa(a) > 4, "Array capacity ignored!\n");
270
+ fiobj_ary_push(a, fiobj_null());
271
+ TEST_ASSERT(fiobj_ary2ptr(a)[0] == fiobj_null(),
272
+ "Array direct access failed!\n");
273
+ fiobj_ary_push(a, fiobj_true());
274
+ fiobj_ary_push(a, fiobj_false());
275
+ TEST_ASSERT(fiobj_ary_count(a) == 3, "Array count isn't 3\n");
276
+ fiobj_ary_set(a, fiobj_true(), 63);
277
+ TEST_ASSERT(fiobj_ary_count(a) == 64, "Array count isn't 64 (%zu)\n",
278
+ fiobj_ary_count(a));
279
+ TEST_ASSERT(fiobj_ary_index(a, 0) == fiobj_null(),
280
+ "Array index retrival error for fiobj_null\n");
281
+ TEST_ASSERT(fiobj_ary_index(a, 1) == fiobj_true(),
282
+ "Array index retrival error for fiobj_true\n");
283
+ TEST_ASSERT(fiobj_ary_index(a, 2) == fiobj_false(),
284
+ "Array index retrival error for fiobj_false\n");
285
+ TEST_ASSERT(fiobj_ary_index(a, 3) == 0,
286
+ "Array index retrival error for NULL\n");
287
+ TEST_ASSERT(fiobj_ary_index(a, 63) == fiobj_true(),
288
+ "Array index retrival error for index 63\n");
289
+ TEST_ASSERT(fiobj_ary_index(a, -1) == fiobj_true(),
290
+ "Array index retrival error for index -1\n");
291
+ fiobj_ary_compact(a);
292
+ TEST_ASSERT(fiobj_ary_index(a, -1) == fiobj_true(),
293
+ "Array index retrival error for index -1\n");
294
+ TEST_ASSERT(fiobj_ary_count(a) == 4, "Array compact error\n");
295
+ fiobj_ary_unshift(a, fiobj_false());
296
+ TEST_ASSERT(fiobj_ary_count(a) == 5, "Array unshift error\n");
297
+ TEST_ASSERT(fiobj_ary_shift(a) == fiobj_false(), "Array shift value error\n");
298
+ TEST_ASSERT(fiobj_ary_replace(a, fiobj_true(), -2) == fiobj_false(),
299
+ "Array replace didn't return correct value\n");
300
+
301
+ FIO_ARY_FOR(&obj2ary(a)->ary, pos) {
302
+ if (*pos) {
303
+ fprintf(stderr, "%lu) %s\n", pos - obj2ary(a)->ary.arry,
304
+ fiobj_obj2cstr(*pos).data);
305
+ }
306
+ }
307
+
308
+ TEST_ASSERT(fiobj_ary_index(a, -2) == fiobj_true(),
309
+ "Array index retrival error for index -2 (should be true)\n");
310
+ TEST_ASSERT(fiobj_ary_count(a) == 4, "Array size error\n");
311
+ fiobj_ary_remove(a, -2);
312
+ TEST_ASSERT(fiobj_ary_count(a) == 3, "Array remove error\n");
313
+
314
+ FIO_ARY_FOR(&obj2ary(a)->ary, pos) {
315
+ if (*pos) {
316
+ fprintf(stderr, "%lu) %s\n", pos - obj2ary(a)->ary.arry,
317
+ fiobj_obj2cstr(*pos).data);
318
+ }
319
+ }
320
+
321
+ fiobj_ary_remove2(a, fiobj_true());
322
+ TEST_ASSERT(fiobj_ary_count(a) == 2, "Array remove2 error\n");
323
+ TEST_ASSERT(fiobj_ary_index(a, 0) == fiobj_null(),
324
+ "Array index 0 should be null - %s\n",
325
+ fiobj_obj2cstr(fiobj_ary_index(a, 0)).data);
326
+ TEST_ASSERT(fiobj_ary_index(a, 1) == fiobj_true(),
327
+ "Array index 0 should be true - %s\n",
328
+ fiobj_obj2cstr(fiobj_ary_index(a, 0)).data);
329
+
330
+ fiobj_free(a);
331
+ fprintf(stderr, "* passed.\n");
332
+ }
333
+ #endif
@@ -0,0 +1,139 @@
1
+ #ifndef FIOBJ_ARRAY_H
2
+ /*
3
+ Copyright: Boaz Segev, 2017-2019
4
+ License: MIT
5
+ */
6
+
7
+ /**
8
+ A dynamic Array type for the fiobj_s dynamic type system.
9
+ */
10
+ #define FIOBJ_ARRAY_H
11
+
12
+ #include <fiobject.h>
13
+
14
+ #ifdef __cplusplus
15
+ extern "C" {
16
+ #endif
17
+
18
+ /* *****************************************************************************
19
+ Array creation API
20
+ ***************************************************************************** */
21
+
22
+ /** Creates a mutable empty Array object. Use `fiobj_free` when done. */
23
+ FIOBJ fiobj_ary_new(void);
24
+
25
+ /** Creates a mutable empty Array object with the requested capacity. */
26
+ FIOBJ fiobj_ary_new2(size_t capa);
27
+
28
+ /* *****************************************************************************
29
+ Array direct entry access API
30
+ ***************************************************************************** */
31
+
32
+ /** Returns the number of elements in the Array. */
33
+ size_t fiobj_ary_count(FIOBJ ary);
34
+
35
+ /** Returns the current, temporary, array capacity (it's dynamic). */
36
+ size_t fiobj_ary_capa(FIOBJ ary);
37
+
38
+ /**
39
+ * Returns a TEMPORARY pointer to the beginning of the array.
40
+ *
41
+ * This pointer can be used for sorting and other direct access operations as
42
+ * long as no other actions (insertion/deletion) are performed on the array.
43
+ */
44
+ FIOBJ *fiobj_ary2ptr(FIOBJ ary);
45
+
46
+ /**
47
+ * Returns a temporary object owned by the Array.
48
+ *
49
+ * Wrap this function call within `fiobj_dup` to get a persistent handle. i.e.:
50
+ *
51
+ * fiobj_dup(fiobj_ary_index(array, 0));
52
+ *
53
+ * Negative values are retrieved from the end of the array. i.e., `-1`
54
+ * is the last item.
55
+ */
56
+ FIOBJ fiobj_ary_index(FIOBJ ary, int64_t pos);
57
+ /** alias for `fiobj_ary_index` */
58
+ #define fiobj_ary_entry(a, p) fiobj_ary_index((a), (p))
59
+
60
+ /**
61
+ * Sets an object at the requested position.
62
+ */
63
+ void fiobj_ary_set(FIOBJ ary, FIOBJ obj, int64_t pos);
64
+
65
+ /* *****************************************************************************
66
+ Array push / shift API
67
+ ***************************************************************************** */
68
+
69
+ /**
70
+ * Pushes an object to the end of the Array.
71
+ */
72
+ void fiobj_ary_push(FIOBJ ary, FIOBJ obj);
73
+
74
+ /** Pops an object from the end of the Array. */
75
+ FIOBJ fiobj_ary_pop(FIOBJ ary);
76
+
77
+ /**
78
+ * Unshifts an object to the beginning of the Array. This could be
79
+ * expensive.
80
+ */
81
+ void fiobj_ary_unshift(FIOBJ ary, FIOBJ obj);
82
+
83
+ /** Shifts an object from the beginning of the Array. */
84
+ FIOBJ fiobj_ary_shift(FIOBJ ary);
85
+
86
+ /* *****************************************************************************
87
+ Array Find / Remove / Replace
88
+ ***************************************************************************** */
89
+
90
+ /**
91
+ * Replaces the object at a specific position, returning the old object -
92
+ * remember to `fiobj_free` the old object.
93
+ */
94
+ FIOBJ fiobj_ary_replace(FIOBJ ary, FIOBJ obj, int64_t pos);
95
+
96
+ /**
97
+ * Finds the index of a specifide object (if any). Returns -1 if the object
98
+ * isn't found.
99
+ */
100
+ int64_t fiobj_ary_find(FIOBJ ary, FIOBJ data);
101
+
102
+ /**
103
+ * Removes the object at the index (if valid), changing the index of any
104
+ * following objects.
105
+ *
106
+ * Returns 0 on success or -1 (if no object or out of bounds).
107
+ */
108
+ int fiobj_ary_remove(FIOBJ ary, int64_t pos);
109
+
110
+ /**
111
+ * Removes the first instance of an object from the Array (if any), changing the
112
+ * index of any following objects.
113
+ *
114
+ * Returns 0 on success or -1 (if the object wasn't found).
115
+ */
116
+ int fiobj_ary_remove2(FIOBJ ary, FIOBJ data);
117
+
118
+ /* *****************************************************************************
119
+ Array compacting (untested)
120
+ ***************************************************************************** */
121
+
122
+ /**
123
+ * Removes any NULL *pointers* from an Array, keeping all Objects (including
124
+ * explicit NULL objects) in the array.
125
+ *
126
+ * This action is O(n) where n in the length of the array.
127
+ * It could get expensive.
128
+ */
129
+ void fiobj_ary_compact(FIOBJ ary);
130
+
131
+ #if DEBUG
132
+ void fiobj_test_array(void);
133
+ #endif
134
+
135
+ #ifdef __cplusplus
136
+ } /* extern "C" */
137
+ #endif
138
+
139
+ #endif