oj 3.16.0 → 3.17.3

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 (137) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +107 -0
  3. data/README.md +0 -16
  4. data/ext/oj/cache.c +4 -2
  5. data/ext/oj/cache.h +3 -2
  6. data/ext/oj/compat.c +3 -3
  7. data/ext/oj/custom.c +17 -11
  8. data/ext/oj/dump.c +624 -90
  9. data/ext/oj/dump.h +9 -2
  10. data/ext/oj/dump_compat.c +15 -9
  11. data/ext/oj/dump_leaf.c +1 -1
  12. data/ext/oj/dump_object.c +32 -17
  13. data/ext/oj/dump_strict.c +20 -14
  14. data/ext/oj/extconf.rb +11 -9
  15. data/ext/oj/fast.c +50 -32
  16. data/ext/oj/intern.c +24 -7
  17. data/ext/oj/mimic_json.c +17 -11
  18. data/ext/oj/object.c +21 -13
  19. data/ext/oj/oj.c +387 -140
  20. data/ext/oj/oj.h +59 -55
  21. data/ext/oj/parse.c +248 -47
  22. data/ext/oj/parser.c +179 -89
  23. data/ext/oj/parser.h +4 -2
  24. data/ext/oj/rails.c +64 -42
  25. data/ext/oj/reader.c +1 -1
  26. data/ext/oj/rxclass.c +1 -1
  27. data/ext/oj/rxclass.h +1 -1
  28. data/ext/oj/safe.c +230 -0
  29. data/ext/oj/safe.h +79 -0
  30. data/ext/oj/saj.c +15 -10
  31. data/ext/oj/scp.c +3 -6
  32. data/ext/oj/simd.h +219 -0
  33. data/ext/oj/sparse.c +6 -3
  34. data/ext/oj/stream_writer.c +38 -28
  35. data/ext/oj/strict.c +2 -4
  36. data/ext/oj/string_writer.c +54 -22
  37. data/ext/oj/usual.c +57 -35
  38. data/ext/oj/usual.h +1 -0
  39. data/ext/oj/val_stack.c +13 -2
  40. data/ext/oj/wab.c +5 -4
  41. data/lib/oj/mimic.rb +1 -5
  42. data/lib/oj/schandler.rb +5 -4
  43. data/lib/oj/version.rb +1 -1
  44. data/pages/Encoding.md +1 -1
  45. metadata +36 -100
  46. data/test/_test_active.rb +0 -75
  47. data/test/_test_active_mimic.rb +0 -95
  48. data/test/_test_mimic_rails.rb +0 -123
  49. data/test/activerecord/result_test.rb +0 -31
  50. data/test/activesupport6/abstract_unit.rb +0 -44
  51. data/test/activesupport6/decoding_test.rb +0 -133
  52. data/test/activesupport6/encoding_test.rb +0 -507
  53. data/test/activesupport6/encoding_test_cases.rb +0 -98
  54. data/test/activesupport6/test_common.rb +0 -17
  55. data/test/activesupport6/test_helper.rb +0 -163
  56. data/test/activesupport6/time_zone_test_helpers.rb +0 -39
  57. data/test/activesupport7/abstract_unit.rb +0 -49
  58. data/test/activesupport7/decoding_test.rb +0 -125
  59. data/test/activesupport7/encoding_test.rb +0 -486
  60. data/test/activesupport7/encoding_test_cases.rb +0 -104
  61. data/test/activesupport7/time_zone_test_helpers.rb +0 -47
  62. data/test/files.rb +0 -29
  63. data/test/foo.rb +0 -14
  64. data/test/helper.rb +0 -39
  65. data/test/isolated/shared.rb +0 -309
  66. data/test/isolated/test_mimic_after.rb +0 -13
  67. data/test/isolated/test_mimic_alone.rb +0 -12
  68. data/test/isolated/test_mimic_as_json.rb +0 -45
  69. data/test/isolated/test_mimic_before.rb +0 -13
  70. data/test/isolated/test_mimic_define.rb +0 -28
  71. data/test/isolated/test_mimic_rails_after.rb +0 -22
  72. data/test/isolated/test_mimic_rails_before.rb +0 -21
  73. data/test/isolated/test_mimic_redefine.rb +0 -15
  74. data/test/json_gem/json_addition_test.rb +0 -216
  75. data/test/json_gem/json_common_interface_test.rb +0 -155
  76. data/test/json_gem/json_encoding_test.rb +0 -107
  77. data/test/json_gem/json_ext_parser_test.rb +0 -21
  78. data/test/json_gem/json_fixtures_test.rb +0 -36
  79. data/test/json_gem/json_generator_test.rb +0 -407
  80. data/test/json_gem/json_generic_object_test.rb +0 -90
  81. data/test/json_gem/json_parser_test.rb +0 -477
  82. data/test/json_gem/json_string_matching_test.rb +0 -42
  83. data/test/json_gem/test_helper.rb +0 -30
  84. data/test/mem.rb +0 -34
  85. data/test/perf.rb +0 -102
  86. data/test/perf_compat.rb +0 -128
  87. data/test/perf_dump.rb +0 -50
  88. data/test/perf_fast.rb +0 -162
  89. data/test/perf_file.rb +0 -62
  90. data/test/perf_object.rb +0 -134
  91. data/test/perf_once.rb +0 -59
  92. data/test/perf_parser.rb +0 -183
  93. data/test/perf_saj.rb +0 -101
  94. data/test/perf_scp.rb +0 -140
  95. data/test/perf_simple.rb +0 -289
  96. data/test/perf_strict.rb +0 -137
  97. data/test/perf_wab.rb +0 -129
  98. data/test/prec.rb +0 -23
  99. data/test/sample/change.rb +0 -13
  100. data/test/sample/dir.rb +0 -18
  101. data/test/sample/doc.rb +0 -35
  102. data/test/sample/file.rb +0 -47
  103. data/test/sample/group.rb +0 -15
  104. data/test/sample/hasprops.rb +0 -15
  105. data/test/sample/layer.rb +0 -11
  106. data/test/sample/line.rb +0 -20
  107. data/test/sample/oval.rb +0 -10
  108. data/test/sample/rect.rb +0 -9
  109. data/test/sample/shape.rb +0 -34
  110. data/test/sample/text.rb +0 -19
  111. data/test/sample.rb +0 -54
  112. data/test/sample_json.rb +0 -37
  113. data/test/test_compat.rb +0 -567
  114. data/test/test_custom.rb +0 -554
  115. data/test/test_debian.rb +0 -50
  116. data/test/test_fast.rb +0 -526
  117. data/test/test_file.rb +0 -250
  118. data/test/test_gc.rb +0 -60
  119. data/test/test_generate.rb +0 -21
  120. data/test/test_hash.rb +0 -39
  121. data/test/test_integer_range.rb +0 -72
  122. data/test/test_null.rb +0 -376
  123. data/test/test_object.rb +0 -1016
  124. data/test/test_parser.rb +0 -11
  125. data/test/test_parser_debug.rb +0 -27
  126. data/test/test_parser_saj.rb +0 -337
  127. data/test/test_parser_usual.rb +0 -217
  128. data/test/test_rails.rb +0 -35
  129. data/test/test_saj.rb +0 -188
  130. data/test/test_scp.rb +0 -431
  131. data/test/test_strict.rb +0 -431
  132. data/test/test_various.rb +0 -801
  133. data/test/test_wab.rb +0 -311
  134. data/test/test_writer.rb +0 -380
  135. data/test/tests.rb +0 -33
  136. data/test/tests_mimic.rb +0 -23
  137. data/test/tests_mimic_addition.rb +0 -16
@@ -225,7 +225,7 @@ void oj_str_writer_pop_all(StrWriter sw) {
225
225
  }
226
226
  }
227
227
 
228
- static void str_writer_free(void *ptr) {
228
+ static void string_writer_free(void *ptr) {
229
229
  StrWriter sw;
230
230
 
231
231
  if (0 == ptr) {
@@ -239,6 +239,23 @@ static void str_writer_free(void *ptr) {
239
239
  OJ_R_FREE(ptr);
240
240
  }
241
241
 
242
+ static const rb_data_type_t oj_string_writer_type = {
243
+ "Oj/string_writer",
244
+ {
245
+ NULL,
246
+ string_writer_free,
247
+ NULL,
248
+ },
249
+ 0,
250
+ 0,
251
+ };
252
+
253
+ StrWriter oj_str_writer_unwrap(VALUE writer) {
254
+ StrWriter sw;
255
+ TypedData_Get_Struct(writer, struct _strWriter, &oj_string_writer_type, sw);
256
+ return sw;
257
+ }
258
+
242
259
  /* Document-method: new
243
260
  * call-seq: new(io, options)
244
261
  *
@@ -266,7 +283,7 @@ static VALUE str_writer_new(int argc, VALUE *argv, VALUE self) {
266
283
  sw->out.argv = argv + 1;
267
284
  sw->out.indent = sw->opts.indent;
268
285
 
269
- return Data_Wrap_Struct(oj_string_writer_class, 0, str_writer_free, sw);
286
+ return TypedData_Wrap_Struct(oj_string_writer_class, &oj_string_writer_type, sw);
270
287
  }
271
288
 
272
289
  /* Document-method: push_key
@@ -278,7 +295,8 @@ static VALUE str_writer_new(int argc, VALUE *argv, VALUE self) {
278
295
  * - *key* [_String_] the key pending for the next push
279
296
  */
280
297
  static VALUE str_writer_push_key(VALUE self, VALUE key) {
281
- StrWriter sw = (StrWriter)DATA_PTR(self);
298
+ StrWriter sw;
299
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
282
300
 
283
301
  oj_str_writer_push_key(sw, StringValuePtr(key));
284
302
 
@@ -293,7 +311,8 @@ static VALUE str_writer_push_key(VALUE self, VALUE key) {
293
311
  * - *key* [_String_] the key if adding to an object in the JSON document
294
312
  */
295
313
  static VALUE str_writer_push_object(int argc, VALUE *argv, VALUE self) {
296
- StrWriter sw = (StrWriter)DATA_PTR(self);
314
+ StrWriter sw;
315
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
297
316
 
298
317
  switch (argc) {
299
318
  case 0: oj_str_writer_push_object(sw, 0); break;
@@ -321,7 +340,8 @@ static VALUE str_writer_push_object(int argc, VALUE *argv, VALUE self) {
321
340
  * - *key* [_String_] the key if adding to an object in the JSON document
322
341
  */
323
342
  static VALUE str_writer_push_array(int argc, VALUE *argv, VALUE self) {
324
- StrWriter sw = (StrWriter)DATA_PTR(self);
343
+ StrWriter sw;
344
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
325
345
 
326
346
  switch (argc) {
327
347
  case 0: oj_str_writer_push_array(sw, 0); break;
@@ -349,13 +369,16 @@ static VALUE str_writer_push_array(int argc, VALUE *argv, VALUE self) {
349
369
  * - *key* [_String_] the key if adding to an object in the JSON document
350
370
  */
351
371
  static VALUE str_writer_push_value(int argc, VALUE *argv, VALUE self) {
372
+ StrWriter sw;
373
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
374
+
352
375
  switch (argc) {
353
- case 1: oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0); break;
376
+ case 1: oj_str_writer_push_value(sw, *argv, 0); break;
354
377
  case 2:
355
378
  if (Qnil == argv[1]) {
356
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
379
+ oj_str_writer_push_value(sw, *argv, 0);
357
380
  } else {
358
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1]));
381
+ oj_str_writer_push_value(sw, *argv, StringValuePtr(argv[1]));
359
382
  }
360
383
  break;
361
384
  default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'."); break;
@@ -373,13 +396,16 @@ static VALUE str_writer_push_value(int argc, VALUE *argv, VALUE self) {
373
396
  * - *key* [_String_] the key if adding to an object in the JSON document
374
397
  */
375
398
  static VALUE str_writer_push_json(int argc, VALUE *argv, VALUE self) {
399
+ StrWriter sw;
400
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
401
+
376
402
  switch (argc) {
377
- case 1: oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0); break;
403
+ case 1: oj_str_writer_push_json(sw, StringValuePtr(*argv), 0); break;
378
404
  case 2:
379
405
  if (Qnil == argv[1]) {
380
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
406
+ oj_str_writer_push_json(sw, StringValuePtr(*argv), 0);
381
407
  } else {
382
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), StringValuePtr(argv[1]));
408
+ oj_str_writer_push_json(sw, StringValuePtr(*argv), StringValuePtr(argv[1]));
383
409
  }
384
410
  break;
385
411
  default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'."); break;
@@ -393,7 +419,10 @@ static VALUE str_writer_push_json(int argc, VALUE *argv, VALUE self) {
393
419
  * currently open.
394
420
  */
395
421
  static VALUE str_writer_pop(VALUE self) {
396
- oj_str_writer_pop((StrWriter)DATA_PTR(self));
422
+ StrWriter sw;
423
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
424
+
425
+ oj_str_writer_pop(sw);
397
426
  return Qnil;
398
427
  }
399
428
 
@@ -404,7 +433,10 @@ static VALUE str_writer_pop(VALUE self) {
404
433
  * currently open.
405
434
  */
406
435
  static VALUE str_writer_pop_all(VALUE self) {
407
- oj_str_writer_pop_all((StrWriter)DATA_PTR(self));
436
+ StrWriter sw;
437
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
438
+
439
+ oj_str_writer_pop_all(sw);
408
440
 
409
441
  return Qnil;
410
442
  }
@@ -415,7 +447,8 @@ static VALUE str_writer_pop_all(VALUE self) {
415
447
  * Reset the writer back to the empty state.
416
448
  */
417
449
  static VALUE str_writer_reset(VALUE self) {
418
- StrWriter sw = (StrWriter)DATA_PTR(self);
450
+ StrWriter sw;
451
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
419
452
 
420
453
  sw->depth = 0;
421
454
  *sw->types = '\0';
@@ -434,23 +467,22 @@ static VALUE str_writer_reset(VALUE self) {
434
467
  * *return* [_String_]
435
468
  */
436
469
  static VALUE str_writer_to_s(VALUE self) {
437
- StrWriter sw = (StrWriter)DATA_PTR(self);
438
- VALUE rstr = rb_str_new(sw->out.buf, sw->out.cur - sw->out.buf);
439
-
440
- return oj_encode(rstr);
470
+ StrWriter sw;
471
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
472
+ return rb_utf8_str_new(sw->out.buf, sw->out.cur - sw->out.buf);
441
473
  }
442
474
 
443
475
  /* Document-method: as_json
444
- * call-seq: as_json()
476
+ * call-seq: as_json(*)
445
477
  *
446
478
  * Returns the contents of the writer as a JSON element. If called from inside
447
479
  * an array or hash by Oj the raw buffer will be used othersize a more
448
480
  * inefficient parse of the contents and a return of the result is
449
- * completed. The parse uses the strict mode.
481
+ * completed. The parse uses the strict mode. Optional arguments are ignored.
450
482
  *
451
483
  * *return* [_Hash_|_Array_|_String_|_Integer_|_Float_|_True_|_False_|_nil|)
452
484
  */
453
- static VALUE str_writer_as_json(VALUE self) {
485
+ static VALUE str_writer_as_json(int argc, VALUE *argv, VALUE self) {
454
486
  if (string_writer_optimized) {
455
487
  return self;
456
488
  }
@@ -481,5 +513,5 @@ void oj_string_writer_init(void) {
481
513
  rb_define_method(oj_string_writer_class, "reset", str_writer_reset, 0);
482
514
  rb_define_method(oj_string_writer_class, "to_s", str_writer_to_s, 0);
483
515
  rb_define_method(oj_string_writer_class, "raw_json", str_writer_to_s, 0);
484
- rb_define_method(oj_string_writer_class, "as_json", str_writer_as_json, 0);
516
+ rb_define_method(oj_string_writer_class, "as_json", str_writer_as_json, -1);
485
517
  }
data/ext/oj/usual.c CHANGED
@@ -63,7 +63,7 @@ static VALUE form_attr(const char *str, size_t len) {
63
63
  memcpy(b + 1, str, len);
64
64
  b[len + 1] = '\0';
65
65
 
66
- id = rb_intern3(buf, len + 1, oj_utf8_encoding);
66
+ id = rb_intern3(b, len + 1, oj_utf8_encoding);
67
67
  OJ_R_FREE(b);
68
68
  return id;
69
69
  }
@@ -200,7 +200,10 @@ static void push_key(ojParser p) {
200
200
  d->ktail = d->khead + pos;
201
201
  d->kend = d->khead + cap;
202
202
  }
203
- d->ktail->len = klen;
203
+ if (32000 < klen) {
204
+ rb_raise(oj_json_parser_error_class, "Key too long. Keys are limited to 32,000 bytes.");
205
+ }
206
+ d->ktail->len = (int16_t)klen;
204
207
  if (klen < sizeof(d->ktail->buf)) {
205
208
  memcpy(d->ktail->buf, key, klen);
206
209
  d->ktail->buf[klen] = '\0';
@@ -281,7 +284,6 @@ static void close_object(ojParser p) {
281
284
  VALUE *head = d->vhead + c->vi + 1;
282
285
  volatile VALUE obj = rb_hash_new();
283
286
 
284
- #if HAVE_RB_HASH_BULK_INSERT
285
287
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
286
288
  *vp = d->get_key(p, kp);
287
289
  if (sizeof(kp->buf) <= (size_t)kp->len) {
@@ -289,18 +291,15 @@ static void close_object(ojParser p) {
289
291
  }
290
292
  }
291
293
  rb_hash_bulk_insert(d->vtail - head, head, obj);
292
- #else
293
- for (vp = head; kp < d->ktail; kp++, vp += 2) {
294
- rb_hash_aset(obj, d->get_key(p, kp), *(vp + 1));
295
- if (sizeof(kp->buf) <= (size_t)kp->len) {
296
- OJ_R_FREE(kp->key);
297
- }
298
- }
299
- #endif
300
294
  d->ktail = d->khead + c->ki;
295
+
301
296
  d->vtail = head;
302
297
  head--;
303
298
  *head = obj;
299
+ if (1 == d->vtail - d->vhead && rb_block_given_p()) {
300
+ d->vtail = d->vhead;
301
+ rb_yield(obj);
302
+ }
304
303
  }
305
304
 
306
305
  static void close_object_class(ojParser p) {
@@ -341,7 +340,6 @@ static void close_object_create(ojParser p) {
341
340
  head++;
342
341
  if (Qnil == d->hash_class) {
343
342
  obj = rb_hash_new();
344
- #if HAVE_RB_HASH_BULK_INSERT
345
343
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
346
344
  *vp = d->get_key(p, kp);
347
345
  if (sizeof(kp->buf) <= (size_t)kp->len) {
@@ -349,14 +347,6 @@ static void close_object_create(ojParser p) {
349
347
  }
350
348
  }
351
349
  rb_hash_bulk_insert(d->vtail - head, head, obj);
352
- #else
353
- for (vp = head; kp < d->ktail; kp++, vp += 2) {
354
- rb_hash_aset(obj, d->get_key(p, kp), *(vp + 1));
355
- if (sizeof(kp->buf) <= (size_t)kp->len) {
356
- OJ_R_FREE(kp->key);
357
- }
358
- }
359
- #endif
360
350
  } else {
361
351
  obj = rb_class_new_instance(0, NULL, d->hash_class);
362
352
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
@@ -373,7 +363,6 @@ static void close_object_create(ojParser p) {
373
363
  if (!d->ignore_json_create && rb_respond_to(clas, oj_json_create_id)) {
374
364
  volatile VALUE arg = rb_hash_new();
375
365
 
376
- #if HAVE_RB_HASH_BULK_INSERT
377
366
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
378
367
  *vp = d->get_key(p, kp);
379
368
  if (sizeof(kp->buf) <= (size_t)kp->len) {
@@ -381,14 +370,6 @@ static void close_object_create(ojParser p) {
381
370
  }
382
371
  }
383
372
  rb_hash_bulk_insert(d->vtail - head, head, arg);
384
- #else
385
- for (vp = head; kp < d->ktail; kp++, vp += 2) {
386
- rb_hash_aset(arg, d->get_key(p, kp), *(vp + 1));
387
- if (sizeof(kp->buf) <= (size_t)kp->len) {
388
- OJ_R_FREE(kp->key);
389
- }
390
- }
391
- #endif
392
373
  obj = rb_funcall(clas, oj_json_create_id, 1, arg);
393
374
  } else {
394
375
  obj = rb_class_new_instance(0, NULL, clas);
@@ -599,7 +580,21 @@ static VALUE result(ojParser p) {
599
580
  Usual d = (Usual)p->ctx;
600
581
 
601
582
  if (d->vhead < d->vtail) {
602
- return *d->vhead;
583
+ long cnt = d->vtail - d->vhead;
584
+ volatile VALUE ary;
585
+ volatile VALUE *vp;
586
+
587
+ if (1 == cnt) {
588
+ return *d->vhead;
589
+ }
590
+ ary = rb_ary_new();
591
+ for (vp = d->vhead; vp < d->vtail; vp++) {
592
+ rb_ary_push(ary, *vp);
593
+ }
594
+ return ary;
595
+ }
596
+ if (d->raise_on_empty) {
597
+ rb_raise(oj_parse_error_class, "empty string");
603
598
  }
604
599
  return Qnil;
605
600
  }
@@ -616,12 +611,16 @@ static void dfree(ojParser p) {
616
611
  Usual d = (Usual)p->ctx;
617
612
 
618
613
  cache_free(d->str_cache);
614
+ d->str_cache = NULL;
619
615
  cache_free(d->attr_cache);
616
+ d->attr_cache = NULL;
620
617
  if (NULL != d->sym_cache) {
621
618
  cache_free(d->sym_cache);
619
+ d->sym_cache = NULL;
622
620
  }
623
621
  if (NULL != d->class_cache) {
624
622
  cache_free(d->class_cache);
623
+ d->class_cache = NULL;
625
624
  }
626
625
  OJ_R_FREE(d->vhead);
627
626
  OJ_R_FREE(d->chead);
@@ -648,6 +647,12 @@ static void mark(ojParser p) {
648
647
  if (NULL != d->class_cache) {
649
648
  cache_mark(d->class_cache);
650
649
  }
650
+ if (Qnil != d->hash_class) {
651
+ rb_gc_mark(d->hash_class);
652
+ }
653
+ if (Qnil != d->array_class) {
654
+ rb_gc_mark(d->array_class);
655
+ }
651
656
  for (vp = d->vhead; vp < d->vtail; vp++) {
652
657
  if (Qundef != *vp) {
653
658
  rb_gc_mark(*vp);
@@ -842,8 +847,8 @@ static VALUE opt_create_id_set(ojParser p, VALUE value) {
842
847
  rb_check_type(value, T_STRING);
843
848
  size_t len = RSTRING_LEN(value);
844
849
 
845
- if (1 << sizeof(d->create_id_len) <= len) {
846
- rb_raise(rb_eArgError, "The create_id values is limited to %d bytes.", 1 << sizeof(d->create_id_len));
850
+ if (1 << (8 * sizeof(d->create_id_len)) <= len) {
851
+ rb_raise(rb_eArgError, "The create_id values is limited to %d bytes.", 1 << (8 * sizeof(d->create_id_len)));
847
852
  }
848
853
  d->create_id_len = (uint8_t)len;
849
854
  d->create_id = str_dup(RSTRING_PTR(value), len);
@@ -1058,14 +1063,28 @@ static VALUE opt_symbol_keys_set(ojParser p, VALUE value) {
1058
1063
  if (NULL != d->sym_cache) {
1059
1064
  cache_free(d->sym_cache);
1060
1065
  d->sym_cache = NULL;
1066
+ d->key_cache = NULL;
1061
1067
  }
1062
- if (!d->cache_keys) {
1063
- d->get_key = str_key;
1064
- }
1068
+ d->cache_keys = false;
1069
+ d->get_key = str_key;
1065
1070
  }
1066
1071
  return (NULL != d->sym_cache) ? Qtrue : Qfalse;
1067
1072
  }
1068
1073
 
1074
+ static VALUE opt_raise_on_empty(ojParser p, VALUE value) {
1075
+ Usual d = (Usual)p->ctx;
1076
+
1077
+ return d->raise_on_empty ? Qtrue : Qfalse;
1078
+ }
1079
+
1080
+ static VALUE opt_raise_on_empty_set(ojParser p, VALUE value) {
1081
+ Usual d = (Usual)p->ctx;
1082
+
1083
+ d->raise_on_empty = (Qtrue == value);
1084
+
1085
+ return d->raise_on_empty ? Qtrue : Qfalse;
1086
+ }
1087
+
1069
1088
  static VALUE option(ojParser p, const char *key, VALUE value) {
1070
1089
  struct opt *op;
1071
1090
  struct opt opts[] = {
@@ -1095,6 +1114,8 @@ static VALUE option(ojParser p, const char *key, VALUE value) {
1095
1114
  {.name = "omit_null=", .func = opt_omit_null_set},
1096
1115
  {.name = "symbol_keys", .func = opt_symbol_keys},
1097
1116
  {.name = "symbol_keys=", .func = opt_symbol_keys_set},
1117
+ {.name = "raise_on_empty", .func = opt_raise_on_empty},
1118
+ {.name = "raise_on_empty=", .func = opt_raise_on_empty_set},
1098
1119
  {.name = NULL},
1099
1120
  };
1100
1121
 
@@ -1129,6 +1150,7 @@ void oj_init_usual(ojParser p, Usual d) {
1129
1150
  d->get_key = cache_key;
1130
1151
  d->cache_keys = true;
1131
1152
  d->ignore_json_create = false;
1153
+ d->raise_on_empty = false;
1132
1154
  d->cache_str = 6;
1133
1155
  d->array_class = Qnil;
1134
1156
  d->hash_class = Qnil;
data/ext/oj/usual.h CHANGED
@@ -60,6 +60,7 @@ typedef struct _usual {
60
60
  uint8_t miss_class;
61
61
  bool cache_keys;
62
62
  bool ignore_json_create;
63
+ bool raise_on_empty;
63
64
  } *Usual;
64
65
 
65
66
  // Initialize the parser with the usual delegate. If the usual delegate is
data/ext/oj/val_stack.c CHANGED
@@ -8,7 +8,7 @@
8
8
  #include "odd.h"
9
9
  #include "oj.h"
10
10
 
11
- static void mark(void *ptr) {
11
+ static void stack_mark(void *ptr) {
12
12
  ValStack stack = (ValStack)ptr;
13
13
  Val v;
14
14
 
@@ -46,6 +46,17 @@ static void mark(void *ptr) {
46
46
  #endif
47
47
  }
48
48
 
49
+ static const rb_data_type_t oj_stack_type = {
50
+ "Oj/stack",
51
+ {
52
+ stack_mark,
53
+ NULL,
54
+ NULL,
55
+ },
56
+ 0,
57
+ 0,
58
+ };
59
+
49
60
  VALUE
50
61
  oj_stack_init(ValStack stack) {
51
62
  #ifdef HAVE_PTHREAD_MUTEX_INIT
@@ -70,7 +81,7 @@ oj_stack_init(ValStack stack) {
70
81
  stack->head->clen = 0;
71
82
  stack->head->next = NEXT_NONE;
72
83
 
73
- return Data_Wrap_Struct(oj_cstack_class, mark, 0, stack);
84
+ return TypedData_Wrap_Struct(oj_cstack_class, &oj_stack_type, stack);
74
85
  }
75
86
 
76
87
  const char *oj_stack_next_string(ValNext n) {
data/ext/oj/wab.c CHANGED
@@ -19,7 +19,7 @@
19
19
  // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
20
20
  #define OJ_INFINITY (1.0 / 0.0)
21
21
 
22
- static char hex_chars[256] = "\
22
+ static char hex_chars[257] = "\
23
23
  ................................\
24
24
  ................xxxxxxxxxx......\
25
25
  .xxxxxx.........................\
@@ -111,10 +111,11 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
111
111
 
112
112
  static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
113
113
  size_t size;
114
- int i, cnt;
114
+ size_t i;
115
+ size_t cnt;
115
116
  int d2 = depth + 1;
116
117
 
117
- cnt = (int)RARRAY_LEN(a);
118
+ cnt = RARRAY_LEN(a);
118
119
  *out->cur++ = '[';
119
120
  size = 2;
120
121
  assure_size(out, size);
@@ -226,7 +227,7 @@ static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
226
227
  } else if (oj_bigdecimal_class == clas) {
227
228
  volatile VALUE rstr = oj_safe_string_convert(obj);
228
229
 
229
- oj_dump_raw(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), out);
230
+ oj_dump_raw(RSTRING_PTR(rstr), RSTRING_LEN(rstr), out);
230
231
  } else if (resolve_wab_uuid_class() == clas) {
231
232
  oj_dump_str(oj_safe_string_convert(obj), depth, out, false);
232
233
  } else if (resolve_uri_http_class() == clas) {
data/lib/oj/mimic.rb CHANGED
@@ -1,11 +1,7 @@
1
1
  # frozen_string_literal: false
2
2
 
3
3
  require 'bigdecimal'
4
- begin
5
- require 'ostruct'
6
- rescue Exception
7
- # ignore
8
- end
4
+ require 'ostruct'
9
5
 
10
6
  module Oj
11
7
 
data/lib/oj/schandler.rb CHANGED
@@ -64,13 +64,14 @@ module Oj
64
64
  #
65
65
  # hash_end
66
66
  #
67
- # When a hash key is encountered the hash_key method is called with the parsed
68
- # hash value key. The return value from the call is then used as the key in
69
- # the key-value pair that follows.
67
+ # At the end of a JSON object element the hash_end() callback is called if
68
+ # public.
70
69
  #
71
70
  # hash_key
72
71
  #
73
- # At the end of a JSON object element the hash_end() callback is called if public.
72
+ # When a hash key is encountered the hash_key() method is called with the
73
+ # parsed hash value key. The return value from the call is then used as the
74
+ # key in the key-value pair that follows.
74
75
  #
75
76
  # hash_set
76
77
  #
data/lib/oj/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Oj
2
2
  # Current version of the module.
3
- VERSION = '3.16.0'
3
+ VERSION = '3.17.3'
4
4
  end
data/pages/Encoding.md CHANGED
@@ -15,7 +15,7 @@ in a JSON document. The formatting follows these rules.
15
15
  * The `'^'` character denotes a special key value when in a JSON Object sequence.
16
16
 
17
17
  * A Ruby String that starts with `':'`or the sequence `'^i'` or `'^r'` are
18
- encoded by excaping the first character so that it appears as `'\u005e'` or
18
+ encoded by escaping the first character so that it appears as `'\u005e'` or
19
19
  `'\u003a'` instead of `':'` or `'^'`.
20
20
 
21
21
  * A `"^c"` JSON Object key indicates the value should be converted to a Ruby