oj 3.12.3 → 3.13.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -3
  3. data/ext/oj/buf.h +9 -0
  4. data/ext/oj/cache.c +341 -0
  5. data/ext/oj/cache.h +21 -0
  6. data/ext/oj/compat.c +7 -22
  7. data/ext/oj/custom.c +15 -17
  8. data/ext/oj/debug.c +132 -0
  9. data/ext/oj/dump.c +12 -15
  10. data/ext/oj/dump_compat.c +3 -3
  11. data/ext/oj/dump_object.c +9 -9
  12. data/ext/oj/dump_strict.c +3 -3
  13. data/ext/oj/err.h +19 -0
  14. data/ext/oj/extconf.rb +5 -0
  15. data/ext/oj/fast.c +7 -18
  16. data/ext/oj/intern.c +281 -0
  17. data/ext/oj/intern.h +26 -0
  18. data/ext/oj/mimic_json.c +2 -2
  19. data/ext/oj/object.c +15 -92
  20. data/ext/oj/odd.c +1 -1
  21. data/ext/oj/oj.c +117 -94
  22. data/ext/oj/oj.h +1 -1
  23. data/ext/oj/parse.c +5 -5
  24. data/ext/oj/parser.c +1483 -0
  25. data/ext/oj/parser.h +90 -0
  26. data/ext/oj/rails.c +5 -5
  27. data/ext/oj/resolve.c +2 -20
  28. data/ext/oj/rxclass.c +1 -1
  29. data/ext/oj/saj.c +1 -1
  30. data/ext/oj/saj2.c +348 -0
  31. data/ext/oj/scp.c +1 -1
  32. data/ext/oj/sparse.c +2 -2
  33. data/ext/oj/stream_writer.c +4 -4
  34. data/ext/oj/strict.c +9 -27
  35. data/ext/oj/string_writer.c +2 -2
  36. data/ext/oj/usual.c +1252 -0
  37. data/ext/oj/validate.c +51 -0
  38. data/ext/oj/wab.c +14 -19
  39. data/lib/oj/error.rb +1 -1
  40. data/lib/oj/state.rb +8 -7
  41. data/lib/oj/version.rb +1 -1
  42. data/pages/Options.md +1 -1
  43. data/pages/Parser.md +309 -0
  44. data/pages/Rails.md +2 -2
  45. data/test/json_gem/json_generator_test.rb +1 -1
  46. data/test/mem.rb +33 -0
  47. data/test/perf_once.rb +58 -0
  48. data/test/perf_parser.rb +189 -0
  49. data/test/test_hash.rb +1 -1
  50. data/test/test_parser.rb +27 -0
  51. data/test/test_parser_saj.rb +245 -0
  52. data/test/test_parser_usual.rb +213 -0
  53. metadata +26 -5
  54. data/ext/oj/hash.c +0 -168
  55. data/ext/oj/hash.h +0 -21
  56. data/ext/oj/hash_test.c +0 -491
data/ext/oj/extconf.rb CHANGED
@@ -30,6 +30,11 @@ have_func('rb_ivar_foreach')
30
30
  have_func('rb_gc_mark_movable')
31
31
  have_func('stpcpy')
32
32
  have_func('pthread_mutex_init')
33
+ have_func('rb_enc_associate')
34
+ have_func('rb_enc_interned_str')
35
+ have_func('rb_ext_ractor_safe', 'ruby.h')
36
+ # rb_hash_bulk_insert is deep down in a header not included in normal build and that seems to fool have_func.
37
+ have_func('rb_hash_bulk_insert', 'ruby.h') unless '2' == version[0] && '6' == version[1]
33
38
 
34
39
  dflags['OJ_DEBUG'] = true unless ENV['OJ_DEBUG'].nil?
35
40
 
data/ext/oj/fast.c CHANGED
@@ -200,9 +200,7 @@ static VALUE leaf_value(Doc doc, Leaf leaf) {
200
200
  break;
201
201
  case T_ARRAY: return leaf_array_value(doc, leaf); break;
202
202
  case T_HASH: return leaf_hash_value(doc, leaf); break;
203
- default:
204
- rb_raise(rb_const_get_at(Oj, rb_intern("Error")), "Unexpected type %02x.", leaf->rtype);
205
- break;
203
+ default: rb_raise(rb_const_get_at(Oj, rb_intern("Error")), "Unexpected type %02x.", leaf->rtype); break;
206
204
  }
207
205
  }
208
206
  return leaf->value;
@@ -773,7 +771,7 @@ static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
773
771
  pi.doc = doc;
774
772
  #if IS_WINDOWS
775
773
  // assume a 1M stack and give half to ruby
776
- pi.stack_min = (void *)((char *)&pi - (512 * 1024));
774
+ pi.stack_min = (void*)((char*)&pi - (512 * 1024));
777
775
  #else
778
776
  {
779
777
  struct rlimit lim;
@@ -825,9 +823,7 @@ static Leaf get_doc_leaf(Doc doc, const char *path) {
825
823
  size_t cnt = doc->where - doc->where_path;
826
824
 
827
825
  if (MAX_STACK <= cnt) {
828
- rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")),
829
- "Path too deep. Limit is %d levels.",
830
- MAX_STACK);
826
+ rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
831
827
  }
832
828
  memcpy(stack, doc->where_path, sizeof(Leaf) * (cnt + 1));
833
829
  lp = stack + cnt;
@@ -868,9 +864,7 @@ static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path) {
868
864
  Leaf leaf = *lp;
869
865
 
870
866
  if (MAX_STACK <= lp - stack) {
871
- rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")),
872
- "Path too deep. Limit is %d levels.",
873
- MAX_STACK);
867
+ rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
874
868
  }
875
869
  if ('\0' != *path) {
876
870
  if ('.' == *path && '.' == *(path + 1)) {
@@ -946,9 +940,7 @@ static void each_leaf(Doc doc, VALUE self) {
946
940
 
947
941
  doc->where++;
948
942
  if (MAX_STACK <= doc->where - doc->where_path) {
949
- rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")),
950
- "Path too deep. Limit is %d levels.",
951
- MAX_STACK);
943
+ rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
952
944
  }
953
945
  do {
954
946
  *doc->where = e;
@@ -964,9 +956,7 @@ static void each_leaf(Doc doc, VALUE self) {
964
956
 
965
957
  static int move_step(Doc doc, const char *path, int loc) {
966
958
  if (MAX_STACK <= doc->where - doc->where_path) {
967
- rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")),
968
- "Path too deep. Limit is %d levels.",
969
- MAX_STACK);
959
+ rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
970
960
  }
971
961
  if ('\0' == *path) {
972
962
  loc = 0;
@@ -1264,7 +1254,6 @@ static VALUE doc_path(VALUE self) {
1264
1254
  return doc_where(self);
1265
1255
  }
1266
1256
 
1267
-
1268
1257
  /* @overload local_key() => String, Fixnum, nil
1269
1258
  *
1270
1259
  * Returns the final key to the current location.
@@ -1483,7 +1472,7 @@ static VALUE doc_move(VALUE self, VALUE str) {
1483
1472
  * to the block on yield is the Doc instance after moving to the child
1484
1473
  * location.
1485
1474
  * @param [String] path if provided it identified the top of the branch to
1486
- * process the chilren of
1475
+ * process the children of
1487
1476
  * @yieldparam [Doc] Doc at the child location
1488
1477
  * @example
1489
1478
  * Oj::Doc.open('[3,[2,1]]') { |doc|
data/ext/oj/intern.c ADDED
@@ -0,0 +1,281 @@
1
+ // Copyright (c) 2011, 2021 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #include "intern.h"
5
+
6
+ #include <stdint.h>
7
+
8
+ #if HAVE_PTHREAD_MUTEX_INIT
9
+ #include <pthread.h>
10
+ #endif
11
+ #include "cache.h"
12
+ #include "parse.h"
13
+
14
+ // Only used for the class cache so 256 should be sufficient.
15
+ #define HASH_SLOT_CNT ((uint64_t)256)
16
+ #define HASH_MASK (HASH_SLOT_CNT - 1)
17
+
18
+ // almost the Murmur hash algorithm
19
+ #define M 0x5bd1e995
20
+
21
+ typedef struct _keyVal {
22
+ struct _keyVal *next;
23
+ const char * key;
24
+ size_t len;
25
+ VALUE val;
26
+ } * KeyVal;
27
+
28
+ typedef struct _hash {
29
+ struct _keyVal slots[HASH_SLOT_CNT];
30
+ #if HAVE_PTHREAD_MUTEX_INIT
31
+ pthread_mutex_t mutex;
32
+ #else
33
+ VALUE mutex;
34
+ #endif
35
+ } * Hash;
36
+
37
+ struct _hash class_hash;
38
+ struct _hash attr_hash;
39
+
40
+ static struct _cache *str_cache = NULL;
41
+ static VALUE str_cache_obj;
42
+
43
+ static struct _cache *sym_cache = NULL;
44
+ static VALUE sym_cache_obj;
45
+
46
+ static struct _cache *attr_cache = NULL;
47
+ static VALUE attr_cache_obj;
48
+
49
+ static VALUE form_str(const char *str, size_t len) {
50
+ return rb_str_freeze(rb_utf8_str_new(str, len));
51
+ }
52
+
53
+ static VALUE form_sym(const char *str, size_t len) {
54
+ return rb_str_intern(rb_utf8_str_new(str, len));
55
+ }
56
+
57
+ static VALUE form_attr(const char *str, size_t len) {
58
+ char buf[256];
59
+
60
+ if (sizeof(buf) - 2 <= len) {
61
+ char *b = ALLOC_N(char, len + 2);
62
+ ID id;
63
+
64
+ if ('~' == *str) {
65
+ memcpy(b, str + 1, len - 1);
66
+ b[len - 1] = '\0';
67
+ len -= 2;
68
+ } else {
69
+ *b = '@';
70
+ memcpy(b + 1, str, len);
71
+ b[len + 1] = '\0';
72
+ }
73
+ id = rb_intern3(buf, len + 1, oj_utf8_encoding);
74
+ xfree(b);
75
+ return id;
76
+ }
77
+ if ('~' == *str) {
78
+ memcpy(buf, str + 1, len - 1);
79
+ buf[len - 1] = '\0';
80
+ len -= 2;
81
+ } else {
82
+ *buf = '@';
83
+ memcpy(buf + 1, str, len);
84
+ buf[len + 1] = '\0';
85
+ }
86
+ return (VALUE)rb_intern3(buf, len + 1, oj_utf8_encoding);
87
+ }
88
+
89
+ void oj_hash_init() {
90
+ VALUE cache_class = rb_define_class_under(Oj, "Cache", rb_cObject);
91
+
92
+ str_cache = cache_create(0, form_str, true, true);
93
+ str_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, str_cache);
94
+ rb_gc_register_address(&str_cache_obj);
95
+
96
+ sym_cache = cache_create(0, form_sym, true, true);
97
+ sym_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, sym_cache);
98
+ rb_gc_register_address(&sym_cache_obj);
99
+
100
+ attr_cache = cache_create(0, form_attr, false, true);
101
+ attr_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, attr_cache);
102
+ rb_gc_register_address(&attr_cache_obj);
103
+
104
+ memset(class_hash.slots, 0, sizeof(class_hash.slots));
105
+ #if HAVE_PTHREAD_MUTEX_INIT
106
+ pthread_mutex_init(&class_hash.mutex, NULL);
107
+ #else
108
+ class_hash.mutex = rb_mutex_new();
109
+ rb_gc_register_address(&class_hash.mutex);
110
+ #endif
111
+ }
112
+
113
+ VALUE
114
+ oj_str_intern(const char *key, size_t len) {
115
+ return cache_intern(str_cache, key, len);
116
+ }
117
+
118
+ VALUE
119
+ oj_sym_intern(const char *key, size_t len) {
120
+ return cache_intern(sym_cache, key, len);
121
+ }
122
+
123
+ ID
124
+ oj_attr_intern(const char *key, size_t len) {
125
+ return cache_intern(attr_cache, key, len);
126
+ }
127
+
128
+ static uint64_t hash_calc(const uint8_t *key, size_t len) {
129
+ const uint8_t *end = key + len;
130
+ const uint8_t *endless = key + (len & 0xFFFFFFFC);
131
+ uint64_t h = (uint64_t)len;
132
+ uint64_t k;
133
+
134
+ while (key < endless) {
135
+ k = (uint64_t)*key++;
136
+ k |= (uint64_t)*key++ << 8;
137
+ k |= (uint64_t)*key++ << 16;
138
+ k |= (uint64_t)*key++ << 24;
139
+
140
+ k *= M;
141
+ k ^= k >> 24;
142
+ h *= M;
143
+ h ^= k * M;
144
+ }
145
+ if (1 < end - key) {
146
+ uint16_t k16 = (uint16_t)*key++;
147
+
148
+ k16 |= (uint16_t)*key++ << 8;
149
+ h ^= k16 << 8;
150
+ }
151
+ if (key < end) {
152
+ h ^= *key;
153
+ }
154
+ h *= M;
155
+ h ^= h >> 13;
156
+ h *= M;
157
+ h ^= h >> 15;
158
+
159
+ return h;
160
+ }
161
+
162
+ static VALUE resolve_classname(VALUE mod, const char *classname, int auto_define) {
163
+ VALUE clas;
164
+ ID ci = rb_intern(classname);
165
+
166
+ if (rb_const_defined_at(mod, ci)) {
167
+ clas = rb_const_get_at(mod, ci);
168
+ } else if (auto_define) {
169
+ clas = rb_define_class_under(mod, classname, oj_bag_class);
170
+ } else {
171
+ clas = Qundef;
172
+ }
173
+ return clas;
174
+ }
175
+
176
+ static VALUE resolve_classpath(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class) {
177
+ char class_name[1024];
178
+ VALUE clas;
179
+ char * end = class_name + sizeof(class_name) - 1;
180
+ char * s;
181
+ const char *n = name;
182
+
183
+ clas = rb_cObject;
184
+ for (s = class_name; 0 < len; n++, len--) {
185
+ if (':' == *n) {
186
+ *s = '\0';
187
+ n++;
188
+ len--;
189
+ if (':' != *n) {
190
+ return Qundef;
191
+ }
192
+ if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
193
+ return Qundef;
194
+ }
195
+ s = class_name;
196
+ } else if (end <= s) {
197
+ return Qundef;
198
+ } else {
199
+ *s++ = *n;
200
+ }
201
+ }
202
+ *s = '\0';
203
+ if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
204
+ oj_set_error_at(pi, error_class, __FILE__, __LINE__, "class %s is not defined", name);
205
+ if (Qnil != error_class) {
206
+ pi->err_class = error_class;
207
+ }
208
+ }
209
+ return clas;
210
+ }
211
+
212
+ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int auto_define, VALUE error_class) {
213
+ uint64_t h = hash_calc((const uint8_t *)key, len) & HASH_MASK;
214
+ KeyVal bucket = class_hash.slots + h;
215
+ KeyVal b;
216
+
217
+ if (safe) {
218
+ #if HAVE_PTHREAD_MUTEX_INIT
219
+ pthread_mutex_lock(&class_hash.mutex);
220
+ #else
221
+ rb_mutex_lock(class_hash.mutex);
222
+ #endif
223
+ if (NULL != bucket->key) { // not the top slot
224
+ for (b = bucket; 0 != b; b = b->next) {
225
+ if (len == b->len && 0 == strncmp(b->key, key, len)) {
226
+ #if HAVE_PTHREAD_MUTEX_INIT
227
+ pthread_mutex_unlock(&class_hash.mutex);
228
+ #else
229
+ rb_mutex_unlock(class_hash.mutex);
230
+ #endif
231
+ return b->val;
232
+ }
233
+ bucket = b;
234
+ }
235
+ b = ALLOC(struct _keyVal);
236
+ b->next = NULL;
237
+ bucket->next = b;
238
+ bucket = b;
239
+ }
240
+ bucket->key = oj_strndup(key, len);
241
+ bucket->len = len;
242
+ bucket->val = resolve_classpath(pi, key, len, auto_define, error_class);
243
+ #if HAVE_PTHREAD_MUTEX_INIT
244
+ pthread_mutex_unlock(&class_hash.mutex);
245
+ #else
246
+ rb_mutex_unlock(class_hash.mutex);
247
+ #endif
248
+ } else {
249
+ if (NULL != bucket->key) {
250
+ for (b = bucket; 0 != b; b = b->next) {
251
+ if (len == b->len && 0 == strncmp(b->key, key, len)) {
252
+ return (ID)b->val;
253
+ }
254
+ bucket = b;
255
+ }
256
+ b = ALLOC(struct _keyVal);
257
+ b->next = NULL;
258
+ bucket->next = b;
259
+ bucket = b;
260
+ }
261
+ bucket->key = oj_strndup(key, len);
262
+ bucket->len = len;
263
+ bucket->val = resolve_classpath(pi, key, len, auto_define, error_class);
264
+ }
265
+ return bucket->val;
266
+ }
267
+
268
+ char *oj_strndup(const char *s, size_t len) {
269
+ char *d = ALLOC_N(char, len + 1);
270
+
271
+ memcpy(d, s, len);
272
+ d[len] = '\0';
273
+
274
+ return d;
275
+ }
276
+
277
+ void intern_cleanup() {
278
+ cache_free(str_cache);
279
+ cache_free(sym_cache);
280
+ cache_free(attr_cache);
281
+ }
data/ext/oj/intern.h ADDED
@@ -0,0 +1,26 @@
1
+ // Copyright (c) 2011, 2021 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #ifndef OJ_INTERN_H
5
+ #define OJ_INTERN_H
6
+
7
+ #include <stdbool.h>
8
+ #include <ruby.h>
9
+
10
+ struct _parseInfo;
11
+
12
+ extern void oj_hash_init();
13
+
14
+ extern VALUE oj_str_intern(const char *key, size_t len);
15
+ extern VALUE oj_sym_intern(const char *key, size_t len);
16
+ extern ID oj_attr_intern(const char *key, size_t len);
17
+ extern VALUE oj_class_intern(const char * key,
18
+ size_t len,
19
+ bool safe,
20
+ struct _parseInfo *pi,
21
+ int auto_define,
22
+ VALUE error_class);
23
+
24
+ extern char *oj_strndup(const char *s, size_t len);
25
+
26
+ #endif /* OJ_INTERN_H */
data/ext/oj/mimic_json.c CHANGED
@@ -682,7 +682,7 @@ static VALUE mimic_set_create_id(VALUE self, VALUE id) {
682
682
  */
683
683
  static VALUE mimic_create_id(VALUE self) {
684
684
  if (NULL != oj_default_options.create_id) {
685
- return oj_encode(rb_str_new_cstr(oj_default_options.create_id));
685
+ return rb_utf8_str_new(oj_default_options.create_id, oj_default_options.create_id_len);
686
686
  }
687
687
  return rb_str_new_cstr(oj_json_class);
688
688
  }
@@ -714,7 +714,7 @@ static struct _options mimic_object_to_json_options = {0, // indent
714
714
  false, // sec_prec_set
715
715
  No, // ignore_under
716
716
  Yes, // cache_keys
717
- 3, // cache_str
717
+ 0, // cache_str
718
718
  0, // int_range_min
719
719
  0, // int_range_max
720
720
  oj_json_class, // create_id
data/ext/oj/object.c CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  #include "encode.h"
9
9
  #include "err.h"
10
- #include "hash.h"
10
+ #include "intern.h"
11
11
  #include "odd.h"
12
12
  #include "oj.h"
13
13
  #include "parse.h"
@@ -30,45 +30,18 @@ inline static long read_long(const char *str, size_t len) {
30
30
 
31
31
  static VALUE calc_hash_key(ParseInfo pi, Val kval, char k1) {
32
32
  volatile VALUE rkey;
33
- #if 0
34
- VALUE *slot;
35
33
 
36
34
  if (':' == k1) {
37
- if (Qnil == (rkey = oj_sym_hash_get(kval->key + 1, kval->klen - 1, &slot))) {
38
- rkey = rb_str_new(kval->key + 1, kval->klen - 1);
39
- rkey = oj_encode(rkey);
40
- rkey = rb_str_intern(rkey);
41
- *slot = rkey;
42
- rb_gc_register_address(slot);
43
- }
44
- } else if (Yes == pi->options.sym_key) {
45
- if (Qnil == (rkey = oj_sym_hash_get(kval->key, kval->klen, &slot))) {
46
- rkey = rb_str_new(kval->key, kval->klen);
47
- rkey = oj_encode(rkey);
48
- rkey = rb_str_intern(rkey);
49
- *slot = rkey;
50
- rb_gc_register_address(slot);
51
- }
52
- } else {
53
- if (Qnil == (rkey = oj_str_hash_get(kval->key, kval->klen, &slot))) {
54
- rkey = rb_str_new(kval->key, kval->klen);
55
- rkey = oj_encode(rkey);
56
- *slot = rkey;
57
- rb_gc_register_address(slot);
58
- }
35
+ return ID2SYM(rb_intern3(kval->key + 1, kval->klen - 1, oj_utf8_encoding));
59
36
  }
60
- #else
61
- if (':' == k1) {
62
- rkey = rb_str_new(kval->key + 1, kval->klen - 1);
63
- rkey = oj_encode(rkey);
64
- rkey = rb_str_intern(rkey);
65
- } else {
66
- rkey = rb_str_new(kval->key, kval->klen);
67
- rkey = oj_encode(rkey);
68
- if (Yes == pi->options.sym_key) {
69
- rkey = rb_str_intern(rkey);
70
- }
37
+ if (Yes == pi->options.sym_key) {
38
+ return ID2SYM(rb_intern3(kval->key, kval->klen, oj_utf8_encoding));
71
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);
72
45
  #endif
73
46
  return rkey;
74
47
  }
@@ -77,9 +50,7 @@ static VALUE str_to_value(ParseInfo pi, const char *str, size_t len, const char
77
50
  volatile VALUE rstr = Qnil;
78
51
 
79
52
  if (':' == *orig && 0 < len) {
80
- rstr = rb_str_new(str + 1, len - 1);
81
- rstr = oj_encode(rstr);
82
- rstr = rb_funcall(rstr, oj_to_sym_id, 0);
53
+ rstr = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding));
83
54
  } else if (pi->circ_array && 3 <= len && '^' == *orig && 'r' == orig[1]) {
84
55
  long i = read_long(str + 2, len - 2);
85
56
 
@@ -89,8 +60,7 @@ static VALUE str_to_value(ParseInfo pi, const char *str, size_t len, const char
89
60
  }
90
61
  rstr = oj_circ_array_get(pi->circ_array, i);
91
62
  } else {
92
- rstr = rb_str_new(str, len);
93
- rstr = oj_encode(rstr);
63
+ rstr = rb_utf8_str_new(str, len);
94
64
  }
95
65
  return rstr;
96
66
  }
@@ -258,13 +228,10 @@ static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t
258
228
  parent->odd_args = oj_odd_alloc_args(odd);
259
229
  } break;
260
230
  case 'm':
261
- parent->val = rb_str_new(str + 1, len - 1);
262
- parent->val = oj_encode(parent->val);
263
- parent->val = rb_funcall(parent->val, oj_to_sym_id, 0);
231
+ parent->val = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding));
264
232
  break;
265
233
  case 's':
266
- parent->val = rb_str_new(str, len);
267
- parent->val = oj_encode(parent->val);
234
+ parent->val = rb_utf8_str_new(str, len);
268
235
  break;
269
236
  case 'c': // class
270
237
  {
@@ -305,7 +272,7 @@ static int hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
305
272
  }
306
273
  if (86400 == ni->exp) { // UTC time
307
274
  parent->val = rb_time_nano_new(ni->i, (long)nsec);
308
- // Since the ruby C routines alway create local time, the
275
+ // Since the ruby C routines always create local time, the
309
276
  // offset and then a conversion to UTC keeps makes the time
310
277
  // match the expected value.
311
278
  parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
@@ -416,51 +383,7 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
416
383
  }
417
384
 
418
385
  void oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
419
- const char *key = kval->key;
420
- int klen = kval->klen;
421
- ID var_id;
422
- ID * slot;
423
-
424
- #ifdef HAVE_PTHREAD_MUTEX_INIT
425
- pthread_mutex_lock(&oj_cache_mutex);
426
- #else
427
- rb_mutex_lock(oj_cache_mutex);
428
- #endif
429
- if (0 == (var_id = oj_attr_hash_get(key, klen, &slot))) {
430
- char attr[256];
431
-
432
- if ((int)sizeof(attr) <= klen + 2) {
433
- char *buf = ALLOC_N(char, klen + 2);
434
-
435
- if ('~' == *key) {
436
- memcpy(buf, key + 1, klen - 1);
437
- buf[klen - 1] = '\0';
438
- } else {
439
- *buf = '@';
440
- memcpy(buf + 1, key, klen);
441
- buf[klen + 1] = '\0';
442
- }
443
- var_id = rb_intern(buf);
444
- xfree(buf);
445
- } else {
446
- if ('~' == *key) {
447
- memcpy(attr, key + 1, klen - 1);
448
- attr[klen - 1] = '\0';
449
- } else {
450
- *attr = '@';
451
- memcpy(attr + 1, key, klen);
452
- attr[klen + 1] = '\0';
453
- }
454
- var_id = rb_intern(attr);
455
- }
456
- *slot = var_id;
457
- }
458
- #ifdef HAVE_PTHREAD_MUTEX_INIT
459
- pthread_mutex_unlock(&oj_cache_mutex);
460
- #else
461
- rb_mutex_unlock(oj_cache_mutex);
462
- #endif
463
- rb_ivar_set(parent->val, var_id, value);
386
+ rb_ivar_set(parent->val, oj_attr_intern(kval->key, kval->klen), value);
464
387
  }
465
388
 
466
389
  static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {