oj 3.7.4 → 3.13.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1352 -0
  3. data/README.md +29 -8
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +53 -72
  6. data/ext/oj/cache.c +326 -0
  7. data/ext/oj/cache.h +21 -0
  8. data/ext/oj/cache8.c +61 -64
  9. data/ext/oj/cache8.h +12 -39
  10. data/ext/oj/circarray.c +37 -43
  11. data/ext/oj/circarray.h +16 -17
  12. data/ext/oj/code.c +165 -179
  13. data/ext/oj/code.h +27 -29
  14. data/ext/oj/compat.c +174 -194
  15. data/ext/oj/custom.c +809 -866
  16. data/ext/oj/debug.c +132 -0
  17. data/ext/oj/dump.c +848 -863
  18. data/ext/oj/dump.h +81 -67
  19. data/ext/oj/dump_compat.c +85 -123
  20. data/ext/oj/dump_leaf.c +100 -188
  21. data/ext/oj/dump_object.c +527 -656
  22. data/ext/oj/dump_strict.c +315 -338
  23. data/ext/oj/encode.h +7 -34
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +40 -29
  26. data/ext/oj/err.h +48 -48
  27. data/ext/oj/extconf.rb +17 -4
  28. data/ext/oj/fast.c +1070 -1087
  29. data/ext/oj/intern.c +301 -0
  30. data/ext/oj/intern.h +26 -0
  31. data/ext/oj/mimic_json.c +469 -436
  32. data/ext/oj/object.c +525 -593
  33. data/ext/oj/odd.c +154 -138
  34. data/ext/oj/odd.h +37 -38
  35. data/ext/oj/oj.c +1325 -986
  36. data/ext/oj/oj.h +333 -316
  37. data/ext/oj/parse.c +1002 -846
  38. data/ext/oj/parse.h +92 -87
  39. data/ext/oj/parser.c +1557 -0
  40. data/ext/oj/parser.h +91 -0
  41. data/ext/oj/rails.c +888 -878
  42. data/ext/oj/rails.h +11 -14
  43. data/ext/oj/reader.c +141 -147
  44. data/ext/oj/reader.h +73 -89
  45. data/ext/oj/resolve.c +41 -62
  46. data/ext/oj/resolve.h +7 -9
  47. data/ext/oj/rxclass.c +71 -75
  48. data/ext/oj/rxclass.h +18 -19
  49. data/ext/oj/saj.c +443 -486
  50. data/ext/oj/saj2.c +602 -0
  51. data/ext/oj/scp.c +88 -113
  52. data/ext/oj/sparse.c +787 -709
  53. data/ext/oj/stream_writer.c +133 -159
  54. data/ext/oj/strict.c +127 -118
  55. data/ext/oj/string_writer.c +230 -249
  56. data/ext/oj/trace.c +34 -41
  57. data/ext/oj/trace.h +19 -19
  58. data/ext/oj/usual.c +1254 -0
  59. data/ext/oj/util.c +136 -0
  60. data/ext/oj/util.h +20 -0
  61. data/ext/oj/val_stack.c +59 -67
  62. data/ext/oj/val_stack.h +91 -129
  63. data/ext/oj/validate.c +46 -0
  64. data/ext/oj/wab.c +342 -353
  65. data/lib/oj/bag.rb +1 -0
  66. data/lib/oj/easy_hash.rb +5 -4
  67. data/lib/oj/error.rb +1 -1
  68. data/lib/oj/json.rb +1 -1
  69. data/lib/oj/mimic.rb +48 -14
  70. data/lib/oj/saj.rb +20 -6
  71. data/lib/oj/state.rb +8 -7
  72. data/lib/oj/version.rb +2 -2
  73. data/lib/oj.rb +0 -8
  74. data/pages/Compatibility.md +1 -1
  75. data/pages/JsonGem.md +15 -0
  76. data/pages/Modes.md +53 -46
  77. data/pages/Options.md +72 -11
  78. data/pages/Parser.md +309 -0
  79. data/pages/Rails.md +73 -22
  80. data/pages/Security.md +1 -1
  81. data/test/activerecord/result_test.rb +7 -2
  82. data/test/activesupport5/abstract_unit.rb +45 -0
  83. data/test/activesupport5/decoding_test.rb +68 -60
  84. data/test/activesupport5/encoding_test.rb +111 -96
  85. data/test/activesupport5/encoding_test_cases.rb +33 -25
  86. data/test/activesupport5/test_helper.rb +43 -21
  87. data/test/activesupport5/time_zone_test_helpers.rb +18 -3
  88. data/test/activesupport6/abstract_unit.rb +44 -0
  89. data/test/activesupport6/decoding_test.rb +133 -0
  90. data/test/activesupport6/encoding_test.rb +507 -0
  91. data/test/activesupport6/encoding_test_cases.rb +98 -0
  92. data/test/activesupport6/test_common.rb +17 -0
  93. data/test/activesupport6/test_helper.rb +163 -0
  94. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  95. data/test/activesupport7/abstract_unit.rb +49 -0
  96. data/test/activesupport7/decoding_test.rb +125 -0
  97. data/test/activesupport7/encoding_test.rb +486 -0
  98. data/test/activesupport7/encoding_test_cases.rb +104 -0
  99. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  100. data/test/bar.rb +6 -12
  101. data/test/baz.rb +16 -0
  102. data/test/bug.rb +16 -0
  103. data/test/foo.rb +69 -75
  104. data/test/helper.rb +16 -0
  105. data/test/json_gem/json_common_interface_test.rb +8 -3
  106. data/test/json_gem/json_generator_test.rb +18 -4
  107. data/test/json_gem/json_parser_test.rb +9 -0
  108. data/test/json_gem/test_helper.rb +12 -0
  109. data/test/mem.rb +33 -0
  110. data/test/perf.rb +1 -1
  111. data/test/perf_dump.rb +50 -0
  112. data/test/perf_once.rb +58 -0
  113. data/test/perf_parser.rb +189 -0
  114. data/test/perf_scp.rb +11 -10
  115. data/test/perf_strict.rb +17 -23
  116. data/test/prec.rb +23 -0
  117. data/test/sample_json.rb +1 -1
  118. data/test/test_compat.rb +46 -10
  119. data/test/test_custom.rb +147 -8
  120. data/test/test_fast.rb +62 -2
  121. data/test/test_file.rb +25 -2
  122. data/test/test_gc.rb +13 -0
  123. data/test/test_generate.rb +21 -0
  124. data/test/test_hash.rb +11 -1
  125. data/test/test_integer_range.rb +7 -2
  126. data/test/test_object.rb +85 -9
  127. data/test/test_parser.rb +27 -0
  128. data/test/test_parser_saj.rb +335 -0
  129. data/test/test_parser_usual.rb +217 -0
  130. data/test/test_rails.rb +35 -0
  131. data/test/test_saj.rb +1 -1
  132. data/test/test_scp.rb +5 -5
  133. data/test/test_strict.rb +26 -1
  134. data/test/test_various.rb +87 -65
  135. data/test/test_wab.rb +2 -0
  136. data/test/test_writer.rb +19 -2
  137. data/test/tests.rb +1 -1
  138. data/test/zoo.rb +13 -0
  139. metadata +60 -110
  140. data/ext/oj/hash.c +0 -163
  141. data/ext/oj/hash.h +0 -46
  142. data/ext/oj/hash_test.c +0 -512
data/ext/oj/strict.c CHANGED
@@ -1,210 +1,219 @@
1
- /* strict.c
2
- * Copyright (c) 2012, Peter Ohler
3
- * All rights reserved.
4
- */
1
+ // Copyright (c) 2012 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
5
3
 
6
- #include <stdlib.h>
7
4
  #include <stdio.h>
5
+ #include <stdlib.h>
8
6
  #include <string.h>
9
7
  #include <unistd.h>
10
8
 
11
- #include "oj.h"
9
+ #include "encode.h"
12
10
  #include "err.h"
11
+ #include "intern.h"
12
+ #include "oj.h"
13
13
  #include "parse.h"
14
- #include "encode.h"
15
14
  #include "trace.h"
16
15
 
17
- static void
18
- hash_end(struct _ParseInfo *pi) {
19
- if (Yes == pi->options.trace) {
20
- oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
16
+ VALUE oj_cstr_to_value(const char *str, size_t len, size_t cache_str) {
17
+ volatile VALUE rstr = Qnil;
18
+
19
+ if (len < cache_str) {
20
+ rstr = oj_str_intern(str, len);
21
+ } else {
22
+ rstr = rb_str_new(str, len);
23
+ rstr = oj_encode(rstr);
21
24
  }
25
+ return rstr;
22
26
  }
23
27
 
24
- static void
25
- array_end(struct _ParseInfo *pi) {
26
- if (Yes == pi->options.trace) {
27
- oj_trace_parse_array_end(pi, __FILE__, __LINE__);
28
+ VALUE oj_calc_hash_key(ParseInfo pi, Val parent) {
29
+ volatile VALUE rkey = parent->key_val;
30
+
31
+ if (Qundef != rkey) {
32
+ return rkey;
28
33
  }
34
+ if (Yes != pi->options.cache_keys) {
35
+ if (Yes == pi->options.sym_key) {
36
+ rkey = ID2SYM(rb_intern3(parent->key, parent->klen, oj_utf8_encoding));
37
+ } else {
38
+ rkey = rb_str_new(parent->key, parent->klen);
39
+ rkey = oj_encode(rkey);
40
+ OBJ_FREEZE(rkey); // frozen when used as a Hash key anyway
41
+ }
42
+ return rkey;
43
+ }
44
+ if (Yes == pi->options.sym_key) {
45
+ rkey = oj_sym_intern(parent->key, parent->klen);
46
+ } else {
47
+ rkey = oj_str_intern(parent->key, parent->klen);
48
+ }
49
+ return rkey;
29
50
  }
30
51
 
31
- static VALUE
32
- noop_hash_key(struct _ParseInfo *pi, const char *key, size_t klen) {
52
+ static void hash_end(ParseInfo pi) {
53
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
54
+ oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
55
+ }
56
+ }
57
+
58
+ static void array_end(ParseInfo pi) {
59
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
60
+ oj_trace_parse_array_end(pi, __FILE__, __LINE__);
61
+ }
62
+ }
63
+
64
+ static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
33
65
  return Qundef;
34
66
  }
35
67
 
36
- static void
37
- add_value(ParseInfo pi, VALUE val) {
38
- if (Yes == pi->options.trace) {
39
- oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val);
68
+ static void add_value(ParseInfo pi, VALUE val) {
69
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
70
+ oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val);
40
71
  }
41
72
  pi->stack.head->val = val;
42
73
  }
43
74
 
44
- static void
45
- add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
46
- volatile VALUE rstr = rb_str_new(str, len);
75
+ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
76
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
47
77
 
48
- rstr = oj_encode(rstr);
49
78
  pi->stack.head->val = rstr;
50
- if (Yes == pi->options.trace) {
51
- oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
79
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
80
+ oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
52
81
  }
53
82
  }
54
83
 
55
- static void
56
- add_num(ParseInfo pi, NumInfo ni) {
84
+ static void add_num(ParseInfo pi, NumInfo ni) {
57
85
  if (ni->infinity || ni->nan) {
58
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
86
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
59
87
  }
60
88
  pi->stack.head->val = oj_num_as_value(ni);
61
- if (Yes == pi->options.trace) {
62
- oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
89
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
90
+ oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
63
91
  }
64
92
  }
65
93
 
66
- static VALUE
67
- start_hash(ParseInfo pi) {
94
+ static VALUE start_hash(ParseInfo pi) {
68
95
  if (Qnil != pi->options.hash_class) {
69
- return rb_class_new_instance(0, NULL, pi->options.hash_class);
96
+ return rb_class_new_instance(0, NULL, pi->options.hash_class);
70
97
  }
71
- if (Yes == pi->options.trace) {
72
- oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
98
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
99
+ oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
73
100
  }
74
101
  return rb_hash_new();
75
102
  }
76
103
 
77
- static VALUE
78
- calc_hash_key(ParseInfo pi, Val parent) {
79
- volatile VALUE rkey = parent->key_val;
104
+ static void hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) {
105
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
80
106
 
81
- if (Qundef == rkey) {
82
- rkey = rb_str_new(parent->key, parent->klen);
107
+ rb_hash_aset(stack_peek(&pi->stack)->val,
108
+ oj_calc_hash_key(pi, parent),
109
+ rstr);
110
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
111
+ oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
83
112
  }
84
- rkey = oj_encode(rkey);
85
- if (Yes == pi->options.sym_key) {
86
- rkey = rb_str_intern(rkey);
87
- }
88
- return rkey;
89
113
  }
90
114
 
91
- static void
92
- hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) {
93
- volatile VALUE rstr = rb_str_new(str, len);
94
-
95
- rstr = oj_encode(rstr);
96
- rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rstr);
97
- if (Yes == pi->options.trace) {
98
- oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
99
- }
100
- }
115
+ static void hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
116
+ volatile VALUE v;
101
117
 
102
- static void
103
- hash_set_num(struct _ParseInfo *pi, Val parent, NumInfo ni) {
104
- volatile VALUE v;
105
-
106
118
  if (ni->infinity || ni->nan) {
107
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
119
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
108
120
  }
109
121
  v = oj_num_as_value(ni);
110
- rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), v);
111
- if (Yes == pi->options.trace) {
112
- oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, v);
122
+ rb_hash_aset(stack_peek(&pi->stack)->val,
123
+ oj_calc_hash_key(pi, parent),
124
+ v);
125
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
126
+ oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, v);
113
127
  }
114
128
  }
115
129
 
116
- static void
117
- hash_set_value(ParseInfo pi, Val parent, VALUE value) {
118
- rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value);
119
- if (Yes == pi->options.trace) {
120
- oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
130
+ static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
131
+ rb_hash_aset(stack_peek(&pi->stack)->val,
132
+ oj_calc_hash_key(pi, parent),
133
+ value);
134
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
135
+ oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
121
136
  }
122
137
  }
123
138
 
124
- static VALUE
125
- start_array(ParseInfo pi) {
126
- if (Yes == pi->options.trace) {
127
- oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
139
+ static VALUE start_array(ParseInfo pi) {
140
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
141
+ oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
128
142
  }
129
143
  return rb_ary_new();
130
144
  }
131
145
 
132
- static void
133
- array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
134
- volatile VALUE rstr = rb_str_new(str, len);
146
+ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
147
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
135
148
 
136
- rstr = oj_encode(rstr);
137
149
  rb_ary_push(stack_peek(&pi->stack)->val, rstr);
138
- if (Yes == pi->options.trace) {
139
- oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
150
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
151
+ oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
140
152
  }
141
153
  }
142
154
 
143
- static void
144
- array_append_num(ParseInfo pi, NumInfo ni) {
145
- volatile VALUE v;
146
-
155
+ static void array_append_num(ParseInfo pi, NumInfo ni) {
156
+ volatile VALUE v;
157
+
147
158
  if (ni->infinity || ni->nan) {
148
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
159
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
149
160
  }
150
161
  v = oj_num_as_value(ni);
151
162
  rb_ary_push(stack_peek(&pi->stack)->val, v);
152
- if (Yes == pi->options.trace) {
153
- oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, v);
163
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
164
+ oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, v);
154
165
  }
155
166
  }
156
167
 
157
- static void
158
- array_append_value(ParseInfo pi, VALUE value) {
168
+ static void array_append_value(ParseInfo pi, VALUE value) {
159
169
  rb_ary_push(stack_peek(&pi->stack)->val, value);
160
- if (Yes == pi->options.trace) {
161
- oj_trace_parse_call("append_value", pi, __FILE__, __LINE__, value);
162
- }
163
- }
164
-
165
- void
166
- oj_set_strict_callbacks(ParseInfo pi) {
167
- pi->start_hash = start_hash;
168
- pi->end_hash = hash_end;
169
- pi->hash_key = noop_hash_key;
170
- pi->hash_set_cstr = hash_set_cstr;
171
- pi->hash_set_num = hash_set_num;
172
- pi->hash_set_value = hash_set_value;
173
- pi->start_array = start_array;
174
- pi->end_array = array_end;
175
- pi->array_append_cstr = array_append_cstr;
176
- pi->array_append_num = array_append_num;
170
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
171
+ oj_trace_parse_call("append_value", pi, __FILE__, __LINE__, value);
172
+ }
173
+ }
174
+
175
+ void oj_set_strict_callbacks(ParseInfo pi) {
176
+ pi->start_hash = start_hash;
177
+ pi->end_hash = hash_end;
178
+ pi->hash_key = noop_hash_key;
179
+ pi->hash_set_cstr = hash_set_cstr;
180
+ pi->hash_set_num = hash_set_num;
181
+ pi->hash_set_value = hash_set_value;
182
+ pi->start_array = start_array;
183
+ pi->end_array = array_end;
184
+ pi->array_append_cstr = array_append_cstr;
185
+ pi->array_append_num = array_append_num;
177
186
  pi->array_append_value = array_append_value;
178
- pi->add_cstr = add_cstr;
179
- pi->add_num = add_num;
180
- pi->add_value = add_value;
181
- pi->expect_value = 1;
187
+ pi->add_cstr = add_cstr;
188
+ pi->add_num = add_num;
189
+ pi->add_value = add_value;
190
+ pi->expect_value = 1;
182
191
  }
183
192
 
184
193
  VALUE
185
194
  oj_strict_parse(int argc, VALUE *argv, VALUE self) {
186
- struct _ParseInfo pi;
195
+ struct _parseInfo pi;
187
196
 
188
197
  parse_info_init(&pi);
189
- pi.options = oj_default_options;
190
- pi.handler = Qnil;
198
+ pi.options = oj_default_options;
199
+ pi.handler = Qnil;
191
200
  pi.err_class = Qnil;
192
201
  oj_set_strict_callbacks(&pi);
193
202
 
194
203
  if (T_STRING == rb_type(*argv)) {
195
- return oj_pi_parse(argc, argv, &pi, 0, 0, true);
204
+ return oj_pi_parse(argc, argv, &pi, 0, 0, true);
196
205
  } else {
197
- return oj_pi_sparse(argc, argv, &pi, 0);
206
+ return oj_pi_sparse(argc, argv, &pi, 0);
198
207
  }
199
208
  }
200
209
 
201
210
  VALUE
202
211
  oj_strict_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
203
- struct _ParseInfo pi;
212
+ struct _parseInfo pi;
204
213
 
205
214
  parse_info_init(&pi);
206
- pi.options = oj_default_options;
207
- pi.handler = Qnil;
215
+ pi.options = oj_default_options;
216
+ pi.handler = Qnil;
208
217
  pi.err_class = Qnil;
209
218
  oj_set_strict_callbacks(&pi);
210
219