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
data/ext/iodine/fiobj_numbers.h
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#ifndef H_FIOBJ_NUMBERS_H
|
2
2
|
#define H_FIOBJ_NUMBERS_H
|
3
3
|
/*
|
4
|
-
Copyright: Boaz Segev, 2017
|
4
|
+
Copyright: Boaz Segev, 2017-2018
|
5
5
|
License: MIT
|
6
6
|
*/
|
7
7
|
|
@@ -15,33 +15,109 @@ extern "C" {
|
|
15
15
|
Numbers API (Integers)
|
16
16
|
***************************************************************************** */
|
17
17
|
|
18
|
-
extern const uintptr_t FIOBJ_T_NUMBER;
|
19
|
-
|
20
18
|
/** Creates a Number object. Remember to use `fiobj_free`. */
|
21
|
-
|
19
|
+
FIO_INLINE FIOBJ fiobj_num_new(intptr_t num);
|
22
20
|
|
23
|
-
/**
|
24
|
-
|
21
|
+
/** Creates a temporary Number object. Avoid using `fiobj_free`. */
|
22
|
+
FIOBJ fiobj_num_tmp(intptr_t num);
|
25
23
|
|
26
24
|
/* *****************************************************************************
|
27
25
|
Float API (Double)
|
28
26
|
***************************************************************************** */
|
29
27
|
|
30
|
-
extern const uintptr_t FIOBJ_T_FLOAT;
|
31
|
-
|
32
28
|
/** Creates a Float object. Remember to use `fiobj_free`. */
|
33
|
-
|
29
|
+
FIOBJ fiobj_float_new(double num);
|
34
30
|
|
35
31
|
/** Mutates a Float object's value. Effects every object's reference! */
|
36
|
-
void fiobj_float_set(
|
32
|
+
void fiobj_float_set(FIOBJ obj, double num);
|
33
|
+
|
34
|
+
/** Creates a temporary Float object. Avoid using `fiobj_free`. */
|
35
|
+
FIOBJ fiobj_float_tmp(double num);
|
36
|
+
|
37
|
+
/* *****************************************************************************
|
38
|
+
Numerical Helpers: not FIOBJ specific, but included as part of the library
|
39
|
+
***************************************************************************** */
|
40
|
+
|
41
|
+
/**
|
42
|
+
* A helper function that converts between String data to a signed int64_t.
|
43
|
+
*
|
44
|
+
* Numbers are assumed to be in base 10.
|
45
|
+
*
|
46
|
+
* The `0x##` (or `x##`) and `0b##` (or `b##`) are recognized as base 16 and
|
47
|
+
* base 2 (binary MSB first) respectively.
|
48
|
+
*
|
49
|
+
* The pointer will be updated to point to the first byte after the number.
|
50
|
+
*/
|
51
|
+
intptr_t fio_atol(char **pstr);
|
52
|
+
|
53
|
+
/** A helper function that convers between String data to a signed double. */
|
54
|
+
double fio_atof(char **pstr);
|
55
|
+
|
56
|
+
/**
|
57
|
+
* A helper function that convers between a signed int64_t to a string.
|
58
|
+
*
|
59
|
+
* No overflow guard is provided, make sure there's at least 66 bytes available
|
60
|
+
* (for base 2).
|
61
|
+
*
|
62
|
+
* Supports base 2, base 10 and base 16. An unsupported base will silently
|
63
|
+
* default to base 10. Prefixes aren't added (i.e., no "0x" or "0b" at the
|
64
|
+
* beginning of the string).
|
65
|
+
*
|
66
|
+
* Returns the number of bytes actually written (excluding the NUL terminator).
|
67
|
+
*/
|
68
|
+
size_t fio_ltoa(char *dest, int64_t num, uint8_t base);
|
69
|
+
|
70
|
+
/**
|
71
|
+
* A helper function that convers between a double to a string.
|
72
|
+
*
|
73
|
+
* No overflow guard is provided, make sure there's at least 130 bytes available
|
74
|
+
* (for base 2).
|
75
|
+
*
|
76
|
+
* Supports base 2, base 10 and base 16. An unsupported base will silently
|
77
|
+
* default to base 10. Prefixes aren't added (i.e., no "0x" or "0b" at the
|
78
|
+
* beginning of the string).
|
79
|
+
*
|
80
|
+
* Returns the number of bytes actually written (excluding the NUL terminator).
|
81
|
+
*/
|
82
|
+
size_t fio_ftoa(char *dest, double num, uint8_t base);
|
83
|
+
|
84
|
+
/** Converts a number to a temporary, thread safe, C string object */
|
85
|
+
fio_cstr_s fio_ltocstr(long);
|
86
|
+
|
87
|
+
/** Converts a float to a temporary, thread safe, C string object */
|
88
|
+
fio_cstr_s fio_ftocstr(double);
|
37
89
|
|
38
90
|
/* *****************************************************************************
|
39
91
|
Pointer Wrapping Helper MACROs (uses integers)
|
40
92
|
***************************************************************************** */
|
41
93
|
|
42
|
-
#define fiobj_ptr_wrap(ptr) fiobj_num_new((
|
94
|
+
#define fiobj_ptr_wrap(ptr) fiobj_num_new((uintptr_t)(ptr))
|
43
95
|
#define fiobj_ptr_unwrap(obj) ((void *)fiobj_obj2num((obj)))
|
44
96
|
|
97
|
+
/* *****************************************************************************
|
98
|
+
Inline Number Initialization
|
99
|
+
***************************************************************************** */
|
100
|
+
|
101
|
+
FIOBJ fiobj_num_new_bignum(intptr_t num);
|
102
|
+
|
103
|
+
/** Creates a Number object. Remember to use `fiobj_free`. */
|
104
|
+
FIO_INLINE FIOBJ fiobj_num_new(intptr_t num) {
|
105
|
+
if ((((uintptr_t)num &
|
106
|
+
(FIOBJ_NUMBER_SIGN_BIT | FIOBJ_NUMBER_SIGN_EXCLUDE_BIT)) == 0) ||
|
107
|
+
(((uintptr_t)num &
|
108
|
+
(FIOBJ_NUMBER_SIGN_BIT | FIOBJ_NUMBER_SIGN_EXCLUDE_BIT)) ==
|
109
|
+
(FIOBJ_NUMBER_SIGN_BIT | FIOBJ_NUMBER_SIGN_EXCLUDE_BIT))) {
|
110
|
+
const uintptr_t num_abs = (uintptr_t)num & FIOBJ_NUMBER_SIGN_MASK;
|
111
|
+
const uintptr_t num_sign = (uintptr_t)num & FIOBJ_NUMBER_SIGN_BIT;
|
112
|
+
return ((num_abs << 1) | num_sign | FIOBJECT_NUMBER_FLAG);
|
113
|
+
}
|
114
|
+
return fiobj_num_new_bignum(num);
|
115
|
+
}
|
116
|
+
|
117
|
+
#if DEBUG
|
118
|
+
void fiobj_test_numbers(void);
|
119
|
+
#endif
|
120
|
+
|
45
121
|
#ifdef __cplusplus
|
46
122
|
} /* extern "C" */
|
47
123
|
#endif
|
data/ext/iodine/fiobj_str.c
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
/*
|
2
|
-
Copyright: Boaz Segev, 2017
|
2
|
+
Copyright: Boaz Segev, 2017-2018
|
3
3
|
License: MIT
|
4
4
|
*/
|
5
5
|
|
@@ -10,16 +10,30 @@ License: MIT
|
|
10
10
|
#include <unistd.h>
|
11
11
|
#endif
|
12
12
|
|
13
|
-
#
|
13
|
+
#ifdef _SC_PAGESIZE
|
14
|
+
#define PAGE_SIZE sysconf(_SC_PAGESIZE)
|
15
|
+
#else
|
16
|
+
#define PAGE_SIZE 4096
|
17
|
+
#endif
|
18
|
+
|
19
|
+
#include "fiobject.h"
|
20
|
+
|
21
|
+
#include "fio_siphash.h"
|
22
|
+
#include "fiobj_numbers.h"
|
14
23
|
#include "fiobj_str.h"
|
15
24
|
|
25
|
+
#include <assert.h>
|
16
26
|
#include <errno.h>
|
17
27
|
#include <fcntl.h>
|
18
28
|
#include <limits.h>
|
29
|
+
#include <string.h>
|
19
30
|
#include <sys/stat.h>
|
20
31
|
|
32
|
+
#define FIO_OVERRIDE_MALLOC 1
|
33
|
+
#include "fio_mem.h"
|
34
|
+
|
21
35
|
#ifndef PATH_MAX
|
22
|
-
#define PATH_MAX
|
36
|
+
#define PATH_MAX PAGE_SIZE
|
23
37
|
#endif
|
24
38
|
|
25
39
|
/* *****************************************************************************
|
@@ -27,137 +41,182 @@ String Type
|
|
27
41
|
***************************************************************************** */
|
28
42
|
|
29
43
|
typedef struct {
|
30
|
-
|
31
|
-
uint64_t
|
32
|
-
|
33
|
-
uint8_t
|
44
|
+
fiobj_object_header_s head;
|
45
|
+
uint64_t hash;
|
46
|
+
uint8_t is_small;
|
47
|
+
uint8_t frozen;
|
48
|
+
uint8_t slen;
|
49
|
+
intptr_t len;
|
50
|
+
uintptr_t capa;
|
34
51
|
char *str;
|
35
52
|
} fiobj_str_s;
|
36
53
|
|
37
|
-
#define obj2str(o) ((fiobj_str_s *)(o))
|
54
|
+
#define obj2str(o) ((fiobj_str_s *)(FIOBJ2PTR(o)))
|
55
|
+
|
56
|
+
#define STR_INTENAL_OFFSET ((uintptr_t)(&(((fiobj_str_s *)0)->slen) + 1))
|
57
|
+
#define STR_INTENAL_CAPA ((uintptr_t)(sizeof(fiobj_str_s) - STR_INTENAL_OFFSET))
|
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};
|
93
|
+
}
|
38
94
|
|
39
95
|
/* *****************************************************************************
|
40
|
-
String
|
96
|
+
String VTables
|
41
97
|
***************************************************************************** */
|
42
98
|
|
43
|
-
static
|
44
|
-
free(obj2str(o)->str);
|
45
|
-
fiobj_dealloc(o);
|
46
|
-
}
|
99
|
+
static fio_cstr_s fio_str2str(const FIOBJ o) { return fiobj_str_get_cstr(o); }
|
47
100
|
|
48
|
-
static
|
49
|
-
if (
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
101
|
+
static void fiobj_str_dealloc(FIOBJ o, void (*task)(FIOBJ, void *), void *arg) {
|
102
|
+
if (obj2str(o)->is_small == 0 && obj2str(o)->capa)
|
103
|
+
fio_free(obj2str(o)->str);
|
104
|
+
fio_free(FIOBJ2PTR(o));
|
105
|
+
(void)task;
|
106
|
+
(void)arg;
|
54
107
|
}
|
55
108
|
|
56
|
-
static
|
57
|
-
|
109
|
+
static size_t fiobj_str_is_eq(const FIOBJ self, const FIOBJ other) {
|
110
|
+
fio_cstr_s o1 = fiobj_str_get_cstr(self);
|
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)));
|
58
114
|
}
|
59
|
-
|
60
|
-
|
61
|
-
|
115
|
+
|
116
|
+
static intptr_t fio_str2i(const FIOBJ o) {
|
117
|
+
char *pos = fiobj_str_mem_addr(o);
|
118
|
+
return fio_atol(&pos);
|
62
119
|
}
|
63
|
-
static double fio_str2f(const
|
64
|
-
char *
|
65
|
-
return fio_atof(&
|
120
|
+
static double fio_str2f(const FIOBJ o) {
|
121
|
+
char *pos = fiobj_str_mem_addr(o);
|
122
|
+
return fio_atof(&pos);
|
66
123
|
}
|
67
124
|
|
68
|
-
static
|
69
|
-
|
70
|
-
static struct fiobj_vtable_s FIOBJ_VTABLE_STRING = {
|
71
|
-
.name = "String",
|
72
|
-
.free = fiobj_str_dealloc,
|
73
|
-
.to_i = fio_str2i,
|
74
|
-
.to_f = fio_str2f,
|
75
|
-
.to_str = fio_str2str,
|
76
|
-
.is_eq = fiobj_str_is_eq,
|
77
|
-
.is_true = fio_str2bool,
|
78
|
-
.count = fiobj_noop_count,
|
79
|
-
.unwrap = fiobj_noop_unwrap,
|
80
|
-
.each1 = fiobj_noop_each1,
|
81
|
-
};
|
125
|
+
static size_t fio_str2bool(const FIOBJ o) { return fiobj_str_getlen(o) != 0; }
|
82
126
|
|
83
|
-
|
127
|
+
uintptr_t fiobject___noop_count(const FIOBJ o);
|
84
128
|
|
85
|
-
|
86
|
-
.
|
87
|
-
.
|
129
|
+
const fiobj_object_vtable_s FIOBJECT_VTABLE_STRING = {
|
130
|
+
.class_name = "String",
|
131
|
+
.dealloc = fiobj_str_dealloc,
|
88
132
|
.to_i = fio_str2i,
|
89
133
|
.to_f = fio_str2f,
|
90
134
|
.to_str = fio_str2str,
|
91
135
|
.is_eq = fiobj_str_is_eq,
|
92
136
|
.is_true = fio_str2bool,
|
93
|
-
.count =
|
94
|
-
.unwrap = fiobj_noop_unwrap,
|
95
|
-
.each1 = fiobj_noop_each1,
|
137
|
+
.count = fiobject___noop_count,
|
96
138
|
};
|
97
139
|
|
98
|
-
const uintptr_t FIOBJ_T_STRING_STATIC =
|
99
|
-
(uintptr_t)(&FIOBJ_VTABLE_STATIC_STRING);
|
100
|
-
|
101
140
|
/* *****************************************************************************
|
102
141
|
String API
|
103
142
|
***************************************************************************** */
|
104
143
|
|
105
|
-
static inline fiobj_s *fiobj_str_alloc(size_t len) {
|
106
|
-
fiobj_s *o = fiobj_alloc(sizeof(fiobj_str_s) + len + 1);
|
107
|
-
if (!o)
|
108
|
-
perror("ERROR: fiobj string couldn't allocate memory"), exit(errno);
|
109
|
-
*obj2str(o) = (fiobj_str_s){
|
110
|
-
.vtable = &FIOBJ_VTABLE_STRING,
|
111
|
-
.len = len,
|
112
|
-
.capa = len + 1,
|
113
|
-
.str = malloc(len + 1),
|
114
|
-
};
|
115
|
-
if (!obj2str(o)->str)
|
116
|
-
perror("ERROR: fiobj string couldn't allocate memory"), exit(errno);
|
117
|
-
obj2str(o)->str[len] = 0;
|
118
|
-
return o;
|
119
|
-
}
|
120
|
-
|
121
|
-
/** Creates a String object. Remember to use `fiobj_free`. */
|
122
|
-
fiobj_s *fiobj_str_new(const char *str, size_t len) {
|
123
|
-
fiobj_s *s = fiobj_str_alloc(len);
|
124
|
-
if (str)
|
125
|
-
memcpy(obj2str(s)->str, str, len);
|
126
|
-
return s;
|
127
|
-
}
|
128
|
-
|
129
144
|
/** Creates a buffer String object. Remember to use `fiobj_free`. */
|
130
|
-
|
145
|
+
FIOBJ fiobj_str_buf(size_t capa) {
|
131
146
|
if (capa)
|
132
|
-
capa = capa
|
147
|
+
capa = capa + 1;
|
133
148
|
else
|
134
|
-
capa =
|
135
|
-
|
136
|
-
|
149
|
+
capa = PAGE_SIZE;
|
150
|
+
|
151
|
+
fiobj_str_s *s = fio_malloc(sizeof(*s));
|
152
|
+
if (!s) {
|
153
|
+
perror("ERROR: fiobj string couldn't allocate memory");
|
154
|
+
exit(errno);
|
155
|
+
}
|
156
|
+
|
157
|
+
if (capa <= STR_INTENAL_CAPA) {
|
158
|
+
*s = (fiobj_str_s){
|
159
|
+
.head =
|
160
|
+
{
|
161
|
+
.ref = 1, .type = FIOBJ_T_STRING,
|
162
|
+
},
|
163
|
+
.is_small = 1,
|
164
|
+
.slen = 0,
|
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
|
+
}
|
180
|
+
}
|
181
|
+
return ((uintptr_t)s | FIOBJECT_STRING_FLAG);
|
182
|
+
}
|
183
|
+
|
184
|
+
/** Creates a String object. Remember to use `fiobj_free`. */
|
185
|
+
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);
|
137
190
|
return s;
|
138
191
|
}
|
139
192
|
|
140
193
|
/**
|
141
194
|
* Creates a String object. Remember to use `fiobj_free`.
|
142
195
|
*
|
143
|
-
* The ownership of the memory indicated by `str` will now "move" to the
|
144
|
-
* so `free` will be called
|
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.
|
145
198
|
*/
|
146
|
-
|
147
|
-
|
148
|
-
if (!
|
149
|
-
perror("ERROR: fiobj string couldn't allocate memory")
|
150
|
-
|
151
|
-
|
199
|
+
FIOBJ fiobj_str_move(char *str, size_t len, size_t capacity) {
|
200
|
+
fiobj_str_s *s = fio_malloc(sizeof(*s));
|
201
|
+
if (!s) {
|
202
|
+
perror("ERROR: fiobj string couldn't allocate memory");
|
203
|
+
exit(errno);
|
204
|
+
}
|
205
|
+
*s = (fiobj_str_s){
|
206
|
+
.head =
|
207
|
+
{
|
208
|
+
.ref = 1, .type = FIOBJ_T_STRING,
|
209
|
+
},
|
152
210
|
.len = len,
|
153
211
|
.capa = (capacity < len ? len : capacity),
|
154
|
-
.str =
|
212
|
+
.str = str,
|
155
213
|
};
|
156
|
-
return
|
214
|
+
return ((uintptr_t)s | FIOBJECT_STRING_FLAG);
|
157
215
|
}
|
158
216
|
|
159
217
|
/**
|
160
|
-
* Creates a static String object from a static C string. Remember
|
218
|
+
* Creates a static String object from a static C string. Remember
|
219
|
+
* `fiobj_free`.
|
161
220
|
*
|
162
221
|
* This variation avoids allocating memory for an existing static String.
|
163
222
|
*
|
@@ -166,31 +225,32 @@ fiobj_s *fiobj_str_move(char *str, size_t len, size_t capacity) {
|
|
166
225
|
*
|
167
226
|
* NOTICE: static strings can't be written to.
|
168
227
|
*/
|
169
|
-
|
170
|
-
|
171
|
-
if (
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
228
|
+
FIOBJ fiobj_str_static(const char *str, size_t len) {
|
229
|
+
#if !FIOBJ_DONT_COPY_SMALL_STATIC_STRINGS
|
230
|
+
if (len < STR_INTENAL_CAPA)
|
231
|
+
return fiobj_str_new(str, len);
|
232
|
+
#endif
|
233
|
+
fiobj_str_s *s = fio_malloc(sizeof(*s));
|
234
|
+
if (!s) {
|
235
|
+
perror("ERROR: fiobj string couldn't allocate memory");
|
236
|
+
exit(errno);
|
237
|
+
}
|
238
|
+
*s = (fiobj_str_s){
|
239
|
+
.head =
|
240
|
+
{
|
241
|
+
.ref = 1, .type = FIOBJ_T_STRING,
|
242
|
+
},
|
243
|
+
.len = len,
|
176
244
|
.capa = 0,
|
177
245
|
.str = (char *)str,
|
178
246
|
};
|
179
|
-
|
180
|
-
perror("ERROR: fiobj string couldn't allocate memory"), exit(errno);
|
181
|
-
return o;
|
182
|
-
}
|
183
|
-
|
184
|
-
/** Creates a copy from an existing String. Remember to use `fiobj_free`. */
|
185
|
-
fiobj_s *fiobj_str_copy(fiobj_s *src) {
|
186
|
-
fio_cstr_s s = fiobj_obj2cstr(src);
|
187
|
-
return fiobj_str_new(s.data, s.len);
|
247
|
+
return ((uintptr_t)s | FIOBJECT_STRING_FLAG);
|
188
248
|
}
|
189
249
|
|
190
250
|
/** Creates a String object using a printf like interface. */
|
191
|
-
__attribute__((format(printf, 1, 0)))
|
192
|
-
|
193
|
-
|
251
|
+
__attribute__((format(printf, 1, 0))) FIOBJ fiobj_strvprintf(const char *format,
|
252
|
+
va_list argv) {
|
253
|
+
FIOBJ str = 0;
|
194
254
|
va_list argv_cpy;
|
195
255
|
va_copy(argv_cpy, argv);
|
196
256
|
int len = vsnprintf(NULL, 0, format, argv_cpy);
|
@@ -199,151 +259,224 @@ fiobj_strvprintf(const char *format, va_list argv) {
|
|
199
259
|
str = fiobj_str_new("", 0);
|
200
260
|
if (len <= 0)
|
201
261
|
return str;
|
202
|
-
str =
|
203
|
-
|
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);
|
204
266
|
return str;
|
205
267
|
}
|
206
|
-
__attribute__((format(printf, 1, 2)))
|
207
|
-
|
268
|
+
__attribute__((format(printf, 1, 2))) FIOBJ fiobj_strprintf(const char *format,
|
269
|
+
...) {
|
208
270
|
va_list argv;
|
209
271
|
va_start(argv, format);
|
210
|
-
|
272
|
+
FIOBJ str = fiobj_strvprintf(format, argv);
|
211
273
|
va_end(argv);
|
212
274
|
return str;
|
213
275
|
}
|
214
276
|
|
277
|
+
/**
|
278
|
+
* Returns a thread-static temporary string. Avoid calling `fiobj_dup` or
|
279
|
+
* `fiobj_free`.
|
280
|
+
*/
|
281
|
+
FIOBJ fiobj_str_tmp(void) {
|
282
|
+
static __thread fiobj_str_s tmp = {
|
283
|
+
.head =
|
284
|
+
{
|
285
|
+
.ref = ((~(uint32_t)0) >> 4), .type = FIOBJ_T_STRING,
|
286
|
+
},
|
287
|
+
.is_small = 1,
|
288
|
+
.slen = 0,
|
289
|
+
};
|
290
|
+
tmp.len = 0;
|
291
|
+
tmp.slen = 0;
|
292
|
+
return ((uintptr_t)&tmp | FIOBJECT_STRING_FLAG);
|
293
|
+
}
|
294
|
+
|
215
295
|
/** Dumps the `filename` file's contents into a new String. If `limit == 0`,
|
216
296
|
* than the data will be read until EOF.
|
217
297
|
*
|
218
|
-
* If the file can't be located, opened or read, or if `start_at` is beyond
|
219
|
-
* EOF position, NULL is returned.
|
298
|
+
* If the file can't be located, opened or read, or if `start_at` is beyond
|
299
|
+
* the EOF position, NULL is returned.
|
220
300
|
*
|
221
301
|
* Remember to use `fiobj_free`.
|
222
302
|
*/
|
223
|
-
|
224
|
-
|
303
|
+
FIOBJ fiobj_str_readfile(const char *filename, intptr_t start_at,
|
304
|
+
intptr_t limit) {
|
225
305
|
#if defined(__unix__) || defined(__linux__) || defined(__APPLE__)
|
226
306
|
/* POSIX implementations. */
|
227
307
|
if (filename == NULL)
|
228
|
-
return
|
308
|
+
return FIOBJ_INVALID;
|
229
309
|
struct stat f_data;
|
230
310
|
int file = -1;
|
231
311
|
size_t file_path_len = strlen(filename);
|
232
|
-
if (file_path_len == 0 || file_path_len
|
233
|
-
return
|
312
|
+
if (file_path_len == 0 || file_path_len >= PATH_MAX)
|
313
|
+
return FIOBJ_INVALID;
|
234
314
|
|
235
|
-
char real_public_path[PATH_MAX
|
236
|
-
real_public_path[PATH_MAX] = 0;
|
315
|
+
char real_public_path[PATH_MAX];
|
316
|
+
real_public_path[PATH_MAX - 1] = 0;
|
237
317
|
|
238
|
-
if (filename[0] == '~' && getenv("HOME") && file_path_len
|
318
|
+
if (filename[0] == '~' && getenv("HOME") && file_path_len < PATH_MAX) {
|
239
319
|
strcpy(real_public_path, getenv("HOME"));
|
240
320
|
memcpy(real_public_path + strlen(real_public_path), filename + 1,
|
241
321
|
file_path_len);
|
242
322
|
filename = real_public_path;
|
243
323
|
}
|
244
324
|
|
245
|
-
if (stat(filename, &f_data) || f_data.st_size
|
246
|
-
return
|
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;
|
247
333
|
|
248
|
-
if (limit <= 0 ||
|
334
|
+
if (limit <= 0 || f_data.st_size < (limit + start_at))
|
249
335
|
limit = f_data.st_size - start_at;
|
250
|
-
|
336
|
+
FIOBJ str = fiobj_str_buf(limit + 1);
|
251
337
|
if (!str)
|
252
|
-
return
|
338
|
+
return FIOBJ_INVALID;
|
253
339
|
file = open(filename, O_RDONLY);
|
254
340
|
if (file < 0) {
|
255
|
-
|
256
|
-
return
|
341
|
+
FIOBJECT2VTBL(str)->dealloc(str, NULL, NULL);
|
342
|
+
return FIOBJ_INVALID;
|
257
343
|
}
|
258
|
-
|
259
|
-
|
260
|
-
fiobj_str_dealloc(str);
|
344
|
+
if (pread(file, fiobj_str_mem_addr(str), limit, start_at) != (ssize_t)limit) {
|
345
|
+
FIOBJECT2VTBL(str)->dealloc(str, NULL, NULL);
|
261
346
|
close(file);
|
262
|
-
return
|
347
|
+
return FIOBJ_INVALID;
|
263
348
|
}
|
264
349
|
close(file);
|
265
|
-
|
266
|
-
obj2str(str)->str[limit] = 0;
|
350
|
+
fiobj_str_setlen(str, limit);
|
267
351
|
return str;
|
268
352
|
#else
|
269
353
|
/* TODO: consider adding non POSIX implementations. */
|
270
|
-
return
|
354
|
+
return FIOBJ_INVALID;
|
271
355
|
#endif
|
272
356
|
}
|
273
357
|
|
358
|
+
/** Prevents the String object from being changed. */
|
359
|
+
void fiobj_str_freeze(FIOBJ str) {
|
360
|
+
if (FIOBJ_TYPE_IS(str, FIOBJ_T_STRING))
|
361
|
+
obj2str(str)->frozen = 1;
|
362
|
+
}
|
363
|
+
|
274
364
|
/** Confirms the requested capacity is available and allocates as required. */
|
275
|
-
size_t fiobj_str_capa_assert(
|
276
|
-
|
277
|
-
|
365
|
+
size_t fiobj_str_capa_assert(FIOBJ str, size_t size) {
|
366
|
+
|
367
|
+
assert(FIOBJ_TYPE_IS(str, FIOBJ_T_STRING));
|
368
|
+
if (obj2str(str)->frozen)
|
369
|
+
return 0;
|
370
|
+
size += 1;
|
371
|
+
if (obj2str(str)->is_small) {
|
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
|
+
};
|
278
391
|
return obj2str(str)->capa;
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
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;
|
284
422
|
}
|
285
423
|
|
286
424
|
/** Return's a String's capacity, if any. */
|
287
|
-
size_t fiobj_str_capa(
|
288
|
-
|
425
|
+
size_t fiobj_str_capa(FIOBJ str) {
|
426
|
+
assert(FIOBJ_TYPE_IS(str, FIOBJ_T_STRING));
|
427
|
+
if (obj2str(str)->frozen)
|
289
428
|
return 0;
|
290
|
-
return
|
429
|
+
return fiobj_str_getcapa(str) - 1;
|
291
430
|
}
|
292
431
|
|
293
432
|
/** Resizes a String object, allocating more memory if required. */
|
294
|
-
void fiobj_str_resize(
|
295
|
-
|
433
|
+
void fiobj_str_resize(FIOBJ str, size_t size) {
|
434
|
+
assert(FIOBJ_TYPE_IS(str, FIOBJ_T_STRING));
|
435
|
+
if (obj2str(str)->frozen)
|
296
436
|
return;
|
297
437
|
fiobj_str_capa_assert(str, size);
|
298
|
-
|
299
|
-
obj2str(str)->str[size] = 0;
|
438
|
+
fiobj_str_setlen(str, size);
|
300
439
|
return;
|
301
440
|
}
|
302
441
|
|
303
442
|
/** Deallocates any unnecessary memory (if supported by OS). */
|
304
|
-
void fiobj_str_minimize(
|
305
|
-
|
443
|
+
void fiobj_str_minimize(FIOBJ str) {
|
444
|
+
assert(FIOBJ_TYPE_IS(str, FIOBJ_T_STRING));
|
445
|
+
if (obj2str(str)->frozen || obj2str(str)->is_small || obj2str(str)->capa == 0)
|
306
446
|
return;
|
307
447
|
obj2str(str)->capa = obj2str(str)->len + 1;
|
308
|
-
obj2str(str)->str =
|
448
|
+
obj2str(str)->str = fio_realloc(obj2str(str)->str, obj2str(str)->capa);
|
309
449
|
return;
|
310
450
|
}
|
311
451
|
|
312
452
|
/** Empties a String's data. */
|
313
|
-
void fiobj_str_clear(
|
314
|
-
|
453
|
+
void fiobj_str_clear(FIOBJ str) {
|
454
|
+
assert(FIOBJ_TYPE_IS(str, FIOBJ_T_STRING));
|
455
|
+
if (obj2str(str)->frozen)
|
315
456
|
return;
|
316
|
-
|
317
|
-
obj2str(str)->len = 0;
|
457
|
+
fiobj_str_setlen(str, 0);
|
318
458
|
}
|
319
459
|
|
320
460
|
/**
|
321
461
|
* Writes data at the end of the string, resizing the string as required.
|
322
462
|
* Returns the new length of the String
|
323
463
|
*/
|
324
|
-
size_t fiobj_str_write(
|
325
|
-
|
464
|
+
size_t fiobj_str_write(FIOBJ dest, const char *data, size_t len) {
|
465
|
+
assert(FIOBJ_TYPE_IS(dest, FIOBJ_T_STRING));
|
466
|
+
if (obj2str(dest)->frozen)
|
326
467
|
return 0;
|
327
|
-
fiobj_str_resize(dest,
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
len--;
|
332
|
-
pos--;
|
333
|
-
obj2str(dest)->str[pos] = data[len];
|
334
|
-
}
|
335
|
-
} else {
|
336
|
-
memcpy(obj2str(dest)->str + obj2str(dest)->len - len, data, len);
|
337
|
-
}
|
338
|
-
// ((fio_str_s *)dest)->str[((fio_str_s *)dest)->len] = 0; // see str_resize
|
339
|
-
return obj2str(dest)->len;
|
468
|
+
fiobj_str_resize(dest, fiobj_str_getlen(dest) + len);
|
469
|
+
fio_cstr_s s = fiobj_str_get_cstr(dest);
|
470
|
+
memcpy(s.data + s.len - len, data, len);
|
471
|
+
return s.len;
|
340
472
|
}
|
341
473
|
/**
|
342
474
|
* Writes data at the end of the string, resizing the string as required.
|
343
475
|
* Returns the new length of the String
|
344
476
|
*/
|
345
|
-
size_t fiobj_str_write2(
|
346
|
-
|
477
|
+
size_t fiobj_str_write2(FIOBJ dest, const char *format, ...) {
|
478
|
+
assert(FIOBJ_TYPE_IS(dest, FIOBJ_T_STRING));
|
479
|
+
if (obj2str(dest)->frozen)
|
347
480
|
return 0;
|
348
481
|
va_list argv;
|
349
482
|
va_start(argv, format);
|
@@ -351,23 +484,129 @@ size_t fiobj_str_write2(fiobj_s *dest, const char *format, ...) {
|
|
351
484
|
va_end(argv);
|
352
485
|
if (len <= 0)
|
353
486
|
return obj2str(dest)->len;
|
354
|
-
fiobj_str_resize(dest,
|
487
|
+
fiobj_str_resize(dest, fiobj_str_getlen(dest) + len);
|
355
488
|
va_start(argv, format);
|
356
|
-
|
357
|
-
|
489
|
+
fio_cstr_s s = fiobj_str_get_cstr(dest);
|
490
|
+
vsnprintf(s.data + s.len - len, len + 1, format, argv);
|
358
491
|
va_end(argv);
|
359
492
|
// ((fio_str_s *)dest)->str[((fio_str_s *)dest)->len] = 0; // see str_resize
|
360
|
-
return
|
493
|
+
return s.len;
|
361
494
|
}
|
362
495
|
/**
|
363
496
|
* Writes data at the end of the string, resizing the string as required.
|
364
497
|
* Returns the new length of the String
|
365
498
|
*/
|
366
|
-
size_t fiobj_str_join(
|
367
|
-
|
499
|
+
size_t fiobj_str_join(FIOBJ dest, FIOBJ obj) {
|
500
|
+
assert(FIOBJ_TYPE_IS(dest, FIOBJ_T_STRING));
|
501
|
+
if (obj2str(dest)->frozen)
|
368
502
|
return 0;
|
369
503
|
fio_cstr_s o = fiobj_obj2cstr(obj);
|
370
504
|
if (o.len == 0)
|
371
505
|
return obj2str(dest)->len;
|
372
506
|
return fiobj_str_write(dest, o.data, o.len);
|
373
507
|
}
|
508
|
+
|
509
|
+
/**
|
510
|
+
* Calculates a String's SipHash value for use as a HashMap key.
|
511
|
+
*/
|
512
|
+
uint64_t fiobj_str_hash(FIOBJ o) {
|
513
|
+
assert(FIOBJ_TYPE_IS(o, FIOBJ_T_STRING));
|
514
|
+
// if (obj2str(o)->is_small) {
|
515
|
+
// return fio_siphash(STR_INTENAL_STR(o), STR_INTENAL_LEN(o));
|
516
|
+
// } else
|
517
|
+
if (obj2str(o)->hash) {
|
518
|
+
return obj2str(o)->hash;
|
519
|
+
}
|
520
|
+
if (obj2str(o)->is_small) {
|
521
|
+
obj2str(o)->hash = fio_siphash(STR_INTENAL_STR(o), STR_INTENAL_LEN(o));
|
522
|
+
} else {
|
523
|
+
obj2str(o)->hash = fio_siphash(obj2str(o)->str, obj2str(o)->len);
|
524
|
+
}
|
525
|
+
return obj2str(o)->hash;
|
526
|
+
}
|
527
|
+
|
528
|
+
/* *****************************************************************************
|
529
|
+
Tests
|
530
|
+
***************************************************************************** */
|
531
|
+
|
532
|
+
#if DEBUG
|
533
|
+
void fiobj_test_string(void) {
|
534
|
+
fprintf(stderr, "=== Testing Strings\n");
|
535
|
+
fprintf(stderr, "* Internal String Capacity %u with offset, %u\n",
|
536
|
+
(unsigned int)STR_INTENAL_CAPA, (unsigned int)STR_INTENAL_OFFSET);
|
537
|
+
#define TEST_ASSERT(cond, ...) \
|
538
|
+
if (!(cond)) { \
|
539
|
+
fprintf(stderr, "* " __VA_ARGS__); \
|
540
|
+
fprintf(stderr, "Testing failed.\n"); \
|
541
|
+
exit(-1); \
|
542
|
+
}
|
543
|
+
#define STR_EQ(o, str) \
|
544
|
+
TEST_ASSERT((fiobj_str_getlen(o) == strlen(str) && \
|
545
|
+
!memcmp(fiobj_str_mem_addr(o), str, strlen(str))), \
|
546
|
+
"String not equal to " str)
|
547
|
+
FIOBJ o = fiobj_str_new("Hello", 5);
|
548
|
+
TEST_ASSERT(FIOBJ_TYPE_IS(o, FIOBJ_T_STRING), "Small String isn't string!\n");
|
549
|
+
TEST_ASSERT(obj2str(o)->is_small, "Hello isn't small\n");
|
550
|
+
fiobj_str_write(o, " World", 6);
|
551
|
+
TEST_ASSERT(FIOBJ_TYPE_IS(o, FIOBJ_T_STRING),
|
552
|
+
"Hello World String isn't string!\n");
|
553
|
+
TEST_ASSERT(obj2str(o)->is_small, "Hello World isn't small\n");
|
554
|
+
TEST_ASSERT(fiobj_obj2cstr(o).len == 11,
|
555
|
+
"Invalid small string length (%u != 11)!\n",
|
556
|
+
(unsigned int)fiobj_obj2cstr(o).len)
|
557
|
+
fiobj_str_write(o, " World, you crazy longer sleep loving person :-)", 48);
|
558
|
+
TEST_ASSERT(!obj2str(o)->is_small, "Crazier shouldn't be small\n");
|
559
|
+
fiobj_free(o);
|
560
|
+
|
561
|
+
o = fiobj_str_new(
|
562
|
+
"hello my dear friend, I hope that your are well and happy.", 58);
|
563
|
+
TEST_ASSERT(FIOBJ_TYPE_IS(o, FIOBJ_T_STRING), "Long String isn't string!\n");
|
564
|
+
TEST_ASSERT(!obj2str(o)->is_small,
|
565
|
+
"Long String is small! (capa: %lu, len: %lu)\n", obj2str(o)->capa,
|
566
|
+
obj2str(o)->len);
|
567
|
+
TEST_ASSERT(fiobj_obj2cstr(o).len == 58,
|
568
|
+
"Invalid long string length (%lu != 58)!\n",
|
569
|
+
fiobj_obj2cstr(o).len)
|
570
|
+
uint64_t hash = fiobj_str_hash(o);
|
571
|
+
TEST_ASSERT(!obj2str(o)->frozen, "String forzen when only hashing!\n");
|
572
|
+
fiobj_str_freeze(o);
|
573
|
+
TEST_ASSERT(obj2str(o)->frozen, "String not forzen!\n");
|
574
|
+
fiobj_str_write(o, " World", 6);
|
575
|
+
TEST_ASSERT(hash == fiobj_str_hash(o),
|
576
|
+
"String hash changed after hashing - not frozen?\n");
|
577
|
+
TEST_ASSERT(fiobj_obj2cstr(o).len == 58,
|
578
|
+
"String was edited after hashing - not frozen!\n (%lu): %s",
|
579
|
+
(unsigned long)fiobj_obj2cstr(o).len, fiobj_obj2cstr(o).data);
|
580
|
+
fiobj_free(o);
|
581
|
+
|
582
|
+
o = fiobj_str_static("Hello", 5);
|
583
|
+
TEST_ASSERT(obj2str(o)->is_small,
|
584
|
+
"Small Static should be converted to dynamic.\n");
|
585
|
+
fiobj_free(o);
|
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");
|
596
|
+
TEST_ASSERT(fiobj_obj2num(o), "fiobj_strprintf integer error.\n");
|
597
|
+
TEST_ASSERT(!memcmp(fiobj_obj2cstr(o).data, "42", 2),
|
598
|
+
"fiobj_strprintf string error.\n");
|
599
|
+
fiobj_free(o);
|
600
|
+
|
601
|
+
o = fiobj_str_buf(4);
|
602
|
+
for (int i = 0; i < 16000; ++i) {
|
603
|
+
fiobj_str_write(o, "a", 1);
|
604
|
+
}
|
605
|
+
TEST_ASSERT(obj2str(o)->len == 16000, "16K fiobj_str_write not 16K.\n");
|
606
|
+
TEST_ASSERT(obj2str(o)->capa > 16001,
|
607
|
+
"16K fiobj_str_write capa not enough.\n");
|
608
|
+
fiobj_free(o);
|
609
|
+
|
610
|
+
fprintf(stderr, "* passed.\n");
|
611
|
+
}
|
612
|
+
#endif
|