iodine 0.4.19 → 0.5.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/.travis.yml +1 -2
- data/CHANGELOG.md +22 -0
- data/LIMITS.md +19 -9
- data/README.md +92 -77
- data/SPEC-PubSub-Draft.md +113 -0
- data/SPEC-Websocket-Draft.md +127 -143
- data/bin/http-hello +0 -1
- data/bin/raw-rbhttp +1 -1
- data/bin/raw_broadcast +8 -10
- data/bin/updated api +2 -2
- data/bin/ws-broadcast +2 -4
- data/bin/ws-echo +2 -2
- data/examples/config.ru +13 -13
- data/examples/echo.ru +5 -6
- data/examples/hello.ru +2 -3
- data/examples/info.md +316 -0
- data/examples/pubsub_engine.ru +81 -0
- data/examples/redis.ru +9 -9
- data/examples/shootout.ru +45 -11
- data/ext/iodine/defer.c +194 -297
- data/ext/iodine/defer.h +61 -53
- data/ext/iodine/evio.c +0 -260
- data/ext/iodine/evio.h +50 -22
- data/ext/iodine/evio_callbacks.c +26 -0
- data/ext/iodine/evio_epoll.c +251 -0
- data/ext/iodine/evio_kqueue.c +193 -0
- data/ext/iodine/extconf.rb +1 -1
- data/ext/iodine/facil.c +1420 -542
- data/ext/iodine/facil.h +151 -64
- data/ext/iodine/fio_ary.h +418 -0
- data/ext/iodine/{base64.c → fio_base64.c} +33 -24
- data/ext/iodine/{base64.h → fio_base64.h} +6 -7
- data/ext/iodine/{fio_cli_helper.c → fio_cli.c} +77 -58
- data/ext/iodine/{fio_cli_helper.h → fio_cli.h} +9 -4
- data/ext/iodine/fio_hashmap.h +759 -0
- data/ext/iodine/fio_json_parser.h +651 -0
- data/ext/iodine/fio_llist.h +257 -0
- data/ext/iodine/fio_mem.c +672 -0
- data/ext/iodine/fio_mem.h +140 -0
- data/ext/iodine/fio_random.c +248 -0
- data/ext/iodine/{random.h → fio_random.h} +11 -14
- data/ext/iodine/{sha1.c → fio_sha1.c} +28 -24
- data/ext/iodine/{sha1.h → fio_sha1.h} +38 -16
- data/ext/iodine/{sha2.c → fio_sha2.c} +66 -49
- data/ext/iodine/{sha2.h → fio_sha2.h} +57 -26
- data/ext/iodine/{fiobj_internal.c → fio_siphash.c} +9 -90
- data/ext/iodine/fio_siphash.h +18 -0
- data/ext/iodine/fio_tmpfile.h +38 -0
- data/ext/iodine/fiobj.h +24 -7
- data/ext/iodine/fiobj4sock.h +23 -0
- data/ext/iodine/fiobj_ary.c +143 -226
- data/ext/iodine/fiobj_ary.h +17 -16
- data/ext/iodine/fiobj_data.c +1160 -0
- data/ext/iodine/fiobj_data.h +164 -0
- data/ext/iodine/fiobj_hash.c +298 -406
- data/ext/iodine/fiobj_hash.h +101 -54
- data/ext/iodine/fiobj_json.c +478 -601
- data/ext/iodine/fiobj_json.h +34 -9
- data/ext/iodine/fiobj_numbers.c +383 -51
- data/ext/iodine/fiobj_numbers.h +87 -11
- data/ext/iodine/fiobj_str.c +423 -184
- data/ext/iodine/fiobj_str.h +81 -32
- data/ext/iodine/fiobject.c +273 -522
- data/ext/iodine/fiobject.h +477 -112
- data/ext/iodine/http.c +2243 -83
- data/ext/iodine/http.h +842 -121
- data/ext/iodine/http1.c +810 -385
- data/ext/iodine/http1.h +16 -39
- data/ext/iodine/http1_parser.c +146 -74
- data/ext/iodine/http1_parser.h +15 -4
- data/ext/iodine/http_internal.c +1258 -0
- data/ext/iodine/http_internal.h +226 -0
- data/ext/iodine/http_mime_parser.h +341 -0
- data/ext/iodine/iodine.c +86 -68
- data/ext/iodine/iodine.h +26 -11
- data/ext/iodine/iodine_helpers.c +8 -7
- data/ext/iodine/iodine_http.c +487 -324
- data/ext/iodine/iodine_json.c +304 -0
- data/ext/iodine/iodine_json.h +6 -0
- data/ext/iodine/iodine_protocol.c +107 -45
- data/ext/iodine/iodine_pubsub.c +526 -225
- data/ext/iodine/iodine_pubsub.h +10 -0
- data/ext/iodine/iodine_websockets.c +268 -510
- data/ext/iodine/iodine_websockets.h +2 -4
- data/ext/iodine/pubsub.c +726 -432
- data/ext/iodine/pubsub.h +85 -103
- data/ext/iodine/rb-call.c +4 -4
- data/ext/iodine/rb-defer.c +46 -22
- data/ext/iodine/rb-fiobj2rb.h +117 -0
- data/ext/iodine/rb-rack-io.c +73 -238
- data/ext/iodine/rb-rack-io.h +2 -2
- data/ext/iodine/rb-registry.c +35 -93
- data/ext/iodine/rb-registry.h +1 -0
- data/ext/iodine/redis_engine.c +742 -304
- data/ext/iodine/redis_engine.h +42 -39
- data/ext/iodine/resp_parser.h +311 -0
- data/ext/iodine/sock.c +627 -490
- data/ext/iodine/sock.h +345 -297
- data/ext/iodine/spnlock.inc +15 -4
- data/ext/iodine/websocket_parser.h +16 -20
- data/ext/iodine/websockets.c +188 -257
- data/ext/iodine/websockets.h +24 -133
- data/lib/iodine.rb +52 -7
- data/lib/iodine/cli.rb +6 -24
- data/lib/iodine/json.rb +40 -0
- data/lib/iodine/version.rb +1 -1
- data/lib/iodine/websocket.rb +5 -3
- data/lib/rack/handler/iodine.rb +58 -13
- metadata +38 -48
- data/bin/ws-shootout +0 -107
- data/examples/broadcast.ru +0 -56
- data/ext/iodine/bscrypt-common.h +0 -116
- data/ext/iodine/bscrypt.h +0 -49
- data/ext/iodine/fio2resp.c +0 -60
- data/ext/iodine/fio2resp.h +0 -51
- data/ext/iodine/fio_dict.c +0 -446
- data/ext/iodine/fio_dict.h +0 -99
- data/ext/iodine/fio_hash_table.h +0 -370
- data/ext/iodine/fio_list.h +0 -111
- data/ext/iodine/fiobj_internal.h +0 -280
- data/ext/iodine/fiobj_primitives.c +0 -131
- data/ext/iodine/fiobj_primitives.h +0 -55
- data/ext/iodine/fiobj_sym.c +0 -135
- data/ext/iodine/fiobj_sym.h +0 -60
- data/ext/iodine/hex.c +0 -124
- data/ext/iodine/hex.h +0 -70
- data/ext/iodine/http1_request.c +0 -81
- data/ext/iodine/http1_request.h +0 -58
- data/ext/iodine/http1_response.c +0 -417
- data/ext/iodine/http1_response.h +0 -95
- data/ext/iodine/http_request.c +0 -111
- data/ext/iodine/http_request.h +0 -102
- data/ext/iodine/http_response.c +0 -1703
- data/ext/iodine/http_response.h +0 -250
- data/ext/iodine/misc.c +0 -182
- data/ext/iodine/misc.h +0 -74
- data/ext/iodine/random.c +0 -208
- data/ext/iodine/redis_connection.c +0 -278
- data/ext/iodine/redis_connection.h +0 -86
- data/ext/iodine/resp.c +0 -842
- data/ext/iodine/resp.h +0 -261
- data/ext/iodine/siphash.c +0 -154
- data/ext/iodine/siphash.h +0 -22
- data/ext/iodine/xor-crypt.c +0 -193
- data/ext/iodine/xor-crypt.h +0 -107
@@ -2,97 +2,10 @@
|
|
2
2
|
Copyright: Boaz Segev, 2017
|
3
3
|
License: MIT
|
4
4
|
*/
|
5
|
-
#include "
|
6
|
-
|
7
|
-
#include <errno.h>
|
8
|
-
#include <math.h>
|
9
|
-
#include <signal.h>
|
10
|
-
#include <stdarg.h>
|
11
|
-
#include <stdio.h>
|
12
|
-
#include <stdlib.h>
|
13
|
-
#include <string.h>
|
14
|
-
#include <sys/types.h>
|
15
|
-
|
16
|
-
/* *****************************************************************************
|
17
|
-
Internal API required across the board
|
18
|
-
***************************************************************************** */
|
19
|
-
|
20
|
-
void fiobj_simple_dealloc(fiobj_s *o) { fiobj_dealloc(o); }
|
21
|
-
|
22
|
-
void fiobj_noop_free(fiobj_s *obj) { OBJ2HEAD(obj)->ref = (uintptr_t)-1; }
|
23
|
-
|
24
|
-
int fiobj_noop_true(const fiobj_s *obj) {
|
25
|
-
return 1;
|
26
|
-
(void)obj;
|
27
|
-
}
|
28
|
-
int fiobj_noop_false(const fiobj_s *obj) {
|
29
|
-
return 0;
|
30
|
-
(void)obj;
|
31
|
-
}
|
32
|
-
fio_cstr_s fiobj_noop_str(const fiobj_s *obj) {
|
33
|
-
return (fio_cstr_s){.length = 0, .data = ""};
|
34
|
-
(void)obj;
|
35
|
-
}
|
36
|
-
int64_t fiobj_noop_i(const fiobj_s *obj) {
|
37
|
-
return 0;
|
38
|
-
(void)obj;
|
39
|
-
}
|
40
|
-
double fiobj_noop_f(const fiobj_s *obj) {
|
41
|
-
return 0;
|
42
|
-
(void)obj;
|
43
|
-
}
|
44
|
-
|
45
|
-
/** always 0. */
|
46
|
-
int fiobj_noop_is_eq(const fiobj_s *self, const fiobj_s *other) {
|
47
|
-
return 0;
|
48
|
-
(void)self;
|
49
|
-
(void)other;
|
50
|
-
}
|
51
|
-
|
52
|
-
size_t fiobj_noop_count(const fiobj_s *obj) {
|
53
|
-
return 0;
|
54
|
-
(void)obj;
|
55
|
-
}
|
56
|
-
fiobj_s *fiobj_noop_unwrap(const fiobj_s *obj) {
|
57
|
-
return (fiobj_s *)obj;
|
58
|
-
(void)obj;
|
59
|
-
}
|
60
|
-
size_t fiobj_noop_each1(fiobj_s *obj, size_t start_at,
|
61
|
-
int (*task)(fiobj_s *obj, void *arg), void *arg) {
|
62
|
-
return 0;
|
63
|
-
(void)obj;
|
64
|
-
(void)start_at;
|
65
|
-
(void)task;
|
66
|
-
(void)arg;
|
67
|
-
}
|
68
|
-
|
69
|
-
/* *****************************************************************************
|
70
|
-
Invalid Object VTable - unused, still considering...
|
71
|
-
***************************************************************************** */
|
72
|
-
|
73
|
-
// static void fiobj_noop_free_invalid(fiobj_s *obj) { (void)obj; }
|
74
|
-
// static int64_t fiobj_noop_i_invalid(const fiobj_s *obj) {
|
75
|
-
// return ((int64_t)(obj) ^ 3);
|
76
|
-
// }
|
77
|
-
// struct fiobj_vtable_s FIOBJ_VTABLE_INVALID = {
|
78
|
-
// .name = "Invalid Class - not a facil.io Object",
|
79
|
-
// .free = fiobj_noop_free_invalid,
|
80
|
-
// .is_true = fiobj_noop_false,
|
81
|
-
// .to_str = fiobj_noop_str,
|
82
|
-
// .to_i = fiobj_noop_i_invalid,
|
83
|
-
// .to_f = fiobj_noop_f,
|
84
|
-
// .is_eq = fiobj_noop_is_eq,
|
85
|
-
// .count = fiobj_noop_count,
|
86
|
-
// .unwrap = fiobj_noop_unwrap,
|
87
|
-
// .each1 = fiobj_noop_each1,
|
88
|
-
// };
|
89
|
-
|
90
|
-
/* *****************************************************************************
|
91
|
-
Internal API required across the board
|
92
|
-
***************************************************************************** */
|
5
|
+
#include "fio_siphash.h"
|
93
6
|
|
94
7
|
/* *****************************************************************************
|
95
|
-
Hashing (SipHash
|
8
|
+
Hashing (SipHash implementation)
|
96
9
|
***************************************************************************** */
|
97
10
|
|
98
11
|
#if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) && \
|
@@ -112,7 +25,7 @@ Hashing (SipHash copy)
|
|
112
25
|
#define lrot64(i, bits) \
|
113
26
|
(((uint64_t)(i) << (bits)) | ((uint64_t)(i) >> (64 - (bits))))
|
114
27
|
|
115
|
-
uint64_t
|
28
|
+
uint64_t fio_siphash(const void *data, size_t len) {
|
116
29
|
/* initialize the 4 words */
|
117
30
|
uint64_t v0 = (0x0706050403020100ULL ^ 0x736f6d6570736575ULL);
|
118
31
|
uint64_t v1 = (0x0f0e0d0c0b0a0908ULL ^ 0x646f72616e646f6dULL);
|
@@ -155,16 +68,22 @@ uint64_t fiobj_sym_hash(const void *data, size_t len) {
|
|
155
68
|
switch (len) { /* fallthrough is intentional */
|
156
69
|
case 7:
|
157
70
|
pos[6] = w8[6];
|
71
|
+
/* fallthrough */
|
158
72
|
case 6:
|
159
73
|
pos[5] = w8[5];
|
74
|
+
/* fallthrough */
|
160
75
|
case 5:
|
161
76
|
pos[4] = w8[4];
|
77
|
+
/* fallthrough */
|
162
78
|
case 4:
|
163
79
|
pos[3] = w8[3];
|
80
|
+
/* fallthrough */
|
164
81
|
case 3:
|
165
82
|
pos[2] = w8[2];
|
83
|
+
/* fallthrough */
|
166
84
|
case 2:
|
167
85
|
pos[1] = w8[1];
|
86
|
+
/* fallthrough */
|
168
87
|
case 1:
|
169
88
|
pos[0] = w8[0];
|
170
89
|
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#ifndef H_FIO_SIPHASH_H
|
2
|
+
#define H_FIO_SIPHASH_H
|
3
|
+
|
4
|
+
#ifndef _GNU_SOURCE
|
5
|
+
#define _GNU_SOURCE
|
6
|
+
#endif
|
7
|
+
|
8
|
+
#include <stdint.h>
|
9
|
+
#include <sys/types.h>
|
10
|
+
|
11
|
+
/**
|
12
|
+
* The Hashing function used by dynamic facil.io objects.
|
13
|
+
*
|
14
|
+
* Currently implemented using SipHash.
|
15
|
+
*/
|
16
|
+
uint64_t fio_siphash(const void *data, size_t len);
|
17
|
+
|
18
|
+
#endif
|
@@ -0,0 +1,38 @@
|
|
1
|
+
/*
|
2
|
+
Copyright: Boaz Segev, 2018
|
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
|
+
int fio_tmpfile(void) {
|
22
|
+
// create a temporary file to contain the data.
|
23
|
+
int fd = 0;
|
24
|
+
#ifdef P_tmpdir
|
25
|
+
if (P_tmpdir[sizeof(P_tmpdir) - 1] == '/') {
|
26
|
+
char name_template[] = P_tmpdir "facil_io_tmpfile_XXXXXXXX";
|
27
|
+
fd = mkstemp(name_template);
|
28
|
+
} else {
|
29
|
+
char name_template[] = P_tmpdir "/facil_io_tmpfile_XXXXXXXX";
|
30
|
+
fd = mkstemp(name_template);
|
31
|
+
}
|
32
|
+
#else
|
33
|
+
char name_template[] = "/tmp/facil_io_tmpfile_XXXXXXXX";
|
34
|
+
fd = mkstemp(name_template);
|
35
|
+
#endif
|
36
|
+
return fd;
|
37
|
+
}
|
38
|
+
#endif
|
data/ext/iodine/fiobj.h
CHANGED
@@ -1,18 +1,35 @@
|
|
1
1
|
/*
|
2
|
-
Copyright: Boaz Segev, 2017
|
2
|
+
Copyright: Boaz Segev, 2017-2018
|
3
3
|
License: MIT
|
4
4
|
*/
|
5
|
-
#ifndef
|
6
|
-
#define
|
7
|
-
|
8
|
-
#include "fiobject.h"
|
5
|
+
#ifndef H_FIOBJ_H
|
6
|
+
#define H_FIOBJ_H
|
9
7
|
|
10
8
|
#include "fiobj_ary.h"
|
9
|
+
#include "fiobj_data.h"
|
11
10
|
#include "fiobj_hash.h"
|
12
11
|
#include "fiobj_json.h"
|
13
12
|
#include "fiobj_numbers.h"
|
14
|
-
#include "fiobj_primitives.h"
|
15
13
|
#include "fiobj_str.h"
|
16
|
-
#include "
|
14
|
+
#include "fiobject.h"
|
17
15
|
|
16
|
+
#include "fio_siphash.h"
|
17
|
+
|
18
|
+
#if DEBUG
|
19
|
+
FIO_INLINE void fiobj_test(void) {
|
20
|
+
fiobj_test_string();
|
21
|
+
fiobj_test_numbers();
|
22
|
+
fiobj_test_array();
|
23
|
+
fiobj_test_hash();
|
24
|
+
fiobj_test_core();
|
25
|
+
fiobj_data_test();
|
26
|
+
fiobj_test_json();
|
27
|
+
}
|
28
|
+
#else
|
29
|
+
FIO_INLINE void fiobj_test(void) {
|
30
|
+
fprintf(stderr, "ERROR: tesing functions only defined with DEBUG=1\n");
|
31
|
+
exit(-1);
|
32
|
+
}
|
33
|
+
#endif
|
34
|
+
#undef FIO_INLINE
|
18
35
|
#endif
|
@@ -0,0 +1,23 @@
|
|
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 "fiobj.h"
|
8
|
+
#include "sock.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_cstr_s s = fiobj_obj2cstr(o);
|
16
|
+
return sock_write2(.uuid = uuid, .buffer = (void *)(o),
|
17
|
+
.offset = (((intptr_t)s.data) - ((intptr_t)(o))),
|
18
|
+
.length = s.length,
|
19
|
+
.dealloc =
|
20
|
+
fiobj4sock_dealloc); // (void (*)(void *))fiobj_free
|
21
|
+
}
|
22
|
+
|
23
|
+
#endif
|
data/ext/iodine/fiobj_ary.c
CHANGED
@@ -1,180 +1,120 @@
|
|
1
1
|
/*
|
2
|
-
Copyright: Boaz Segev, 2017
|
2
|
+
Copyright: Boaz Segev, 2017-2018
|
3
3
|
License: MIT
|
4
4
|
*/
|
5
5
|
|
6
|
-
#include "
|
6
|
+
#include "fiobject.h"
|
7
|
+
|
8
|
+
#define FIO_OVERRIDE_MALLOC 1
|
9
|
+
#include "fio_mem.h"
|
10
|
+
|
11
|
+
#include "fio_ary.h"
|
12
|
+
#include <assert.h>
|
13
|
+
|
14
|
+
#ifndef FIOBJ_ARRAY_DEFAULT_CAPA
|
15
|
+
#define FIOBJ_ARRAY_DEFAULT_CAPA 8
|
16
|
+
#endif
|
17
|
+
#ifndef FIOBJ_ARRAY_DEFAULT_OFFSET
|
18
|
+
#define FIOBJ_ARRAY_DEFAULT_OFFSET (FIOBJ_ARRAY_DEFAULT_CAPA >> 2)
|
19
|
+
#endif
|
7
20
|
|
8
21
|
/* *****************************************************************************
|
9
22
|
Array Type
|
10
23
|
***************************************************************************** */
|
11
24
|
|
12
25
|
typedef struct {
|
13
|
-
|
14
|
-
|
15
|
-
uint64_t end;
|
16
|
-
uint64_t capa;
|
17
|
-
fiobj_s **arry;
|
26
|
+
fiobj_object_header_s head;
|
27
|
+
fio_ary_s ary;
|
18
28
|
} fiobj_ary_s;
|
19
29
|
|
20
30
|
#define obj2ary(o) ((fiobj_ary_s *)(o))
|
21
31
|
|
22
|
-
/* *****************************************************************************
|
23
|
-
Array memory management
|
24
|
-
***************************************************************************** */
|
25
|
-
|
26
|
-
/* This funcation manages the Array's memory. */
|
27
|
-
static void fiobj_ary_getmem(fiobj_s *ary, int64_t needed) {
|
28
|
-
/* we have enough memory, but we need to re-organize it. */
|
29
|
-
if (needed == -1) {
|
30
|
-
if (obj2ary(ary)->end < obj2ary(ary)->capa) {
|
31
|
-
/* since allocation can be cheaper than memmove (depending on size),
|
32
|
-
* we'll just shove everything to the end...
|
33
|
-
*/
|
34
|
-
uint64_t len = obj2ary(ary)->end - obj2ary(ary)->start;
|
35
|
-
memmove(obj2ary(ary)->arry + (obj2ary(ary)->capa - len),
|
36
|
-
obj2ary(ary)->arry + obj2ary(ary)->start,
|
37
|
-
len * sizeof(*obj2ary(ary)->arry));
|
38
|
-
obj2ary(ary)->start = obj2ary(ary)->capa - len;
|
39
|
-
obj2ary(ary)->end = obj2ary(ary)->capa;
|
40
|
-
|
41
|
-
return;
|
42
|
-
}
|
43
|
-
/* add some breathing room for future `unshift`s */
|
44
|
-
needed =
|
45
|
-
0 - ((obj2ary(ary)->capa <= 1024) ? (obj2ary(ary)->capa >> 1) : 1024);
|
46
|
-
}
|
47
|
-
|
48
|
-
/* FIFO support optimizes smaller FIFO ranges over bloating allocations. */
|
49
|
-
if (needed == 1 && obj2ary(ary)->start >= (obj2ary(ary)->capa >> 1)) {
|
50
|
-
uint64_t len = obj2ary(ary)->end - obj2ary(ary)->start;
|
51
|
-
memmove(obj2ary(ary)->arry + 2, obj2ary(ary)->arry + obj2ary(ary)->start,
|
52
|
-
len * sizeof(*obj2ary(ary)->arry));
|
53
|
-
obj2ary(ary)->start = 2;
|
54
|
-
obj2ary(ary)->end = len + 2;
|
55
|
-
|
56
|
-
return;
|
57
|
-
}
|
58
|
-
|
59
|
-
/* alocate using exponential growth, up to single page size. */
|
60
|
-
uint64_t updated_capa = obj2ary(ary)->capa;
|
61
|
-
uint64_t minimum =
|
62
|
-
obj2ary(ary)->capa + ((needed < 0) ? (0 - needed) : needed);
|
63
|
-
while (updated_capa <= minimum)
|
64
|
-
updated_capa =
|
65
|
-
(updated_capa <= 4096) ? (updated_capa << 1) : (updated_capa + 4096);
|
66
|
-
|
67
|
-
/* we assume memory allocation works. it's better to crash than to continue
|
68
|
-
* living without memory... besides, malloc is optimistic these days. */
|
69
|
-
obj2ary(ary)->arry =
|
70
|
-
realloc(obj2ary(ary)->arry, updated_capa * sizeof(*obj2ary(ary)->arry));
|
71
|
-
obj2ary(ary)->capa = updated_capa;
|
72
|
-
if (!obj2ary(ary)->arry)
|
73
|
-
perror("ERROR: fiobj array couldn't be reallocated"), exit(errno);
|
74
|
-
|
75
|
-
if (needed >= 0) /* we're done, realloc grows the top of the address space*/
|
76
|
-
return;
|
77
|
-
|
78
|
-
/* move everything to the max, since memmove could get expensive */
|
79
|
-
uint64_t len = obj2ary(ary)->end - obj2ary(ary)->start;
|
80
|
-
needed = obj2ary(ary)->capa - len;
|
81
|
-
memmove(obj2ary(ary)->arry + needed, obj2ary(ary)->arry + obj2ary(ary)->start,
|
82
|
-
len * sizeof(*obj2ary(ary)->arry));
|
83
|
-
obj2ary(ary)->end = needed + len;
|
84
|
-
obj2ary(ary)->start = needed;
|
85
|
-
}
|
86
|
-
|
87
32
|
/* *****************************************************************************
|
88
33
|
VTable
|
89
34
|
***************************************************************************** */
|
90
35
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
free(
|
95
|
-
fiobj_dealloc(a);
|
36
|
+
static void fiobj_ary_dealloc(FIOBJ o, void (*task)(FIOBJ, void *), void *arg) {
|
37
|
+
FIO_ARY_FOR(&obj2ary(o)->ary, i) { task((FIOBJ)i.obj, arg); }
|
38
|
+
fio_ary_free(&obj2ary(o)->ary);
|
39
|
+
free(FIOBJ2PTR(o));
|
96
40
|
}
|
97
41
|
|
98
|
-
static size_t fiobj_ary_each1(
|
99
|
-
int (*task)(
|
100
|
-
|
101
|
-
|
102
|
-
while (start_at < obj2ary(o)->end &&
|
103
|
-
task(obj2ary(o)->arry[start_at++], arg) != -1)
|
104
|
-
;
|
105
|
-
return start_at - start_pos;
|
42
|
+
static size_t fiobj_ary_each1(FIOBJ o, size_t start_at,
|
43
|
+
int (*task)(FIOBJ obj, void *arg), void *arg) {
|
44
|
+
return fio_ary_each(&obj2ary(o)->ary, start_at, (int (*)(void *, void *))task,
|
45
|
+
arg);
|
106
46
|
}
|
107
47
|
|
108
|
-
static
|
109
|
-
|
110
|
-
|
111
|
-
if (
|
112
|
-
(obj2ary(self)->end - obj2ary(self)->start) !=
|
113
|
-
(obj2ary(other)->end - obj2ary(other)->start))
|
48
|
+
static size_t fiobj_ary_is_eq(const FIOBJ self, const FIOBJ other) {
|
49
|
+
fio_ary_s *a = &obj2ary(self)->ary;
|
50
|
+
fio_ary_s *b = &obj2ary(other)->ary;
|
51
|
+
if (fio_ary_count(a) != fio_ary_count(b))
|
114
52
|
return 0;
|
115
53
|
return 1;
|
116
54
|
}
|
117
55
|
|
118
56
|
/** Returns the number of elements in the Array. */
|
119
|
-
|
120
|
-
|
57
|
+
size_t fiobj_ary_count(const FIOBJ ary) {
|
58
|
+
assert(FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
|
59
|
+
return fio_ary_count(&obj2ary(ary)->ary);
|
121
60
|
}
|
122
61
|
|
123
|
-
static
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
62
|
+
static size_t fiobj_ary_is_true(const FIOBJ ary) {
|
63
|
+
return fiobj_ary_count(ary) > 0;
|
64
|
+
}
|
65
|
+
|
66
|
+
fio_cstr_s fiobject___noop_to_str(const FIOBJ o);
|
67
|
+
intptr_t fiobject___noop_to_i(const FIOBJ o);
|
68
|
+
double fiobject___noop_to_f(const FIOBJ o);
|
69
|
+
|
70
|
+
const fiobj_object_vtable_s FIOBJECT_VTABLE_ARRAY = {
|
71
|
+
.class_name = "Array",
|
72
|
+
.dealloc = fiobj_ary_dealloc,
|
129
73
|
.is_eq = fiobj_ary_is_eq,
|
130
|
-
.
|
131
|
-
.
|
132
|
-
.
|
74
|
+
.is_true = fiobj_ary_is_true,
|
75
|
+
.count = fiobj_ary_count,
|
76
|
+
.each = fiobj_ary_each1,
|
77
|
+
.to_i = fiobject___noop_to_i,
|
78
|
+
.to_f = fiobject___noop_to_f,
|
79
|
+
.to_str = fiobject___noop_to_str,
|
133
80
|
};
|
134
81
|
|
135
|
-
const uintptr_t FIOBJ_T_ARRAY = (uintptr_t)(&FIOBJ_VTABLE_ARRAY);
|
136
|
-
|
137
82
|
/* *****************************************************************************
|
138
83
|
Allocation
|
139
84
|
***************************************************************************** */
|
140
85
|
|
141
|
-
static
|
142
|
-
|
143
|
-
if (!ary)
|
144
|
-
perror("ERROR: fiobj array couldn't allocate memory")
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
.
|
149
|
-
|
150
|
-
|
86
|
+
static FIOBJ fiobj_ary_alloc(size_t capa, size_t start_at) {
|
87
|
+
fiobj_ary_s *ary = malloc(sizeof(*ary));
|
88
|
+
if (!ary) {
|
89
|
+
perror("ERROR: fiobj array couldn't allocate memory");
|
90
|
+
exit(errno);
|
91
|
+
}
|
92
|
+
*ary = (fiobj_ary_s){
|
93
|
+
.head =
|
94
|
+
{
|
95
|
+
.ref = 1, .type = FIOBJ_T_ARRAY,
|
96
|
+
},
|
151
97
|
};
|
152
|
-
|
153
|
-
|
154
|
-
return ary;
|
98
|
+
fio_ary_new(&ary->ary, capa);
|
99
|
+
ary->ary.start = ary->ary.end = start_at;
|
100
|
+
return (FIOBJ)ary;
|
155
101
|
}
|
156
102
|
|
157
103
|
/** Creates a mutable empty Array object. Use `fiobj_free` when done. */
|
158
|
-
|
104
|
+
FIOBJ fiobj_ary_new(void) {
|
105
|
+
return fiobj_ary_alloc(FIOBJ_ARRAY_DEFAULT_CAPA, FIOBJ_ARRAY_DEFAULT_OFFSET);
|
106
|
+
}
|
159
107
|
/** Creates a mutable empty Array object with the requested capacity. */
|
160
|
-
|
108
|
+
FIOBJ fiobj_ary_new2(size_t capa) { return fiobj_ary_alloc(capa, 0); }
|
161
109
|
|
162
110
|
/* *****************************************************************************
|
163
111
|
Array direct entry access API
|
164
112
|
***************************************************************************** */
|
165
113
|
|
166
|
-
/** Returns the number of elements in the Array. */
|
167
|
-
size_t fiobj_ary_count(fiobj_s *ary) {
|
168
|
-
if (!ary)
|
169
|
-
return 0;
|
170
|
-
return (obj2ary(ary)->end - obj2ary(ary)->start);
|
171
|
-
}
|
172
|
-
|
173
114
|
/** Returns the current, temporary, array capacity (it's dynamic). */
|
174
|
-
size_t fiobj_ary_capa(
|
175
|
-
|
176
|
-
|
177
|
-
return obj2ary(ary)->capa;
|
115
|
+
size_t fiobj_ary_capa(FIOBJ ary) {
|
116
|
+
assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
|
117
|
+
return fio_ary_capa(&obj2ary(ary)->ary);
|
178
118
|
}
|
179
119
|
|
180
120
|
/**
|
@@ -183,8 +123,9 @@ size_t fiobj_ary_capa(fiobj_s *ary) {
|
|
183
123
|
* This pointer can be used for sorting and other direct access operations as
|
184
124
|
* long as no other actions (insertion/deletion) are performed on the array.
|
185
125
|
*/
|
186
|
-
|
187
|
-
|
126
|
+
FIOBJ *fiobj_ary2ptr(FIOBJ ary) {
|
127
|
+
assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
|
128
|
+
return (FIOBJ *)(obj2ary(ary)->ary.arry + obj2ary(ary)->ary.start);
|
188
129
|
}
|
189
130
|
|
190
131
|
/**
|
@@ -193,61 +134,18 @@ fiobj_s **fiobj_ary2prt(fiobj_s *ary) {
|
|
193
134
|
* Negative values are retrived from the end of the array. i.e., `-1`
|
194
135
|
* is the last item.
|
195
136
|
*/
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
/* position is relative to `start`*/
|
200
|
-
if (pos >= 0) {
|
201
|
-
pos = pos + obj2ary(ary)->start;
|
202
|
-
if ((uint64_t)pos >= obj2ary(ary)->end)
|
203
|
-
return NULL;
|
204
|
-
return obj2ary(ary)->arry[pos];
|
205
|
-
}
|
206
|
-
/* position is relative to `end`*/
|
207
|
-
pos = (int64_t)obj2ary(ary)->end + pos;
|
208
|
-
if (pos < 0)
|
209
|
-
return NULL;
|
210
|
-
if ((uint64_t)pos < obj2ary(ary)->start)
|
211
|
-
return NULL;
|
212
|
-
return obj2ary(ary)->arry[pos];
|
137
|
+
FIOBJ fiobj_ary_index(FIOBJ ary, int64_t pos) {
|
138
|
+
assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
|
139
|
+
return (FIOBJ)fio_ary_index(&obj2ary(ary)->ary, pos);
|
213
140
|
}
|
214
141
|
|
215
142
|
/**
|
216
143
|
* Sets an object at the requested position.
|
217
144
|
*/
|
218
|
-
void fiobj_ary_set(
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
return;
|
223
|
-
}
|
224
|
-
|
225
|
-
/* test for memory and request memory if missing, promises valid bounds. */
|
226
|
-
if (pos >= 0) {
|
227
|
-
if ((uint64_t)pos + obj2ary(ary)->start >= obj2ary(ary)->capa)
|
228
|
-
fiobj_ary_getmem(ary, (((uint64_t)pos + obj2ary(ary)->start) -
|
229
|
-
(obj2ary(ary)->capa - 1)));
|
230
|
-
} else if (pos + (int64_t)obj2ary(ary)->end < 0)
|
231
|
-
fiobj_ary_getmem(ary, pos + obj2ary(ary)->end);
|
232
|
-
|
233
|
-
if (pos >= 0) {
|
234
|
-
/* position relative to start */
|
235
|
-
pos = pos + obj2ary(ary)->start;
|
236
|
-
/* initialize empty spaces, if any, setting new boundries */
|
237
|
-
while ((uint64_t)pos >= obj2ary(ary)->end)
|
238
|
-
obj2ary(ary)->arry[(obj2ary(ary)->end)++] = NULL;
|
239
|
-
} else {
|
240
|
-
/* position relative to end */
|
241
|
-
pos = pos + (int64_t)obj2ary(ary)->end;
|
242
|
-
/* initialize empty spaces, if any, setting new boundries */
|
243
|
-
while (obj2ary(ary)->start > (uint64_t)pos)
|
244
|
-
obj2ary(ary)->arry[--(obj2ary(ary)->start)] = NULL;
|
245
|
-
}
|
246
|
-
|
247
|
-
/* check for an existing object and set new objects */
|
248
|
-
if (obj2ary(ary)->arry[pos])
|
249
|
-
fiobj_free(obj2ary(ary)->arry[pos]);
|
250
|
-
obj2ary(ary)->arry[pos] = obj;
|
145
|
+
void fiobj_ary_set(FIOBJ ary, FIOBJ obj, int64_t pos) {
|
146
|
+
assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
|
147
|
+
FIOBJ old = (FIOBJ)fio_ary_set(&obj2ary(ary)->ary, (void *)obj, pos);
|
148
|
+
fiobj_free(old);
|
251
149
|
}
|
252
150
|
|
253
151
|
/* *****************************************************************************
|
@@ -257,49 +155,30 @@ Array push / shift API
|
|
257
155
|
/**
|
258
156
|
* Pushes an object to the end of the Array.
|
259
157
|
*/
|
260
|
-
void fiobj_ary_push(
|
261
|
-
|
262
|
-
|
263
|
-
fiobj_free(obj);
|
264
|
-
return;
|
265
|
-
}
|
266
|
-
if (obj2ary(ary)->capa <= obj2ary(ary)->end)
|
267
|
-
fiobj_ary_getmem(ary, 1);
|
268
|
-
obj2ary(ary)->arry[(obj2ary(ary)->end)++] = obj;
|
158
|
+
void fiobj_ary_push(FIOBJ ary, FIOBJ obj) {
|
159
|
+
assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
|
160
|
+
fio_ary_push(&obj2ary(ary)->ary, (void *)obj);
|
269
161
|
}
|
270
162
|
|
271
163
|
/** Pops an object from the end of the Array. */
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
return NULL;
|
276
|
-
fiobj_s *ret = obj2ary(ary)->arry[--(obj2ary(ary)->end)];
|
277
|
-
return ret;
|
164
|
+
FIOBJ fiobj_ary_pop(FIOBJ ary) {
|
165
|
+
assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
|
166
|
+
return (FIOBJ)fio_ary_pop(&obj2ary(ary)->ary);
|
278
167
|
}
|
279
168
|
|
280
169
|
/**
|
281
170
|
* Unshifts an object to the begining of the Array. This could be
|
282
171
|
* expensive.
|
283
172
|
*/
|
284
|
-
void fiobj_ary_unshift(
|
285
|
-
|
286
|
-
|
287
|
-
fiobj_free(obj);
|
288
|
-
return;
|
289
|
-
}
|
290
|
-
if (obj2ary(ary)->start == 0)
|
291
|
-
fiobj_ary_getmem(ary, -1);
|
292
|
-
obj2ary(ary)->arry[--(obj2ary(ary)->start)] = obj;
|
173
|
+
void fiobj_ary_unshift(FIOBJ ary, FIOBJ obj) {
|
174
|
+
assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
|
175
|
+
fio_ary_unshift(&obj2ary(ary)->ary, (void *)obj);
|
293
176
|
}
|
294
177
|
|
295
178
|
/** Shifts an object from the beginning of the Array. */
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
if (obj2ary(ary)->start == obj2ary(ary)->end)
|
300
|
-
return NULL;
|
301
|
-
fiobj_s *ret = obj2ary(ary)->arry[(obj2ary(ary)->start)++];
|
302
|
-
return ret;
|
179
|
+
FIOBJ fiobj_ary_shift(FIOBJ ary) {
|
180
|
+
assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
|
181
|
+
return (FIOBJ)fio_ary_shift(&obj2ary(ary)->ary);
|
303
182
|
}
|
304
183
|
|
305
184
|
/* *****************************************************************************
|
@@ -313,17 +192,55 @@ Array compacting (untested)
|
|
313
192
|
* This action is O(n) where n in the length of the array.
|
314
193
|
* It could get expensive.
|
315
194
|
*/
|
316
|
-
void fiobj_ary_compact(
|
317
|
-
|
318
|
-
|
319
|
-
fiobj_s **reader = obj2ary(ary)->arry + obj2ary(ary)->start;
|
320
|
-
fiobj_s **writer = obj2ary(ary)->arry + obj2ary(ary)->start;
|
321
|
-
while (reader < (obj2ary(ary)->arry + obj2ary(ary)->end)) {
|
322
|
-
if (*reader == NULL) {
|
323
|
-
reader++;
|
324
|
-
continue;
|
325
|
-
}
|
326
|
-
*(writer++) = *(reader++);
|
327
|
-
}
|
328
|
-
obj2ary(ary)->end = (uint64_t)(writer - obj2ary(ary)->arry);
|
195
|
+
void fiobj_ary_compact(FIOBJ ary) {
|
196
|
+
assert(ary && FIOBJ_TYPE_IS(ary, FIOBJ_T_ARRAY));
|
197
|
+
fio_ary_compact(&obj2ary(ary)->ary);
|
329
198
|
}
|
199
|
+
|
200
|
+
/* *****************************************************************************
|
201
|
+
Simple Tests
|
202
|
+
***************************************************************************** */
|
203
|
+
|
204
|
+
#if DEBUG
|
205
|
+
void fiobj_test_array(void) {
|
206
|
+
fprintf(stderr, "=== Testing Array\n");
|
207
|
+
#define TEST_ASSERT(cond, ...) \
|
208
|
+
if (!(cond)) { \
|
209
|
+
fprintf(stderr, "* " __VA_ARGS__); \
|
210
|
+
fprintf(stderr, "Testing failed.\n"); \
|
211
|
+
exit(-1); \
|
212
|
+
}
|
213
|
+
FIOBJ a = fiobj_ary_new2(4);
|
214
|
+
TEST_ASSERT(FIOBJ_TYPE_IS(a, FIOBJ_T_ARRAY), "Array type isn't an array!\n");
|
215
|
+
TEST_ASSERT(fiobj_ary_capa(a) == 4, "Array capacity ignored!\n");
|
216
|
+
fiobj_ary_push(a, fiobj_null());
|
217
|
+
TEST_ASSERT(fiobj_ary2ptr(a)[0] == fiobj_null(),
|
218
|
+
"Array direct access failed!\n");
|
219
|
+
fiobj_ary_push(a, fiobj_true());
|
220
|
+
fiobj_ary_push(a, fiobj_false());
|
221
|
+
TEST_ASSERT(fiobj_ary_count(a) == 3, "Array count isn't 3\n");
|
222
|
+
fiobj_ary_set(a, fiobj_true(), 63);
|
223
|
+
TEST_ASSERT(fiobj_ary_count(a) == 64, "Array count isn't 64\n");
|
224
|
+
TEST_ASSERT(fiobj_ary_index(a, 0) == fiobj_null(),
|
225
|
+
"Array index retrival error for fiobj_null\n");
|
226
|
+
TEST_ASSERT(fiobj_ary_index(a, 1) == fiobj_true(),
|
227
|
+
"Array index retrival error for fiobj_true\n");
|
228
|
+
TEST_ASSERT(fiobj_ary_index(a, 2) == fiobj_false(),
|
229
|
+
"Array index retrival error for fiobj_false\n");
|
230
|
+
TEST_ASSERT(fiobj_ary_index(a, 3) == 0,
|
231
|
+
"Array index retrival error for NULL\n");
|
232
|
+
TEST_ASSERT(fiobj_ary_index(a, 63) == fiobj_true(),
|
233
|
+
"Array index retrival error for index 63\n");
|
234
|
+
TEST_ASSERT(fiobj_ary_index(a, -1) == fiobj_true(),
|
235
|
+
"Array index retrival error for index -1\n");
|
236
|
+
fiobj_ary_compact(a);
|
237
|
+
TEST_ASSERT(fiobj_ary_index(a, -1) == fiobj_true(),
|
238
|
+
"Array index retrival error for index -1\n");
|
239
|
+
TEST_ASSERT(fiobj_ary_count(a) == 4, "Array compact error\n");
|
240
|
+
fiobj_ary_unshift(a, fiobj_false());
|
241
|
+
TEST_ASSERT(fiobj_ary_count(a) == 5, "Array unshift error\n");
|
242
|
+
TEST_ASSERT(fiobj_ary_shift(a) == fiobj_false(), "Array shift value error\n");
|
243
|
+
fiobj_free(a);
|
244
|
+
fprintf(stderr, "* passed.\n");
|
245
|
+
}
|
246
|
+
#endif
|