iodine 0.6.5 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of iodine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +4 -4
- data/SPEC-Websocket-Draft.md +3 -6
- data/bin/mustache.rb +128 -0
- data/examples/test_template.mustache +16 -0
- data/ext/iodine/fio.c +9397 -0
- data/ext/iodine/fio.h +4723 -0
- data/ext/iodine/fio_ary.h +353 -54
- data/ext/iodine/fio_cli.c +351 -361
- data/ext/iodine/fio_cli.h +84 -105
- data/ext/iodine/fio_hashmap.h +70 -16
- data/ext/iodine/fio_json_parser.h +35 -24
- data/ext/iodine/fio_siphash.c +104 -4
- data/ext/iodine/fio_siphash.h +18 -2
- data/ext/iodine/fio_str.h +1218 -0
- data/ext/iodine/fio_tmpfile.h +1 -1
- data/ext/iodine/fiobj.h +13 -8
- data/ext/iodine/fiobj4sock.h +6 -8
- data/ext/iodine/fiobj_ary.c +107 -17
- data/ext/iodine/fiobj_ary.h +36 -4
- data/ext/iodine/fiobj_data.c +146 -127
- data/ext/iodine/fiobj_data.h +25 -23
- data/ext/iodine/fiobj_hash.c +7 -7
- data/ext/iodine/fiobj_hash.h +6 -5
- data/ext/iodine/fiobj_json.c +20 -17
- data/ext/iodine/fiobj_json.h +5 -5
- data/ext/iodine/fiobj_mem.h +71 -0
- data/ext/iodine/fiobj_mustache.c +310 -0
- data/ext/iodine/fiobj_mustache.h +40 -0
- data/ext/iodine/fiobj_numbers.c +199 -94
- data/ext/iodine/fiobj_numbers.h +7 -7
- data/ext/iodine/fiobj_str.c +142 -333
- data/ext/iodine/fiobj_str.h +65 -55
- data/ext/iodine/fiobject.c +49 -11
- data/ext/iodine/fiobject.h +40 -39
- data/ext/iodine/http.c +382 -190
- data/ext/iodine/http.h +124 -80
- data/ext/iodine/http1.c +99 -127
- data/ext/iodine/http1.h +5 -5
- data/ext/iodine/http1_parser.c +3 -2
- data/ext/iodine/http1_parser.h +2 -2
- data/ext/iodine/http_internal.c +14 -12
- data/ext/iodine/http_internal.h +25 -19
- data/ext/iodine/iodine.c +37 -18
- data/ext/iodine/iodine.h +4 -0
- data/ext/iodine/iodine_caller.c +9 -2
- data/ext/iodine/iodine_caller.h +2 -0
- data/ext/iodine/iodine_connection.c +82 -117
- data/ext/iodine/iodine_defer.c +57 -50
- data/ext/iodine/iodine_defer.h +0 -1
- data/ext/iodine/iodine_fiobj2rb.h +4 -2
- data/ext/iodine/iodine_helpers.c +4 -4
- data/ext/iodine/iodine_http.c +25 -32
- data/ext/iodine/iodine_json.c +2 -1
- data/ext/iodine/iodine_mustache.c +423 -0
- data/ext/iodine/iodine_mustache.h +6 -0
- data/ext/iodine/iodine_pubsub.c +48 -153
- data/ext/iodine/iodine_pubsub.h +5 -4
- data/ext/iodine/iodine_rack_io.c +7 -5
- data/ext/iodine/iodine_store.c +16 -13
- data/ext/iodine/iodine_tcp.c +26 -34
- data/ext/iodine/mustache_parser.h +1085 -0
- data/ext/iodine/redis_engine.c +740 -646
- data/ext/iodine/redis_engine.h +13 -15
- data/ext/iodine/resp_parser.h +11 -5
- data/ext/iodine/websocket_parser.h +13 -13
- data/ext/iodine/websockets.c +240 -393
- data/ext/iodine/websockets.h +52 -113
- data/lib/iodine.rb +1 -1
- data/lib/iodine/mustache.rb +140 -0
- data/lib/iodine/version.rb +1 -1
- metadata +15 -28
- data/ext/iodine/defer.c +0 -566
- data/ext/iodine/defer.h +0 -148
- data/ext/iodine/evio.c +0 -26
- data/ext/iodine/evio.h +0 -161
- data/ext/iodine/evio_callbacks.c +0 -26
- data/ext/iodine/evio_epoll.c +0 -251
- data/ext/iodine/evio_kqueue.c +0 -194
- data/ext/iodine/facil.c +0 -2325
- data/ext/iodine/facil.h +0 -616
- data/ext/iodine/fio_base64.c +0 -277
- data/ext/iodine/fio_base64.h +0 -71
- data/ext/iodine/fio_llist.h +0 -257
- data/ext/iodine/fio_mem.c +0 -675
- data/ext/iodine/fio_mem.h +0 -143
- data/ext/iodine/fio_random.c +0 -248
- data/ext/iodine/fio_random.h +0 -45
- data/ext/iodine/fio_sha1.c +0 -362
- data/ext/iodine/fio_sha1.h +0 -107
- data/ext/iodine/fio_sha2.c +0 -842
- data/ext/iodine/fio_sha2.h +0 -169
- data/ext/iodine/pubsub.c +0 -867
- data/ext/iodine/pubsub.h +0 -221
- data/ext/iodine/sock.c +0 -1366
- data/ext/iodine/sock.h +0 -566
- data/ext/iodine/spnlock.inc +0 -111
data/ext/iodine/fio_ary.h
CHANGED
@@ -5,19 +5,25 @@ License: MIT
|
|
5
5
|
*/
|
6
6
|
|
7
7
|
/**
|
8
|
-
* A Dynamic Array for general use (void * pointers).
|
8
|
+
* A Dynamic Array for general use (for void * pointers or a predefined type).
|
9
|
+
*
|
10
|
+
* It's possible to switch from the default `void *` type to any type by
|
11
|
+
* defining the `FIO_ARY_TYPE`, `FIO_ARY_TYPE_COMPARE(a,b)` and
|
12
|
+
* `FIO_ARY_TYPE_INVALID` macros.
|
13
|
+
*
|
14
|
+
* However, this will effect ALL the arrays that share the same translation unit
|
15
|
+
* (the same *.c file).
|
9
16
|
*
|
10
17
|
* The file was written to be compatible with C++ as well as C, hence some
|
11
18
|
* pointer casting.
|
12
19
|
*
|
13
20
|
* Use:
|
14
|
-
|
15
|
-
fio_ary_s ary;
|
16
|
-
fio_ary_new(&ary);
|
17
|
-
fio_ary_push(&ary, (void*)1 );
|
18
|
-
fio_ary_free(&ary)
|
19
|
-
|
20
|
-
|
21
|
+
*
|
22
|
+
* fio_ary_s ary; // a container can be placed on the stack.
|
23
|
+
* fio_ary_new(&ary); // initialize the container
|
24
|
+
* fio_ary_push(&ary, (void*)1 ); // add / remove / read data...
|
25
|
+
* fio_ary_free(&ary) // free any resources, not the container.
|
26
|
+
*
|
21
27
|
*/
|
22
28
|
#define H_FIO_ARRAY_H
|
23
29
|
|
@@ -30,6 +36,20 @@ fio_ary_free(&ary) // free any resources, not the container.
|
|
30
36
|
#define _GNU_SOURCE
|
31
37
|
#endif
|
32
38
|
|
39
|
+
/**
|
40
|
+
* Both FIO_ARY_TYPE, FIO_ARY_TYPE_INVALID and FIO_ARY_TYPE_COMPARE must be
|
41
|
+
* defined to change default behavior.
|
42
|
+
*/
|
43
|
+
#if !defined(FIO_ARY_TYPE) || !defined(FIO_ARY_TYPE_INVALID) || \
|
44
|
+
!defined(FIO_ARY_TYPE_COMPARE)
|
45
|
+
#undef FIO_ARY_TYPE
|
46
|
+
#undef FIO_ARY_TYPE_INVALID
|
47
|
+
#undef FIO_ARY_TYPE_COMPARE
|
48
|
+
#define FIO_ARY_TYPE void *
|
49
|
+
#define FIO_ARY_TYPE_INVALID NULL
|
50
|
+
#define FIO_ARY_TYPE_COMPARE(a, b) ((a) == (b))
|
51
|
+
#endif
|
52
|
+
|
33
53
|
#ifndef FIO_FUNC
|
34
54
|
#define FIO_FUNC static __attribute__((unused))
|
35
55
|
#endif
|
@@ -42,7 +62,7 @@ typedef struct fio_ary_s {
|
|
42
62
|
size_t start;
|
43
63
|
size_t end;
|
44
64
|
size_t capa;
|
45
|
-
|
65
|
+
FIO_ARY_TYPE *arry;
|
46
66
|
} fio_ary_s;
|
47
67
|
|
48
68
|
/** this value can be used for lazy initialization. */
|
@@ -58,6 +78,13 @@ FIO_FUNC inline void fio_ary_new(fio_ary_s *ary, size_t capa);
|
|
58
78
|
/** Frees the array's internal data. */
|
59
79
|
FIO_FUNC inline void fio_ary_free(fio_ary_s *ary);
|
60
80
|
|
81
|
+
/**
|
82
|
+
* Adds all the items in the `src` Array to the end of the `dest` Array.
|
83
|
+
*
|
84
|
+
* The `src` Array remain untouched.
|
85
|
+
*/
|
86
|
+
FIO_FUNC inline void fio_ary_concat(fio_ary_s *dest, fio_ary_s *src);
|
87
|
+
|
61
88
|
/** Returns the number of elements in the Array. */
|
62
89
|
FIO_FUNC inline size_t fio_ary_count(fio_ary_s *ary);
|
63
90
|
|
@@ -65,13 +92,18 @@ FIO_FUNC inline size_t fio_ary_count(fio_ary_s *ary);
|
|
65
92
|
FIO_FUNC inline size_t fio_ary_capa(fio_ary_s *ary);
|
66
93
|
|
67
94
|
/**
|
68
|
-
* Returns the object placed in the Array, if any. Returns
|
69
|
-
* the index is out of bounds.
|
95
|
+
* Returns the object placed in the Array, if any. Returns FIO_ARY_TYPE_INVALID
|
96
|
+
* if no data or if the index is out of bounds.
|
70
97
|
*
|
71
|
-
* Negative values are
|
98
|
+
* Negative values are retrieved from the end of the array. i.e., `-1`
|
72
99
|
* is the last item.
|
73
100
|
*/
|
74
|
-
FIO_FUNC inline
|
101
|
+
FIO_FUNC inline FIO_ARY_TYPE fio_ary_index(fio_ary_s *ary, intptr_t pos);
|
102
|
+
|
103
|
+
/**
|
104
|
+
* Returns the index of the object or -1 if the object wasn't found.
|
105
|
+
*/
|
106
|
+
FIO_FUNC inline intptr_t fio_ary_find(fio_ary_s *ary, FIO_ARY_TYPE data);
|
75
107
|
|
76
108
|
/** alias for `fiobj_ary_index` */
|
77
109
|
#define fio_ary_entry(a, p) fiobj_ary_index((a), (p))
|
@@ -83,25 +115,43 @@ FIO_FUNC inline void *fio_ary_index(fio_ary_s *ary, intptr_t pos);
|
|
83
115
|
*
|
84
116
|
* If an error occurs, the same data passed to the function is returned.
|
85
117
|
*/
|
86
|
-
FIO_FUNC inline
|
118
|
+
FIO_FUNC inline FIO_ARY_TYPE fio_ary_set(fio_ary_s *ary, FIO_ARY_TYPE data,
|
119
|
+
intptr_t pos);
|
87
120
|
|
88
121
|
/**
|
89
122
|
* Pushes an object to the end of the Array. Returns -1 on error.
|
90
123
|
*/
|
91
|
-
FIO_FUNC inline int fio_ary_push(fio_ary_s *ary,
|
124
|
+
FIO_FUNC inline int fio_ary_push(fio_ary_s *ary, FIO_ARY_TYPE data);
|
92
125
|
|
93
126
|
/** Pops an object from the end of the Array. */
|
94
|
-
FIO_FUNC inline
|
127
|
+
FIO_FUNC inline FIO_ARY_TYPE fio_ary_pop(fio_ary_s *ary);
|
95
128
|
|
96
129
|
/**
|
97
130
|
* Unshifts an object to the beginning of the Array. Returns -1 on error.
|
98
131
|
*
|
99
132
|
* This could be expensive, causing `memmove`.
|
100
133
|
*/
|
101
|
-
FIO_FUNC inline int fio_ary_unshift(fio_ary_s *ary,
|
134
|
+
FIO_FUNC inline int fio_ary_unshift(fio_ary_s *ary, FIO_ARY_TYPE data);
|
102
135
|
|
103
136
|
/** Shifts an object from the beginning of the Array. */
|
104
|
-
FIO_FUNC inline
|
137
|
+
FIO_FUNC inline FIO_ARY_TYPE fio_ary_shift(fio_ary_s *ary);
|
138
|
+
|
139
|
+
/**
|
140
|
+
* Removes an object from the array, MOVING all the other objects to prevent
|
141
|
+
* "holes" in the data.
|
142
|
+
*
|
143
|
+
* Returns the removed object or FIO_ARY_TYPE_INVALID (on error).
|
144
|
+
*/
|
145
|
+
FIO_FUNC inline FIO_ARY_TYPE fio_ary_remove(fio_ary_s *ary, intptr_t index);
|
146
|
+
|
147
|
+
/**
|
148
|
+
* Removes an object from the array, if it exists, MOVING all the other objects
|
149
|
+
* to prevent "holes" in the data.
|
150
|
+
*
|
151
|
+
* Returns -1 if the object wasn't found or 0 if the object was successfully
|
152
|
+
* removed.
|
153
|
+
*/
|
154
|
+
FIO_FUNC inline int fio_ary_remove2(fio_ary_s *ary, FIO_ARY_TYPE data);
|
105
155
|
|
106
156
|
/**
|
107
157
|
* Iteration using a callback for each entry in the array.
|
@@ -115,11 +165,11 @@ FIO_FUNC inline void *fio_ary_shift(fio_ary_s *ary);
|
|
115
165
|
* the starting point.
|
116
166
|
*/
|
117
167
|
FIO_FUNC inline size_t fio_ary_each(fio_ary_s *ary, size_t start_at,
|
118
|
-
int (*task)(
|
168
|
+
int (*task)(FIO_ARY_TYPE pt, void *arg),
|
119
169
|
void *arg);
|
120
170
|
/**
|
121
|
-
* Removes any
|
122
|
-
* array.
|
171
|
+
* Removes any FIO_ARY_TYPE_INVALID object from an Array (NULL pointers by
|
172
|
+
* default), keeping all other data in the array.
|
123
173
|
*
|
124
174
|
* This action is O(n) where n in the length of the array.
|
125
175
|
* It could get expensive.
|
@@ -140,7 +190,7 @@ FIO_FUNC inline void fio_ary_compact(fio_ary_s *ary);
|
|
140
190
|
(++pos.i))
|
141
191
|
struct fio_ary_pos_for_loop_s {
|
142
192
|
unsigned long i;
|
143
|
-
|
193
|
+
FIO_ARY_TYPE obj;
|
144
194
|
};
|
145
195
|
|
146
196
|
/* *****************************************************************************
|
@@ -150,7 +200,7 @@ Array creation API
|
|
150
200
|
FIO_FUNC inline void fio_ary_new(fio_ary_s *ary, size_t capa) {
|
151
201
|
if (!capa)
|
152
202
|
capa = 32;
|
153
|
-
*ary = (fio_ary_s){.arry = (
|
203
|
+
*ary = (fio_ary_s){.arry = (FIO_ARY_TYPE *)malloc(capa * sizeof(*ary->arry)),
|
154
204
|
.capa = capa};
|
155
205
|
if (!ary->arry) {
|
156
206
|
perror("ERROR: facil.io dynamic array couldn't be allocated");
|
@@ -158,8 +208,10 @@ FIO_FUNC inline void fio_ary_new(fio_ary_s *ary, size_t capa) {
|
|
158
208
|
}
|
159
209
|
}
|
160
210
|
FIO_FUNC inline void fio_ary_free(fio_ary_s *ary) {
|
161
|
-
if (ary)
|
211
|
+
if (ary) {
|
162
212
|
free(ary->arry);
|
213
|
+
*ary = FIO_ARY_INIT;
|
214
|
+
}
|
163
215
|
}
|
164
216
|
|
165
217
|
/* *****************************************************************************
|
@@ -170,13 +222,18 @@ Array memory management
|
|
170
222
|
FIO_FUNC void fio_ary_getmem(fio_ary_s *ary, intptr_t needed) {
|
171
223
|
/* we have enough memory, but we need to re-organize it. */
|
172
224
|
if (needed == -1) {
|
225
|
+
if (ary->start > 0) {
|
226
|
+
return;
|
227
|
+
}
|
173
228
|
if (ary->end < ary->capa) {
|
174
229
|
/* since allocation can be cheaper than memmove (depending on size),
|
175
230
|
* we'll just shove everything to the end...
|
176
231
|
*/
|
177
232
|
size_t len = ary->end - ary->start;
|
178
|
-
|
179
|
-
|
233
|
+
if (len) {
|
234
|
+
memmove(ary->arry + ary->capa - len, ary->arry + ary->start,
|
235
|
+
len * sizeof(*ary->arry));
|
236
|
+
}
|
180
237
|
ary->start = ary->capa - len;
|
181
238
|
ary->end = ary->capa;
|
182
239
|
return;
|
@@ -184,10 +241,12 @@ FIO_FUNC void fio_ary_getmem(fio_ary_s *ary, intptr_t needed) {
|
|
184
241
|
/* add some breathing room for future `unshift`s */
|
185
242
|
needed = 0 - ((ary->capa < 1024) ? (ary->capa >> 1) : 1024);
|
186
243
|
|
187
|
-
} else if (needed == 1 && ary->start >= (ary->capa >> 1)) {
|
244
|
+
} else if (needed == 1 && ary->start && ary->start >= (ary->capa >> 1)) {
|
188
245
|
/* FIFO support optimizes smaller FIFO ranges over bloating allocations. */
|
189
246
|
size_t len = ary->end - ary->start;
|
190
|
-
|
247
|
+
if (len) {
|
248
|
+
memmove(ary->arry + 2, ary->arry + ary->start, len * sizeof(*ary->arry));
|
249
|
+
}
|
191
250
|
ary->start = 2;
|
192
251
|
ary->end = len + 2;
|
193
252
|
return;
|
@@ -196,13 +255,17 @@ FIO_FUNC void fio_ary_getmem(fio_ary_s *ary, intptr_t needed) {
|
|
196
255
|
/* alocate using exponential growth, up to single page size. */
|
197
256
|
size_t updated_capa = ary->capa;
|
198
257
|
size_t minimum = ary->capa + ((needed < 0) ? (0 - needed) : needed);
|
258
|
+
if (!updated_capa) {
|
259
|
+
updated_capa = 1;
|
260
|
+
}
|
199
261
|
while (updated_capa <= minimum)
|
200
262
|
updated_capa =
|
201
263
|
(updated_capa <= 4096) ? (updated_capa << 1) : (updated_capa + 4096);
|
202
264
|
|
203
265
|
/* we assume memory allocation works. it's better to crash than to continue
|
204
266
|
* living without memory... besides, malloc is optimistic these days. */
|
205
|
-
ary->arry =
|
267
|
+
ary->arry =
|
268
|
+
(FIO_ARY_TYPE *)realloc(ary->arry, updated_capa * sizeof(*ary->arry));
|
206
269
|
ary->capa = updated_capa;
|
207
270
|
if (!ary->arry) {
|
208
271
|
perror("ERROR: facil.io dynamic array couldn't be reallocated");
|
@@ -212,7 +275,7 @@ FIO_FUNC void fio_ary_getmem(fio_ary_s *ary, intptr_t needed) {
|
|
212
275
|
if (needed >= 0) /* we're done, realloc grows the top of the address space*/
|
213
276
|
return;
|
214
277
|
|
215
|
-
/* move everything to the max, since
|
278
|
+
/* move everything to the max, since memmove could get expensive */
|
216
279
|
size_t len = ary->end - ary->start;
|
217
280
|
memmove((ary->arry + ary->capa) - len, ary->arry + ary->start,
|
218
281
|
len * sizeof(*ary->arry));
|
@@ -224,6 +287,28 @@ FIO_FUNC inline void fiobj_ary_init(fio_ary_s *ary) {
|
|
224
287
|
*ary = (fio_ary_s){.arry = NULL};
|
225
288
|
}
|
226
289
|
|
290
|
+
/* *****************************************************************************
|
291
|
+
Array concat API
|
292
|
+
***************************************************************************** */
|
293
|
+
|
294
|
+
/**
|
295
|
+
* Adds all the items in the `src` Array to the end of the `dest` Array.
|
296
|
+
*
|
297
|
+
* The `src` Array remain untouched.
|
298
|
+
*/
|
299
|
+
FIO_FUNC inline void fio_ary_concat(fio_ary_s *dest, fio_ary_s *src) {
|
300
|
+
if (!dest || !src || src->start == src->end)
|
301
|
+
return;
|
302
|
+
const intptr_t len = src->end - src->start;
|
303
|
+
fio_ary_getmem(dest, len);
|
304
|
+
memcpy(dest->arry + dest->end, src->arry + src->start,
|
305
|
+
(len * sizeof(*dest->arry)));
|
306
|
+
// memcpy((void *)((uintptr_t)dest->arry + (sizeof(*dest->arry) * dest->end)),
|
307
|
+
// (void *)((uintptr_t)src->arry + (sizeof(*dest->arry) * src->start)),
|
308
|
+
// (len * sizeof(*dest->arry)));
|
309
|
+
dest->end += len;
|
310
|
+
}
|
311
|
+
|
227
312
|
/* *****************************************************************************
|
228
313
|
Array direct entry access API
|
229
314
|
***************************************************************************** */
|
@@ -243,29 +328,46 @@ FIO_FUNC inline size_t fio_ary_capa(fio_ary_s *ary) { return ary->capa; }
|
|
243
328
|
*
|
244
329
|
* fiobj_dup(fiobj_ary_index(array, 0));
|
245
330
|
*
|
246
|
-
* Negative values are
|
331
|
+
* Negative values are retrieved from the end of the array. i.e., `-1`
|
247
332
|
* is the last item.
|
248
333
|
*/
|
249
|
-
FIO_FUNC inline
|
334
|
+
FIO_FUNC inline FIO_ARY_TYPE fio_ary_index(fio_ary_s *ary, intptr_t pos) {
|
250
335
|
if (!ary || !ary->arry)
|
251
|
-
return
|
336
|
+
return FIO_ARY_TYPE_INVALID;
|
252
337
|
/* position is relative to `start`*/
|
253
338
|
if (pos >= 0) {
|
254
339
|
pos = pos + ary->start;
|
255
340
|
if ((size_t)pos >= ary->end)
|
256
|
-
return
|
341
|
+
return FIO_ARY_TYPE_INVALID;
|
257
342
|
return ary->arry[pos];
|
258
343
|
}
|
259
344
|
/* position is relative to `end`*/
|
260
345
|
pos = (intptr_t)ary->end + pos;
|
261
346
|
if (pos < 0 || (size_t)pos < ary->start)
|
262
|
-
return
|
347
|
+
return FIO_ARY_TYPE_INVALID;
|
263
348
|
return ary->arry[pos];
|
264
349
|
}
|
265
350
|
|
266
351
|
/** alias for `fiobj_ary_index` */
|
267
352
|
#define fio_ary_entry(a, p) fiobj_ary_index((a), (p))
|
268
353
|
|
354
|
+
/**
|
355
|
+
* Returns the index of the object or -1 if the object wasn't found.
|
356
|
+
*/
|
357
|
+
FIO_FUNC inline intptr_t fio_ary_find(fio_ary_s *ary, FIO_ARY_TYPE data) {
|
358
|
+
if (!ary || ary->start == ary->end || !ary->arry) {
|
359
|
+
return -1;
|
360
|
+
}
|
361
|
+
size_t pos = ary->start;
|
362
|
+
register const size_t end = ary->end;
|
363
|
+
while (pos < end && !FIO_ARY_TYPE_COMPARE(data, ary->arry[pos])) {
|
364
|
+
++pos;
|
365
|
+
}
|
366
|
+
if (pos == end)
|
367
|
+
return -1;
|
368
|
+
return (pos - ary->start);
|
369
|
+
}
|
370
|
+
|
269
371
|
/**
|
270
372
|
* Sets an object at the requested position.
|
271
373
|
*
|
@@ -273,11 +375,12 @@ FIO_FUNC inline void *fio_ary_index(fio_ary_s *ary, intptr_t pos) {
|
|
273
375
|
*
|
274
376
|
* If an error occurs, the same data passed to the function is returned.
|
275
377
|
*/
|
276
|
-
FIO_FUNC inline
|
378
|
+
FIO_FUNC inline FIO_ARY_TYPE fio_ary_set(fio_ary_s *ary, FIO_ARY_TYPE data,
|
379
|
+
intptr_t pos) {
|
277
380
|
if (!ary->arry) {
|
278
381
|
fio_ary_new(ary, 0);
|
279
382
|
}
|
280
|
-
|
383
|
+
FIO_ARY_TYPE old = FIO_ARY_TYPE_INVALID;
|
281
384
|
/* test for memory and request memory if missing, promises valid bounds. */
|
282
385
|
if (pos >= 0) {
|
283
386
|
if ((size_t)pos + ary->start >= ary->capa)
|
@@ -290,13 +393,13 @@ FIO_FUNC inline void *fio_ary_set(fio_ary_s *ary, void *data, intptr_t pos) {
|
|
290
393
|
pos = pos + ary->start;
|
291
394
|
/* initialize empty spaces, if any, setting new boundries */
|
292
395
|
while ((size_t)pos >= ary->end)
|
293
|
-
ary->arry[(ary->end)++] =
|
396
|
+
ary->arry[(ary->end)++] = FIO_ARY_TYPE_INVALID;
|
294
397
|
} else {
|
295
398
|
/* position relative to end */
|
296
399
|
pos = pos + (intptr_t)ary->end;
|
297
400
|
/* initialize empty spaces, if any, setting new boundries */
|
298
401
|
while (ary->start > (size_t)pos)
|
299
|
-
ary->arry[--(ary->start)] =
|
402
|
+
ary->arry[--(ary->start)] = FIO_ARY_TYPE_INVALID;
|
300
403
|
}
|
301
404
|
|
302
405
|
/* check for an existing object and set new objects */
|
@@ -313,7 +416,7 @@ Array push / shift API
|
|
313
416
|
/**
|
314
417
|
* Pushes an object to the end of the Array. Returns -1 on error.
|
315
418
|
*/
|
316
|
-
FIO_FUNC inline int fio_ary_push(fio_ary_s *ary,
|
419
|
+
FIO_FUNC inline int fio_ary_push(fio_ary_s *ary, FIO_ARY_TYPE data) {
|
317
420
|
if (!ary->arry)
|
318
421
|
fio_ary_new(ary, 0);
|
319
422
|
else if (ary->capa <= ary->end)
|
@@ -324,32 +427,31 @@ FIO_FUNC inline int fio_ary_push(fio_ary_s *ary, void *data) {
|
|
324
427
|
}
|
325
428
|
|
326
429
|
/** Pops an object from the end of the Array. */
|
327
|
-
FIO_FUNC inline
|
430
|
+
FIO_FUNC inline FIO_ARY_TYPE fio_ary_pop(fio_ary_s *ary) {
|
328
431
|
if (!ary || ary->start == ary->end)
|
329
|
-
return
|
432
|
+
return FIO_ARY_TYPE_INVALID;
|
330
433
|
ary->end -= 1;
|
331
434
|
return ary->arry[ary->end];
|
332
435
|
}
|
333
436
|
|
334
437
|
/**
|
335
|
-
* Unshifts an object to the
|
438
|
+
* Unshifts an object to the beginning of the Array. Returns -1 on error.
|
336
439
|
*
|
337
440
|
* This could be expensive, causing `memmove`.
|
338
441
|
*/
|
339
|
-
FIO_FUNC inline int fio_ary_unshift(fio_ary_s *ary,
|
442
|
+
FIO_FUNC inline int fio_ary_unshift(fio_ary_s *ary, FIO_ARY_TYPE data) {
|
340
443
|
if (!ary->arry)
|
341
444
|
fio_ary_new(ary, 0);
|
342
|
-
|
343
|
-
fio_ary_getmem(ary, -1);
|
445
|
+
fio_ary_getmem(ary, -1);
|
344
446
|
ary->start -= 1;
|
345
447
|
ary->arry[ary->start] = data;
|
346
448
|
return 0;
|
347
449
|
}
|
348
450
|
|
349
451
|
/** Shifts an object from the beginning of the Array. */
|
350
|
-
FIO_FUNC inline
|
452
|
+
FIO_FUNC inline FIO_ARY_TYPE fio_ary_shift(fio_ary_s *ary) {
|
351
453
|
if (!ary || ary->start == ary->end)
|
352
|
-
return
|
454
|
+
return FIO_ARY_TYPE_INVALID;
|
353
455
|
#ifdef __cplusplus
|
354
456
|
const size_t pos = ary->start;
|
355
457
|
#else
|
@@ -359,6 +461,55 @@ FIO_FUNC inline void *fio_ary_shift(fio_ary_s *ary) {
|
|
359
461
|
return ary->arry[pos];
|
360
462
|
}
|
361
463
|
|
464
|
+
/**
|
465
|
+
* Removes an object from the array, MOVING all the other objects to prevent
|
466
|
+
* "holes" in the data.
|
467
|
+
*
|
468
|
+
* Returns the removed object or FIO_ARY_TYPE_INVALID (on error).
|
469
|
+
*/
|
470
|
+
FIO_FUNC inline FIO_ARY_TYPE fio_ary_remove(fio_ary_s *ary, intptr_t index) {
|
471
|
+
if (!ary || ary->start == ary->end || !ary->arry) {
|
472
|
+
return FIO_ARY_TYPE_INVALID;
|
473
|
+
}
|
474
|
+
if (index < 0) {
|
475
|
+
index = (ary->end - ary->start) + index;
|
476
|
+
if (index < 0) {
|
477
|
+
return FIO_ARY_TYPE_INVALID;
|
478
|
+
}
|
479
|
+
}
|
480
|
+
--ary->end;
|
481
|
+
index += ary->start;
|
482
|
+
FIO_ARY_TYPE old = ary->arry[(size_t)index];
|
483
|
+
register const size_t len = ary->end;
|
484
|
+
while ((size_t)index < len) {
|
485
|
+
ary->arry[(size_t)index] = ary->arry[(size_t)index + 1];
|
486
|
+
++index;
|
487
|
+
}
|
488
|
+
return old;
|
489
|
+
}
|
490
|
+
|
491
|
+
/**
|
492
|
+
* Removes an object from the array, if it exists, MOVING all the other objects
|
493
|
+
* to prevent "holes" in the data.
|
494
|
+
*
|
495
|
+
* Returns -1 if the object wasn't found or 0 if the object was successfully
|
496
|
+
* removed.
|
497
|
+
*/
|
498
|
+
FIO_FUNC inline int fio_ary_remove2(fio_ary_s *ary, FIO_ARY_TYPE data) {
|
499
|
+
intptr_t index = fio_ary_find(ary, data);
|
500
|
+
if (index == -1) {
|
501
|
+
return -1;
|
502
|
+
}
|
503
|
+
index += ary->start;
|
504
|
+
--ary->end;
|
505
|
+
register const size_t len = ary->end;
|
506
|
+
while ((size_t)index < len) {
|
507
|
+
ary->arry[(size_t)index] = ary->arry[(size_t)index + 1];
|
508
|
+
++index;
|
509
|
+
}
|
510
|
+
return 0;
|
511
|
+
}
|
512
|
+
|
362
513
|
/**
|
363
514
|
* Single layer iteration using a callback for each entry in the array.
|
364
515
|
*
|
@@ -371,7 +522,7 @@ FIO_FUNC inline void *fio_ary_shift(fio_ary_s *ary) {
|
|
371
522
|
* the starting point.
|
372
523
|
*/
|
373
524
|
FIO_FUNC inline size_t fio_ary_each(fio_ary_s *ary, size_t start_at,
|
374
|
-
int (*task)(
|
525
|
+
int (*task)(FIO_ARY_TYPE data, void *arg),
|
375
526
|
void *arg) {
|
376
527
|
if (!ary || ary->start == ary->end)
|
377
528
|
return 0;
|
@@ -387,8 +538,8 @@ Array compacting (untested)
|
|
387
538
|
***************************************************************************** */
|
388
539
|
|
389
540
|
/**
|
390
|
-
* Removes any
|
391
|
-
* array.
|
541
|
+
* Removes any FIO_ARY_TYPE_INVALID *pointers* from an Array, keeping all other
|
542
|
+
* data in the array.
|
392
543
|
*
|
393
544
|
* This action is O(n) where n in the length of the array.
|
394
545
|
* It could get expensive.
|
@@ -396,9 +547,9 @@ Array compacting (untested)
|
|
396
547
|
FIO_FUNC inline void fio_ary_compact(fio_ary_s *ary) {
|
397
548
|
if (!ary || ary->start == ary->end)
|
398
549
|
return;
|
399
|
-
register
|
400
|
-
register
|
401
|
-
register
|
550
|
+
register FIO_ARY_TYPE *pos = ary->arry + ary->start;
|
551
|
+
register FIO_ARY_TYPE *reader = ary->arry + ary->start;
|
552
|
+
register FIO_ARY_TYPE *stop = ary->arry + ary->end;
|
402
553
|
while (reader < stop) {
|
403
554
|
if (*reader) {
|
404
555
|
*pos = *reader;
|
@@ -409,6 +560,154 @@ FIO_FUNC inline void fio_ary_compact(fio_ary_s *ary) {
|
|
409
560
|
ary->end = (size_t)(pos - ary->arry);
|
410
561
|
}
|
411
562
|
|
563
|
+
/* *****************************************************************************
|
564
|
+
Testing
|
565
|
+
***************************************************************************** */
|
566
|
+
|
567
|
+
#if DEBUG
|
568
|
+
#include <stdio.h>
|
569
|
+
#define TEST_LIMIT 1016
|
570
|
+
#define TEST_ASSERT(cond, ...) \
|
571
|
+
if (!(cond)) { \
|
572
|
+
fprintf(stderr, "* " __VA_ARGS__); \
|
573
|
+
fprintf(stderr, "\n !!! Testing failed !!!\n"); \
|
574
|
+
exit(-1); \
|
575
|
+
}
|
576
|
+
/**
|
577
|
+
* Removes any FIO_ARY_TYPE_INVALID *pointers* from an Array, keeping all other
|
578
|
+
* data in the array.
|
579
|
+
*
|
580
|
+
* This action is O(n) where n in the length of the array.
|
581
|
+
* It could get expensive.
|
582
|
+
*/
|
583
|
+
FIO_FUNC inline void fio_ary_test(void) {
|
584
|
+
union {
|
585
|
+
FIO_ARY_TYPE obj;
|
586
|
+
uintptr_t i;
|
587
|
+
} mem[TEST_LIMIT];
|
588
|
+
fio_ary_s ary = FIO_ARY_INIT;
|
589
|
+
fprintf(stderr, "=== Testing Core Array features (fio_ary.h)\n");
|
590
|
+
|
591
|
+
for (uintptr_t i = 0; i < TEST_LIMIT; ++i) {
|
592
|
+
mem[i].i = i + 1;
|
593
|
+
fio_ary_push(&ary, mem[i].obj);
|
594
|
+
}
|
595
|
+
fprintf(stderr,
|
596
|
+
"* Array populated using `push` with %zu items,\n"
|
597
|
+
" with capacity limit of %zu and start index %zu\n",
|
598
|
+
(size_t)fio_ary_count(&ary), (size_t)fio_ary_capa(&ary), ary.start);
|
599
|
+
TEST_ASSERT(fio_ary_count(&ary) == TEST_LIMIT,
|
600
|
+
"Wrong object count for array %zu", (size_t)fio_ary_count(&ary));
|
601
|
+
for (uintptr_t i = 0; i < TEST_LIMIT; ++i) {
|
602
|
+
mem[0].obj = fio_ary_shift(&ary);
|
603
|
+
TEST_ASSERT(mem[0].i == i + 1, "Array shift value error");
|
604
|
+
}
|
605
|
+
|
606
|
+
fio_ary_free(&ary);
|
607
|
+
TEST_ASSERT(!ary.arry, "Array not reset after fio_ary_free");
|
608
|
+
|
609
|
+
for (uintptr_t i = 0; i < TEST_LIMIT; ++i) {
|
610
|
+
mem[i].i = TEST_LIMIT - i;
|
611
|
+
fio_ary_unshift(&ary, mem[i].obj);
|
612
|
+
}
|
613
|
+
fprintf(stderr,
|
614
|
+
"* Array populated using `unshift` with %zu items,\n"
|
615
|
+
" with capacity limit of %zu and start index %zu\n",
|
616
|
+
(size_t)fio_ary_count(&ary), (size_t)fio_ary_capa(&ary), ary.start);
|
617
|
+
TEST_ASSERT(fio_ary_count(&ary) == TEST_LIMIT,
|
618
|
+
"Wrong object count for array %zu", (size_t)fio_ary_count(&ary));
|
619
|
+
for (uintptr_t i = 0; i < TEST_LIMIT; ++i) {
|
620
|
+
mem[0].obj = fio_ary_pop(&ary);
|
621
|
+
TEST_ASSERT(mem[0].i == TEST_LIMIT - i, "Array pop value error");
|
622
|
+
}
|
623
|
+
fio_ary_free(&ary);
|
624
|
+
TEST_ASSERT(!ary.arry, "Array not reset after fio_ary_free");
|
625
|
+
|
626
|
+
for (uintptr_t i = 0; i < TEST_LIMIT; ++i) {
|
627
|
+
mem[i].i = TEST_LIMIT - i;
|
628
|
+
fio_ary_unshift(&ary, mem[i].obj);
|
629
|
+
}
|
630
|
+
|
631
|
+
for (int i = 0; i < TEST_LIMIT; ++i) {
|
632
|
+
mem[0].i = i + 1;
|
633
|
+
TEST_ASSERT(fio_ary_find(&ary, mem[0].obj) == i,
|
634
|
+
"Wrong object index - ary[%zd] != %zu",
|
635
|
+
(ssize_t)fio_ary_find(&ary, mem[0].obj), (size_t)mem[0].i);
|
636
|
+
mem[0].obj = fio_ary_index(&ary, i);
|
637
|
+
TEST_ASSERT(mem[0].i == (uintptr_t)(i + 1),
|
638
|
+
"Wrong object returned from fio_ary_index - ary[%d] != %d", i,
|
639
|
+
i + 1);
|
640
|
+
}
|
641
|
+
|
642
|
+
TEST_ASSERT((mem[0].obj = fio_ary_pop(&ary)), "Couldn't pop element.");
|
643
|
+
TEST_ASSERT(mem[0].i == TEST_LIMIT, "Element value error (%zu).",
|
644
|
+
(size_t)mem[0].i);
|
645
|
+
TEST_ASSERT(fio_ary_count(&ary) == TEST_LIMIT - 1,
|
646
|
+
"Wrong object count after pop %zu", (size_t)fio_ary_count(&ary));
|
647
|
+
|
648
|
+
mem[0].i = (TEST_LIMIT >> 1);
|
649
|
+
TEST_ASSERT(!fio_ary_remove2(&ary, mem[0].obj),
|
650
|
+
"Couldn't fio_ary_remove2 object from Array (%zu)",
|
651
|
+
(size_t)mem[0].i);
|
652
|
+
TEST_ASSERT(fio_ary_count(&ary) == TEST_LIMIT - 2,
|
653
|
+
"Wrong object count after remove2 %zu",
|
654
|
+
(size_t)fio_ary_count(&ary));
|
655
|
+
mem[0].i = (TEST_LIMIT >> 1) + 1;
|
656
|
+
TEST_ASSERT(fio_ary_find(&ary, mem[0].obj) != (TEST_LIMIT >> 1) + 1,
|
657
|
+
"fio_ary_remove2 didn't clear holes from Array (%zu)",
|
658
|
+
(size_t)fio_ary_find(&ary, mem[0].obj));
|
659
|
+
|
660
|
+
mem[0].obj = fio_ary_remove(&ary, 0);
|
661
|
+
TEST_ASSERT(mem[0].i == 1, "Couldn't fio_ary_remove object from Array (%zd)",
|
662
|
+
(ssize_t)mem[0].i);
|
663
|
+
TEST_ASSERT(fio_ary_count(&ary) == TEST_LIMIT - 3,
|
664
|
+
"Wrong object count after remove %zu",
|
665
|
+
(size_t)fio_ary_count(&ary));
|
666
|
+
TEST_ASSERT(fio_ary_find(&ary, mem[0].obj) == -1,
|
667
|
+
"fio_ary_find should have failed after fio_ary_remove (%zd)",
|
668
|
+
(ssize_t)fio_ary_find(&ary, mem[0].obj));
|
669
|
+
mem[0].i = 2;
|
670
|
+
TEST_ASSERT(fio_ary_find(&ary, mem[0].obj) == 0,
|
671
|
+
"fio_ary_remove didn't clear holes from Array (%zu)",
|
672
|
+
(size_t)fio_ary_find(&ary, mem[0].obj));
|
673
|
+
|
674
|
+
fio_ary_free(&ary);
|
675
|
+
|
676
|
+
fio_ary_s ary2 = FIO_ARY_INIT;
|
677
|
+
for (uintptr_t i = 0; i < (TEST_LIMIT >> 1); ++i) {
|
678
|
+
mem[i].i = ((TEST_LIMIT >> 1) << 1) - i;
|
679
|
+
fio_ary_unshift(&ary2, mem[i].obj);
|
680
|
+
mem[i].i = (TEST_LIMIT >> 1) - i;
|
681
|
+
fio_ary_unshift(&ary, mem[i].obj);
|
682
|
+
}
|
683
|
+
fio_ary_concat(&ary, &ary2);
|
684
|
+
fio_ary_free(&ary2);
|
685
|
+
TEST_ASSERT(fio_ary_count(&ary) == ((TEST_LIMIT >> 1) << 1),
|
686
|
+
"Wrong object count after fio_ary_concat %zu",
|
687
|
+
(size_t)fio_ary_count(&ary));
|
688
|
+
for (int i = 0; i < ((TEST_LIMIT >> 1) << 1); ++i) {
|
689
|
+
mem[0].obj = fio_ary_index(&ary, i);
|
690
|
+
TEST_ASSERT(
|
691
|
+
mem[0].i == (uintptr_t)(i + 1),
|
692
|
+
"Wrong object returned from fio_ary_index after concat - ary[%d] != %d",
|
693
|
+
i, i + 1);
|
694
|
+
}
|
695
|
+
mem[1].i = 0;
|
696
|
+
while ((mem[0].obj = fio_ary_pop(&ary))) {
|
697
|
+
++mem[1].i;
|
698
|
+
}
|
699
|
+
TEST_ASSERT(mem[1].i == ((TEST_LIMIT >> 1) << 1),
|
700
|
+
"fio_ary_pop overflow (%zu)?", (size_t)mem[1].i);
|
701
|
+
fio_ary_free(&ary);
|
702
|
+
}
|
703
|
+
#undef TEST_LIMIT
|
704
|
+
#undef TEST_ASSERT
|
705
|
+
#endif
|
706
|
+
|
707
|
+
/* *****************************************************************************
|
708
|
+
Done
|
709
|
+
***************************************************************************** */
|
710
|
+
|
412
711
|
#ifdef __cplusplus
|
413
712
|
#undef register
|
414
713
|
#endif
|