oj 3.12.1 → 3.13.1

Sign up to get free protection for your applications and to get access to all the features.
data/ext/oj/parser.h ADDED
@@ -0,0 +1,90 @@
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 OJ_PARSER_H
5
+ #define OJ_PARSER_H
6
+
7
+ #include <stdbool.h>
8
+ #include <ruby.h>
9
+
10
+ #include "buf.h"
11
+
12
+ #define TOP_FUN 0
13
+ #define ARRAY_FUN 1
14
+ #define OBJECT_FUN 2
15
+
16
+ typedef uint8_t byte;
17
+
18
+ typedef enum {
19
+ OJ_NONE = '\0',
20
+ OJ_NULL = 'n',
21
+ OJ_TRUE = 't',
22
+ OJ_FALSE = 'f',
23
+ OJ_INT = 'i',
24
+ OJ_DECIMAL = 'd',
25
+ OJ_BIG = 'b', // indicates parser buf is used
26
+ OJ_STRING = 's',
27
+ OJ_OBJECT = 'o',
28
+ OJ_ARRAY = 'a',
29
+ } ojType;
30
+
31
+ typedef struct _num {
32
+ long double dub;
33
+ int64_t fixnum; // holds all digits
34
+ uint32_t len;
35
+ int16_t div; // 10^div
36
+ int16_t exp;
37
+ uint8_t shift; // shift of fixnum to get decimal
38
+ bool neg;
39
+ bool exp_neg;
40
+ // for numbers as strings, reuse buf
41
+ } * Num;
42
+
43
+ struct _ojParser;
44
+
45
+ typedef struct _funcs {
46
+ void (*add_null)(struct _ojParser *p);
47
+ void (*add_true)(struct _ojParser *p);
48
+ void (*add_false)(struct _ojParser *p);
49
+ void (*add_int)(struct _ojParser *p);
50
+ void (*add_float)(struct _ojParser *p);
51
+ void (*add_big)(struct _ojParser *p);
52
+ void (*add_str)(struct _ojParser *p);
53
+ void (*open_array)(struct _ojParser *p);
54
+ void (*close_array)(struct _ojParser *p);
55
+ void (*open_object)(struct _ojParser *p);
56
+ void (*close_object)(struct _ojParser *p);
57
+ } * Funcs;
58
+
59
+ typedef struct _ojParser {
60
+ const char * map;
61
+ const char * next_map;
62
+ int depth;
63
+ unsigned char stack[1024];
64
+
65
+ // value data
66
+ struct _num num;
67
+ struct _buf key;
68
+ struct _buf buf;
69
+
70
+ struct _funcs funcs[3]; // indexed by XXX_FUN defines
71
+
72
+ void (*start)(struct _ojParser *p);
73
+ VALUE (*option)(struct _ojParser *p, const char *key, VALUE value);
74
+ VALUE (*result)(struct _ojParser *p);
75
+ void (*free)(struct _ojParser *p);
76
+ void (*mark)(struct _ojParser *p);
77
+
78
+ void *ctx;
79
+ VALUE reader;
80
+
81
+ char token[8];
82
+ long line;
83
+ long col;
84
+ int ri;
85
+ uint32_t ucode;
86
+ ojType type; // valType
87
+ bool just_one;
88
+ } * ojParser;
89
+
90
+ #endif /* OJ_PARSER_H */
data/ext/oj/rails.c CHANGED
@@ -157,9 +157,9 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
157
157
  assure_size(out, 2);
158
158
  *out->cur++ = '{';
159
159
  for (i = 0; i < cnt; i++) {
160
- volatile VALUE s = rb_sym_to_s(rb_ary_entry(ma, i));
160
+ volatile VALUE s = rb_sym2str(rb_ary_entry(ma, i));
161
161
 
162
- name = rb_string_value_ptr((VALUE *)&s);
162
+ name = RSTRING_PTR(s);
163
163
  len = (int)RSTRING_LEN(s);
164
164
  assure_size(out, size + sep_len + 6);
165
165
  if (0 < i) {
@@ -202,7 +202,7 @@ static void dump_enumerable(VALUE obj, int depth, Out out, bool as_ok) {
202
202
 
203
203
  static void dump_bigdecimal(VALUE obj, int depth, Out out, bool as_ok) {
204
204
  volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
205
- const char * str = rb_string_value_ptr((VALUE *)&rstr);
205
+ const char * str = RSTRING_PTR(rstr);
206
206
 
207
207
  if ('I' == *str || 'N' == *str || ('-' == *str && 'I' == str[1])) {
208
208
  oj_dump_nil(Qnil, depth, out, false);
@@ -355,7 +355,7 @@ static void dump_timewithzone(VALUE obj, int depth, Out out, bool as_ok) {
355
355
  static void dump_to_s(VALUE obj, int depth, Out out, bool as_ok) {
356
356
  volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
357
357
 
358
- oj_dump_cstr(rb_string_value_ptr((VALUE *)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
358
+ oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
359
359
  }
360
360
 
361
361
  static ID parameters_id = 0;
@@ -1224,7 +1224,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1224
1224
  } else {
1225
1225
  volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
1226
1226
 
1227
- strcpy(buf, rb_string_value_ptr((VALUE *)&rstr));
1227
+ strcpy(buf, RSTRING_PTR(rstr));
1228
1228
  cnt = (int)RSTRING_LEN(rstr);
1229
1229
  }
1230
1230
  }
data/ext/oj/resolve.c CHANGED
@@ -9,7 +9,7 @@
9
9
  #endif
10
10
 
11
11
  #include "err.h"
12
- #include "hash.h"
12
+ #include "intern.h"
13
13
  #include "oj.h"
14
14
  #include "parse.h"
15
15
 
@@ -66,28 +66,10 @@ resolve_classpath(ParseInfo pi, const char *name, size_t len, int auto_define, V
66
66
 
67
67
  VALUE
68
68
  oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class) {
69
- VALUE clas;
70
- VALUE *slot;
71
-
72
69
  if (No == pi->options.class_cache) {
73
70
  return resolve_classpath(pi, name, len, auto_define, error_class);
74
71
  }
75
- #ifdef HAVE_PTHREAD_MUTEX_INIT
76
- pthread_mutex_lock(&oj_cache_mutex);
77
- #else
78
- rb_mutex_lock(oj_cache_mutex);
79
- #endif
80
- if (Qnil == (clas = oj_class_hash_get(name, len, &slot))) {
81
- if (Qundef != (clas = resolve_classpath(pi, name, len, auto_define, error_class))) {
82
- *slot = clas;
83
- }
84
- }
85
- #ifdef HAVE_PTHREAD_MUTEX_INIT
86
- pthread_mutex_unlock(&oj_cache_mutex);
87
- #else
88
- rb_mutex_unlock(oj_cache_mutex);
89
- #endif
90
- return clas;
72
+ return oj_class_intern(name, len, true, pi, auto_define, error_class);
91
73
  }
92
74
 
93
75
  VALUE
data/ext/oj/saj2.c ADDED
@@ -0,0 +1,346 @@
1
+ // Copyright (c) 2021, Peter Ohler, All rights reserved.
2
+
3
+ #include "cache.h"
4
+ #include "oj.h"
5
+ #include "parser.h"
6
+
7
+ typedef struct _delegate {
8
+ VALUE handler;
9
+ VALUE * keys;
10
+ VALUE * tail;
11
+ size_t klen;
12
+ struct _cache *str_cache;
13
+ uint8_t cache_str;
14
+ bool cache_keys;
15
+ bool thread_safe;
16
+ } * Delegate;
17
+
18
+ static VALUE get_key(ojParser p) {
19
+ Delegate d = (Delegate)p->ctx;
20
+ const char * key = buf_str(&p->key);
21
+ size_t len = buf_len(&p->key);
22
+ volatile VALUE rkey;
23
+
24
+ if (d->cache_keys) {
25
+ rkey = cache_intern(d->str_cache, key, len);
26
+ } else {
27
+ rkey = rb_utf8_str_new(key, len);
28
+ }
29
+ return rkey;
30
+ }
31
+
32
+ static void push_key(Delegate d, VALUE key) {
33
+ if (d->klen <= (size_t)(d->tail - d->keys)) {
34
+ size_t off = d->tail - d->keys;
35
+
36
+ d->klen += d->klen / 2;
37
+ REALLOC_N(d->keys, VALUE, d->klen);
38
+ d->tail = d->keys + off;
39
+ }
40
+ *d->tail = key;
41
+ d->tail++;
42
+ }
43
+
44
+ static void noop(ojParser p) {
45
+ }
46
+
47
+ static void open_object(ojParser p) {
48
+ rb_funcall(((Delegate)p->ctx)->handler, oj_hash_start_id, 1, Qnil);
49
+ }
50
+
51
+ static void open_object_key(ojParser p) {
52
+ Delegate d = (Delegate)p->ctx;
53
+ volatile VALUE key = get_key(p);
54
+
55
+ push_key(d, key);
56
+ rb_funcall(d->handler, oj_hash_start_id, 1, key);
57
+ }
58
+
59
+ static void open_array(ojParser p) {
60
+ rb_funcall(((Delegate)p->ctx)->handler, oj_array_start_id, 1, Qnil);
61
+ }
62
+
63
+ static void open_array_key(ojParser p) {
64
+ Delegate d = (Delegate)p->ctx;
65
+ volatile VALUE key = get_key(p);
66
+
67
+ push_key(d, key);
68
+ rb_funcall(d->handler, oj_array_start_id, 1, key);
69
+ }
70
+
71
+ static void close_object(ojParser p) {
72
+ Delegate d = (Delegate)p->ctx;
73
+ VALUE key = Qnil;
74
+
75
+ if (OBJECT_FUN == p->stack[p->depth]) {
76
+ d->tail--;
77
+ if (d->tail < d->keys) {
78
+ rb_raise(rb_eIndexError, "accessing key stack");
79
+ }
80
+ key = *d->tail;
81
+ }
82
+ rb_funcall(d->handler, oj_hash_end_id, 1, key);
83
+ }
84
+
85
+ static void close_array(ojParser p) {
86
+ Delegate d = (Delegate)p->ctx;
87
+ VALUE key = Qnil;
88
+
89
+ if (OBJECT_FUN == p->stack[p->depth]) {
90
+ d->tail--;
91
+ if (d->tail < d->keys) {
92
+ rb_raise(rb_eIndexError, "accessing key stack");
93
+ }
94
+ key = *d->tail;
95
+ }
96
+ rb_funcall(d->handler, oj_array_end_id, 1, key);
97
+ }
98
+
99
+ static void add_null(ojParser p) {
100
+ rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qnil, Qnil);
101
+ }
102
+
103
+ static void add_null_key(ojParser p) {
104
+ rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qnil, get_key(p));
105
+ }
106
+
107
+ static void add_true(ojParser p) {
108
+ rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qtrue, Qnil);
109
+ }
110
+
111
+ static void add_true_key(ojParser p) {
112
+ rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qtrue, get_key(p));
113
+ }
114
+
115
+ static void add_false(ojParser p) {
116
+ rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qfalse, Qnil);
117
+ }
118
+
119
+ static void add_false_key(ojParser p) {
120
+ rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qfalse, get_key(p));
121
+ }
122
+
123
+ static void add_int(ojParser p) {
124
+ rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, LONG2NUM(p->num.fixnum), Qnil);
125
+ }
126
+
127
+ static void add_int_key(ojParser p) {
128
+ rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, LONG2NUM(p->num.fixnum), get_key(p));
129
+ }
130
+
131
+ static void add_float(ojParser p) {
132
+ rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, rb_float_new(p->num.dub), Qnil);
133
+ }
134
+
135
+ static void add_float_key(ojParser p) {
136
+ rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, rb_float_new(p->num.dub), get_key(p));
137
+ }
138
+
139
+ static void add_big(ojParser p) {
140
+ rb_funcall((VALUE)p->ctx,
141
+ oj_add_value_id,
142
+ 2,
143
+ rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
144
+ Qnil);
145
+ }
146
+
147
+ static void add_big_key(ojParser p) {
148
+ rb_funcall((VALUE)p->ctx,
149
+ oj_add_value_id,
150
+ 2,
151
+ rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
152
+ get_key(p));
153
+ }
154
+
155
+ static void add_str(ojParser p) {
156
+ Delegate d = (Delegate)p->ctx;
157
+ volatile VALUE rstr;
158
+ const char * str = buf_str(&p->buf);
159
+ size_t len = buf_len(&p->buf);
160
+
161
+ if (d->cache_str <= len) {
162
+ rstr = cache_intern(d->str_cache, str, len);
163
+ } else {
164
+ rstr = rb_utf8_str_new(str, len);
165
+ }
166
+ rb_funcall(d->handler, oj_add_value_id, 2, rstr, Qnil);
167
+ }
168
+
169
+ static void add_str_key(ojParser p) {
170
+ Delegate d = (Delegate)p->ctx;
171
+ volatile VALUE rstr;
172
+ const char * str = buf_str(&p->buf);
173
+ size_t len = buf_len(&p->buf);
174
+
175
+ if (d->cache_str <= len) {
176
+ rstr = cache_intern(d->str_cache, str, len);
177
+ } else {
178
+ rstr = rb_utf8_str_new(str, len);
179
+ }
180
+ rb_funcall(d->handler, oj_add_value_id, 2, rstr, get_key(p));
181
+ }
182
+
183
+ static void reset(ojParser p) {
184
+ Funcs end = p->funcs + 3;
185
+
186
+ for (Funcs f = p->funcs; f < end; f++) {
187
+ f->add_null = noop;
188
+ f->add_true = noop;
189
+ f->add_false = noop;
190
+ f->add_int = noop;
191
+ f->add_float = noop;
192
+ f->add_big = noop;
193
+ f->add_str = noop;
194
+ f->open_array = noop;
195
+ f->close_array = noop;
196
+ f->open_object = noop;
197
+ f->close_object = noop;
198
+ }
199
+ }
200
+
201
+ static VALUE option(ojParser p, const char *key, VALUE value) {
202
+ Delegate d = (Delegate)p->ctx;
203
+
204
+ if (0 == strcmp(key, "handler")) {
205
+ return d->handler;
206
+ }
207
+ if (0 == strcmp(key, "handler=")) {
208
+ d->tail = d->keys;
209
+ d->handler = value;
210
+ reset(p);
211
+ if (rb_respond_to(value, oj_hash_start_id)) {
212
+ p->funcs[TOP_FUN].open_object = open_object;
213
+ p->funcs[ARRAY_FUN].open_object = open_object;
214
+ p->funcs[OBJECT_FUN].open_object = open_object_key;
215
+ }
216
+ if (rb_respond_to(value, oj_array_start_id)) {
217
+ p->funcs[TOP_FUN].open_array = open_array;
218
+ p->funcs[ARRAY_FUN].open_array = open_array;
219
+ p->funcs[OBJECT_FUN].open_array = open_array_key;
220
+ }
221
+ if (rb_respond_to(value, oj_hash_end_id)) {
222
+ p->funcs[TOP_FUN].close_object = close_object;
223
+ p->funcs[ARRAY_FUN].close_object = close_object;
224
+ p->funcs[OBJECT_FUN].close_object = close_object;
225
+ }
226
+ if (rb_respond_to(value, oj_array_end_id)) {
227
+ p->funcs[TOP_FUN].close_array = close_array;
228
+ p->funcs[ARRAY_FUN].close_array = close_array;
229
+ p->funcs[OBJECT_FUN].close_array = close_array;
230
+ }
231
+ if (rb_respond_to(value, oj_add_value_id)) {
232
+ p->funcs[TOP_FUN].add_null = add_null;
233
+ p->funcs[ARRAY_FUN].add_null = add_null;
234
+ p->funcs[OBJECT_FUN].add_null = add_null_key;
235
+
236
+ p->funcs[TOP_FUN].add_true = add_true;
237
+ p->funcs[ARRAY_FUN].add_true = add_true;
238
+ p->funcs[OBJECT_FUN].add_true = add_true_key;
239
+
240
+ p->funcs[TOP_FUN].add_false = add_false;
241
+ p->funcs[ARRAY_FUN].add_false = add_false;
242
+ p->funcs[OBJECT_FUN].add_false = add_false_key;
243
+
244
+ p->funcs[TOP_FUN].add_int = add_int;
245
+ p->funcs[ARRAY_FUN].add_int = add_int;
246
+ p->funcs[OBJECT_FUN].add_int = add_int_key;
247
+
248
+ p->funcs[TOP_FUN].add_float = add_float;
249
+ p->funcs[ARRAY_FUN].add_float = add_float;
250
+ p->funcs[OBJECT_FUN].add_float = add_float_key;
251
+
252
+ p->funcs[TOP_FUN].add_big = add_big;
253
+ p->funcs[ARRAY_FUN].add_big = add_big;
254
+ p->funcs[OBJECT_FUN].add_big = add_big_key;
255
+
256
+ p->funcs[TOP_FUN].add_str = add_str;
257
+ p->funcs[ARRAY_FUN].add_str = add_str;
258
+ p->funcs[OBJECT_FUN].add_str = add_str_key;
259
+ }
260
+ return Qnil;
261
+ }
262
+ if (0 == strcmp(key, "cache_keys")) {
263
+ return d->cache_keys ? Qtrue : Qfalse;
264
+ }
265
+ if (0 == strcmp(key, "cache_keys=")) {
266
+ d->cache_keys = (Qtrue == value);
267
+
268
+ return d->cache_keys ? Qtrue : Qfalse;
269
+ }
270
+ if (0 == strcmp(key, "cache_strings")) {
271
+ return INT2NUM((int)d->cache_str);
272
+ }
273
+ if (0 == strcmp(key, "cache_strings=")) {
274
+ int limit = NUM2INT(value);
275
+
276
+ if (CACHE_MAX_KEY < limit) {
277
+ limit = CACHE_MAX_KEY;
278
+ } else if (limit < 0) {
279
+ limit = 0;
280
+ }
281
+ d->cache_str = limit;
282
+
283
+ return INT2NUM((int)d->cache_str);
284
+ }
285
+ rb_raise(rb_eArgError, "%s is not an option for the SAJ (Simple API for JSON) delegate", key);
286
+
287
+ return Qnil; // Never reached due to the raise but required by the compiler.
288
+ }
289
+
290
+ static VALUE result(ojParser p) {
291
+ return Qnil;
292
+ }
293
+
294
+ static void start(ojParser p) {
295
+ Delegate d = (Delegate)p->ctx;
296
+
297
+ d->tail = d->keys;
298
+ }
299
+
300
+ static void dfree(ojParser p) {
301
+ Delegate d = (Delegate)p->ctx;
302
+
303
+ if (NULL != d->keys) {
304
+ xfree(d->keys);
305
+ }
306
+ cache_free(d->str_cache);
307
+ xfree(p->ctx);
308
+ }
309
+
310
+ static void mark(ojParser p) {
311
+ if (NULL == p->ctx) {
312
+ return;
313
+ }
314
+ Delegate d = (Delegate)p->ctx;
315
+
316
+ cache_mark(d->str_cache);
317
+ if (Qnil != d->handler) {
318
+ rb_gc_mark(d->handler);
319
+ }
320
+ if (!d->cache_keys) {
321
+ for (VALUE *kp = d->keys; kp < d->tail; kp++) {
322
+ rb_gc_mark(*kp);
323
+ }
324
+ }
325
+ }
326
+
327
+ static VALUE form_str(const char *str, size_t len) {
328
+ return rb_str_freeze(rb_utf8_str_new(str, len));
329
+ }
330
+
331
+ void oj_set_parser_saj(ojParser p) {
332
+ Delegate d = ALLOC(struct _delegate);
333
+
334
+ d->klen = 256;
335
+ d->keys = ALLOC_N(VALUE, d->klen);
336
+ d->tail = d->keys;
337
+ d->str_cache = cache_create(0, form_str, true);
338
+
339
+ p->ctx = (void *)d;
340
+ reset(p);
341
+ p->option = option;
342
+ p->result = result;
343
+ p->free = dfree;
344
+ p->mark = mark;
345
+ p->start = start;
346
+ }