oj 3.7.4 → 3.13.23

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 (147) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1360 -0
  3. data/README.md +31 -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 +790 -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 +1073 -1088
  29. data/ext/oj/intern.c +298 -0
  30. data/ext/oj/intern.h +26 -0
  31. data/ext/oj/mimic_json.c +469 -436
  32. data/ext/oj/object.c +532 -599
  33. data/ext/oj/odd.c +154 -138
  34. data/ext/oj/odd.h +37 -38
  35. data/ext/oj/oj.c +1333 -986
  36. data/ext/oj/oj.h +336 -316
  37. data/ext/oj/parse.c +1002 -846
  38. data/ext/oj/parse.h +92 -87
  39. data/ext/oj/parser.c +1587 -0
  40. data/ext/oj/parser.h +102 -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 +596 -0
  51. data/ext/oj/saj2.h +23 -0
  52. data/ext/oj/scp.c +88 -113
  53. data/ext/oj/sparse.c +787 -709
  54. data/ext/oj/stream_writer.c +133 -159
  55. data/ext/oj/strict.c +127 -118
  56. data/ext/oj/string_writer.c +230 -249
  57. data/ext/oj/trace.c +34 -41
  58. data/ext/oj/trace.h +19 -19
  59. data/ext/oj/usual.c +1207 -0
  60. data/ext/oj/usual.h +68 -0
  61. data/ext/oj/util.c +136 -0
  62. data/ext/oj/util.h +20 -0
  63. data/ext/oj/val_stack.c +60 -68
  64. data/ext/oj/val_stack.h +91 -129
  65. data/ext/oj/validate.c +46 -0
  66. data/ext/oj/wab.c +342 -353
  67. data/lib/oj/bag.rb +1 -0
  68. data/lib/oj/easy_hash.rb +5 -4
  69. data/lib/oj/error.rb +1 -1
  70. data/lib/oj/json.rb +1 -1
  71. data/lib/oj/mimic.rb +48 -14
  72. data/lib/oj/saj.rb +20 -6
  73. data/lib/oj/state.rb +9 -8
  74. data/lib/oj/version.rb +2 -2
  75. data/lib/oj.rb +0 -8
  76. data/pages/Compatibility.md +1 -1
  77. data/pages/JsonGem.md +15 -0
  78. data/pages/Modes.md +53 -46
  79. data/pages/Options.md +78 -11
  80. data/pages/Parser.md +309 -0
  81. data/pages/Rails.md +73 -22
  82. data/pages/Security.md +1 -1
  83. data/test/activerecord/result_test.rb +7 -2
  84. data/test/activesupport5/abstract_unit.rb +45 -0
  85. data/test/activesupport5/decoding_test.rb +68 -60
  86. data/test/activesupport5/encoding_test.rb +111 -96
  87. data/test/activesupport5/encoding_test_cases.rb +33 -25
  88. data/test/activesupport5/test_helper.rb +43 -21
  89. data/test/activesupport5/time_zone_test_helpers.rb +18 -3
  90. data/test/activesupport6/abstract_unit.rb +44 -0
  91. data/test/activesupport6/decoding_test.rb +133 -0
  92. data/test/activesupport6/encoding_test.rb +507 -0
  93. data/test/activesupport6/encoding_test_cases.rb +98 -0
  94. data/test/activesupport6/test_common.rb +17 -0
  95. data/test/activesupport6/test_helper.rb +163 -0
  96. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  97. data/test/activesupport7/abstract_unit.rb +49 -0
  98. data/test/activesupport7/decoding_test.rb +125 -0
  99. data/test/activesupport7/encoding_test.rb +486 -0
  100. data/test/activesupport7/encoding_test_cases.rb +104 -0
  101. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  102. data/test/bar.rb +6 -12
  103. data/test/baz.rb +16 -0
  104. data/test/bug.rb +16 -0
  105. data/test/foo.rb +69 -75
  106. data/test/helper.rb +16 -0
  107. data/test/json_gem/json_common_interface_test.rb +8 -3
  108. data/test/json_gem/json_generator_test.rb +21 -8
  109. data/test/json_gem/json_parser_test.rb +8 -1
  110. data/test/json_gem/test_helper.rb +12 -0
  111. data/test/mem.rb +33 -0
  112. data/test/perf.rb +1 -1
  113. data/test/perf_dump.rb +50 -0
  114. data/test/perf_once.rb +58 -0
  115. data/test/perf_parser.rb +189 -0
  116. data/test/perf_scp.rb +11 -10
  117. data/test/perf_strict.rb +17 -23
  118. data/test/prec.rb +23 -0
  119. data/test/sample_json.rb +1 -1
  120. data/test/test_compat.rb +46 -10
  121. data/test/test_custom.rb +145 -7
  122. data/test/test_fast.rb +62 -2
  123. data/test/test_file.rb +23 -7
  124. data/test/test_gc.rb +11 -0
  125. data/test/test_generate.rb +21 -0
  126. data/test/test_hash.rb +11 -1
  127. data/test/test_integer_range.rb +1 -2
  128. data/test/test_object.rb +43 -12
  129. data/test/test_parser.rb +11 -0
  130. data/test/test_parser_debug.rb +27 -0
  131. data/test/test_parser_saj.rb +335 -0
  132. data/test/test_parser_usual.rb +217 -0
  133. data/test/test_rails.rb +35 -0
  134. data/test/test_saj.rb +1 -1
  135. data/test/test_scp.rb +3 -5
  136. data/test/test_strict.rb +26 -1
  137. data/test/test_various.rb +86 -65
  138. data/test/test_wab.rb +2 -0
  139. data/test/test_writer.rb +19 -2
  140. data/test/tests.rb +10 -1
  141. data/test/tests_mimic.rb +9 -0
  142. data/test/tests_mimic_addition.rb +9 -0
  143. data/test/zoo.rb +13 -0
  144. metadata +63 -110
  145. data/ext/oj/hash.c +0 -163
  146. data/ext/oj/hash.h +0 -46
  147. data/ext/oj/hash_test.c +0 -512
data/ext/oj/object.c CHANGED
@@ -1,803 +1,736 @@
1
- /* object.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
 
4
+ #include <stdint.h>
6
5
  #include <stdio.h>
7
6
  #include <time.h>
8
7
 
9
- #include "oj.h"
8
+ #include "encode.h"
10
9
  #include "err.h"
10
+ #include "intern.h"
11
+ #include "odd.h"
12
+ #include "oj.h"
11
13
  #include "parse.h"
12
14
  #include "resolve.h"
13
- #include "hash.h"
14
- #include "odd.h"
15
- #include "encode.h"
16
15
  #include "trace.h"
16
+ #include "util.h"
17
17
 
18
- inline static long
19
- read_long(const char *str, size_t len) {
20
- long n = 0;
18
+ inline static long read_long(const char *str, size_t len) {
19
+ long n = 0;
21
20
 
22
21
  for (; 0 < len; str++, len--) {
23
- if ('0' <= *str && *str <= '9') {
24
- n = n * 10 + (*str - '0');
25
- } else {
26
- return -1;
27
- }
22
+ if ('0' <= *str && *str <= '9') {
23
+ n = n * 10 + (*str - '0');
24
+ } else {
25
+ return -1;
26
+ }
28
27
  }
29
28
  return n;
30
29
  }
31
30
 
32
- static VALUE
33
- calc_hash_key(ParseInfo pi, Val kval, char k1) {
34
- volatile VALUE rkey;
31
+ static VALUE calc_hash_key(ParseInfo pi, Val kval, char k1) {
32
+ volatile VALUE rkey;
35
33
 
36
34
  if (':' == k1) {
37
- rkey = rb_str_new(kval->key + 1, kval->klen - 1);
38
- rkey = oj_encode(rkey);
39
- rkey = rb_funcall(rkey, oj_to_sym_id, 0);
40
- } else {
41
- rkey = rb_str_new(kval->key, kval->klen);
42
- rkey = oj_encode(rkey);
43
- if (Yes == pi->options.sym_key) {
44
- rkey = rb_str_intern(rkey);
45
- }
35
+ return ID2SYM(rb_intern3(kval->key + 1, kval->klen - 1, oj_utf8_encoding));
46
36
  }
37
+ if (Yes == pi->options.sym_key) {
38
+ return ID2SYM(rb_intern3(kval->key, kval->klen, oj_utf8_encoding));
39
+ }
40
+ #if HAVE_RB_ENC_INTERNED_STR
41
+ rkey = rb_enc_interned_str(kval->key, kval->klen, oj_utf8_encoding);
42
+ #else
43
+ rkey = rb_utf8_str_new(kval->key, kval->klen);
44
+ OBJ_FREEZE(rkey);
45
+ #endif
47
46
  return rkey;
48
47
  }
49
48
 
50
- static VALUE
51
- str_to_value(ParseInfo pi, const char *str, size_t len, const char *orig) {
52
- volatile VALUE rstr = Qnil;
49
+ static VALUE str_to_value(ParseInfo pi, const char *str, size_t len, const char *orig) {
50
+ volatile VALUE rstr = Qnil;
53
51
 
54
52
  if (':' == *orig && 0 < len) {
55
- rstr = rb_str_new(str + 1, len - 1);
56
- rstr = oj_encode(rstr);
57
- rstr = rb_funcall(rstr, oj_to_sym_id, 0);
53
+ rstr = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding));
58
54
  } else if (pi->circ_array && 3 <= len && '^' == *orig && 'r' == orig[1]) {
59
- long i = read_long(str + 2, len - 2);
55
+ long i = read_long(str + 2, len - 2);
60
56
 
61
- if (0 > i) {
62
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a valid ID number");
63
- return Qnil;
64
- }
65
- rstr = oj_circ_array_get(pi->circ_array, i);
57
+ if (0 > i) {
58
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a valid ID number");
59
+ return Qnil;
60
+ }
61
+ rstr = oj_circ_array_get(pi->circ_array, i);
66
62
  } else {
67
- rstr = rb_str_new(str, len);
68
- rstr = oj_encode(rstr);
63
+ rstr = rb_utf8_str_new(str, len);
69
64
  }
70
65
  return rstr;
71
66
  }
72
67
 
73
- #if (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8)
74
- static VALUE
75
- oj_parse_xml_time(const char *str, int len) {
76
- return rb_funcall(rb_cTime, oj_parse_id, 1, rb_str_new(str, len));
77
- }
78
- #else
79
68
  // The much faster approach (4x faster)
80
- static int
81
- parse_num(const char *str, const char *end, int cnt) {
82
- int n = 0;
83
- char c;
84
- int i;
69
+ static int parse_num(const char *str, const char *end, int cnt) {
70
+ int n = 0;
71
+ char c;
72
+ int i;
85
73
 
86
74
  for (i = cnt; 0 < i; i--, str++) {
87
- c = *str;
88
- if (end <= str || c < '0' || '9' < c) {
89
- return -1;
90
- }
91
- n = n * 10 + (c - '0');
75
+ c = *str;
76
+ if (end <= str || c < '0' || '9' < c) {
77
+ return -1;
78
+ }
79
+ n = n * 10 + (c - '0');
92
80
  }
93
81
  return n;
94
82
  }
95
83
 
96
84
  VALUE
97
85
  oj_parse_xml_time(const char *str, int len) {
98
- VALUE args[8];
99
- const char *end = str + len;
100
- int n;
86
+ VALUE args[8];
87
+ const char *end = str + len;
88
+ int n;
101
89
 
102
90
  // year
103
91
  if (0 > (n = parse_num(str, end, 4))) {
104
- return Qnil;
92
+ return Qnil;
105
93
  }
106
94
  str += 4;
107
95
  args[0] = LONG2NUM(n);
108
96
  if ('-' != *str++) {
109
- return Qnil;
97
+ return Qnil;
110
98
  }
111
99
  // month
112
100
  if (0 > (n = parse_num(str, end, 2))) {
113
- return Qnil;
101
+ return Qnil;
114
102
  }
115
103
  str += 2;
116
104
  args[1] = LONG2NUM(n);
117
105
  if ('-' != *str++) {
118
- return Qnil;
106
+ return Qnil;
119
107
  }
120
108
  // day
121
109
  if (0 > (n = parse_num(str, end, 2))) {
122
- return Qnil;
110
+ return Qnil;
123
111
  }
124
112
  str += 2;
125
113
  args[2] = LONG2NUM(n);
126
114
  if ('T' != *str++) {
127
- return Qnil;
115
+ return Qnil;
128
116
  }
129
117
  // hour
130
118
  if (0 > (n = parse_num(str, end, 2))) {
131
- return Qnil;
119
+ return Qnil;
132
120
  }
133
121
  str += 2;
134
122
  args[3] = LONG2NUM(n);
135
123
  if (':' != *str++) {
136
- return Qnil;
124
+ return Qnil;
137
125
  }
138
126
  // minute
139
127
  if (0 > (n = parse_num(str, end, 2))) {
140
- return Qnil;
128
+ return Qnil;
141
129
  }
142
130
  str += 2;
143
131
  args[4] = LONG2NUM(n);
144
132
  if (':' != *str++) {
145
- return Qnil;
133
+ return Qnil;
146
134
  }
147
135
  // second
148
136
  if (0 > (n = parse_num(str, end, 2))) {
149
- return Qnil;
137
+ return Qnil;
150
138
  }
151
139
  str += 2;
152
140
  if (str == end) {
153
- args[5] = LONG2NUM(n);
154
- args[6] = LONG2NUM(0);
141
+ args[5] = LONG2NUM(n);
142
+ args[6] = LONG2NUM(0);
155
143
  } else {
156
- char c = *str++;
157
-
158
- if ('.' == c) {
159
- long long nsec = 0;
160
-
161
- for (; str < end; str++) {
162
- c = *str;
163
- if (c < '0' || '9' < c) {
164
- str++;
165
- break;
166
- }
167
- nsec = nsec * 10 + (c - '0');
168
- }
169
- args[5] = rb_float_new((double)n + ((double)nsec + 0.5) / 1000000000.0);
170
- } else {
171
- args[5] = rb_ll2inum(n);
172
- }
173
- if (end < str) {
174
- args[6] = LONG2NUM(0);
175
- } else {
176
- if ('Z' == c) {
177
- return rb_funcall2(rb_cTime, oj_utc_id, 6, args);
178
- } else if ('+' == c) {
179
- int hr = parse_num(str, end, 2);
180
- int min;
181
-
182
- str += 2;
183
- if (0 > hr || ':' != *str++) {
184
- return Qnil;
185
- }
186
- min = parse_num(str, end, 2);
187
- if (0 > min) {
188
- return Qnil;
189
- }
190
- args[6] = LONG2NUM(hr * 3600 + min * 60);
191
- } else if ('-' == c) {
192
- int hr = parse_num(str, end, 2);
193
- int min;
194
-
195
- str += 2;
196
- if (0 > hr || ':' != *str++) {
197
- return Qnil;
198
- }
199
- min = parse_num(str, end, 2);
200
- if (0 > min) {
201
- return Qnil;
202
- }
203
- args[6] = LONG2NUM(-(hr * 3600 + min * 60));
204
- } else {
205
- args[6] = LONG2NUM(0);
206
- }
207
- }
144
+ char c = *str++;
145
+
146
+ if ('.' == c) {
147
+ long long nsec = 0;
148
+
149
+ for (; str < end; str++) {
150
+ c = *str;
151
+ if (c < '0' || '9' < c) {
152
+ str++;
153
+ break;
154
+ }
155
+ nsec = nsec * 10 + (c - '0');
156
+ }
157
+ args[5] = rb_float_new((double)n + ((double)nsec + 0.5) / 1000000000.0);
158
+ } else {
159
+ args[5] = rb_ll2inum(n);
160
+ }
161
+ if (end < str) {
162
+ args[6] = LONG2NUM(0);
163
+ } else {
164
+ if ('Z' == c) {
165
+ return rb_funcall2(rb_cTime, oj_utc_id, 6, args);
166
+ } else if ('+' == c) {
167
+ int hr = parse_num(str, end, 2);
168
+ int min;
169
+
170
+ str += 2;
171
+ if (0 > hr || ':' != *str++) {
172
+ return Qnil;
173
+ }
174
+ min = parse_num(str, end, 2);
175
+ if (0 > min) {
176
+ return Qnil;
177
+ }
178
+ args[6] = LONG2NUM(hr * 3600 + min * 60);
179
+ } else if ('-' == c) {
180
+ int hr = parse_num(str, end, 2);
181
+ int min;
182
+
183
+ str += 2;
184
+ if (0 > hr || ':' != *str++) {
185
+ return Qnil;
186
+ }
187
+ min = parse_num(str, end, 2);
188
+ if (0 > min) {
189
+ return Qnil;
190
+ }
191
+ args[6] = LONG2NUM(-(hr * 3600 + min * 60));
192
+ } else {
193
+ args[6] = LONG2NUM(0);
194
+ }
195
+ }
208
196
  }
209
197
  return rb_funcall2(rb_cTime, oj_new_id, 7, args);
210
198
  }
211
- #endif
212
199
 
213
- static int
214
- hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t len) {
215
- const char *key = kval->key;
216
- int klen = kval->klen;
200
+ static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t len) {
201
+ const char *key = kval->key;
202
+ int klen = kval->klen;
217
203
 
218
204
  if (2 == klen) {
219
- switch (key[1]) {
220
- case 'o': // object
221
- { // name2class sets an error if the class is not found or created
222
- VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError);
223
-
224
- if (Qundef != clas) {
225
- parent->val = rb_obj_alloc(clas);
226
- }
227
- }
228
- break;
229
- case 'O': // odd object
230
- {
231
- Odd odd = oj_get_oddc(str, len);
232
-
233
- if (0 == odd) {
234
- return 0;
235
- }
236
- parent->val = odd->clas;
237
- parent->odd_args = oj_odd_alloc_args(odd);
238
- }
239
- break;
240
- case 'm':
241
- parent->val = rb_str_new(str + 1, len - 1);
242
- parent->val = oj_encode(parent->val);
243
- parent->val = rb_funcall(parent->val, oj_to_sym_id, 0);
244
- break;
245
- case 's':
246
- parent->val = rb_str_new(str, len);
247
- parent->val = oj_encode(parent->val);
248
- break;
249
- case 'c': // class
250
- {
251
- VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError);
252
-
253
- if (Qundef == clas) {
254
- return 0;
255
- } else {
256
- parent->val = clas;
257
- }
258
- }
259
- break;
260
- case 't': // time
261
- parent->val = oj_parse_xml_time(str, (int)len);
262
- break;
263
- default:
264
- return 0;
265
- break;
266
- }
267
- return 1; // handled
205
+ switch (key[1]) {
206
+ case 'o': // object
207
+ { // name2class sets an error if the class is not found or created
208
+ VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError);
209
+
210
+ if (Qundef != clas) {
211
+ parent->val = rb_obj_alloc(clas);
212
+ }
213
+ } break;
214
+ case 'O': // odd object
215
+ {
216
+ Odd odd = oj_get_oddc(str, len);
217
+
218
+ if (0 == odd) {
219
+ return 0;
220
+ }
221
+ parent->val = odd->clas;
222
+ parent->odd_args = oj_odd_alloc_args(odd);
223
+ break;
224
+ }
225
+ case 'm': parent->val = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding)); break;
226
+ case 's': parent->val = rb_utf8_str_new(str, len); break;
227
+ case 'c': // class
228
+ {
229
+ VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError);
230
+
231
+ if (Qundef == clas) {
232
+ return 0;
233
+ } else {
234
+ parent->val = clas;
235
+ }
236
+ break;
237
+ }
238
+ case 't': // time
239
+ parent->val = oj_parse_xml_time(str, (int)len);
240
+ break;
241
+ default: return 0; break;
242
+ }
243
+ return 1; // handled
268
244
  }
269
245
  return 0;
270
246
  }
271
247
 
272
- static int
273
- hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
248
+ static int hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
274
249
  if (2 == kval->klen) {
275
- switch (kval->key[1]) {
276
- case 't': // time as a float
277
- {
278
- int64_t nsec = ni->num * 1000000000LL / ni->div;
279
-
280
- if (ni->neg) {
281
- ni->i = -ni->i;
282
- if (0 < nsec) {
283
- ni->i--;
284
- nsec = 1000000000LL - nsec;
285
- }
286
- }
287
- if (86400 == ni->exp) { // UTC time
288
- parent->val = rb_time_nano_new(ni->i, (long)nsec);
289
- // Since the ruby C routines alway create local time, the
290
- // offset and then a conversion to UTC keeps makes the time
291
- // match the expected value.
292
- parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
293
- } else if (ni->hasExp) {
294
- time_t t = (time_t)(ni->i + ni->exp);
295
- struct tm *st = gmtime(&t);
296
- VALUE args[8];
297
-
298
- // Windows does not support dates before 1970 so ignore
299
- // the zone and do the best we can.
300
- if (NULL == st) {
301
- parent->val = rb_time_nano_new(ni->i, (long)nsec);
302
- } else {
303
- args[0] = LONG2NUM((long)(1900 + st->tm_year));
304
- args[1] = LONG2NUM(1 + st->tm_mon);
305
- args[2] = LONG2NUM(st->tm_mday);
306
- args[3] = LONG2NUM(st->tm_hour);
307
- args[4] = LONG2NUM(st->tm_min);
308
- args[5] = rb_float_new((double)st->tm_sec + ((double)nsec + 0.5) / 1000000000.0);
309
- args[6] = LONG2NUM(ni->exp);
310
- parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
311
- }
312
- } else {
313
- parent->val = rb_time_nano_new(ni->i, (long)nsec);
314
- }
315
- }
316
- break;
317
- case 'i': // circular index
318
- if (!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
319
- if (Qnil == parent->val) {
320
- parent->val = rb_hash_new();
321
- }
322
- oj_circ_array_set(pi->circ_array, parent->val, ni->i);
323
- } else {
324
- return 0;
325
- }
326
- break;
327
- default:
328
- return 0;
329
- break;
330
- }
331
- return 1; // handled
250
+ switch (kval->key[1]) {
251
+ case 't': // time as a float
252
+ if (0 == ni->div || 9 < ni->di) {
253
+ rb_raise(rb_eArgError, "Invalid time decimal representation.");
254
+ // parent->val = rb_time_nano_new(0, 0);
255
+ } else {
256
+ int64_t nsec = ni->num * 1000000000LL / ni->div;
257
+
258
+ if (ni->neg) {
259
+ ni->i = -ni->i;
260
+ if (0 < nsec) {
261
+ ni->i--;
262
+ nsec = 1000000000LL - nsec;
263
+ }
264
+ }
265
+ if (86400 == ni->exp) { // UTC time
266
+ parent->val = rb_time_nano_new(ni->i, (long)nsec);
267
+ // Since the ruby C routines always create local time, the
268
+ // offset and then a conversion to UTC keeps makes the time
269
+ // match the expected value.
270
+ parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
271
+ } else if (ni->has_exp) {
272
+ struct timespec ts;
273
+ ts.tv_sec = ni->i;
274
+ ts.tv_nsec = nsec;
275
+ parent->val = rb_time_timespec_new(&ts, (int)ni->exp);
276
+ } else {
277
+ parent->val = rb_time_nano_new(ni->i, (long)nsec);
278
+ }
279
+ }
280
+ break;
281
+ case 'i': // circular index
282
+ if (!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
283
+ if (Qnil == parent->val) {
284
+ parent->val = rb_hash_new();
285
+ }
286
+ oj_circ_array_set(pi->circ_array, parent->val, ni->i);
287
+ } else {
288
+ return 0;
289
+ }
290
+ break;
291
+ default: return 0; break;
292
+ }
293
+ return 1; // handled
332
294
  }
333
295
  return 0;
334
296
  }
335
297
 
336
- static int
337
- hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, volatile VALUE value) {
298
+ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, volatile VALUE value) {
338
299
  if (T_ARRAY == rb_type(value)) {
339
- int len = (int)RARRAY_LEN(value);
340
-
341
- if (2 == klen && 'u' == key[1]) {
342
- volatile VALUE sc;
343
- volatile VALUE e1;
344
- int slen;
345
-
346
- if (0 == len) {
347
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
348
- return 1;
349
- }
350
- e1 = *RARRAY_PTR(value);
351
- // check for anonymous Struct
352
- if (T_ARRAY == rb_type(e1)) {
353
- VALUE args[1024];
354
- volatile VALUE rstr;
355
- int i, cnt = (int)RARRAY_LEN(e1);
356
-
357
- for (i = 0; i < cnt; i++) {
358
- rstr = rb_ary_entry(e1, i);
359
- args[i] = rb_funcall(rstr, oj_to_sym_id, 0);
360
- }
361
- sc = rb_funcall2(rb_cStruct, oj_new_id, cnt, args);
362
- } else {
363
- // If struct is not defined then we let this fail and raise an exception.
364
- sc = oj_name2struct(pi, *RARRAY_PTR(value), rb_eArgError);
365
- }
366
- // Create a properly initialized struct instance without calling the initialize method.
367
- parent->val = rb_obj_alloc(sc);
368
- // If the JSON array has more entries than the struct class allows, we record an error.
300
+ int len = (int)RARRAY_LEN(value);
301
+
302
+ if (2 == klen && 'u' == key[1]) {
303
+ volatile VALUE sc;
304
+ volatile VALUE e1;
305
+ int slen;
306
+
307
+ if (0 == len) {
308
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
309
+ return 1;
310
+ }
311
+ e1 = *RARRAY_PTR(value);
312
+ // check for anonymous Struct
313
+ if (T_ARRAY == rb_type(e1)) {
314
+ VALUE args[1024];
315
+ volatile VALUE rstr;
316
+ int i, cnt = (int)RARRAY_LEN(e1);
317
+
318
+ for (i = 0; i < cnt; i++) {
319
+ rstr = RARRAY_AREF(e1, i);
320
+ args[i] = rb_funcall(rstr, oj_to_sym_id, 0);
321
+ }
322
+ sc = rb_funcall2(rb_cStruct, oj_new_id, cnt, args);
323
+ } else {
324
+ // If struct is not defined then we let this fail and raise an exception.
325
+ sc = oj_name2struct(pi, *RARRAY_PTR(value), rb_eArgError);
326
+ }
327
+ if (sc == rb_cRange) {
328
+ parent->val = rb_class_new_instance(len - 1, RARRAY_PTR(value) + 1, rb_cRange);
329
+ } else {
330
+ // Create a properly initialized struct instance without calling the initialize method.
331
+ parent->val = rb_obj_alloc(sc);
332
+ // If the JSON array has more entries than the struct class allows, we record an error.
369
333
  #ifdef RSTRUCT_LEN
370
334
  #if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
371
- slen = (int)NUM2LONG(RSTRUCT_LEN(parent->val));
372
- #else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
373
- slen = (int)RSTRUCT_LEN(parent->val);
374
- #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
335
+ slen = (int)NUM2LONG(RSTRUCT_LEN(parent->val));
336
+ #else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
337
+ slen = (int)RSTRUCT_LEN(parent->val);
338
+ #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
375
339
  #else
376
- slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
340
+ slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
377
341
  #endif
378
- // MRI >= 1.9
379
- if (len - 1 > slen) {
380
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
381
- } else {
382
- int i;
383
-
384
- for (i = 0; i < len - 1; i++) {
385
- rb_struct_aset(parent->val, INT2FIX(i), RARRAY_PTR(value)[i + 1]);
386
- }
342
+ // MRI >= 1.9
343
+ if (len - 1 > slen) {
344
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
345
+ } else {
346
+ int i;
347
+
348
+ for (i = 0; i < len - 1; i++) {
349
+ rb_struct_aset(parent->val, INT2FIX(i), RARRAY_PTR(value)[i + 1]);
350
+ }
351
+ }
387
352
  }
388
- return 1;
389
- } else if (3 <= klen && '#' == key[1]) {
390
- volatile VALUE *a;
353
+ return 1;
354
+ } else if (3 <= klen && '#' == key[1]) {
355
+ volatile VALUE *a;
391
356
 
392
- if (2 != len) {
393
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
394
- return 1;
395
- }
396
- parent->val = rb_hash_new();
397
- a = RARRAY_PTR(value);
398
- rb_hash_aset(parent->val, *a, a[1]);
357
+ if (2 != len) {
358
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
359
+ return 1;
360
+ }
361
+ parent->val = rb_hash_new();
362
+ a = RARRAY_PTR(value);
363
+ rb_hash_aset(parent->val, *a, a[1]);
399
364
 
400
- return 1;
401
- }
365
+ return 1;
366
+ }
402
367
  }
403
368
  return 0;
404
369
  }
405
370
 
406
- static void
407
- copy_ivars(VALUE target, VALUE src) {
408
- volatile VALUE vars = rb_funcall(src, oj_instance_variables_id, 0);
409
- volatile VALUE *np = RARRAY_PTR(vars);
410
- ID vid;
411
- int i, cnt = (int)RARRAY_LEN(vars);
412
- const char *attr;
413
-
414
- for (i = cnt; 0 < i; i--, np++) {
415
- vid = rb_to_id(*np);
416
- attr = rb_id2name(vid);
417
- if ('@' == *attr) {
418
- rb_ivar_set(target, vid, rb_ivar_get(src, vid));
419
- }
371
+ void oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
372
+ if (kval->klen == 5 && strncmp("~mesg", kval->key, 5) == 0 && rb_obj_is_kind_of(parent->val, rb_eException)) {
373
+ parent->val = rb_funcall(parent->val, rb_intern("exception"), 1, value);
374
+ } else if (kval->klen == 3 && strncmp("~bt", kval->key, 3) == 0 && rb_obj_is_kind_of(parent->val, rb_eException)) {
375
+ rb_funcall(parent->val, rb_intern("set_backtrace"), 1, value);
376
+ } else {
377
+ rb_ivar_set(parent->val, oj_attr_intern(kval->key, kval->klen), value);
420
378
  }
421
379
  }
422
380
 
423
- void
424
- oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
425
- const char *key = kval->key;
426
- int klen = kval->klen;
427
- ID var_id;
428
- ID *slot;
429
-
430
- if ('~' == *key && Qtrue == rb_obj_is_kind_of(parent->val, rb_eException)) {
431
- if (5 == klen && 0 == strncmp("~mesg", key, klen)) {
432
- VALUE args[1];
433
- volatile VALUE prev = parent->val;
434
-
435
- args[0] = value;
436
- parent->val = rb_class_new_instance(1, args, rb_class_of(parent->val));
437
- copy_ivars(parent->val, prev);
438
- } else if (3 == klen && 0 == strncmp("~bt", key, klen)) {
439
- rb_funcall(parent->val, rb_intern("set_backtrace"), 1, value);
440
- }
441
- }
442
- #if HAVE_LIBPTHREAD
443
- pthread_mutex_lock(&oj_cache_mutex);
444
- #else
445
- rb_mutex_lock(oj_cache_mutex);
446
- #endif
447
- if (0 == (var_id = oj_attr_hash_get(key, klen, &slot))) {
448
- char attr[256];
449
-
450
- if ((int)sizeof(attr) <= klen + 2) {
451
- char *buf = ALLOC_N(char, klen + 2);
452
-
453
- if ('~' == *key) {
454
- strncpy(buf, key + 1, klen - 1);
455
- buf[klen - 1] = '\0';
456
- } else {
457
- *buf = '@';
458
- strncpy(buf + 1, key, klen);
459
- buf[klen + 1] = '\0';
460
- }
461
- var_id = rb_intern(buf);
462
- xfree(buf);
463
- } else {
464
- if ('~' == *key) {
465
- strncpy(attr, key + 1, klen - 1);
466
- attr[klen - 1] = '\0';
467
- } else {
468
- *attr = '@';
469
- strncpy(attr + 1, key, klen);
470
- attr[klen + 1] = '\0';
471
- }
472
- var_id = rb_intern(attr);
473
- }
474
- *slot = var_id;
475
- }
476
- #if HAVE_LIBPTHREAD
477
- pthread_mutex_unlock(&oj_cache_mutex);
478
- #else
479
- rb_mutex_unlock(oj_cache_mutex);
480
- #endif
481
- rb_ivar_set(parent->val, var_id, value);
482
- }
483
-
484
- static void
485
- hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
486
- const char *key = kval->key;
487
- int klen = kval->klen;
488
- Val parent = stack_peek(&pi->stack);
489
- volatile VALUE rval = Qnil;
381
+ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
382
+ const char *key = kval->key;
383
+ int klen = kval->klen;
384
+ Val parent = stack_peek(&pi->stack);
385
+ volatile VALUE rval = Qnil;
490
386
 
491
- WHICH_TYPE:
387
+ WHICH_TYPE:
492
388
  switch (rb_type(parent->val)) {
493
389
  case T_NIL:
494
- parent->odd_args = 0; // make sure it is 0 in case not odd
495
- if ('^' != *key || !hat_cstr(pi, parent, kval, str, len)) {
496
- parent->val = rb_hash_new();
497
- goto WHICH_TYPE;
498
- }
499
- break;
390
+ parent->odd_args = NULL; // make sure it is NULL in case not odd
391
+ if ('^' != *key || !hat_cstr(pi, parent, kval, str, len)) {
392
+ parent->val = rb_hash_new();
393
+ goto WHICH_TYPE;
394
+ }
395
+ break;
500
396
  case T_HASH:
501
- rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), str_to_value(pi, str, len, orig));
502
- break;
397
+ rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), str_to_value(pi, str, len, orig));
398
+ break;
503
399
  case T_STRING:
504
- rval = str_to_value(pi, str, len, orig);
505
- if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
506
- rb_funcall(parent->val, oj_replace_id, 1, rval);
507
- } else {
508
- oj_set_obj_ivar(parent, kval, rval);
509
- }
510
- break;
400
+ rval = str_to_value(pi, str, len, orig);
401
+ if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
402
+ rb_funcall(parent->val, oj_replace_id, 1, rval);
403
+ } else {
404
+ oj_set_obj_ivar(parent, kval, rval);
405
+ }
406
+ break;
511
407
  case T_OBJECT:
512
- rval = str_to_value(pi, str, len, orig);
513
- oj_set_obj_ivar(parent, kval, rval);
514
- break;
408
+ rval = str_to_value(pi, str, len, orig);
409
+ oj_set_obj_ivar(parent, kval, rval);
410
+ break;
515
411
  case T_CLASS:
516
- if (0 == parent->odd_args) {
517
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
518
- return;
519
- } else {
520
- rval = str_to_value(pi, str, len, orig);
521
- if (0 != oj_odd_set_arg(parent->odd_args, kval->key, kval->klen, rval)) {
522
- char buf[256];
523
-
524
- if ((int)sizeof(buf) - 1 <= klen) {
525
- klen = sizeof(buf) - 2;
526
- }
527
- memcpy(buf, key, klen);
528
- buf[klen] = '\0';
529
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val)));
530
- }
531
- }
532
- break;
412
+ if (NULL == parent->odd_args) {
413
+ oj_set_error_at(pi,
414
+ oj_parse_error_class,
415
+ __FILE__,
416
+ __LINE__,
417
+ "%s is not an odd class",
418
+ rb_class2name(rb_obj_class(parent->val)));
419
+ return;
420
+ } else {
421
+ rval = str_to_value(pi, str, len, orig);
422
+ if (0 != oj_odd_set_arg(parent->odd_args, kval->key, kval->klen, rval)) {
423
+ char buf[256];
424
+
425
+ if ((int)sizeof(buf) - 1 <= klen) {
426
+ klen = sizeof(buf) - 2;
427
+ }
428
+ memcpy(buf, key, klen);
429
+ buf[klen] = '\0';
430
+ oj_set_error_at(pi,
431
+ oj_parse_error_class,
432
+ __FILE__,
433
+ __LINE__,
434
+ "%s is not an attribute of %s",
435
+ buf,
436
+ rb_class2name(rb_obj_class(parent->val)));
437
+ }
438
+ }
439
+ break;
533
440
  default:
534
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val)));
535
- return;
441
+ oj_set_error_at(pi,
442
+ oj_parse_error_class,
443
+ __FILE__,
444
+ __LINE__,
445
+ "can not add attributes to a %s",
446
+ rb_class2name(rb_obj_class(parent->val)));
447
+ return;
536
448
  }
537
- if (Yes == pi->options.trace) {
538
- oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
449
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
450
+ oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
539
451
  }
540
452
  }
541
453
 
542
- static void
543
- hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
544
- const char *key = kval->key;
545
- int klen = kval->klen;
546
- Val parent = stack_peek(&pi->stack);
547
- volatile VALUE rval = Qnil;
454
+ static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
455
+ const char *key = kval->key;
456
+ int klen = kval->klen;
457
+ Val parent = stack_peek(&pi->stack);
458
+ volatile VALUE rval = Qnil;
548
459
 
549
- WHICH_TYPE:
460
+ WHICH_TYPE:
550
461
  switch (rb_type(parent->val)) {
551
462
  case T_NIL:
552
- parent->odd_args = 0; // make sure it is 0 in case not odd
553
- if ('^' != *key || !hat_num(pi, parent, kval, ni)) {
554
- parent->val = rb_hash_new();
555
- goto WHICH_TYPE;
556
- }
557
- break;
463
+ parent->odd_args = NULL; // make sure it is NULL in case not odd
464
+ if ('^' != *key || !hat_num(pi, parent, kval, ni)) {
465
+ parent->val = rb_hash_new();
466
+ goto WHICH_TYPE;
467
+ }
468
+ break;
558
469
  case T_HASH:
559
- rval = oj_num_as_value(ni);
560
- rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), rval);
561
- break;
470
+ rval = oj_num_as_value(ni);
471
+ rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), rval);
472
+ break;
562
473
  case T_OBJECT:
563
- if (2 == klen && '^' == *key && 'i' == key[1] &&
564
- !ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
565
- oj_circ_array_set(pi->circ_array, parent->val, ni->i);
566
- } else {
567
- rval = oj_num_as_value(ni);
568
- oj_set_obj_ivar(parent, kval, rval);
569
- }
570
- break;
474
+ if (2 == klen && '^' == *key && 'i' == key[1] && !ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp &&
475
+ 0 != pi->circ_array) { // fixnum
476
+ oj_circ_array_set(pi->circ_array, parent->val, ni->i);
477
+ } else {
478
+ rval = oj_num_as_value(ni);
479
+ oj_set_obj_ivar(parent, kval, rval);
480
+ }
481
+ break;
571
482
  case T_CLASS:
572
- if (0 == parent->odd_args) {
573
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
574
- return;
575
- } else {
576
- rval = oj_num_as_value(ni);
577
- if (0 != oj_odd_set_arg(parent->odd_args, key, klen, rval)) {
578
- char buf[256];
579
-
580
- if ((int)sizeof(buf) - 1 <= klen) {
581
- klen = sizeof(buf) - 2;
582
- }
583
- memcpy(buf, key, klen);
584
- buf[klen] = '\0';
585
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val)));
586
- }
587
- }
588
- break;
483
+ if (NULL == parent->odd_args) {
484
+ oj_set_error_at(pi,
485
+ oj_parse_error_class,
486
+ __FILE__,
487
+ __LINE__,
488
+ "%s is not an odd class",
489
+ rb_class2name(rb_obj_class(parent->val)));
490
+ return;
491
+ } else {
492
+ rval = oj_num_as_value(ni);
493
+ if (0 != oj_odd_set_arg(parent->odd_args, key, klen, rval)) {
494
+ char buf[256];
495
+
496
+ if ((int)sizeof(buf) - 1 <= klen) {
497
+ klen = sizeof(buf) - 2;
498
+ }
499
+ memcpy(buf, key, klen);
500
+ buf[klen] = '\0';
501
+ oj_set_error_at(pi,
502
+ oj_parse_error_class,
503
+ __FILE__,
504
+ __LINE__,
505
+ "%s is not an attribute of %s",
506
+ buf,
507
+ rb_class2name(rb_obj_class(parent->val)));
508
+ }
509
+ }
510
+ break;
589
511
  default:
590
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val)));
591
- return;
512
+ oj_set_error_at(pi,
513
+ oj_parse_error_class,
514
+ __FILE__,
515
+ __LINE__,
516
+ "can not add attributes to a %s",
517
+ rb_class2name(rb_obj_class(parent->val)));
518
+ return;
592
519
  }
593
- if (Yes == pi->options.trace) {
594
- oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, rval);
520
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
521
+ oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, rval);
595
522
  }
596
523
  }
597
524
 
598
- static void
599
- hash_set_value(ParseInfo pi, Val kval, VALUE value) {
600
- const char *key = kval->key;
601
- int klen = kval->klen;
602
- Val parent = stack_peek(&pi->stack);
525
+ static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
526
+ const char *key = kval->key;
527
+ int klen = kval->klen;
528
+ Val parent = stack_peek(&pi->stack);
603
529
 
604
- WHICH_TYPE:
530
+ WHICH_TYPE:
605
531
  switch (rb_type(parent->val)) {
606
532
  case T_NIL:
607
- parent->odd_args = 0; // make sure it is 0 in case not odd
608
- if ('^' != *key || !hat_value(pi, parent, key, klen, value)) {
609
- parent->val = rb_hash_new();
610
- goto WHICH_TYPE;
611
- }
612
- break;
533
+ parent->odd_args = NULL; // make sure it is NULL in case not odd
534
+ if ('^' != *key || !hat_value(pi, parent, key, klen, value)) {
535
+ parent->val = rb_hash_new();
536
+ goto WHICH_TYPE;
537
+ }
538
+ break;
613
539
  case T_HASH:
614
- if (rb_cHash != rb_obj_class(parent->val)) {
615
- if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
616
- rb_funcall(parent->val, oj_replace_id, 1, value);
617
- } else {
618
- oj_set_obj_ivar(parent, kval, value);
619
- }
620
- } else {
621
- if (3 <= klen && '^' == *key && '#' == key[1] && T_ARRAY == rb_type(value)) {
622
- long len = RARRAY_LEN(value);
623
- volatile VALUE *a = RARRAY_PTR(value);
624
-
625
- if (2 != len) {
626
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
627
- return;
628
- }
629
- rb_hash_aset(parent->val, *a, a[1]);
630
- } else {
631
- rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), value);
632
- }
633
- }
634
- break;
540
+ if (rb_cHash != rb_obj_class(parent->val)) {
541
+ if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
542
+ rb_funcall(parent->val, oj_replace_id, 1, value);
543
+ } else {
544
+ oj_set_obj_ivar(parent, kval, value);
545
+ }
546
+ } else {
547
+ if (3 <= klen && '^' == *key && '#' == key[1] && T_ARRAY == rb_type(value)) {
548
+ long len = RARRAY_LEN(value);
549
+ volatile VALUE *a = RARRAY_PTR(value);
550
+
551
+ if (2 != len) {
552
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
553
+ return;
554
+ }
555
+ rb_hash_aset(parent->val, *a, a[1]);
556
+ } else {
557
+ rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), value);
558
+ }
559
+ }
560
+ break;
635
561
  case T_ARRAY:
636
- if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
637
- rb_funcall(parent->val, oj_replace_id, 1, value);
638
- } else {
639
- oj_set_obj_ivar(parent, kval, value);
640
- }
641
- break;
642
- case T_STRING: // for subclassed strings
643
- case T_OBJECT:
644
- oj_set_obj_ivar(parent, kval, value);
645
- break;
562
+ if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
563
+ rb_funcall(parent->val, oj_replace_id, 1, value);
564
+ } else {
565
+ oj_set_obj_ivar(parent, kval, value);
566
+ }
567
+ break;
568
+ case T_STRING: // for subclassed strings
569
+ case T_OBJECT: oj_set_obj_ivar(parent, kval, value); break;
646
570
  case T_MODULE:
647
571
  case T_CLASS:
648
- if (0 == parent->odd_args) {
649
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
650
- return;
651
- } else if (0 != oj_odd_set_arg(parent->odd_args, key, klen, value)) {
652
- char buf[256];
653
-
654
- if ((int)sizeof(buf) - 1 <= klen) {
655
- klen = sizeof(buf) - 2;
656
- }
657
- memcpy(buf, key, klen);
658
- buf[klen] = '\0';
659
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val)));
660
- }
661
- break;
572
+ if (NULL == parent->odd_args) {
573
+ oj_set_error_at(pi,
574
+ oj_parse_error_class,
575
+ __FILE__,
576
+ __LINE__,
577
+ "%s is not an odd class",
578
+ rb_class2name(rb_obj_class(parent->val)));
579
+ return;
580
+ } else if (0 != oj_odd_set_arg(parent->odd_args, key, klen, value)) {
581
+ char buf[256];
582
+
583
+ if ((int)sizeof(buf) - 1 <= klen) {
584
+ klen = sizeof(buf) - 2;
585
+ }
586
+ memcpy(buf, key, klen);
587
+ buf[klen] = '\0';
588
+ oj_set_error_at(pi,
589
+ oj_parse_error_class,
590
+ __FILE__,
591
+ __LINE__,
592
+ "%s is not an attribute of %s",
593
+ buf,
594
+ rb_class2name(rb_obj_class(parent->val)));
595
+ }
596
+ break;
662
597
  default:
663
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val)));
664
- return;
598
+ oj_set_error_at(pi,
599
+ oj_parse_error_class,
600
+ __FILE__,
601
+ __LINE__,
602
+ "can not add attributes to a %s",
603
+ rb_class2name(rb_obj_class(parent->val)));
604
+ return;
665
605
  }
666
- if (Yes == pi->options.trace) {
667
- oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, value);
606
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
607
+ oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, value);
668
608
  }
669
609
  }
670
610
 
671
- static VALUE
672
- start_hash(ParseInfo pi) {
673
- if (Yes == pi->options.trace) {
674
- oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
611
+ static VALUE start_hash(ParseInfo pi) {
612
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
613
+ oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
675
614
  }
676
615
  return Qnil;
677
616
  }
678
617
 
679
- static void
680
- end_hash(struct _ParseInfo *pi) {
681
- Val parent = stack_peek(&pi->stack);
618
+ static void end_hash(ParseInfo pi) {
619
+ Val parent = stack_peek(&pi->stack);
682
620
 
683
621
  if (Qnil == parent->val) {
684
- parent->val = rb_hash_new();
685
- } else if (0 != parent->odd_args) {
686
- OddArgs oa = parent->odd_args;
622
+ parent->val = rb_hash_new();
623
+ } else if (NULL != parent->odd_args) {
624
+ OddArgs oa = parent->odd_args;
687
625
 
688
- parent->val = rb_funcall2(oa->odd->create_obj, oa->odd->create_op, oa->odd->attr_cnt, oa->args);
689
- oj_odd_free(oa);
690
- parent->odd_args = 0;
626
+ parent->val = rb_funcall2(oa->odd->create_obj, oa->odd->create_op, oa->odd->attr_cnt, oa->args);
627
+ oj_odd_free(oa);
628
+ parent->odd_args = NULL;
691
629
  }
692
- if (Yes == pi->options.trace) {
693
- oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
630
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
631
+ oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
694
632
  }
695
633
  }
696
634
 
697
- static void
698
- array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
699
- volatile VALUE rval = Qnil;
700
-
701
- if (3 <= len && 0 != pi->circ_array) {
702
- if ('i' == str[1]) {
703
- long i = read_long(str + 2, len - 2);
635
+ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
636
+ volatile VALUE rval = Qnil;
704
637
 
705
- if (0 < i) {
706
- oj_circ_array_set(pi->circ_array, stack_peek(&pi->stack)->val, i);
707
- return;
708
- }
709
- } else if ('r' == str[1]) {
710
- long i = read_long(str + 2, len - 2);
638
+ // orig lets us know whether the string was ^r1 or \u005er1
639
+ if (3 <= len && 0 != pi->circ_array && '^' == orig[0] && 0 == rb_array_len(stack_peek(&pi->stack)->val)) {
640
+ if ('i' == str[1]) {
641
+ long i = read_long(str + 2, len - 2);
711
642
 
712
- if (0 < i) {
713
- rb_ary_push(stack_peek(&pi->stack)->val, oj_circ_array_get(pi->circ_array, i));
714
- return;
715
- }
643
+ if (0 < i) {
644
+ oj_circ_array_set(pi->circ_array, stack_peek(&pi->stack)->val, i);
645
+ return;
646
+ }
647
+ } else if ('r' == str[1]) {
648
+ long i = read_long(str + 2, len - 2);
716
649
 
717
- }
650
+ if (0 < i) {
651
+ rb_ary_push(stack_peek(&pi->stack)->val, oj_circ_array_get(pi->circ_array, i));
652
+ return;
653
+ }
654
+ }
718
655
  }
719
656
  rval = str_to_value(pi, str, len, orig);
720
657
  rb_ary_push(stack_peek(&pi->stack)->val, rval);
721
- if (Yes == pi->options.trace) {
722
- oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rval);
658
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
659
+ oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rval);
723
660
  }
724
661
  }
725
662
 
726
- static void
727
- array_append_num(ParseInfo pi, NumInfo ni) {
728
- volatile VALUE rval = oj_num_as_value(ni);
729
-
663
+ static void array_append_num(ParseInfo pi, NumInfo ni) {
664
+ volatile VALUE rval = oj_num_as_value(ni);
665
+
730
666
  rb_ary_push(stack_peek(&pi->stack)->val, rval);
731
- if (Yes == pi->options.trace) {
732
- oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
667
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
668
+ oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
733
669
  }
734
670
  }
735
671
 
736
- static void
737
- add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
672
+ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
738
673
  pi->stack.head->val = str_to_value(pi, str, len, orig);
739
- if (Yes == pi->options.trace) {
740
- oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
674
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
675
+ oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
741
676
  }
742
677
  }
743
678
 
744
- static void
745
- add_num(ParseInfo pi, NumInfo ni) {
679
+ static void add_num(ParseInfo pi, NumInfo ni) {
746
680
  pi->stack.head->val = oj_num_as_value(ni);
747
- if (Yes == pi->options.trace) {
748
- oj_trace_parse_call("add_num", pi, __FILE__, __LINE__, pi->stack.head->val);
681
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
682
+ oj_trace_parse_call("add_num", pi, __FILE__, __LINE__, pi->stack.head->val);
749
683
  }
750
684
  }
751
685
 
752
- void
753
- oj_set_object_callbacks(ParseInfo pi) {
686
+ void oj_set_object_callbacks(ParseInfo pi) {
754
687
  oj_set_strict_callbacks(pi);
755
- pi->end_hash = end_hash;
756
- pi->start_hash = start_hash;
757
- pi->hash_set_cstr = hash_set_cstr;
758
- pi->hash_set_num = hash_set_num;
759
- pi->hash_set_value = hash_set_value;
760
- pi->add_cstr = add_cstr;
761
- pi->add_num = add_num;
688
+ pi->end_hash = end_hash;
689
+ pi->start_hash = start_hash;
690
+ pi->hash_set_cstr = hash_set_cstr;
691
+ pi->hash_set_num = hash_set_num;
692
+ pi->hash_set_value = hash_set_value;
693
+ pi->add_cstr = add_cstr;
694
+ pi->add_num = add_num;
762
695
  pi->array_append_cstr = array_append_cstr;
763
- pi->array_append_num = array_append_num;
696
+ pi->array_append_num = array_append_num;
764
697
  }
765
698
 
766
699
  VALUE
767
700
  oj_object_parse(int argc, VALUE *argv, VALUE self) {
768
- struct _ParseInfo pi;
701
+ struct _parseInfo pi;
769
702
 
770
703
  parse_info_init(&pi);
771
- pi.options = oj_default_options;
772
- pi.handler = Qnil;
704
+ pi.options = oj_default_options;
705
+ pi.handler = Qnil;
773
706
  pi.err_class = Qnil;
774
707
  oj_set_object_callbacks(&pi);
775
708
 
776
709
  if (T_STRING == rb_type(*argv)) {
777
- return oj_pi_parse(argc, argv, &pi, 0, 0, 1);
710
+ return oj_pi_parse(argc, argv, &pi, 0, 0, 1);
778
711
  } else {
779
- return oj_pi_sparse(argc, argv, &pi, 0);
712
+ return oj_pi_sparse(argc, argv, &pi, 0);
780
713
  }
781
714
  }
782
715
 
783
716
  VALUE
784
717
  oj_object_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
785
- struct _ParseInfo pi;
718
+ struct _parseInfo pi;
786
719
 
787
720
  parse_info_init(&pi);
788
- pi.options = oj_default_options;
789
- pi.handler = Qnil;
721
+ pi.options = oj_default_options;
722
+ pi.handler = Qnil;
790
723
  pi.err_class = Qnil;
791
724
  oj_set_strict_callbacks(&pi);
792
- pi.end_hash = end_hash;
793
- pi.start_hash = start_hash;
794
- pi.hash_set_cstr = hash_set_cstr;
795
- pi.hash_set_num = hash_set_num;
796
- pi.hash_set_value = hash_set_value;
797
- pi.add_cstr = add_cstr;
798
- pi.add_num = add_num;
725
+ pi.end_hash = end_hash;
726
+ pi.start_hash = start_hash;
727
+ pi.hash_set_cstr = hash_set_cstr;
728
+ pi.hash_set_num = hash_set_num;
729
+ pi.hash_set_value = hash_set_value;
730
+ pi.add_cstr = add_cstr;
731
+ pi.add_num = add_num;
799
732
  pi.array_append_cstr = array_append_cstr;
800
- pi.array_append_num = array_append_num;
733
+ pi.array_append_num = array_append_num;
801
734
 
802
735
  return oj_pi_parse(argc, argv, &pi, json, len, 1);
803
736
  }