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/fiobj_numbers.h
CHANGED
@@ -5,7 +5,7 @@ Copyright: Boaz Segev, 2017-2018
|
|
5
5
|
License: MIT
|
6
6
|
*/
|
7
7
|
|
8
|
-
#include
|
8
|
+
#include <fiobject.h>
|
9
9
|
|
10
10
|
#ifdef __cplusplus
|
11
11
|
extern "C" {
|
@@ -48,13 +48,13 @@ Numerical Helpers: not FIOBJ specific, but included as part of the library
|
|
48
48
|
*
|
49
49
|
* The pointer will be updated to point to the first byte after the number.
|
50
50
|
*/
|
51
|
-
|
51
|
+
int64_t fio_atol(char **pstr);
|
52
52
|
|
53
|
-
/** A helper function that
|
53
|
+
/** A helper function that converts between String data to a signed double. */
|
54
54
|
double fio_atof(char **pstr);
|
55
55
|
|
56
56
|
/**
|
57
|
-
* A helper function that
|
57
|
+
* A helper function that converts between a signed int64_t to a string.
|
58
58
|
*
|
59
59
|
* No overflow guard is provided, make sure there's at least 66 bytes available
|
60
60
|
* (for base 2).
|
@@ -68,7 +68,7 @@ double fio_atof(char **pstr);
|
|
68
68
|
size_t fio_ltoa(char *dest, int64_t num, uint8_t base);
|
69
69
|
|
70
70
|
/**
|
71
|
-
* A helper function that
|
71
|
+
* A helper function that converts between a double to a string.
|
72
72
|
*
|
73
73
|
* No overflow guard is provided, make sure there's at least 130 bytes available
|
74
74
|
* (for base 2).
|
@@ -82,10 +82,10 @@ size_t fio_ltoa(char *dest, int64_t num, uint8_t base);
|
|
82
82
|
size_t fio_ftoa(char *dest, double num, uint8_t base);
|
83
83
|
|
84
84
|
/** Converts a number to a temporary, thread safe, C string object */
|
85
|
-
|
85
|
+
fio_str_info_s fio_ltocstr(long);
|
86
86
|
|
87
87
|
/** Converts a float to a temporary, thread safe, C string object */
|
88
|
-
|
88
|
+
fio_str_info_s fio_ftocstr(double);
|
89
89
|
|
90
90
|
/* *****************************************************************************
|
91
91
|
Pointer Wrapping Helper MACROs (uses integers)
|
data/ext/iodine/fiobj_str.c
CHANGED
@@ -16,11 +16,11 @@ License: MIT
|
|
16
16
|
#define PAGE_SIZE 4096
|
17
17
|
#endif
|
18
18
|
|
19
|
-
#include
|
19
|
+
#include <fiobject.h>
|
20
20
|
|
21
|
-
#include
|
22
|
-
#include
|
23
|
-
#include
|
21
|
+
#include <fio_siphash.h>
|
22
|
+
#include <fiobj_numbers.h>
|
23
|
+
#include <fiobj_str.h>
|
24
24
|
|
25
25
|
#include <assert.h>
|
26
26
|
#include <errno.h>
|
@@ -30,7 +30,9 @@ License: MIT
|
|
30
30
|
#include <sys/stat.h>
|
31
31
|
|
32
32
|
#define FIO_OVERRIDE_MALLOC 1
|
33
|
-
#include
|
33
|
+
#include <fiobj_mem.h>
|
34
|
+
|
35
|
+
#include <fio_str.h>
|
34
36
|
|
35
37
|
#ifndef PATH_MAX
|
36
38
|
#define PATH_MAX PAGE_SIZE
|
@@ -43,86 +45,46 @@ String Type
|
|
43
45
|
typedef struct {
|
44
46
|
fiobj_object_header_s head;
|
45
47
|
uint64_t hash;
|
46
|
-
|
47
|
-
uint8_t frozen;
|
48
|
-
uint8_t slen;
|
49
|
-
intptr_t len;
|
50
|
-
uintptr_t capa;
|
51
|
-
char *str;
|
48
|
+
fio_str_s str;
|
52
49
|
} fiobj_str_s;
|
53
50
|
|
54
51
|
#define obj2str(o) ((fiobj_str_s *)(FIOBJ2PTR(o)))
|
55
52
|
|
56
|
-
|
57
|
-
|
58
|
-
#define STR_INTENAL_STR(o) \
|
59
|
-
((char *)((uintptr_t)FIOBJ2PTR(o) + STR_INTENAL_OFFSET))
|
60
|
-
#define STR_INTENAL_LEN(o) (((fiobj_str_s *)FIOBJ2PTR(o))->slen)
|
61
|
-
|
62
|
-
static inline char *fiobj_str_mem_addr(FIOBJ o) {
|
63
|
-
if (obj2str(o)->is_small)
|
64
|
-
return STR_INTENAL_STR(o);
|
65
|
-
return obj2str(o)->str;
|
66
|
-
}
|
67
|
-
static inline size_t fiobj_str_getlen(FIOBJ o) {
|
68
|
-
if (obj2str(o)->is_small)
|
69
|
-
return obj2str(o)->slen;
|
70
|
-
return obj2str(o)->len;
|
71
|
-
}
|
72
|
-
static inline size_t fiobj_str_getcapa(FIOBJ o) {
|
73
|
-
if (obj2str(o)->is_small)
|
74
|
-
return STR_INTENAL_CAPA;
|
75
|
-
return obj2str(o)->capa;
|
76
|
-
}
|
77
|
-
static inline void fiobj_str_setlen(FIOBJ o, size_t len) {
|
78
|
-
if (obj2str(o)->is_small) {
|
79
|
-
obj2str(o)->slen = len;
|
80
|
-
STR_INTENAL_STR(o)[len] = 0;
|
81
|
-
} else {
|
82
|
-
obj2str(o)->len = len;
|
83
|
-
obj2str(o)->str[len] = 0;
|
84
|
-
obj2str(o)->hash = 0;
|
85
|
-
}
|
86
|
-
}
|
87
|
-
static inline fio_cstr_s fiobj_str_get_cstr(const FIOBJ o) {
|
88
|
-
if (obj2str(o)->is_small)
|
89
|
-
return (fio_cstr_s){.buffer = STR_INTENAL_STR(o),
|
90
|
-
.len = STR_INTENAL_LEN(o)};
|
91
|
-
;
|
92
|
-
return (fio_cstr_s){.buffer = obj2str(o)->str, .len = obj2str(o)->len};
|
53
|
+
static inline fio_str_info_s fiobj_str_get_cstr(const FIOBJ o) {
|
54
|
+
return fio_str_state(&obj2str(o)->str);
|
93
55
|
}
|
94
56
|
|
95
57
|
/* *****************************************************************************
|
96
58
|
String VTables
|
97
59
|
***************************************************************************** */
|
98
60
|
|
99
|
-
static
|
61
|
+
static fio_str_info_s fio_str2str(const FIOBJ o) {
|
62
|
+
return fiobj_str_get_cstr(o);
|
63
|
+
}
|
100
64
|
|
101
65
|
static void fiobj_str_dealloc(FIOBJ o, void (*task)(FIOBJ, void *), void *arg) {
|
102
|
-
|
103
|
-
fio_free(obj2str(o)->str);
|
66
|
+
fio_str_free(&obj2str(o)->str);
|
104
67
|
fio_free(FIOBJ2PTR(o));
|
105
68
|
(void)task;
|
106
69
|
(void)arg;
|
107
70
|
}
|
108
71
|
|
109
72
|
static size_t fiobj_str_is_eq(const FIOBJ self, const FIOBJ other) {
|
110
|
-
|
111
|
-
fio_cstr_s o2 = fiobj_str_get_cstr(other);
|
112
|
-
return (o1.len == o2.len &&
|
113
|
-
(o1.data == o2.data || !memcmp(o1.data, o2.data, o1.len)));
|
73
|
+
return fio_str_iseq(&obj2str(self)->str, &obj2str(other)->str);
|
114
74
|
}
|
115
75
|
|
116
76
|
static intptr_t fio_str2i(const FIOBJ o) {
|
117
|
-
char *pos =
|
77
|
+
char *pos = fio_str_data(&obj2str(o)->str);
|
118
78
|
return fio_atol(&pos);
|
119
79
|
}
|
120
80
|
static double fio_str2f(const FIOBJ o) {
|
121
|
-
char *pos =
|
81
|
+
char *pos = fio_str_data(&obj2str(o)->str);
|
122
82
|
return fio_atof(&pos);
|
123
83
|
}
|
124
84
|
|
125
|
-
static size_t fio_str2bool(const FIOBJ o) {
|
85
|
+
static size_t fio_str2bool(const FIOBJ o) {
|
86
|
+
return fio_str_len(&obj2str(o)->str) != 0;
|
87
|
+
}
|
126
88
|
|
127
89
|
uintptr_t fiobject___noop_count(const FIOBJ o);
|
128
90
|
|
@@ -153,50 +115,22 @@ FIOBJ fiobj_str_buf(size_t capa) {
|
|
153
115
|
perror("ERROR: fiobj string couldn't allocate memory");
|
154
116
|
exit(errno);
|
155
117
|
}
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
} else {
|
167
|
-
*s = (fiobj_str_s){
|
168
|
-
.head =
|
169
|
-
{
|
170
|
-
.ref = 1, .type = FIOBJ_T_STRING,
|
171
|
-
},
|
172
|
-
.len = 0,
|
173
|
-
.capa = capa,
|
174
|
-
.str = fio_malloc(capa),
|
175
|
-
};
|
176
|
-
if (!s->str) {
|
177
|
-
perror("ERROR: fiobj string couldn't allocate buffer memory");
|
178
|
-
exit(errno);
|
179
|
-
}
|
118
|
+
*s = (fiobj_str_s){
|
119
|
+
.head =
|
120
|
+
{
|
121
|
+
.ref = 1,
|
122
|
+
.type = FIOBJ_T_STRING,
|
123
|
+
},
|
124
|
+
.str = FIO_STR_INIT,
|
125
|
+
};
|
126
|
+
if (capa) {
|
127
|
+
fio_str_capa_assert(&s->str, capa);
|
180
128
|
}
|
181
129
|
return ((uintptr_t)s | FIOBJECT_STRING_FLAG);
|
182
130
|
}
|
183
131
|
|
184
132
|
/** Creates a String object. Remember to use `fiobj_free`. */
|
185
133
|
FIOBJ fiobj_str_new(const char *str, size_t len) {
|
186
|
-
FIOBJ s = fiobj_str_buf(len);
|
187
|
-
char *mem = fiobj_str_mem_addr(s);
|
188
|
-
memcpy(mem, str, len);
|
189
|
-
fiobj_str_setlen(s, len);
|
190
|
-
return s;
|
191
|
-
}
|
192
|
-
|
193
|
-
/**
|
194
|
-
* Creates a String object. Remember to use `fiobj_free`.
|
195
|
-
*
|
196
|
-
* The ownership of the memory indicated by `str` will now "move" to the
|
197
|
-
* object, so `free` will be called by the `fiobj` library as needed.
|
198
|
-
*/
|
199
|
-
FIOBJ fiobj_str_move(char *str, size_t len, size_t capacity) {
|
200
134
|
fiobj_str_s *s = fio_malloc(sizeof(*s));
|
201
135
|
if (!s) {
|
202
136
|
perror("ERROR: fiobj string couldn't allocate memory");
|
@@ -205,31 +139,28 @@ FIOBJ fiobj_str_move(char *str, size_t len, size_t capacity) {
|
|
205
139
|
*s = (fiobj_str_s){
|
206
140
|
.head =
|
207
141
|
{
|
208
|
-
.ref = 1,
|
142
|
+
.ref = 1,
|
143
|
+
.type = FIOBJ_T_STRING,
|
209
144
|
},
|
210
|
-
.
|
211
|
-
.capa = (capacity < len ? len : capacity),
|
212
|
-
.str = str,
|
145
|
+
.str = FIO_STR_INIT,
|
213
146
|
};
|
147
|
+
if (str && len) {
|
148
|
+
fio_str_write(&s->str, str, len);
|
149
|
+
}
|
214
150
|
return ((uintptr_t)s | FIOBJECT_STRING_FLAG);
|
215
151
|
}
|
216
152
|
|
217
153
|
/**
|
218
|
-
* Creates a
|
219
|
-
* `fiobj_free`.
|
220
|
-
*
|
221
|
-
* This variation avoids allocating memory for an existing static String.
|
154
|
+
* Creates a String object. Remember to use `fiobj_free`.
|
222
155
|
*
|
223
|
-
*
|
224
|
-
*
|
156
|
+
* It's possible to wrap a previosly allocated memory block in a FIOBJ String
|
157
|
+
* object, as long as it was allocated using `fio_malloc`.
|
225
158
|
*
|
226
|
-
*
|
159
|
+
* The ownership of the memory indicated by `str` will "move" to the object and
|
160
|
+
* will be freed (using `fio_free`) once the object's reference count drops to
|
161
|
+
* zero.
|
227
162
|
*/
|
228
|
-
FIOBJ
|
229
|
-
#if !FIOBJ_DONT_COPY_SMALL_STATIC_STRINGS
|
230
|
-
if (len < STR_INTENAL_CAPA)
|
231
|
-
return fiobj_str_new(str, len);
|
232
|
-
#endif
|
163
|
+
FIOBJ fiobj_str_move(char *str, size_t len, size_t capacity) {
|
233
164
|
fiobj_str_s *s = fio_malloc(sizeof(*s));
|
234
165
|
if (!s) {
|
235
166
|
perror("ERROR: fiobj string couldn't allocate memory");
|
@@ -238,42 +169,14 @@ FIOBJ fiobj_str_static(const char *str, size_t len) {
|
|
238
169
|
*s = (fiobj_str_s){
|
239
170
|
.head =
|
240
171
|
{
|
241
|
-
.ref = 1,
|
172
|
+
.ref = 1,
|
173
|
+
.type = FIOBJ_T_STRING,
|
242
174
|
},
|
243
|
-
.
|
244
|
-
.capa = 0,
|
245
|
-
.str = (char *)str,
|
175
|
+
.str = FIO_STR_INIT_EXISTING(str, len, capacity),
|
246
176
|
};
|
247
177
|
return ((uintptr_t)s | FIOBJECT_STRING_FLAG);
|
248
178
|
}
|
249
179
|
|
250
|
-
/** Creates a String object using a printf like interface. */
|
251
|
-
__attribute__((format(printf, 1, 0))) FIOBJ fiobj_strvprintf(const char *format,
|
252
|
-
va_list argv) {
|
253
|
-
FIOBJ str = 0;
|
254
|
-
va_list argv_cpy;
|
255
|
-
va_copy(argv_cpy, argv);
|
256
|
-
int len = vsnprintf(NULL, 0, format, argv_cpy);
|
257
|
-
va_end(argv_cpy);
|
258
|
-
if (len == 0)
|
259
|
-
str = fiobj_str_new("", 0);
|
260
|
-
if (len <= 0)
|
261
|
-
return str;
|
262
|
-
str = fiobj_str_buf(len);
|
263
|
-
char *mem = FIOBJECT2VTBL(str)->to_str(str).data;
|
264
|
-
vsnprintf(mem, len + 1, format, argv);
|
265
|
-
fiobj_str_setlen(str, len);
|
266
|
-
return str;
|
267
|
-
}
|
268
|
-
__attribute__((format(printf, 1, 2))) FIOBJ fiobj_strprintf(const char *format,
|
269
|
-
...) {
|
270
|
-
va_list argv;
|
271
|
-
va_start(argv, format);
|
272
|
-
FIOBJ str = fiobj_strvprintf(format, argv);
|
273
|
-
va_end(argv);
|
274
|
-
return str;
|
275
|
-
}
|
276
|
-
|
277
180
|
/**
|
278
181
|
* Returns a thread-static temporary string. Avoid calling `fiobj_dup` or
|
279
182
|
* `fiobj_free`.
|
@@ -282,179 +185,58 @@ FIOBJ fiobj_str_tmp(void) {
|
|
282
185
|
static __thread fiobj_str_s tmp = {
|
283
186
|
.head =
|
284
187
|
{
|
285
|
-
.ref = ((~(uint32_t)0) >> 4),
|
188
|
+
.ref = ((~(uint32_t)0) >> 4),
|
189
|
+
.type = FIOBJ_T_STRING,
|
286
190
|
},
|
287
|
-
.
|
288
|
-
.slen = 0,
|
191
|
+
.str = {.small = 1},
|
289
192
|
};
|
290
|
-
tmp.
|
291
|
-
tmp.
|
193
|
+
tmp.str.frozen = 0;
|
194
|
+
fio_str_resize(&tmp.str, 0);
|
292
195
|
return ((uintptr_t)&tmp | FIOBJECT_STRING_FLAG);
|
293
196
|
}
|
294
197
|
|
295
|
-
/** Dumps the `filename` file's contents into a new String. If `limit == 0`,
|
296
|
-
* than the data will be read until EOF.
|
297
|
-
*
|
298
|
-
* If the file can't be located, opened or read, or if `start_at` is beyond
|
299
|
-
* the EOF position, NULL is returned.
|
300
|
-
*
|
301
|
-
* Remember to use `fiobj_free`.
|
302
|
-
*/
|
303
|
-
FIOBJ fiobj_str_readfile(const char *filename, intptr_t start_at,
|
304
|
-
intptr_t limit) {
|
305
|
-
#if defined(__unix__) || defined(__linux__) || defined(__APPLE__)
|
306
|
-
/* POSIX implementations. */
|
307
|
-
if (filename == NULL)
|
308
|
-
return FIOBJ_INVALID;
|
309
|
-
struct stat f_data;
|
310
|
-
int file = -1;
|
311
|
-
size_t file_path_len = strlen(filename);
|
312
|
-
if (file_path_len == 0 || file_path_len >= PATH_MAX)
|
313
|
-
return FIOBJ_INVALID;
|
314
|
-
|
315
|
-
char real_public_path[PATH_MAX];
|
316
|
-
real_public_path[PATH_MAX - 1] = 0;
|
317
|
-
|
318
|
-
if (filename[0] == '~' && getenv("HOME") && file_path_len < PATH_MAX) {
|
319
|
-
strcpy(real_public_path, getenv("HOME"));
|
320
|
-
memcpy(real_public_path + strlen(real_public_path), filename + 1,
|
321
|
-
file_path_len);
|
322
|
-
filename = real_public_path;
|
323
|
-
}
|
324
|
-
|
325
|
-
if (stat(filename, &f_data) || f_data.st_size <= 0)
|
326
|
-
return FIOBJ_INVALID;
|
327
|
-
|
328
|
-
if (start_at < 0)
|
329
|
-
start_at = f_data.st_size + start_at;
|
330
|
-
|
331
|
-
if (start_at < 0 || start_at >= f_data.st_size)
|
332
|
-
return FIOBJ_INVALID;
|
333
|
-
|
334
|
-
if (limit <= 0 || f_data.st_size < (limit + start_at))
|
335
|
-
limit = f_data.st_size - start_at;
|
336
|
-
FIOBJ str = fiobj_str_buf(limit + 1);
|
337
|
-
if (!str)
|
338
|
-
return FIOBJ_INVALID;
|
339
|
-
file = open(filename, O_RDONLY);
|
340
|
-
if (file < 0) {
|
341
|
-
FIOBJECT2VTBL(str)->dealloc(str, NULL, NULL);
|
342
|
-
return FIOBJ_INVALID;
|
343
|
-
}
|
344
|
-
if (pread(file, fiobj_str_mem_addr(str), limit, start_at) != (ssize_t)limit) {
|
345
|
-
FIOBJECT2VTBL(str)->dealloc(str, NULL, NULL);
|
346
|
-
close(file);
|
347
|
-
return FIOBJ_INVALID;
|
348
|
-
}
|
349
|
-
close(file);
|
350
|
-
fiobj_str_setlen(str, limit);
|
351
|
-
return str;
|
352
|
-
#else
|
353
|
-
/* TODO: consider adding non POSIX implementations. */
|
354
|
-
return FIOBJ_INVALID;
|
355
|
-
#endif
|
356
|
-
}
|
357
|
-
|
358
198
|
/** Prevents the String object from being changed. */
|
359
199
|
void fiobj_str_freeze(FIOBJ str) {
|
360
200
|
if (FIOBJ_TYPE_IS(str, FIOBJ_T_STRING))
|
361
|
-
obj2str(str)->
|
201
|
+
fio_str_freeze(&obj2str(str)->str);
|
362
202
|
}
|
363
203
|
|
364
204
|
/** Confirms the requested capacity is available and allocates as required. */
|
365
205
|
size_t fiobj_str_capa_assert(FIOBJ str, size_t size) {
|
366
206
|
|
367
207
|
assert(FIOBJ_TYPE_IS(str, FIOBJ_T_STRING));
|
368
|
-
if (obj2str(str)->frozen)
|
208
|
+
if (obj2str(str)->str.frozen)
|
369
209
|
return 0;
|
370
|
-
|
371
|
-
|
372
|
-
if (size <= STR_INTENAL_CAPA)
|
373
|
-
return STR_INTENAL_CAPA;
|
374
|
-
if (size >> 12)
|
375
|
-
size = ((size >> 12) + 1) << 12;
|
376
|
-
char *mem = fio_malloc(size);
|
377
|
-
if (!mem) {
|
378
|
-
perror("FATAL ERROR: Couldn't allocate larger String memory");
|
379
|
-
exit(errno);
|
380
|
-
}
|
381
|
-
memcpy(mem, STR_INTENAL_STR(str), obj2str(str)->slen + 1);
|
382
|
-
*obj2str(str) = (fiobj_str_s){
|
383
|
-
.head =
|
384
|
-
{
|
385
|
-
.ref = obj2str(str)->head.ref, .type = FIOBJ_T_STRING,
|
386
|
-
},
|
387
|
-
.len = obj2str(str)->slen,
|
388
|
-
.capa = size,
|
389
|
-
.str = mem,
|
390
|
-
};
|
391
|
-
return obj2str(str)->capa;
|
392
|
-
}
|
393
|
-
if (obj2str(str)->capa >= size)
|
394
|
-
return obj2str(str)->capa;
|
395
|
-
|
396
|
-
/* large strings should increase memory by page size (assumes 4096 pages) */
|
397
|
-
if (size >> 12)
|
398
|
-
size = ((size >> 12) + 1) << 12;
|
399
|
-
else if (size < (obj2str(str)->capa << 1))
|
400
|
-
size = obj2str(str)->capa << 1; /* grow in steps */
|
401
|
-
|
402
|
-
if (obj2str(str)->capa == 0) {
|
403
|
-
/* a static string */
|
404
|
-
char *mem = fio_malloc(size);
|
405
|
-
if (!mem) {
|
406
|
-
perror("FATAL ERROR: Couldn't allocate new String memory");
|
407
|
-
exit(errno);
|
408
|
-
}
|
409
|
-
memcpy(mem, obj2str(str)->str, obj2str(str)->len + 1);
|
410
|
-
obj2str(str)->str = mem;
|
411
|
-
} else {
|
412
|
-
/* it's better to crash than live without memory... */
|
413
|
-
obj2str(str)->str =
|
414
|
-
fio_realloc2(obj2str(str)->str, size, obj2str(str)->len + 1);
|
415
|
-
if (!obj2str(str)->str) {
|
416
|
-
perror("FATAL ERROR: Couldn't (re)allocate String memory");
|
417
|
-
exit(errno);
|
418
|
-
}
|
419
|
-
}
|
420
|
-
obj2str(str)->capa = size;
|
421
|
-
return obj2str(str)->capa - 1;
|
210
|
+
fio_str_info_s state = fio_str_capa_assert(&obj2str(str)->str, size);
|
211
|
+
return state.capa;
|
422
212
|
}
|
423
213
|
|
424
214
|
/** Return's a String's capacity, if any. */
|
425
215
|
size_t fiobj_str_capa(FIOBJ str) {
|
426
216
|
assert(FIOBJ_TYPE_IS(str, FIOBJ_T_STRING));
|
427
|
-
|
428
|
-
return 0;
|
429
|
-
return fiobj_str_getcapa(str) - 1;
|
217
|
+
return fio_str_capa(&obj2str(str)->str);
|
430
218
|
}
|
431
219
|
|
432
220
|
/** Resizes a String object, allocating more memory if required. */
|
433
221
|
void fiobj_str_resize(FIOBJ str, size_t size) {
|
434
222
|
assert(FIOBJ_TYPE_IS(str, FIOBJ_T_STRING));
|
435
|
-
|
436
|
-
|
437
|
-
fiobj_str_capa_assert(str, size);
|
438
|
-
fiobj_str_setlen(str, size);
|
223
|
+
fio_str_resize(&obj2str(str)->str, size);
|
224
|
+
obj2str(str)->hash = 0;
|
439
225
|
return;
|
440
226
|
}
|
441
227
|
|
442
228
|
/** Deallocates any unnecessary memory (if supported by OS). */
|
443
|
-
void
|
229
|
+
void fiobj_str_compact(FIOBJ str) {
|
444
230
|
assert(FIOBJ_TYPE_IS(str, FIOBJ_T_STRING));
|
445
|
-
|
446
|
-
return;
|
447
|
-
obj2str(str)->capa = obj2str(str)->len + 1;
|
448
|
-
obj2str(str)->str = fio_realloc(obj2str(str)->str, obj2str(str)->capa);
|
231
|
+
fio_str_compact(&obj2str(str)->str);
|
449
232
|
return;
|
450
233
|
}
|
451
234
|
|
452
235
|
/** Empties a String's data. */
|
453
236
|
void fiobj_str_clear(FIOBJ str) {
|
454
237
|
assert(FIOBJ_TYPE_IS(str, FIOBJ_T_STRING));
|
455
|
-
|
456
|
-
|
457
|
-
fiobj_str_setlen(str, 0);
|
238
|
+
fio_str_resize(&obj2str(str)->str, 0);
|
239
|
+
obj2str(str)->hash = 0;
|
458
240
|
}
|
459
241
|
|
460
242
|
/**
|
@@ -463,47 +245,78 @@ void fiobj_str_clear(FIOBJ str) {
|
|
463
245
|
*/
|
464
246
|
size_t fiobj_str_write(FIOBJ dest, const char *data, size_t len) {
|
465
247
|
assert(FIOBJ_TYPE_IS(dest, FIOBJ_T_STRING));
|
466
|
-
if (obj2str(dest)->frozen)
|
248
|
+
if (obj2str(dest)->str.frozen)
|
249
|
+
return 0;
|
250
|
+
obj2str(dest)->hash = 0;
|
251
|
+
return fio_str_write(&obj2str(dest)->str, data, len).len;
|
252
|
+
}
|
253
|
+
|
254
|
+
/**
|
255
|
+
* Writes a number at the end of the String using normal base 10 notation.
|
256
|
+
*
|
257
|
+
* Returns the new length of the String
|
258
|
+
*/
|
259
|
+
size_t fiobj_str_write_i(FIOBJ dest, int64_t num) {
|
260
|
+
assert(FIOBJ_TYPE_IS(dest, FIOBJ_T_STRING));
|
261
|
+
if (obj2str(dest)->str.frozen)
|
467
262
|
return 0;
|
468
|
-
|
469
|
-
|
470
|
-
memcpy(s.data + s.len - len, data, len);
|
471
|
-
return s.len;
|
263
|
+
obj2str(dest)->hash = 0;
|
264
|
+
return fio_str_write_i(&obj2str(dest)->str, num).len;
|
472
265
|
}
|
266
|
+
|
473
267
|
/**
|
474
268
|
* Writes data at the end of the string, resizing the string as required.
|
475
269
|
* Returns the new length of the String
|
476
270
|
*/
|
477
|
-
size_t
|
271
|
+
size_t fiobj_str_printf(FIOBJ dest, const char *format, ...) {
|
478
272
|
assert(FIOBJ_TYPE_IS(dest, FIOBJ_T_STRING));
|
479
|
-
if (obj2str(dest)->frozen)
|
273
|
+
if (obj2str(dest)->str.frozen)
|
480
274
|
return 0;
|
275
|
+
obj2str(dest)->hash = 0;
|
481
276
|
va_list argv;
|
482
277
|
va_start(argv, format);
|
483
|
-
|
278
|
+
fio_str_info_s state = fio_str_vprintf(&obj2str(dest)->str, format, argv);
|
484
279
|
va_end(argv);
|
485
|
-
|
486
|
-
return obj2str(dest)->len;
|
487
|
-
fiobj_str_resize(dest, fiobj_str_getlen(dest) + len);
|
488
|
-
va_start(argv, format);
|
489
|
-
fio_cstr_s s = fiobj_str_get_cstr(dest);
|
490
|
-
vsnprintf(s.data + s.len - len, len + 1, format, argv);
|
491
|
-
va_end(argv);
|
492
|
-
// ((fio_str_s *)dest)->str[((fio_str_s *)dest)->len] = 0; // see str_resize
|
493
|
-
return s.len;
|
280
|
+
return state.len;
|
494
281
|
}
|
282
|
+
|
283
|
+
size_t fiobj_str_vprintf(FIOBJ dest, const char *format, va_list argv) {
|
284
|
+
assert(FIOBJ_TYPE_IS(dest, FIOBJ_T_STRING));
|
285
|
+
if (obj2str(dest)->str.frozen)
|
286
|
+
return 0;
|
287
|
+
obj2str(dest)->hash = 0;
|
288
|
+
fio_str_info_s state = fio_str_vprintf(&obj2str(dest)->str, format, argv);
|
289
|
+
return state.len;
|
290
|
+
}
|
291
|
+
|
292
|
+
/** Dumps the `filename` file's contents at the end of a String. If `limit ==
|
293
|
+
* 0`, than the data will be read until EOF.
|
294
|
+
*
|
295
|
+
* If the file can't be located, opened or read, or if `start_at` is beyond
|
296
|
+
* the EOF position, NULL is returned.
|
297
|
+
*
|
298
|
+
* Remember to use `fiobj_free`.
|
299
|
+
*/
|
300
|
+
size_t fiobj_str_readfile(FIOBJ dest, const char *filename, intptr_t start_at,
|
301
|
+
intptr_t limit) {
|
302
|
+
fio_str_info_s state =
|
303
|
+
fio_str_readfile(&obj2str(dest)->str, filename, start_at, limit);
|
304
|
+
return state.len;
|
305
|
+
}
|
306
|
+
|
495
307
|
/**
|
496
308
|
* Writes data at the end of the string, resizing the string as required.
|
497
309
|
* Returns the new length of the String
|
498
310
|
*/
|
499
|
-
size_t
|
311
|
+
size_t fiobj_str_concat(FIOBJ dest, FIOBJ obj) {
|
500
312
|
assert(FIOBJ_TYPE_IS(dest, FIOBJ_T_STRING));
|
501
|
-
if (obj2str(dest)->frozen)
|
313
|
+
if (obj2str(dest)->str.frozen)
|
502
314
|
return 0;
|
503
|
-
|
315
|
+
obj2str(dest)->hash = 0;
|
316
|
+
fio_str_info_s o = fiobj_obj2cstr(obj);
|
504
317
|
if (o.len == 0)
|
505
|
-
return obj2str(dest)->
|
506
|
-
return
|
318
|
+
return fio_str_len(&obj2str(dest)->str);
|
319
|
+
return fio_str_write(&obj2str(dest)->str, o.data, o.len).len;
|
507
320
|
}
|
508
321
|
|
509
322
|
/**
|
@@ -517,11 +330,8 @@ uint64_t fiobj_str_hash(FIOBJ o) {
|
|
517
330
|
if (obj2str(o)->hash) {
|
518
331
|
return obj2str(o)->hash;
|
519
332
|
}
|
520
|
-
|
521
|
-
|
522
|
-
} else {
|
523
|
-
obj2str(o)->hash = fio_siphash(obj2str(o)->str, obj2str(o)->len);
|
524
|
-
}
|
333
|
+
fio_str_info_s state = fio_str_state(&obj2str(o)->str);
|
334
|
+
obj2str(o)->hash = fio_siphash(state.data, state.len);
|
525
335
|
return obj2str(o)->hash;
|
526
336
|
}
|
527
337
|
|
@@ -532,8 +342,8 @@ Tests
|
|
532
342
|
#if DEBUG
|
533
343
|
void fiobj_test_string(void) {
|
534
344
|
fprintf(stderr, "=== Testing Strings\n");
|
535
|
-
fprintf(stderr, "* Internal String Capacity %u
|
536
|
-
(unsigned int)
|
345
|
+
fprintf(stderr, "* Internal String Capacity %u \n",
|
346
|
+
(unsigned int)FIO_STR_SMALL_CAPA);
|
537
347
|
#define TEST_ASSERT(cond, ...) \
|
538
348
|
if (!(cond)) { \
|
539
349
|
fprintf(stderr, "* " __VA_ARGS__); \
|
@@ -546,31 +356,31 @@ void fiobj_test_string(void) {
|
|
546
356
|
"String not equal to " str)
|
547
357
|
FIOBJ o = fiobj_str_new("Hello", 5);
|
548
358
|
TEST_ASSERT(FIOBJ_TYPE_IS(o, FIOBJ_T_STRING), "Small String isn't string!\n");
|
549
|
-
TEST_ASSERT(obj2str(o)->
|
359
|
+
TEST_ASSERT(obj2str(o)->str.small, "Hello isn't small\n");
|
550
360
|
fiobj_str_write(o, " World", 6);
|
551
361
|
TEST_ASSERT(FIOBJ_TYPE_IS(o, FIOBJ_T_STRING),
|
552
362
|
"Hello World String isn't string!\n");
|
553
|
-
TEST_ASSERT(obj2str(o)->
|
363
|
+
TEST_ASSERT(obj2str(o)->str.small, "Hello World isn't small\n");
|
554
364
|
TEST_ASSERT(fiobj_obj2cstr(o).len == 11,
|
555
365
|
"Invalid small string length (%u != 11)!\n",
|
556
366
|
(unsigned int)fiobj_obj2cstr(o).len)
|
557
367
|
fiobj_str_write(o, " World, you crazy longer sleep loving person :-)", 48);
|
558
|
-
TEST_ASSERT(!obj2str(o)->
|
368
|
+
TEST_ASSERT(!obj2str(o)->str.small, "Crazier shouldn't be small\n");
|
559
369
|
fiobj_free(o);
|
560
370
|
|
561
371
|
o = fiobj_str_new(
|
562
372
|
"hello my dear friend, I hope that your are well and happy.", 58);
|
563
373
|
TEST_ASSERT(FIOBJ_TYPE_IS(o, FIOBJ_T_STRING), "Long String isn't string!\n");
|
564
|
-
TEST_ASSERT(!obj2str(o)->
|
565
|
-
"Long String is small! (capa: %lu, len: %lu)\n",
|
566
|
-
obj2str(o)->
|
374
|
+
TEST_ASSERT(!obj2str(o)->str.small,
|
375
|
+
"Long String is small! (capa: %lu, len: %lu)\n",
|
376
|
+
fio_str_capa(&obj2str(o)->str), fio_str_len(&obj2str(o)->str));
|
567
377
|
TEST_ASSERT(fiobj_obj2cstr(o).len == 58,
|
568
378
|
"Invalid long string length (%lu != 58)!\n",
|
569
379
|
fiobj_obj2cstr(o).len)
|
570
380
|
uint64_t hash = fiobj_str_hash(o);
|
571
|
-
TEST_ASSERT(!obj2str(o)->frozen, "String forzen when only hashing!\n");
|
381
|
+
TEST_ASSERT(!obj2str(o)->str.frozen, "String forzen when only hashing!\n");
|
572
382
|
fiobj_str_freeze(o);
|
573
|
-
TEST_ASSERT(obj2str(o)->frozen, "String not forzen!\n");
|
383
|
+
TEST_ASSERT(obj2str(o)->str.frozen, "String not forzen!\n");
|
574
384
|
fiobj_str_write(o, " World", 6);
|
575
385
|
TEST_ASSERT(hash == fiobj_str_hash(o),
|
576
386
|
"String hash changed after hashing - not frozen?\n");
|
@@ -579,20 +389,10 @@ void fiobj_test_string(void) {
|
|
579
389
|
(unsigned long)fiobj_obj2cstr(o).len, fiobj_obj2cstr(o).data);
|
580
390
|
fiobj_free(o);
|
581
391
|
|
582
|
-
o =
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
o = fiobj_str_static(
|
588
|
-
"hello my dear friend, I hope that your are well and happy.", 58);
|
589
|
-
fiobj_str_write(o, " World", 6);
|
590
|
-
STR_EQ(o, "hello my dear friend, I hope that your are well and happy."
|
591
|
-
" World");
|
592
|
-
fiobj_free(o);
|
593
|
-
|
594
|
-
o = fiobj_strprintf("%u", 42);
|
595
|
-
TEST_ASSERT(fiobj_str_getlen(o) == 2, "fiobj_strprintf length error.\n");
|
392
|
+
o = fiobj_str_buf(1);
|
393
|
+
fiobj_str_printf(o, "%u", 42);
|
394
|
+
TEST_ASSERT(fio_str_len(&obj2str(o)->str) == 2,
|
395
|
+
"fiobj_strprintf length error.\n");
|
596
396
|
TEST_ASSERT(fiobj_obj2num(o), "fiobj_strprintf integer error.\n");
|
597
397
|
TEST_ASSERT(!memcmp(fiobj_obj2cstr(o).data, "42", 2),
|
598
398
|
"fiobj_strprintf string error.\n");
|
@@ -602,11 +402,20 @@ void fiobj_test_string(void) {
|
|
602
402
|
for (int i = 0; i < 16000; ++i) {
|
603
403
|
fiobj_str_write(o, "a", 1);
|
604
404
|
}
|
605
|
-
TEST_ASSERT(obj2str(o)->
|
606
|
-
|
405
|
+
TEST_ASSERT(fio_str_len(&obj2str(o)->str) == 16000,
|
406
|
+
"16K fiobj_str_write not 16K.\n");
|
407
|
+
TEST_ASSERT(fio_str_capa(&obj2str(o)->str) >= 16000,
|
607
408
|
"16K fiobj_str_write capa not enough.\n");
|
608
409
|
fiobj_free(o);
|
609
410
|
|
411
|
+
o = fiobj_str_buf(0);
|
412
|
+
TEST_ASSERT(fiobj_str_readfile(o, __FILE__, 0, 0),
|
413
|
+
"`fiobj_str_readfile` - file wasn't read!");
|
414
|
+
TEST_ASSERT(!memcmp(fiobj_obj2cstr(o).data, "/*", 2),
|
415
|
+
"`fiobj_str_readfile` error, start of file doesn't match:\n%s",
|
416
|
+
fiobj_obj2cstr(o).data);
|
417
|
+
fiobj_free(o);
|
418
|
+
|
610
419
|
fprintf(stderr, "* passed.\n");
|
611
420
|
}
|
612
421
|
#endif
|