json 2.10.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/CHANGES.md +56 -0
- data/README.md +13 -0
- data/ext/json/ext/fbuffer/fbuffer.h +80 -15
- data/ext/json/ext/generator/extconf.rb +30 -0
- data/ext/json/ext/generator/generator.c +466 -100
- data/ext/json/ext/generator/simd.h +112 -0
- data/ext/json/ext/parser/extconf.rb +0 -1
- data/ext/json/ext/parser/parser.c +180 -250
- data/ext/json/ext/vendor/fpconv.c +479 -0
- data/ext/json/ext/vendor/jeaiii-ltoa.h +267 -0
- data/lib/json/common.rb +280 -163
- data/lib/json/ext.rb +2 -2
- data/lib/json/truffle_ruby/generator.rb +1 -1
- data/lib/json/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b76bc749fd1bc82cd84df8c7d14317305d5426e0962d0e034864b218e952e474
|
4
|
+
data.tar.gz: 8e8d9179b6ca7ce69c7a281691973dc9cb1e6b147a5812b96d02c3b41d8f8cec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a241873428f8de2106604f3a31484aa243b6f62c6c6f38f8e381669f937b19f03b35add48ddf4f1d24c5a9f469c2dbdc8bafca36d8f3bcf678313ad8d9ea11d3
|
7
|
+
data.tar.gz: 99d07dbf3dcacda3cf662ee05bc181aa3ca6e43ce8779b9f5edc454fba8e718abe876eb81b4918e0c0bb1a3b4286e1d85df086425e552743420942a8e0098f0e
|
data/CHANGES.md
CHANGED
@@ -1,10 +1,66 @@
|
|
1
1
|
# Changes
|
2
2
|
|
3
|
+
### Unreleased
|
4
|
+
|
5
|
+
### 2025-05-23 (2.12.2)
|
6
|
+
|
7
|
+
* Fix compiler optimization level.
|
8
|
+
|
9
|
+
### 2025-05-23 (2.12.1)
|
10
|
+
|
11
|
+
* Fix a potential crash in large negative floating point number generation.
|
12
|
+
* Fix for JSON.pretty_generate to use passed state object's generate instead of state class as the required parameters aren't available.
|
13
|
+
|
14
|
+
### 2025-05-12 (2.12.0)
|
15
|
+
|
16
|
+
* Improve floating point generation to not use scientific notation as much.
|
17
|
+
* Include line and column in parser errors. Both in the message and as exception attributes.
|
18
|
+
* Handle non-string hash keys with broken `to_s` implementations.
|
19
|
+
* `JSON.generate` now uses SSE2 (x86) or NEON (arm64) instructions when available to escape strings.
|
20
|
+
|
21
|
+
### 2025-04-25 (2.11.3)
|
22
|
+
|
23
|
+
* Fix a regression in `JSON.pretty_generate` that could cause indentation to be off once some `#to_json` has been called.
|
24
|
+
|
25
|
+
### 2025-04-24 (2.11.2)
|
26
|
+
|
27
|
+
* Add back `JSON::PRETTY_STATE_PROTOTYPE`. This constant was private API but is used by popular gems like `multi_json`.
|
28
|
+
It now emits a deprecation warning.
|
29
|
+
|
30
|
+
### 2025-04-24 (2.11.1)
|
31
|
+
|
32
|
+
* Add back `JSON.restore`, `JSON.unparse`, `JSON.fast_unparse` and `JSON.pretty_unparse`.
|
33
|
+
These were deprecated 16 years ago, but never emited warnings, only undocumented, so are
|
34
|
+
still used by a few gems.
|
35
|
+
|
36
|
+
### 2025-04-24 (2.11.0)
|
37
|
+
|
38
|
+
* Optimize Integer generation to be ~1.8x faster.
|
39
|
+
* Optimize Float generation to be ~10x faster.
|
40
|
+
* Fix `JSON.load` proc argument to substitute the parsed object with the return value.
|
41
|
+
This better match `Marshal.load` behavior.
|
42
|
+
* Deprecate `JSON.fast_generate` (it's not any faster, so pointless).
|
43
|
+
* Deprecate `JSON.load_default_options`.
|
44
|
+
* Deprecate `JSON.unsafe_load_default_options`.
|
45
|
+
* Deprecate `JSON.dump_default_options`.
|
46
|
+
* Deprecate `Kernel#j`
|
47
|
+
* Deprecate `Kernel#jj`
|
48
|
+
* Remove outdated `JSON.iconv`.
|
49
|
+
* Remove `Class#json_creatable?` monkey patch.
|
50
|
+
* Remove deprecated `JSON.restore` method.
|
51
|
+
* Remove deprecated `JSON.unparse` method.
|
52
|
+
* Remove deprecated `JSON.fast_unparse` method.
|
53
|
+
* Remove deprecated `JSON.pretty_unparse` method.
|
54
|
+
* Remove deprecated `JSON::UnparserError` constant.
|
55
|
+
* Remove outdated `JSON::MissingUnicodeSupport` constant.
|
56
|
+
|
3
57
|
### 2025-03-12 (2.10.2)
|
4
58
|
|
5
59
|
* Fix a potential crash in the C extension parser.
|
6
60
|
* Raise a ParserError on all incomplete unicode escape sequence. This was the behavior until `2.10.0` unadvertently changed it.
|
7
61
|
* Ensure document snippets that are included in parser errors don't include truncated multibyte characters.
|
62
|
+
* Ensure parser error snippets are valid UTF-8.
|
63
|
+
* Fix `JSON::GeneratorError#detailed_message` on Ruby < 3.2
|
8
64
|
|
9
65
|
### 2025-02-10 (2.10.1)
|
10
66
|
|
data/README.md
CHANGED
@@ -233,6 +233,19 @@ the `pp` library's `pp` methods.
|
|
233
233
|
|
234
234
|
## Development
|
235
235
|
|
236
|
+
### Prerequisites
|
237
|
+
|
238
|
+
1. Clone the repository
|
239
|
+
2. Install dependencies with `bundle install`
|
240
|
+
|
241
|
+
### Testing
|
242
|
+
|
243
|
+
The full test suite can be run with:
|
244
|
+
|
245
|
+
```bash
|
246
|
+
bundle exec rake test
|
247
|
+
```
|
248
|
+
|
236
249
|
### Release
|
237
250
|
|
238
251
|
Update the `lib/json/version.rb` file.
|
@@ -3,6 +3,7 @@
|
|
3
3
|
|
4
4
|
#include "ruby.h"
|
5
5
|
#include "ruby/encoding.h"
|
6
|
+
#include "../vendor/jeaiii-ltoa.h"
|
6
7
|
|
7
8
|
/* shims */
|
8
9
|
/* This is the fallback definition from Ruby 3.4 */
|
@@ -35,6 +36,12 @@ typedef unsigned char _Bool;
|
|
35
36
|
# define MAYBE_UNUSED(x) x
|
36
37
|
#endif
|
37
38
|
|
39
|
+
#ifdef RUBY_DEBUG
|
40
|
+
#ifndef JSON_DEBUG
|
41
|
+
#define JSON_DEBUG RUBY_DEBUG
|
42
|
+
#endif
|
43
|
+
#endif
|
44
|
+
|
38
45
|
enum fbuffer_type {
|
39
46
|
FBUFFER_HEAP_ALLOCATED = 0,
|
40
47
|
FBUFFER_STACK_ALLOCATED = 1,
|
@@ -45,6 +52,9 @@ typedef struct FBufferStruct {
|
|
45
52
|
unsigned long initial_length;
|
46
53
|
unsigned long len;
|
47
54
|
unsigned long capa;
|
55
|
+
#ifdef JSON_DEBUG
|
56
|
+
unsigned long requested;
|
57
|
+
#endif
|
48
58
|
char *ptr;
|
49
59
|
VALUE io;
|
50
60
|
} FBuffer;
|
@@ -73,6 +83,20 @@ static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char *
|
|
73
83
|
fb->ptr = stack_buffer;
|
74
84
|
fb->capa = stack_buffer_size;
|
75
85
|
}
|
86
|
+
#ifdef JSON_DEBUG
|
87
|
+
fb->requested = 0;
|
88
|
+
#endif
|
89
|
+
}
|
90
|
+
|
91
|
+
static inline void fbuffer_consumed(FBuffer *fb, unsigned long consumed)
|
92
|
+
{
|
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;
|
76
100
|
}
|
77
101
|
|
78
102
|
static void fbuffer_free(FBuffer *fb)
|
@@ -136,6 +160,10 @@ static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
|
|
136
160
|
|
137
161
|
static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
|
138
162
|
{
|
163
|
+
#ifdef JSON_DEBUG
|
164
|
+
fb->requested = requested;
|
165
|
+
#endif
|
166
|
+
|
139
167
|
if (RB_UNLIKELY(requested > fb->capa - fb->len)) {
|
140
168
|
fbuffer_do_inc_capa(fb, requested);
|
141
169
|
}
|
@@ -146,10 +174,24 @@ static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len)
|
|
146
174
|
if (len > 0) {
|
147
175
|
fbuffer_inc_capa(fb, len);
|
148
176
|
MEMCPY(fb->ptr + fb->len, newstr, char, len);
|
149
|
-
fb
|
177
|
+
fbuffer_consumed(fb, len);
|
150
178
|
}
|
151
179
|
}
|
152
180
|
|
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
|
+
|
153
195
|
static void fbuffer_append_str(FBuffer *fb, VALUE str)
|
154
196
|
{
|
155
197
|
const char *newstr = StringValuePtr(str);
|
@@ -164,28 +206,51 @@ static inline void fbuffer_append_char(FBuffer *fb, char newchr)
|
|
164
206
|
{
|
165
207
|
fbuffer_inc_capa(fb, 1);
|
166
208
|
*(fb->ptr + fb->len) = newchr;
|
167
|
-
fb
|
209
|
+
fbuffer_consumed(fb, 1);
|
168
210
|
}
|
169
211
|
|
170
|
-
static
|
212
|
+
static inline char *fbuffer_cursor(FBuffer *fb)
|
171
213
|
{
|
172
|
-
|
173
|
-
|
174
|
-
char* tmp = buf;
|
214
|
+
return fb->ptr + fb->len;
|
215
|
+
}
|
175
216
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
return buf - tmp;
|
217
|
+
static inline void fbuffer_advance_to(FBuffer *fb, char *end)
|
218
|
+
{
|
219
|
+
fbuffer_consumed(fb, (end - fb->ptr) - fb->len);
|
180
220
|
}
|
181
221
|
|
182
|
-
|
222
|
+
/*
|
223
|
+
* Appends the decimal string representation of \a number into the buffer.
|
224
|
+
*/
|
183
225
|
static void fbuffer_append_long(FBuffer *fb, long number)
|
184
226
|
{
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
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
|
+
}
|
251
|
+
|
252
|
+
char *end = jeaiii_ultoa(fbuffer_cursor(fb), number);
|
253
|
+
fbuffer_advance_to(fb, end);
|
189
254
|
}
|
190
255
|
|
191
256
|
static VALUE fbuffer_finalize(FBuffer *fb)
|
@@ -6,5 +6,35 @@ if RUBY_ENGINE == 'truffleruby'
|
|
6
6
|
else
|
7
7
|
append_cflags("-std=c99")
|
8
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
|
+
|
9
39
|
create_makefile 'json/ext/generator'
|
10
40
|
end
|