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.

Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -2
  3. data/CHANGELOG.md +22 -0
  4. data/LIMITS.md +19 -9
  5. data/README.md +92 -77
  6. data/SPEC-PubSub-Draft.md +113 -0
  7. data/SPEC-Websocket-Draft.md +127 -143
  8. data/bin/http-hello +0 -1
  9. data/bin/raw-rbhttp +1 -1
  10. data/bin/raw_broadcast +8 -10
  11. data/bin/updated api +2 -2
  12. data/bin/ws-broadcast +2 -4
  13. data/bin/ws-echo +2 -2
  14. data/examples/config.ru +13 -13
  15. data/examples/echo.ru +5 -6
  16. data/examples/hello.ru +2 -3
  17. data/examples/info.md +316 -0
  18. data/examples/pubsub_engine.ru +81 -0
  19. data/examples/redis.ru +9 -9
  20. data/examples/shootout.ru +45 -11
  21. data/ext/iodine/defer.c +194 -297
  22. data/ext/iodine/defer.h +61 -53
  23. data/ext/iodine/evio.c +0 -260
  24. data/ext/iodine/evio.h +50 -22
  25. data/ext/iodine/evio_callbacks.c +26 -0
  26. data/ext/iodine/evio_epoll.c +251 -0
  27. data/ext/iodine/evio_kqueue.c +193 -0
  28. data/ext/iodine/extconf.rb +1 -1
  29. data/ext/iodine/facil.c +1420 -542
  30. data/ext/iodine/facil.h +151 -64
  31. data/ext/iodine/fio_ary.h +418 -0
  32. data/ext/iodine/{base64.c → fio_base64.c} +33 -24
  33. data/ext/iodine/{base64.h → fio_base64.h} +6 -7
  34. data/ext/iodine/{fio_cli_helper.c → fio_cli.c} +77 -58
  35. data/ext/iodine/{fio_cli_helper.h → fio_cli.h} +9 -4
  36. data/ext/iodine/fio_hashmap.h +759 -0
  37. data/ext/iodine/fio_json_parser.h +651 -0
  38. data/ext/iodine/fio_llist.h +257 -0
  39. data/ext/iodine/fio_mem.c +672 -0
  40. data/ext/iodine/fio_mem.h +140 -0
  41. data/ext/iodine/fio_random.c +248 -0
  42. data/ext/iodine/{random.h → fio_random.h} +11 -14
  43. data/ext/iodine/{sha1.c → fio_sha1.c} +28 -24
  44. data/ext/iodine/{sha1.h → fio_sha1.h} +38 -16
  45. data/ext/iodine/{sha2.c → fio_sha2.c} +66 -49
  46. data/ext/iodine/{sha2.h → fio_sha2.h} +57 -26
  47. data/ext/iodine/{fiobj_internal.c → fio_siphash.c} +9 -90
  48. data/ext/iodine/fio_siphash.h +18 -0
  49. data/ext/iodine/fio_tmpfile.h +38 -0
  50. data/ext/iodine/fiobj.h +24 -7
  51. data/ext/iodine/fiobj4sock.h +23 -0
  52. data/ext/iodine/fiobj_ary.c +143 -226
  53. data/ext/iodine/fiobj_ary.h +17 -16
  54. data/ext/iodine/fiobj_data.c +1160 -0
  55. data/ext/iodine/fiobj_data.h +164 -0
  56. data/ext/iodine/fiobj_hash.c +298 -406
  57. data/ext/iodine/fiobj_hash.h +101 -54
  58. data/ext/iodine/fiobj_json.c +478 -601
  59. data/ext/iodine/fiobj_json.h +34 -9
  60. data/ext/iodine/fiobj_numbers.c +383 -51
  61. data/ext/iodine/fiobj_numbers.h +87 -11
  62. data/ext/iodine/fiobj_str.c +423 -184
  63. data/ext/iodine/fiobj_str.h +81 -32
  64. data/ext/iodine/fiobject.c +273 -522
  65. data/ext/iodine/fiobject.h +477 -112
  66. data/ext/iodine/http.c +2243 -83
  67. data/ext/iodine/http.h +842 -121
  68. data/ext/iodine/http1.c +810 -385
  69. data/ext/iodine/http1.h +16 -39
  70. data/ext/iodine/http1_parser.c +146 -74
  71. data/ext/iodine/http1_parser.h +15 -4
  72. data/ext/iodine/http_internal.c +1258 -0
  73. data/ext/iodine/http_internal.h +226 -0
  74. data/ext/iodine/http_mime_parser.h +341 -0
  75. data/ext/iodine/iodine.c +86 -68
  76. data/ext/iodine/iodine.h +26 -11
  77. data/ext/iodine/iodine_helpers.c +8 -7
  78. data/ext/iodine/iodine_http.c +487 -324
  79. data/ext/iodine/iodine_json.c +304 -0
  80. data/ext/iodine/iodine_json.h +6 -0
  81. data/ext/iodine/iodine_protocol.c +107 -45
  82. data/ext/iodine/iodine_pubsub.c +526 -225
  83. data/ext/iodine/iodine_pubsub.h +10 -0
  84. data/ext/iodine/iodine_websockets.c +268 -510
  85. data/ext/iodine/iodine_websockets.h +2 -4
  86. data/ext/iodine/pubsub.c +726 -432
  87. data/ext/iodine/pubsub.h +85 -103
  88. data/ext/iodine/rb-call.c +4 -4
  89. data/ext/iodine/rb-defer.c +46 -22
  90. data/ext/iodine/rb-fiobj2rb.h +117 -0
  91. data/ext/iodine/rb-rack-io.c +73 -238
  92. data/ext/iodine/rb-rack-io.h +2 -2
  93. data/ext/iodine/rb-registry.c +35 -93
  94. data/ext/iodine/rb-registry.h +1 -0
  95. data/ext/iodine/redis_engine.c +742 -304
  96. data/ext/iodine/redis_engine.h +42 -39
  97. data/ext/iodine/resp_parser.h +311 -0
  98. data/ext/iodine/sock.c +627 -490
  99. data/ext/iodine/sock.h +345 -297
  100. data/ext/iodine/spnlock.inc +15 -4
  101. data/ext/iodine/websocket_parser.h +16 -20
  102. data/ext/iodine/websockets.c +188 -257
  103. data/ext/iodine/websockets.h +24 -133
  104. data/lib/iodine.rb +52 -7
  105. data/lib/iodine/cli.rb +6 -24
  106. data/lib/iodine/json.rb +40 -0
  107. data/lib/iodine/version.rb +1 -1
  108. data/lib/iodine/websocket.rb +5 -3
  109. data/lib/rack/handler/iodine.rb +58 -13
  110. metadata +38 -48
  111. data/bin/ws-shootout +0 -107
  112. data/examples/broadcast.ru +0 -56
  113. data/ext/iodine/bscrypt-common.h +0 -116
  114. data/ext/iodine/bscrypt.h +0 -49
  115. data/ext/iodine/fio2resp.c +0 -60
  116. data/ext/iodine/fio2resp.h +0 -51
  117. data/ext/iodine/fio_dict.c +0 -446
  118. data/ext/iodine/fio_dict.h +0 -99
  119. data/ext/iodine/fio_hash_table.h +0 -370
  120. data/ext/iodine/fio_list.h +0 -111
  121. data/ext/iodine/fiobj_internal.h +0 -280
  122. data/ext/iodine/fiobj_primitives.c +0 -131
  123. data/ext/iodine/fiobj_primitives.h +0 -55
  124. data/ext/iodine/fiobj_sym.c +0 -135
  125. data/ext/iodine/fiobj_sym.h +0 -60
  126. data/ext/iodine/hex.c +0 -124
  127. data/ext/iodine/hex.h +0 -70
  128. data/ext/iodine/http1_request.c +0 -81
  129. data/ext/iodine/http1_request.h +0 -58
  130. data/ext/iodine/http1_response.c +0 -417
  131. data/ext/iodine/http1_response.h +0 -95
  132. data/ext/iodine/http_request.c +0 -111
  133. data/ext/iodine/http_request.h +0 -102
  134. data/ext/iodine/http_response.c +0 -1703
  135. data/ext/iodine/http_response.h +0 -250
  136. data/ext/iodine/misc.c +0 -182
  137. data/ext/iodine/misc.h +0 -74
  138. data/ext/iodine/random.c +0 -208
  139. data/ext/iodine/redis_connection.c +0 -278
  140. data/ext/iodine/redis_connection.h +0 -86
  141. data/ext/iodine/resp.c +0 -842
  142. data/ext/iodine/resp.h +0 -261
  143. data/ext/iodine/siphash.c +0 -154
  144. data/ext/iodine/siphash.h +0 -22
  145. data/ext/iodine/xor-crypt.c +0 -193
  146. 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 "fiobj_internal.h"
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 copy)
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 fiobj_sym_hash(const void *data, size_t len) {
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 FIOBJ_H
6
- #define FIOBJ_H
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 "fiobj_sym.h"
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
@@ -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 "fiobj_internal.h"
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
- struct fiobj_vtable_s *vtable;
14
- uint64_t start;
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
- const uintptr_t FIOBJ_T_ARRAY;
92
-
93
- static void fiobj_ary_dealloc(fiobj_s *a) {
94
- free(obj2ary(a)->arry);
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(fiobj_s *o, size_t start_at,
99
- int (*task)(fiobj_s *obj, void *arg), void *arg) {
100
- const uint64_t start_pos = obj2ary(o)->start;
101
- start_at += start_pos;
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 int fiobj_ary_is_eq(const fiobj_s *self, const fiobj_s *other) {
109
- if (self == other)
110
- return 1;
111
- if (!other || other->type != FIOBJ_T_ARRAY ||
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
- static size_t fiobj_ary_count_items(const fiobj_s *ary) {
120
- return (obj2ary(ary)->end - obj2ary(ary)->start);
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 struct fiobj_vtable_s FIOBJ_VTABLE_ARRAY = {
124
- .name = "Array",
125
- .free = fiobj_ary_dealloc,
126
- .to_i = fiobj_noop_i,
127
- .to_f = fiobj_noop_f,
128
- .to_str = fiobj_noop_str,
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
- .count = fiobj_ary_count_items,
131
- .unwrap = fiobj_noop_unwrap,
132
- .each1 = fiobj_ary_each1,
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 fiobj_s *fiobj_ary_alloc(size_t capa, size_t start_at) {
142
- fiobj_s *ary = fiobj_alloc(sizeof(fiobj_ary_s));
143
- if (!ary)
144
- perror("ERROR: fiobj array couldn't allocate memory"), exit(errno);
145
- *(obj2ary(ary)) = (fiobj_ary_s){
146
- .vtable = &FIOBJ_VTABLE_ARRAY,
147
- .start = start_at,
148
- .end = start_at,
149
- .capa = capa,
150
- .arry = malloc(sizeof(fiobj_s *) * capa),
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
- if (capa && !obj2ary(ary)->capa)
153
- perror("ERROR: fiobj array couldn't allocate memory"), exit(errno);
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
- fiobj_s *fiobj_ary_new(void) { return fiobj_ary_alloc(32, 8); }
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
- fiobj_s *fiobj_ary_new2(size_t capa) { return fiobj_ary_alloc(capa, 0); }
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(fiobj_s *ary) {
175
- if (!ary)
176
- return 0;
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
- fiobj_s **fiobj_ary2prt(fiobj_s *ary) {
187
- return obj2ary(ary)->arry + obj2ary(ary)->start;
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
- fiobj_s *fiobj_ary_index(fiobj_s *ary, int64_t pos) {
197
- if (!ary || ary->type != FIOBJ_T_ARRAY)
198
- return NULL;
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(fiobj_s *ary, fiobj_s *obj, int64_t pos) {
219
- if (!ary || ary->type != FIOBJ_T_ARRAY) {
220
- /* function takes ownership of memory even if an error occurs. */
221
- fiobj_free(obj);
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(fiobj_s *ary, fiobj_s *obj) {
261
- if (!ary || ary->type != FIOBJ_T_ARRAY) {
262
- /* function takes ownership of memory even if an error occurs. */
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
- fiobj_s *fiobj_ary_pop(fiobj_s *ary) {
273
- if (!ary || ary->type != FIOBJ_T_ARRAY ||
274
- obj2ary(ary)->start == obj2ary(ary)->end)
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(fiobj_s *ary, fiobj_s *obj) {
285
- if (!ary || ary->type != FIOBJ_T_ARRAY) {
286
- /* function takes ownership of memory even if an error occurs. */
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
- fiobj_s *fiobj_ary_shift(fiobj_s *ary) {
297
- if (!ary || ary->type != FIOBJ_T_ARRAY)
298
- return NULL;
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(fiobj_s *ary) {
317
- if (!ary || ary->type != FIOBJ_T_ARRAY)
318
- return;
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