ox-bundlecachetest 2.14.23

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.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +751 -0
  3. data/LICENSE +21 -0
  4. data/README.md +351 -0
  5. data/ext/ox/attr.h +78 -0
  6. data/ext/ox/base64.c +105 -0
  7. data/ext/ox/base64.h +18 -0
  8. data/ext/ox/buf.h +162 -0
  9. data/ext/ox/builder.c +948 -0
  10. data/ext/ox/cache.c +351 -0
  11. data/ext/ox/cache.h +21 -0
  12. data/ext/ox/cache8.c +106 -0
  13. data/ext/ox/cache8.h +23 -0
  14. data/ext/ox/dump.c +1260 -0
  15. data/ext/ox/err.c +46 -0
  16. data/ext/ox/err.h +36 -0
  17. data/ext/ox/extconf.rb +47 -0
  18. data/ext/ox/gen_load.c +342 -0
  19. data/ext/ox/hash_load.c +309 -0
  20. data/ext/ox/helper.h +84 -0
  21. data/ext/ox/intern.c +157 -0
  22. data/ext/ox/intern.h +25 -0
  23. data/ext/ox/obj_load.c +809 -0
  24. data/ext/ox/ox.c +1649 -0
  25. data/ext/ox/ox.h +245 -0
  26. data/ext/ox/parse.c +1197 -0
  27. data/ext/ox/sax.c +1570 -0
  28. data/ext/ox/sax.h +69 -0
  29. data/ext/ox/sax_as.c +270 -0
  30. data/ext/ox/sax_buf.c +209 -0
  31. data/ext/ox/sax_buf.h +204 -0
  32. data/ext/ox/sax_hint.c +207 -0
  33. data/ext/ox/sax_hint.h +40 -0
  34. data/ext/ox/sax_stack.h +113 -0
  35. data/ext/ox/slotcache.c +158 -0
  36. data/ext/ox/slotcache.h +19 -0
  37. data/ext/ox/special.c +390 -0
  38. data/ext/ox/special.h +14 -0
  39. data/ext/ox/type.h +39 -0
  40. data/lib/ox/bag.rb +103 -0
  41. data/lib/ox/cdata.rb +10 -0
  42. data/lib/ox/comment.rb +11 -0
  43. data/lib/ox/doctype.rb +11 -0
  44. data/lib/ox/document.rb +28 -0
  45. data/lib/ox/element.rb +464 -0
  46. data/lib/ox/error.rb +25 -0
  47. data/lib/ox/hasattrs.rb +54 -0
  48. data/lib/ox/instruct.rb +34 -0
  49. data/lib/ox/node.rb +23 -0
  50. data/lib/ox/raw.rb +12 -0
  51. data/lib/ox/sax.rb +97 -0
  52. data/lib/ox/version.rb +4 -0
  53. data/lib/ox/xmlrpc_adapter.rb +33 -0
  54. data/lib/ox.rb +79 -0
  55. metadata +128 -0
data/ext/ox/cache.c ADDED
@@ -0,0 +1,351 @@
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.
3
+
4
+ #if HAVE_PTHREAD_MUTEX_INIT
5
+ #include <pthread.h>
6
+ #endif
7
+ #include <stdlib.h>
8
+
9
+ #include "cache.h"
10
+
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.
14
+
15
+ #define REHASH_LIMIT 4
16
+ #define MIN_SHIFT 8
17
+ #define REUSE_MAX 8192
18
+
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
26
+
27
+ // almost the Murmur hash algorithm
28
+ #define M 0x5bd1e995
29
+
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
+ const rb_data_type_t ox_cache_type = {
58
+ "Ox/Cache",
59
+ {
60
+ ox_cache_mark,
61
+ ox_cache_free,
62
+ NULL,
63
+ },
64
+ 0,
65
+ 0,
66
+ };
67
+
68
+ static uint64_t hash_calc(const uint8_t *key, size_t len) {
69
+ const uint8_t *end = key + len;
70
+ const uint8_t *endless = key + (len & 0xFFFFFFFC);
71
+ uint64_t h = (uint64_t)len;
72
+ uint64_t k;
73
+
74
+ while (key < endless) {
75
+ k = (uint64_t)*key++;
76
+ k |= (uint64_t)*key++ << 8;
77
+ k |= (uint64_t)*key++ << 16;
78
+ k |= (uint64_t)*key++ << 24;
79
+
80
+ k *= M;
81
+ k ^= k >> 24;
82
+ h *= M;
83
+ h ^= k * M;
84
+ }
85
+ if (1 < end - key) {
86
+ uint16_t k16 = (uint16_t)*key++;
87
+
88
+ k16 |= (uint16_t)*key++ << 8;
89
+ h ^= k16 << 8;
90
+ }
91
+ if (key < end) {
92
+ h ^= *key;
93
+ }
94
+ h *= M;
95
+ h ^= h >> 13;
96
+ h *= M;
97
+ h ^= h >> 15;
98
+
99
+ return h;
100
+ }
101
+
102
+ static void rehash(Cache c) {
103
+ uint64_t osize;
104
+ Slot *end;
105
+ Slot *sp;
106
+
107
+ osize = c->size;
108
+ c->size = osize * 4;
109
+ c->mask = c->size - 1;
110
+ c->slots = realloc((void *)c->slots, sizeof(Slot) * c->size);
111
+ memset((Slot *)c->slots + osize, 0, sizeof(Slot) * osize * 3);
112
+ end = (Slot *)c->slots + osize;
113
+ for (sp = (Slot *)c->slots; sp < end; sp++) {
114
+ Slot s = *sp;
115
+ Slot next = NULL;
116
+
117
+ *sp = NULL;
118
+ for (; NULL != s; s = next) {
119
+ uint64_t h = s->hash & c->mask;
120
+ Slot *bucket = (Slot *)c->slots + h;
121
+
122
+ next = s->next;
123
+ s->next = *bucket;
124
+ *bucket = s;
125
+ }
126
+ }
127
+ }
128
+
129
+ static VALUE ox_lockless_intern(Cache c, const char *key, size_t len, const char **keyp) {
130
+ uint64_t h = hash_calc((const uint8_t *)key, len);
131
+ Slot *bucket = (Slot *)c->slots + (h & c->mask);
132
+ Slot b;
133
+ volatile VALUE rkey;
134
+
135
+ while (REUSE_MAX < c->rcnt) {
136
+ if (NULL != (b = c->reuse)) {
137
+ c->reuse = b->next;
138
+ free(b);
139
+ c->rcnt--;
140
+ } else {
141
+ // An accounting error occured somewhere so correct it.
142
+ c->rcnt = 0;
143
+ }
144
+ }
145
+ for (b = *bucket; NULL != b; b = b->next) {
146
+ if ((uint8_t)len == b->klen && 0 == strncmp(b->key, key, len)) {
147
+ b->use_cnt += 16;
148
+ if (NULL != keyp) {
149
+ *keyp = b->key;
150
+ }
151
+ return b->val;
152
+ }
153
+ }
154
+ rkey = c->form(key, len);
155
+ if (NULL == (b = c->reuse)) {
156
+ b = calloc(1, sizeof(struct _slot));
157
+ } else {
158
+ c->reuse = b->next;
159
+ c->rcnt--;
160
+ }
161
+ b->hash = h;
162
+ memcpy(b->key, key, len);
163
+ b->klen = (uint8_t)len;
164
+ b->key[len] = '\0';
165
+ b->val = rkey;
166
+ b->use_cnt = 4;
167
+ b->next = *bucket;
168
+ *bucket = b;
169
+ c->cnt++; // Don't worry about wrapping. Worse case is the entry is removed and recreated.
170
+ if (NULL != keyp) {
171
+ *keyp = b->key;
172
+ }
173
+ if (REHASH_LIMIT < c->cnt / c->size) {
174
+ rehash(c);
175
+ }
176
+ return rkey;
177
+ }
178
+
179
+ static VALUE ox_locking_intern(Cache c, const char *key, size_t len, const char **keyp) {
180
+ uint64_t h;
181
+ Slot *bucket;
182
+ Slot b;
183
+ uint64_t old_size;
184
+ volatile VALUE rkey;
185
+
186
+ CACHE_LOCK(c);
187
+ while (REUSE_MAX < c->rcnt) {
188
+ if (NULL != (b = c->reuse)) {
189
+ c->reuse = b->next;
190
+ free(b);
191
+ c->rcnt--;
192
+ } else {
193
+ // An accounting error occured somewhere so correct it.
194
+ c->rcnt = 0;
195
+ }
196
+ }
197
+ h = hash_calc((const uint8_t *)key, len);
198
+ bucket = (Slot *)c->slots + (h & c->mask);
199
+ for (b = *bucket; NULL != b; b = b->next) {
200
+ if ((uint8_t)len == b->klen && 0 == strncmp(b->key, key, len)) {
201
+ b->use_cnt += 4;
202
+ if (NULL != keyp) {
203
+ *keyp = b->key;
204
+ }
205
+ CACHE_UNLOCK(c);
206
+
207
+ return b->val;
208
+ }
209
+ }
210
+ old_size = c->size;
211
+ // The creation of a new value may trigger a GC which be a problem if the
212
+ // cache is locked so make sure it is unlocked for the key value creation.
213
+ if (NULL != (b = c->reuse)) {
214
+ c->reuse = b->next;
215
+ c->rcnt--;
216
+ }
217
+ CACHE_UNLOCK(c);
218
+ if (NULL == b) {
219
+ b = calloc(1, sizeof(struct _slot));
220
+ }
221
+ rkey = c->form(key, len);
222
+ b->hash = h;
223
+ memcpy(b->key, key, len);
224
+ b->klen = (uint8_t)len;
225
+ b->key[len] = '\0';
226
+ b->val = rkey;
227
+ b->use_cnt = 16;
228
+
229
+ // Lock again to add the new entry.
230
+ CACHE_LOCK(c);
231
+ if (old_size != c->size) {
232
+ h = hash_calc((const uint8_t *)key, len);
233
+ bucket = (Slot *)c->slots + (h & c->mask);
234
+ }
235
+ b->next = *bucket;
236
+ *bucket = b;
237
+ c->cnt++; // Don't worry about wrapping. Worse case is the entry is removed and recreated.
238
+ if (NULL != keyp) {
239
+ *keyp = b->key;
240
+ }
241
+ if (REHASH_LIMIT < c->cnt / c->size) {
242
+ rehash(c);
243
+ }
244
+ CACHE_UNLOCK(c);
245
+
246
+ return rkey;
247
+ }
248
+
249
+ Cache ox_cache_create(size_t size, VALUE (*form)(const char *str, size_t len), bool mark, bool locking) {
250
+ Cache c = calloc(1, sizeof(struct _cache));
251
+ int shift = 0;
252
+
253
+ for (; REHASH_LIMIT < size; size /= 2, shift++) {
254
+ }
255
+ if (shift < MIN_SHIFT) {
256
+ shift = MIN_SHIFT;
257
+ }
258
+ #if HAVE_PTHREAD_MUTEX_INIT
259
+ pthread_mutex_init(&c->mutex, NULL);
260
+ #else
261
+ c->mutex = rb_mutex_new();
262
+ #endif
263
+ c->size = 1 << shift;
264
+ c->mask = c->size - 1;
265
+ c->slots = calloc(c->size, sizeof(Slot));
266
+ c->form = form;
267
+ c->xrate = 1; // low
268
+ c->mark = mark;
269
+ if (locking) {
270
+ c->intern = ox_locking_intern;
271
+ } else {
272
+ c->intern = ox_lockless_intern;
273
+ }
274
+ return c;
275
+ }
276
+
277
+ void ox_cache_free(void *ptr) {
278
+ Cache c = (Cache)ptr;
279
+ uint64_t i;
280
+
281
+ for (i = 0; i < c->size; i++) {
282
+ Slot next;
283
+ Slot s;
284
+
285
+ for (s = c->slots[i]; NULL != s; s = next) {
286
+ next = s->next;
287
+ free(s);
288
+ }
289
+ }
290
+ free((void *)c->slots);
291
+ free(c);
292
+ }
293
+
294
+ void ox_cache_mark(void *ptr) {
295
+ Cache c = (Cache)ptr;
296
+ uint64_t i;
297
+
298
+ #if !HAVE_PTHREAD_MUTEX_INIT
299
+ rb_gc_mark(c->mutex);
300
+ #endif
301
+ if (0 == c->cnt) {
302
+ return;
303
+ }
304
+ for (i = 0; i < c->size; i++) {
305
+ Slot s;
306
+ Slot prev = NULL;
307
+ Slot next;
308
+
309
+ for (s = c->slots[i]; NULL != s; s = next) {
310
+ next = s->next;
311
+ if (0 == s->use_cnt) {
312
+ if (NULL == prev) {
313
+ c->slots[i] = next;
314
+ } else {
315
+ prev->next = next;
316
+ }
317
+ c->cnt--;
318
+ s->next = c->reuse;
319
+ c->reuse = s;
320
+ c->rcnt++;
321
+ continue;
322
+ }
323
+ switch (c->xrate) {
324
+ case 0: break;
325
+ case 2: s->use_cnt -= 2; break;
326
+ case 3: s->use_cnt /= 2; break;
327
+ default: s->use_cnt--; break;
328
+ }
329
+ if (c->mark) {
330
+ rb_gc_mark(s->val);
331
+ }
332
+ prev = s;
333
+ }
334
+ }
335
+ }
336
+
337
+ VALUE
338
+ ox_cache_intern(Cache c, const char *key, size_t len, const char **keyp) {
339
+ if (CACHE_MAX_KEY <= len) {
340
+ if (NULL != keyp) {
341
+ volatile VALUE rkey = c->form(key, len);
342
+
343
+ if (SYMBOL_P(rkey)) {
344
+ *keyp = rb_id2name(rb_sym2id(rkey));
345
+ }
346
+ return rkey;
347
+ }
348
+ return c->form(key, len);
349
+ }
350
+ return c->intern(c, key, len, keyp);
351
+ }
data/ext/ox/cache.h ADDED
@@ -0,0 +1,21 @@
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.
3
+
4
+ #ifndef OX_CACHE_H
5
+ #define OX_CACHE_H
6
+
7
+ #include <ruby.h>
8
+ #include <stdbool.h>
9
+
10
+ #define CACHE_MAX_KEY 35
11
+
12
+ struct _cache;
13
+
14
+ extern const rb_data_type_t ox_cache_type;
15
+
16
+ extern struct _cache *ox_cache_create(size_t size, VALUE (*form)(const char *str, size_t len), bool mark, bool locking);
17
+ extern void ox_cache_free(void *ptr);
18
+ extern void ox_cache_mark(void *ptr);
19
+ extern VALUE ox_cache_intern(struct _cache *c, const char *key, size_t len, const char **keyp);
20
+
21
+ #endif /* OX_CACHE_H */
data/ext/ox/cache8.c ADDED
@@ -0,0 +1,106 @@
1
+ /* cache8.h
2
+ * Copyright (c) 2011, Peter Ohler
3
+ * All rights reserved.
4
+ */
5
+
6
+ #include "cache8.h"
7
+
8
+ #include <errno.h>
9
+ #include <stdarg.h>
10
+ #include <stdio.h>
11
+ #include <stdlib.h>
12
+ #include <string.h>
13
+
14
+ #include "ruby.h"
15
+
16
+ #define BITS 4
17
+ #define MASK 0x000000000000000FULL
18
+ #define SLOT_CNT 16
19
+ #define DEPTH 16
20
+
21
+ typedef union {
22
+ struct _cache8 *child;
23
+ slot_t value;
24
+ } Bucket;
25
+
26
+ struct _cache8 {
27
+ Bucket buckets[SLOT_CNT];
28
+ };
29
+
30
+ static void cache8_delete(Cache8 cache, int depth);
31
+ // static void slot_print(Cache8 cache, sid_t key, unsigned int depth);
32
+
33
+ void ox_cache8_new(Cache8 *cache) {
34
+ Bucket *b;
35
+ int i;
36
+
37
+ *cache = ALLOC(struct _cache8);
38
+ for (i = SLOT_CNT, b = (*cache)->buckets; 0 < i; i--, b++) {
39
+ b->value = 0;
40
+ }
41
+ }
42
+
43
+ void ox_cache8_delete(Cache8 cache) {
44
+ cache8_delete(cache, 0);
45
+ }
46
+
47
+ static void cache8_delete(Cache8 cache, int depth) {
48
+ Bucket *b;
49
+ unsigned int i;
50
+
51
+ for (i = 0, b = cache->buckets; i < SLOT_CNT; i++, b++) {
52
+ if (0 != b->child) {
53
+ if (DEPTH - 1 != depth) {
54
+ cache8_delete(b->child, depth + 1);
55
+ }
56
+ }
57
+ }
58
+ xfree(cache);
59
+ }
60
+
61
+ slot_t ox_cache8_get(Cache8 cache, sid_t key, slot_t **slot) {
62
+ Bucket *b;
63
+ int i;
64
+ sid_t k8 = (sid_t)key;
65
+ sid_t k;
66
+
67
+ for (i = 64 - BITS; 0 < i; i -= BITS) {
68
+ k = (k8 >> i) & MASK;
69
+ b = cache->buckets + k;
70
+ if (0 == b->child) {
71
+ ox_cache8_new(&b->child);
72
+ }
73
+ cache = b->child;
74
+ }
75
+ *slot = &(cache->buckets + (k8 & MASK))->value;
76
+
77
+ return **slot;
78
+ }
79
+
80
+ #if 0
81
+ void
82
+ ox_cache8_print(Cache8 cache) {
83
+ //printf("-------------------------------------------\n");
84
+ slot_print(cache, 0, 0);
85
+ }
86
+
87
+ static void
88
+ slot_print(Cache8 c, sid_t key, unsigned int depth) {
89
+ Bucket *b;
90
+ unsigned int i;
91
+ sid_t k8 = (sid_t)key;
92
+ sid_t k;
93
+
94
+ for (i = 0, b = c->buckets; i < SLOT_CNT; i++, b++) {
95
+ if (0 != b->child) {
96
+ k = (k8 << BITS) | i;
97
+ //printf("*** key: 0x%016llx depth: %u i: %u\n", k, depth, i);
98
+ if (DEPTH - 1 == depth) {
99
+ printf("0x%016llx: %4llu\n", (unsigned long long)k, (unsigned long long)b->value);
100
+ } else {
101
+ slot_print(b->child, k, depth + 1);
102
+ }
103
+ }
104
+ }
105
+ }
106
+ #endif
data/ext/ox/cache8.h ADDED
@@ -0,0 +1,23 @@
1
+ /* cache8.h
2
+ * Copyright (c) 2011, Peter Ohler
3
+ * All rights reserved.
4
+ */
5
+
6
+ #ifndef OX_CACHE8_H
7
+ #define OX_CACHE8_H
8
+
9
+ #include "ruby.h"
10
+ #include "stdint.h"
11
+
12
+ typedef struct _cache8 *Cache8;
13
+ typedef uint64_t slot_t;
14
+ typedef uint64_t sid_t;
15
+
16
+ extern void ox_cache8_new(Cache8 *cache);
17
+ extern void ox_cache8_delete(Cache8 cache);
18
+
19
+ extern slot_t ox_cache8_get(Cache8 cache, sid_t key, slot_t **slot);
20
+
21
+ // extern void ox_cache8_print(Cache8 cache);
22
+
23
+ #endif /* OX_CACHE8_H */