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
data/ext/oj/saj.c CHANGED
@@ -94,8 +94,7 @@ inline static void call_add_value(VALUE handler, VALUE value, const char *key) {
94
94
  if (0 == key) {
95
95
  k = Qnil;
96
96
  } else {
97
- k = rb_str_new2(key);
98
- k = oj_encode(k);
97
+ k = rb_utf8_str_new_cstr(key);
99
98
  }
100
99
  rb_funcall(handler, oj_add_value_id, 2, value, k);
101
100
  }
@@ -106,8 +105,7 @@ inline static void call_no_value(VALUE handler, ID method, const char *key) {
106
105
  if (0 == key) {
107
106
  k = Qnil;
108
107
  } else {
109
- k = rb_str_new2(key);
110
- k = oj_encode(k);
108
+ k = rb_utf8_str_new_cstr(key);
111
109
  }
112
110
  rb_funcall(handler, method, 1, k);
113
111
  }
@@ -257,9 +255,8 @@ static void read_str(ParseInfo pi, const char *key) {
257
255
 
258
256
  text = read_quoted_value(pi);
259
257
  if (pi->has_add_value) {
260
- VALUE s = rb_str_new2(text);
258
+ VALUE s = rb_utf8_str_new_cstr(text);
261
259
 
262
- s = oj_encode(s);
263
260
  call_add_value(pi->handler, s, key);
264
261
  }
265
262
  }
@@ -578,7 +575,7 @@ static void saj_parse(VALUE handler, char *json) {
578
575
  /* initialize parse info */
579
576
  pi.str = json;
580
577
  pi.s = json;
581
- #if IS_WINDOWS
578
+ #if IS_WINDOWS || !defined(HAVE_GETRLIMIT)
582
579
  pi.stack_min = (void *)((char *)&obj - (512L * 1024L)); /* assume a 1M stack and give half to ruby */
583
580
  #else
584
581
  {
@@ -587,7 +584,7 @@ static void saj_parse(VALUE handler, char *json) {
587
584
  if (0 == getrlimit(RLIMIT_STACK, &lim) && RLIM_INFINITY != lim.rlim_cur) {
588
585
  pi.stack_min = (void *)((char *)&obj - (lim.rlim_cur / 4 * 3)); /* let 3/4ths of the stack be used only */
589
586
  } else {
590
- pi.stack_min = 0; /* indicates not to check stack limit */
587
+ pi.stack_min = 0; /* indicates not to check stack limit */
591
588
  }
592
589
  }
593
590
  #endif
@@ -651,8 +648,16 @@ oj_saj_parse(int argc, VALUE *argv, VALUE self) {
651
648
  len = lseek(fd, 0, SEEK_END);
652
649
  lseek(fd, 0, SEEK_SET);
653
650
  json = OJ_R_ALLOC_N(char, len + 1);
654
- if (0 >= (cnt = read(fd, json, len)) || cnt != (ssize_t)len) {
655
- rb_raise(rb_eIOError, "failed to read from IO Object.");
651
+ {
652
+ size_t total = 0;
653
+
654
+ while (total < len) {
655
+ cnt = read(fd, json + total, len - total);
656
+ if (cnt <= 0) {
657
+ rb_raise(rb_eIOError, "failed to read from IO Object.");
658
+ }
659
+ total += cnt;
660
+ }
656
661
  }
657
662
  json[len] = '\0';
658
663
  #endif
data/ext/oj/scp.c CHANGED
@@ -56,9 +56,8 @@ static void add_value(ParseInfo pi, VALUE val) {
56
56
  }
57
57
 
58
58
  static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
59
- volatile VALUE rstr = rb_str_new(str, len);
59
+ volatile VALUE rstr = rb_utf8_str_new(str, len);
60
60
 
61
- rstr = oj_encode(rstr);
62
61
  rb_funcall(pi->handler, oj_add_value_id, 1, rstr);
63
62
  }
64
63
 
@@ -87,9 +86,8 @@ static VALUE hash_key(ParseInfo pi, const char *key, size_t klen) {
87
86
  }
88
87
 
89
88
  static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
90
- volatile VALUE rstr = rb_str_new(str, len);
89
+ volatile VALUE rstr = rb_utf8_str_new(str, len);
91
90
 
92
- rstr = oj_encode(rstr);
93
91
  rb_funcall(pi->handler, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, kval), rstr);
94
92
  }
95
93
 
@@ -107,9 +105,8 @@ static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
107
105
  }
108
106
 
109
107
  static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
110
- volatile VALUE rstr = rb_str_new(str, len);
108
+ volatile VALUE rstr = rb_utf8_str_new(str, len);
111
109
 
112
- rstr = oj_encode(rstr);
113
110
  rb_funcall(pi->handler, oj_array_append_id, 2, stack_peek(&pi->stack)->val, rstr);
114
111
  }
115
112
 
data/ext/oj/simd.h ADDED
@@ -0,0 +1,219 @@
1
+ #ifndef OJ_SIMD_H
2
+ #define OJ_SIMD_H
3
+
4
+ // SIMD architecture detection and configuration
5
+ // This header provides unified SIMD support across different CPU architectures
6
+ // with cross-platform runtime detection (Windows/Linux/Mac)
7
+
8
+ // SIMD implementation enum - used for runtime selection
9
+ typedef enum _simd_implementation { SIMD_NONE, SIMD_NEON, SIMD_SSE2, SIMD_SSE42 } SIMD_Implementation;
10
+
11
+ // Define in oj.c.
12
+ extern SIMD_Implementation SIMD_Impl;
13
+
14
+ // Runtime CPU detection function (implemented in oj.c)
15
+ SIMD_Implementation oj_get_simd_implementation(void);
16
+
17
+ // =============================================================================
18
+ // Compiler compatibility macros
19
+ // =============================================================================
20
+
21
+ // Branch prediction hints
22
+ #if defined(__GNUC__) || defined(__clang__)
23
+ #define OJ_LIKELY(x) __builtin_expect(!!(x), 1)
24
+ #define OJ_UNLIKELY(x) __builtin_expect(!!(x), 0)
25
+ #else
26
+ #define OJ_LIKELY(x) (x)
27
+ #define OJ_UNLIKELY(x) (x)
28
+ #endif
29
+
30
+ // Prefetch hints
31
+ #if defined(__GNUC__) || defined(__clang__)
32
+ #define OJ_PREFETCH(addr) __builtin_prefetch(addr, 0, 0)
33
+ #elif defined(_MSC_VER)
34
+ #include <intrin.h>
35
+ #define OJ_PREFETCH(addr) _mm_prefetch((const char *)(addr), _MM_HINT_T0)
36
+ #else
37
+ #define OJ_PREFETCH(addr) ((void)0)
38
+ #endif
39
+
40
+ // Count trailing zeros (for SSE2 mask scanning)
41
+ #if defined(__GNUC__) || defined(__clang__)
42
+ #define OJ_CTZ(x) __builtin_ctz(x)
43
+ #define OJ_CTZ64(x) __builtin_ctzll(x)
44
+ #elif defined(_MSC_VER)
45
+ #include <intrin.h>
46
+ static __inline int oj_ctz_msvc(unsigned int x) {
47
+ unsigned long index;
48
+ if (0 == x) {
49
+ return 32;
50
+ }
51
+ _BitScanForward(&index, x);
52
+ return (int)index;
53
+ }
54
+ static __inline int oj_ctz64_msvc(uint64_t x) {
55
+ unsigned long index;
56
+ if (_BitScanForward64(&index, x)) {
57
+ return (int)index;
58
+ }
59
+ return 64;
60
+ }
61
+ #define OJ_CTZ(x) oj_ctz_msvc(x)
62
+ #define OJ_CTZ64(x) oj_ctz64_msvc(x)
63
+ #else
64
+ // Fallback: naive implementation
65
+ static inline int oj_ctz_fallback(unsigned int x) {
66
+ int count = 0;
67
+ while ((x & 1) == 0 && count < 32) {
68
+ x >>= 1;
69
+ count++;
70
+ }
71
+ return count;
72
+ }
73
+
74
+ static inline int oj_ctz64_fallback(uint64_t x) {
75
+ int count = 0;
76
+ while ((x & 1) == 0 && count < 64) {
77
+ x >>= 1;
78
+ count++;
79
+ }
80
+ return count;
81
+ }
82
+ #define OJ_CTZ(x) oj_ctz_fallback(x)
83
+ #define OJ_CTZ64(x) oj_ctz64_fallback(x)
84
+ #endif
85
+
86
+ // =============================================================================
87
+ // x86/x86_64 SIMD detection
88
+ // =============================================================================
89
+ #if defined(__x86_64__) || defined(__i386__) || defined(_M_IX86) || defined(_M_X64)
90
+ #define HAVE_SIMD_X86 1
91
+
92
+ // Include appropriate SIMD headers
93
+ #if defined(_MSC_VER)
94
+ // MSVC: use intrin.h for all intrinsics
95
+ #include <intrin.h>
96
+ #define HAVE_SIMD_SSE4_2 1
97
+ #define HAVE_SIMD_SSE2 1
98
+ #elif defined(__GNUC__) || defined(__clang__)
99
+ // GCC/Clang: check for header availability and include them
100
+ // We include headers but use target attributes to enable instructions per-function
101
+ // Include cpuid.h for __get_cpuid fallback when __builtin_cpu_supports is unavailable
102
+ #if __has_include(<cpuid.h>)
103
+ #include <cpuid.h>
104
+ #endif
105
+ #if defined(__SSE4_2__) || defined(__SSE2__)
106
+ // If any SSE is enabled globally, x86intrin.h should be available
107
+ #include <x86intrin.h>
108
+ #define HAVE_SIMD_SSE4_2 1
109
+ #define HAVE_SIMD_SSE2 1
110
+ #else
111
+ // Try to include headers anyway for target attribute functions
112
+ #if __has_include(<x86intrin.h>)
113
+ #include <x86intrin.h>
114
+ #define HAVE_SIMD_SSE4_2 1
115
+ #define HAVE_SIMD_SSE2 1
116
+ #elif __has_include(<nmmintrin.h>)
117
+ #include <nmmintrin.h>
118
+ #define HAVE_SIMD_SSE4_2 1
119
+ #define HAVE_SIMD_SSE2 1
120
+ #elif __has_include(<emmintrin.h>)
121
+ #include <emmintrin.h>
122
+ #define HAVE_SIMD_SSE2 1
123
+ #endif
124
+ #endif
125
+ #endif
126
+
127
+ // Target attribute macros for function-level SIMD enabling
128
+ #if defined(__clang__) || defined(__GNUC__)
129
+ #define OJ_TARGET_SSE42 __attribute__((target("sse4.2")))
130
+ #define OJ_TARGET_SSE2 __attribute__((target("sse2")))
131
+ #else
132
+ // MSVC doesn't need target attributes - intrinsics are always available
133
+ #define OJ_TARGET_SSE42
134
+ #define OJ_TARGET_SSE2
135
+ #endif
136
+
137
+ #endif // x86/x86_64
138
+
139
+ // =============================================================================
140
+ // ARM NEON detection
141
+ // =============================================================================
142
+ #if defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(__aarch64__) || defined(_M_ARM64)
143
+ #define HAVE_SIMD_NEON 1
144
+ #define SIMD_MINIMUM_THRESHOLD 6
145
+ #include <arm_neon.h>
146
+ #endif
147
+
148
+ // =============================================================================
149
+ // SIMD type string for debugging/logging
150
+ // =============================================================================
151
+ #if defined(HAVE_SIMD_SSE4_2) || defined(HAVE_SIMD_SSE2)
152
+ #define HAVE_SIMD_STRING_SCAN 1
153
+ #define SIMD_TYPE "x86 (runtime detected)"
154
+ #elif defined(HAVE_SIMD_NEON)
155
+ #define HAVE_SIMD_STRING_SCAN 1
156
+ #define SIMD_TYPE "NEON"
157
+ #else
158
+ #define SIMD_TYPE "none"
159
+ #endif
160
+
161
+ #if defined(HAVE_SIMD_SSE4_2)
162
+
163
+ #define SIMD_MINIMUM_THRESHOLD 6
164
+
165
+ extern void initialize_sse42(void);
166
+
167
+ static inline OJ_TARGET_SSE42 __m128i vector_lookup_sse42(__m128i input, __m128i *lookup_table, int tab_size) {
168
+ // Extract high 4 bits to determine which 16-byte chunk (0-15)
169
+ __m128i hi_index = _mm_and_si128(_mm_srli_epi32(input, 4), _mm_set1_epi8(0x0F));
170
+
171
+ // Extract low 4 bits for index within the chunk (0-15)
172
+ __m128i low_index = _mm_and_si128(input, _mm_set1_epi8(0x0F));
173
+
174
+ // Perform lookups in all 16 tables
175
+ __m128i results[16];
176
+ for (int i = 0; i < tab_size; i++) {
177
+ results[i] = _mm_shuffle_epi8(lookup_table[i], low_index);
178
+ }
179
+
180
+ // Create masks for each chunk and blend results
181
+ __m128i final_result = _mm_setzero_si128();
182
+
183
+ for (int i = 0; i < tab_size; i++) {
184
+ __m128i mask = _mm_cmpeq_epi8(hi_index, _mm_set1_epi8(i));
185
+ __m128i masked_result = _mm_and_si128(mask, results[i]);
186
+ final_result = _mm_or_si128(final_result, masked_result);
187
+ }
188
+
189
+ return final_result;
190
+ }
191
+
192
+ #endif
193
+
194
+ #ifndef __has_builtin
195
+ #define __has_builtin(x) 0
196
+ #endif
197
+
198
+ #if __has_builtin(__builtin_memcpy)
199
+ #define HAVE_FAST_MEMCPY 1
200
+
201
+ inline static void fast_memcpy16(void *dest, const void *src, size_t n) {
202
+ char *d = (char *)dest;
203
+ char *s = (char *)src;
204
+ if (n >= 8) {
205
+ __builtin_memcpy(d, s, 8);
206
+ __builtin_memcpy(d + n - 8, s + n - 8, 8);
207
+ } else if (n >= 4) {
208
+ __builtin_memcpy(d, s, 4);
209
+ __builtin_memcpy(d + n - 4, s + n - 4, 4);
210
+ } else if (n >= 2) {
211
+ __builtin_memcpy(d, s, 2);
212
+ __builtin_memcpy(d + n - 2, s + n - 2, 2);
213
+ } else if (n >= 1) {
214
+ *d = *s;
215
+ }
216
+ }
217
+ #endif
218
+
219
+ #endif /* OJ_SIMD_H */
data/ext/oj/sparse.c CHANGED
@@ -399,6 +399,7 @@ static void read_num(ParseInfo pi) {
399
399
  char c;
400
400
 
401
401
  reader_protect(&pi->rd);
402
+ ni.pi = pi;
402
403
  ni.i = 0;
403
404
  ni.num = 0;
404
405
  ni.div = 1;
@@ -415,7 +416,7 @@ static void read_num(ParseInfo pi) {
415
416
  ni.bigdec_load = pi->options.compat_bigdec;
416
417
  } else {
417
418
  ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
418
- RubyDec == pi->options.bigdec_load);
419
+ RubyDec == pi->options.bigdec_load);
419
420
  ni.bigdec_load = pi->options.bigdec_load;
420
421
  }
421
422
 
@@ -549,6 +550,7 @@ static void read_nan(ParseInfo pi) {
549
550
  struct _numInfo ni;
550
551
  char c;
551
552
 
553
+ ni.pi = pi;
552
554
  ni.str = pi->rd.str;
553
555
  ni.i = 0;
554
556
  ni.num = 0;
@@ -565,7 +567,7 @@ static void read_nan(ParseInfo pi) {
565
567
  ni.bigdec_load = pi->options.compat_bigdec;
566
568
  } else {
567
569
  ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
568
- RubyDec == pi->options.bigdec_load);
570
+ RubyDec == pi->options.bigdec_load);
569
571
  ni.bigdec_load = pi->options.bigdec_load;
570
572
  }
571
573
 
@@ -745,6 +747,7 @@ void oj_sparse2(ParseInfo pi) {
745
747
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected NaN");
746
748
  return;
747
749
  }
750
+ ni.pi = pi;
748
751
  ni.str = pi->rd.str;
749
752
  ni.i = 0;
750
753
  ni.num = 0;
@@ -761,7 +764,7 @@ void oj_sparse2(ParseInfo pi) {
761
764
  ni.bigdec_load = pi->options.compat_bigdec;
762
765
  } else {
763
766
  ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
764
- RubyDec == pi->options.bigdec_load);
767
+ RubyDec == pi->options.bigdec_load);
765
768
  ni.bigdec_load = pi->options.bigdec_load;
766
769
  }
767
770
  add_num_value(pi, &ni);
@@ -21,6 +21,17 @@ static void stream_writer_free(void *ptr) {
21
21
  OJ_R_FREE(ptr);
22
22
  }
23
23
 
24
+ static const rb_data_type_t oj_stream_writer_type = {
25
+ "Oj/stream_writer",
26
+ {
27
+ NULL,
28
+ stream_writer_free,
29
+ NULL,
30
+ },
31
+ 0,
32
+ 0,
33
+ };
34
+
24
35
  static void stream_writer_reset_buf(StreamWriter sw) {
25
36
  sw->sw.out.cur = sw->sw.out.buf;
26
37
  *sw->sw.out.cur = '\0';
@@ -31,22 +42,12 @@ static void stream_writer_write(StreamWriter sw) {
31
42
 
32
43
  switch (sw->type) {
33
44
  case STRING_IO:
34
- case STREAM_IO: {
35
- volatile VALUE rs = rb_str_new(sw->sw.out.buf, size);
36
-
37
- // Oddly enough, when pushing ASCII characters with UTF-8 encoding or
38
- // even ASCII-8BIT does not change the output encoding. Pushing any
39
- // non-ASCII no matter what the encoding changes the output encoding
40
- // to ASCII-8BIT if it the string is not forced to UTF-8 here.
41
- rs = oj_encode(rs);
45
+ case STREAM_IO:
46
+ case FILE_IO: {
47
+ volatile VALUE rs = rb_utf8_str_new(sw->sw.out.buf, size);
42
48
  rb_funcall(sw->stream, oj_write_id, 1, rs);
43
49
  break;
44
50
  }
45
- case FILE_IO:
46
- if (size != write(sw->fd, sw->sw.out.buf, size)) {
47
- rb_raise(rb_eIOError, "Write failed. [_%d_:%s]\n", errno, strerror(errno));
48
- }
49
- break;
50
51
  default: rb_raise(rb_eArgError, "expected an IO Object.");
51
52
  }
52
53
  stream_writer_reset_buf(sw);
@@ -120,7 +121,7 @@ static VALUE stream_writer_new(int argc, VALUE *argv, VALUE self) {
120
121
  sw->type = type;
121
122
  sw->fd = fd;
122
123
 
123
- return Data_Wrap_Struct(oj_stream_writer_class, 0, stream_writer_free, sw);
124
+ return TypedData_Wrap_Struct(oj_stream_writer_class, &oj_stream_writer_type, sw);
124
125
  }
125
126
 
126
127
  /* Document-method: push_key
@@ -133,7 +134,8 @@ static VALUE stream_writer_new(int argc, VALUE *argv, VALUE self) {
133
134
  * - *key* [_String_] the key pending for the next push
134
135
  */
135
136
  static VALUE stream_writer_push_key(VALUE self, VALUE key) {
136
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
137
+ StreamWriter sw;
138
+ TypedData_Get_Struct(self, struct _streamWriter, &oj_stream_writer_type, sw);
137
139
 
138
140
  oj_str_writer_push_key(&sw->sw, StringValuePtr(key));
139
141
  if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
@@ -151,7 +153,8 @@ static VALUE stream_writer_push_key(VALUE self, VALUE key) {
151
153
  * - *key* [_String_] the key if adding to an object in the JSON document
152
154
  */
153
155
  static VALUE stream_writer_push_object(int argc, VALUE *argv, VALUE self) {
154
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
156
+ StreamWriter sw;
157
+ TypedData_Get_Struct(self, struct _streamWriter, &oj_stream_writer_type, sw);
155
158
 
156
159
  switch (argc) {
157
160
  case 0: oj_str_writer_push_object(&sw->sw, 0); break;
@@ -179,7 +182,8 @@ static VALUE stream_writer_push_object(int argc, VALUE *argv, VALUE self) {
179
182
  * - *key* [_String_] the key if adding to an object in the JSON document
180
183
  */
181
184
  static VALUE stream_writer_push_array(int argc, VALUE *argv, VALUE self) {
182
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
185
+ StreamWriter sw;
186
+ TypedData_Get_Struct(self, struct _streamWriter, &oj_stream_writer_type, sw);
183
187
 
184
188
  switch (argc) {
185
189
  case 0: oj_str_writer_push_array(&sw->sw, 0); break;
@@ -206,15 +210,16 @@ static VALUE stream_writer_push_array(int argc, VALUE *argv, VALUE self) {
206
210
  * - *key* [_String_] the key if adding to an object in the JSON document
207
211
  */
208
212
  static VALUE stream_writer_push_value(int argc, VALUE *argv, VALUE self) {
209
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
213
+ StreamWriter sw;
214
+ TypedData_Get_Struct(self, struct _streamWriter, &oj_stream_writer_type, sw);
210
215
 
211
216
  switch (argc) {
212
- case 1: oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0); break;
217
+ case 1: oj_str_writer_push_value((StrWriter)sw, *argv, 0); break;
213
218
  case 2:
214
219
  if (Qnil == argv[1]) {
215
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
220
+ oj_str_writer_push_value((StrWriter)sw, *argv, 0);
216
221
  } else {
217
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1]));
222
+ oj_str_writer_push_value((StrWriter)sw, *argv, StringValuePtr(argv[1]));
218
223
  }
219
224
  break;
220
225
  default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'."); break;
@@ -235,15 +240,16 @@ static VALUE stream_writer_push_value(int argc, VALUE *argv, VALUE self) {
235
240
  * - *key* [_String_] the key if adding to an object in the JSON document
236
241
  */
237
242
  static VALUE stream_writer_push_json(int argc, VALUE *argv, VALUE self) {
238
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
243
+ StreamWriter sw;
244
+ TypedData_Get_Struct(self, struct _streamWriter, &oj_stream_writer_type, sw);
239
245
 
240
246
  switch (argc) {
241
- case 1: oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0); break;
247
+ case 1: oj_str_writer_push_json((StrWriter)sw, StringValuePtr(*argv), 0); break;
242
248
  case 2:
243
249
  if (Qnil == argv[1]) {
244
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
250
+ oj_str_writer_push_json((StrWriter)sw, StringValuePtr(*argv), 0);
245
251
  } else {
246
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), StringValuePtr(argv[1]));
252
+ oj_str_writer_push_json((StrWriter)sw, StringValuePtr(*argv), StringValuePtr(argv[1]));
247
253
  }
248
254
  break;
249
255
  default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'."); break;
@@ -261,7 +267,8 @@ static VALUE stream_writer_push_json(int argc, VALUE *argv, VALUE self) {
261
267
  * currently open.
262
268
  */
263
269
  static VALUE stream_writer_pop(VALUE self) {
264
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
270
+ StreamWriter sw;
271
+ TypedData_Get_Struct(self, struct _streamWriter, &oj_stream_writer_type, sw);
265
272
 
266
273
  oj_str_writer_pop(&sw->sw);
267
274
  if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
@@ -277,7 +284,8 @@ static VALUE stream_writer_pop(VALUE self) {
277
284
  * currently open.
278
285
  */
279
286
  static VALUE stream_writer_pop_all(VALUE self) {
280
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
287
+ StreamWriter sw;
288
+ TypedData_Get_Struct(self, struct _streamWriter, &oj_stream_writer_type, sw);
281
289
 
282
290
  oj_str_writer_pop_all(&sw->sw);
283
291
  stream_writer_write(sw);
@@ -291,7 +299,9 @@ static VALUE stream_writer_pop_all(VALUE self) {
291
299
  * Flush any remaining characters in the buffer.
292
300
  */
293
301
  static VALUE stream_writer_flush(VALUE self) {
294
- stream_writer_write((StreamWriter)DATA_PTR(self));
302
+ StreamWriter sw;
303
+ TypedData_Get_Struct(self, struct _streamWriter, &oj_stream_writer_type, sw);
304
+ stream_writer_write(sw);
295
305
 
296
306
  return Qnil;
297
307
  }
data/ext/oj/strict.c CHANGED
@@ -19,8 +19,7 @@ VALUE oj_cstr_to_value(const char *str, size_t len, size_t cache_str) {
19
19
  if (len < cache_str) {
20
20
  rstr = oj_str_intern(str, len);
21
21
  } else {
22
- rstr = rb_str_new(str, len);
23
- rstr = oj_encode(rstr);
22
+ rstr = rb_utf8_str_new(str, len);
24
23
  }
25
24
  return rstr;
26
25
  }
@@ -35,8 +34,7 @@ VALUE oj_calc_hash_key(ParseInfo pi, Val parent) {
35
34
  if (Yes == pi->options.sym_key) {
36
35
  rkey = ID2SYM(rb_intern3(parent->key, parent->klen, oj_utf8_encoding));
37
36
  } else {
38
- rkey = rb_str_new(parent->key, parent->klen);
39
- rkey = oj_encode(rkey);
37
+ rkey = rb_utf8_str_new(parent->key, parent->klen);
40
38
  OBJ_FREEZE(rkey); // frozen when used as a Hash key anyway
41
39
  }
42
40
  return rkey;