json 2.12.0 → 2.13.2
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/CHANGES.md +23 -0
- data/README.md +13 -0
- data/ext/json/ext/fbuffer/fbuffer.h +38 -4
- data/ext/json/ext/generator/extconf.rb +2 -25
- data/ext/json/ext/generator/generator.c +80 -107
- data/ext/json/ext/parser/extconf.rb +5 -1
- data/ext/json/ext/parser/parser.c +214 -66
- data/ext/json/ext/simd/conf.rb +24 -0
- data/ext/json/ext/simd/simd.h +188 -0
- data/ext/json/ext/vendor/fpconv.c +5 -5
- data/json.gemspec +2 -3
- data/lib/json/common.rb +23 -22
- data/lib/json/ext.rb +2 -2
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +33 -0
- metadata +4 -3
- data/ext/json/ext/generator/simd.h +0 -112
@@ -0,0 +1,188 @@
|
|
1
|
+
typedef enum {
|
2
|
+
SIMD_NONE,
|
3
|
+
SIMD_NEON,
|
4
|
+
SIMD_SSE2
|
5
|
+
} SIMD_Implementation;
|
6
|
+
|
7
|
+
#ifdef JSON_ENABLE_SIMD
|
8
|
+
|
9
|
+
#ifdef __clang__
|
10
|
+
# if __has_builtin(__builtin_ctzll)
|
11
|
+
# define HAVE_BUILTIN_CTZLL 1
|
12
|
+
# else
|
13
|
+
# define HAVE_BUILTIN_CTZLL 0
|
14
|
+
# endif
|
15
|
+
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
|
16
|
+
# define HAVE_BUILTIN_CTZLL 1
|
17
|
+
#else
|
18
|
+
# define HAVE_BUILTIN_CTZLL 0
|
19
|
+
#endif
|
20
|
+
|
21
|
+
static inline uint32_t trailing_zeros64(uint64_t input)
|
22
|
+
{
|
23
|
+
#if HAVE_BUILTIN_CTZLL
|
24
|
+
return __builtin_ctzll(input);
|
25
|
+
#else
|
26
|
+
uint32_t trailing_zeros = 0;
|
27
|
+
uint64_t temp = input;
|
28
|
+
while ((temp & 1) == 0 && temp > 0) {
|
29
|
+
trailing_zeros++;
|
30
|
+
temp >>= 1;
|
31
|
+
}
|
32
|
+
return trailing_zeros;
|
33
|
+
#endif
|
34
|
+
}
|
35
|
+
|
36
|
+
static inline int trailing_zeros(int input)
|
37
|
+
{
|
38
|
+
#if HAVE_BUILTIN_CTZLL
|
39
|
+
return __builtin_ctz(input);
|
40
|
+
#else
|
41
|
+
int trailing_zeros = 0;
|
42
|
+
int temp = input;
|
43
|
+
while ((temp & 1) == 0 && temp > 0) {
|
44
|
+
trailing_zeros++;
|
45
|
+
temp >>= 1;
|
46
|
+
}
|
47
|
+
return trailing_zeros;
|
48
|
+
#endif
|
49
|
+
}
|
50
|
+
|
51
|
+
#if (defined(__GNUC__ ) || defined(__clang__))
|
52
|
+
#define FORCE_INLINE __attribute__((always_inline))
|
53
|
+
#else
|
54
|
+
#define FORCE_INLINE
|
55
|
+
#endif
|
56
|
+
|
57
|
+
|
58
|
+
#define SIMD_MINIMUM_THRESHOLD 6
|
59
|
+
|
60
|
+
#if defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(__aarch64__) || defined(_M_ARM64)
|
61
|
+
#include <arm_neon.h>
|
62
|
+
|
63
|
+
#define FIND_SIMD_IMPLEMENTATION_DEFINED 1
|
64
|
+
static inline SIMD_Implementation find_simd_implementation(void)
|
65
|
+
{
|
66
|
+
return SIMD_NEON;
|
67
|
+
}
|
68
|
+
|
69
|
+
#define HAVE_SIMD 1
|
70
|
+
#define HAVE_SIMD_NEON 1
|
71
|
+
|
72
|
+
// See: https://community.arm.com/arm-community-blogs/b/servers-and-cloud-computing-blog/posts/porting-x86-vector-bitmask-optimizations-to-arm-neon
|
73
|
+
static inline FORCE_INLINE uint64_t neon_match_mask(uint8x16_t matches)
|
74
|
+
{
|
75
|
+
const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(matches), 4);
|
76
|
+
const uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(res), 0);
|
77
|
+
return mask & 0x8888888888888888ull;
|
78
|
+
}
|
79
|
+
|
80
|
+
static inline FORCE_INLINE uint64_t compute_chunk_mask_neon(const char *ptr)
|
81
|
+
{
|
82
|
+
uint8x16_t chunk = vld1q_u8((const unsigned char *)ptr);
|
83
|
+
|
84
|
+
// Trick: c < 32 || c == 34 can be factored as c ^ 2 < 33
|
85
|
+
// https://lemire.me/blog/2025/04/13/detect-control-characters-quotes-and-backslashes-efficiently-using-swar/
|
86
|
+
const uint8x16_t too_low_or_dbl_quote = vcltq_u8(veorq_u8(chunk, vdupq_n_u8(2)), vdupq_n_u8(33));
|
87
|
+
|
88
|
+
uint8x16_t has_backslash = vceqq_u8(chunk, vdupq_n_u8('\\'));
|
89
|
+
uint8x16_t needs_escape = vorrq_u8(too_low_or_dbl_quote, has_backslash);
|
90
|
+
return neon_match_mask(needs_escape);
|
91
|
+
}
|
92
|
+
|
93
|
+
static inline FORCE_INLINE int string_scan_simd_neon(const char **ptr, const char *end, uint64_t *mask)
|
94
|
+
{
|
95
|
+
while (*ptr + sizeof(uint8x16_t) <= end) {
|
96
|
+
uint64_t chunk_mask = compute_chunk_mask_neon(*ptr);
|
97
|
+
if (chunk_mask) {
|
98
|
+
*mask = chunk_mask;
|
99
|
+
return 1;
|
100
|
+
}
|
101
|
+
*ptr += sizeof(uint8x16_t);
|
102
|
+
}
|
103
|
+
return 0;
|
104
|
+
}
|
105
|
+
|
106
|
+
static inline uint8x16x4_t load_uint8x16_4(const unsigned char *table)
|
107
|
+
{
|
108
|
+
uint8x16x4_t tab;
|
109
|
+
tab.val[0] = vld1q_u8(table);
|
110
|
+
tab.val[1] = vld1q_u8(table+16);
|
111
|
+
tab.val[2] = vld1q_u8(table+32);
|
112
|
+
tab.val[3] = vld1q_u8(table+48);
|
113
|
+
return tab;
|
114
|
+
}
|
115
|
+
|
116
|
+
#endif /* ARM Neon Support.*/
|
117
|
+
|
118
|
+
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
|
119
|
+
|
120
|
+
#ifdef HAVE_X86INTRIN_H
|
121
|
+
#include <x86intrin.h>
|
122
|
+
|
123
|
+
#define HAVE_SIMD 1
|
124
|
+
#define HAVE_SIMD_SSE2 1
|
125
|
+
|
126
|
+
#ifdef HAVE_CPUID_H
|
127
|
+
#define FIND_SIMD_IMPLEMENTATION_DEFINED 1
|
128
|
+
|
129
|
+
#if defined(__clang__) || defined(__GNUC__)
|
130
|
+
#define TARGET_SSE2 __attribute__((target("sse2")))
|
131
|
+
#else
|
132
|
+
#define TARGET_SSE2
|
133
|
+
#endif
|
134
|
+
|
135
|
+
#define _mm_cmpge_epu8(a, b) _mm_cmpeq_epi8(_mm_max_epu8(a, b), a)
|
136
|
+
#define _mm_cmple_epu8(a, b) _mm_cmpge_epu8(b, a)
|
137
|
+
#define _mm_cmpgt_epu8(a, b) _mm_xor_si128(_mm_cmple_epu8(a, b), _mm_set1_epi8(-1))
|
138
|
+
#define _mm_cmplt_epu8(a, b) _mm_cmpgt_epu8(b, a)
|
139
|
+
|
140
|
+
static inline TARGET_SSE2 FORCE_INLINE int compute_chunk_mask_sse2(const char *ptr)
|
141
|
+
{
|
142
|
+
__m128i chunk = _mm_loadu_si128((__m128i const*)ptr);
|
143
|
+
// Trick: c < 32 || c == 34 can be factored as c ^ 2 < 33
|
144
|
+
// https://lemire.me/blog/2025/04/13/detect-control-characters-quotes-and-backslashes-efficiently-using-swar/
|
145
|
+
__m128i too_low_or_dbl_quote = _mm_cmplt_epu8(_mm_xor_si128(chunk, _mm_set1_epi8(2)), _mm_set1_epi8(33));
|
146
|
+
__m128i has_backslash = _mm_cmpeq_epi8(chunk, _mm_set1_epi8('\\'));
|
147
|
+
__m128i needs_escape = _mm_or_si128(too_low_or_dbl_quote, has_backslash);
|
148
|
+
return _mm_movemask_epi8(needs_escape);
|
149
|
+
}
|
150
|
+
|
151
|
+
static inline TARGET_SSE2 FORCE_INLINE int string_scan_simd_sse2(const char **ptr, const char *end, int *mask)
|
152
|
+
{
|
153
|
+
while (*ptr + sizeof(__m128i) <= end) {
|
154
|
+
int chunk_mask = compute_chunk_mask_sse2(*ptr);
|
155
|
+
if (chunk_mask) {
|
156
|
+
*mask = chunk_mask;
|
157
|
+
return 1;
|
158
|
+
}
|
159
|
+
*ptr += sizeof(__m128i);
|
160
|
+
}
|
161
|
+
|
162
|
+
return 0;
|
163
|
+
}
|
164
|
+
|
165
|
+
#include <cpuid.h>
|
166
|
+
#endif /* HAVE_CPUID_H */
|
167
|
+
|
168
|
+
static inline SIMD_Implementation find_simd_implementation(void)
|
169
|
+
{
|
170
|
+
// TODO Revisit. I think the SSE version now only uses SSE2 instructions.
|
171
|
+
if (__builtin_cpu_supports("sse2")) {
|
172
|
+
return SIMD_SSE2;
|
173
|
+
}
|
174
|
+
|
175
|
+
return SIMD_NONE;
|
176
|
+
}
|
177
|
+
|
178
|
+
#endif /* HAVE_X86INTRIN_H */
|
179
|
+
#endif /* X86_64 Support */
|
180
|
+
|
181
|
+
#endif /* JSON_ENABLE_SIMD */
|
182
|
+
|
183
|
+
#ifndef FIND_SIMD_IMPLEMENTATION_DEFINED
|
184
|
+
static inline SIMD_Implementation find_simd_implementation(void)
|
185
|
+
{
|
186
|
+
return SIMD_NONE;
|
187
|
+
}
|
188
|
+
#endif
|
@@ -92,7 +92,7 @@ static Fp find_cachedpow10(int exp, int* k)
|
|
92
92
|
{
|
93
93
|
const double one_log_ten = 0.30102999566398114;
|
94
94
|
|
95
|
-
int approx = -(exp + npowers) * one_log_ten;
|
95
|
+
int approx = (int)(-(exp + npowers) * one_log_ten);
|
96
96
|
int idx = (approx - firstpower) / steppowers;
|
97
97
|
|
98
98
|
while(1) {
|
@@ -432,8 +432,8 @@ static int filter_special(double fp, char* dest)
|
|
432
432
|
*
|
433
433
|
* Input:
|
434
434
|
* fp -> the double to convert, dest -> destination buffer.
|
435
|
-
* The generated string will never be longer than
|
436
|
-
* Make sure to pass a pointer to at least
|
435
|
+
* The generated string will never be longer than 28 characters.
|
436
|
+
* Make sure to pass a pointer to at least 28 bytes of memory.
|
437
437
|
* The emitted string will not be null terminated.
|
438
438
|
*
|
439
439
|
* Output:
|
@@ -443,7 +443,7 @@ static int filter_special(double fp, char* dest)
|
|
443
443
|
*
|
444
444
|
* void print(double d)
|
445
445
|
* {
|
446
|
-
* char buf[
|
446
|
+
* char buf[28 + 1] // plus null terminator
|
447
447
|
* int str_len = fpconv_dtoa(d, buf);
|
448
448
|
*
|
449
449
|
* buf[str_len] = '\0';
|
@@ -451,7 +451,7 @@ static int filter_special(double fp, char* dest)
|
|
451
451
|
* }
|
452
452
|
*
|
453
453
|
*/
|
454
|
-
static int fpconv_dtoa(double d, char dest[
|
454
|
+
static int fpconv_dtoa(double d, char dest[28])
|
455
455
|
{
|
456
456
|
char digits[18];
|
457
457
|
|
data/json.gemspec
CHANGED
@@ -44,15 +44,14 @@ spec = Gem::Specification.new do |s|
|
|
44
44
|
"LEGAL",
|
45
45
|
"README.md",
|
46
46
|
"json.gemspec",
|
47
|
-
|
48
|
-
]
|
47
|
+
] + Dir.glob("lib/**/*.rb", base: File.expand_path("..", __FILE__))
|
49
48
|
|
50
49
|
if java_ext
|
51
50
|
s.platform = 'java'
|
52
51
|
s.files += Dir["lib/json/ext/**/*.jar"]
|
53
52
|
else
|
54
53
|
s.extensions = Dir["ext/json/**/extconf.rb"]
|
55
|
-
s.files += Dir["ext/json/**/*.{c,h}"]
|
54
|
+
s.files += Dir["ext/json/**/*.{c,h,rb}"]
|
56
55
|
end
|
57
56
|
end
|
58
57
|
|
data/lib/json/common.rb
CHANGED
@@ -48,7 +48,7 @@ module JSON
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
# TODO:
|
51
|
+
# TODO: extract :create_additions support to another gem for version 3.0
|
52
52
|
def create_additions_proc(opts)
|
53
53
|
if opts[:symbolize_names]
|
54
54
|
raise ArgumentError, "options :symbolize_names and :create_additions cannot be used in conjunction"
|
@@ -87,31 +87,32 @@ module JSON
|
|
87
87
|
opts
|
88
88
|
end
|
89
89
|
|
90
|
-
GEM_ROOT = File.expand_path("../../../", __FILE__) + "/"
|
91
90
|
def create_additions_warning
|
92
|
-
|
91
|
+
JSON.deprecation_warning "JSON.load implicit support for `create_additions: true` is deprecated " \
|
93
92
|
"and will be removed in 3.0, use JSON.unsafe_load or explicitly " \
|
94
93
|
"pass `create_additions: true`"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
95
97
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
if RUBY_VERSION >= "3.0"
|
106
|
-
warn(message, uplevel: uplevel - 1, category: :deprecated)
|
98
|
+
class << self
|
99
|
+
def deprecation_warning(message, uplevel = 3) # :nodoc:
|
100
|
+
gem_root = File.expand_path("../../../", __FILE__) + "/"
|
101
|
+
caller_locations(uplevel, 10).each do |frame|
|
102
|
+
if frame.path.nil? || frame.path.start_with?(gem_root) || frame.path.end_with?("/truffle/cext_ruby.rb", ".c")
|
103
|
+
uplevel += 1
|
107
104
|
else
|
108
|
-
|
105
|
+
break
|
109
106
|
end
|
110
107
|
end
|
108
|
+
|
109
|
+
if RUBY_VERSION >= "3.0"
|
110
|
+
warn(message, uplevel: uplevel, category: :deprecated)
|
111
|
+
else
|
112
|
+
warn(message, uplevel: uplevel)
|
113
|
+
end
|
111
114
|
end
|
112
|
-
end
|
113
115
|
|
114
|
-
class << self
|
115
116
|
# :call-seq:
|
116
117
|
# JSON[object] -> new_array or new_string
|
117
118
|
#
|
@@ -172,7 +173,7 @@ module JSON
|
|
172
173
|
end
|
173
174
|
end
|
174
175
|
self.state = generator::State
|
175
|
-
const_set :State,
|
176
|
+
const_set :State, state
|
176
177
|
ensure
|
177
178
|
$VERBOSE = old
|
178
179
|
end
|
@@ -268,7 +269,7 @@ module JSON
|
|
268
269
|
# to string interpolation.
|
269
270
|
#
|
270
271
|
# Note: no validation is performed on the provided string. It is the
|
271
|
-
#
|
272
|
+
# responsibility of the caller to ensure the string contains valid JSON.
|
272
273
|
Fragment = Struct.new(:json) do
|
273
274
|
def initialize(json)
|
274
275
|
unless string = String.try_convert(json)
|
@@ -490,7 +491,7 @@ module JSON
|
|
490
491
|
# }
|
491
492
|
#
|
492
493
|
def pretty_generate(obj, opts = nil)
|
493
|
-
return
|
494
|
+
return opts.generate(obj) if State === opts
|
494
495
|
|
495
496
|
options = PRETTY_GENERATE_OPTIONS
|
496
497
|
|
@@ -1072,7 +1073,7 @@ module ::Kernel
|
|
1072
1073
|
end
|
1073
1074
|
|
1074
1075
|
objs.each do |obj|
|
1075
|
-
puts JSON
|
1076
|
+
puts JSON.generate(obj, :allow_nan => true, :max_nesting => false)
|
1076
1077
|
end
|
1077
1078
|
nil
|
1078
1079
|
end
|
@@ -1087,7 +1088,7 @@ module ::Kernel
|
|
1087
1088
|
end
|
1088
1089
|
|
1089
1090
|
objs.each do |obj|
|
1090
|
-
puts JSON
|
1091
|
+
puts JSON.pretty_generate(obj, :allow_nan => true, :max_nesting => false)
|
1091
1092
|
end
|
1092
1093
|
nil
|
1093
1094
|
end
|
data/lib/json/ext.rb
CHANGED
@@ -34,12 +34,12 @@ module JSON
|
|
34
34
|
|
35
35
|
if RUBY_ENGINE == 'truffleruby'
|
36
36
|
require 'json/truffle_ruby/generator'
|
37
|
-
JSON.generator =
|
37
|
+
JSON.generator = JSON::TruffleRuby::Generator
|
38
38
|
else
|
39
39
|
require 'json/ext/generator'
|
40
40
|
JSON.generator = Generator
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
JSON_LOADED = true unless defined?(
|
44
|
+
JSON_LOADED = true unless defined?(JSON::JSON_LOADED)
|
45
45
|
end
|
data/lib/json/version.rb
CHANGED
data/lib/json.rb
CHANGED
@@ -127,6 +127,24 @@ require 'json/common'
|
|
127
127
|
#
|
128
128
|
# ---
|
129
129
|
#
|
130
|
+
# Option +allow_duplicate_key+ specifies whether duplicate keys in objects
|
131
|
+
# should be ignored or cause an error to be raised:
|
132
|
+
#
|
133
|
+
# When not specified:
|
134
|
+
# # The last value is used and a deprecation warning emitted.
|
135
|
+
# JSON.parse('{"a": 1, "a":2}') => {"a" => 2}
|
136
|
+
# # waring: detected duplicate keys in JSON object.
|
137
|
+
# # This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`
|
138
|
+
#
|
139
|
+
# When set to `+true+`
|
140
|
+
# # The last value is used.
|
141
|
+
# JSON.parse('{"a": 1, "a":2}') => {"a" => 2}
|
142
|
+
#
|
143
|
+
# When set to `+false+`, the future default:
|
144
|
+
# JSON.parse('{"a": 1, "a":2}') => duplicate key at line 1 column 1 (JSON::ParserError)
|
145
|
+
#
|
146
|
+
# ---
|
147
|
+
#
|
130
148
|
# Option +allow_nan+ (boolean) specifies whether to allow
|
131
149
|
# NaN, Infinity, and MinusInfinity in +source+;
|
132
150
|
# defaults to +false+.
|
@@ -143,8 +161,23 @@ require 'json/common'
|
|
143
161
|
# ruby = JSON.parse(source, {allow_nan: true})
|
144
162
|
# ruby # => [NaN, Infinity, -Infinity]
|
145
163
|
#
|
164
|
+
# ---
|
165
|
+
#
|
166
|
+
# Option +allow_trailing_comma+ (boolean) specifies whether to allow
|
167
|
+
# trailing commas in objects and arrays;
|
168
|
+
# defaults to +false+.
|
169
|
+
#
|
170
|
+
# With the default, +false+:
|
171
|
+
# JSON.parse('[1,]') # unexpected character: ']' at line 1 column 4 (JSON::ParserError)
|
172
|
+
#
|
173
|
+
# When enabled:
|
174
|
+
# JSON.parse('[1,]', allow_trailing_comma: true) # => [1]
|
175
|
+
#
|
146
176
|
# ====== Output Options
|
147
177
|
#
|
178
|
+
# Option +freeze+ (boolean) specifies whether the returned objects will be frozen;
|
179
|
+
# defaults to +false+.
|
180
|
+
#
|
148
181
|
# Option +symbolize_names+ (boolean) specifies whether returned \Hash keys
|
149
182
|
# should be Symbols;
|
150
183
|
# defaults to +false+ (use Strings).
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.13.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Florian Frank
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-07-28 00:00:00.000000000 Z
|
11
11
|
dependencies: []
|
12
12
|
description: This is a JSON implementation as a Ruby extension in C.
|
13
13
|
email: flori@ping.de
|
@@ -26,9 +26,10 @@ files:
|
|
26
26
|
- ext/json/ext/fbuffer/fbuffer.h
|
27
27
|
- ext/json/ext/generator/extconf.rb
|
28
28
|
- ext/json/ext/generator/generator.c
|
29
|
-
- ext/json/ext/generator/simd.h
|
30
29
|
- ext/json/ext/parser/extconf.rb
|
31
30
|
- ext/json/ext/parser/parser.c
|
31
|
+
- ext/json/ext/simd/conf.rb
|
32
|
+
- ext/json/ext/simd/simd.h
|
32
33
|
- ext/json/ext/vendor/fpconv.c
|
33
34
|
- ext/json/ext/vendor/jeaiii-ltoa.h
|
34
35
|
- json.gemspec
|
@@ -1,112 +0,0 @@
|
|
1
|
-
typedef enum {
|
2
|
-
SIMD_NONE,
|
3
|
-
SIMD_NEON,
|
4
|
-
SIMD_SSE2
|
5
|
-
} SIMD_Implementation;
|
6
|
-
|
7
|
-
#ifdef JSON_ENABLE_SIMD
|
8
|
-
|
9
|
-
#ifdef __clang__
|
10
|
-
#if __has_builtin(__builtin_ctzll)
|
11
|
-
#define HAVE_BUILTIN_CTZLL 1
|
12
|
-
#else
|
13
|
-
#define HAVE_BUILTIN_CTZLL 0
|
14
|
-
#endif
|
15
|
-
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
|
16
|
-
#define HAVE_BUILTIN_CTZLL 1
|
17
|
-
#else
|
18
|
-
#define HAVE_BUILTIN_CTZLL 0
|
19
|
-
#endif
|
20
|
-
|
21
|
-
static inline uint32_t trailing_zeros64(uint64_t input) {
|
22
|
-
#if HAVE_BUILTIN_CTZLL
|
23
|
-
return __builtin_ctzll(input);
|
24
|
-
#else
|
25
|
-
uint32_t trailing_zeros = 0;
|
26
|
-
uint64_t temp = input;
|
27
|
-
while ((temp & 1) == 0 && temp > 0) {
|
28
|
-
trailing_zeros++;
|
29
|
-
temp >>= 1;
|
30
|
-
}
|
31
|
-
return trailing_zeros;
|
32
|
-
#endif
|
33
|
-
}
|
34
|
-
|
35
|
-
static inline int trailing_zeros(int input) {
|
36
|
-
#if HAVE_BUILTIN_CTZLL
|
37
|
-
return __builtin_ctz(input);
|
38
|
-
#else
|
39
|
-
int trailing_zeros = 0;
|
40
|
-
int temp = input;
|
41
|
-
while ((temp & 1) == 0 && temp > 0) {
|
42
|
-
trailing_zeros++;
|
43
|
-
temp >>= 1;
|
44
|
-
}
|
45
|
-
return trailing_zeros;
|
46
|
-
#endif
|
47
|
-
}
|
48
|
-
|
49
|
-
#define SIMD_MINIMUM_THRESHOLD 6
|
50
|
-
|
51
|
-
#if defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(__aarch64__) || defined(_M_ARM64)
|
52
|
-
#include <arm_neon.h>
|
53
|
-
|
54
|
-
#define FIND_SIMD_IMPLEMENTATION_DEFINED 1
|
55
|
-
static SIMD_Implementation find_simd_implementation(void) {
|
56
|
-
return SIMD_NEON;
|
57
|
-
}
|
58
|
-
|
59
|
-
#define HAVE_SIMD 1
|
60
|
-
#define HAVE_SIMD_NEON 1
|
61
|
-
|
62
|
-
uint8x16x4_t load_uint8x16_4(const unsigned char *table) {
|
63
|
-
uint8x16x4_t tab;
|
64
|
-
tab.val[0] = vld1q_u8(table);
|
65
|
-
tab.val[1] = vld1q_u8(table+16);
|
66
|
-
tab.val[2] = vld1q_u8(table+32);
|
67
|
-
tab.val[3] = vld1q_u8(table+48);
|
68
|
-
return tab;
|
69
|
-
}
|
70
|
-
|
71
|
-
#endif /* ARM Neon Support.*/
|
72
|
-
|
73
|
-
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
|
74
|
-
|
75
|
-
#ifdef HAVE_X86INTRIN_H
|
76
|
-
#include <x86intrin.h>
|
77
|
-
|
78
|
-
#define HAVE_SIMD 1
|
79
|
-
#define HAVE_SIMD_SSE2 1
|
80
|
-
|
81
|
-
#ifdef HAVE_CPUID_H
|
82
|
-
#define FIND_SIMD_IMPLEMENTATION_DEFINED 1
|
83
|
-
|
84
|
-
#include <cpuid.h>
|
85
|
-
#endif /* HAVE_CPUID_H */
|
86
|
-
|
87
|
-
static SIMD_Implementation find_simd_implementation(void) {
|
88
|
-
|
89
|
-
#if defined(__GNUC__ ) || defined(__clang__)
|
90
|
-
#ifdef __GNUC__
|
91
|
-
__builtin_cpu_init();
|
92
|
-
#endif /* __GNUC__ */
|
93
|
-
|
94
|
-
// TODO Revisit. I think the SSE version now only uses SSE2 instructions.
|
95
|
-
if (__builtin_cpu_supports("sse2")) {
|
96
|
-
return SIMD_SSE2;
|
97
|
-
}
|
98
|
-
#endif /* __GNUC__ || __clang__*/
|
99
|
-
|
100
|
-
return SIMD_NONE;
|
101
|
-
}
|
102
|
-
|
103
|
-
#endif /* HAVE_X86INTRIN_H */
|
104
|
-
#endif /* X86_64 Support */
|
105
|
-
|
106
|
-
#endif /* JSON_ENABLE_SIMD */
|
107
|
-
|
108
|
-
#ifndef FIND_SIMD_IMPLEMENTATION_DEFINED
|
109
|
-
static SIMD_Implementation find_simd_implementation(void) {
|
110
|
-
return SIMD_NONE;
|
111
|
-
}
|
112
|
-
#endif
|