ox 2.14.7 → 2.14.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d34e2f569a6f870bc46c1ed8bf2e39e860f63ee8da1ad8aec0897e11904d8444
4
- data.tar.gz: 90049302c1ba8e443a28aa1e69115db636ae86517695c6aab278fc8f7dcc8590
3
+ metadata.gz: e6a58bfa91298fd0da2d02538dfe039bb5a426edfba8e4f245d8bd91b7388cbb
4
+ data.tar.gz: 77765350035814045329fa94935cd3de29975eaefbaef1666e4ffe29269338d8
5
5
  SHA512:
6
- metadata.gz: 2f5f3e9ef3f7172a7c25b43b00a92c57858e052e592ec7265077dabf1ab8280888953639232ca06e088e4524287e4f264ac3ddfe017dfde9d5c5b8dc5bd847a8
7
- data.tar.gz: 35ebe783817b228b82eaacfcbdc7805de7327ad77fcf34f605baf7fab53103b79f5bd893c13b9a1a8f74f2e529b241ae805a21f487993db229e03b817f78aabf
6
+ metadata.gz: 9ac7c0bd9c0ac54cd033f432a0e14cd29b265b078459025c889ca08a907703d1aa202aee9ccae792e87a47b783bacf3044e62bedfc0c25090457dd5035ee2ee3
7
+ data.tar.gz: 73fc0775f561ca3290b6f6a875d0c8076d4434a642f0c0e7321952ed8b1adc655aa0f880916e1fde5f02f0d29b5c7cc57de871e4e58c869540c219bd46d75403
data/CHANGELOG.md CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  All changes to the Ox gem are documented here. Releases follow semantic versioning.
4
4
 
5
+ ## [2.14.10] - 2022-03-10
6
+
7
+ ### Fixed
8
+
9
+ - Writing strings over 16K to a file with builder no longer causes a crash.
10
+
11
+ ## [2.14.9] - 2022-02-11
12
+
13
+ ### Fixed
14
+
15
+ - Fixed the `\r` replacement with `\n` with the SAX parser according to https://www.w3.org/TR/2008/REC-xml-20081126/#sec-line-ends.
16
+
17
+ ## [2.14.8] - 2022-02-09
18
+
19
+ ### Fixed
20
+
21
+ - Renamed internal functions to avoid linking issues where Oj and Ox function names collided.
22
+
5
23
  ## [2.14.7] - 2022-02-03
6
24
 
7
25
  ### Fixed
data/ext/ox/buf.h CHANGED
@@ -86,8 +86,16 @@ buf_append_string(Buf buf, const char *s, size_t slen) {
86
86
 
87
87
  if (len != (size_t)write(buf->fd, buf->head, len)) {
88
88
  buf->err = true;
89
+ return;
89
90
  }
90
91
  buf->tail = buf->head;
92
+ if (sizeof(buf->base) <= slen) {
93
+ if (slen != (size_t)write(buf->fd, s, slen)) {
94
+ buf->err = true;
95
+ return;
96
+ }
97
+ return;
98
+ }
91
99
  } else {
92
100
  size_t len = buf->end - buf->head;
93
101
  size_t toff = buf->tail - buf->head;
data/ext/ox/cache.c CHANGED
@@ -28,7 +28,7 @@
28
28
  #define M 0x5bd1e995
29
29
 
30
30
  typedef struct _slot {
31
- struct _slot * next;
31
+ struct _slot *next;
32
32
  VALUE val;
33
33
  uint64_t hash;
34
34
  volatile uint32_t use_cnt;
@@ -37,7 +37,7 @@ typedef struct _slot {
37
37
  } * Slot;
38
38
 
39
39
  typedef struct _cache {
40
- volatile Slot * slots;
40
+ volatile Slot *slots;
41
41
  volatile size_t cnt;
42
42
  VALUE (*form)(const char *str, size_t len);
43
43
  uint64_t size;
@@ -54,10 +54,6 @@ typedef struct _cache {
54
54
  bool mark;
55
55
  } * Cache;
56
56
 
57
- void cache_set_form(Cache c, VALUE (*form)(const char *str, size_t len)) {
58
- c->form = form;
59
- }
60
-
61
57
  static uint64_t hash_calc(const uint8_t *key, size_t len) {
62
58
  const uint8_t *end = key + len;
63
59
  const uint8_t *endless = key + (len & 0xFFFFFFFC);
@@ -94,8 +90,8 @@ static uint64_t hash_calc(const uint8_t *key, size_t len) {
94
90
 
95
91
  static void rehash(Cache c) {
96
92
  uint64_t osize;
97
- Slot * end;
98
- Slot * sp;
93
+ Slot *end;
94
+ Slot *sp;
99
95
 
100
96
  osize = c->size;
101
97
  c->size = osize * 4;
@@ -110,7 +106,7 @@ static void rehash(Cache c) {
110
106
  *sp = NULL;
111
107
  for (; NULL != s; s = next) {
112
108
  uint64_t h = s->hash & c->mask;
113
- Slot * bucket = (Slot *)c->slots + h;
109
+ Slot *bucket = (Slot *)c->slots + h;
114
110
 
115
111
  next = s->next;
116
112
  s->next = *bucket;
@@ -119,9 +115,9 @@ static void rehash(Cache c) {
119
115
  }
120
116
  }
121
117
 
122
- static VALUE lockless_intern(Cache c, const char *key, size_t len, const char **keyp) {
118
+ static VALUE ox_lockless_intern(Cache c, const char *key, size_t len, const char **keyp) {
123
119
  uint64_t h = hash_calc((const uint8_t *)key, len);
124
- Slot * bucket = (Slot *)c->slots + (h & c->mask);
120
+ Slot *bucket = (Slot *)c->slots + (h & c->mask);
125
121
  Slot b;
126
122
  volatile VALUE rkey;
127
123
 
@@ -169,9 +165,9 @@ static VALUE lockless_intern(Cache c, const char *key, size_t len, const char **
169
165
  return rkey;
170
166
  }
171
167
 
172
- static VALUE locking_intern(Cache c, const char *key, size_t len, const char **keyp) {
168
+ static VALUE ox_locking_intern(Cache c, const char *key, size_t len, const char **keyp) {
173
169
  uint64_t h;
174
- Slot * bucket;
170
+ Slot *bucket;
175
171
  Slot b;
176
172
  uint64_t old_size;
177
173
  volatile VALUE rkey;
@@ -239,10 +235,7 @@ static VALUE locking_intern(Cache c, const char *key, size_t len, const char **k
239
235
  return rkey;
240
236
  }
241
237
 
242
- Cache cache_create(size_t size,
243
- VALUE (*form)(const char *str, size_t len),
244
- bool mark,
245
- bool locking) {
238
+ Cache ox_cache_create(size_t size, VALUE (*form)(const char *str, size_t len), bool mark, bool locking) {
246
239
  Cache c = calloc(1, sizeof(struct _cache));
247
240
  int shift = 0;
248
241
 
@@ -263,18 +256,14 @@ Cache cache_create(size_t size,
263
256
  c->xrate = 1; // low
264
257
  c->mark = mark;
265
258
  if (locking) {
266
- c->intern = locking_intern;
259
+ c->intern = ox_locking_intern;
267
260
  } else {
268
- c->intern = lockless_intern;
261
+ c->intern = ox_lockless_intern;
269
262
  }
270
263
  return c;
271
264
  }
272
265
 
273
- void cache_set_expunge_rate(Cache c, int rate) {
274
- c->xrate = (uint8_t)rate;
275
- }
276
-
277
- void cache_free(Cache c) {
266
+ void ox_cache_free(Cache c) {
278
267
  uint64_t i;
279
268
 
280
269
  for (i = 0; i < c->size; i++) {
@@ -290,7 +279,7 @@ void cache_free(Cache c) {
290
279
  free(c);
291
280
  }
292
281
 
293
- void cache_mark(Cache c) {
282
+ void ox_cache_mark(Cache c) {
294
283
  uint64_t i;
295
284
 
296
285
  #if !HAVE_PTHREAD_MUTEX_INIT
@@ -333,7 +322,7 @@ void cache_mark(Cache c) {
333
322
  }
334
323
 
335
324
  VALUE
336
- cache_intern(Cache c, const char *key, size_t len, const char **keyp) {
325
+ ox_cache_intern(Cache c, const char *key, size_t len, const char **keyp) {
337
326
  if (CACHE_MAX_KEY <= len) {
338
327
  if (NULL != keyp) {
339
328
  volatile VALUE rkey = c->form(key, len);
data/ext/ox/cache.h CHANGED
@@ -1,8 +1,8 @@
1
1
  // Copyright (c) 2021 Peter Ohler. All rights reserved.
2
2
  // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
3
 
4
- #ifndef CACHE_H
5
- #define CACHE_H
4
+ #ifndef OX_CACHE_H
5
+ #define OX_CACHE_H
6
6
 
7
7
  #include <ruby.h>
8
8
  #include <stdbool.h>
@@ -11,11 +11,9 @@
11
11
 
12
12
  struct _cache;
13
13
 
14
- extern struct _cache *cache_create(size_t size, VALUE (*form)(const char *str, size_t len), bool mark, bool locking);
15
- extern void cache_free(struct _cache *c);
16
- extern void cache_mark(struct _cache *c);
17
- extern void cache_set_form(struct _cache *c, VALUE (*form)(const char *str, size_t len));
18
- extern VALUE cache_intern(struct _cache *c, const char *key, size_t len, const char **keyp);
19
- extern void cache_set_expunge_rate(struct _cache *c, int rate);
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);
20
18
 
21
- #endif /* CACHE_H */
19
+ #endif /* OX_CACHE_H */
data/ext/ox/intern.c CHANGED
@@ -8,17 +8,19 @@
8
8
  #include "cache.h"
9
9
  #include "ox.h"
10
10
 
11
- static struct _cache *str_cache = NULL;
12
- static VALUE str_cache_obj;
11
+ // These are statics but in an attempt to stop the cross linking or maybe
12
+ // something in Ruby they all have been given an ox prefix.
13
+ static struct _cache *ox_str_cache = NULL;
14
+ static VALUE ox_str_cache_obj;
13
15
 
14
- static struct _cache *sym_cache = NULL;
15
- static VALUE sym_cache_obj;
16
+ static struct _cache *ox_sym_cache = NULL;
17
+ static VALUE ox_sym_cache_obj;
16
18
 
17
- static struct _cache *attr_cache = NULL;
18
- static VALUE attr_cache_obj;
19
+ static struct _cache *ox_attr_cache = NULL;
20
+ static VALUE ox_attr_cache_obj;
19
21
 
20
- static struct _cache *id_cache = NULL;
21
- static VALUE id_cache_obj;
22
+ static struct _cache *ox_id_cache = NULL;
23
+ static VALUE ox_id_cache_obj;
22
24
 
23
25
  static VALUE form_str(const char *str, size_t len) {
24
26
  return rb_str_freeze(rb_utf8_str_new(str, len));
@@ -67,21 +69,21 @@ static VALUE form_id(const char *str, size_t len) {
67
69
  void ox_hash_init() {
68
70
  VALUE cache_class = rb_define_class_under(Ox, "Cache", rb_cObject);
69
71
 
70
- str_cache = cache_create(0, form_str, true, false);
71
- str_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, str_cache);
72
- rb_gc_register_address(&str_cache_obj);
72
+ ox_str_cache = ox_cache_create(0, form_str, true, false);
73
+ ox_str_cache_obj = Data_Wrap_Struct(cache_class, ox_cache_mark, ox_cache_free, ox_str_cache);
74
+ rb_gc_register_address(&ox_str_cache_obj);
73
75
 
74
- sym_cache = cache_create(0, form_sym, true, false);
75
- sym_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, sym_cache);
76
- rb_gc_register_address(&sym_cache_obj);
76
+ ox_sym_cache = ox_cache_create(0, form_sym, true, false);
77
+ ox_sym_cache_obj = Data_Wrap_Struct(cache_class, ox_cache_mark, ox_cache_free, ox_sym_cache);
78
+ rb_gc_register_address(&ox_sym_cache_obj);
77
79
 
78
- attr_cache = cache_create(0, form_attr, false, false);
79
- attr_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, attr_cache);
80
- rb_gc_register_address(&attr_cache_obj);
80
+ ox_attr_cache = ox_cache_create(0, form_attr, false, false);
81
+ ox_attr_cache_obj = Data_Wrap_Struct(cache_class, ox_cache_mark, ox_cache_free, ox_attr_cache);
82
+ rb_gc_register_address(&ox_attr_cache_obj);
81
83
 
82
- id_cache = cache_create(0, form_id, false, false);
83
- id_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, id_cache);
84
- rb_gc_register_address(&id_cache_obj);
84
+ ox_id_cache = ox_cache_create(0, form_id, false, false);
85
+ ox_id_cache_obj = Data_Wrap_Struct(cache_class, ox_cache_mark, ox_cache_free, ox_id_cache);
86
+ rb_gc_register_address(&ox_id_cache_obj);
85
87
  }
86
88
 
87
89
  VALUE
@@ -92,21 +94,21 @@ ox_str_intern(const char *key, size_t len, const char **keyp) {
92
94
  #if HAVE_RB_ENC_INTERNED_STR && 0
93
95
  return rb_enc_interned_str(key, len, rb_utf8_encoding());
94
96
  #else
95
- return cache_intern(str_cache, key, len, keyp);
97
+ return ox_cache_intern(ox_str_cache, key, len, keyp);
96
98
  #endif
97
99
  }
98
100
 
99
101
  VALUE
100
102
  ox_sym_intern(const char *key, size_t len, const char **keyp) {
101
- return cache_intern(sym_cache, key, len, keyp);
103
+ return ox_cache_intern(ox_sym_cache, key, len, keyp);
102
104
  }
103
105
 
104
106
  ID ox_attr_intern(const char *key, size_t len) {
105
- return cache_intern(attr_cache, key, len, NULL);
107
+ return ox_cache_intern(ox_attr_cache, key, len, NULL);
106
108
  }
107
109
 
108
110
  ID ox_id_intern(const char *key, size_t len) {
109
- return cache_intern(id_cache, key, len, NULL);
111
+ return ox_cache_intern(ox_id_cache, key, len, NULL);
110
112
  }
111
113
 
112
114
  char *ox_strndup(const char *s, size_t len) {
@@ -118,13 +120,6 @@ char *ox_strndup(const char *s, size_t len) {
118
120
  return d;
119
121
  }
120
122
 
121
- void intern_cleanup() {
122
- cache_free(str_cache);
123
- cache_free(sym_cache);
124
- cache_free(attr_cache);
125
- cache_free(id_cache);
126
- }
127
-
128
123
  VALUE
129
124
  ox_utf8_name(const char *str, size_t len, rb_encoding *encoding, const char **strp) {
130
125
  return ox_str_intern(str, len, strp);
data/ext/ox/obj_load.c CHANGED
@@ -12,6 +12,7 @@
12
12
 
13
13
  #include "ruby.h"
14
14
  #include "ruby/encoding.h"
15
+
15
16
  #include "base64.h"
16
17
  #include "ox.h"
17
18
  #include "intern.h"
@@ -152,7 +153,7 @@ classname2class(const char *name, PInfo pi, VALUE base_class) {
152
153
  VALUE *slot;
153
154
  VALUE clas;
154
155
 
155
- if (Qundef == (clas = ox_cache_get(ox_class_cache, name, &slot, 0))) {
156
+ if (Qundef == (clas = slot_cache_get(ox_class_cache, name, &slot, 0))) {
156
157
  char class_name[1024];
157
158
  char *s;
158
159
  const char *n = name;
data/ext/ox/ox.c CHANGED
@@ -107,9 +107,7 @@ VALUE ox_struct_class;
107
107
  VALUE ox_syntax_error_class;
108
108
  VALUE ox_time_class;
109
109
 
110
- Cache ox_symbol_cache = 0;
111
- Cache ox_class_cache = 0;
112
- Cache ox_attr_cache = 0;
110
+ SlotCache ox_class_cache = 0;
113
111
 
114
112
  static VALUE abort_sym;
115
113
  static VALUE active_sym;
@@ -1646,9 +1644,7 @@ void Init_ox() {
1646
1644
  rb_gc_register_address(&ox_time_class);
1647
1645
  rb_gc_register_address(&ox_version_sym);
1648
1646
 
1649
- ox_cache_new(&ox_symbol_cache);
1650
- ox_cache_new(&ox_class_cache);
1651
- ox_cache_new(&ox_attr_cache);
1647
+ slot_cache_new(&ox_class_cache);
1652
1648
 
1653
1649
  ox_sax_define();
1654
1650
  ox_hash_init();
data/ext/ox/ox.h CHANGED
@@ -28,7 +28,7 @@ extern "C" {
28
28
  #include "attr.h"
29
29
  #include "err.h"
30
30
  #include "helper.h"
31
- #include "oxcache.h"
31
+ #include "slotcache.h"
32
32
  #include "type.h"
33
33
 
34
34
  #define raise_error(msg, xml, current) _ox_raise_error(msg, xml, current, __FILE__, __LINE__)
@@ -238,9 +238,7 @@ extern VALUE ox_raw_clas;
238
238
  extern VALUE ox_doctype_clas;
239
239
  extern VALUE ox_cdata_clas;
240
240
 
241
- extern Cache ox_symbol_cache;
242
- extern Cache ox_class_cache;
243
- extern Cache ox_attr_cache;
241
+ extern SlotCache ox_class_cache;
244
242
 
245
243
  extern void ox_init_builder(VALUE ox);
246
244
 
data/ext/ox/parse.c CHANGED
@@ -108,7 +108,7 @@ static void fix_newlines(char *buf) {
108
108
  if ('\n' == *(s + 1)) {
109
109
  continue;
110
110
  }
111
- *s = '\n';
111
+ *d = '\n';
112
112
  } else if (d < s) {
113
113
  *d = *s;
114
114
  }
data/ext/ox/sax.c CHANGED
@@ -307,8 +307,8 @@ static void sax_drive_init(SaxDrive dr, VALUE handler, VALUE io, SaxOptions opti
307
307
  dr->encoding = rb_enc_find(ox_default_options.encoding);
308
308
  }
309
309
  dr->utf8 = (NULL == dr->encoding || rb_utf8_encoding() == dr->encoding);
310
- if (NULL == dr->encoding || rb_utf8_encoding() == dr->encoding) { // UTF-8
311
- dr->get_name = dr->options.symbolize ? ox_utf8_sym : ox_utf8_name; // TBD UTF8 sym?
310
+ if (NULL == dr->encoding || rb_utf8_encoding() == dr->encoding) { // UTF-8
311
+ dr->get_name = dr->options.symbolize ? ox_utf8_sym : ox_utf8_name; // TBD UTF8 sym?
312
312
  } else {
313
313
  dr->get_name = dr->options.symbolize ? ox_enc_sym : ox_enc_name;
314
314
  }
@@ -334,7 +334,7 @@ static char skipBOM(SaxDrive dr) {
334
334
  if (0xEF == (uint8_t)c) { /* only UTF8 is supported */
335
335
  if (0xBB == (uint8_t)buf_get(&dr->buf) && 0xBF == (uint8_t)buf_get(&dr->buf)) {
336
336
  dr->encoding = ox_utf8_encoding;
337
- c = buf_get(&dr->buf);
337
+ c = buf_get(&dr->buf);
338
338
  } else {
339
339
  ox_sax_drive_error(dr, BAD_BOM "invalid BOM or a binary file.");
340
340
  c = '\0';
@@ -1217,7 +1217,7 @@ static char read_attrs(SaxDrive dr, char c, char termc, char term2, int is_xml,
1217
1217
  attr_value = dr->buf.str;
1218
1218
  if (is_encoding) {
1219
1219
  dr->encoding = rb_enc_find(dr->buf.str);
1220
- is_encoding = 0;
1220
+ is_encoding = 0;
1221
1221
  }
1222
1222
  }
1223
1223
  if (0 >= dr->blocked && (NULL == h || ActiveOverlay == h->overlay || NestOverlay == h->overlay)) {
@@ -1368,7 +1368,8 @@ int ox_sax_collapse_special(SaxDrive dr, char *str, long pos, long line, long co
1368
1368
  char *b = str;
1369
1369
 
1370
1370
  while ('\0' != *s) {
1371
- if ('&' == *s) {
1371
+ switch (*s) {
1372
+ case '&': {
1372
1373
  int c = 0;
1373
1374
  char *end;
1374
1375
 
@@ -1458,13 +1459,25 @@ int ox_sax_collapse_special(SaxDrive dr, char *str, long pos, long line, long co
1458
1459
  }
1459
1460
  *b++ = (char)c;
1460
1461
  col++;
1461
- } else {
1462
+ break;
1463
+ }
1464
+ case '\r':
1465
+ s++;
1462
1466
  if ('\n' == *s) {
1463
- line++;
1464
- col = 0;
1465
- }
1467
+ continue;
1468
+ }
1469
+ line++;
1470
+ col = 1;
1471
+ *b++ = '\n';
1472
+ break;
1473
+ case '\n':
1474
+ line++;
1475
+ col = 0;
1476
+ // fall through
1477
+ default:
1466
1478
  col++;
1467
1479
  *b++ = *s++;
1480
+ break;
1468
1481
  }
1469
1482
  }
1470
1483
  *b = '\0';
@@ -0,0 +1,158 @@
1
+ /* slotcache.c
2
+ * Copyright (c) 2011, Peter Ohler
3
+ * All rights reserved.
4
+ */
5
+
6
+ #include "slotcache.h"
7
+
8
+ #include <errno.h>
9
+ #include <stdarg.h>
10
+ #include <stdint.h>
11
+ #include <stdio.h>
12
+ #include <stdlib.h>
13
+ #include <string.h>
14
+ #include <strings.h>
15
+
16
+ struct _slotCache {
17
+ /* The key is a length byte followed by the key as a string. If the key is longer than 254 characters then the
18
+ length is 255. The key can be for a premature value and in that case the length byte is greater than the length
19
+ of the key. */
20
+ char *key;
21
+ VALUE value;
22
+ struct _slotCache *slots[16];
23
+ };
24
+
25
+ static void slot_print(SlotCache cache, unsigned int depth);
26
+
27
+ static char *form_key(const char *s) {
28
+ size_t len = strlen(s);
29
+ char *d = ALLOC_N(char, len + 2);
30
+
31
+ *(uint8_t *)d = (255 <= len) ? 255 : len;
32
+ memcpy(d + 1, s, len + 1);
33
+
34
+ return d;
35
+ }
36
+
37
+ void slot_cache_new(SlotCache *cache) {
38
+ *cache = ALLOC(struct _slotCache);
39
+ (*cache)->key = 0;
40
+ (*cache)->value = Qundef;
41
+ memset((*cache)->slots, 0, sizeof((*cache)->slots));
42
+ }
43
+
44
+ VALUE
45
+ slot_cache_get(SlotCache cache, const char *key, VALUE **slot, const char **keyp) {
46
+ unsigned char *k = (unsigned char *)key;
47
+ SlotCache *cp;
48
+
49
+ for (; '\0' != *k; k++) {
50
+ cp = cache->slots + (unsigned int)(*k >> 4); /* upper 4 bits */
51
+ if (0 == *cp) {
52
+ slot_cache_new(cp);
53
+ }
54
+ cache = *cp;
55
+ cp = cache->slots + (unsigned int)(*k & 0x0F); /* lower 4 bits */
56
+ if (0 == *cp) { /* nothing on this tree so set key and value as a premature key/value pair */
57
+ slot_cache_new(cp);
58
+ cache = *cp;
59
+ cache->key = form_key(key);
60
+ break;
61
+ } else {
62
+ int depth = (int)(k - (unsigned char *)key + 1);
63
+
64
+ cache = *cp;
65
+
66
+ if ('\0' == *(k + 1)) { /* exact match */
67
+ if (0 == cache->key) { /* nothing in this spot so take it */
68
+ cache->key = form_key(key);
69
+ break;
70
+ } else if ((depth == *cache->key || 255 < depth) && 0 == strcmp(key, cache->key + 1)) { /* match */
71
+ break;
72
+ } else { /* have to move the current premature key/value deeper */
73
+ unsigned char *ck = (unsigned char *)(cache->key + depth + 1);
74
+ SlotCache orig = *cp;
75
+
76
+ cp = (*cp)->slots + (*ck >> 4);
77
+ slot_cache_new(cp);
78
+ cp = (*cp)->slots + (*ck & 0x0F);
79
+ slot_cache_new(cp);
80
+ (*cp)->key = cache->key;
81
+ (*cp)->value = cache->value;
82
+ orig->key = form_key(key);
83
+ orig->value = Qundef;
84
+ }
85
+ } else { /* not exact match but on the path */
86
+ if (0 != cache->key) { /* there is a key/value here already */
87
+ if (depth == *cache->key || (255 <= depth && 0 == strncmp(cache->key, key, depth) &&
88
+ '\0' == cache->key[depth])) { /* key belongs here */
89
+ continue;
90
+ } else {
91
+ unsigned char *ck = (unsigned char *)(cache->key + depth + 1);
92
+ SlotCache orig = *cp;
93
+
94
+ cp = (*cp)->slots + (*ck >> 4);
95
+ slot_cache_new(cp);
96
+ cp = (*cp)->slots + (*ck & 0x0F);
97
+ slot_cache_new(cp);
98
+ (*cp)->key = cache->key;
99
+ (*cp)->value = cache->value;
100
+ orig->key = 0;
101
+ orig->value = Qundef;
102
+ }
103
+ }
104
+ }
105
+ }
106
+ }
107
+ *slot = &cache->value;
108
+ if (0 != keyp) {
109
+ if (0 == cache->key) {
110
+ printf("*** Error: failed to set the key for '%s'\n", key);
111
+ *keyp = 0;
112
+ } else {
113
+ *keyp = cache->key + 1;
114
+ }
115
+ }
116
+ return cache->value;
117
+ }
118
+
119
+ void slot_cache_print(SlotCache cache) {
120
+ /*printf("-------------------------------------------\n");*/
121
+ slot_print(cache, 0);
122
+ }
123
+
124
+ static void slot_print(SlotCache c, unsigned int depth) {
125
+ char indent[256];
126
+ SlotCache *cp;
127
+ unsigned int i;
128
+
129
+ if (sizeof(indent) - 1 < depth) {
130
+ depth = ((int)sizeof(indent) - 1);
131
+ }
132
+ memset(indent, ' ', depth);
133
+ indent[depth] = '\0';
134
+ for (i = 0, cp = c->slots; i < 16; i++, cp++) {
135
+ if (0 == *cp) {
136
+ /*printf("%s%02u:\n", indent, i);*/
137
+ } else {
138
+ if (0 == (*cp)->key && Qundef == (*cp)->value) {
139
+ printf("%s%02u:\n", indent, i);
140
+ } else {
141
+ const char *vs;
142
+ const char *clas;
143
+
144
+ if (Qundef == (*cp)->value) {
145
+ vs = "undefined";
146
+ clas = "";
147
+ } else {
148
+ VALUE rs = rb_funcall2((*cp)->value, rb_intern("to_s"), 0, 0);
149
+
150
+ vs = StringValuePtr(rs);
151
+ clas = rb_class2name(rb_obj_class((*cp)->value));
152
+ }
153
+ printf("%s%02u: %s = %s (%s)\n", indent, i, (*cp)->key, vs, clas);
154
+ }
155
+ slot_print(*cp, depth + 2);
156
+ }
157
+ }
158
+ }
@@ -0,0 +1,19 @@
1
+ /* slotcache.h
2
+ * Copyright (c) 2011, Peter Ohler
3
+ * All rights reserved.
4
+ */
5
+
6
+ #ifndef SLOT_CACHE_H
7
+ #define SLOT_CACHE_H
8
+
9
+ #include "ruby.h"
10
+
11
+ typedef struct _slotCache *SlotCache;
12
+
13
+ extern void slot_cache_new(SlotCache *cache);
14
+
15
+ extern VALUE slot_cache_get(SlotCache cache, const char *key, VALUE **slot, const char **keyp);
16
+
17
+ extern void slot_cache_print(SlotCache cache);
18
+
19
+ #endif /* SLOT_CACHE_H */
data/lib/ox/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Ox
3
3
  # Current version of the module.
4
- VERSION = '2.14.7'
4
+ VERSION = '2.14.10'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ox
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.14.7
4
+ version: 2.14.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Ohler
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-04 00:00:00.000000000 Z
11
+ date: 2022-03-10 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: "A fast XML parser and object serializer that uses only standard C lib.\n\nOptimized
14
14
  XML (Ox), as the name implies was written to provide speed optimized\nXML handling.
@@ -46,8 +46,6 @@ files:
46
46
  - ext/ox/obj_load.c
47
47
  - ext/ox/ox.c
48
48
  - ext/ox/ox.h
49
- - ext/ox/oxcache.c
50
- - ext/ox/oxcache.h
51
49
  - ext/ox/parse.c
52
50
  - ext/ox/sax.c
53
51
  - ext/ox/sax.h
@@ -57,6 +55,8 @@ files:
57
55
  - ext/ox/sax_hint.c
58
56
  - ext/ox/sax_hint.h
59
57
  - ext/ox/sax_stack.h
58
+ - ext/ox/slotcache.c
59
+ - ext/ox/slotcache.h
60
60
  - ext/ox/special.c
61
61
  - ext/ox/special.h
62
62
  - ext/ox/type.h
data/ext/ox/oxcache.c DELETED
@@ -1,160 +0,0 @@
1
- /* cache.c
2
- * Copyright (c) 2011, Peter Ohler
3
- * All rights reserved.
4
- */
5
-
6
- #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
-
14
- #include "oxcache.h"
15
-
16
- struct _cache {
17
- /* The key is a length byte followed by the key as a string. If the key is longer than 254 characters then the
18
- length is 255. The key can be for a premature value and in that case the length byte is greater than the length
19
- of the key. */
20
- char *key;
21
- VALUE value;
22
- struct _cache *slots[16];
23
- };
24
-
25
- static void slot_print(Cache cache, unsigned int depth);
26
-
27
- static char* form_key(const char *s) {
28
- size_t len = strlen(s);
29
- char *d = ALLOC_N(char, len + 2);
30
-
31
- *(uint8_t*)d = (255 <= len) ? 255 : len;
32
- memcpy(d + 1, s, len + 1);
33
-
34
- return d;
35
- }
36
-
37
- void
38
- ox_cache_new(Cache *cache) {
39
- *cache = ALLOC(struct _cache);
40
- (*cache)->key = 0;
41
- (*cache)->value = Qundef;
42
- memset((*cache)->slots, 0, sizeof((*cache)->slots));
43
- }
44
-
45
- VALUE
46
- ox_cache_get(Cache cache, const char *key, VALUE **slot, const char **keyp) {
47
- unsigned char *k = (unsigned char*)key;
48
- Cache *cp;
49
-
50
- for (; '\0' != *k; k++) {
51
- cp = cache->slots + (unsigned int)(*k >> 4); /* upper 4 bits */
52
- if (0 == *cp) {
53
- ox_cache_new(cp);
54
- }
55
- cache = *cp;
56
- cp = cache->slots + (unsigned int)(*k & 0x0F); /* lower 4 bits */
57
- if (0 == *cp) { /* nothing on this tree so set key and value as a premature key/value pair */
58
- ox_cache_new(cp);
59
- cache = *cp;
60
- cache->key = form_key(key);
61
- break;
62
- } else {
63
- int depth = (int)(k - (unsigned char*)key + 1);
64
-
65
- cache = *cp;
66
-
67
- if ('\0' == *(k + 1)) { /* exact match */
68
- if (0 == cache->key) { /* nothing in this spot so take it */
69
- cache->key = form_key(key);
70
- break;
71
- } else if ((depth == *cache->key || 255 < depth) && 0 == strcmp(key, cache->key + 1)) { /* match */
72
- break;
73
- } else { /* have to move the current premature key/value deeper */
74
- unsigned char *ck = (unsigned char*)(cache->key + depth + 1);
75
- Cache orig = *cp;
76
-
77
- cp = (*cp)->slots + (*ck >> 4);
78
- ox_cache_new(cp);
79
- cp = (*cp)->slots + (*ck & 0x0F);
80
- ox_cache_new(cp);
81
- (*cp)->key = cache->key;
82
- (*cp)->value = cache->value;
83
- orig->key = form_key(key);
84
- orig->value = Qundef;
85
- }
86
- } else { /* not exact match but on the path */
87
- if (0 != cache->key) { /* there is a key/value here already */
88
- if (depth == *cache->key || (255 <= depth && 0 == strncmp(cache->key, key, depth) && '\0' == cache->key[depth])) { /* key belongs here */
89
- continue;
90
- } else {
91
- unsigned char *ck = (unsigned char*)(cache->key + depth + 1);
92
- Cache orig = *cp;
93
-
94
- cp = (*cp)->slots + (*ck >> 4);
95
- ox_cache_new(cp);
96
- cp = (*cp)->slots + (*ck & 0x0F);
97
- ox_cache_new(cp);
98
- (*cp)->key = cache->key;
99
- (*cp)->value = cache->value;
100
- orig->key = 0;
101
- orig->value = Qundef;
102
- }
103
- }
104
- }
105
- }
106
- }
107
- *slot = &cache->value;
108
- if (0 != keyp) {
109
- if (0 == cache->key) {
110
- printf("*** Error: failed to set the key for '%s'\n", key);
111
- *keyp = 0;
112
- } else {
113
- *keyp = cache->key + 1;
114
- }
115
- }
116
- return cache->value;
117
- }
118
-
119
- void
120
- ox_cache_print(Cache cache) {
121
- /*printf("-------------------------------------------\n");*/
122
- slot_print(cache, 0);
123
- }
124
-
125
- static void
126
- slot_print(Cache c, unsigned int depth) {
127
- char indent[256];
128
- Cache *cp;
129
- unsigned int i;
130
-
131
- if (sizeof(indent) - 1 < depth) {
132
- depth = ((int)sizeof(indent) - 1);
133
- }
134
- memset(indent, ' ', depth);
135
- indent[depth] = '\0';
136
- for (i = 0, cp = c->slots; i < 16; i++, cp++) {
137
- if (0 == *cp) {
138
- /*printf("%s%02u:\n", indent, i);*/
139
- } else {
140
- if (0 == (*cp)->key && Qundef == (*cp)->value) {
141
- printf("%s%02u:\n", indent, i);
142
- } else {
143
- const char *vs;
144
- const char *clas;
145
-
146
- if (Qundef == (*cp)->value) {
147
- vs = "undefined";
148
- clas = "";
149
- } else {
150
- VALUE rs = rb_funcall2((*cp)->value, rb_intern("to_s"), 0, 0);
151
-
152
- vs = StringValuePtr(rs);
153
- clas = rb_class2name(rb_obj_class((*cp)->value));
154
- }
155
- printf("%s%02u: %s = %s (%s)\n", indent, i, (*cp)->key, vs, clas);
156
- }
157
- slot_print(*cp, depth + 2);
158
- }
159
- }
160
- }
data/ext/ox/oxcache.h DELETED
@@ -1,19 +0,0 @@
1
- /* cache.h
2
- * Copyright (c) 2011, Peter Ohler
3
- * All rights reserved.
4
- */
5
-
6
- #ifndef OX_CACHE_H
7
- #define OX_CACHE_H
8
-
9
- #include "ruby.h"
10
-
11
- typedef struct _cache *Cache;
12
-
13
- extern void ox_cache_new(Cache *cache);
14
-
15
- extern VALUE ox_cache_get(Cache cache, const char *key, VALUE **slot, const char **keyp);
16
-
17
- extern void ox_cache_print(Cache cache);
18
-
19
- #endif /* OX_CACHE_H */