json 2.10.2 → 2.12.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b909ed90787afa31835c9926529808ca3c6b161755e1f6126b7fe203231fa0c2
4
- data.tar.gz: efd6a873e98f9e4b2b8c078210f141dfde5f3773884bd5851f228c184ff94ff7
3
+ metadata.gz: 8e71f977a9d4c1316007814d62236fd185f5aaade7a79f3e5d48a9ffde32f520
4
+ data.tar.gz: f1be8ac3136a6dcf48aa15c7ec08fa4dfcedb6f89b1b6ad8944727708a16e074
5
5
  SHA512:
6
- metadata.gz: bff39363d5d7fa2f209d5bf97a5728738058bc83600b732d95487e263a5a3901b1e18d5c42d7d2be019ac55ef069a50cedc1d9a8d22b11e6061f2eef747dc94d
7
- data.tar.gz: 693e480f8f2489e26c43eef56ad8977ab3f00fada03318a48b88ac55e2b82b15ffae92fd05dd47d86686fae39169b079f59a68fffc6efaf44ee3503a45060e30
6
+ metadata.gz: 23f2d490dfb7ea60b189f8227787fde0c53844f62c8e9023ba1d413a72b46b7a3b77836d1a6050dd0a2fa925370bd260da0a52d738bd1231c81ad1ef4a17adda
7
+ data.tar.gz: 22326ad3f75f99e20c7f1ad3cc0f519ffc56b7c85c94aa124a2ea47c8d0c86f604307fe504f216b347651d3c82df83623798dbdbabc45be78a1e4721cc7b8cbe
data/CHANGES.md CHANGED
@@ -1,10 +1,57 @@
1
1
  # Changes
2
2
 
3
+ ### Unreleased
4
+
5
+ ### 2025-05-12 (2.12.0)
6
+
7
+ * Improve floating point generation to not use scientific notation as much.
8
+ * Include line and column in parser errors. Both in the message and as exception attributes.
9
+ * Handle non-string hash keys with broken `to_s` implementations.
10
+ * `JSON.generate` now uses SSE2 (x86) or NEON (arm64) instructions when available to escape strings.
11
+
12
+ ### 2025-04-25 (2.11.3)
13
+
14
+ * Fix a regression in `JSON.pretty_generate` that could cause indentation to be off once some `#to_json` has been called.
15
+
16
+ ### 2025-04-24 (2.11.2)
17
+
18
+ * Add back `JSON::PRETTY_STATE_PROTOTYPE`. This constant was private API but is used by popular gems like `multi_json`.
19
+ It now emits a deprecation warning.
20
+
21
+ ### 2025-04-24 (2.11.1)
22
+
23
+ * Add back `JSON.restore`, `JSON.unparse`, `JSON.fast_unparse` and `JSON.pretty_unparse`.
24
+ These were deprecated 16 years ago, but never emited warnings, only undocumented, so are
25
+ still used by a few gems.
26
+
27
+ ### 2025-04-24 (2.11.0)
28
+
29
+ * Optimize Integer generation to be ~1.8x faster.
30
+ * Optimize Float generation to be ~10x faster.
31
+ * Fix `JSON.load` proc argument to substitute the parsed object with the return value.
32
+ This better match `Marshal.load` behavior.
33
+ * Deprecate `JSON.fast_generate` (it's not any faster, so pointless).
34
+ * Deprecate `JSON.load_default_options`.
35
+ * Deprecate `JSON.unsafe_load_default_options`.
36
+ * Deprecate `JSON.dump_default_options`.
37
+ * Deprecate `Kernel#j`
38
+ * Deprecate `Kernel#jj`
39
+ * Remove outdated `JSON.iconv`.
40
+ * Remove `Class#json_creatable?` monkey patch.
41
+ * Remove deprecated `JSON.restore` method.
42
+ * Remove deprecated `JSON.unparse` method.
43
+ * Remove deprecated `JSON.fast_unparse` method.
44
+ * Remove deprecated `JSON.pretty_unparse` method.
45
+ * Remove deprecated `JSON::UnparserError` constant.
46
+ * Remove outdated `JSON::MissingUnicodeSupport` constant.
47
+
3
48
  ### 2025-03-12 (2.10.2)
4
49
 
5
50
  * Fix a potential crash in the C extension parser.
6
51
  * Raise a ParserError on all incomplete unicode escape sequence. This was the behavior until `2.10.0` unadvertently changed it.
7
52
  * Ensure document snippets that are included in parser errors don't include truncated multibyte characters.
53
+ * Ensure parser error snippets are valid UTF-8.
54
+ * Fix `JSON::GeneratorError#detailed_message` on Ruby < 3.2
8
55
 
9
56
  ### 2025-02-10 (2.10.1)
10
57
 
@@ -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 */
@@ -150,6 +151,13 @@ static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len)
150
151
  }
151
152
  }
152
153
 
154
+ /* Appends a character into a buffer. The buffer needs to have sufficient capacity, via fbuffer_inc_capa(...). */
155
+ static inline void fbuffer_append_reserved_char(FBuffer *fb, char chr)
156
+ {
157
+ fb->ptr[fb->len] = chr;
158
+ fb->len += 1;
159
+ }
160
+
153
161
  static void fbuffer_append_str(FBuffer *fb, VALUE str)
154
162
  {
155
163
  const char *newstr = StringValuePtr(str);
@@ -167,25 +175,48 @@ static inline void fbuffer_append_char(FBuffer *fb, char newchr)
167
175
  fb->len++;
168
176
  }
169
177
 
170
- static long fltoa(long number, char *buf)
178
+ static inline char *fbuffer_cursor(FBuffer *fb)
179
+ {
180
+ return fb->ptr + fb->len;
181
+ }
182
+
183
+ static inline void fbuffer_advance_to(FBuffer *fb, char *end)
171
184
  {
172
- static const char digits[] = "0123456789";
173
- long sign = number;
174
- char* tmp = buf;
175
-
176
- if (sign < 0) number = -number;
177
- do *tmp-- = digits[number % 10]; while (number /= 10);
178
- if (sign < 0) *tmp-- = '-';
179
- return buf - tmp;
185
+ fb->len = end - fb->ptr;
180
186
  }
181
187
 
182
- #define LONG_BUFFER_SIZE 20
188
+ /*
189
+ * Appends the decimal string representation of \a number into the buffer.
190
+ */
183
191
  static void fbuffer_append_long(FBuffer *fb, long number)
184
192
  {
185
- char buf[LONG_BUFFER_SIZE];
186
- char *buffer_end = buf + LONG_BUFFER_SIZE;
187
- long len = fltoa(number, buffer_end - 1);
188
- fbuffer_append(fb, buffer_end - len, len);
193
+ /*
194
+ * The jeaiii_ultoa() function produces digits left-to-right,
195
+ * allowing us to write directly into the buffer, but we don't know
196
+ * the number of resulting characters.
197
+ *
198
+ * We do know, however, that the `number` argument is always in the
199
+ * range 0xc000000000000000 to 0x3fffffffffffffff, or, in decimal,
200
+ * -4611686018427387904 to 4611686018427387903. The max number of chars
201
+ * generated is therefore 20 (including a potential sign character).
202
+ */
203
+
204
+ static const int MAX_CHARS_FOR_LONG = 20;
205
+
206
+ fbuffer_inc_capa(fb, MAX_CHARS_FOR_LONG);
207
+
208
+ if (number < 0) {
209
+ fbuffer_append_reserved_char(fb, '-');
210
+
211
+ /*
212
+ * Since number is always > LONG_MIN, `-number` will not overflow
213
+ * and is always the positive abs() value.
214
+ */
215
+ number = -number;
216
+ }
217
+
218
+ char *end = jeaiii_ultoa(fbuffer_cursor(fb), number);
219
+ fbuffer_advance_to(fb, end);
189
220
  }
190
221
 
191
222
  static VALUE fbuffer_finalize(FBuffer *fb)
@@ -6,5 +6,34 @@ if RUBY_ENGINE == 'truffleruby'
6
6
  else
7
7
  append_cflags("-std=c99")
8
8
  $defs << "-DJSON_GENERATOR"
9
+
10
+ if enable_config('generator-use-simd', default=!ENV["JSON_DISABLE_SIMD"])
11
+ if RbConfig::CONFIG['host_cpu'] =~ /^(arm.*|aarch64.*)/
12
+ # Try to compile a small program using NEON instructions
13
+ if have_header('arm_neon.h')
14
+ have_type('uint8x16_t', headers=['arm_neon.h']) && try_compile(<<~'SRC')
15
+ #include <arm_neon.h>
16
+ int main() {
17
+ uint8x16_t test = vdupq_n_u8(32);
18
+ return 0;
19
+ }
20
+ SRC
21
+ $defs.push("-DJSON_ENABLE_SIMD")
22
+ end
23
+ end
24
+
25
+ if have_header('x86intrin.h') && have_type('__m128i', headers=['x86intrin.h']) && try_compile(<<~'SRC')
26
+ #include <x86intrin.h>
27
+ int main() {
28
+ __m128i test = _mm_set1_epi8(32);
29
+ return 0;
30
+ }
31
+ SRC
32
+ $defs.push("-DJSON_ENABLE_SIMD")
33
+ end
34
+
35
+ have_header('cpuid.h')
36
+ end
37
+
9
38
  create_makefile 'json/ext/generator'
10
39
  end