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/intern.c ADDED
@@ -0,0 +1,298 @@
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 VALUE str_cache_obj;
41
+
42
+ static VALUE sym_cache_obj;
43
+
44
+ static VALUE attr_cache_obj;
45
+
46
+ static VALUE form_str(const char *str, size_t len) {
47
+ return rb_str_freeze(rb_utf8_str_new(str, len));
48
+ }
49
+
50
+ static VALUE form_sym(const char *str, size_t len) {
51
+ return rb_to_symbol(rb_str_intern(rb_utf8_str_new(str, len)));
52
+ }
53
+
54
+ static VALUE form_attr(const char *str, size_t len) {
55
+ char buf[256];
56
+
57
+ if (sizeof(buf) - 2 <= len) {
58
+ char *b = ALLOC_N(char, len + 2);
59
+ ID id;
60
+
61
+ if ('~' == *str) {
62
+ memcpy(b, str + 1, len - 1);
63
+ b[len - 1] = '\0';
64
+ len -= 2;
65
+ } else {
66
+ *b = '@';
67
+ memcpy(b + 1, str, len);
68
+ b[len + 1] = '\0';
69
+ }
70
+ id = rb_intern3(buf, len + 1, oj_utf8_encoding);
71
+ xfree(b);
72
+ return id;
73
+ }
74
+ if ('~' == *str) {
75
+ memcpy(buf, str + 1, len - 1);
76
+ buf[len - 1] = '\0';
77
+ len -= 2;
78
+ } else {
79
+ *buf = '@';
80
+ memcpy(buf + 1, str, len);
81
+ buf[len + 1] = '\0';
82
+ }
83
+ return (VALUE)rb_intern3(buf, len + 1, oj_utf8_encoding);
84
+ }
85
+
86
+ void oj_hash_init(void) {
87
+ VALUE cache_class = rb_define_class_under(Oj, "Cache", rb_cObject);
88
+ rb_undef_alloc_func(cache_class);
89
+
90
+ rb_gc_register_address(&cache_class);
91
+ rb_undef_alloc_func(cache_class);
92
+
93
+ struct _cache *str_cache = cache_create(0, form_str, true, true);
94
+ str_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, str_cache);
95
+ rb_gc_register_address(&str_cache_obj);
96
+
97
+ struct _cache *sym_cache = cache_create(0, form_sym, true, true);
98
+ sym_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, sym_cache);
99
+ rb_gc_register_address(&sym_cache_obj);
100
+
101
+ struct _cache *attr_cache = cache_create(0, form_attr, false, true);
102
+ attr_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, attr_cache);
103
+ rb_gc_register_address(&attr_cache_obj);
104
+
105
+ memset(class_hash.slots, 0, sizeof(class_hash.slots));
106
+ #if HAVE_PTHREAD_MUTEX_INIT
107
+ pthread_mutex_init(&class_hash.mutex, NULL);
108
+ #else
109
+ class_hash.mutex = rb_mutex_new();
110
+ rb_gc_register_address(&class_hash.mutex);
111
+ #endif
112
+ }
113
+
114
+ VALUE
115
+ oj_str_intern(const char *key, size_t len) {
116
+ // For huge cache sizes over half a million the rb_enc_interned_str
117
+ // performs slightly better but at more "normal" size of a several
118
+ // thousands the cache intern performs about 20% better.
119
+ #if HAVE_RB_ENC_INTERNED_STR && 0
120
+ return rb_enc_interned_str(key, len, rb_utf8_encoding());
121
+ #else
122
+ return cache_intern(DATA_PTR(str_cache_obj), key, len);
123
+ #endif
124
+ }
125
+
126
+ VALUE
127
+ oj_sym_intern(const char *key, size_t len) {
128
+ return cache_intern(DATA_PTR(sym_cache_obj), key, len);
129
+ }
130
+
131
+ ID
132
+ oj_attr_intern(const char *key, size_t len) {
133
+ return cache_intern(DATA_PTR(attr_cache_obj), key, len);
134
+ }
135
+
136
+ static uint64_t hash_calc(const uint8_t *key, size_t len) {
137
+ const uint8_t *end = key + len;
138
+ const uint8_t *endless = key + (len & 0xFFFFFFFC);
139
+ uint64_t h = (uint64_t)len;
140
+ uint64_t k;
141
+
142
+ while (key < endless) {
143
+ k = (uint64_t)*key++;
144
+ k |= (uint64_t)*key++ << 8;
145
+ k |= (uint64_t)*key++ << 16;
146
+ k |= (uint64_t)*key++ << 24;
147
+
148
+ k *= M;
149
+ k ^= k >> 24;
150
+ h *= M;
151
+ h ^= k * M;
152
+ }
153
+ if (1 < end - key) {
154
+ uint16_t k16 = (uint16_t)*key++;
155
+
156
+ k16 |= (uint16_t)*key++ << 8;
157
+ h ^= k16 << 8;
158
+ }
159
+ if (key < end) {
160
+ h ^= *key;
161
+ }
162
+ h *= M;
163
+ h ^= h >> 13;
164
+ h *= M;
165
+ h ^= h >> 15;
166
+
167
+ return h;
168
+ }
169
+
170
+ static VALUE resolve_classname(VALUE mod, const char *classname, int auto_define) {
171
+ VALUE clas;
172
+ ID ci = rb_intern(classname);
173
+
174
+ if (rb_const_defined_at(mod, ci)) {
175
+ clas = rb_const_get_at(mod, ci);
176
+ } else if (auto_define) {
177
+ clas = rb_define_class_under(mod, classname, oj_bag_class);
178
+ } else {
179
+ clas = Qundef;
180
+ }
181
+ return clas;
182
+ }
183
+
184
+ static VALUE resolve_classpath(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class) {
185
+ char class_name[1024];
186
+ VALUE clas;
187
+ char * end = class_name + sizeof(class_name) - 1;
188
+ char * s;
189
+ const char *n = name;
190
+ size_t nlen = len;
191
+
192
+ clas = rb_cObject;
193
+ for (s = class_name; 0 < len; n++, len--) {
194
+ if (':' == *n) {
195
+ *s = '\0';
196
+ n++;
197
+ len--;
198
+ if (':' != *n) {
199
+ return Qundef;
200
+ }
201
+ if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
202
+ return Qundef;
203
+ }
204
+ s = class_name;
205
+ } else if (end <= s) {
206
+ return Qundef;
207
+ } else {
208
+ *s++ = *n;
209
+ }
210
+ }
211
+ *s = '\0';
212
+ if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
213
+ if (sizeof(class_name) <= nlen) {
214
+ nlen = sizeof(class_name) - 1;
215
+ }
216
+ strncpy(class_name, name, nlen);
217
+ class_name[nlen] = '\0';
218
+ oj_set_error_at(pi, error_class, __FILE__, __LINE__, "class '%s' is not defined", class_name);
219
+ if (Qnil != error_class) {
220
+ pi->err_class = error_class;
221
+ }
222
+ }
223
+ return clas;
224
+ }
225
+
226
+ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int auto_define, VALUE error_class) {
227
+ uint64_t h = hash_calc((const uint8_t *)key, len) & HASH_MASK;
228
+ KeyVal bucket = class_hash.slots + h;
229
+ KeyVal b;
230
+
231
+ if (safe) {
232
+ #if HAVE_PTHREAD_MUTEX_INIT
233
+ pthread_mutex_lock(&class_hash.mutex);
234
+ #else
235
+ rb_mutex_lock(class_hash.mutex);
236
+ #endif
237
+ if (NULL != bucket->key) { // not the top slot
238
+ for (b = bucket; 0 != b; b = b->next) {
239
+ if (len == b->len && 0 == strncmp(b->key, key, len)) {
240
+ #if HAVE_PTHREAD_MUTEX_INIT
241
+ pthread_mutex_unlock(&class_hash.mutex);
242
+ #else
243
+ rb_mutex_unlock(class_hash.mutex);
244
+ #endif
245
+ return b->val;
246
+ }
247
+ bucket = b;
248
+ }
249
+ b = ALLOC(struct _keyVal);
250
+ b->next = NULL;
251
+ bucket->next = b;
252
+ bucket = b;
253
+ }
254
+ bucket->key = oj_strndup(key, len);
255
+ bucket->len = len;
256
+ bucket->val = resolve_classpath(pi, key, len, auto_define, error_class);
257
+ #if HAVE_PTHREAD_MUTEX_INIT
258
+ pthread_mutex_unlock(&class_hash.mutex);
259
+ #else
260
+ rb_mutex_unlock(class_hash.mutex);
261
+ #endif
262
+ } else {
263
+ if (NULL != bucket->key) {
264
+ for (b = bucket; 0 != b; b = b->next) {
265
+ if (len == b->len && 0 == strncmp(b->key, key, len)) {
266
+ return (ID)b->val;
267
+ }
268
+ bucket = b;
269
+ }
270
+ b = ALLOC(struct _keyVal);
271
+ b->next = NULL;
272
+ bucket->next = b;
273
+ bucket = b;
274
+ }
275
+ bucket->key = oj_strndup(key, len);
276
+ bucket->len = len;
277
+ bucket->val = resolve_classpath(pi, key, len, auto_define, error_class);
278
+ }
279
+ rb_gc_register_mark_object(bucket->val);
280
+ return bucket->val;
281
+ }
282
+
283
+ char *oj_strndup(const char *s, size_t len) {
284
+ char *d = ALLOC_N(char, len + 1);
285
+
286
+ memcpy(d, s, len);
287
+ d[len] = '\0';
288
+
289
+ return d;
290
+ }
291
+
292
+ /*
293
+ void intern_cleanup(void) {
294
+ cache_free(str_cache);
295
+ cache_free(sym_cache);
296
+ cache_free(attr_cache);
297
+ }
298
+ */
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(void);
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 */