ox 2.14.5 → 2.14.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -0
- data/README.md +1 -1
- data/ext/ox/builder.c +1 -5
- data/ext/ox/cache.c +309 -131
- data/ext/ox/cache.h +10 -10
- data/ext/ox/dump.c +2 -2
- data/ext/ox/extconf.rb +5 -2
- data/ext/ox/gen_load.c +5 -73
- data/ext/ox/hash_load.c +0 -4
- data/ext/ox/intern.c +153 -0
- data/ext/ox/intern.h +25 -0
- data/ext/ox/obj_load.c +14 -86
- data/ext/ox/ox.c +1018 -935
- data/ext/ox/ox.h +186 -210
- data/ext/ox/parse.c +72 -31
- data/ext/ox/sax.c +1103 -1276
- data/ext/ox/sax.h +45 -31
- data/ext/ox/sax_as.c +3 -5
- data/ext/ox/sax_buf.c +7 -16
- data/ext/ox/slotcache.c +158 -0
- data/ext/ox/slotcache.h +19 -0
- data/lib/ox/version.rb +1 -1
- metadata +7 -4
- data/ext/ox/sax_has.h +0 -53
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3cc19bc7d94f71b8e8252f3b22475383d3700b2cfe7f3e97aeaff4c36dc4730
|
4
|
+
data.tar.gz: 0034552f9848f7215d7533066d5a971c59dbfd1526257b479512489fe30e371b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b6ea9d757870451eaf28771481fe703ade50de9dc85d91575545be65ba0a65d7a71a4d193684130725ccad58ad506e1b47fd241aef92950c619be7d49779cbef
|
7
|
+
data.tar.gz: cdd97b3ee73f8755cc7a4296c64d41553b03619c7f37f561ad55b958e769e0dc65e652800da0a03b1a9ecb74a17b563188f01a1b8f86fed2d01395ec2eabd587
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,38 @@
|
|
2
2
|
|
3
3
|
All changes to the Ox gem are documented here. Releases follow semantic versioning.
|
4
4
|
|
5
|
+
## [2.14.9] - 2022-02-11
|
6
|
+
|
7
|
+
### Fixed
|
8
|
+
|
9
|
+
- Fixed the `\r` replacement with `\n` with the SAX parser according to https://www.w3.org/TR/2008/REC-xml-20081126/#sec-line-ends.
|
10
|
+
|
11
|
+
## [2.14.8] - 2022-02-09
|
12
|
+
|
13
|
+
### Fixed
|
14
|
+
|
15
|
+
- Renamed internal functions to avoid linking issues where Oj and Ox function names collided.
|
16
|
+
|
17
|
+
## [2.14.7] - 2022-02-03
|
18
|
+
|
19
|
+
### Fixed
|
20
|
+
|
21
|
+
- All classes and symbols are now registered to avoid issues with GC compaction movement.
|
22
|
+
- Parsing of any size processing instruction is now allowed. There is no 1024 limit.
|
23
|
+
- Fixed the `\r` replacement with `\n` according to https://www.w3.org/TR/2008/REC-xml-20081126/#sec-line-ends.
|
24
|
+
|
25
|
+
### Changed
|
26
|
+
|
27
|
+
- Symbol and string caching changed but should have no impact on use
|
28
|
+
other than being slightly faster and handles large numbers of cached
|
29
|
+
items more efficiently.
|
30
|
+
|
31
|
+
## [2.14.6] - 2021-11-03
|
32
|
+
|
33
|
+
### Fixed
|
34
|
+
|
35
|
+
- Closing tags in builder are now escapped correctly thanks to ezekg.
|
36
|
+
|
5
37
|
## [2.14.5] - 2021-06-04
|
6
38
|
|
7
39
|
### Fixed
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Ox gem
|
2
2
|
A fast XML parser and Object marshaller as a Ruby gem.
|
3
3
|
|
4
|
-
[](https://github.com/ohler55/ox/actions/workflows/CI.yml)
|
5
5
|
|
6
6
|
## Installation
|
7
7
|
gem install ox
|
data/ext/ox/builder.c
CHANGED
@@ -9,9 +9,7 @@
|
|
9
9
|
#include <string.h>
|
10
10
|
|
11
11
|
#include "ruby.h"
|
12
|
-
#if HAVE_RB_ENC_ASSOCIATE
|
13
12
|
#include "ruby/encoding.h"
|
14
|
-
#endif
|
15
13
|
#include "ox.h"
|
16
14
|
#include "buf.h"
|
17
15
|
#include "err.h"
|
@@ -286,7 +284,7 @@ pop(Builder b) {
|
|
286
284
|
append_indent(b);
|
287
285
|
}
|
288
286
|
buf_append_string(&b->buf, "</", 2);
|
289
|
-
|
287
|
+
append_string(b, e->name, e->len, xml_element_chars, false);
|
290
288
|
buf_append(&b->buf, '>');
|
291
289
|
b->col += e->len + 3;
|
292
290
|
b->pos += e->len + 3;
|
@@ -335,9 +333,7 @@ to_s(Builder b) {
|
|
335
333
|
rstr = rb_str_new(b->buf.head, buf_len(&b->buf));
|
336
334
|
|
337
335
|
if ('\0' != *b->encoding) {
|
338
|
-
#if HAVE_RB_ENC_ASSOCIATE
|
339
336
|
rb_enc_associate(rstr, rb_enc_find(b->encoding));
|
340
|
-
#endif
|
341
337
|
}
|
342
338
|
return rstr;
|
343
339
|
}
|
data/ext/ox/cache.c
CHANGED
@@ -1,160 +1,338 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
* All rights reserved.
|
4
|
-
*/
|
1
|
+
// Copyright (c) 2011, 2021 Peter Ohler. All rights reserved.
|
2
|
+
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
5
3
|
|
4
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
5
|
+
#include <pthread.h>
|
6
|
+
#endif
|
6
7
|
#include <stdlib.h>
|
7
|
-
#include <errno.h>
|
8
|
-
#include <stdio.h>
|
9
|
-
#include <string.h>
|
10
|
-
#include <strings.h>
|
11
|
-
#include <stdarg.h>
|
12
|
-
#include <stdint.h>
|
13
8
|
|
14
9
|
#include "cache.h"
|
15
10
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
of the key. */
|
20
|
-
char *key;
|
21
|
-
VALUE value;
|
22
|
-
struct _cache *slots[16];
|
23
|
-
};
|
11
|
+
// The stdlib calloc, realloc, and free are used instead of the Ruby ALLOC,
|
12
|
+
// ALLOC_N, REALLOC, and xfree since the later could trigger a GC which will
|
13
|
+
// either corrupt memory or if the mark function locks will deadlock.
|
24
14
|
|
25
|
-
|
15
|
+
#define REHASH_LIMIT 4
|
16
|
+
#define MIN_SHIFT 8
|
17
|
+
#define REUSE_MAX 8192
|
26
18
|
|
27
|
-
|
28
|
-
|
29
|
-
|
19
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
20
|
+
#define CACHE_LOCK(c) pthread_mutex_lock(&((c)->mutex))
|
21
|
+
#define CACHE_UNLOCK(c) pthread_mutex_unlock(&((c)->mutex))
|
22
|
+
#else
|
23
|
+
#define CACHE_LOCK(c) rb_mutex_lock((c)->mutex)
|
24
|
+
#define CACHE_UNLOCK(c) rb_mutex_unlock((c)->mutex)
|
25
|
+
#endif
|
30
26
|
|
31
|
-
|
32
|
-
|
27
|
+
// almost the Murmur hash algorithm
|
28
|
+
#define M 0x5bd1e995
|
33
29
|
|
34
|
-
|
30
|
+
typedef struct _slot {
|
31
|
+
struct _slot *next;
|
32
|
+
VALUE val;
|
33
|
+
uint64_t hash;
|
34
|
+
volatile uint32_t use_cnt;
|
35
|
+
uint8_t klen;
|
36
|
+
char key[CACHE_MAX_KEY];
|
37
|
+
} * Slot;
|
38
|
+
|
39
|
+
typedef struct _cache {
|
40
|
+
volatile Slot *slots;
|
41
|
+
volatile size_t cnt;
|
42
|
+
VALUE (*form)(const char *str, size_t len);
|
43
|
+
uint64_t size;
|
44
|
+
uint64_t mask;
|
45
|
+
VALUE (*intern)(struct _cache *c, const char *key, size_t len, const char **keyp);
|
46
|
+
volatile Slot reuse;
|
47
|
+
size_t rcnt;
|
48
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
49
|
+
pthread_mutex_t mutex;
|
50
|
+
#else
|
51
|
+
VALUE mutex;
|
52
|
+
#endif
|
53
|
+
uint8_t xrate;
|
54
|
+
bool mark;
|
55
|
+
} * Cache;
|
56
|
+
|
57
|
+
static uint64_t hash_calc(const uint8_t *key, size_t len) {
|
58
|
+
const uint8_t *end = key + len;
|
59
|
+
const uint8_t *endless = key + (len & 0xFFFFFFFC);
|
60
|
+
uint64_t h = (uint64_t)len;
|
61
|
+
uint64_t k;
|
62
|
+
|
63
|
+
while (key < endless) {
|
64
|
+
k = (uint64_t)*key++;
|
65
|
+
k |= (uint64_t)*key++ << 8;
|
66
|
+
k |= (uint64_t)*key++ << 16;
|
67
|
+
k |= (uint64_t)*key++ << 24;
|
68
|
+
|
69
|
+
k *= M;
|
70
|
+
k ^= k >> 24;
|
71
|
+
h *= M;
|
72
|
+
h ^= k * M;
|
73
|
+
}
|
74
|
+
if (1 < end - key) {
|
75
|
+
uint16_t k16 = (uint16_t)*key++;
|
76
|
+
|
77
|
+
k16 |= (uint16_t)*key++ << 8;
|
78
|
+
h ^= k16 << 8;
|
79
|
+
}
|
80
|
+
if (key < end) {
|
81
|
+
h ^= *key;
|
82
|
+
}
|
83
|
+
h *= M;
|
84
|
+
h ^= h >> 13;
|
85
|
+
h *= M;
|
86
|
+
h ^= h >> 15;
|
87
|
+
|
88
|
+
return h;
|
35
89
|
}
|
36
90
|
|
37
|
-
void
|
38
|
-
|
39
|
-
*
|
40
|
-
|
41
|
-
|
42
|
-
|
91
|
+
static void rehash(Cache c) {
|
92
|
+
uint64_t osize;
|
93
|
+
Slot *end;
|
94
|
+
Slot *sp;
|
95
|
+
|
96
|
+
osize = c->size;
|
97
|
+
c->size = osize * 4;
|
98
|
+
c->mask = c->size - 1;
|
99
|
+
c->slots = realloc((void *)c->slots, sizeof(Slot) * c->size);
|
100
|
+
memset((Slot *)c->slots + osize, 0, sizeof(Slot) * osize * 3);
|
101
|
+
end = (Slot *)c->slots + osize;
|
102
|
+
for (sp = (Slot *)c->slots; sp < end; sp++) {
|
103
|
+
Slot s = *sp;
|
104
|
+
Slot next = NULL;
|
105
|
+
|
106
|
+
*sp = NULL;
|
107
|
+
for (; NULL != s; s = next) {
|
108
|
+
uint64_t h = s->hash & c->mask;
|
109
|
+
Slot *bucket = (Slot *)c->slots + h;
|
110
|
+
|
111
|
+
next = s->next;
|
112
|
+
s->next = *bucket;
|
113
|
+
*bucket = s;
|
114
|
+
}
|
115
|
+
}
|
43
116
|
}
|
44
117
|
|
45
|
-
VALUE
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
if (
|
53
|
-
|
118
|
+
static VALUE ox_lockless_intern(Cache c, const char *key, size_t len, const char **keyp) {
|
119
|
+
uint64_t h = hash_calc((const uint8_t *)key, len);
|
120
|
+
Slot *bucket = (Slot *)c->slots + (h & c->mask);
|
121
|
+
Slot b;
|
122
|
+
volatile VALUE rkey;
|
123
|
+
|
124
|
+
while (REUSE_MAX < c->rcnt) {
|
125
|
+
if (NULL != (b = c->reuse)) {
|
126
|
+
c->reuse = b->next;
|
127
|
+
free(b);
|
128
|
+
c->rcnt--;
|
129
|
+
} else {
|
130
|
+
// An accounting error occured somewhere so correct it.
|
131
|
+
c->rcnt = 0;
|
132
|
+
}
|
133
|
+
}
|
134
|
+
for (b = *bucket; NULL != b; b = b->next) {
|
135
|
+
if ((uint8_t)len == b->klen && 0 == strncmp(b->key, key, len)) {
|
136
|
+
b->use_cnt += 16;
|
137
|
+
if (NULL != keyp) {
|
138
|
+
*keyp = b->key;
|
139
|
+
}
|
140
|
+
return b->val;
|
54
141
|
}
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
142
|
+
}
|
143
|
+
rkey = c->form(key, len);
|
144
|
+
if (NULL == (b = c->reuse)) {
|
145
|
+
b = calloc(1, sizeof(struct _slot));
|
146
|
+
} else {
|
147
|
+
c->reuse = b->next;
|
148
|
+
c->rcnt--;
|
149
|
+
}
|
150
|
+
b->hash = h;
|
151
|
+
memcpy(b->key, key, len);
|
152
|
+
b->klen = (uint8_t)len;
|
153
|
+
b->key[len] = '\0';
|
154
|
+
b->val = rkey;
|
155
|
+
b->use_cnt = 4;
|
156
|
+
b->next = *bucket;
|
157
|
+
*bucket = b;
|
158
|
+
c->cnt++; // Don't worry about wrapping. Worse case is the entry is removed and recreated.
|
159
|
+
if (NULL != keyp) {
|
160
|
+
*keyp = b->key;
|
161
|
+
}
|
162
|
+
if (REHASH_LIMIT < c->cnt / c->size) {
|
163
|
+
rehash(c);
|
164
|
+
}
|
165
|
+
return rkey;
|
166
|
+
}
|
167
|
+
|
168
|
+
static VALUE ox_locking_intern(Cache c, const char *key, size_t len, const char **keyp) {
|
169
|
+
uint64_t h;
|
170
|
+
Slot *bucket;
|
171
|
+
Slot b;
|
172
|
+
uint64_t old_size;
|
173
|
+
volatile VALUE rkey;
|
174
|
+
|
175
|
+
CACHE_LOCK(c);
|
176
|
+
while (REUSE_MAX < c->rcnt) {
|
177
|
+
if (NULL != (b = c->reuse)) {
|
178
|
+
c->reuse = b->next;
|
179
|
+
free(b);
|
180
|
+
c->rcnt--;
|
181
|
+
} else {
|
182
|
+
// An accounting error occured somewhere so correct it.
|
183
|
+
c->rcnt = 0;
|
184
|
+
}
|
185
|
+
}
|
186
|
+
h = hash_calc((const uint8_t *)key, len);
|
187
|
+
bucket = (Slot *)c->slots + (h & c->mask);
|
188
|
+
for (b = *bucket; NULL != b; b = b->next) {
|
189
|
+
if ((uint8_t)len == b->klen && 0 == strncmp(b->key, key, len)) {
|
190
|
+
b->use_cnt += 4;
|
191
|
+
if (NULL != keyp) {
|
192
|
+
*keyp = b->key;
|
193
|
+
}
|
194
|
+
CACHE_UNLOCK(c);
|
195
|
+
|
196
|
+
return b->val;
|
105
197
|
}
|
106
198
|
}
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
199
|
+
old_size = c->size;
|
200
|
+
// The creation of a new value may trigger a GC which be a problem if the
|
201
|
+
// cache is locked so make sure it is unlocked for the key value creation.
|
202
|
+
if (NULL != (b = c->reuse)) {
|
203
|
+
c->reuse = b->next;
|
204
|
+
c->rcnt--;
|
205
|
+
}
|
206
|
+
CACHE_UNLOCK(c);
|
207
|
+
if (NULL == b) {
|
208
|
+
b = calloc(1, sizeof(struct _slot));
|
209
|
+
}
|
210
|
+
rkey = c->form(key, len);
|
211
|
+
b->hash = h;
|
212
|
+
memcpy(b->key, key, len);
|
213
|
+
b->klen = (uint8_t)len;
|
214
|
+
b->key[len] = '\0';
|
215
|
+
b->val = rkey;
|
216
|
+
b->use_cnt = 16;
|
217
|
+
|
218
|
+
// Lock again to add the new entry.
|
219
|
+
CACHE_LOCK(c);
|
220
|
+
if (old_size != c->size) {
|
221
|
+
h = hash_calc((const uint8_t *)key, len);
|
222
|
+
bucket = (Slot *)c->slots + (h & c->mask);
|
223
|
+
}
|
224
|
+
b->next = *bucket;
|
225
|
+
*bucket = b;
|
226
|
+
c->cnt++; // Don't worry about wrapping. Worse case is the entry is removed and recreated.
|
227
|
+
if (NULL != keyp) {
|
228
|
+
*keyp = b->key;
|
115
229
|
}
|
116
|
-
|
230
|
+
if (REHASH_LIMIT < c->cnt / c->size) {
|
231
|
+
rehash(c);
|
232
|
+
}
|
233
|
+
CACHE_UNLOCK(c);
|
234
|
+
|
235
|
+
return rkey;
|
117
236
|
}
|
118
237
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
238
|
+
Cache ox_cache_create(size_t size, VALUE (*form)(const char *str, size_t len), bool mark, bool locking) {
|
239
|
+
Cache c = calloc(1, sizeof(struct _cache));
|
240
|
+
int shift = 0;
|
241
|
+
|
242
|
+
for (; REHASH_LIMIT < size; size /= 2, shift++) {
|
243
|
+
}
|
244
|
+
if (shift < MIN_SHIFT) {
|
245
|
+
shift = MIN_SHIFT;
|
246
|
+
}
|
247
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
248
|
+
pthread_mutex_init(&c->mutex, NULL);
|
249
|
+
#else
|
250
|
+
c->mutex = rb_mutex_new();
|
251
|
+
#endif
|
252
|
+
c->size = 1 << shift;
|
253
|
+
c->mask = c->size - 1;
|
254
|
+
c->slots = calloc(c->size, sizeof(Slot));
|
255
|
+
c->form = form;
|
256
|
+
c->xrate = 1; // low
|
257
|
+
c->mark = mark;
|
258
|
+
if (locking) {
|
259
|
+
c->intern = ox_locking_intern;
|
260
|
+
} else {
|
261
|
+
c->intern = ox_lockless_intern;
|
262
|
+
}
|
263
|
+
return c;
|
123
264
|
}
|
124
265
|
|
125
|
-
|
126
|
-
|
127
|
-
char indent[256];
|
128
|
-
Cache *cp;
|
129
|
-
unsigned int i;
|
266
|
+
void ox_cache_free(Cache c) {
|
267
|
+
uint64_t i;
|
130
268
|
|
131
|
-
|
132
|
-
|
269
|
+
for (i = 0; i < c->size; i++) {
|
270
|
+
Slot next;
|
271
|
+
Slot s;
|
272
|
+
|
273
|
+
for (s = c->slots[i]; NULL != s; s = next) {
|
274
|
+
next = s->next;
|
275
|
+
free(s);
|
276
|
+
}
|
133
277
|
}
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
278
|
+
free((void *)c->slots);
|
279
|
+
free(c);
|
280
|
+
}
|
281
|
+
|
282
|
+
void ox_cache_mark(Cache c) {
|
283
|
+
uint64_t i;
|
284
|
+
|
285
|
+
#if !HAVE_PTHREAD_MUTEX_INIT
|
286
|
+
rb_gc_mark(c->mutex);
|
287
|
+
#endif
|
288
|
+
if (0 == c->cnt) {
|
289
|
+
return;
|
290
|
+
}
|
291
|
+
for (i = 0; i < c->size; i++) {
|
292
|
+
Slot s;
|
293
|
+
Slot prev = NULL;
|
294
|
+
Slot next;
|
151
295
|
|
152
|
-
|
153
|
-
|
296
|
+
for (s = c->slots[i]; NULL != s; s = next) {
|
297
|
+
next = s->next;
|
298
|
+
if (0 == s->use_cnt) {
|
299
|
+
if (NULL == prev) {
|
300
|
+
c->slots[i] = next;
|
301
|
+
} else {
|
302
|
+
prev->next = next;
|
154
303
|
}
|
155
|
-
|
304
|
+
c->cnt--;
|
305
|
+
s->next = c->reuse;
|
306
|
+
c->reuse = s;
|
307
|
+
c->rcnt++;
|
308
|
+
continue;
|
309
|
+
}
|
310
|
+
switch (c->xrate) {
|
311
|
+
case 0: break;
|
312
|
+
case 2: s->use_cnt -= 2; break;
|
313
|
+
case 3: s->use_cnt /= 2; break;
|
314
|
+
default: s->use_cnt--; break;
|
315
|
+
}
|
316
|
+
if (c->mark) {
|
317
|
+
rb_gc_mark(s->val);
|
318
|
+
}
|
319
|
+
prev = s;
|
320
|
+
}
|
321
|
+
}
|
322
|
+
}
|
323
|
+
|
324
|
+
VALUE
|
325
|
+
ox_cache_intern(Cache c, const char *key, size_t len, const char **keyp) {
|
326
|
+
if (CACHE_MAX_KEY <= len) {
|
327
|
+
if (NULL != keyp) {
|
328
|
+
volatile VALUE rkey = c->form(key, len);
|
329
|
+
|
330
|
+
if (SYMBOL_P(rkey)) {
|
331
|
+
*keyp = rb_id2name(rb_sym2id(rkey));
|
156
332
|
}
|
157
|
-
|
333
|
+
return rkey;
|
158
334
|
}
|
335
|
+
return c->form(key, len);
|
159
336
|
}
|
337
|
+
return c->intern(c, key, len, keyp);
|
160
338
|
}
|
data/ext/ox/cache.h
CHANGED
@@ -1,19 +1,19 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
* All rights reserved.
|
4
|
-
*/
|
1
|
+
// Copyright (c) 2021 Peter Ohler. All rights reserved.
|
2
|
+
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
5
3
|
|
6
4
|
#ifndef OX_CACHE_H
|
7
5
|
#define OX_CACHE_H
|
8
6
|
|
9
|
-
#include
|
7
|
+
#include <ruby.h>
|
8
|
+
#include <stdbool.h>
|
10
9
|
|
11
|
-
|
10
|
+
#define CACHE_MAX_KEY 35
|
12
11
|
|
13
|
-
|
12
|
+
struct _cache;
|
14
13
|
|
15
|
-
extern
|
16
|
-
|
17
|
-
extern void
|
14
|
+
extern struct _cache *ox_cache_create(size_t size, VALUE (*form)(const char *str, size_t len), bool mark, bool locking);
|
15
|
+
extern void ox_cache_free(struct _cache *c);
|
16
|
+
extern void ox_cache_mark(struct _cache *c);
|
17
|
+
extern VALUE ox_cache_intern(struct _cache *c, const char *key, size_t len, const char **keyp);
|
18
18
|
|
19
19
|
#endif /* OX_CACHE_H */
|
data/ext/ox/dump.c
CHANGED
@@ -511,7 +511,7 @@ dump_date(Out out, VALUE obj) {
|
|
511
511
|
static void
|
512
512
|
dump_time_xsd(Out out, VALUE obj) {
|
513
513
|
struct tm *tm;
|
514
|
-
#if
|
514
|
+
#if HAVE_RB_TIME_TIMESPEC
|
515
515
|
struct timespec ts = rb_time_timespec(obj);
|
516
516
|
time_t sec = ts.tv_sec;
|
517
517
|
long nsec = ts.tv_nsec;
|
@@ -528,7 +528,7 @@ dump_time_xsd(Out out, VALUE obj) {
|
|
528
528
|
}
|
529
529
|
/* 2010-07-09T10:47:45.895826+09:00 */
|
530
530
|
tm = localtime(&sec);
|
531
|
-
#if
|
531
|
+
#if HAVE_ST_TM_GMTOFF
|
532
532
|
if (0 > tm->tm_gmtoff) {
|
533
533
|
tzsign = '-';
|
534
534
|
tzhour = (int)(tm->tm_gmtoff / -3600);
|
data/ext/ox/extconf.rb
CHANGED
@@ -33,11 +33,14 @@ CONFIG['warnflags'].slice!(/ -Wdeclaration-after-statement/)
|
|
33
33
|
CONFIG['warnflags'].slice!(/ -Wmissing-noreturn/)
|
34
34
|
|
35
35
|
have_func('rb_time_timespec')
|
36
|
-
have_func('rb_enc_associate')
|
37
|
-
have_func('rb_enc_find')
|
38
36
|
have_func('rb_struct_alloc_noinit')
|
39
37
|
have_func('rb_obj_encoding')
|
40
38
|
have_func('rb_ivar_foreach')
|
39
|
+
have_func('rb_ext_ractor_safe', 'ruby.h')
|
40
|
+
have_func('pthread_mutex_init')
|
41
|
+
have_func('rb_enc_interned_str')
|
42
|
+
have_func('rb_time_nano_new')
|
43
|
+
have_func('index')
|
41
44
|
|
42
45
|
have_header('ruby/st.h')
|
43
46
|
have_header('sys/uio.h')
|