oj 3.13.23 → 3.16.10

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 (178) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +86 -0
  3. data/README.md +2 -2
  4. data/ext/oj/buf.h +7 -6
  5. data/ext/oj/cache.c +29 -26
  6. data/ext/oj/cache.h +3 -2
  7. data/ext/oj/cache8.c +10 -9
  8. data/ext/oj/circarray.c +7 -5
  9. data/ext/oj/circarray.h +2 -2
  10. data/ext/oj/code.c +5 -12
  11. data/ext/oj/code.h +2 -2
  12. data/ext/oj/compat.c +20 -60
  13. data/ext/oj/custom.c +26 -59
  14. data/ext/oj/debug.c +3 -9
  15. data/ext/oj/dump.c +103 -53
  16. data/ext/oj/dump.h +1 -4
  17. data/ext/oj/dump_compat.c +557 -592
  18. data/ext/oj/dump_leaf.c +3 -5
  19. data/ext/oj/dump_object.c +42 -48
  20. data/ext/oj/dump_strict.c +10 -22
  21. data/ext/oj/encoder.c +1 -1
  22. data/ext/oj/err.c +2 -13
  23. data/ext/oj/err.h +9 -12
  24. data/ext/oj/extconf.rb +16 -7
  25. data/ext/oj/fast.c +63 -98
  26. data/ext/oj/intern.c +62 -47
  27. data/ext/oj/intern.h +3 -7
  28. data/ext/oj/mem.c +318 -0
  29. data/ext/oj/mem.h +53 -0
  30. data/ext/oj/mimic_json.c +54 -38
  31. data/ext/oj/object.c +33 -43
  32. data/ext/oj/odd.c +8 -6
  33. data/ext/oj/odd.h +4 -4
  34. data/ext/oj/oj.c +245 -216
  35. data/ext/oj/oj.h +83 -81
  36. data/ext/oj/parse.c +109 -153
  37. data/ext/oj/parse.h +21 -24
  38. data/ext/oj/parser.c +80 -67
  39. data/ext/oj/parser.h +9 -8
  40. data/ext/oj/rails.c +71 -94
  41. data/ext/oj/reader.c +9 -14
  42. data/ext/oj/reader.h +4 -2
  43. data/ext/oj/resolve.c +3 -4
  44. data/ext/oj/rxclass.c +6 -5
  45. data/ext/oj/rxclass.h +1 -1
  46. data/ext/oj/saj.c +13 -15
  47. data/ext/oj/saj2.c +37 -49
  48. data/ext/oj/saj2.h +1 -1
  49. data/ext/oj/scp.c +6 -20
  50. data/ext/oj/sparse.c +22 -70
  51. data/ext/oj/stream_writer.c +46 -48
  52. data/ext/oj/strict.c +22 -56
  53. data/ext/oj/string_writer.c +64 -40
  54. data/ext/oj/trace.h +31 -4
  55. data/ext/oj/usual.c +125 -114
  56. data/ext/oj/usual.h +7 -6
  57. data/ext/oj/util.h +1 -1
  58. data/ext/oj/val_stack.c +13 -2
  59. data/ext/oj/val_stack.h +8 -7
  60. data/ext/oj/wab.c +25 -57
  61. data/lib/oj/active_support_helper.rb +1 -3
  62. data/lib/oj/bag.rb +7 -1
  63. data/lib/oj/easy_hash.rb +4 -5
  64. data/lib/oj/error.rb +0 -1
  65. data/lib/oj/json.rb +162 -150
  66. data/lib/oj/mimic.rb +7 -7
  67. data/lib/oj/schandler.rb +5 -4
  68. data/lib/oj/state.rb +8 -5
  69. data/lib/oj/version.rb +1 -2
  70. data/lib/oj.rb +2 -0
  71. data/pages/InstallOptions.md +20 -0
  72. data/pages/Options.md +4 -0
  73. metadata +46 -121
  74. data/test/_test_active.rb +0 -76
  75. data/test/_test_active_mimic.rb +0 -96
  76. data/test/_test_mimic_rails.rb +0 -126
  77. data/test/activerecord/result_test.rb +0 -32
  78. data/test/activesupport4/decoding_test.rb +0 -108
  79. data/test/activesupport4/encoding_test.rb +0 -531
  80. data/test/activesupport4/test_helper.rb +0 -41
  81. data/test/activesupport5/abstract_unit.rb +0 -45
  82. data/test/activesupport5/decoding_test.rb +0 -133
  83. data/test/activesupport5/encoding_test.rb +0 -500
  84. data/test/activesupport5/encoding_test_cases.rb +0 -98
  85. data/test/activesupport5/test_helper.rb +0 -72
  86. data/test/activesupport5/time_zone_test_helpers.rb +0 -39
  87. data/test/activesupport6/abstract_unit.rb +0 -44
  88. data/test/activesupport6/decoding_test.rb +0 -133
  89. data/test/activesupport6/encoding_test.rb +0 -507
  90. data/test/activesupport6/encoding_test_cases.rb +0 -98
  91. data/test/activesupport6/test_common.rb +0 -17
  92. data/test/activesupport6/test_helper.rb +0 -163
  93. data/test/activesupport6/time_zone_test_helpers.rb +0 -39
  94. data/test/activesupport7/abstract_unit.rb +0 -49
  95. data/test/activesupport7/decoding_test.rb +0 -125
  96. data/test/activesupport7/encoding_test.rb +0 -486
  97. data/test/activesupport7/encoding_test_cases.rb +0 -104
  98. data/test/activesupport7/time_zone_test_helpers.rb +0 -47
  99. data/test/bar.rb +0 -11
  100. data/test/baz.rb +0 -16
  101. data/test/bug.rb +0 -16
  102. data/test/files.rb +0 -29
  103. data/test/foo.rb +0 -77
  104. data/test/helper.rb +0 -42
  105. data/test/isolated/shared.rb +0 -308
  106. data/test/isolated/test_mimic_after.rb +0 -13
  107. data/test/isolated/test_mimic_alone.rb +0 -12
  108. data/test/isolated/test_mimic_as_json.rb +0 -45
  109. data/test/isolated/test_mimic_before.rb +0 -13
  110. data/test/isolated/test_mimic_define.rb +0 -28
  111. data/test/isolated/test_mimic_rails_after.rb +0 -22
  112. data/test/isolated/test_mimic_rails_before.rb +0 -21
  113. data/test/isolated/test_mimic_redefine.rb +0 -15
  114. data/test/json_gem/json_addition_test.rb +0 -216
  115. data/test/json_gem/json_common_interface_test.rb +0 -153
  116. data/test/json_gem/json_encoding_test.rb +0 -107
  117. data/test/json_gem/json_ext_parser_test.rb +0 -20
  118. data/test/json_gem/json_fixtures_test.rb +0 -35
  119. data/test/json_gem/json_generator_test.rb +0 -396
  120. data/test/json_gem/json_generic_object_test.rb +0 -90
  121. data/test/json_gem/json_parser_test.rb +0 -477
  122. data/test/json_gem/json_string_matching_test.rb +0 -42
  123. data/test/json_gem/test_helper.rb +0 -30
  124. data/test/mem.rb +0 -33
  125. data/test/perf.rb +0 -107
  126. data/test/perf_compat.rb +0 -130
  127. data/test/perf_dump.rb +0 -50
  128. data/test/perf_fast.rb +0 -164
  129. data/test/perf_file.rb +0 -64
  130. data/test/perf_object.rb +0 -138
  131. data/test/perf_once.rb +0 -58
  132. data/test/perf_parser.rb +0 -189
  133. data/test/perf_saj.rb +0 -109
  134. data/test/perf_scp.rb +0 -152
  135. data/test/perf_simple.rb +0 -287
  136. data/test/perf_strict.rb +0 -139
  137. data/test/perf_wab.rb +0 -131
  138. data/test/prec.rb +0 -23
  139. data/test/sample/change.rb +0 -14
  140. data/test/sample/dir.rb +0 -19
  141. data/test/sample/doc.rb +0 -36
  142. data/test/sample/file.rb +0 -48
  143. data/test/sample/group.rb +0 -16
  144. data/test/sample/hasprops.rb +0 -16
  145. data/test/sample/layer.rb +0 -12
  146. data/test/sample/line.rb +0 -20
  147. data/test/sample/oval.rb +0 -10
  148. data/test/sample/rect.rb +0 -10
  149. data/test/sample/shape.rb +0 -35
  150. data/test/sample/text.rb +0 -20
  151. data/test/sample.rb +0 -54
  152. data/test/sample_json.rb +0 -37
  153. data/test/test_compat.rb +0 -540
  154. data/test/test_custom.rb +0 -544
  155. data/test/test_debian.rb +0 -53
  156. data/test/test_fast.rb +0 -530
  157. data/test/test_file.rb +0 -255
  158. data/test/test_gc.rb +0 -60
  159. data/test/test_generate.rb +0 -21
  160. data/test/test_hash.rb +0 -39
  161. data/test/test_integer_range.rb +0 -72
  162. data/test/test_null.rb +0 -376
  163. data/test/test_object.rb +0 -1025
  164. data/test/test_parser.rb +0 -11
  165. data/test/test_parser_debug.rb +0 -27
  166. data/test/test_parser_saj.rb +0 -335
  167. data/test/test_parser_usual.rb +0 -217
  168. data/test/test_rails.rb +0 -35
  169. data/test/test_saj.rb +0 -186
  170. data/test/test_scp.rb +0 -431
  171. data/test/test_strict.rb +0 -435
  172. data/test/test_various.rb +0 -752
  173. data/test/test_wab.rb +0 -309
  174. data/test/test_writer.rb +0 -380
  175. data/test/tests.rb +0 -33
  176. data/test/tests_mimic.rb +0 -23
  177. data/test/tests_mimic_addition.rb +0 -16
  178. data/test/zoo.rb +0 -13
data/ext/oj/dump.c CHANGED
@@ -15,6 +15,7 @@
15
15
  #endif
16
16
 
17
17
  #include "cache8.h"
18
+ #include "mem.h"
18
19
  #include "odd.h"
19
20
  #include "oj.h"
20
21
  #include "trace.h"
@@ -197,7 +198,18 @@ inline static long rails_xss_friendly_size(const uint8_t *str, size_t len) {
197
198
  }
198
199
 
199
200
  inline static size_t rails_friendly_size(const uint8_t *str, size_t len) {
200
- return calculate_string_size(str, len, rails_friendly_chars);
201
+ long size = 0;
202
+ size_t i = len;
203
+ uint8_t hi = 0;
204
+
205
+ for (; 0 < i; str++, i--) {
206
+ size += rails_friendly_chars[*str];
207
+ hi |= *str & 0x80;
208
+ }
209
+ if (0 == hi) {
210
+ return size - len * (size_t)'0';
211
+ }
212
+ return -(size - len * (size_t)'0');
201
213
  }
202
214
 
203
215
  const char *oj_nan_str(VALUE obj, int opt, int mode, bool plus, int *lenp) {
@@ -305,8 +317,8 @@ static const char *dump_unicode(const char *str, const char *end, Out out, const
305
317
  uint32_t c1;
306
318
 
307
319
  code -= 0x00010000;
308
- c1 = ((code >> 10) & 0x000003FF) + 0x0000D800;
309
- code = (code & 0x000003FF) + 0x0000DC00;
320
+ c1 = ((code >> 10) & 0x000003FF) + 0x0000D800;
321
+ code = (code & 0x000003FF) + 0x0000DC00;
310
322
  APPEND_CHARS(out->cur, "\\u", 2);
311
323
  for (i = 3; 0 <= i; i--) {
312
324
  *out->cur++ = hex_chars[(uint8_t)(c1 >> (i * 4)) & 0x0F];
@@ -463,7 +475,7 @@ void oj_dump_time(VALUE obj, Out out, int withZone) {
463
475
  }
464
476
 
465
477
  void oj_dump_ruby_time(VALUE obj, Out out) {
466
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
478
+ volatile VALUE rstr = oj_safe_string_convert(obj);
467
479
 
468
480
  oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
469
481
  }
@@ -609,7 +621,7 @@ void oj_write_obj_to_file(VALUE obj, const char *path, Options copts) {
609
621
 
610
622
  oj_out_init(&out);
611
623
 
612
- out.omit_nil = copts->dump_opts.omit_nil;
624
+ out.omit_nil = copts->dump_opts.omit_nil;
613
625
  oj_dump_obj_to_json(obj, copts, &out);
614
626
  size = out.cur - out.buf;
615
627
  if (0 == (f = fopen(path, "w"))) {
@@ -657,7 +669,7 @@ void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
657
669
 
658
670
  oj_out_init(&out);
659
671
 
660
- out.omit_nil = copts->dump_opts.omit_nil;
672
+ out.omit_nil = copts->dump_opts.omit_nil;
661
673
  oj_dump_obj_to_json(obj, copts, &out);
662
674
  size = out.cur - out.buf;
663
675
  if (oj_stringio_class == clas) {
@@ -697,7 +709,7 @@ void oj_dump_str(VALUE obj, int depth, Out out, bool as_ok) {
697
709
 
698
710
  if (oj_utf8_encoding_index != idx) {
699
711
  rb_encoding *enc = rb_enc_from_index(idx);
700
- obj = rb_str_conv_enc(obj, enc, oj_utf8_encoding);
712
+ obj = rb_str_conv_enc(obj, enc, oj_utf8_encoding);
701
713
  }
702
714
  oj_dump_cstr(RSTRING_PTR(obj), (int)RSTRING_LEN(obj), 0, 0, out);
703
715
  }
@@ -726,8 +738,11 @@ static void debug_raise(const char *orig, size_t cnt, int line) {
726
738
 
727
739
  void oj_dump_raw_json(VALUE obj, int depth, Out out) {
728
740
  if (oj_string_writer_class == rb_obj_class(obj)) {
729
- StrWriter sw = (StrWriter)DATA_PTR(obj);
730
- size_t len = sw->out.cur - sw->out.buf;
741
+ StrWriter sw;
742
+ size_t len;
743
+
744
+ sw = oj_str_writer_unwrap(obj);
745
+ len = sw->out.cur - sw->out.buf;
731
746
 
732
747
  if (0 < len) {
733
748
  len--;
@@ -736,13 +751,9 @@ void oj_dump_raw_json(VALUE obj, int depth, Out out) {
736
751
  } else {
737
752
  volatile VALUE jv;
738
753
 
739
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
740
- oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
741
- }
754
+ TRACE(out->opts->trace, "raw_json", obj, depth + 1, TraceRubyIn);
742
755
  jv = rb_funcall(obj, oj_raw_json_id, 2, RB_INT2NUM(depth), RB_INT2NUM(out->indent));
743
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
744
- oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
745
- }
756
+ TRACE(out->opts->trace, "raw_json", obj, depth + 1, TraceRubyOut);
746
757
  oj_dump_raw(RSTRING_PTR(jv), (size_t)RSTRING_LEN(jv), out);
747
758
  }
748
759
  }
@@ -750,8 +761,9 @@ void oj_dump_raw_json(VALUE obj, int depth, Out out) {
750
761
  void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out out) {
751
762
  size_t size;
752
763
  char *cmap;
753
- const char *orig = str;
754
- bool has_hi = false;
764
+ const char *orig = str;
765
+ bool has_hi = false;
766
+ bool do_unicode_validation = false;
755
767
 
756
768
  switch (out->opts->escape_mode) {
757
769
  case NLEsc:
@@ -764,16 +776,17 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
764
776
  break;
765
777
  case SlashEsc:
766
778
  has_hi = true;
767
- cmap = slash_friendly_chars;
768
- size = slash_friendly_size((uint8_t *)str, cnt);
779
+ cmap = slash_friendly_chars;
780
+ size = slash_friendly_size((uint8_t *)str, cnt);
769
781
  break;
770
782
  case XSSEsc:
771
783
  cmap = xss_friendly_chars;
772
784
  size = xss_friendly_size((uint8_t *)str, cnt);
773
785
  break;
774
786
  case JXEsc:
775
- cmap = hixss_friendly_chars;
776
- size = hixss_friendly_size((uint8_t *)str, cnt);
787
+ cmap = hixss_friendly_chars;
788
+ size = hixss_friendly_size((uint8_t *)str, cnt);
789
+ do_unicode_validation = true;
777
790
  break;
778
791
  case RailsXEsc: {
779
792
  long sz;
@@ -786,12 +799,22 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
786
799
  } else {
787
800
  size = (size_t)sz;
788
801
  }
802
+ do_unicode_validation = true;
789
803
  break;
790
804
  }
791
- case RailsEsc:
805
+ case RailsEsc: {
806
+ long sz;
792
807
  cmap = rails_friendly_chars;
793
- size = rails_friendly_size((uint8_t *)str, cnt);
808
+ sz = rails_friendly_size((uint8_t *)str, cnt);
809
+ if (sz < 0) {
810
+ has_hi = true;
811
+ size = (size_t)-sz;
812
+ } else {
813
+ size = (size_t)sz;
814
+ }
815
+ do_unicode_validation = true;
794
816
  break;
817
+ }
795
818
  case JSONEsc:
796
819
  default: cmap = hibit_friendly_chars; size = hibit_friendly_size((uint8_t *)str, cnt);
797
820
  }
@@ -822,7 +845,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
822
845
  for (; str < end; str++) {
823
846
  switch (cmap[(uint8_t)*str]) {
824
847
  case '1':
825
- if ((JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && check_start <= str) {
848
+ if (do_unicode_validation && check_start <= str) {
826
849
  if (0 != (0x80 & (uint8_t)*str)) {
827
850
  if (0xC0 == (0xC0 & (uint8_t)*str)) {
828
851
  check_start = check_unicode(str, end, orig);
@@ -846,8 +869,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
846
869
  }
847
870
  break;
848
871
  case '3': // Unicode
849
- if (0xe2 == (uint8_t)*str && (JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) &&
850
- 2 <= end - str) {
872
+ if (0xe2 == (uint8_t)*str && do_unicode_validation && 2 <= end - str) {
851
873
  if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
852
874
  str = dump_unicode(str, end, out, orig);
853
875
  } else {
@@ -860,11 +882,13 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
860
882
  break;
861
883
  case '6': // control characters
862
884
  if (*(uint8_t *)str < 0x80) {
885
+ if (0 == (uint8_t)*str && out->opts->dump_opts.omit_null_byte) {
886
+ break;
887
+ }
863
888
  APPEND_CHARS(out->cur, "\\u00", 4);
864
889
  dump_hex((uint8_t)*str, out);
865
890
  } else {
866
- if (0xe2 == (uint8_t)*str &&
867
- (JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && 2 <= end - str) {
891
+ if (0xe2 == (uint8_t)*str && do_unicode_validation && 2 <= end - str) {
868
892
  if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
869
893
  str = dump_unicode(str, end, out, orig);
870
894
  } else {
@@ -881,8 +905,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
881
905
  }
882
906
  *out->cur++ = '"';
883
907
  }
884
- if ((JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && 0 < str - orig &&
885
- 0 != (0x80 & *(str - 1))) {
908
+ if (do_unicode_validation && 0 < str - orig && 0 != (0x80 & *(str - 1))) {
886
909
  uint8_t c = (uint8_t) * (str - 1);
887
910
  int i;
888
911
  int scnt = (int)(str - orig);
@@ -932,7 +955,7 @@ void oj_dump_class(VALUE obj, int depth, Out out, bool as_ok) {
932
955
  }
933
956
 
934
957
  void oj_dump_obj_to_s(VALUE obj, Out out) {
935
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
958
+ volatile VALUE rstr = oj_safe_string_convert(obj);
936
959
 
937
960
  oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
938
961
  }
@@ -944,15 +967,15 @@ void oj_dump_raw(const char *str, size_t cnt, Out out) {
944
967
  }
945
968
 
946
969
  void oj_out_init(Out out) {
947
- out->buf = out->stack_buffer;
948
- out->cur = out->buf;
949
- out->end = out->buf + sizeof(out->stack_buffer) - BUFFER_EXTRA;
970
+ out->buf = out->stack_buffer;
971
+ out->cur = out->buf;
972
+ out->end = out->buf + sizeof(out->stack_buffer) - BUFFER_EXTRA;
950
973
  out->allocated = false;
951
974
  }
952
975
 
953
976
  void oj_out_free(Out out) {
954
977
  if (out->allocated) {
955
- xfree(out->buf); // TBD
978
+ OJ_R_FREE(out->buf); // TBD
956
979
  }
957
980
  }
958
981
 
@@ -966,9 +989,9 @@ void oj_grow_out(Out out, size_t len) {
966
989
  size += len;
967
990
  }
968
991
  if (out->allocated) {
969
- REALLOC_N(buf, char, (size + BUFFER_EXTRA));
992
+ OJ_R_REALLOC_N(buf, char, (size + BUFFER_EXTRA));
970
993
  } else {
971
- buf = ALLOC_N(char, (size + BUFFER_EXTRA));
994
+ buf = OJ_R_ALLOC_N(char, (size + BUFFER_EXTRA));
972
995
  out->allocated = true;
973
996
  memcpy(buf, out->buf, out->end - out->buf + BUFFER_EXTRA);
974
997
  }
@@ -983,26 +1006,60 @@ void oj_grow_out(Out out, size_t len) {
983
1006
  void oj_dump_nil(VALUE obj, int depth, Out out, bool as_ok) {
984
1007
  assure_size(out, 4);
985
1008
  APPEND_CHARS(out->cur, "null", 4);
986
- *out->cur = '\0';
1009
+ *out->cur = '\0';
987
1010
  }
988
1011
 
989
1012
  void oj_dump_true(VALUE obj, int depth, Out out, bool as_ok) {
990
1013
  assure_size(out, 4);
991
1014
  APPEND_CHARS(out->cur, "true", 4);
992
- *out->cur = '\0';
1015
+ *out->cur = '\0';
993
1016
  }
994
1017
 
995
1018
  void oj_dump_false(VALUE obj, int depth, Out out, bool as_ok) {
996
1019
  assure_size(out, 5);
997
1020
  APPEND_CHARS(out->cur, "false", 5);
998
- *out->cur = '\0';
1021
+ *out->cur = '\0';
1022
+ }
1023
+
1024
+ static const char digits_table[] = "\
1025
+ 00010203040506070809\
1026
+ 10111213141516171819\
1027
+ 20212223242526272829\
1028
+ 30313233343536373839\
1029
+ 40414243444546474849\
1030
+ 50515253545556575859\
1031
+ 60616263646566676869\
1032
+ 70717273747576777879\
1033
+ 80818283848586878889\
1034
+ 90919293949596979899";
1035
+
1036
+ char *oj_longlong_to_string(long long num, bool negative, char *buf) {
1037
+ while (100 <= num) {
1038
+ unsigned idx = num % 100 * 2;
1039
+ *buf-- = digits_table[idx + 1];
1040
+ *buf-- = digits_table[idx];
1041
+ num /= 100;
1042
+ }
1043
+ if (num < 10) {
1044
+ *buf-- = num + '0';
1045
+ } else {
1046
+ *buf-- = digits_table[num * 2 + 1];
1047
+ *buf-- = digits_table[num * 2];
1048
+ }
1049
+
1050
+ if (negative) {
1051
+ *buf = '-';
1052
+ } else {
1053
+ buf++;
1054
+ }
1055
+ return buf;
999
1056
  }
1000
1057
 
1001
1058
  void oj_dump_fixnum(VALUE obj, int depth, Out out, bool as_ok) {
1002
1059
  char buf[32];
1003
- char * b = buf + sizeof(buf) - 1;
1060
+ char *b = buf + sizeof(buf) - 1;
1004
1061
  long long num = NUM2LL(obj);
1005
- int neg = 0;
1062
+ bool neg = false;
1006
1063
  size_t cnt = 0;
1007
1064
  bool dump_as_string = false;
1008
1065
 
@@ -1011,7 +1068,7 @@ void oj_dump_fixnum(VALUE obj, int depth, Out out, bool as_ok) {
1011
1068
  dump_as_string = true;
1012
1069
  }
1013
1070
  if (0 > num) {
1014
- neg = 1;
1071
+ neg = true;
1015
1072
  num = -num;
1016
1073
  }
1017
1074
  *b-- = '\0';
@@ -1020,14 +1077,7 @@ void oj_dump_fixnum(VALUE obj, int depth, Out out, bool as_ok) {
1020
1077
  *b-- = '"';
1021
1078
  }
1022
1079
  if (0 < num) {
1023
- for (; 0 < num; num /= 10, b--) {
1024
- *b = (num % 10) + '0';
1025
- }
1026
- if (neg) {
1027
- *b = '-';
1028
- } else {
1029
- b++;
1030
- }
1080
+ b = oj_longlong_to_string(num, neg, b);
1031
1081
  } else {
1032
1082
  *b = '0';
1033
1083
  }
@@ -1173,7 +1223,7 @@ void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1173
1223
  } else if (d == (double)(long long int)d) {
1174
1224
  cnt = snprintf(buf, sizeof(buf), "%.1f", d);
1175
1225
  } else if (0 == out->opts->float_prec) {
1176
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
1226
+ volatile VALUE rstr = oj_safe_string_convert(obj);
1177
1227
 
1178
1228
  cnt = (int)RSTRING_LEN(rstr);
1179
1229
  if ((int)sizeof(buf) <= cnt) {
@@ -1195,7 +1245,7 @@ int oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char
1195
1245
  // Round off issues at 16 significant digits so check for obvious ones of
1196
1246
  // 0001 and 9999.
1197
1247
  if (17 <= cnt && (0 == strcmp("0001", buf + cnt - 4) || 0 == strcmp("9999", buf + cnt - 4))) {
1198
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
1248
+ volatile VALUE rstr = oj_safe_string_convert(obj);
1199
1249
 
1200
1250
  strcpy(buf, RSTRING_PTR(rstr));
1201
1251
  cnt = (int)RSTRING_LEN(rstr);
data/ext/oj/dump.h CHANGED
@@ -93,10 +93,7 @@ inline static void dump_ulong(unsigned long num, Out out) {
93
93
 
94
94
  *b-- = '\0';
95
95
  if (0 < num) {
96
- for (; 0 < num; num /= 10, b--) {
97
- *b = (num % 10) + '0';
98
- }
99
- b++;
96
+ b = oj_longlong_to_string((long long)num, false, b);
100
97
  } else {
101
98
  *b = '0';
102
99
  }