oj 3.13.4 → 3.13.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +1 -1
- data/RELEASE_NOTES.md +55 -0
- data/ext/oj/custom.c +2 -2
- data/ext/oj/parser.c +76 -28
- data/ext/oj/strict.c +2 -2
- data/ext/oj/usual.c +15 -15
- data/lib/oj/version.rb +1 -1
- data/test/bar.rb +16 -0
- data/test/baz.rb +16 -0
- data/test/foo.rb +8 -6
- data/test/prec.rb +23 -0
- data/test/test_parser_usual.rb +9 -5
- data/test/zoo.rb +13 -0
- metadata +17 -11
- data/test/benny.rb +0 -50
- data/test/big.rb +0 -15
- data/test/test_parser_memory.rb +0 -45
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c01eed4e3f068cda64af85aa6fe2aa15d7c559a3d1947385a8122112ae1b80b4
|
4
|
+
data.tar.gz: caba410a8bfee592344b8cfb281da48932cc2871ee3cc7fe71dadefacb55dc13
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 15dc55ed4572c0dcba2a3345aee97e5ab17f3106eef44c3d0a3c9e258915c1d95cae3bda8bbce6f21d3de08c22662a07ce7e39a52b77ff6c1f660cb576054e1f
|
7
|
+
data.tar.gz: 768977fae9b1c60baa679e32eb3d66d02206eb4357c2f6c29189b1d2dd27982a59f65648f8ee11424211f4e80a2a4ca11f19b285bee18db1d08ddbaba10fa1ca
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 3.13.6 - 2021-09-11
|
4
|
+
|
5
|
+
- Fixed unicode UTF 8 parsing in string values.
|
6
|
+
|
7
|
+
- Fixed hash key allocation issue.
|
8
|
+
|
9
|
+
- The `Oj::Parser.new()` function now allows optional arguments that
|
10
|
+
set the allowed options for the mode. As an example
|
11
|
+
`Oj::Parser.new(:usual, cache_keys: true)`.
|
12
|
+
|
13
|
+
## 3.13.5 - 2021-09-08
|
14
|
+
|
15
|
+
- Assure value strings of zero length are not always cached.
|
16
|
+
|
3
17
|
## 3.13.4 - 2021-09-04
|
4
18
|
|
5
19
|
- Fixed concurrent GC issue in the cache.
|
data/README.md
CHANGED
data/RELEASE_NOTES.md
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# RELEASE NOTES
|
2
|
+
|
3
|
+
The release notes here are organized by release. For a list of changes
|
4
|
+
see the See [{file:CHANGELOG.md}](CHANGELOG.md) file. In this file are
|
5
|
+
the steps to take to aid in keeping things rolling after updating to
|
6
|
+
the latest version.
|
7
|
+
|
8
|
+
## 3.13.x
|
9
|
+
|
10
|
+
This release included a new cache that performs better than the
|
11
|
+
earlier cache and a new high performance parser.
|
12
|
+
|
13
|
+
### Cache
|
14
|
+
|
15
|
+
The new cache includes a least recently used expiration to reduce
|
16
|
+
memory use. The cache is also self adjusting and will expand as needed
|
17
|
+
for better performance. It also handles Hash keys and string values
|
18
|
+
with two options, `:cache_keys`, a boolean and `:cache_str` an
|
19
|
+
integer. The `:cache_str` if set to more than zero is the limit for
|
20
|
+
the length of string values to cache. The maximum value is 35 which
|
21
|
+
allows strings up to 34 bytes to be cached.
|
22
|
+
|
23
|
+
One interesting aspect of the cache is not so much the string caching
|
24
|
+
which performs similar to the Ruby intern functions but the caching of
|
25
|
+
symbols and object attribute names. There is a significant gain for
|
26
|
+
symbols and object attributes.
|
27
|
+
|
28
|
+
If the cache is not desired then setting the default options to turn
|
29
|
+
it off can be done with this line:
|
30
|
+
|
31
|
+
``` ruby
|
32
|
+
Oj.default_options = { cache_keys: false, cache_str: 0 }
|
33
|
+
```
|
34
|
+
|
35
|
+
### Oj::Parser
|
36
|
+
|
37
|
+
The new parser uses a different core that follows the approach taken
|
38
|
+
by [OjC](https://github.com/ohler55/ojc) and
|
39
|
+
[OjG](https://github.com/ohler55/ojg). It also takes advantage of the
|
40
|
+
bulk Array and Hash functions. Another issue the new parser addresses
|
41
|
+
is option management. Instead of a single global default_options each
|
42
|
+
parser instance maintains it's own options.
|
43
|
+
|
44
|
+
There is a price to be paid when using the Oj::Parser. The API is not
|
45
|
+
the same the older parser. A single parser can only be used in a
|
46
|
+
single thread. This allows reuse of internal buffers for additional
|
47
|
+
improvements in performance.
|
48
|
+
|
49
|
+
The performane advantage of the Oj::Parse is that it is more than 3
|
50
|
+
times faster than the Oj::compat_load call and 6 times faster than the
|
51
|
+
JSON gem.
|
52
|
+
|
53
|
+
### Dump Performance
|
54
|
+
|
55
|
+
Thanks to Watson1978 Oj.dump also received a speed boost.
|
data/ext/oj/custom.c
CHANGED
@@ -955,8 +955,8 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
|
|
955
955
|
}
|
956
956
|
}
|
957
957
|
} else {
|
958
|
-
|
959
|
-
volatile VALUE rstr = rb_utf8_str_new(str, len);
|
958
|
+
volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
|
959
|
+
//volatile VALUE rstr = rb_utf8_str_new(str, len);
|
960
960
|
|
961
961
|
if (Qundef == rkey) {
|
962
962
|
if (Yes == pi->options.sym_key) {
|
data/ext/oj/parser.c
CHANGED
@@ -610,6 +610,9 @@ static void parse(ojParser p, const byte *json) {
|
|
610
610
|
printf("*** parse - mode: %c %s\n", p->map[256], (const char *)json);
|
611
611
|
#endif
|
612
612
|
for (; '\0' != *b; b++) {
|
613
|
+
#if DEBUG
|
614
|
+
printf("*** parse - mode: %c %02x %s => %c\n", p->map[256], *b, b, p->map[*b]);
|
615
|
+
#endif
|
613
616
|
switch (p->map[*b]) {
|
614
617
|
case SKIP_NEWLINE:
|
615
618
|
p->line++;
|
@@ -887,13 +890,17 @@ static void parse(ojParser p, const byte *json) {
|
|
887
890
|
buf_append_string(&p->buf, (const char *)start, b - start);
|
888
891
|
}
|
889
892
|
if ('"' == *b) {
|
893
|
+
p->funcs[p->stack[p->depth]].add_str(p);
|
890
894
|
p->map = p->next_map;
|
891
895
|
break;
|
892
896
|
}
|
893
897
|
b--;
|
894
898
|
break;
|
895
899
|
case STR_SLASH: p->map = esc_map; break;
|
896
|
-
case STR_QUOTE:
|
900
|
+
case STR_QUOTE:
|
901
|
+
p->funcs[p->stack[p->depth]].add_str(p);
|
902
|
+
p->map = p->next_map;
|
903
|
+
break;
|
897
904
|
case ESC_U:
|
898
905
|
p->map = u_map;
|
899
906
|
p->ri = 0;
|
@@ -1135,13 +1142,42 @@ extern void oj_set_parser_saj(ojParser p);
|
|
1135
1142
|
extern void oj_set_parser_usual(ojParser p);
|
1136
1143
|
extern void oj_set_parser_debug(ojParser p);
|
1137
1144
|
|
1145
|
+
static int opt_cb(VALUE rkey, VALUE value, VALUE ptr) {
|
1146
|
+
ojParser p = (ojParser)ptr;
|
1147
|
+
const char *key = NULL;
|
1148
|
+
char set_key[64];
|
1149
|
+
long klen;
|
1150
|
+
|
1151
|
+
switch (rb_type(rkey)) {
|
1152
|
+
case RUBY_T_SYMBOL:
|
1153
|
+
rkey = rb_sym2str(rkey);
|
1154
|
+
// fall through
|
1155
|
+
case RUBY_T_STRING:
|
1156
|
+
key = rb_string_value_ptr(&rkey);
|
1157
|
+
klen = RSTRING_LEN(rkey);
|
1158
|
+
break;
|
1159
|
+
default: rb_raise(rb_eArgError, "option keys must be a symbol or string");
|
1160
|
+
}
|
1161
|
+
if ((long)sizeof(set_key) - 1 <= klen) {
|
1162
|
+
return ST_CONTINUE;
|
1163
|
+
}
|
1164
|
+
memcpy(set_key, key, klen);
|
1165
|
+
set_key[klen] = '=';
|
1166
|
+
set_key[klen + 1] = '\0';
|
1167
|
+
p->option(p, set_key, value);
|
1168
|
+
|
1169
|
+
return ST_CONTINUE;
|
1170
|
+
}
|
1171
|
+
|
1138
1172
|
/* Document-method: new
|
1139
1173
|
* call-seq: new(mode=nil)
|
1140
1174
|
*
|
1141
1175
|
* Creates a new Parser with the specified mode. If no mode is provided
|
1142
|
-
* validation is assumed.
|
1176
|
+
* validation is assumed. Optional arguments can be provided that match the
|
1177
|
+
* mode. For example with the :usual mode the call might look like
|
1178
|
+
* Oj::Parser.new(:usual, cache_keys: true).
|
1143
1179
|
*/
|
1144
|
-
static VALUE parser_new(VALUE
|
1180
|
+
static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
|
1145
1181
|
ojParser p = ALLOC(struct _ojParser);
|
1146
1182
|
|
1147
1183
|
#if HAVE_RB_EXT_RACTOR_SAFE
|
@@ -1151,33 +1187,45 @@ static VALUE parser_new(VALUE self, VALUE mode) {
|
|
1151
1187
|
memset(p, 0, sizeof(struct _ojParser));
|
1152
1188
|
buf_init(&p->key);
|
1153
1189
|
buf_init(&p->buf);
|
1154
|
-
|
1155
1190
|
p->map = value_map;
|
1156
|
-
|
1157
|
-
|
1191
|
+
|
1192
|
+
if (argc < 1) {
|
1193
|
+
oj_set_parser_validator(p);
|
1158
1194
|
} else {
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
case RUBY_T_SYMBOL:
|
1163
|
-
mode = rb_sym2str(mode);
|
1164
|
-
// fall through
|
1165
|
-
case RUBY_T_STRING: ms = RSTRING_PTR(mode); break;
|
1166
|
-
default: rb_raise(rb_eArgError, "mode must be :validate, :usual, :saj, or :object");
|
1167
|
-
}
|
1168
|
-
if (0 == strcmp("usual", ms) || 0 == strcmp("standard", ms) || 0 == strcmp("strict", ms) ||
|
1169
|
-
0 == strcmp("compat", ms)) {
|
1170
|
-
oj_set_parser_usual(p);
|
1171
|
-
} else if (0 == strcmp("object", ms)) {
|
1172
|
-
// TBD
|
1173
|
-
} else if (0 == strcmp("saj", ms)) {
|
1174
|
-
oj_set_parser_saj(p);
|
1175
|
-
} else if (0 == strcmp("validate", ms)) {
|
1195
|
+
VALUE mode = argv[0];
|
1196
|
+
|
1197
|
+
if (Qnil == mode) {
|
1176
1198
|
oj_set_parser_validator(p);
|
1177
|
-
} else if (0 == strcmp("debug", ms)) {
|
1178
|
-
oj_set_parser_debug(p);
|
1179
1199
|
} else {
|
1180
|
-
|
1200
|
+
const char *ms = NULL;
|
1201
|
+
|
1202
|
+
switch (rb_type(mode)) {
|
1203
|
+
case RUBY_T_SYMBOL:
|
1204
|
+
mode = rb_sym2str(mode);
|
1205
|
+
// fall through
|
1206
|
+
case RUBY_T_STRING: ms = RSTRING_PTR(mode); break;
|
1207
|
+
default: rb_raise(rb_eArgError, "mode must be :validate, :usual, :saj, or :object");
|
1208
|
+
}
|
1209
|
+
if (0 == strcmp("usual", ms) || 0 == strcmp("standard", ms) || 0 == strcmp("strict", ms) ||
|
1210
|
+
0 == strcmp("compat", ms)) {
|
1211
|
+
oj_set_parser_usual(p);
|
1212
|
+
} else if (0 == strcmp("object", ms)) {
|
1213
|
+
// TBD
|
1214
|
+
} else if (0 == strcmp("saj", ms)) {
|
1215
|
+
oj_set_parser_saj(p);
|
1216
|
+
} else if (0 == strcmp("validate", ms)) {
|
1217
|
+
oj_set_parser_validator(p);
|
1218
|
+
} else if (0 == strcmp("debug", ms)) {
|
1219
|
+
oj_set_parser_debug(p);
|
1220
|
+
} else {
|
1221
|
+
rb_raise(rb_eArgError, "mode must be :validate, :usual, :saj, or :object");
|
1222
|
+
}
|
1223
|
+
}
|
1224
|
+
if (1 < argc) {
|
1225
|
+
VALUE ropts = argv[1];
|
1226
|
+
|
1227
|
+
Check_Type(ropts, T_HASH);
|
1228
|
+
rb_hash_foreach(ropts, opt_cb, (VALUE)p);
|
1181
1229
|
}
|
1182
1230
|
}
|
1183
1231
|
return Data_Wrap_Struct(parser_class, parser_mark, parser_free, p);
|
@@ -1204,7 +1252,7 @@ static VALUE parser_new(VALUE self, VALUE mode) {
|
|
1204
1252
|
* - *:usual*
|
1205
1253
|
* - _cache_keys=_ sets the value of the _cache_keys_ flag.
|
1206
1254
|
* - _cache_keys_ returns the value of the _cache_keys_ flag.
|
1207
|
-
* - _cache_strings=_ sets the value of the _cache_strings_ to
|
1255
|
+
* - _cache_strings=_ sets the value of the _cache_strings_ to a positive integer less than 35. Strings shorter than
|
1208
1256
|
* that length are cached.
|
1209
1257
|
* - _cache_strings_ returns the value of the _cache_strings_ integer value.
|
1210
1258
|
* - _cache_expunge=_ sets the value of the _cache_expunge_ where 0 never expunges, 1 expunges slowly, 2 expunges
|
@@ -1469,7 +1517,7 @@ static VALUE parser_validate(VALUE self) {
|
|
1469
1517
|
*/
|
1470
1518
|
void oj_parser_init() {
|
1471
1519
|
parser_class = rb_define_class_under(Oj, "Parser", rb_cObject);
|
1472
|
-
rb_define_module_function(parser_class, "new", parser_new, 1);
|
1520
|
+
rb_define_module_function(parser_class, "new", parser_new, -1);
|
1473
1521
|
rb_define_method(parser_class, "parse", parser_parse, 1);
|
1474
1522
|
rb_define_method(parser_class, "load", parser_load, 1);
|
1475
1523
|
rb_define_method(parser_class, "file", parser_file, 1);
|
data/ext/oj/strict.c
CHANGED
@@ -16,7 +16,7 @@
|
|
16
16
|
VALUE oj_cstr_to_value(const char *str, size_t len, size_t cache_str) {
|
17
17
|
volatile VALUE rstr = Qnil;
|
18
18
|
|
19
|
-
if (len
|
19
|
+
if (len < cache_str) {
|
20
20
|
rstr = oj_str_intern(str, len);
|
21
21
|
} else {
|
22
22
|
rstr = rb_str_new(str, len);
|
@@ -37,7 +37,7 @@ VALUE oj_calc_hash_key(ParseInfo pi, Val parent) {
|
|
37
37
|
} else {
|
38
38
|
rkey = rb_str_new(parent->key, parent->klen);
|
39
39
|
rkey = oj_encode(rkey);
|
40
|
-
|
40
|
+
OBJ_FREEZE(rkey); // frozen when used as a Hash key anyway
|
41
41
|
}
|
42
42
|
return rkey;
|
43
43
|
}
|
data/ext/oj/usual.c
CHANGED
@@ -39,7 +39,7 @@ typedef struct _col {
|
|
39
39
|
typedef union _key {
|
40
40
|
struct {
|
41
41
|
int16_t len;
|
42
|
-
char buf[
|
42
|
+
char buf[30];
|
43
43
|
};
|
44
44
|
struct {
|
45
45
|
int16_t xlen; // should be the same as len
|
@@ -209,21 +209,21 @@ static void push(ojParser p, VALUE v) {
|
|
209
209
|
static VALUE cache_key(ojParser p, Key kp) {
|
210
210
|
Delegate d = (Delegate)p->ctx;
|
211
211
|
|
212
|
-
if ((size_t)kp->len < sizeof(kp->buf)
|
212
|
+
if ((size_t)kp->len < sizeof(kp->buf)) {
|
213
213
|
return cache_intern(d->key_cache, kp->buf, kp->len);
|
214
214
|
}
|
215
215
|
return cache_intern(d->key_cache, kp->key, kp->len);
|
216
216
|
}
|
217
217
|
|
218
218
|
static VALUE str_key(ojParser p, Key kp) {
|
219
|
-
if ((size_t)kp->len < sizeof(kp->buf)
|
219
|
+
if ((size_t)kp->len < sizeof(kp->buf)) {
|
220
220
|
return rb_str_freeze(rb_utf8_str_new(kp->buf, kp->len));
|
221
221
|
}
|
222
222
|
return rb_str_freeze(rb_utf8_str_new(kp->key, kp->len));
|
223
223
|
}
|
224
224
|
|
225
225
|
static VALUE sym_key(ojParser p, Key kp) {
|
226
|
-
if ((size_t)kp->len < sizeof(kp->buf)
|
226
|
+
if ((size_t)kp->len < sizeof(kp->buf)) {
|
227
227
|
return rb_str_freeze(rb_str_intern(rb_utf8_str_new(kp->buf, kp->len)));
|
228
228
|
}
|
229
229
|
return rb_str_freeze(rb_str_intern(rb_utf8_str_new(kp->key, kp->len)));
|
@@ -232,7 +232,7 @@ static VALUE sym_key(ojParser p, Key kp) {
|
|
232
232
|
static ID get_attr_id(ojParser p, Key kp) {
|
233
233
|
Delegate d = (Delegate)p->ctx;
|
234
234
|
|
235
|
-
if ((size_t)kp->len < sizeof(kp->buf)
|
235
|
+
if ((size_t)kp->len < sizeof(kp->buf)) {
|
236
236
|
return (ID)cache_intern(d->attr_cache, kp->buf, kp->len);
|
237
237
|
}
|
238
238
|
return (ID)cache_intern(d->attr_cache, kp->key, kp->len);
|
@@ -253,7 +253,7 @@ static void push_key(ojParser p) {
|
|
253
253
|
d->kend = d->khead + cap;
|
254
254
|
}
|
255
255
|
d->ktail->len = klen;
|
256
|
-
if (klen
|
256
|
+
if (klen < sizeof(d->ktail->buf)) {
|
257
257
|
memcpy(d->ktail->buf, key, klen);
|
258
258
|
d->ktail->buf[klen] = '\0';
|
259
259
|
} else {
|
@@ -336,7 +336,7 @@ static void close_object(ojParser p) {
|
|
336
336
|
#if HAVE_RB_HASH_BULK_INSERT
|
337
337
|
for (vp = head; kp < d->ktail; kp++, vp += 2) {
|
338
338
|
*vp = d->get_key(p, kp);
|
339
|
-
if (sizeof(kp->buf)
|
339
|
+
if (sizeof(kp->buf) <= (size_t)kp->len) {
|
340
340
|
xfree(kp->key);
|
341
341
|
}
|
342
342
|
}
|
@@ -344,7 +344,7 @@ static void close_object(ojParser p) {
|
|
344
344
|
#else
|
345
345
|
for (vp = head; kp < d->ktail; kp++, vp += 2) {
|
346
346
|
rb_hash_aset(obj, d->get_key(p, kp), *(vp + 1));
|
347
|
-
if (sizeof(kp->buf)
|
347
|
+
if (sizeof(kp->buf) <= (size_t)kp->len) {
|
348
348
|
xfree(kp->key);
|
349
349
|
}
|
350
350
|
}
|
@@ -368,7 +368,7 @@ static void close_object_class(ojParser p) {
|
|
368
368
|
|
369
369
|
for (vp = head; kp < d->ktail; kp++, vp += 2) {
|
370
370
|
rb_funcall(obj, hset_id, 2, d->get_key(p, kp), *(vp + 1));
|
371
|
-
if (sizeof(kp->buf)
|
371
|
+
if (sizeof(kp->buf) <= (size_t)kp->len) {
|
372
372
|
xfree(kp->key);
|
373
373
|
}
|
374
374
|
}
|
@@ -396,7 +396,7 @@ static void close_object_create(ojParser p) {
|
|
396
396
|
#if HAVE_RB_HASH_BULK_INSERT
|
397
397
|
for (vp = head; kp < d->ktail; kp++, vp += 2) {
|
398
398
|
*vp = d->get_key(p, kp);
|
399
|
-
if (sizeof(kp->buf)
|
399
|
+
if (sizeof(kp->buf) <= (size_t)kp->len) {
|
400
400
|
xfree(kp->key);
|
401
401
|
}
|
402
402
|
}
|
@@ -404,7 +404,7 @@ static void close_object_create(ojParser p) {
|
|
404
404
|
#else
|
405
405
|
for (vp = head; kp < d->ktail; kp++, vp += 2) {
|
406
406
|
rb_hash_aset(obj, d->get_key(p, kp), *(vp + 1));
|
407
|
-
if (sizeof(kp->buf)
|
407
|
+
if (sizeof(kp->buf) <= (size_t)kp->len) {
|
408
408
|
xfree(kp->key);
|
409
409
|
}
|
410
410
|
}
|
@@ -413,7 +413,7 @@ static void close_object_create(ojParser p) {
|
|
413
413
|
obj = rb_class_new_instance(0, NULL, d->hash_class);
|
414
414
|
for (vp = head; kp < d->ktail; kp++, vp += 2) {
|
415
415
|
rb_funcall(obj, hset_id, 2, d->get_key(p, kp), *(vp + 1));
|
416
|
-
if (sizeof(kp->buf)
|
416
|
+
if (sizeof(kp->buf) <= (size_t)kp->len) {
|
417
417
|
xfree(kp->key);
|
418
418
|
}
|
419
419
|
}
|
@@ -428,7 +428,7 @@ static void close_object_create(ojParser p) {
|
|
428
428
|
#if HAVE_RB_HASH_BULK_INSERT
|
429
429
|
for (vp = head; kp < d->ktail; kp++, vp += 2) {
|
430
430
|
*vp = d->get_key(p, kp);
|
431
|
-
if (sizeof(kp->buf)
|
431
|
+
if (sizeof(kp->buf) <= (size_t)kp->len) {
|
432
432
|
xfree(kp->key);
|
433
433
|
}
|
434
434
|
}
|
@@ -436,7 +436,7 @@ static void close_object_create(ojParser p) {
|
|
436
436
|
#else
|
437
437
|
for (vp = head; kp < d->ktail; kp++, vp += 2) {
|
438
438
|
rb_hash_aset(arg, d->get_key(p, kp), *(vp + 1));
|
439
|
-
if (sizeof(kp->buf)
|
439
|
+
if (sizeof(kp->buf) <= (size_t)kp->len) {
|
440
440
|
xfree(kp->key);
|
441
441
|
}
|
442
442
|
}
|
@@ -446,7 +446,7 @@ static void close_object_create(ojParser p) {
|
|
446
446
|
obj = rb_class_new_instance(0, NULL, clas);
|
447
447
|
for (vp = head; kp < d->ktail; kp++, vp += 2) {
|
448
448
|
rb_ivar_set(obj, get_attr_id(p, kp), *(vp + 1));
|
449
|
-
if (sizeof(kp->buf)
|
449
|
+
if (sizeof(kp->buf) <= (size_t)kp->len) {
|
450
450
|
xfree(kp->key);
|
451
451
|
}
|
452
452
|
}
|
data/lib/oj/version.rb
CHANGED
data/test/bar.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << '.'
|
4
|
+
$: << File.join(File.dirname(__FILE__), "../lib")
|
5
|
+
$: << File.join(File.dirname(__FILE__), "../ext")
|
6
|
+
|
7
|
+
require 'oj'
|
8
|
+
|
9
|
+
json = %|[{"x12345678901234567890": true}]|
|
10
|
+
|
11
|
+
p = Oj::Parser.new(:usual)
|
12
|
+
p.cache_keys = false
|
13
|
+
p.symbol_keys = true
|
14
|
+
x = p.parse(json)
|
15
|
+
|
16
|
+
pp x
|
data/test/baz.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << File.dirname(__FILE__)
|
4
|
+
$oj_dir = File.dirname(File.expand_path(File.dirname(__FILE__)))
|
5
|
+
%w(lib ext).each do |dir|
|
6
|
+
$: << File.join($oj_dir, dir)
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'oj'
|
10
|
+
Oj.mimic_JSON()
|
11
|
+
|
12
|
+
begin
|
13
|
+
::JSON.load('name=&email=&subject=&comment=&submit=Send+Message')
|
14
|
+
rescue ::JSON::ParserError
|
15
|
+
puts "*** Pass"
|
16
|
+
end
|
data/test/foo.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
$: << '.'
|
4
|
-
$: << '../lib'
|
5
|
-
$: << '../ext'
|
6
|
-
|
7
3
|
require 'oj'
|
8
4
|
|
9
|
-
|
5
|
+
Oj::default_options = {cache_str: 0, cache_keys: true, mode: :strict}
|
6
|
+
|
7
|
+
puts "Ruby version: #{RUBY_VERSION}"
|
8
|
+
puts "Oj version: #{Oj::VERSION}"
|
9
|
+
|
10
|
+
puts "cache_keys: #{Oj::default_options[:cache_keys]}"
|
11
|
+
puts "cache_str: #{Oj::default_options[:cache_str]}"
|
10
12
|
|
11
|
-
|
13
|
+
Oj.load('{"":""}').each_pair {|k,v| puts "k.frozen?: #{k.frozen?}\nv.frozen?: #{v.frozen?}"}
|
data/test/prec.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'oj'
|
4
|
+
|
5
|
+
extras = {"locationLng" => -97.14690769100295}
|
6
|
+
|
7
|
+
Oj.default_options = {float_precision: 17}
|
8
|
+
|
9
|
+
encoded = Oj.dump(extras)
|
10
|
+
puts encoded
|
11
|
+
puts Oj.load(encoded)
|
12
|
+
|
13
|
+
require "active_record"
|
14
|
+
|
15
|
+
Oj::Rails.set_encoder()
|
16
|
+
Oj::Rails.set_decoder()
|
17
|
+
|
18
|
+
Oj.default_options = {float_precision: 17}
|
19
|
+
# Using Oj rails encoder, gets the correct value: {"locationLng":-97.14690769100295}
|
20
|
+
encoded = ActiveSupport::JSON.encode(extras)
|
21
|
+
puts encoded
|
22
|
+
puts ActiveSupport::JSON.decode(encoded)
|
23
|
+
puts Oj.load(encoded)
|
data/test/test_parser_usual.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# encoding:
|
2
|
+
# encoding: utf-8
|
3
3
|
|
4
4
|
$: << File.dirname(__FILE__)
|
5
5
|
|
@@ -73,9 +73,14 @@ class UsualTest < Minitest::Test
|
|
73
73
|
assert_equal({a: true, b: false}, doc)
|
74
74
|
end
|
75
75
|
|
76
|
-
def
|
76
|
+
def test_strings
|
77
77
|
p = Oj::Parser.new(:usual)
|
78
|
-
p.
|
78
|
+
doc = p.parse('{"ぴ": "", "ぴ ": "x", "c": "ぴーたー", "d": " ぴーたー "}')
|
79
|
+
assert_equal({'ぴ' => '', 'ぴ ' => 'x', 'c' => 'ぴーたー', 'd' => ' ぴーたー '}, doc)
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_capacity
|
83
|
+
p = Oj::Parser.new(:usual, capacity: 1000)
|
79
84
|
assert_equal(4096, p.capacity)
|
80
85
|
p.capacity = 5000
|
81
86
|
assert_equal(5000, p.capacity)
|
@@ -181,8 +186,7 @@ class UsualTest < Minitest::Test
|
|
181
186
|
end
|
182
187
|
|
183
188
|
def test_missing_class
|
184
|
-
p = Oj::Parser.new(:usual)
|
185
|
-
p.create_id = '^'
|
189
|
+
p = Oj::Parser.new(:usual, create_id: '^')
|
186
190
|
json = '{"a":true,"^":"Auto","b":false}'
|
187
191
|
doc = p.parse(json)
|
188
192
|
assert_equal(Hash, doc.class)
|
data/test/zoo.rb
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oj
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.13.
|
4
|
+
version: 3.13.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Ohler
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-09-
|
11
|
+
date: 2021-09-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -79,6 +79,9 @@ extensions:
|
|
79
79
|
- ext/oj/extconf.rb
|
80
80
|
extra_rdoc_files:
|
81
81
|
- README.md
|
82
|
+
- LICENSE
|
83
|
+
- CHANGELOG.md
|
84
|
+
- RELEASE_NOTES.md
|
82
85
|
- pages/Advanced.md
|
83
86
|
- pages/Compatibility.md
|
84
87
|
- pages/Custom.md
|
@@ -94,6 +97,7 @@ files:
|
|
94
97
|
- CHANGELOG.md
|
95
98
|
- LICENSE
|
96
99
|
- README.md
|
100
|
+
- RELEASE_NOTES.md
|
97
101
|
- ext/oj/buf.h
|
98
102
|
- ext/oj/cache.c
|
99
103
|
- ext/oj/cache.h
|
@@ -195,8 +199,8 @@ files:
|
|
195
199
|
- test/activesupport6/test_common.rb
|
196
200
|
- test/activesupport6/test_helper.rb
|
197
201
|
- test/activesupport6/time_zone_test_helpers.rb
|
198
|
-
- test/
|
199
|
-
- test/
|
202
|
+
- test/bar.rb
|
203
|
+
- test/baz.rb
|
200
204
|
- test/files.rb
|
201
205
|
- test/foo.rb
|
202
206
|
- test/helper.rb
|
@@ -232,6 +236,7 @@ files:
|
|
232
236
|
- test/perf_simple.rb
|
233
237
|
- test/perf_strict.rb
|
234
238
|
- test/perf_wab.rb
|
239
|
+
- test/prec.rb
|
235
240
|
- test/sample.rb
|
236
241
|
- test/sample/change.rb
|
237
242
|
- test/sample/dir.rb
|
@@ -258,7 +263,6 @@ files:
|
|
258
263
|
- test/test_null.rb
|
259
264
|
- test/test_object.rb
|
260
265
|
- test/test_parser.rb
|
261
|
-
- test/test_parser_memory.rb
|
262
266
|
- test/test_parser_saj.rb
|
263
267
|
- test/test_parser_usual.rb
|
264
268
|
- test/test_rails.rb
|
@@ -271,6 +275,7 @@ files:
|
|
271
275
|
- test/tests.rb
|
272
276
|
- test/tests_mimic.rb
|
273
277
|
- test/tests_mimic_addition.rb
|
278
|
+
- test/zoo.rb
|
274
279
|
homepage: http://www.ohler.com/oj
|
275
280
|
licenses:
|
276
281
|
- MIT
|
@@ -281,7 +286,7 @@ metadata:
|
|
281
286
|
homepage_uri: http://www.ohler.com/oj/
|
282
287
|
source_code_uri: https://github.com/ohler55/oj
|
283
288
|
wiki_uri: https://github.com/ohler55/oj/wiki
|
284
|
-
post_install_message:
|
289
|
+
post_install_message:
|
285
290
|
rdoc_options:
|
286
291
|
- "--title"
|
287
292
|
- Oj
|
@@ -301,7 +306,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
301
306
|
version: '0'
|
302
307
|
requirements: []
|
303
308
|
rubygems_version: 3.2.22
|
304
|
-
signing_key:
|
309
|
+
signing_key:
|
305
310
|
specification_version: 4
|
306
311
|
summary: A fast JSON parser and serializer.
|
307
312
|
test_files:
|
@@ -325,8 +330,8 @@ test_files:
|
|
325
330
|
- test/activesupport6/test_common.rb
|
326
331
|
- test/activesupport6/test_helper.rb
|
327
332
|
- test/activesupport6/time_zone_test_helpers.rb
|
328
|
-
- test/
|
329
|
-
- test/
|
333
|
+
- test/bar.rb
|
334
|
+
- test/baz.rb
|
330
335
|
- test/files.rb
|
331
336
|
- test/foo.rb
|
332
337
|
- test/helper.rb
|
@@ -362,6 +367,7 @@ test_files:
|
|
362
367
|
- test/perf_simple.rb
|
363
368
|
- test/perf_strict.rb
|
364
369
|
- test/perf_wab.rb
|
370
|
+
- test/prec.rb
|
365
371
|
- test/sample/change.rb
|
366
372
|
- test/sample/dir.rb
|
367
373
|
- test/sample/doc.rb
|
@@ -388,7 +394,6 @@ test_files:
|
|
388
394
|
- test/test_null.rb
|
389
395
|
- test/test_object.rb
|
390
396
|
- test/test_parser.rb
|
391
|
-
- test/test_parser_memory.rb
|
392
397
|
- test/test_parser_saj.rb
|
393
398
|
- test/test_parser_usual.rb
|
394
399
|
- test/test_rails.rb
|
@@ -401,3 +406,4 @@ test_files:
|
|
401
406
|
- test/tests.rb
|
402
407
|
- test/tests_mimic.rb
|
403
408
|
- test/tests_mimic_addition.rb
|
409
|
+
- test/zoo.rb
|
data/test/benny.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal
|
3
|
-
|
4
|
-
require 'bundler/inline'
|
5
|
-
|
6
|
-
gemfile do
|
7
|
-
source 'https://rubygems.org'
|
8
|
-
|
9
|
-
gem 'oj'
|
10
|
-
gem 'benchmark-ips', require: 'benchmark/ips'
|
11
|
-
end
|
12
|
-
|
13
|
-
require 'json'
|
14
|
-
require 'open-uri'
|
15
|
-
|
16
|
-
CANADA_DATA_JSON = URI.parse('https://raw.githubusercontent.com/serde-rs/json-benchmark/master/data/canada.json').read
|
17
|
-
CANADA_DATA = JSON.parse(CANADA_DATA_JSON)
|
18
|
-
|
19
|
-
Benchmark.ips do |x|
|
20
|
-
x.config(:time => 10, :warmup => 5)
|
21
|
-
|
22
|
-
x.report("marshall Canada data with Oj") do
|
23
|
-
Oj.dump(CANADA_DATA)
|
24
|
-
end
|
25
|
-
|
26
|
-
x.report("marshall Canada data with JSON") do
|
27
|
-
JSON.dump(CANADA_DATA)
|
28
|
-
end
|
29
|
-
|
30
|
-
x.compare!
|
31
|
-
end
|
32
|
-
|
33
|
-
Oj.default_options = {
|
34
|
-
mode: :strict,
|
35
|
-
bigdecimal_load: :fast
|
36
|
-
}
|
37
|
-
|
38
|
-
Benchmark.ips do |x|
|
39
|
-
x.config(:time => 10, :warmup => 5)
|
40
|
-
|
41
|
-
x.report("unmarshall Canada data with Oj") do
|
42
|
-
Oj.load(CANADA_DATA_JSON)
|
43
|
-
end
|
44
|
-
|
45
|
-
x.report("unmarshall Canada data with JSON") do
|
46
|
-
JSON.parse(CANADA_DATA_JSON)
|
47
|
-
end
|
48
|
-
|
49
|
-
x.compare!
|
50
|
-
end
|
data/test/big.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
#require 'active_support'
|
2
|
-
#require 'active_support/core_ext'
|
3
|
-
#require 'active_support/json'
|
4
|
-
require 'oj'
|
5
|
-
|
6
|
-
#Oj.optimize_rails
|
7
|
-
Oj.mimic_JSON
|
8
|
-
|
9
|
-
h = {:type=>:record, :name=>:group, :namespace=>"com.salsify.identity", :fields=>[{:name=>"id", :type=>{:name=>:salsify_uuid, :type=>:fixed, :namespace=>"com.salsify", :size=>38}}, {:name=>"type", :type=>"string", :default=>"groups"}, {:name=>"external_id", :type=>[:null, "string"], :default=>nil}, {:name=>"created_at", :type=>{:type=>"long", :logicalType=>"timestamp-micros"}}, {:name=>"updated_at", :type=>{:type=>"long", :logicalType=>"timestamp-micros"}}, {:name=>"name", :type=>"string"}, {:name=>"policy", :type=>[:null, {:type=>:record, :name=>:policy, :namespace=>"com.salsify.security", :fields=>[{:name=>"created_at", :type=>{:type=>"long", :logicalType=>"timestamp-micros"}}, {:name=>"updated_at", :type=>{:type=>"long", :logicalType=>"timestamp-micros"}}, {:name=>"id", :type=>"com.salsify.salsify_uuid"}, {:name=>"type", :type=>"string", :default=>"policies"}, {:name=>"external_id", :type=>[:null, "string"], :default=>nil}, {:name=>"name", :type=>"string"}, {:name=>"statements", :type=>{:type=>:array, :items=>{:type=>:record, :name=>:statement, :namespace=>"com.salsify.security", :fields=>[{:name=>"created_at", :type=>{:type=>"long", :logicalType=>"timestamp-micros"}}, {:name=>"updated_at", :type=>{:type=>"long", :logicalType=>"timestamp-micros"}}, {:name=>"id", :type=>"com.salsify.salsify_uuid"}, {:name=>"type", :type=>"string", :default=>"statements"}, {:name=>"external_id", :type=>[:null, "string"], :default=>nil}, {:name=>"action", :type=>{:name=>"__statement_action_enum", :type=>:enum, :namespace=>"com.salsify.security", :symbols=>[:manage, :read]}}, {:name=>"resource", :type=>{:name=>"__statement_resource_enum", :type=>:enum, :namespace=>"com.salsify.security", :symbols=>[:product, :digital_asset]}}, {:name=>"conditions", :type=>{:type=>:array, :items=>{:type=>:record, :name=>:condition, :namespace=>"com.salsify.security", :fields=>[{:name=>"created_at", :type=>{:type=>"long", :logicalType=>"timestamp-micros"}}, {:name=>"updated_at", :type=>{:type=>"long", :logicalType=>"timestamp-micros"}}, {:name=>"id", :type=>"com.salsify.salsify_uuid"}, {:name=>"type", :type=>"string", :default=>"conditions"}, {:name=>"external_id", :type=>[:null, "string"], :default=>nil}, {:name=>"operator", :type=>{:name=>"__condition_operator_enum", :type=>:enum, :namespace=>"com.salsify.security", :symbols=>[:equals]}}, {:name=>"attribute_type", :type=>{:name=>"__condition_attribute_type_enum", :type=>:enum, :namespace=>"com.salsify.security", :symbols=>[:resource]}}, {:name=>"value", :type=>"string"}, {:name=>"attribute", :type=>[:null, {:type=>:record, :name=>:reference, :namespace=>"com.salsify", :fields=>[{:name=>"id", :type=>"com.salsify.salsify_uuid"}, {:name=>"type", :type=>"string", :doc=>"snake_case, plural name for the resource type"}, {:name=>"external_id", :type=>[:null, "string"], :default=>nil}]}], :default=>nil}, {:name=>"broken", :type=>[:null, "boolean"], :default=>nil}]}}}]}}}]}], :default=>nil}]}
|
10
|
-
|
11
|
-
#Oj.dump(h)
|
12
|
-
puts JSON.pretty_generate(h)
|
13
|
-
#puts JSON.fast_generate(h)
|
14
|
-
#puts JSON.generate(h)
|
15
|
-
|
data/test/test_parser_memory.rb
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# encoding: utf-8
|
3
|
-
|
4
|
-
%w(lib ext test).each do |dir|
|
5
|
-
$LOAD_PATH.unshift File.expand_path("../../#{dir}", __FILE__)
|
6
|
-
end
|
7
|
-
|
8
|
-
require 'oj'
|
9
|
-
|
10
|
-
json =<<-EOF
|
11
|
-
{
|
12
|
-
"$id": "https://example.com/person.schema.json",
|
13
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
14
|
-
"title": "Person",
|
15
|
-
"type": "object",
|
16
|
-
"properties": {
|
17
|
-
"firstName": {
|
18
|
-
"type": "string",
|
19
|
-
"description": "The person's first name."
|
20
|
-
},
|
21
|
-
"lastName": {
|
22
|
-
"type": "string",
|
23
|
-
"description": "The person's last name."
|
24
|
-
},
|
25
|
-
"age": {
|
26
|
-
"description": "Age in years which must be equal to or greater than zero.",
|
27
|
-
"type": "integer",
|
28
|
-
"minimum": 0
|
29
|
-
}
|
30
|
-
}
|
31
|
-
}
|
32
|
-
EOF
|
33
|
-
|
34
|
-
#json = '{"abc": true}'
|
35
|
-
#json = '[true,false]'
|
36
|
-
|
37
|
-
100_001.times do |i|
|
38
|
-
p = Oj::Parser.new(:usual).parse(json)
|
39
|
-
|
40
|
-
if i % 10_000 == 0
|
41
|
-
GC.start
|
42
|
-
rss = Integer(`ps -o rss= -p #{Process.pid}`) / 1024.0
|
43
|
-
puts "#{i},#{rss} MB"
|
44
|
-
end
|
45
|
-
end
|