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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +107 -0
- data/README.md +0 -16
- data/ext/oj/cache.c +4 -2
- data/ext/oj/cache.h +3 -2
- data/ext/oj/compat.c +3 -3
- data/ext/oj/custom.c +17 -11
- data/ext/oj/dump.c +624 -90
- data/ext/oj/dump.h +9 -2
- data/ext/oj/dump_compat.c +15 -9
- data/ext/oj/dump_leaf.c +1 -1
- data/ext/oj/dump_object.c +32 -17
- data/ext/oj/dump_strict.c +20 -14
- data/ext/oj/extconf.rb +11 -9
- data/ext/oj/fast.c +50 -32
- data/ext/oj/intern.c +24 -7
- data/ext/oj/mimic_json.c +17 -11
- data/ext/oj/object.c +21 -13
- data/ext/oj/oj.c +387 -140
- data/ext/oj/oj.h +59 -55
- data/ext/oj/parse.c +248 -47
- data/ext/oj/parser.c +179 -89
- data/ext/oj/parser.h +4 -2
- data/ext/oj/rails.c +64 -42
- data/ext/oj/reader.c +1 -1
- data/ext/oj/rxclass.c +1 -1
- data/ext/oj/rxclass.h +1 -1
- data/ext/oj/safe.c +230 -0
- data/ext/oj/safe.h +79 -0
- data/ext/oj/saj.c +15 -10
- data/ext/oj/scp.c +3 -6
- data/ext/oj/simd.h +219 -0
- data/ext/oj/sparse.c +6 -3
- data/ext/oj/stream_writer.c +38 -28
- data/ext/oj/strict.c +2 -4
- data/ext/oj/string_writer.c +54 -22
- data/ext/oj/usual.c +57 -35
- data/ext/oj/usual.h +1 -0
- data/ext/oj/val_stack.c +13 -2
- data/ext/oj/wab.c +5 -4
- data/lib/oj/mimic.rb +1 -5
- data/lib/oj/schandler.rb +5 -4
- data/lib/oj/version.rb +1 -1
- data/pages/Encoding.md +1 -1
- metadata +36 -100
- data/test/_test_active.rb +0 -75
- data/test/_test_active_mimic.rb +0 -95
- data/test/_test_mimic_rails.rb +0 -123
- data/test/activerecord/result_test.rb +0 -31
- data/test/activesupport6/abstract_unit.rb +0 -44
- data/test/activesupport6/decoding_test.rb +0 -133
- data/test/activesupport6/encoding_test.rb +0 -507
- data/test/activesupport6/encoding_test_cases.rb +0 -98
- data/test/activesupport6/test_common.rb +0 -17
- data/test/activesupport6/test_helper.rb +0 -163
- data/test/activesupport6/time_zone_test_helpers.rb +0 -39
- data/test/activesupport7/abstract_unit.rb +0 -49
- data/test/activesupport7/decoding_test.rb +0 -125
- data/test/activesupport7/encoding_test.rb +0 -486
- data/test/activesupport7/encoding_test_cases.rb +0 -104
- data/test/activesupport7/time_zone_test_helpers.rb +0 -47
- data/test/files.rb +0 -29
- data/test/foo.rb +0 -14
- data/test/helper.rb +0 -39
- data/test/isolated/shared.rb +0 -309
- data/test/isolated/test_mimic_after.rb +0 -13
- data/test/isolated/test_mimic_alone.rb +0 -12
- data/test/isolated/test_mimic_as_json.rb +0 -45
- data/test/isolated/test_mimic_before.rb +0 -13
- data/test/isolated/test_mimic_define.rb +0 -28
- data/test/isolated/test_mimic_rails_after.rb +0 -22
- data/test/isolated/test_mimic_rails_before.rb +0 -21
- data/test/isolated/test_mimic_redefine.rb +0 -15
- data/test/json_gem/json_addition_test.rb +0 -216
- data/test/json_gem/json_common_interface_test.rb +0 -155
- data/test/json_gem/json_encoding_test.rb +0 -107
- data/test/json_gem/json_ext_parser_test.rb +0 -21
- data/test/json_gem/json_fixtures_test.rb +0 -36
- data/test/json_gem/json_generator_test.rb +0 -407
- data/test/json_gem/json_generic_object_test.rb +0 -90
- data/test/json_gem/json_parser_test.rb +0 -477
- data/test/json_gem/json_string_matching_test.rb +0 -42
- data/test/json_gem/test_helper.rb +0 -30
- data/test/mem.rb +0 -34
- data/test/perf.rb +0 -102
- data/test/perf_compat.rb +0 -128
- data/test/perf_dump.rb +0 -50
- data/test/perf_fast.rb +0 -162
- data/test/perf_file.rb +0 -62
- data/test/perf_object.rb +0 -134
- data/test/perf_once.rb +0 -59
- data/test/perf_parser.rb +0 -183
- data/test/perf_saj.rb +0 -101
- data/test/perf_scp.rb +0 -140
- data/test/perf_simple.rb +0 -289
- data/test/perf_strict.rb +0 -137
- data/test/perf_wab.rb +0 -129
- data/test/prec.rb +0 -23
- data/test/sample/change.rb +0 -13
- data/test/sample/dir.rb +0 -18
- data/test/sample/doc.rb +0 -35
- data/test/sample/file.rb +0 -47
- data/test/sample/group.rb +0 -15
- data/test/sample/hasprops.rb +0 -15
- data/test/sample/layer.rb +0 -11
- data/test/sample/line.rb +0 -20
- data/test/sample/oval.rb +0 -10
- data/test/sample/rect.rb +0 -9
- data/test/sample/shape.rb +0 -34
- data/test/sample/text.rb +0 -19
- data/test/sample.rb +0 -54
- data/test/sample_json.rb +0 -37
- data/test/test_compat.rb +0 -567
- data/test/test_custom.rb +0 -554
- data/test/test_debian.rb +0 -50
- data/test/test_fast.rb +0 -526
- data/test/test_file.rb +0 -250
- data/test/test_gc.rb +0 -60
- data/test/test_generate.rb +0 -21
- data/test/test_hash.rb +0 -39
- data/test/test_integer_range.rb +0 -72
- data/test/test_null.rb +0 -376
- data/test/test_object.rb +0 -1016
- data/test/test_parser.rb +0 -11
- data/test/test_parser_debug.rb +0 -27
- data/test/test_parser_saj.rb +0 -337
- data/test/test_parser_usual.rb +0 -217
- data/test/test_rails.rb +0 -35
- data/test/test_saj.rb +0 -188
- data/test/test_scp.rb +0 -431
- data/test/test_strict.rb +0 -431
- data/test/test_various.rb +0 -801
- data/test/test_wab.rb +0 -311
- data/test/test_writer.rb +0 -380
- data/test/tests.rb +0 -33
- data/test/tests_mimic.rb +0 -23
- 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 =
|
|
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 =
|
|
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 =
|
|
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;
|
|
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
|
-
|
|
655
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
767
|
+
RubyDec == pi->options.bigdec_load);
|
|
765
768
|
ni.bigdec_load = pi->options.bigdec_load;
|
|
766
769
|
}
|
|
767
770
|
add_num_value(pi, &ni);
|
data/ext/oj/stream_writer.c
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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)
|
|
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)
|
|
220
|
+
oj_str_writer_push_value((StrWriter)sw, *argv, 0);
|
|
216
221
|
} else {
|
|
217
|
-
oj_str_writer_push_value((StrWriter)
|
|
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
|
|
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)
|
|
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)
|
|
250
|
+
oj_str_writer_push_json((StrWriter)sw, StringValuePtr(*argv), 0);
|
|
245
251
|
} else {
|
|
246
|
-
oj_str_writer_push_json((StrWriter)
|
|
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
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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;
|