json 2.6.1 → 2.21.1
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 +370 -17
- data/LEGAL +20 -0
- data/README.md +96 -213
- data/ext/json/ext/fbuffer/fbuffer.h +190 -118
- data/ext/json/ext/generator/extconf.rb +17 -2
- data/ext/json/ext/generator/generator.c +1532 -1074
- data/ext/json/ext/json.h +183 -0
- data/ext/json/ext/parser/extconf.rb +30 -25
- data/ext/json/ext/parser/parser.c +2837 -3258
- data/ext/json/ext/simd/conf.rb +24 -0
- data/ext/json/ext/simd/simd.h +208 -0
- data/ext/json/ext/vendor/fast_float_parser.h +814 -0
- data/ext/json/ext/vendor/fpconv.c +480 -0
- data/ext/json/ext/vendor/jeaiii-ltoa.h +267 -0
- data/json.gemspec +48 -53
- data/lib/json/add/bigdecimal.rb +39 -10
- data/lib/json/add/complex.rb +29 -6
- data/lib/json/add/core.rb +2 -1
- data/lib/json/add/date.rb +27 -7
- data/lib/json/add/date_time.rb +26 -9
- data/lib/json/add/exception.rb +25 -7
- data/lib/json/add/ostruct.rb +32 -9
- data/lib/json/add/range.rb +33 -8
- data/lib/json/add/rational.rb +28 -6
- data/lib/json/add/regexp.rb +26 -8
- data/lib/json/add/set.rb +25 -6
- data/lib/json/add/string.rb +35 -0
- data/lib/json/add/struct.rb +29 -7
- data/lib/json/add/symbol.rb +34 -7
- data/lib/json/add/time.rb +29 -15
- data/lib/json/common.rb +746 -267
- data/lib/json/ext/generator/state.rb +104 -0
- data/lib/json/ext.rb +61 -5
- data/lib/json/generic_object.rb +7 -11
- data/lib/json/truffle_ruby/generator.rb +790 -0
- data/lib/json/version.rb +3 -7
- data/lib/json.rb +134 -24
- metadata +22 -26
- data/VERSION +0 -1
- data/ext/json/ext/generator/depend +0 -1
- data/ext/json/ext/generator/generator.h +0 -174
- 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 -977
- data/ext/json/extconf.rb +0 -3
- data/lib/json/pure/generator.rb +0 -479
- data/lib/json/pure/parser.rb +0 -337
- data/lib/json/pure.rb +0 -15
- /data/{LICENSE → COPYING} +0 -0
|
@@ -1,89 +1,75 @@
|
|
|
1
|
-
|
|
2
1
|
#ifndef _FBUFFER_H_
|
|
3
2
|
#define _FBUFFER_H_
|
|
4
3
|
|
|
5
|
-
#include "
|
|
6
|
-
|
|
7
|
-
#ifndef RHASH_SIZE
|
|
8
|
-
#define RHASH_SIZE(hsh) (RHASH(hsh)->tbl->num_entries)
|
|
9
|
-
#endif
|
|
10
|
-
|
|
11
|
-
#ifndef RFLOAT_VALUE
|
|
12
|
-
#define RFLOAT_VALUE(val) (RFLOAT(val)->value)
|
|
13
|
-
#endif
|
|
14
|
-
|
|
15
|
-
#ifndef RARRAY_LEN
|
|
16
|
-
#define RARRAY_LEN(ARRAY) RARRAY(ARRAY)->len
|
|
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
|
|
23
|
-
#endif
|
|
24
|
-
|
|
25
|
-
#ifdef PRIsVALUE
|
|
26
|
-
# define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
|
|
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)
|
|
32
|
-
#endif
|
|
4
|
+
#include "../json.h"
|
|
5
|
+
#include "../vendor/jeaiii-ltoa.h"
|
|
33
6
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
#define FORCE_UTF8(obj)
|
|
39
|
-
#endif
|
|
40
|
-
|
|
41
|
-
/* We don't need to guard objects for rbx, so let's do nothing at all. */
|
|
42
|
-
#ifndef RB_GC_GUARD
|
|
43
|
-
#define RB_GC_GUARD(object)
|
|
44
|
-
#endif
|
|
7
|
+
enum fbuffer_type {
|
|
8
|
+
FBUFFER_HEAP_ALLOCATED = 0,
|
|
9
|
+
FBUFFER_STACK_ALLOCATED = 1,
|
|
10
|
+
};
|
|
45
11
|
|
|
46
12
|
typedef struct FBufferStruct {
|
|
47
|
-
|
|
13
|
+
enum fbuffer_type type;
|
|
14
|
+
size_t initial_length;
|
|
15
|
+
size_t len;
|
|
16
|
+
size_t capa;
|
|
17
|
+
#if JSON_DEBUG
|
|
18
|
+
size_t requested;
|
|
19
|
+
#endif
|
|
48
20
|
char *ptr;
|
|
49
|
-
|
|
50
|
-
unsigned long capa;
|
|
21
|
+
VALUE io;
|
|
51
22
|
} FBuffer;
|
|
52
23
|
|
|
24
|
+
#define FBUFFER_STACK_SIZE 512
|
|
25
|
+
#define FBUFFER_IO_BUFFER_SIZE (16384 - 1)
|
|
53
26
|
#define FBUFFER_INITIAL_LENGTH_DEFAULT 1024
|
|
54
27
|
|
|
55
|
-
#define FBUFFER_PTR(fb) (fb->ptr)
|
|
56
|
-
#define FBUFFER_LEN(fb) (fb->len)
|
|
57
|
-
#define FBUFFER_CAPA(fb) (fb->capa)
|
|
28
|
+
#define FBUFFER_PTR(fb) ((fb)->ptr)
|
|
29
|
+
#define FBUFFER_LEN(fb) ((fb)->len)
|
|
30
|
+
#define FBUFFER_CAPA(fb) ((fb)->capa)
|
|
58
31
|
#define FBUFFER_PAIR(fb) FBUFFER_PTR(fb), FBUFFER_LEN(fb)
|
|
59
32
|
|
|
60
|
-
static FBuffer *fbuffer_alloc(unsigned long initial_length);
|
|
61
33
|
static void fbuffer_free(FBuffer *fb);
|
|
62
34
|
static void fbuffer_clear(FBuffer *fb);
|
|
63
|
-
static void fbuffer_append(FBuffer *fb, const char *newstr,
|
|
64
|
-
#ifdef JSON_GENERATOR
|
|
35
|
+
static void fbuffer_append(FBuffer *fb, const char *newstr, size_t len);
|
|
65
36
|
static void fbuffer_append_long(FBuffer *fb, long number);
|
|
37
|
+
static inline void fbuffer_append_char(FBuffer *fb, char newchr);
|
|
38
|
+
static VALUE fbuffer_finalize(FBuffer *fb);
|
|
39
|
+
|
|
40
|
+
static void fbuffer_init(FBuffer *fb, size_t initial_length, VALUE io, char *stack_buffer, size_t stack_buffer_size)
|
|
41
|
+
{
|
|
42
|
+
if (RTEST(io)) {
|
|
43
|
+
JSON_ASSERT(fb->type == FBUFFER_HEAP_ALLOCATED);
|
|
44
|
+
fb->io = io;
|
|
45
|
+
fb->initial_length = (initial_length > 0) ? initial_length : FBUFFER_IO_BUFFER_SIZE;
|
|
46
|
+
} else {
|
|
47
|
+
fb->type = FBUFFER_STACK_ALLOCATED;
|
|
48
|
+
fb->ptr = stack_buffer;
|
|
49
|
+
fb->capa = stack_buffer_size;
|
|
50
|
+
fb->initial_length = (initial_length > 0) ? initial_length : FBUFFER_INITIAL_LENGTH_DEFAULT;
|
|
51
|
+
}
|
|
52
|
+
#if JSON_DEBUG
|
|
53
|
+
fb->requested = 0;
|
|
66
54
|
#endif
|
|
67
|
-
|
|
68
|
-
#ifdef JSON_GENERATOR
|
|
69
|
-
static FBuffer *fbuffer_dup(FBuffer *fb);
|
|
70
|
-
static VALUE fbuffer_to_s(FBuffer *fb);
|
|
71
|
-
#endif
|
|
55
|
+
}
|
|
72
56
|
|
|
73
|
-
static FBuffer *
|
|
57
|
+
static inline void fbuffer_consumed(FBuffer *fb, size_t consumed)
|
|
74
58
|
{
|
|
75
|
-
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
fb->
|
|
80
|
-
|
|
59
|
+
#if JSON_DEBUG
|
|
60
|
+
if (consumed > fb->requested) {
|
|
61
|
+
rb_bug("fbuffer: Out of bound write");
|
|
62
|
+
}
|
|
63
|
+
fb->requested = 0;
|
|
64
|
+
#endif
|
|
65
|
+
fb->len += consumed;
|
|
81
66
|
}
|
|
82
67
|
|
|
83
68
|
static void fbuffer_free(FBuffer *fb)
|
|
84
69
|
{
|
|
85
|
-
if (fb->ptr
|
|
86
|
-
|
|
70
|
+
if (fb->ptr && fb->type == FBUFFER_HEAP_ALLOCATED) {
|
|
71
|
+
JSON_SIZED_FREE_N(fb->ptr, fb->capa);
|
|
72
|
+
}
|
|
87
73
|
}
|
|
88
74
|
|
|
89
75
|
static void fbuffer_clear(FBuffer *fb)
|
|
@@ -91,97 +77,183 @@ static void fbuffer_clear(FBuffer *fb)
|
|
|
91
77
|
fb->len = 0;
|
|
92
78
|
}
|
|
93
79
|
|
|
94
|
-
static void
|
|
80
|
+
static void fbuffer_flush(FBuffer *fb)
|
|
95
81
|
{
|
|
96
|
-
|
|
82
|
+
rb_io_write(fb->io, rb_utf8_str_new(fb->ptr, fb->len));
|
|
83
|
+
fbuffer_clear(fb);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
static void fbuffer_realloc(FBuffer *fb, size_t new_capa)
|
|
87
|
+
{
|
|
88
|
+
if (new_capa > fb->capa) {
|
|
89
|
+
if (fb->type == FBUFFER_STACK_ALLOCATED) {
|
|
90
|
+
const char *old_buffer = fb->ptr;
|
|
91
|
+
fb->ptr = ALLOC_N(char, new_capa);
|
|
92
|
+
fb->type = FBUFFER_HEAP_ALLOCATED;
|
|
93
|
+
MEMCPY(fb->ptr, old_buffer, char, fb->len);
|
|
94
|
+
} else {
|
|
95
|
+
JSON_SIZED_REALLOC_N(fb->ptr, char, new_capa, fb->capa);
|
|
96
|
+
}
|
|
97
|
+
fb->capa = new_capa;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
97
100
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
+
static void fbuffer_do_inc_capa(FBuffer *fb, size_t requested)
|
|
102
|
+
{
|
|
103
|
+
if (RB_UNLIKELY(fb->io)) {
|
|
104
|
+
if (fb->capa != 0) {
|
|
105
|
+
fbuffer_flush(fb);
|
|
106
|
+
if (RB_LIKELY(requested < fb->capa)) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
101
110
|
}
|
|
102
111
|
|
|
103
|
-
|
|
112
|
+
size_t new_capa = fb->capa ? fb->capa : fb->initial_length;
|
|
113
|
+
size_t needed_capa = requested + fb->len;
|
|
104
114
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
fb->capa = required;
|
|
115
|
+
while (new_capa < needed_capa) {
|
|
116
|
+
new_capa *= 2;
|
|
108
117
|
}
|
|
118
|
+
|
|
119
|
+
fbuffer_realloc(fb, new_capa);
|
|
109
120
|
}
|
|
110
121
|
|
|
111
|
-
static void
|
|
122
|
+
static inline void fbuffer_inc_capa(FBuffer *fb, size_t requested)
|
|
112
123
|
{
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
124
|
+
#if JSON_DEBUG
|
|
125
|
+
fb->requested = requested;
|
|
126
|
+
#endif
|
|
127
|
+
|
|
128
|
+
if (RB_UNLIKELY(requested > fb->capa - fb->len)) {
|
|
129
|
+
fbuffer_do_inc_capa(fb, requested);
|
|
117
130
|
}
|
|
118
131
|
}
|
|
119
132
|
|
|
120
|
-
|
|
121
|
-
static void fbuffer_append_str(FBuffer *fb, VALUE str)
|
|
133
|
+
static inline size_t fbuffer_size_mul_or_raise(size_t a, size_t b)
|
|
122
134
|
{
|
|
123
|
-
|
|
124
|
-
|
|
135
|
+
size_t result = a * b;
|
|
136
|
+
if (RB_UNLIKELY(a != 0 && (result / a) != b)) {
|
|
137
|
+
rb_raise(rb_eArgError, "Buffer overflow, the resulting document is too large to be generated");
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
125
141
|
|
|
126
|
-
|
|
142
|
+
static inline void fbuffer_append_reserved(FBuffer *fb, const char *newstr, size_t len)
|
|
143
|
+
{
|
|
144
|
+
MEMCPY(fb->ptr + fb->len, newstr, char, len);
|
|
145
|
+
fbuffer_consumed(fb, len);
|
|
146
|
+
}
|
|
127
147
|
|
|
128
|
-
|
|
148
|
+
static inline void fbuffer_append(FBuffer *fb, const char *newstr, size_t len)
|
|
149
|
+
{
|
|
150
|
+
if (len > 0) {
|
|
151
|
+
fbuffer_inc_capa(fb, len);
|
|
152
|
+
fbuffer_append_reserved(fb, newstr, len);
|
|
153
|
+
}
|
|
129
154
|
}
|
|
130
|
-
#endif
|
|
131
155
|
|
|
132
|
-
|
|
156
|
+
/* Appends a character into a buffer. The buffer needs to have sufficient capacity, via fbuffer_inc_capa(...). */
|
|
157
|
+
static inline void fbuffer_append_reserved_char(FBuffer *fb, char chr)
|
|
133
158
|
{
|
|
134
|
-
|
|
135
|
-
|
|
159
|
+
#if JSON_DEBUG
|
|
160
|
+
if (fb->requested < 1) {
|
|
161
|
+
rb_bug("fbuffer: unreserved write");
|
|
162
|
+
}
|
|
163
|
+
fb->requested--;
|
|
164
|
+
#endif
|
|
165
|
+
|
|
166
|
+
fb->ptr[fb->len] = chr;
|
|
136
167
|
fb->len++;
|
|
137
168
|
}
|
|
138
169
|
|
|
139
|
-
|
|
140
|
-
static void freverse(char *start, char *end)
|
|
170
|
+
static void fbuffer_append_str(FBuffer *fb, VALUE str)
|
|
141
171
|
{
|
|
142
|
-
char
|
|
172
|
+
const char *ptr;
|
|
173
|
+
size_t len;
|
|
174
|
+
RSTRING_GETMEM(str, ptr, len);
|
|
143
175
|
|
|
144
|
-
|
|
145
|
-
|
|
176
|
+
fbuffer_append(fb, ptr, len);
|
|
177
|
+
RB_GC_GUARD(str);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
static void fbuffer_append_str_repeat(FBuffer *fb, VALUE str, size_t repeat)
|
|
181
|
+
{
|
|
182
|
+
const char *ptr;
|
|
183
|
+
size_t len;
|
|
184
|
+
RSTRING_GETMEM(str, ptr, len);
|
|
185
|
+
|
|
186
|
+
fbuffer_inc_capa(fb, fbuffer_size_mul_or_raise(repeat, len));
|
|
187
|
+
while (repeat) {
|
|
188
|
+
#if JSON_DEBUG
|
|
189
|
+
fb->requested = len;
|
|
190
|
+
#endif
|
|
191
|
+
fbuffer_append_reserved(fb, ptr, len);
|
|
192
|
+
repeat--;
|
|
146
193
|
}
|
|
194
|
+
RB_GC_GUARD(str);
|
|
147
195
|
}
|
|
148
196
|
|
|
149
|
-
static
|
|
197
|
+
static inline void fbuffer_append_char(FBuffer *fb, char newchr)
|
|
150
198
|
{
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
199
|
+
fbuffer_inc_capa(fb, 1);
|
|
200
|
+
*(fb->ptr + fb->len) = newchr;
|
|
201
|
+
fbuffer_consumed(fb, 1);
|
|
202
|
+
}
|
|
154
203
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
freverse(buf, tmp - 1);
|
|
159
|
-
return tmp - buf;
|
|
204
|
+
static inline char *fbuffer_cursor(FBuffer *fb)
|
|
205
|
+
{
|
|
206
|
+
return fb->ptr + fb->len;
|
|
160
207
|
}
|
|
161
208
|
|
|
162
|
-
static void
|
|
209
|
+
static inline void fbuffer_advance_to(FBuffer *fb, char *end)
|
|
163
210
|
{
|
|
164
|
-
|
|
165
|
-
unsigned long len = fltoa(number, buf);
|
|
166
|
-
fbuffer_append(fb, buf, len);
|
|
211
|
+
fbuffer_consumed(fb, (end - fb->ptr) - fb->len);
|
|
167
212
|
}
|
|
168
213
|
|
|
169
|
-
|
|
214
|
+
/*
|
|
215
|
+
* Appends the decimal string representation of \a number into the buffer.
|
|
216
|
+
*/
|
|
217
|
+
static void fbuffer_append_long(FBuffer *fb, long number)
|
|
170
218
|
{
|
|
171
|
-
|
|
172
|
-
|
|
219
|
+
/*
|
|
220
|
+
* The jeaiii_ultoa() function produces digits left-to-right,
|
|
221
|
+
* allowing us to write directly into the buffer, but we don't know
|
|
222
|
+
* the number of resulting characters.
|
|
223
|
+
*
|
|
224
|
+
* We do know, however, that the `number` argument is always in the
|
|
225
|
+
* range 0xc000000000000000 to 0x3fffffffffffffff, or, in decimal,
|
|
226
|
+
* -4611686018427387904 to 4611686018427387903. The max number of chars
|
|
227
|
+
* generated is therefore 20 (including a potential sign character).
|
|
228
|
+
*/
|
|
229
|
+
|
|
230
|
+
static const int MAX_CHARS_FOR_LONG = 20;
|
|
231
|
+
|
|
232
|
+
fbuffer_inc_capa(fb, MAX_CHARS_FOR_LONG);
|
|
233
|
+
|
|
234
|
+
if (number < 0) {
|
|
235
|
+
fbuffer_append_reserved_char(fb, '-');
|
|
236
|
+
|
|
237
|
+
/*
|
|
238
|
+
* Since number is always > LONG_MIN, `-number` will not overflow
|
|
239
|
+
* and is always the positive abs() value.
|
|
240
|
+
*/
|
|
241
|
+
number = -number;
|
|
242
|
+
}
|
|
173
243
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
return result;
|
|
244
|
+
char *end = jeaiii_ultoa(fbuffer_cursor(fb), number);
|
|
245
|
+
fbuffer_advance_to(fb, end);
|
|
177
246
|
}
|
|
178
247
|
|
|
179
|
-
static VALUE
|
|
248
|
+
static VALUE fbuffer_finalize(FBuffer *fb)
|
|
180
249
|
{
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
250
|
+
if (fb->io) {
|
|
251
|
+
fbuffer_flush(fb);
|
|
252
|
+
rb_io_flush(fb->io);
|
|
253
|
+
return fb->io;
|
|
254
|
+
} else {
|
|
255
|
+
return rb_utf8_str_new(FBUFFER_PTR(fb), FBUFFER_LEN(fb));
|
|
256
|
+
}
|
|
185
257
|
}
|
|
186
|
-
|
|
187
|
-
#endif
|
|
258
|
+
|
|
259
|
+
#endif // _FBUFFER_H_
|
|
@@ -1,4 +1,19 @@
|
|
|
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
|
+
have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3
|
|
9
|
+
have_func("ruby_xfree_sized", "ruby.h") # RUBY_VERSION >= 4.1
|
|
10
|
+
|
|
11
|
+
$defs << "-DJSON_GENERATOR"
|
|
12
|
+
$defs << "-DJSON_DEBUG" if ENV.fetch("JSON_DEBUG", "0") != "0"
|
|
13
|
+
|
|
14
|
+
if enable_config('generator-use-simd', default=!ENV["JSON_DISABLE_SIMD"])
|
|
15
|
+
load __dir__ + "/../simd/conf.rb"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
create_makefile 'json/ext/generator'
|
|
19
|
+
end
|