oj 3.12.3 → 3.13.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 125ec67a260b09db65d47add3487d46c55ee805ebaa721d3bf841ef27fe3ade7
4
- data.tar.gz: a1cd38c40217e8c5ffd24f8759ff00f0d6770dcab56a736bd0c4ba52d5f3a03a
3
+ metadata.gz: 659a7b0d5dc0fd786f01d8879cf94549d7ba1c7b893048222579b77455dc1654
4
+ data.tar.gz: 3413e8022bb3b6972a0c91acd63ca1d292bccebb9531fc8fb1f86aecfe675471
5
5
  SHA512:
6
- metadata.gz: 63496098643062caf40131db78e9ef1ccd75f9fd56f32e49538ccb6e005a42dcc86198d202562edc0b149b7ee649492376584d21554423846ac078efec700899
7
- data.tar.gz: 9d619857d1f9f217d5e7c27c8a999013516680de8e28bc835ee2e267e60eee5dacde1a69e2de694d99d8caf21eb7e5c0c5a51ab9407d03b509423af894913985
6
+ metadata.gz: 41123b593024773a786bdb12982820387da83a7dc6e385e2cd40f3a4a8b1779bbc3d2a15b8e9f52e4a69b54c4b086c453e745a33bcf21d7d237e22f1fd9e6b04
7
+ data.tar.gz: 4daa8aadb603184ab90b91dd91a81a74fc1c8bfcb85d77b342ffb8054bd48bda34b94d46990ace8eb07784e4e2221f4a836d304b3a1057bcf6fdb844b89997e5
data/README.md CHANGED
@@ -8,8 +8,7 @@
8
8
 
9
9
  A *fast* JSON parser and Object marshaller as a Ruby gem.
10
10
 
11
- Version 3.0 is out! 3.0 provides better json gem and Rails compatibility. It
12
- also provides additional optimization options.
11
+ Version 3.13 is out with a much faster parser (`Oj::Parser`) and option isolation.
13
12
 
14
13
  ## Using
15
14
 
data/ext/oj/buf.h CHANGED
@@ -19,6 +19,10 @@ inline static void buf_init(Buf buf) {
19
19
  buf->tail = buf->head;
20
20
  }
21
21
 
22
+ inline static void buf_reset(Buf buf) {
23
+ buf->tail = buf->head;
24
+ }
25
+
22
26
  inline static void buf_cleanup(Buf buf) {
23
27
  if (buf->base != buf->head) {
24
28
  xfree(buf->head);
@@ -29,6 +33,11 @@ inline static size_t buf_len(Buf buf) {
29
33
  return buf->tail - buf->head;
30
34
  }
31
35
 
36
+ inline static const char *buf_str(Buf buf) {
37
+ *buf->tail = '\0';
38
+ return buf->head;
39
+ }
40
+
32
41
  inline static void buf_append_string(Buf buf, const char *s, size_t slen) {
33
42
  if (buf->end <= buf->tail + slen) {
34
43
  size_t len = buf->end - buf->head;
data/ext/oj/cache.c ADDED
@@ -0,0 +1,187 @@
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
+ #include "cache.h"
5
+
6
+ #define REHASH_LIMIT 64
7
+ #define MIN_SHIFT 8
8
+
9
+ typedef struct _slot {
10
+ struct _slot *next;
11
+ VALUE val;
12
+ uint32_t hash;
13
+ uint8_t klen;
14
+ char key[CACHE_MAX_KEY];
15
+ } * Slot;
16
+
17
+ typedef struct _cache {
18
+ Slot * slots;
19
+ size_t cnt;
20
+ VALUE (*form)(const char *str, size_t len);
21
+ uint32_t size;
22
+ uint32_t mask;
23
+ bool mark;
24
+ } * Cache;
25
+
26
+ // almost the Murmur hash algorithm
27
+ #define M 0x5bd1e995
28
+ #define C1 0xCC9E2D51
29
+ #define C2 0x1B873593
30
+ #define N 0xE6546B64
31
+
32
+ void cache_set_form(Cache c, VALUE (*form)(const char *str, size_t len)) {
33
+ c->form = form;
34
+ }
35
+
36
+ #if 0
37
+ // For debugging only.
38
+ static void cache_print(Cache c) {
39
+ for (uint32_t i = 0; i < c->size; i++) {
40
+ printf("%4d:", i);
41
+ for (Slot s = c->slots[i]; NULL != s; s = s->next) {
42
+ char buf[40];
43
+ strncpy(buf, s->key, s->klen);
44
+ buf[s->klen] = '\0';
45
+ printf(" %s", buf);
46
+ }
47
+ printf("\n");
48
+ }
49
+ }
50
+ #endif
51
+
52
+ static uint32_t hash_calc(const uint8_t *key, size_t len) {
53
+ const uint8_t *end = key + len;
54
+ const uint8_t *endless = key + (len & 0xFFFFFFFC);
55
+ uint32_t h = (uint32_t)len;
56
+ uint32_t k;
57
+
58
+ while (key < endless) {
59
+ k = (uint32_t)*key++;
60
+ k |= (uint32_t)*key++ << 8;
61
+ k |= (uint32_t)*key++ << 16;
62
+ k |= (uint32_t)*key++ << 24;
63
+
64
+ k *= M;
65
+ k ^= k >> 24;
66
+ h *= M;
67
+ h ^= k * M;
68
+ }
69
+ if (1 < end - key) {
70
+ uint16_t k16 = (uint16_t)*key++;
71
+
72
+ k16 |= (uint16_t)*key++ << 8;
73
+ h ^= k16 << 8;
74
+ }
75
+ if (key < end) {
76
+ h ^= *key;
77
+ }
78
+ h *= M;
79
+ h ^= h >> 13;
80
+ h *= M;
81
+ h ^= h >> 15;
82
+
83
+ return h;
84
+ }
85
+
86
+ Cache cache_create(size_t size, VALUE (*form)(const char *str, size_t len), bool mark) {
87
+ Cache c = ALLOC(struct _cache);
88
+ int shift = 0;
89
+
90
+ for (; REHASH_LIMIT < size; size /= 2, shift++) {
91
+ }
92
+ if (shift < MIN_SHIFT) {
93
+ shift = MIN_SHIFT;
94
+ }
95
+ c->size = 1 << shift;
96
+ c->mask = c->size - 1;
97
+ c->slots = ALLOC_N(Slot, c->size);
98
+ memset(c->slots, 0, sizeof(Slot) * c->size);
99
+ c->form = form;
100
+ c->cnt = 0;
101
+ c->mark = mark;
102
+
103
+ return c;
104
+ }
105
+
106
+ static void rehash(Cache c) {
107
+ uint32_t osize = c->size;
108
+
109
+ c->size = osize * 4;
110
+ c->mask = c->size - 1;
111
+ REALLOC_N(c->slots, Slot, c->size);
112
+ memset(c->slots + osize, 0, sizeof(Slot) * osize * 3);
113
+
114
+ Slot *end = c->slots + osize;
115
+ for (Slot *sp = c->slots; sp < end; sp++) {
116
+ Slot s = *sp;
117
+ Slot next = NULL;
118
+
119
+ *sp = NULL;
120
+ for (; NULL != s; s = next) {
121
+ next = s->next;
122
+
123
+ uint32_t h = s->hash & c->mask;
124
+ Slot * bucket = c->slots + h;
125
+
126
+ s->next = *bucket;
127
+ *bucket = s;
128
+ }
129
+ }
130
+ }
131
+
132
+ void cache_free(Cache c) {
133
+ for (uint32_t i = 0; i < c->size; i++) {
134
+ Slot next;
135
+ for (Slot s = c->slots[i]; NULL != s; s = next) {
136
+ next = s->next;
137
+ xfree(s);
138
+ }
139
+ }
140
+ xfree(c->slots);
141
+ xfree(c);
142
+ }
143
+
144
+ void cache_mark(Cache c) {
145
+ if (c->mark) {
146
+ for (uint32_t i = 0; i < c->size; i++) {
147
+ for (Slot s = c->slots[i]; NULL != s; s = s->next) {
148
+ rb_gc_mark(s->val);
149
+ }
150
+ }
151
+ }
152
+ }
153
+
154
+ VALUE
155
+ cache_intern(Cache c, const char *key, size_t len) {
156
+ if (CACHE_MAX_KEY < len) {
157
+ return c->form(key, len);
158
+ }
159
+ uint32_t h = hash_calc((const uint8_t *)key, len);
160
+ Slot * bucket = c->slots + (h & c->mask);
161
+ Slot b;
162
+ Slot tail = NULL;
163
+
164
+ for (b = *bucket; NULL != b; b = b->next) {
165
+ if ((uint8_t)len == b->klen && 0 == strncmp(b->key, key, len)) {
166
+ return b->val;
167
+ }
168
+ tail = b;
169
+ }
170
+ b = ALLOC(struct _slot);
171
+ b->hash = h;
172
+ b->next = NULL;
173
+ memcpy(b->key, key, len);
174
+ b->klen = (uint8_t)len;
175
+ b->key[len] = '\0';
176
+ b->val = c->form(key, len);
177
+ if (NULL == tail) {
178
+ *bucket = b;
179
+ } else {
180
+ tail->next = b;
181
+ }
182
+ c->cnt++;
183
+ if (REHASH_LIMIT < c->cnt / c->size) {
184
+ rehash(c);
185
+ }
186
+ return b->val;
187
+ }
data/ext/oj/cache.h ADDED
@@ -0,0 +1,20 @@
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 CACHE_H
5
+ #define 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 struct _cache *cache_create(size_t size, VALUE (*form)(const char *str, size_t len), bool mark);
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);
19
+
20
+ #endif /* CACHE_H */
data/ext/oj/compat.c CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  #include "encode.h"
7
7
  #include "err.h"
8
- #include "hash.h"
8
+ #include "intern.h"
9
9
  #include "oj.h"
10
10
  #include "parse.h"
11
11
  #include "resolve.h"
@@ -27,30 +27,16 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
27
27
 
28
28
  if (Qundef == rkey) {
29
29
  if (Yes != pi->options.cache_keys) {
30
- rkey = rb_str_new(key, klen);
31
- rkey = oj_encode(rkey);
32
30
  if (Yes == pi->options.sym_key) {
33
- rkey = rb_str_intern(rkey);
34
- }
35
- } else {
36
- VALUE *slot;
37
-
38
- if (Yes == pi->options.sym_key) {
39
- if (Qnil == (rkey = oj_sym_hash_get(key, klen, &slot))) {
40
- rkey = rb_str_new(key, klen);
41
- rkey = oj_encode(rkey);
42
- rkey = rb_str_intern(rkey);
43
- *slot = rkey;
44
- rb_gc_register_address(slot);
45
- }
31
+ rkey = ID2SYM(rb_intern3(key, klen, oj_utf8_encoding));
46
32
  } else {
47
- if (Qnil == (rkey = oj_str_hash_get(key, klen, &slot))) {
48
- rkey = rb_str_new(key, klen);
49
- rkey = oj_encode(rkey);
50
- *slot = rkey;
51
- rb_gc_register_address(slot);
52
- }
33
+ rkey = rb_str_new(key, klen);
34
+ rkey = oj_encode(rkey);
53
35
  }
36
+ } else if (Yes == pi->options.sym_key) {
37
+ rkey = oj_sym_intern(key, klen);
38
+ } else {
39
+ rkey = oj_str_intern(key, klen);
54
40
  }
55
41
  }
56
42
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
data/ext/oj/custom.c CHANGED
@@ -8,7 +8,7 @@
8
8
  #include "dump.h"
9
9
  #include "encode.h"
10
10
  #include "err.h"
11
- #include "hash.h"
11
+ #include "intern.h"
12
12
  #include "odd.h"
13
13
  #include "oj.h"
14
14
  #include "parse.h"
@@ -31,14 +31,14 @@ static void dump_obj_str(VALUE obj, int depth, Out out) {
31
31
 
32
32
  static void dump_obj_as_str(VALUE obj, int depth, Out out) {
33
33
  volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
34
- const char * str = rb_string_value_ptr((VALUE *)&rstr);
34
+ const char * str = RSTRING_PTR(rstr);
35
35
 
36
36
  oj_dump_cstr(str, RSTRING_LEN(rstr), 0, 0, out);
37
37
  }
38
38
 
39
39
  static void bigdecimal_dump(VALUE obj, int depth, Out out) {
40
40
  volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
41
- const char * str = rb_string_value_ptr((VALUE *)&rstr);
41
+ const char * str = RSTRING_PTR(rstr);
42
42
  int len = (int)RSTRING_LEN(rstr);
43
43
 
44
44
  if (0 == strcasecmp("Infinity", str)) {
@@ -123,7 +123,7 @@ static void date_dump(VALUE obj, int depth, Out out) {
123
123
  case RubyTime:
124
124
  case XmlTime:
125
125
  v = rb_funcall(obj, rb_intern("iso8601"), 0);
126
- oj_dump_cstr(rb_string_value_ptr((VALUE *)&v), (int)RSTRING_LEN(v), 0, 0, out);
126
+ oj_dump_cstr(RSTRING_PTR(v), (int)RSTRING_LEN(v), 0, 0, out);
127
127
  break;
128
128
  case UnixZTime:
129
129
  v = rb_funcall(obj, rb_intern("to_time"), 0);
@@ -420,7 +420,7 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
420
420
  if (Qundef == v || T_STRING != rb_type(v)) {
421
421
  rb_raise(rb_eEncodingError, "Invalid type for raw JSON.\n");
422
422
  } else {
423
- const char *s = rb_string_value_ptr((VALUE *)&v);
423
+ const char *s = RSTRING_PTR(v);
424
424
  int len = (int)RSTRING_LEN(v);
425
425
  const char *name = rb_id2name(*odd->attrs);
426
426
  size_t nlen = strlen(name);
@@ -510,7 +510,7 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
510
510
  if (Yes == out->opts->trace) {
511
511
  oj_trace("to_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
512
512
  }
513
- s = rb_string_value_ptr((VALUE *)&rs);
513
+ s = RSTRING_PTR(rs);
514
514
  len = (int)RSTRING_LEN(rs);
515
515
 
516
516
  assure_size(out, len + 1);
@@ -537,7 +537,7 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
537
537
  if (aj == obj) {
538
538
  volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
539
539
 
540
- oj_dump_cstr(rb_string_value_ptr((VALUE *)&rstr),
540
+ oj_dump_cstr(RSTRING_PTR(rstr),
541
541
  (int)RSTRING_LEN(rstr),
542
542
  false,
543
543
  false,
@@ -835,7 +835,7 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
835
835
  if (ma != Qnil) {
836
836
  volatile VALUE s = rb_sym_to_s(rb_ary_entry(ma, i));
837
837
 
838
- name = rb_string_value_ptr((VALUE *)&s);
838
+ name = RSTRING_PTR(s);
839
839
  len = (int)RSTRING_LEN(s);
840
840
  } else {
841
841
  len = snprintf(num_id, sizeof(num_id), "%d", i);
@@ -959,12 +959,13 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
959
959
  volatile VALUE rstr = rb_str_new(str, len);
960
960
 
961
961
  if (Qundef == rkey) {
962
- rkey = rb_str_new(key, klen);
963
- rstr = oj_encode(rstr);
964
- rkey = oj_encode(rkey);
965
962
  if (Yes == pi->options.sym_key) {
966
- rkey = rb_str_intern(rkey);
963
+ rkey = ID2SYM(rb_intern3(key, klen, oj_utf8_encoding));
964
+ } else {
965
+ rkey = rb_str_new(key, klen);
966
+ rkey = oj_encode(rkey);
967
967
  }
968
+ rstr = oj_encode(rstr);
968
969
  }
969
970
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
970
971
  VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
data/ext/oj/debug.c ADDED
@@ -0,0 +1,131 @@
1
+ // Copyright (c) 2021, Peter Ohler, All rights reserved.
2
+
3
+ #include "parser.h"
4
+
5
+ static void add_null(struct _ojParser *p) {
6
+ switch (p->stack[p->depth]) {
7
+ case TOP_FUN: printf("*** add_null at top\n"); break;
8
+ case ARRAY_FUN: printf("*** add_null to array\n"); break;
9
+ case OBJECT_FUN: printf("*** add_null with '%s'\n", buf_str(&p->key)); break;
10
+ }
11
+ }
12
+
13
+ static void add_true(struct _ojParser *p) {
14
+ switch (p->stack[p->depth]) {
15
+ case TOP_FUN: printf("*** add_true at top\n"); break;
16
+ case ARRAY_FUN: printf("*** add_true to array\n"); break;
17
+ case OBJECT_FUN: printf("*** add_true with '%s'\n", buf_str(&p->key)); break;
18
+ }
19
+ }
20
+
21
+ static void add_false(struct _ojParser *p) {
22
+ switch (p->stack[p->depth]) {
23
+ case TOP_FUN: printf("*** add_false at top\n"); break;
24
+ case ARRAY_FUN: printf("*** add_false to array\n"); break;
25
+ case OBJECT_FUN: printf("*** add_false with '%s'\n", buf_str(&p->key)); break;
26
+ }
27
+ }
28
+
29
+ static void add_int(struct _ojParser *p) {
30
+ switch (p->stack[p->depth]) {
31
+ case TOP_FUN: printf("*** add_int %lld at top\n", (long long)p->num.fixnum); break;
32
+ case ARRAY_FUN: printf("*** add_int %lld to array\n", (long long)p->num.fixnum); break;
33
+ case OBJECT_FUN:
34
+ printf("*** add_int %lld with '%s'\n", (long long)p->num.fixnum, buf_str(&p->key));
35
+ break;
36
+ }
37
+ }
38
+
39
+ static void add_float(struct _ojParser *p) {
40
+ switch (p->stack[p->depth]) {
41
+ case TOP_FUN: printf("*** add_float %Lf at top\n", p->num.dub); break;
42
+ case ARRAY_FUN: printf("*** add_float %Lf to array\n", p->num.dub); break;
43
+ case OBJECT_FUN: printf("*** add_float %Lf with '%s'\n", p->num.dub, buf_str(&p->key)); break;
44
+ }
45
+ }
46
+
47
+ static void add_big(struct _ojParser *p) {
48
+ switch (p->stack[p->depth]) {
49
+ case TOP_FUN: printf("*** add_big %s at top\n", buf_str(&p->buf)); break;
50
+ case ARRAY_FUN: printf("*** add_big %s to array\n", buf_str(&p->buf)); break;
51
+ case OBJECT_FUN:
52
+ printf("*** add_big %s with '%s'\n", buf_str(&p->buf), buf_str(&p->key));
53
+ break;
54
+ }
55
+ }
56
+
57
+ static void add_str(struct _ojParser *p) {
58
+ switch (p->stack[p->depth]) {
59
+ case TOP_FUN: printf("*** add_str '%s' at top\n", buf_str(&p->buf)); break;
60
+ case ARRAY_FUN: printf("*** add_str '%s' to array\n", buf_str(&p->buf)); break;
61
+ case OBJECT_FUN:
62
+ printf("*** add_str '%s' with '%s'\n", buf_str(&p->buf), buf_str(&p->key));
63
+ break;
64
+ }
65
+ }
66
+
67
+ static void open_array(struct _ojParser *p) {
68
+ switch (p->stack[p->depth]) {
69
+ case TOP_FUN: printf("*** open_array at top\n"); break;
70
+ case ARRAY_FUN: printf("*** open_array to array\n"); break;
71
+ case OBJECT_FUN: printf("*** open_array with '%s'\n", buf_str(&p->key)); break;
72
+ }
73
+ }
74
+
75
+ static void close_array(struct _ojParser *p) {
76
+ printf("*** close_array\n");
77
+ }
78
+
79
+ static void open_object(struct _ojParser *p) {
80
+ switch (p->stack[p->depth]) {
81
+ case TOP_FUN: printf("*** open_object at top\n"); break;
82
+ case ARRAY_FUN: printf("*** open_object to array\n"); break;
83
+ case OBJECT_FUN: printf("*** open_object with '%s'\n", buf_str(&p->key)); break;
84
+ }
85
+ }
86
+
87
+ static void close_object(struct _ojParser *p) {
88
+ printf("*** close_object\n");
89
+ }
90
+
91
+ static VALUE option(ojParser p, const char *key, VALUE value) {
92
+ rb_raise(rb_eArgError, "%s is not an option for the debug delegate", key);
93
+ return Qnil;
94
+ }
95
+
96
+ static VALUE result(struct _ojParser *p) {
97
+ return Qnil;
98
+ }
99
+
100
+ static void start(struct _ojParser *p) {
101
+ printf("*** start\n");
102
+ }
103
+
104
+ static void dfree(struct _ojParser *p) {
105
+ }
106
+
107
+ static void mark(struct _ojParser *p) {
108
+ }
109
+
110
+ void oj_set_parser_debug(ojParser p) {
111
+ Funcs end = p->funcs + 3;
112
+
113
+ for (Funcs f = p->funcs; f < end; f++) {
114
+ f->add_null = add_null;
115
+ f->add_true = add_true;
116
+ f->add_false = add_false;
117
+ f->add_int = add_int;
118
+ f->add_float = add_float;
119
+ f->add_big = add_big;
120
+ f->add_str = add_str;
121
+ f->open_array = open_array;
122
+ f->close_array = close_array;
123
+ f->open_object = open_object;
124
+ f->close_object = close_object;
125
+ }
126
+ p->option = option;
127
+ p->result = result;
128
+ p->free = dfree;
129
+ p->mark = mark;
130
+ p->start = start;
131
+ }