oj 3.13.23 → 3.16.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +81 -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 +60 -92
  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 +51 -32
  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 +243 -212
  35. data/ext/oj/oj.h +83 -81
  36. data/ext/oj/parse.c +94 -148
  37. data/ext/oj/parse.h +21 -24
  38. data/ext/oj/parser.c +80 -67
  39. data/ext/oj/parser.h +7 -8
  40. data/ext/oj/rails.c +70 -92
  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 +10 -9
  47. data/ext/oj/saj2.c +37 -49
  48. data/ext/oj/saj2.h +1 -1
  49. data/ext/oj/scp.c +3 -14
  50. data/ext/oj/sparse.c +22 -70
  51. data/ext/oj/stream_writer.c +45 -41
  52. data/ext/oj/strict.c +20 -52
  53. data/ext/oj/string_writer.c +64 -38
  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. data/test/_test_active.rb +8 -9
  74. data/test/_test_active_mimic.rb +7 -8
  75. data/test/_test_mimic_rails.rb +17 -20
  76. data/test/activerecord/result_test.rb +5 -6
  77. data/test/activesupport6/encoding_test.rb +63 -28
  78. data/test/activesupport7/abstract_unit.rb +4 -1
  79. data/test/activesupport7/encoding_test.rb +72 -22
  80. data/test/files.rb +15 -15
  81. data/test/foo.rb +18 -69
  82. data/test/helper.rb +5 -8
  83. data/test/isolated/shared.rb +3 -2
  84. data/test/json_gem/json_addition_test.rb +2 -2
  85. data/test/json_gem/json_common_interface_test.rb +8 -6
  86. data/test/json_gem/json_encoding_test.rb +0 -0
  87. data/test/json_gem/json_ext_parser_test.rb +1 -0
  88. data/test/json_gem/json_fixtures_test.rb +3 -2
  89. data/test/json_gem/json_generator_test.rb +50 -33
  90. data/test/json_gem/json_generic_object_test.rb +11 -11
  91. data/test/json_gem/json_parser_test.rb +46 -46
  92. data/test/json_gem/json_string_matching_test.rb +9 -9
  93. data/test/mem.rb +13 -12
  94. data/test/perf.rb +21 -26
  95. data/test/perf_compat.rb +31 -33
  96. data/test/perf_dump.rb +28 -28
  97. data/test/perf_fast.rb +80 -82
  98. data/test/perf_file.rb +27 -29
  99. data/test/perf_object.rb +65 -69
  100. data/test/perf_once.rb +12 -11
  101. data/test/perf_parser.rb +42 -48
  102. data/test/perf_saj.rb +46 -54
  103. data/test/perf_scp.rb +57 -69
  104. data/test/perf_simple.rb +41 -39
  105. data/test/perf_strict.rb +68 -70
  106. data/test/perf_wab.rb +67 -69
  107. data/test/prec.rb +5 -5
  108. data/test/sample/change.rb +0 -1
  109. data/test/sample/dir.rb +0 -1
  110. data/test/sample/doc.rb +0 -1
  111. data/test/sample/file.rb +0 -1
  112. data/test/sample/group.rb +0 -1
  113. data/test/sample/hasprops.rb +0 -1
  114. data/test/sample/layer.rb +0 -1
  115. data/test/sample/rect.rb +0 -1
  116. data/test/sample/shape.rb +0 -1
  117. data/test/sample/text.rb +0 -1
  118. data/test/sample.rb +16 -16
  119. data/test/sample_json.rb +8 -8
  120. data/test/test_compat.rb +81 -54
  121. data/test/test_custom.rb +63 -52
  122. data/test/test_debian.rb +7 -10
  123. data/test/test_fast.rb +86 -90
  124. data/test/test_file.rb +24 -29
  125. data/test/test_gc.rb +5 -5
  126. data/test/test_generate.rb +5 -5
  127. data/test/test_hash.rb +4 -4
  128. data/test/test_integer_range.rb +9 -9
  129. data/test/test_null.rb +20 -20
  130. data/test/test_object.rb +92 -87
  131. data/test/test_parser.rb +4 -4
  132. data/test/test_parser_debug.rb +5 -5
  133. data/test/test_parser_saj.rb +27 -25
  134. data/test/test_parser_usual.rb +44 -6
  135. data/test/test_rails.rb +2 -2
  136. data/test/test_saj.rb +10 -8
  137. data/test/test_scp.rb +35 -35
  138. data/test/test_strict.rb +38 -32
  139. data/test/test_various.rb +146 -97
  140. data/test/test_wab.rb +46 -44
  141. data/test/test_writer.rb +63 -47
  142. data/test/tests.rb +7 -7
  143. data/test/tests_mimic.rb +6 -6
  144. data/test/tests_mimic_addition.rb +6 -6
  145. metadata +46 -26
  146. data/test/activesupport4/decoding_test.rb +0 -108
  147. data/test/activesupport4/encoding_test.rb +0 -531
  148. data/test/activesupport4/test_helper.rb +0 -41
  149. data/test/activesupport5/abstract_unit.rb +0 -45
  150. data/test/activesupport5/decoding_test.rb +0 -133
  151. data/test/activesupport5/encoding_test.rb +0 -500
  152. data/test/activesupport5/encoding_test_cases.rb +0 -98
  153. data/test/activesupport5/test_helper.rb +0 -72
  154. data/test/activesupport5/time_zone_test_helpers.rb +0 -39
  155. data/test/bar.rb +0 -11
  156. data/test/baz.rb +0 -16
  157. data/test/bug.rb +0 -16
  158. 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
  }