json 2.7.2 → 2.12.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/BSDL +22 -0
- data/CHANGES.md +160 -17
- data/LEGAL +8 -0
- data/README.md +76 -211
- data/ext/json/ext/fbuffer/fbuffer.h +178 -95
- data/ext/json/ext/generator/extconf.rb +38 -2
- data/ext/json/ext/generator/generator.c +1311 -826
- data/ext/json/ext/generator/simd.h +112 -0
- data/ext/json/ext/parser/extconf.rb +6 -27
- data/ext/json/ext/parser/parser.c +1176 -1971
- data/ext/json/ext/vendor/fpconv.c +479 -0
- data/ext/json/ext/vendor/jeaiii-ltoa.h +267 -0
- data/json.gemspec +44 -49
- data/lib/json/add/bigdecimal.rb +2 -2
- data/lib/json/add/complex.rb +1 -1
- data/lib/json/add/core.rb +1 -1
- data/lib/json/add/date.rb +1 -1
- data/lib/json/add/date_time.rb +1 -1
- data/lib/json/add/exception.rb +1 -1
- data/lib/json/add/ostruct.rb +1 -1
- data/lib/json/add/range.rb +1 -1
- data/lib/json/add/rational.rb +1 -1
- data/lib/json/add/regexp.rb +1 -1
- data/lib/json/add/struct.rb +1 -1
- data/lib/json/add/symbol.rb +8 -4
- data/lib/json/add/time.rb +3 -10
- data/lib/json/common.rb +647 -241
- data/lib/json/ext/generator/state.rb +106 -0
- data/lib/json/ext.rb +35 -5
- data/lib/json/generic_object.rb +1 -1
- data/lib/json/{pure → truffle_ruby}/generator.rb +322 -145
- data/lib/json/version.rb +3 -7
- data/lib/json.rb +16 -21
- metadata +18 -22
- data/ext/json/ext/generator/depend +0 -1
- data/ext/json/ext/generator/generator.h +0 -177
- data/ext/json/ext/parser/depend +0 -1
- data/ext/json/ext/parser/parser.h +0 -96
- data/ext/json/ext/parser/parser.rl +0 -971
- data/ext/json/extconf.rb +0 -3
- data/lib/json/pure/parser.rb +0 -337
- data/lib/json/pure.rb +0 -15
- /data/{LICENSE → COPYING} +0 -0
@@ -1,89 +1,109 @@
|
|
1
|
-
|
2
1
|
#ifndef _FBUFFER_H_
|
3
2
|
#define _FBUFFER_H_
|
4
3
|
|
5
4
|
#include "ruby.h"
|
6
|
-
|
7
|
-
#
|
8
|
-
|
5
|
+
#include "ruby/encoding.h"
|
6
|
+
#include "../vendor/jeaiii-ltoa.h"
|
7
|
+
|
8
|
+
/* shims */
|
9
|
+
/* This is the fallback definition from Ruby 3.4 */
|
10
|
+
|
11
|
+
#ifndef RBIMPL_STDBOOL_H
|
12
|
+
#if defined(__cplusplus)
|
13
|
+
# if defined(HAVE_STDBOOL_H) && (__cplusplus >= 201103L)
|
14
|
+
# include <cstdbool>
|
15
|
+
# endif
|
16
|
+
#elif defined(HAVE_STDBOOL_H)
|
17
|
+
# include <stdbool.h>
|
18
|
+
#elif !defined(HAVE__BOOL)
|
19
|
+
typedef unsigned char _Bool;
|
20
|
+
# define bool _Bool
|
21
|
+
# define true ((_Bool)+1)
|
22
|
+
# define false ((_Bool)+0)
|
23
|
+
# define __bool_true_false_are_defined
|
9
24
|
#endif
|
10
|
-
|
11
|
-
#ifndef RFLOAT_VALUE
|
12
|
-
#define RFLOAT_VALUE(val) (RFLOAT(val)->value)
|
13
25
|
#endif
|
14
26
|
|
15
|
-
#ifndef
|
16
|
-
#define
|
17
|
-
#endif
|
18
|
-
#ifndef RSTRING_PTR
|
19
|
-
#define RSTRING_PTR(string) RSTRING(string)->ptr
|
20
|
-
#endif
|
21
|
-
#ifndef RSTRING_LEN
|
22
|
-
#define RSTRING_LEN(string) RSTRING(string)->len
|
27
|
+
#ifndef RB_UNLIKELY
|
28
|
+
#define RB_UNLIKELY(expr) expr
|
23
29
|
#endif
|
24
30
|
|
25
|
-
#
|
26
|
-
#
|
27
|
-
# define RB_OBJ_STRING(obj) (obj)
|
28
|
-
#else
|
29
|
-
# define PRIsVALUE "s"
|
30
|
-
# define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj)
|
31
|
-
# define RB_OBJ_STRING(obj) StringValueCStr(obj)
|
31
|
+
#ifndef RB_LIKELY
|
32
|
+
#define RB_LIKELY(expr) expr
|
32
33
|
#endif
|
33
34
|
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#define FORCE_UTF8(obj) rb_enc_associate((obj), rb_utf8_encoding())
|
37
|
-
#else
|
38
|
-
#define FORCE_UTF8(obj)
|
35
|
+
#ifndef MAYBE_UNUSED
|
36
|
+
# define MAYBE_UNUSED(x) x
|
39
37
|
#endif
|
40
38
|
|
41
|
-
|
42
|
-
#ifndef
|
43
|
-
#define
|
39
|
+
#ifdef RUBY_DEBUG
|
40
|
+
#ifndef JSON_DEBUG
|
41
|
+
#define JSON_DEBUG RUBY_DEBUG
|
42
|
+
#endif
|
44
43
|
#endif
|
45
44
|
|
45
|
+
enum fbuffer_type {
|
46
|
+
FBUFFER_HEAP_ALLOCATED = 0,
|
47
|
+
FBUFFER_STACK_ALLOCATED = 1,
|
48
|
+
};
|
49
|
+
|
46
50
|
typedef struct FBufferStruct {
|
51
|
+
enum fbuffer_type type;
|
47
52
|
unsigned long initial_length;
|
48
|
-
char *ptr;
|
49
53
|
unsigned long len;
|
50
54
|
unsigned long capa;
|
55
|
+
#ifdef JSON_DEBUG
|
56
|
+
unsigned long requested;
|
57
|
+
#endif
|
58
|
+
char *ptr;
|
59
|
+
VALUE io;
|
51
60
|
} FBuffer;
|
52
61
|
|
62
|
+
#define FBUFFER_STACK_SIZE 512
|
63
|
+
#define FBUFFER_IO_BUFFER_SIZE (16384 - 1)
|
53
64
|
#define FBUFFER_INITIAL_LENGTH_DEFAULT 1024
|
54
65
|
|
55
|
-
#define FBUFFER_PTR(fb) (fb->ptr)
|
56
|
-
#define FBUFFER_LEN(fb) (fb->len)
|
57
|
-
#define FBUFFER_CAPA(fb) (fb->capa)
|
66
|
+
#define FBUFFER_PTR(fb) ((fb)->ptr)
|
67
|
+
#define FBUFFER_LEN(fb) ((fb)->len)
|
68
|
+
#define FBUFFER_CAPA(fb) ((fb)->capa)
|
58
69
|
#define FBUFFER_PAIR(fb) FBUFFER_PTR(fb), FBUFFER_LEN(fb)
|
59
70
|
|
60
|
-
static FBuffer *fbuffer_alloc(unsigned long initial_length);
|
61
71
|
static void fbuffer_free(FBuffer *fb);
|
62
72
|
static void fbuffer_clear(FBuffer *fb);
|
63
73
|
static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len);
|
64
|
-
#ifdef JSON_GENERATOR
|
65
74
|
static void fbuffer_append_long(FBuffer *fb, long number);
|
75
|
+
static inline void fbuffer_append_char(FBuffer *fb, char newchr);
|
76
|
+
static VALUE fbuffer_finalize(FBuffer *fb);
|
77
|
+
|
78
|
+
static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char *stack_buffer, long stack_buffer_size)
|
79
|
+
{
|
80
|
+
fb->initial_length = (initial_length > 0) ? initial_length : FBUFFER_INITIAL_LENGTH_DEFAULT;
|
81
|
+
if (stack_buffer) {
|
82
|
+
fb->type = FBUFFER_STACK_ALLOCATED;
|
83
|
+
fb->ptr = stack_buffer;
|
84
|
+
fb->capa = stack_buffer_size;
|
85
|
+
}
|
86
|
+
#ifdef JSON_DEBUG
|
87
|
+
fb->requested = 0;
|
66
88
|
#endif
|
67
|
-
|
68
|
-
#ifdef JSON_GENERATOR
|
69
|
-
static FBuffer *fbuffer_dup(FBuffer *fb);
|
70
|
-
static VALUE fbuffer_to_s(FBuffer *fb);
|
71
|
-
#endif
|
89
|
+
}
|
72
90
|
|
73
|
-
static FBuffer *
|
91
|
+
static inline void fbuffer_consumed(FBuffer *fb, unsigned long consumed)
|
74
92
|
{
|
75
|
-
|
76
|
-
if (
|
77
|
-
|
78
|
-
|
79
|
-
fb->
|
80
|
-
|
93
|
+
#ifdef JSON_DEBUG
|
94
|
+
if (consumed > fb->requested) {
|
95
|
+
rb_bug("fbuffer: Out of bound write");
|
96
|
+
}
|
97
|
+
fb->requested = 0;
|
98
|
+
#endif
|
99
|
+
fb->len += consumed;
|
81
100
|
}
|
82
101
|
|
83
102
|
static void fbuffer_free(FBuffer *fb)
|
84
103
|
{
|
85
|
-
if (fb->ptr
|
86
|
-
|
104
|
+
if (fb->ptr && fb->type == FBUFFER_HEAP_ALLOCATED) {
|
105
|
+
ruby_xfree(fb->ptr);
|
106
|
+
}
|
87
107
|
}
|
88
108
|
|
89
109
|
static void fbuffer_clear(FBuffer *fb)
|
@@ -91,20 +111,61 @@ static void fbuffer_clear(FBuffer *fb)
|
|
91
111
|
fb->len = 0;
|
92
112
|
}
|
93
113
|
|
94
|
-
static void
|
114
|
+
static void fbuffer_flush(FBuffer *fb)
|
115
|
+
{
|
116
|
+
rb_io_write(fb->io, rb_utf8_str_new(fb->ptr, fb->len));
|
117
|
+
fbuffer_clear(fb);
|
118
|
+
}
|
119
|
+
|
120
|
+
static void fbuffer_realloc(FBuffer *fb, unsigned long required)
|
121
|
+
{
|
122
|
+
if (required > fb->capa) {
|
123
|
+
if (fb->type == FBUFFER_STACK_ALLOCATED) {
|
124
|
+
const char *old_buffer = fb->ptr;
|
125
|
+
fb->ptr = ALLOC_N(char, required);
|
126
|
+
fb->type = FBUFFER_HEAP_ALLOCATED;
|
127
|
+
MEMCPY(fb->ptr, old_buffer, char, fb->len);
|
128
|
+
} else {
|
129
|
+
REALLOC_N(fb->ptr, char, required);
|
130
|
+
}
|
131
|
+
fb->capa = required;
|
132
|
+
}
|
133
|
+
}
|
134
|
+
|
135
|
+
static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
|
95
136
|
{
|
137
|
+
if (RB_UNLIKELY(fb->io)) {
|
138
|
+
if (fb->capa < FBUFFER_IO_BUFFER_SIZE) {
|
139
|
+
fbuffer_realloc(fb, FBUFFER_IO_BUFFER_SIZE);
|
140
|
+
} else {
|
141
|
+
fbuffer_flush(fb);
|
142
|
+
}
|
143
|
+
|
144
|
+
if (RB_LIKELY(requested < fb->capa)) {
|
145
|
+
return;
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
96
149
|
unsigned long required;
|
97
150
|
|
98
|
-
if (!fb->ptr) {
|
151
|
+
if (RB_UNLIKELY(!fb->ptr)) {
|
99
152
|
fb->ptr = ALLOC_N(char, fb->initial_length);
|
100
153
|
fb->capa = fb->initial_length;
|
101
154
|
}
|
102
155
|
|
103
156
|
for (required = fb->capa; requested > required - fb->len; required <<= 1);
|
104
157
|
|
105
|
-
|
106
|
-
|
107
|
-
|
158
|
+
fbuffer_realloc(fb, required);
|
159
|
+
}
|
160
|
+
|
161
|
+
static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
|
162
|
+
{
|
163
|
+
#ifdef JSON_DEBUG
|
164
|
+
fb->requested = requested;
|
165
|
+
#endif
|
166
|
+
|
167
|
+
if (RB_UNLIKELY(requested > fb->capa - fb->len)) {
|
168
|
+
fbuffer_do_inc_capa(fb, requested);
|
108
169
|
}
|
109
170
|
}
|
110
171
|
|
@@ -113,11 +174,24 @@ static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len)
|
|
113
174
|
if (len > 0) {
|
114
175
|
fbuffer_inc_capa(fb, len);
|
115
176
|
MEMCPY(fb->ptr + fb->len, newstr, char, len);
|
116
|
-
fb
|
177
|
+
fbuffer_consumed(fb, len);
|
117
178
|
}
|
118
179
|
}
|
119
180
|
|
120
|
-
|
181
|
+
/* Appends a character into a buffer. The buffer needs to have sufficient capacity, via fbuffer_inc_capa(...). */
|
182
|
+
static inline void fbuffer_append_reserved_char(FBuffer *fb, char chr)
|
183
|
+
{
|
184
|
+
#ifdef JSON_DEBUG
|
185
|
+
if (fb->requested < 1) {
|
186
|
+
rb_bug("fbuffer: unreserved write");
|
187
|
+
}
|
188
|
+
fb->requested--;
|
189
|
+
#endif
|
190
|
+
|
191
|
+
fb->ptr[fb->len] = chr;
|
192
|
+
fb->len++;
|
193
|
+
}
|
194
|
+
|
121
195
|
static void fbuffer_append_str(FBuffer *fb, VALUE str)
|
122
196
|
{
|
123
197
|
const char *newstr = StringValuePtr(str);
|
@@ -127,61 +201,70 @@ static void fbuffer_append_str(FBuffer *fb, VALUE str)
|
|
127
201
|
|
128
202
|
fbuffer_append(fb, newstr, len);
|
129
203
|
}
|
130
|
-
#endif
|
131
204
|
|
132
|
-
static void fbuffer_append_char(FBuffer *fb, char newchr)
|
205
|
+
static inline void fbuffer_append_char(FBuffer *fb, char newchr)
|
133
206
|
{
|
134
207
|
fbuffer_inc_capa(fb, 1);
|
135
208
|
*(fb->ptr + fb->len) = newchr;
|
136
|
-
fb
|
209
|
+
fbuffer_consumed(fb, 1);
|
137
210
|
}
|
138
211
|
|
139
|
-
|
140
|
-
static void freverse(char *start, char *end)
|
212
|
+
static inline char *fbuffer_cursor(FBuffer *fb)
|
141
213
|
{
|
142
|
-
|
143
|
-
|
144
|
-
while (end > start) {
|
145
|
-
c = *end, *end-- = *start, *start++ = c;
|
146
|
-
}
|
214
|
+
return fb->ptr + fb->len;
|
147
215
|
}
|
148
216
|
|
149
|
-
static
|
217
|
+
static inline void fbuffer_advance_to(FBuffer *fb, char *end)
|
150
218
|
{
|
151
|
-
|
152
|
-
long sign = number;
|
153
|
-
char* tmp = buf;
|
154
|
-
|
155
|
-
if (sign < 0) number = -number;
|
156
|
-
do *tmp++ = digits[number % 10]; while (number /= 10);
|
157
|
-
if (sign < 0) *tmp++ = '-';
|
158
|
-
freverse(buf, tmp - 1);
|
159
|
-
return tmp - buf;
|
219
|
+
fbuffer_consumed(fb, (end - fb->ptr) - fb->len);
|
160
220
|
}
|
161
221
|
|
222
|
+
/*
|
223
|
+
* Appends the decimal string representation of \a number into the buffer.
|
224
|
+
*/
|
162
225
|
static void fbuffer_append_long(FBuffer *fb, long number)
|
163
226
|
{
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
227
|
+
/*
|
228
|
+
* The jeaiii_ultoa() function produces digits left-to-right,
|
229
|
+
* allowing us to write directly into the buffer, but we don't know
|
230
|
+
* the number of resulting characters.
|
231
|
+
*
|
232
|
+
* We do know, however, that the `number` argument is always in the
|
233
|
+
* range 0xc000000000000000 to 0x3fffffffffffffff, or, in decimal,
|
234
|
+
* -4611686018427387904 to 4611686018427387903. The max number of chars
|
235
|
+
* generated is therefore 20 (including a potential sign character).
|
236
|
+
*/
|
237
|
+
|
238
|
+
static const int MAX_CHARS_FOR_LONG = 20;
|
239
|
+
|
240
|
+
fbuffer_inc_capa(fb, MAX_CHARS_FOR_LONG);
|
241
|
+
|
242
|
+
if (number < 0) {
|
243
|
+
fbuffer_append_reserved_char(fb, '-');
|
244
|
+
|
245
|
+
/*
|
246
|
+
* Since number is always > LONG_MIN, `-number` will not overflow
|
247
|
+
* and is always the positive abs() value.
|
248
|
+
*/
|
249
|
+
number = -number;
|
250
|
+
}
|
173
251
|
|
174
|
-
|
175
|
-
|
176
|
-
return result;
|
252
|
+
char *end = jeaiii_ultoa(fbuffer_cursor(fb), number);
|
253
|
+
fbuffer_advance_to(fb, end);
|
177
254
|
}
|
178
255
|
|
179
|
-
static VALUE
|
256
|
+
static VALUE fbuffer_finalize(FBuffer *fb)
|
180
257
|
{
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
258
|
+
if (fb->io) {
|
259
|
+
fbuffer_flush(fb);
|
260
|
+
fbuffer_free(fb);
|
261
|
+
rb_io_flush(fb->io);
|
262
|
+
return fb->io;
|
263
|
+
} else {
|
264
|
+
VALUE result = rb_utf8_str_new(FBUFFER_PTR(fb), FBUFFER_LEN(fb));
|
265
|
+
fbuffer_free(fb);
|
266
|
+
return result;
|
267
|
+
}
|
185
268
|
}
|
186
|
-
|
269
|
+
|
187
270
|
#endif
|
@@ -1,4 +1,40 @@
|
|
1
1
|
require 'mkmf'
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
if RUBY_ENGINE == 'truffleruby'
|
4
|
+
# The pure-Ruby generator is faster on TruffleRuby, so skip compiling the generator extension
|
5
|
+
File.write('Makefile', dummy_makefile("").join)
|
6
|
+
else
|
7
|
+
append_cflags("-std=c99")
|
8
|
+
$defs << "-DJSON_GENERATOR"
|
9
|
+
$defs << "-DJSON_DEBUG" if ENV["JSON_DEBUG"]
|
10
|
+
|
11
|
+
if enable_config('generator-use-simd', default=!ENV["JSON_DISABLE_SIMD"])
|
12
|
+
if RbConfig::CONFIG['host_cpu'] =~ /^(arm.*|aarch64.*)/
|
13
|
+
# Try to compile a small program using NEON instructions
|
14
|
+
if have_header('arm_neon.h')
|
15
|
+
have_type('uint8x16_t', headers=['arm_neon.h']) && try_compile(<<~'SRC')
|
16
|
+
#include <arm_neon.h>
|
17
|
+
int main() {
|
18
|
+
uint8x16_t test = vdupq_n_u8(32);
|
19
|
+
return 0;
|
20
|
+
}
|
21
|
+
SRC
|
22
|
+
$defs.push("-DJSON_ENABLE_SIMD")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
if have_header('x86intrin.h') && have_type('__m128i', headers=['x86intrin.h']) && try_compile(<<~'SRC')
|
27
|
+
#include <x86intrin.h>
|
28
|
+
int main() {
|
29
|
+
__m128i test = _mm_set1_epi8(32);
|
30
|
+
return 0;
|
31
|
+
}
|
32
|
+
SRC
|
33
|
+
$defs.push("-DJSON_ENABLE_SIMD")
|
34
|
+
end
|
35
|
+
|
36
|
+
have_header('cpuid.h')
|
37
|
+
end
|
38
|
+
|
39
|
+
create_makefile 'json/ext/generator'
|
40
|
+
end
|