Coverage Report

Created: 2026-09-01 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/yyjson/src/yyjson.c
Line
Count
Source
1
/*==============================================================================
2
 Copyright (c) 2020 YaoYuan <ibireme@gmail.com>
3
4
 Permission is hereby granted, free of charge, to any person obtaining a copy
5
 of this software and associated documentation files (the "Software"), to deal
6
 in the Software without restriction, including without limitation the rights
7
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
 copies of the Software, and to permit persons to whom the Software is
9
 furnished to do so, subject to the following conditions:
10
11
 The above copyright notice and this permission notice shall be included in all
12
 copies or substantial portions of the Software.
13
14
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
 SOFTWARE.
21
 *============================================================================*/
22
23
#include "yyjson.h"
24
25
26
27
/*==============================================================================
28
 * MARK: - Warning Suppress (Private)
29
 *============================================================================*/
30
31
#if defined(__clang__)
32
#   pragma clang diagnostic ignored "-Wunused-function"
33
#   pragma clang diagnostic ignored "-Wunused-parameter"
34
#   pragma clang diagnostic ignored "-Wunused-label"
35
#   pragma clang diagnostic ignored "-Wunused-macros"
36
#   pragma clang diagnostic ignored "-Wunused-variable"
37
#elif YYJSON_IS_REAL_GCC && yyjson_gcc_available(4, 2, 0)
38
#   pragma GCC diagnostic ignored "-Wunused-function"
39
#   pragma GCC diagnostic ignored "-Wunused-parameter"
40
#   pragma GCC diagnostic ignored "-Wunused-label"
41
#   pragma GCC diagnostic ignored "-Wunused-macros"
42
#   pragma GCC diagnostic ignored "-Wunused-variable"
43
#elif defined(_MSC_VER)
44
#   pragma warning(disable:4100) /* unreferenced formal parameter */
45
#   pragma warning(disable:4101) /* unreferenced variable */
46
#   pragma warning(disable:4102) /* unreferenced label */
47
#   pragma warning(disable:4127) /* conditional expression is constant */
48
#   pragma warning(disable:4702) /* unreachable code */
49
#   pragma warning(disable:4706) /* assignment within conditional expression */
50
#endif
51
52
53
54
/*==============================================================================
55
 * MARK: - Version (Public)
56
 *============================================================================*/
57
58
0
uint32_t yyjson_version(void) {
59
0
    return YYJSON_VERSION_HEX;
60
0
}
61
62
63
64
/*==============================================================================
65
 * MARK: - Flags (Private)
66
 *============================================================================*/
67
68
/* msvc intrinsic */
69
#if YYJSON_MSC_VER >= 1400
70
#   include <intrin.h>
71
#   if defined(_M_AMD64) || defined(_M_ARM64)
72
#       define MSC_HAS_BIT_SCAN_64 1
73
#       pragma intrinsic(_BitScanForward64)
74
#       pragma intrinsic(_BitScanReverse64)
75
#   else
76
#       define MSC_HAS_BIT_SCAN_64 0
77
#   endif
78
#   if defined(_M_AMD64) || defined(_M_ARM64) || \
79
        defined(_M_IX86) || defined(_M_ARM)
80
#       define MSC_HAS_BIT_SCAN 1
81
#       pragma intrinsic(_BitScanForward)
82
#       pragma intrinsic(_BitScanReverse)
83
#   else
84
#       define MSC_HAS_BIT_SCAN 0
85
#   endif
86
#   if defined(_M_AMD64)
87
#       define MSC_HAS_UMUL128 1
88
#       pragma intrinsic(_umul128)
89
#   else
90
#       define MSC_HAS_UMUL128 0
91
#   endif
92
#else
93
#   define MSC_HAS_BIT_SCAN_64 0
94
#   define MSC_HAS_BIT_SCAN 0
95
#   define MSC_HAS_UMUL128 0
96
#endif
97
98
/* gcc builtin */
99
#if yyjson_has_builtin(__builtin_clzll) || yyjson_gcc_available(3, 4, 0)
100
#   define GCC_HAS_CLZLL 1
101
#else
102
#   define GCC_HAS_CLZLL 0
103
#endif
104
105
#if yyjson_has_builtin(__builtin_ctzll) || yyjson_gcc_available(3, 4, 0)
106
#   define GCC_HAS_CTZLL 1
107
#else
108
#   define GCC_HAS_CTZLL 0
109
#endif
110
111
/* int128 type */
112
#ifndef YYJSON_HAS_INT128
113
#   if defined(__SIZEOF_INT128__) && (__SIZEOF_INT128__ == 16) && \
114
    (defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER)) && \
115
    (!defined(__EMSCRIPTEN__) && !defined(__wasm__))
116
#       define YYJSON_HAS_INT128 1
117
#   else
118
#       define YYJSON_HAS_INT128 0
119
#   endif
120
#endif
121
122
/* IEEE 754 floating-point binary representation */
123
#ifndef YYJSON_HAS_IEEE_754
124
#   if defined(__STDC_IEC_559__) || defined(__STDC_IEC_60559_BFP__)
125
#       define YYJSON_HAS_IEEE_754 1
126
#   elif FLT_RADIX == 2 && \
127
    FLT_MANT_DIG == 24 && FLT_DIG == 6 && \
128
    FLT_MIN_EXP == -125 && FLT_MAX_EXP == 128 && \
129
    FLT_MIN_10_EXP == -37 && FLT_MAX_10_EXP == 38 && \
130
    DBL_MANT_DIG == 53 && DBL_DIG == 15 && \
131
    DBL_MIN_EXP == -1021 && DBL_MAX_EXP == 1024 && \
132
    DBL_MIN_10_EXP == -307 && DBL_MAX_10_EXP == 308
133
#       define YYJSON_HAS_IEEE_754 1
134
#   else
135
#       define YYJSON_HAS_IEEE_754 0
136
#       undef  YYJSON_DISABLE_FAST_FP_CONV
137
#       define YYJSON_DISABLE_FAST_FP_CONV 1
138
#   endif
139
#endif
140
141
#if YYJSON_DISABLE_FAST_FP_CONV && YYJSON_FREESTANDING
142
#   error DISABLE_FAST_FP_CONV and FREESTANDING cannot be used together
143
#endif
144
145
/* Inf and NaN */
146
#ifndef INFINITY
147
#    ifndef HUGE_VAL
148
#        define INFINITY ((double)(1.0 / 0.0))
149
#    else
150
#        define INFINITY HUGE_VAL
151
#    endif
152
#endif
153
#ifndef NAN
154
#    define NAN ((double)(0.0 / 0.0))
155
#endif
156
157
/*
158
 Correct rounding in double number computations.
159
160
 On the x86 architecture, some compilers may use x87 FPU instructions for
161
 floating-point arithmetic. The x87 FPU loads all floating-point numbers as
162
 80-bit double-extended precision internally, then rounds the result to the
163
 original precision, which may produce inaccurate results. For a more detailed
164
 explanation, see the paper: https://arxiv.org/abs/cs/0701192
165
166
 Here are some examples of double precision calculation error:
167
168
     2877.0 / 1e6   == 0.002877,  but x87 returns 0.0028770000000000002
169
     43683.0 * 1e21 == 4.3683e25, but x87 returns 4.3683000000000004e25
170
171
 Here are some examples of compiler flags to generate x87 instructions on x86:
172
173
     clang -m32 -mno-sse
174
     gcc/icc -m32 -mfpmath=387
175
     msvc /arch:SSE or /arch:IA32
176
177
 If we are sure that there's no similar error described above, we can define the
178
 YYJSON_DOUBLE_MATH_CORRECT as 1 to enable the fast path calculation. This is
179
 not an accurate detection; it just tries to avoid the error at compile-time.
180
 An accurate detection can be done at run-time:
181
182
     bool is_double_math_correct(void) {
183
         volatile double r = 43683.0;
184
         r *= 1e21;
185
         return r == 4.3683e25;
186
     }
187
188
 See also: utils.h in https://github.com/google/double-conversion/
189
 */
190
#if !defined(FLT_EVAL_METHOD) && defined(__FLT_EVAL_METHOD__)
191
#    define FLT_EVAL_METHOD __FLT_EVAL_METHOD__
192
#endif
193
194
#if defined(FLT_EVAL_METHOD) && FLT_EVAL_METHOD != 0 && FLT_EVAL_METHOD != 1
195
#    define YYJSON_DOUBLE_MATH_CORRECT 0
196
#elif defined(i386) || defined(__i386) || defined(__i386__) || \
197
    defined(_X86_) || defined(__X86__) || defined(_M_IX86) || \
198
    defined(__I86__) || defined(__IA32__) || defined(__THW_INTEL)
199
#   if (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP == 2) || \
200
        (defined(__SSE2_MATH__) && __SSE2_MATH__)
201
#       define YYJSON_DOUBLE_MATH_CORRECT 1
202
#   else
203
#       define YYJSON_DOUBLE_MATH_CORRECT 0
204
#   endif
205
#elif defined(__mc68000__) || defined(__pnacl__) || defined(__native_client__)
206
#   define YYJSON_DOUBLE_MATH_CORRECT 0
207
#else
208
#   define YYJSON_DOUBLE_MATH_CORRECT 1
209
#endif
210
211
/*
212
 Detect the endianness at compile-time.
213
 YYJSON_ENDIAN == YYJSON_BIG_ENDIAN
214
 YYJSON_ENDIAN == YYJSON_LITTLE_ENDIAN
215
 */
216
#define YYJSON_BIG_ENDIAN       4321
217
#define YYJSON_LITTLE_ENDIAN    1234
218
219
#if yyjson_has_include(<sys/types.h>)
220
#    include <sys/types.h> /* POSIX */
221
#endif
222
#if yyjson_has_include(<endian.h>)
223
#    include <endian.h> /* Linux */
224
#elif yyjson_has_include(<sys/endian.h>)
225
#    include <sys/endian.h> /* BSD, Android */
226
#elif yyjson_has_include(<machine/endian.h>)
227
#    include <machine/endian.h> /* BSD, Darwin */
228
#endif
229
230
#if defined(BYTE_ORDER) && BYTE_ORDER
231
#   if defined(BIG_ENDIAN) && (BYTE_ORDER == BIG_ENDIAN)
232
#       define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
233
#   elif defined(LITTLE_ENDIAN) && (BYTE_ORDER == LITTLE_ENDIAN)
234
#       define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
235
#   endif
236
#elif defined(__BYTE_ORDER) && __BYTE_ORDER
237
#   if defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN)
238
#       define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
239
#   elif defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN)
240
#       define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
241
#   endif
242
#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__
243
#   if defined(__ORDER_BIG_ENDIAN__) && \
244
        (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
245
#       define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
246
#   elif defined(__ORDER_LITTLE_ENDIAN__) && \
247
        (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
248
#       define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
249
#   endif
250
#elif (defined(__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__ == 1) || \
251
    defined(__i386) || defined(__i386__) || \
252
    defined(_X86_) || defined(__X86__) || \
253
    defined(_M_IX86) || defined(__THW_INTEL__) || \
254
    defined(__x86_64) || defined(__x86_64__) || \
255
    defined(__amd64) || defined(__amd64__) || \
256
    defined(_M_AMD64) || defined(_M_X64) || \
257
    defined(_M_ARM) || defined(_M_ARM64) || \
258
    defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \
259
    defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || \
260
    defined(__EMSCRIPTEN__) || defined(__wasm__) || \
261
    defined(__loongarch__)
262
#   define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
263
#elif (defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ == 1) || \
264
    defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \
265
    defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) || \
266
    defined(__or1k__) || defined(__OR1K__)
267
#   define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
268
#else
269
#   define YYJSON_ENDIAN 0 /* unknown endian, detect at run-time */
270
#endif
271
272
/*
273
 This macro controls how yyjson handles unaligned memory accesses.
274
275
 By default, yyjson uses `memcpy()` for memory copying. This allows the compiler
276
 to optimize the code and emit unaligned memory access instructions when
277
 supported by the target architecture.
278
279
 However, on some older compilers or architectures where `memcpy()` is not
280
 well-optimized and may result in unnecessary function calls, defining this
281
 macro as 1 may help. In such cases, yyjson switches to manual byte-by-byte
282
 access, which can potentially improve performance.
283
284
 An example of the generated assembly code for ARM can be found here:
285
 https://godbolt.org/z/334jjhxPT
286
287
 This flag is already enabled for common architectures in the following code,
288
 so manual configuration is usually unnecessary. If unsure, you can check the
289
 generated assembly or run benchmarks to make an informed decision.
290
 */
291
#ifndef YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
292
#   if defined(__ia64) || defined(_IA64) || defined(__IA64__) ||  \
293
        defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
294
#       define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* Itanium */
295
#   elif (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) && \
296
        (defined(__GNUC__) || defined(__clang__)) && \
297
        (!defined(__ARM_FEATURE_UNALIGNED) || !__ARM_FEATURE_UNALIGNED)
298
#       define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* ARM */
299
#   elif defined(__sparc) || defined(__sparc__)
300
#       define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* SPARC */
301
#   elif defined(__mips) || defined(__mips__) || defined(__MIPS__)
302
#       define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* MIPS */
303
#   elif defined(__m68k__) || defined(M68000)
304
#       define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* M68K */
305
#   else
306
#       define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 0
307
#   endif
308
#endif
309
310
/*
311
 Estimated initial ratio of the JSON data (data_size / value_count).
312
 For example:
313
314
    data:        {"id":12345678,"name":"Harry"}
315
    data_size:   30
316
    value_count: 5
317
    ratio:       6
318
319
 yyjson uses dynamic memory with a growth factor of 1.5 when reading and writing
320
 JSON, the ratios below are used to determine the initial memory size.
321
322
 A too large ratio will waste memory, and a too small ratio will cause multiple
323
 memory growths and degrade performance. Currently, these ratios are generated
324
 with some commonly used JSON datasets.
325
 */
326
31.5k
#define YYJSON_READER_ESTIMATED_PRETTY_RATIO 16
327
51.1k
#define YYJSON_READER_ESTIMATED_MINIFY_RATIO 6
328
5.11k
#define YYJSON_WRITER_ESTIMATED_PRETTY_RATIO 32
329
11.1k
#define YYJSON_WRITER_ESTIMATED_MINIFY_RATIO 18
330
331
/* The initial and maximum size of the memory pool's chunk in yyjson_mut_doc. */
332
30.5k
#define YYJSON_MUT_DOC_STR_POOL_INIT_SIZE   0x100
333
30.5k
#define YYJSON_MUT_DOC_STR_POOL_MAX_SIZE    0x10000000
334
30.5k
#define YYJSON_MUT_DOC_VAL_POOL_INIT_SIZE   (0x10 * sizeof(yyjson_mut_val))
335
30.5k
#define YYJSON_MUT_DOC_VAL_POOL_MAX_SIZE    (0x1000000 * sizeof(yyjson_mut_val))
336
337
/* The minimum size of the dynamic allocator's chunk. */
338
0
#define YYJSON_ALC_DYN_MIN_SIZE             0x1000
339
340
/* Default value for compile-time options. */
341
342
#ifndef YYJSON_READER_DEPTH_LIMIT
343
#define YYJSON_READER_DEPTH_LIMIT 0
344
#endif
345
346
/*==============================================================================
347
 * MARK: - Macros (Private)
348
 *============================================================================*/
349
350
/* Macros used for loop unrolling and other purposes. */
351
#define repeat2(x)  { x x }
352
#define repeat4(x)  { x x x x }
353
#define repeat8(x)  { x x x x x x x x }
354
2.44M
#define repeat16(x) { x x x x x x x x x x x x x x x x }
355
356
#define repeat2_incr(x)   { x(0)  x(1) }
357
21.2M
#define repeat4_incr(x)   { x(0)  x(1)  x(2)  x(3) }
358
#define repeat8_incr(x)   { x(0)  x(1)  x(2)  x(3)  x(4)  x(5)  x(6)  x(7)  }
359
57.4M
#define repeat16_incr(x)  { x(0)  x(1)  x(2)  x(3)  x(4)  x(5)  x(6)  x(7)  \
360
15.7M
                            x(8)  x(9)  x(10) x(11) x(12) x(13) x(14) x(15) }
361
4.98M
#define repeat_in_1_18(x) { x(1)  x(2)  x(3)  x(4)  x(5)  x(6)  x(7)  x(8)  \
362
1.23M
                            x(9)  x(10) x(11) x(12) x(13) x(14) x(15) x(16) \
363
316k
                            x(17) x(18) }
364
365
/* Macros used to provide branch prediction information for compiler. */
366
#undef  likely
367
185M
#define likely(x)       yyjson_likely(x)
368
#undef  unlikely
369
4.63G
#define unlikely(x)     yyjson_unlikely(x)
370
371
/* Macros used to provide inline information for compiler. */
372
#undef  static_inline
373
#define static_inline   static yyjson_inline
374
#undef  static_noinline
375
#define static_noinline static yyjson_noinline
376
377
/* Macros for min and max. */
378
#undef  yyjson_min
379
148k
#define yyjson_min(x, y) ((x) < (y) ? (x) : (y))
380
#undef  yyjson_max
381
3.73M
#define yyjson_max(x, y) ((x) > (y) ? (x) : (y))
382
383
/* Used to write u64 literal for C89 which doesn't support "ULL" suffix. */
384
#undef  U64
385
9.34M
#define U64(hi, lo) ((((u64)hi##UL) << 32U) + lo##UL)
386
#undef  U32
387
0
#define U32(hi) ((u32)(hi##UL))
388
389
/* Used to cast away (remove) const qualifier. */
390
233k
#define constcast yyjson_constcast
391
392
/*
393
 Compiler barriers for single variables.
394
395
 These macros inform GCC that a read or write access to the given memory
396
 location will occur, preventing certain compiler optimizations or reordering
397
 around the access to 'val'. They do not emit any actual instructions.
398
399
 This is useful when GCC's default optimization strategies are suboptimal and
400
 precise control over memory access patterns is required.
401
 These barriers are not needed when using Clang or MSVC.
402
 */
403
#if YYJSON_IS_REAL_GCC
404
#   define gcc_load_barrier(val)   __asm__ volatile(""::"m"(val))
405
#   define gcc_store_barrier(val)  __asm__ volatile("":"=m"(val))
406
#   define gcc_full_barrier(val)   __asm__ volatile("":"=m"(val):"m"(val))
407
#else
408
#   define gcc_load_barrier(val)
409
#   define gcc_store_barrier(val)
410
#   define gcc_full_barrier(val)
411
#endif
412
413
414
415
/*==============================================================================
416
 * MARK: - Constants (Private)
417
 *============================================================================*/
418
419
/* Common error messages. */
420
#define MSG_FOPEN       "failed to open file"
421
#define MSG_FREAD       "failed to read file"
422
#define MSG_FWRITE      "failed to write file"
423
#define MSG_FCLOSE      "failed to close file"
424
#define MSG_MALLOC      "failed to allocate memory"
425
#define MSG_CHAR_T      "invalid literal, expected 'true'"
426
#define MSG_CHAR_F      "invalid literal, expected 'false'"
427
#define MSG_CHAR_N      "invalid literal, expected 'null'"
428
#define MSG_CHAR        "unexpected character, expected a JSON value"
429
#define MSG_ARR_END     "unexpected character, expected ',' or ']'"
430
#define MSG_OBJ_KEY     "unexpected character, expected a string key"
431
#define MSG_OBJ_SEP     "unexpected character, expected ':' after key"
432
#define MSG_OBJ_END     "unexpected character, expected ',' or '}'"
433
#define MSG_GARBAGE     "unexpected content after document"
434
41.0k
#define MSG_NOT_END     "unexpected end of data"
435
#define MSG_COMMENT     "unclosed multiline comment"
436
#define MSG_COMMA       "trailing comma is not allowed"
437
#define MSG_NAN_INF     "nan or inf number is not allowed"
438
#define MSG_ERR_TYPE    "invalid JSON value type"
439
11
#define MSG_ERR_BOM     "UTF-8 byte order mark (BOM) is not supported"
440
#define MSG_ERR_UTF8    "invalid utf-8 encoding in string"
441
48
#define MSG_ERR_UTF16   "UTF-16 encoding is not supported"
442
21
#define MSG_ERR_UTF32   "UTF-32 encoding is not supported"
443
#define MSG_DEPTH       "depth limit exceeded"
444
445
/* U64 constant values */
446
#undef  U64_MAX
447
34.8k
#define U64_MAX         U64(0xFFFFFFFF, 0xFFFFFFFF)
448
#undef  I64_MAX
449
#define I64_MAX         U64(0x7FFFFFFF, 0xFFFFFFFF)
450
#undef  USIZE_MAX
451
170k
#define USIZE_MAX       ((usize)(~(usize)0))
452
453
/* Maximum number of digits for reading u32/u64/usize safety (not overflow). */
454
#undef  U32_SAFE_DIG
455
#define U32_SAFE_DIG    9   /* u32 max is 4294967295, 10 digits */
456
#undef  U64_SAFE_DIG
457
11.0M
#define U64_SAFE_DIG    19  /* u64 max is 18446744073709551615, 20 digits */
458
#undef  USIZE_SAFE_DIG
459
#define USIZE_SAFE_DIG  (sizeof(usize) == 8 ? U64_SAFE_DIG : U32_SAFE_DIG)
460
461
/* Inf bits (positive) */
462
7.88k
#define F64_BITS_INF U64(0x7FF00000, 0x00000000)
463
464
/* NaN bits (quiet NaN, no payload, no sign) */
465
#if defined(__hppa__) || (defined(__mips__) && !defined(__mips_nan2008))
466
#define F64_BITS_NAN U64(0x7FF7FFFF, 0xFFFFFFFF)
467
#else
468
6.43k
#define F64_BITS_NAN U64(0x7FF80000, 0x00000000)
469
#endif
470
471
/* maximum significant digits count in decimal when reading double number */
472
53.1k
#define F64_MAX_DEC_DIG 768
473
474
/* maximum decimal power of double number (1.7976931348623157e308) */
475
#define F64_MAX_DEC_EXP 308
476
477
/* minimum decimal power of double number (4.9406564584124654e-324) */
478
#define F64_MIN_DEC_EXP (-324)
479
480
/* maximum binary power of double number */
481
#define F64_MAX_BIN_EXP 1024
482
483
/* minimum binary power of double number */
484
30.2k
#define F64_MIN_BIN_EXP (-1021)
485
486
/* float/double number bits */
487
0
#define F32_BITS 32
488
4.95M
#define F64_BITS 64
489
490
/* float/double number exponent part bits */
491
#define F32_EXP_BITS 8
492
#define F64_EXP_BITS 11
493
494
/* float/double number significand part bits */
495
0
#define F32_SIG_BITS 23
496
17.0M
#define F64_SIG_BITS 52
497
498
/* float/double number significand part bits (with 1 hidden bit) */
499
#define F32_SIG_FULL_BITS 24
500
699k
#define F64_SIG_FULL_BITS 53
501
502
/* float/double number significand bit mask */
503
0
#define F32_SIG_MASK U32(0x007FFFFF)
504
4.72M
#define F64_SIG_MASK U64(0x000FFFFF, 0xFFFFFFFF)
505
506
/* float/double number exponent bit mask */
507
0
#define F32_EXP_MASK U32(0x7F800000)
508
4.56M
#define F64_EXP_MASK U64(0x7FF00000, 0x00000000)
509
510
/* float/double number exponent bias */
511
0
#define F32_EXP_BIAS 127
512
4.89M
#define F64_EXP_BIAS 1023
513
514
/* float/double number significant digits count in decimal */
515
#define F32_DEC_DIG 9
516
#define F64_DEC_DIG 17
517
518
/* buffer length required for float/double number writer */
519
#define FP_BUF_LEN 40
520
521
/* maximum length of a number in incremental parsing */
522
#define INCR_NUM_MAX_LEN 1024
523
524
525
526
/*==============================================================================
527
 * MARK: - Types (Private)
528
 *============================================================================*/
529
530
/** Type aliases for primitive types. */
531
typedef float       f32;
532
typedef double      f64;
533
typedef int8_t      i8;
534
typedef uint8_t     u8;
535
typedef int16_t     i16;
536
typedef uint16_t    u16;
537
typedef int32_t     i32;
538
typedef uint32_t    u32;
539
typedef int64_t     i64;
540
typedef uint64_t    u64;
541
typedef size_t      usize;
542
543
/** 128-bit integer, used by floating-point number reader and writer. */
544
#if YYJSON_HAS_INT128
545
__extension__ typedef __int128          i128;
546
__extension__ typedef unsigned __int128 u128;
547
#endif
548
549
/** 16/32/64-bit vector */
550
typedef struct v16 { char c[2]; } v16;
551
typedef struct v32 { char c[4]; } v32;
552
typedef struct v64 { char c[8]; } v64;
553
554
/** 16/32/64-bit vector union */
555
typedef union v16_uni { v16 v; u16 u; } v16_uni;
556
typedef union v32_uni { v32 v; u32 u; } v32_uni;
557
typedef union v64_uni { v64 v; u64 u; } v64_uni;
558
559
560
561
/*==============================================================================
562
 * MARK: - Load/Store Utils (Private)
563
 *============================================================================*/
564
565
#define byte_move_idx(x) ((char *)dst)[x] = ((const char *)src)[x];
566
#define byte_move_src(x) ((char *)tmp)[x] = ((const char *)src)[x];
567
#define byte_move_dst(x) ((char *)dst)[x] = ((const char *)tmp)[x];
568
569
/** Same as `memcpy(dst, src, 2)`, no overlap. */
570
759M
static_inline void byte_copy_2(void *dst, const void *src) {
571
759M
#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
572
759M
    memcpy(dst, src, 2);
573
#else
574
    repeat2_incr(byte_move_idx)
575
#endif
576
759M
}
577
578
/** Same as `memcpy(dst, src, 4)`, no overlap. */
579
7.88G
static_inline void byte_copy_4(void *dst, const void *src) {
580
7.88G
#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
581
7.88G
    memcpy(dst, src, 4);
582
#else
583
    repeat4_incr(byte_move_idx)
584
#endif
585
7.88G
}
586
587
/** Same as `memcpy(dst, src, 8)`, no overlap. */
588
672k
static_inline void byte_copy_8(void *dst, const void *src) {
589
672k
#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
590
672k
    memcpy(dst, src, 8);
591
#else
592
    repeat8_incr(byte_move_idx)
593
#endif
594
672k
}
595
596
/** Same as `memcpy(dst, src, 16)`, no overlap. */
597
30.4M
static_inline void byte_copy_16(void *dst, const void *src) {
598
30.4M
#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
599
30.4M
    memcpy(dst, src, 16);
600
#else
601
    repeat16_incr(byte_move_idx)
602
#endif
603
30.4M
}
604
605
/** Same as `memmove(dst, src, 2)`, allows overlap. */
606
870k
static_inline void byte_move_2(void *dst, const void *src) {
607
870k
#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
608
870k
    u16 tmp;
609
870k
    memcpy(&tmp, src, 2);
610
870k
    memcpy(dst, &tmp, 2);
611
#else
612
    char tmp[2];
613
    repeat2_incr(byte_move_src)
614
    repeat2_incr(byte_move_dst)
615
#endif
616
870k
}
617
618
/** Same as `memmove(dst, src, 4)`, allows overlap. */
619
616k
static_inline void byte_move_4(void *dst, const void *src) {
620
616k
#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
621
616k
    u32 tmp;
622
616k
    memcpy(&tmp, src, 4);
623
616k
    memcpy(dst, &tmp, 4);
624
#else
625
    char tmp[4];
626
    repeat4_incr(byte_move_src)
627
    repeat4_incr(byte_move_dst)
628
#endif
629
616k
}
630
631
/** Same as `memmove(dst, src, 8)`, allows overlap. */
632
660k
static_inline void byte_move_8(void *dst, const void *src) {
633
660k
#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
634
660k
    u64 tmp;
635
660k
    memcpy(&tmp, src, 8);
636
660k
    memcpy(dst, &tmp, 8);
637
#else
638
    char tmp[8];
639
    repeat8_incr(byte_move_src)
640
    repeat8_incr(byte_move_dst)
641
#endif
642
660k
}
643
644
/** Same as `memmove(dst, src, 16)`, allows overlap. */
645
2.58M
static_inline void byte_move_16(void *dst, const void *src) {
646
2.58M
#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
647
2.58M
    char *pdst = (char *)dst;
648
2.58M
    const char *psrc = (const char *)src;
649
2.58M
    u64 tmp1, tmp2;
650
2.58M
    memcpy(&tmp1, psrc, 8);
651
2.58M
    memcpy(&tmp2, psrc + 8, 8);
652
2.58M
    memcpy(pdst, &tmp1, 8);
653
2.58M
    memcpy(pdst + 8, &tmp2, 8);
654
#else
655
    char tmp[16];
656
    repeat16_incr(byte_move_src)
657
    repeat16_incr(byte_move_dst)
658
#endif
659
2.58M
}
660
661
/** Same as `memmove(dst, src, n)`, but only `dst <= src` and `n <= 16`. */
662
1.82M
static_inline void byte_move_forward(void *dst, void *src, usize n) {
663
1.82M
    char *d = (char *)dst, *s = (char *)src;
664
1.82M
    n += (n % 2); /* round up to even */
665
1.82M
    if (n == 16) { byte_move_16(d, s); return; }
666
1.71M
    if (n >= 8) { byte_move_8(d, s); n -= 8; d += 8; s += 8; }
667
1.71M
    if (n >= 4) { byte_move_4(d, s); n -= 4; d += 4; s += 4; }
668
1.71M
    if (n >= 2) { byte_move_2(d, s); }
669
1.71M
}
670
671
/** Same as `memcmp(buf, pat, 2) == 0`. */
672
2.96M
static_inline bool byte_match_2(void *buf, const char *pat) {
673
2.96M
#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
674
2.96M
    v16_uni u1, u2;
675
2.96M
    memcpy(&u1, buf, 2);
676
2.96M
    memcpy(&u2, pat, 2);
677
2.96M
    return u1.u == u2.u;
678
#else
679
    return ((char *)buf)[0] == ((const char *)pat)[0] &&
680
           ((char *)buf)[1] == ((const char *)pat)[1];
681
#endif
682
2.96M
}
683
684
/** Same as `memcmp(buf, pat, 4) == 0`. */
685
253k
static_inline bool byte_match_4(void *buf, const char *pat) {
686
253k
#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
687
253k
    v32_uni u1, u2;
688
253k
    memcpy(&u1, buf, 4);
689
253k
    memcpy(&u2, pat, 4);
690
253k
    return u1.u == u2.u;
691
#else
692
    return ((char *)buf)[0] == ((const char *)pat)[0] &&
693
           ((char *)buf)[1] == ((const char *)pat)[1] &&
694
           ((char *)buf)[2] == ((const char *)pat)[2] &&
695
           ((char *)buf)[3] == ((const char *)pat)[3];
696
#endif
697
253k
}
698
699
/** Loads 2 bytes from `src` as a u16 (native-endian). */
700
1.44M
static_inline u16 byte_load_2(const void *src) {
701
1.44M
    v16_uni uni;
702
1.44M
#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
703
1.44M
    memcpy(&uni, src, 2);
704
#else
705
    uni.v.c[0] = ((const char *)src)[0];
706
    uni.v.c[1] = ((const char *)src)[1];
707
#endif
708
1.44M
    return uni.u;
709
1.44M
}
710
711
/** Loads 3 bytes from `src` as a u32 (native-endian). */
712
60.8k
static_inline u32 byte_load_3(const void *src) {
713
60.8k
    v32_uni uni;
714
60.8k
#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
715
60.8k
    memcpy(&uni, src, 2);
716
60.8k
    uni.v.c[2] = ((const char *)src)[2];
717
60.8k
    uni.v.c[3] = 0;
718
#else
719
    uni.v.c[0] = ((const char *)src)[0];
720
    uni.v.c[1] = ((const char *)src)[1];
721
    uni.v.c[2] = ((const char *)src)[2];
722
    uni.v.c[3] = 0;
723
#endif
724
60.8k
    return uni.u;
725
60.8k
}
726
727
/** Loads 4 bytes from `src` as a u32 (native-endian). */
728
5.68M
static_inline u32 byte_load_4(const void *src) {
729
5.68M
    v32_uni uni;
730
5.68M
#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
731
5.68M
    memcpy(&uni, src, 4);
732
#else
733
    uni.v.c[0] = ((const char *)src)[0];
734
    uni.v.c[1] = ((const char *)src)[1];
735
    uni.v.c[2] = ((const char *)src)[2];
736
    uni.v.c[3] = ((const char *)src)[3];
737
#endif
738
5.68M
    return uni.u;
739
5.68M
}
740
741
742
743
/*==============================================================================
744
 * MARK: - Character Utils (Private)
745
 * These lookup tables were generated by `misc/make_tables.c`.
746
 *============================================================================*/
747
748
/* char_table1 */
749
32.2M
#define CHAR_TYPE_ASCII     (1 << 0) /* Except: ["\], [0x00-0x1F, 0x80-0xFF] */
750
490k
#define CHAR_TYPE_ASCII_SQ  (1 << 1) /* Except: ['\], [0x00-0x1F, 0x80-0xFF] */
751
4.72M
#define CHAR_TYPE_SPACE     (1 << 2) /* Whitespace: [ \t\n\r] */
752
4.87M
#define CHAR_TYPE_SPACE_EXT (1 << 3) /* Whitespace: [ \t\n\r\v\f], JSON5 */
753
4.49M
#define CHAR_TYPE_NUM       (1 << 4) /* Number: [.-+0-9] */
754
995k
#define CHAR_TYPE_COMMENT   (1 << 5) /* Comment: [/] */
755
756
/* char_table2 */
757
22.6k
#define CHAR_TYPE_EOL       (1 << 0) /* End of line: [\r\n] */
758
34.7k
#define CHAR_TYPE_EOL_EXT   (1 << 1) /* End of line: [\r\n], JSON5 */
759
25.5k
#define CHAR_TYPE_ID_START  (1 << 2) /* ID start: [_$A-Za-z\], U+0080+ */
760
28.1k
#define CHAR_TYPE_ID_NEXT   (1 << 3) /* ID next: [_$A-Za-z0-9\], U+0080+ */
761
216k
#define CHAR_TYPE_ID_ASCII  (1 << 4) /* ID next ASCII: [_$A-Za-z0-9] */
762
763
/* char_table3 */
764
241k
#define CHAR_TYPE_SIGN      (1 << 0) /* [-+] */
765
11.2M
#define CHAR_TYPE_DIGIT     (1 << 1) /* [0-9] */
766
3.44M
#define CHAR_TYPE_NONZERO   (1 << 2) /* [1-9] */
767
4.72M
#define CHAR_TYPE_EXP       (1 << 3) /* [eE] */
768
3.63M
#define CHAR_TYPE_DOT       (1 << 4) /* [.] */
769
770
static const u8 char_table1[256] = {
771
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
772
    0x00, 0x0C, 0x0C, 0x08, 0x08, 0x0C, 0x00, 0x00,
773
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
774
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
775
    0x0F, 0x03, 0x02, 0x03, 0x03, 0x03, 0x03, 0x01,
776
    0x03, 0x03, 0x03, 0x13, 0x03, 0x13, 0x13, 0x23,
777
    0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
778
    0x13, 0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
779
    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
780
    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
781
    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
782
    0x03, 0x03, 0x03, 0x03, 0x00, 0x03, 0x03, 0x03,
783
    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
784
    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
785
    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
786
    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
787
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
788
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
789
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
790
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
791
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
792
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
793
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
794
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
795
    0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
796
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
797
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
798
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
799
    0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
800
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
801
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
802
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
803
};
804
805
static const u8 char_table2[256] = {
806
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
807
    0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
808
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
809
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
810
    0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
811
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
812
    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
813
    0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
814
    0x00, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
815
    0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
816
    0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
817
    0x1C, 0x1C, 0x1C, 0x00, 0x0C, 0x00, 0x00, 0x1C,
818
    0x00, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
819
    0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
820
    0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
821
    0x1C, 0x1C, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00,
822
    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
823
    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
824
    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
825
    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
826
    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
827
    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
828
    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
829
    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
830
    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
831
    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
832
    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
833
    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
834
    0x0C, 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
835
    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
836
    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
837
    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C
838
};
839
840
static const u8 char_table3[256] = {
841
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
842
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
843
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
844
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
845
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
846
    0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x10, 0x00,
847
    0x02, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
848
    0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
849
    0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
850
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
851
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
852
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
853
    0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
854
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
855
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
856
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
857
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
858
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
859
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
860
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
861
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
862
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
863
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
864
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
865
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
866
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
867
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
868
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
869
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
870
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
871
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
872
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
873
};
874
875
/** Match a whitespace: [ \t\n\r]. */
876
4.72M
static_inline bool char_is_space(u8 c) {
877
4.72M
    return !!(char_table1[c] & CHAR_TYPE_SPACE);
878
4.72M
}
879
880
/** Match an extended whitespace: [ \t\n\r\\v\\f], JSON5 whitespace. */
881
3.88M
static_inline bool char_is_space_ext(u8 c) {
882
3.88M
    return !!(char_table1[c] & CHAR_TYPE_SPACE_EXT);
883
3.88M
}
884
885
/** Match a JSON number: [.-+0-9]. */
886
4.49M
static_inline bool char_is_num(u8 c) {
887
4.49M
    return !!(char_table1[c] & CHAR_TYPE_NUM);
888
4.49M
}
889
890
/** Match an ASCII character in string: ["\], [0x00-0x1F, 0x80-0xFF]. */
891
32.2M
static_inline bool char_is_ascii_skip(u8 c) {
892
32.2M
    return !!(char_table1[c] & CHAR_TYPE_ASCII);
893
32.2M
}
894
895
/** Match an ASCII character single-quoted: ['\], [0x00-0x1F, 0x80-0xFF]. */
896
490k
static_inline bool char_is_ascii_skip_sq(u8 c) {
897
490k
    return !!(char_table1[c] & CHAR_TYPE_ASCII_SQ);
898
490k
}
899
900
/** Match a trivia character: extended whitespace or comment. */
901
995k
static_inline bool char_is_trivia(u8 c) {
902
995k
    return !!(char_table1[c] & (CHAR_TYPE_SPACE_EXT | CHAR_TYPE_COMMENT));
903
995k
}
904
905
/** Match a line end character: [\r\n]. */
906
22.6k
static_inline bool char_is_eol(u8 c) {
907
22.6k
    return !!(char_table2[c] & CHAR_TYPE_EOL);
908
22.6k
}
909
910
/** Match an extended line end character: [\r\n], JSON5 line terminator. */
911
34.7k
static_inline bool char_is_eol_ext(u8 c) {
912
34.7k
    return !!(char_table2[c] & CHAR_TYPE_EOL_EXT);
913
34.7k
}
914
915
/** Match an identifier name start: [_$A-Za-z\], U+0080+. */
916
25.5k
static_inline bool char_is_id_start(u8 c) {
917
25.5k
    return !!(char_table2[c] & CHAR_TYPE_ID_START);
918
25.5k
}
919
920
/** Match an identifier name next: [_$A-Za-z0-9\], U+0080+. */
921
28.1k
static_inline bool char_is_id_next(u8 c) {
922
28.1k
    return !!(char_table2[c] & CHAR_TYPE_ID_NEXT);
923
28.1k
}
924
925
/** Match an identifier name ASCII: [_$A-Za-z0-9]. */
926
216k
static_inline bool char_is_id_ascii(u8 c) {
927
216k
    return !!(char_table2[c] & CHAR_TYPE_ID_ASCII);
928
216k
}
929
930
/** Match a sign: [+-] */
931
241k
static_inline bool char_is_sign(u8 d) {
932
241k
    return !!(char_table3[d] & CHAR_TYPE_SIGN);
933
241k
}
934
935
/** Match a non-zero digit: [1-9] */
936
3.44M
static_inline bool char_is_nonzero(u8 d) {
937
3.44M
    return !!(char_table3[d] & CHAR_TYPE_NONZERO);
938
3.44M
}
939
940
/** Match a digit: [0-9] */
941
10.9M
static_inline bool char_is_digit(u8 d) {
942
10.9M
    return !!(char_table3[d] & CHAR_TYPE_DIGIT);
943
10.9M
}
944
945
/** Match an exponent character: [eE]. */
946
1.09M
static_inline bool char_is_exp(u8 d) {
947
1.09M
    return !!(char_table3[d] & CHAR_TYPE_EXP);
948
1.09M
}
949
950
/** Match a floating point indicator: [.eE]. */
951
3.31M
static_inline bool char_is_fp(u8 d) {
952
3.31M
    return !!(char_table3[d] & (CHAR_TYPE_DOT | CHAR_TYPE_EXP));
953
3.31M
}
954
955
/** Match a digit or floating point indicator: [0-9.eE]. */
956
315k
static_inline bool char_is_digit_or_fp(u8 d) {
957
315k
    return !!(char_table3[d] & (CHAR_TYPE_DIGIT | CHAR_TYPE_DOT |
958
315k
                                CHAR_TYPE_EXP));
959
315k
}
960
961
/** Match a JSON container: `{` or `[`. */
962
266k
static_inline bool char_is_ctn(u8 c) {
963
266k
    return (c & 0xDF) == 0x5B; /* '[': 0x5B, '{': 0x7B */
964
266k
}
965
966
/** Convert ASCII letter to lowercase; valid only for [A-Za-z]. */
967
86.0k
static_inline u8 char_to_lower(u8 c) {
968
86.0k
    return c | 0x20;
969
86.0k
}
970
971
/** Match UTF-8 byte order mask. */
972
8.58k
static_inline bool is_utf8_bom(const u8 *cur) {
973
8.58k
    return byte_load_3(cur) == byte_load_3("\xEF\xBB\xBF");
974
8.58k
}
975
976
/** Match UTF-16 byte order mask. */
977
7.78k
static_inline bool is_utf16_bom(const u8 *cur) {
978
7.78k
    return byte_load_2(cur) == byte_load_2("\xFE\xFF") ||
979
7.75k
           byte_load_2(cur) == byte_load_2("\xFF\xFE");
980
7.78k
}
981
982
/** Match UTF-32 byte order mask, need length check to avoid zero padding. */
983
3.22k
static_inline bool is_utf32_bom(const u8 *cur) {
984
3.22k
    return byte_load_4(cur) == byte_load_4("\x00\x00\xFE\xFF") ||
985
3.20k
           byte_load_4(cur) == byte_load_4("\xFF\xFE\x00\x00");
986
3.22k
}
987
988
/** Get the extended line end length. Used with `char_is_eol_ext`. */
989
1.90k
static_inline usize ext_eol_len(const u8 *cur) {
990
1.90k
    if (cur[0] < 0x80) return 1;
991
899
    if (cur[1] == 0x80 && (cur[2] == 0xA8 || cur[2] == 0xA9)) return 3;
992
493
    return 0;
993
899
}
994
995
/** Get the extended whitespace length. Used with `char_is_space_ext`. */
996
2.01M
static_inline usize ext_space_len(const u8 *cur) {
997
2.01M
    if (cur[0] < 0x80) {
998
2.00M
        return 1;
999
2.00M
    } else if (byte_load_2(cur) == byte_load_2("\xC2\xA0")) {
1000
934
        return 2;
1001
15.3k
    } else if (byte_load_2(cur) == byte_load_2("\xE2\x80")) {
1002
7.57k
        if (cur[2] >= 0x80 && cur[2] <= 0x8A) return 3;
1003
5.22k
        if (cur[2] == 0xA8 || cur[2] == 0xA9 || cur[2] == 0xAF) return 3;
1004
7.76k
    } else {
1005
7.76k
        u32 uni = byte_load_3(cur);
1006
7.76k
        if (uni == byte_load_3("\xE1\x9A\x80") ||
1007
6.42k
            uni == byte_load_3("\xE2\x81\x9F") ||
1008
4.48k
            uni == byte_load_3("\xE3\x80\x80") ||
1009
4.68k
            uni == byte_load_3("\xEF\xBB\xBF")) return 3;
1010
7.76k
    }
1011
3.84k
    return 0;
1012
2.01M
}
1013
1014
1015
1016
/*==============================================================================
1017
 * MARK: - Hex Character Reader (Private)
1018
 * This function is used by JSON reader to read escaped characters.
1019
 *============================================================================*/
1020
1021
/**
1022
 This table is used to convert a 4-hex-character sequence to a number.
1023
 A valid hex character [0-9A-Fa-f] is mapped to its raw value [0x00, 0x0F];
1024
 an invalid hex character is mapped to [0xF0].
1025
 (generated with misc/make_tables.c)
1026
 */
1027
static const u8 hex_conv_table[256] = {
1028
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1029
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1030
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1031
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1032
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1033
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1034
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1035
    0x08, 0x09, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1036
    0xF0, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF0,
1037
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1038
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1039
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1040
    0xF0, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF0,
1041
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1042
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1043
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1044
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1045
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1046
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1047
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1048
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1049
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1050
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1051
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1052
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1053
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1054
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1055
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1056
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1057
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1058
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1059
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0
1060
};
1061
1062
/** Load 4 hex characters to `u16`, return true on valid input. */
1063
38.6k
static_inline bool hex_load_4(const u8 *src, u16 *dst) {
1064
38.6k
    u16 c0 = hex_conv_table[src[0]];
1065
38.6k
    u16 c1 = hex_conv_table[src[1]];
1066
38.6k
    u16 c2 = hex_conv_table[src[2]];
1067
38.6k
    u16 c3 = hex_conv_table[src[3]];
1068
38.6k
    u16 t0 = (u16)((c0 << 8) | c2);
1069
38.6k
    u16 t1 = (u16)((c1 << 8) | c3);
1070
38.6k
    *dst = (u16)((t0 << 4) | t1);
1071
38.6k
    return ((t0 | t1) & (u16)0xF0F0) == 0;
1072
38.6k
}
1073
1074
/** Load 2 hex characters to `u8`, return true on valid input. */
1075
2.96k
static_inline bool hex_load_2(const u8 *src, u8 *dst) {
1076
2.96k
    u8 c0 = hex_conv_table[src[0]];
1077
2.96k
    u8 c1 = hex_conv_table[src[1]];
1078
2.96k
    *dst = (u8)((c0 << 4) | c1);
1079
2.96k
    return ((c0 | c1) & 0xF0) == 0;
1080
2.96k
}
1081
1082
/** Match a hexadecimal numeric character: [0-9a-fA-F]. */
1083
780
static_inline bool char_is_hex(u8 c) {
1084
780
    return hex_conv_table[c] != 0xF0;
1085
780
}
1086
1087
1088
1089
/*==============================================================================
1090
 * MARK: - UTF8 Validation (Private)
1091
 * Each Unicode code point is encoded using 1 to 4 bytes in UTF-8.
1092
 * Validation is performed using a 4-byte mask and pattern-based approach,
1093
 * which requires the input data to be padded with four zero bytes at the end.
1094
 *============================================================================*/
1095
1096
/* Macro for concatenating four u8 into a u32 and keeping the byte order. */
1097
#if YYJSON_ENDIAN == YYJSON_LITTLE_ENDIAN
1098
#   define utf8_seq_def(name, a, b, c, d) \
1099
        static const u32 utf8_seq_##name = 0x##d##c##b##a##UL;
1100
20.9M
#   define utf8_seq(name) utf8_seq_##name
1101
#elif YYJSON_ENDIAN == YYJSON_BIG_ENDIAN
1102
#   define utf8_seq_def(name, a, b, c, d) \
1103
        static const u32 utf8_seq_##name = 0x##a##b##c##d##UL;
1104
#   define utf8_seq(name) utf8_seq_##name
1105
#else
1106
#   define utf8_seq_def(name, a, b, c, d) \
1107
        static const v32_uni utf8_uni_##name = {{ 0x##a, 0x##b, 0x##c, 0x##d }};
1108
#   define utf8_seq(name) utf8_uni_##name.u
1109
#endif
1110
1111
/*
1112
 1-byte sequence (U+0000 to U+007F)
1113
 bit min        [.......0] (U+0000)
1114
 bit max        [.1111111] (U+007F)
1115
 bit mask       [x.......] (80)
1116
 bit pattern    [0.......] (00)
1117
 */
1118
utf8_seq_def(b1_mask, 80, 00, 00, 00)
1119
utf8_seq_def(b1_patt, 00, 00, 00, 00)
1120
1.99M
#define is_utf8_seq1(uni) ( \
1121
1.99M
    ((uni & utf8_seq(b1_mask)) == utf8_seq(b1_patt)) )
1122
1123
/*
1124
 2-byte sequence (U+0080 to U+07FF)
1125
 bit min        [......10 ..000000] (U+0080)
1126
 bit max        [...11111 ..111111] (U+07FF)
1127
 bit mask       [xxx..... xx......] (E0 C0)
1128
 bit pattern    [110..... 10......] (C0 80)
1129
 bit require    [...xxxx. ........] (1E 00)
1130
 */
1131
utf8_seq_def(b2_mask, E0, C0, 00, 00)
1132
utf8_seq_def(b2_patt, C0, 80, 00, 00)
1133
utf8_seq_def(b2_requ, 1E, 00, 00, 00)
1134
3.44M
#define is_utf8_seq2(uni) ( \
1135
3.44M
    ((uni & utf8_seq(b2_mask)) == utf8_seq(b2_patt)) && \
1136
3.44M
    ((uni & utf8_seq(b2_requ))) )
1137
1138
/*
1139
 3-byte sequence (U+0800 to U+FFFF)
1140
 bit min        [........ ..100000 ..000000] (U+0800)
1141
 bit max        [....1111 ..111111 ..111111] (U+FFFF)
1142
 bit mask       [xxxx.... xx...... xx......] (F0 C0 C0)
1143
 bit pattern    [1110.... 10...... 10......] (E0 80 80)
1144
 bit require    [....xxxx ..x..... ........] (0F 20 00)
1145
1146
 3-byte invalid sequence, reserved for surrogate halves (U+D800 to U+DFFF)
1147
 bit min        [....1101 ..100000 ..000000] (U+D800)
1148
 bit max        [....1101 ..111111 ..111111] (U+DFFF)
1149
 bit mask       [....xxxx ..x..... ........] (0F 20 00)
1150
 bit pattern    [....1101 ..1..... ........] (0D 20 00)
1151
 */
1152
utf8_seq_def(b3_mask, F0, C0, C0, 00)
1153
utf8_seq_def(b3_patt, E0, 80, 80, 00)
1154
utf8_seq_def(b3_requ, 0F, 20, 00, 00)
1155
utf8_seq_def(b3_erro, 0D, 20, 00, 00)
1156
2.04M
#define is_utf8_seq3(uni) ( \
1157
2.04M
    ((uni & utf8_seq(b3_mask)) == utf8_seq(b3_patt)) && \
1158
2.04M
    ((tmp = (uni & utf8_seq(b3_requ)))) && \
1159
2.04M
    ((tmp != utf8_seq(b3_erro))) )
1160
1161
/*
1162
 4-byte sequence (U+10000 to U+10FFFF)
1163
 bit min        [........ ...10000 ..000000 ..000000] (U+10000)
1164
 bit max        [.....100 ..001111 ..111111 ..111111] (U+10FFFF)
1165
 bit mask       [xxxxx... xx...... xx...... xx......] (F8 C0 C0 C0)
1166
 bit pattern    [11110... 10...... 10...... 10......] (F0 80 80 80)
1167
 bit require    [.....xxx ..xx.... ........ ........] (07 30 00 00)
1168
 bit require 1  [.....x.. ........ ........ ........] (04 00 00 00)
1169
 bit require 2  [......xx ..xx.... ........ ........] (03 30 00 00)
1170
 */
1171
utf8_seq_def(b4_mask, F8, C0, C0, C0)
1172
utf8_seq_def(b4_patt, F0, 80, 80, 80)
1173
utf8_seq_def(b4_requ, 07, 30, 00, 00)
1174
utf8_seq_def(b4_req1, 04, 00, 00, 00)
1175
utf8_seq_def(b4_req2, 03, 30, 00, 00)
1176
2.05M
#define is_utf8_seq4(uni) ( \
1177
2.05M
    ((uni & utf8_seq(b4_mask)) == utf8_seq(b4_patt)) && \
1178
2.05M
    ((tmp = (uni & utf8_seq(b4_requ)))) && \
1179
2.05M
    ((tmp & utf8_seq(b4_req1)) == 0 || (tmp & utf8_seq(b4_req2)) == 0) )
1180
1181
1182
1183
/*==============================================================================
1184
 * MARK: - Power10 Lookup Table (Private)
1185
 * These data are used by the floating-point number reader and writer.
1186
 *============================================================================*/
1187
1188
#if !YYJSON_DISABLE_FAST_FP_CONV
1189
1190
/** Maximum pow10 exponent that can be represented exactly as a float64. */
1191
2.90M
#define F64_POW10_MAX_EXACT_EXP 22
1192
1193
#if YYJSON_DOUBLE_MATH_CORRECT
1194
/** Cached pow10 table. */
1195
static const f64 f64_pow10_table[F64_POW10_MAX_EXACT_EXP + 1] = {
1196
    1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12,
1197
    1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22
1198
};
1199
#endif
1200
1201
/** Maximum pow10 exponent that can be represented exactly as a uint64. */
1202
3.14M
#define U64_POW10_MAX_EXACT_EXP 19
1203
1204
/** Table: [ 10^0, ..., 10^19 ] (generated with misc/make_tables.c) */
1205
static const u64 u64_pow10_table[U64_POW10_MAX_EXACT_EXP + 1] = {
1206
    U64(0x00000000, 0x00000001), U64(0x00000000, 0x0000000A),
1207
    U64(0x00000000, 0x00000064), U64(0x00000000, 0x000003E8),
1208
    U64(0x00000000, 0x00002710), U64(0x00000000, 0x000186A0),
1209
    U64(0x00000000, 0x000F4240), U64(0x00000000, 0x00989680),
1210
    U64(0x00000000, 0x05F5E100), U64(0x00000000, 0x3B9ACA00),
1211
    U64(0x00000002, 0x540BE400), U64(0x00000017, 0x4876E800),
1212
    U64(0x000000E8, 0xD4A51000), U64(0x00000918, 0x4E72A000),
1213
    U64(0x00005AF3, 0x107A4000), U64(0x00038D7E, 0xA4C68000),
1214
    U64(0x002386F2, 0x6FC10000), U64(0x01634578, 0x5D8A0000),
1215
    U64(0x0DE0B6B3, 0xA7640000), U64(0x8AC72304, 0x89E80000)
1216
};
1217
1218
/** Minimum decimal exponent in pow10_sig_table. */
1219
4.44M
#define POW10_SIG_TABLE_MIN_EXP -343
1220
1221
/** Maximum decimal exponent in pow10_sig_table. */
1222
#define POW10_SIG_TABLE_MAX_EXP 324
1223
1224
/** Minimum exact decimal exponent in pow10_sig_table */
1225
#define POW10_SIG_TABLE_MIN_EXACT_EXP 0
1226
1227
/** Maximum exact decimal exponent in pow10_sig_table */
1228
#define POW10_SIG_TABLE_MAX_EXACT_EXP 55
1229
1230
/** Normalized significant 128 bits of pow10, not rounded up (size: 10.4KB).
1231
    This lookup table is used by both the double number reader and writer.
1232
    (generated with misc/make_tables.c) */
1233
static const u64 pow10_sig_table[] = {
1234
    U64(0xBF29DCAB, 0xA82FDEAE), U64(0x7432EE87, 0x3880FC33), /* ~= 10^-343 */
1235
    U64(0xEEF453D6, 0x923BD65A), U64(0x113FAA29, 0x06A13B3F), /* ~= 10^-342 */
1236
    U64(0x9558B466, 0x1B6565F8), U64(0x4AC7CA59, 0xA424C507), /* ~= 10^-341 */
1237
    U64(0xBAAEE17F, 0xA23EBF76), U64(0x5D79BCF0, 0x0D2DF649), /* ~= 10^-340 */
1238
    U64(0xE95A99DF, 0x8ACE6F53), U64(0xF4D82C2C, 0x107973DC), /* ~= 10^-339 */
1239
    U64(0x91D8A02B, 0xB6C10594), U64(0x79071B9B, 0x8A4BE869), /* ~= 10^-338 */
1240
    U64(0xB64EC836, 0xA47146F9), U64(0x9748E282, 0x6CDEE284), /* ~= 10^-337 */
1241
    U64(0xE3E27A44, 0x4D8D98B7), U64(0xFD1B1B23, 0x08169B25), /* ~= 10^-336 */
1242
    U64(0x8E6D8C6A, 0xB0787F72), U64(0xFE30F0F5, 0xE50E20F7), /* ~= 10^-335 */
1243
    U64(0xB208EF85, 0x5C969F4F), U64(0xBDBD2D33, 0x5E51A935), /* ~= 10^-334 */
1244
    U64(0xDE8B2B66, 0xB3BC4723), U64(0xAD2C7880, 0x35E61382), /* ~= 10^-333 */
1245
    U64(0x8B16FB20, 0x3055AC76), U64(0x4C3BCB50, 0x21AFCC31), /* ~= 10^-332 */
1246
    U64(0xADDCB9E8, 0x3C6B1793), U64(0xDF4ABE24, 0x2A1BBF3D), /* ~= 10^-331 */
1247
    U64(0xD953E862, 0x4B85DD78), U64(0xD71D6DAD, 0x34A2AF0D), /* ~= 10^-330 */
1248
    U64(0x87D4713D, 0x6F33AA6B), U64(0x8672648C, 0x40E5AD68), /* ~= 10^-329 */
1249
    U64(0xA9C98D8C, 0xCB009506), U64(0x680EFDAF, 0x511F18C2), /* ~= 10^-328 */
1250
    U64(0xD43BF0EF, 0xFDC0BA48), U64(0x0212BD1B, 0x2566DEF2), /* ~= 10^-327 */
1251
    U64(0x84A57695, 0xFE98746D), U64(0x014BB630, 0xF7604B57), /* ~= 10^-326 */
1252
    U64(0xA5CED43B, 0x7E3E9188), U64(0x419EA3BD, 0x35385E2D), /* ~= 10^-325 */
1253
    U64(0xCF42894A, 0x5DCE35EA), U64(0x52064CAC, 0x828675B9), /* ~= 10^-324 */
1254
    U64(0x818995CE, 0x7AA0E1B2), U64(0x7343EFEB, 0xD1940993), /* ~= 10^-323 */
1255
    U64(0xA1EBFB42, 0x19491A1F), U64(0x1014EBE6, 0xC5F90BF8), /* ~= 10^-322 */
1256
    U64(0xCA66FA12, 0x9F9B60A6), U64(0xD41A26E0, 0x77774EF6), /* ~= 10^-321 */
1257
    U64(0xFD00B897, 0x478238D0), U64(0x8920B098, 0x955522B4), /* ~= 10^-320 */
1258
    U64(0x9E20735E, 0x8CB16382), U64(0x55B46E5F, 0x5D5535B0), /* ~= 10^-319 */
1259
    U64(0xC5A89036, 0x2FDDBC62), U64(0xEB2189F7, 0x34AA831D), /* ~= 10^-318 */
1260
    U64(0xF712B443, 0xBBD52B7B), U64(0xA5E9EC75, 0x01D523E4), /* ~= 10^-317 */
1261
    U64(0x9A6BB0AA, 0x55653B2D), U64(0x47B233C9, 0x2125366E), /* ~= 10^-316 */
1262
    U64(0xC1069CD4, 0xEABE89F8), U64(0x999EC0BB, 0x696E840A), /* ~= 10^-315 */
1263
    U64(0xF148440A, 0x256E2C76), U64(0xC00670EA, 0x43CA250D), /* ~= 10^-314 */
1264
    U64(0x96CD2A86, 0x5764DBCA), U64(0x38040692, 0x6A5E5728), /* ~= 10^-313 */
1265
    U64(0xBC807527, 0xED3E12BC), U64(0xC6050837, 0x04F5ECF2), /* ~= 10^-312 */
1266
    U64(0xEBA09271, 0xE88D976B), U64(0xF7864A44, 0xC633682E), /* ~= 10^-311 */
1267
    U64(0x93445B87, 0x31587EA3), U64(0x7AB3EE6A, 0xFBE0211D), /* ~= 10^-310 */
1268
    U64(0xB8157268, 0xFDAE9E4C), U64(0x5960EA05, 0xBAD82964), /* ~= 10^-309 */
1269
    U64(0xE61ACF03, 0x3D1A45DF), U64(0x6FB92487, 0x298E33BD), /* ~= 10^-308 */
1270
    U64(0x8FD0C162, 0x06306BAB), U64(0xA5D3B6D4, 0x79F8E056), /* ~= 10^-307 */
1271
    U64(0xB3C4F1BA, 0x87BC8696), U64(0x8F48A489, 0x9877186C), /* ~= 10^-306 */
1272
    U64(0xE0B62E29, 0x29ABA83C), U64(0x331ACDAB, 0xFE94DE87), /* ~= 10^-305 */
1273
    U64(0x8C71DCD9, 0xBA0B4925), U64(0x9FF0C08B, 0x7F1D0B14), /* ~= 10^-304 */
1274
    U64(0xAF8E5410, 0x288E1B6F), U64(0x07ECF0AE, 0x5EE44DD9), /* ~= 10^-303 */
1275
    U64(0xDB71E914, 0x32B1A24A), U64(0xC9E82CD9, 0xF69D6150), /* ~= 10^-302 */
1276
    U64(0x892731AC, 0x9FAF056E), U64(0xBE311C08, 0x3A225CD2), /* ~= 10^-301 */
1277
    U64(0xAB70FE17, 0xC79AC6CA), U64(0x6DBD630A, 0x48AAF406), /* ~= 10^-300 */
1278
    U64(0xD64D3D9D, 0xB981787D), U64(0x092CBBCC, 0xDAD5B108), /* ~= 10^-299 */
1279
    U64(0x85F04682, 0x93F0EB4E), U64(0x25BBF560, 0x08C58EA5), /* ~= 10^-298 */
1280
    U64(0xA76C5823, 0x38ED2621), U64(0xAF2AF2B8, 0x0AF6F24E), /* ~= 10^-297 */
1281
    U64(0xD1476E2C, 0x07286FAA), U64(0x1AF5AF66, 0x0DB4AEE1), /* ~= 10^-296 */
1282
    U64(0x82CCA4DB, 0x847945CA), U64(0x50D98D9F, 0xC890ED4D), /* ~= 10^-295 */
1283
    U64(0xA37FCE12, 0x6597973C), U64(0xE50FF107, 0xBAB528A0), /* ~= 10^-294 */
1284
    U64(0xCC5FC196, 0xFEFD7D0C), U64(0x1E53ED49, 0xA96272C8), /* ~= 10^-293 */
1285
    U64(0xFF77B1FC, 0xBEBCDC4F), U64(0x25E8E89C, 0x13BB0F7A), /* ~= 10^-292 */
1286
    U64(0x9FAACF3D, 0xF73609B1), U64(0x77B19161, 0x8C54E9AC), /* ~= 10^-291 */
1287
    U64(0xC795830D, 0x75038C1D), U64(0xD59DF5B9, 0xEF6A2417), /* ~= 10^-290 */
1288
    U64(0xF97AE3D0, 0xD2446F25), U64(0x4B057328, 0x6B44AD1D), /* ~= 10^-289 */
1289
    U64(0x9BECCE62, 0x836AC577), U64(0x4EE367F9, 0x430AEC32), /* ~= 10^-288 */
1290
    U64(0xC2E801FB, 0x244576D5), U64(0x229C41F7, 0x93CDA73F), /* ~= 10^-287 */
1291
    U64(0xF3A20279, 0xED56D48A), U64(0x6B435275, 0x78C1110F), /* ~= 10^-286 */
1292
    U64(0x9845418C, 0x345644D6), U64(0x830A1389, 0x6B78AAA9), /* ~= 10^-285 */
1293
    U64(0xBE5691EF, 0x416BD60C), U64(0x23CC986B, 0xC656D553), /* ~= 10^-284 */
1294
    U64(0xEDEC366B, 0x11C6CB8F), U64(0x2CBFBE86, 0xB7EC8AA8), /* ~= 10^-283 */
1295
    U64(0x94B3A202, 0xEB1C3F39), U64(0x7BF7D714, 0x32F3D6A9), /* ~= 10^-282 */
1296
    U64(0xB9E08A83, 0xA5E34F07), U64(0xDAF5CCD9, 0x3FB0CC53), /* ~= 10^-281 */
1297
    U64(0xE858AD24, 0x8F5C22C9), U64(0xD1B3400F, 0x8F9CFF68), /* ~= 10^-280 */
1298
    U64(0x91376C36, 0xD99995BE), U64(0x23100809, 0xB9C21FA1), /* ~= 10^-279 */
1299
    U64(0xB5854744, 0x8FFFFB2D), U64(0xABD40A0C, 0x2832A78A), /* ~= 10^-278 */
1300
    U64(0xE2E69915, 0xB3FFF9F9), U64(0x16C90C8F, 0x323F516C), /* ~= 10^-277 */
1301
    U64(0x8DD01FAD, 0x907FFC3B), U64(0xAE3DA7D9, 0x7F6792E3), /* ~= 10^-276 */
1302
    U64(0xB1442798, 0xF49FFB4A), U64(0x99CD11CF, 0xDF41779C), /* ~= 10^-275 */
1303
    U64(0xDD95317F, 0x31C7FA1D), U64(0x40405643, 0xD711D583), /* ~= 10^-274 */
1304
    U64(0x8A7D3EEF, 0x7F1CFC52), U64(0x482835EA, 0x666B2572), /* ~= 10^-273 */
1305
    U64(0xAD1C8EAB, 0x5EE43B66), U64(0xDA324365, 0x0005EECF), /* ~= 10^-272 */
1306
    U64(0xD863B256, 0x369D4A40), U64(0x90BED43E, 0x40076A82), /* ~= 10^-271 */
1307
    U64(0x873E4F75, 0xE2224E68), U64(0x5A7744A6, 0xE804A291), /* ~= 10^-270 */
1308
    U64(0xA90DE353, 0x5AAAE202), U64(0x711515D0, 0xA205CB36), /* ~= 10^-269 */
1309
    U64(0xD3515C28, 0x31559A83), U64(0x0D5A5B44, 0xCA873E03), /* ~= 10^-268 */
1310
    U64(0x8412D999, 0x1ED58091), U64(0xE858790A, 0xFE9486C2), /* ~= 10^-267 */
1311
    U64(0xA5178FFF, 0x668AE0B6), U64(0x626E974D, 0xBE39A872), /* ~= 10^-266 */
1312
    U64(0xCE5D73FF, 0x402D98E3), U64(0xFB0A3D21, 0x2DC8128F), /* ~= 10^-265 */
1313
    U64(0x80FA687F, 0x881C7F8E), U64(0x7CE66634, 0xBC9D0B99), /* ~= 10^-264 */
1314
    U64(0xA139029F, 0x6A239F72), U64(0x1C1FFFC1, 0xEBC44E80), /* ~= 10^-263 */
1315
    U64(0xC9874347, 0x44AC874E), U64(0xA327FFB2, 0x66B56220), /* ~= 10^-262 */
1316
    U64(0xFBE91419, 0x15D7A922), U64(0x4BF1FF9F, 0x0062BAA8), /* ~= 10^-261 */
1317
    U64(0x9D71AC8F, 0xADA6C9B5), U64(0x6F773FC3, 0x603DB4A9), /* ~= 10^-260 */
1318
    U64(0xC4CE17B3, 0x99107C22), U64(0xCB550FB4, 0x384D21D3), /* ~= 10^-259 */
1319
    U64(0xF6019DA0, 0x7F549B2B), U64(0x7E2A53A1, 0x46606A48), /* ~= 10^-258 */
1320
    U64(0x99C10284, 0x4F94E0FB), U64(0x2EDA7444, 0xCBFC426D), /* ~= 10^-257 */
1321
    U64(0xC0314325, 0x637A1939), U64(0xFA911155, 0xFEFB5308), /* ~= 10^-256 */
1322
    U64(0xF03D93EE, 0xBC589F88), U64(0x793555AB, 0x7EBA27CA), /* ~= 10^-255 */
1323
    U64(0x96267C75, 0x35B763B5), U64(0x4BC1558B, 0x2F3458DE), /* ~= 10^-254 */
1324
    U64(0xBBB01B92, 0x83253CA2), U64(0x9EB1AAED, 0xFB016F16), /* ~= 10^-253 */
1325
    U64(0xEA9C2277, 0x23EE8BCB), U64(0x465E15A9, 0x79C1CADC), /* ~= 10^-252 */
1326
    U64(0x92A1958A, 0x7675175F), U64(0x0BFACD89, 0xEC191EC9), /* ~= 10^-251 */
1327
    U64(0xB749FAED, 0x14125D36), U64(0xCEF980EC, 0x671F667B), /* ~= 10^-250 */
1328
    U64(0xE51C79A8, 0x5916F484), U64(0x82B7E127, 0x80E7401A), /* ~= 10^-249 */
1329
    U64(0x8F31CC09, 0x37AE58D2), U64(0xD1B2ECB8, 0xB0908810), /* ~= 10^-248 */
1330
    U64(0xB2FE3F0B, 0x8599EF07), U64(0x861FA7E6, 0xDCB4AA15), /* ~= 10^-247 */
1331
    U64(0xDFBDCECE, 0x67006AC9), U64(0x67A791E0, 0x93E1D49A), /* ~= 10^-246 */
1332
    U64(0x8BD6A141, 0x006042BD), U64(0xE0C8BB2C, 0x5C6D24E0), /* ~= 10^-245 */
1333
    U64(0xAECC4991, 0x4078536D), U64(0x58FAE9F7, 0x73886E18), /* ~= 10^-244 */
1334
    U64(0xDA7F5BF5, 0x90966848), U64(0xAF39A475, 0x506A899E), /* ~= 10^-243 */
1335
    U64(0x888F9979, 0x7A5E012D), U64(0x6D8406C9, 0x52429603), /* ~= 10^-242 */
1336
    U64(0xAAB37FD7, 0xD8F58178), U64(0xC8E5087B, 0xA6D33B83), /* ~= 10^-241 */
1337
    U64(0xD5605FCD, 0xCF32E1D6), U64(0xFB1E4A9A, 0x90880A64), /* ~= 10^-240 */
1338
    U64(0x855C3BE0, 0xA17FCD26), U64(0x5CF2EEA0, 0x9A55067F), /* ~= 10^-239 */
1339
    U64(0xA6B34AD8, 0xC9DFC06F), U64(0xF42FAA48, 0xC0EA481E), /* ~= 10^-238 */
1340
    U64(0xD0601D8E, 0xFC57B08B), U64(0xF13B94DA, 0xF124DA26), /* ~= 10^-237 */
1341
    U64(0x823C1279, 0x5DB6CE57), U64(0x76C53D08, 0xD6B70858), /* ~= 10^-236 */
1342
    U64(0xA2CB1717, 0xB52481ED), U64(0x54768C4B, 0x0C64CA6E), /* ~= 10^-235 */
1343
    U64(0xCB7DDCDD, 0xA26DA268), U64(0xA9942F5D, 0xCF7DFD09), /* ~= 10^-234 */
1344
    U64(0xFE5D5415, 0x0B090B02), U64(0xD3F93B35, 0x435D7C4C), /* ~= 10^-233 */
1345
    U64(0x9EFA548D, 0x26E5A6E1), U64(0xC47BC501, 0x4A1A6DAF), /* ~= 10^-232 */
1346
    U64(0xC6B8E9B0, 0x709F109A), U64(0x359AB641, 0x9CA1091B), /* ~= 10^-231 */
1347
    U64(0xF867241C, 0x8CC6D4C0), U64(0xC30163D2, 0x03C94B62), /* ~= 10^-230 */
1348
    U64(0x9B407691, 0xD7FC44F8), U64(0x79E0DE63, 0x425DCF1D), /* ~= 10^-229 */
1349
    U64(0xC2109436, 0x4DFB5636), U64(0x985915FC, 0x12F542E4), /* ~= 10^-228 */
1350
    U64(0xF294B943, 0xE17A2BC4), U64(0x3E6F5B7B, 0x17B2939D), /* ~= 10^-227 */
1351
    U64(0x979CF3CA, 0x6CEC5B5A), U64(0xA705992C, 0xEECF9C42), /* ~= 10^-226 */
1352
    U64(0xBD8430BD, 0x08277231), U64(0x50C6FF78, 0x2A838353), /* ~= 10^-225 */
1353
    U64(0xECE53CEC, 0x4A314EBD), U64(0xA4F8BF56, 0x35246428), /* ~= 10^-224 */
1354
    U64(0x940F4613, 0xAE5ED136), U64(0x871B7795, 0xE136BE99), /* ~= 10^-223 */
1355
    U64(0xB9131798, 0x99F68584), U64(0x28E2557B, 0x59846E3F), /* ~= 10^-222 */
1356
    U64(0xE757DD7E, 0xC07426E5), U64(0x331AEADA, 0x2FE589CF), /* ~= 10^-221 */
1357
    U64(0x9096EA6F, 0x3848984F), U64(0x3FF0D2C8, 0x5DEF7621), /* ~= 10^-220 */
1358
    U64(0xB4BCA50B, 0x065ABE63), U64(0x0FED077A, 0x756B53A9), /* ~= 10^-219 */
1359
    U64(0xE1EBCE4D, 0xC7F16DFB), U64(0xD3E84959, 0x12C62894), /* ~= 10^-218 */
1360
    U64(0x8D3360F0, 0x9CF6E4BD), U64(0x64712DD7, 0xABBBD95C), /* ~= 10^-217 */
1361
    U64(0xB080392C, 0xC4349DEC), U64(0xBD8D794D, 0x96AACFB3), /* ~= 10^-216 */
1362
    U64(0xDCA04777, 0xF541C567), U64(0xECF0D7A0, 0xFC5583A0), /* ~= 10^-215 */
1363
    U64(0x89E42CAA, 0xF9491B60), U64(0xF41686C4, 0x9DB57244), /* ~= 10^-214 */
1364
    U64(0xAC5D37D5, 0xB79B6239), U64(0x311C2875, 0xC522CED5), /* ~= 10^-213 */
1365
    U64(0xD77485CB, 0x25823AC7), U64(0x7D633293, 0x366B828B), /* ~= 10^-212 */
1366
    U64(0x86A8D39E, 0xF77164BC), U64(0xAE5DFF9C, 0x02033197), /* ~= 10^-211 */
1367
    U64(0xA8530886, 0xB54DBDEB), U64(0xD9F57F83, 0x0283FDFC), /* ~= 10^-210 */
1368
    U64(0xD267CAA8, 0x62A12D66), U64(0xD072DF63, 0xC324FD7B), /* ~= 10^-209 */
1369
    U64(0x8380DEA9, 0x3DA4BC60), U64(0x4247CB9E, 0x59F71E6D), /* ~= 10^-208 */
1370
    U64(0xA4611653, 0x8D0DEB78), U64(0x52D9BE85, 0xF074E608), /* ~= 10^-207 */
1371
    U64(0xCD795BE8, 0x70516656), U64(0x67902E27, 0x6C921F8B), /* ~= 10^-206 */
1372
    U64(0x806BD971, 0x4632DFF6), U64(0x00BA1CD8, 0xA3DB53B6), /* ~= 10^-205 */
1373
    U64(0xA086CFCD, 0x97BF97F3), U64(0x80E8A40E, 0xCCD228A4), /* ~= 10^-204 */
1374
    U64(0xC8A883C0, 0xFDAF7DF0), U64(0x6122CD12, 0x8006B2CD), /* ~= 10^-203 */
1375
    U64(0xFAD2A4B1, 0x3D1B5D6C), U64(0x796B8057, 0x20085F81), /* ~= 10^-202 */
1376
    U64(0x9CC3A6EE, 0xC6311A63), U64(0xCBE33036, 0x74053BB0), /* ~= 10^-201 */
1377
    U64(0xC3F490AA, 0x77BD60FC), U64(0xBEDBFC44, 0x11068A9C), /* ~= 10^-200 */
1378
    U64(0xF4F1B4D5, 0x15ACB93B), U64(0xEE92FB55, 0x15482D44), /* ~= 10^-199 */
1379
    U64(0x99171105, 0x2D8BF3C5), U64(0x751BDD15, 0x2D4D1C4A), /* ~= 10^-198 */
1380
    U64(0xBF5CD546, 0x78EEF0B6), U64(0xD262D45A, 0x78A0635D), /* ~= 10^-197 */
1381
    U64(0xEF340A98, 0x172AACE4), U64(0x86FB8971, 0x16C87C34), /* ~= 10^-196 */
1382
    U64(0x9580869F, 0x0E7AAC0E), U64(0xD45D35E6, 0xAE3D4DA0), /* ~= 10^-195 */
1383
    U64(0xBAE0A846, 0xD2195712), U64(0x89748360, 0x59CCA109), /* ~= 10^-194 */
1384
    U64(0xE998D258, 0x869FACD7), U64(0x2BD1A438, 0x703FC94B), /* ~= 10^-193 */
1385
    U64(0x91FF8377, 0x5423CC06), U64(0x7B6306A3, 0x4627DDCF), /* ~= 10^-192 */
1386
    U64(0xB67F6455, 0x292CBF08), U64(0x1A3BC84C, 0x17B1D542), /* ~= 10^-191 */
1387
    U64(0xE41F3D6A, 0x7377EECA), U64(0x20CABA5F, 0x1D9E4A93), /* ~= 10^-190 */
1388
    U64(0x8E938662, 0x882AF53E), U64(0x547EB47B, 0x7282EE9C), /* ~= 10^-189 */
1389
    U64(0xB23867FB, 0x2A35B28D), U64(0xE99E619A, 0x4F23AA43), /* ~= 10^-188 */
1390
    U64(0xDEC681F9, 0xF4C31F31), U64(0x6405FA00, 0xE2EC94D4), /* ~= 10^-187 */
1391
    U64(0x8B3C113C, 0x38F9F37E), U64(0xDE83BC40, 0x8DD3DD04), /* ~= 10^-186 */
1392
    U64(0xAE0B158B, 0x4738705E), U64(0x9624AB50, 0xB148D445), /* ~= 10^-185 */
1393
    U64(0xD98DDAEE, 0x19068C76), U64(0x3BADD624, 0xDD9B0957), /* ~= 10^-184 */
1394
    U64(0x87F8A8D4, 0xCFA417C9), U64(0xE54CA5D7, 0x0A80E5D6), /* ~= 10^-183 */
1395
    U64(0xA9F6D30A, 0x038D1DBC), U64(0x5E9FCF4C, 0xCD211F4C), /* ~= 10^-182 */
1396
    U64(0xD47487CC, 0x8470652B), U64(0x7647C320, 0x0069671F), /* ~= 10^-181 */
1397
    U64(0x84C8D4DF, 0xD2C63F3B), U64(0x29ECD9F4, 0x0041E073), /* ~= 10^-180 */
1398
    U64(0xA5FB0A17, 0xC777CF09), U64(0xF4681071, 0x00525890), /* ~= 10^-179 */
1399
    U64(0xCF79CC9D, 0xB955C2CC), U64(0x7182148D, 0x4066EEB4), /* ~= 10^-178 */
1400
    U64(0x81AC1FE2, 0x93D599BF), U64(0xC6F14CD8, 0x48405530), /* ~= 10^-177 */
1401
    U64(0xA21727DB, 0x38CB002F), U64(0xB8ADA00E, 0x5A506A7C), /* ~= 10^-176 */
1402
    U64(0xCA9CF1D2, 0x06FDC03B), U64(0xA6D90811, 0xF0E4851C), /* ~= 10^-175 */
1403
    U64(0xFD442E46, 0x88BD304A), U64(0x908F4A16, 0x6D1DA663), /* ~= 10^-174 */
1404
    U64(0x9E4A9CEC, 0x15763E2E), U64(0x9A598E4E, 0x043287FE), /* ~= 10^-173 */
1405
    U64(0xC5DD4427, 0x1AD3CDBA), U64(0x40EFF1E1, 0x853F29FD), /* ~= 10^-172 */
1406
    U64(0xF7549530, 0xE188C128), U64(0xD12BEE59, 0xE68EF47C), /* ~= 10^-171 */
1407
    U64(0x9A94DD3E, 0x8CF578B9), U64(0x82BB74F8, 0x301958CE), /* ~= 10^-170 */
1408
    U64(0xC13A148E, 0x3032D6E7), U64(0xE36A5236, 0x3C1FAF01), /* ~= 10^-169 */
1409
    U64(0xF18899B1, 0xBC3F8CA1), U64(0xDC44E6C3, 0xCB279AC1), /* ~= 10^-168 */
1410
    U64(0x96F5600F, 0x15A7B7E5), U64(0x29AB103A, 0x5EF8C0B9), /* ~= 10^-167 */
1411
    U64(0xBCB2B812, 0xDB11A5DE), U64(0x7415D448, 0xF6B6F0E7), /* ~= 10^-166 */
1412
    U64(0xEBDF6617, 0x91D60F56), U64(0x111B495B, 0x3464AD21), /* ~= 10^-165 */
1413
    U64(0x936B9FCE, 0xBB25C995), U64(0xCAB10DD9, 0x00BEEC34), /* ~= 10^-164 */
1414
    U64(0xB84687C2, 0x69EF3BFB), U64(0x3D5D514F, 0x40EEA742), /* ~= 10^-163 */
1415
    U64(0xE65829B3, 0x046B0AFA), U64(0x0CB4A5A3, 0x112A5112), /* ~= 10^-162 */
1416
    U64(0x8FF71A0F, 0xE2C2E6DC), U64(0x47F0E785, 0xEABA72AB), /* ~= 10^-161 */
1417
    U64(0xB3F4E093, 0xDB73A093), U64(0x59ED2167, 0x65690F56), /* ~= 10^-160 */
1418
    U64(0xE0F218B8, 0xD25088B8), U64(0x306869C1, 0x3EC3532C), /* ~= 10^-159 */
1419
    U64(0x8C974F73, 0x83725573), U64(0x1E414218, 0xC73A13FB), /* ~= 10^-158 */
1420
    U64(0xAFBD2350, 0x644EEACF), U64(0xE5D1929E, 0xF90898FA), /* ~= 10^-157 */
1421
    U64(0xDBAC6C24, 0x7D62A583), U64(0xDF45F746, 0xB74ABF39), /* ~= 10^-156 */
1422
    U64(0x894BC396, 0xCE5DA772), U64(0x6B8BBA8C, 0x328EB783), /* ~= 10^-155 */
1423
    U64(0xAB9EB47C, 0x81F5114F), U64(0x066EA92F, 0x3F326564), /* ~= 10^-154 */
1424
    U64(0xD686619B, 0xA27255A2), U64(0xC80A537B, 0x0EFEFEBD), /* ~= 10^-153 */
1425
    U64(0x8613FD01, 0x45877585), U64(0xBD06742C, 0xE95F5F36), /* ~= 10^-152 */
1426
    U64(0xA798FC41, 0x96E952E7), U64(0x2C481138, 0x23B73704), /* ~= 10^-151 */
1427
    U64(0xD17F3B51, 0xFCA3A7A0), U64(0xF75A1586, 0x2CA504C5), /* ~= 10^-150 */
1428
    U64(0x82EF8513, 0x3DE648C4), U64(0x9A984D73, 0xDBE722FB), /* ~= 10^-149 */
1429
    U64(0xA3AB6658, 0x0D5FDAF5), U64(0xC13E60D0, 0xD2E0EBBA), /* ~= 10^-148 */
1430
    U64(0xCC963FEE, 0x10B7D1B3), U64(0x318DF905, 0x079926A8), /* ~= 10^-147 */
1431
    U64(0xFFBBCFE9, 0x94E5C61F), U64(0xFDF17746, 0x497F7052), /* ~= 10^-146 */
1432
    U64(0x9FD561F1, 0xFD0F9BD3), U64(0xFEB6EA8B, 0xEDEFA633), /* ~= 10^-145 */
1433
    U64(0xC7CABA6E, 0x7C5382C8), U64(0xFE64A52E, 0xE96B8FC0), /* ~= 10^-144 */
1434
    U64(0xF9BD690A, 0x1B68637B), U64(0x3DFDCE7A, 0xA3C673B0), /* ~= 10^-143 */
1435
    U64(0x9C1661A6, 0x51213E2D), U64(0x06BEA10C, 0xA65C084E), /* ~= 10^-142 */
1436
    U64(0xC31BFA0F, 0xE5698DB8), U64(0x486E494F, 0xCFF30A62), /* ~= 10^-141 */
1437
    U64(0xF3E2F893, 0xDEC3F126), U64(0x5A89DBA3, 0xC3EFCCFA), /* ~= 10^-140 */
1438
    U64(0x986DDB5C, 0x6B3A76B7), U64(0xF8962946, 0x5A75E01C), /* ~= 10^-139 */
1439
    U64(0xBE895233, 0x86091465), U64(0xF6BBB397, 0xF1135823), /* ~= 10^-138 */
1440
    U64(0xEE2BA6C0, 0x678B597F), U64(0x746AA07D, 0xED582E2C), /* ~= 10^-137 */
1441
    U64(0x94DB4838, 0x40B717EF), U64(0xA8C2A44E, 0xB4571CDC), /* ~= 10^-136 */
1442
    U64(0xBA121A46, 0x50E4DDEB), U64(0x92F34D62, 0x616CE413), /* ~= 10^-135 */
1443
    U64(0xE896A0D7, 0xE51E1566), U64(0x77B020BA, 0xF9C81D17), /* ~= 10^-134 */
1444
    U64(0x915E2486, 0xEF32CD60), U64(0x0ACE1474, 0xDC1D122E), /* ~= 10^-133 */
1445
    U64(0xB5B5ADA8, 0xAAFF80B8), U64(0x0D819992, 0x132456BA), /* ~= 10^-132 */
1446
    U64(0xE3231912, 0xD5BF60E6), U64(0x10E1FFF6, 0x97ED6C69), /* ~= 10^-131 */
1447
    U64(0x8DF5EFAB, 0xC5979C8F), U64(0xCA8D3FFA, 0x1EF463C1), /* ~= 10^-130 */
1448
    U64(0xB1736B96, 0xB6FD83B3), U64(0xBD308FF8, 0xA6B17CB2), /* ~= 10^-129 */
1449
    U64(0xDDD0467C, 0x64BCE4A0), U64(0xAC7CB3F6, 0xD05DDBDE), /* ~= 10^-128 */
1450
    U64(0x8AA22C0D, 0xBEF60EE4), U64(0x6BCDF07A, 0x423AA96B), /* ~= 10^-127 */
1451
    U64(0xAD4AB711, 0x2EB3929D), U64(0x86C16C98, 0xD2C953C6), /* ~= 10^-126 */
1452
    U64(0xD89D64D5, 0x7A607744), U64(0xE871C7BF, 0x077BA8B7), /* ~= 10^-125 */
1453
    U64(0x87625F05, 0x6C7C4A8B), U64(0x11471CD7, 0x64AD4972), /* ~= 10^-124 */
1454
    U64(0xA93AF6C6, 0xC79B5D2D), U64(0xD598E40D, 0x3DD89BCF), /* ~= 10^-123 */
1455
    U64(0xD389B478, 0x79823479), U64(0x4AFF1D10, 0x8D4EC2C3), /* ~= 10^-122 */
1456
    U64(0x843610CB, 0x4BF160CB), U64(0xCEDF722A, 0x585139BA), /* ~= 10^-121 */
1457
    U64(0xA54394FE, 0x1EEDB8FE), U64(0xC2974EB4, 0xEE658828), /* ~= 10^-120 */
1458
    U64(0xCE947A3D, 0xA6A9273E), U64(0x733D2262, 0x29FEEA32), /* ~= 10^-119 */
1459
    U64(0x811CCC66, 0x8829B887), U64(0x0806357D, 0x5A3F525F), /* ~= 10^-118 */
1460
    U64(0xA163FF80, 0x2A3426A8), U64(0xCA07C2DC, 0xB0CF26F7), /* ~= 10^-117 */
1461
    U64(0xC9BCFF60, 0x34C13052), U64(0xFC89B393, 0xDD02F0B5), /* ~= 10^-116 */
1462
    U64(0xFC2C3F38, 0x41F17C67), U64(0xBBAC2078, 0xD443ACE2), /* ~= 10^-115 */
1463
    U64(0x9D9BA783, 0x2936EDC0), U64(0xD54B944B, 0x84AA4C0D), /* ~= 10^-114 */
1464
    U64(0xC5029163, 0xF384A931), U64(0x0A9E795E, 0x65D4DF11), /* ~= 10^-113 */
1465
    U64(0xF64335BC, 0xF065D37D), U64(0x4D4617B5, 0xFF4A16D5), /* ~= 10^-112 */
1466
    U64(0x99EA0196, 0x163FA42E), U64(0x504BCED1, 0xBF8E4E45), /* ~= 10^-111 */
1467
    U64(0xC06481FB, 0x9BCF8D39), U64(0xE45EC286, 0x2F71E1D6), /* ~= 10^-110 */
1468
    U64(0xF07DA27A, 0x82C37088), U64(0x5D767327, 0xBB4E5A4C), /* ~= 10^-109 */
1469
    U64(0x964E858C, 0x91BA2655), U64(0x3A6A07F8, 0xD510F86F), /* ~= 10^-108 */
1470
    U64(0xBBE226EF, 0xB628AFEA), U64(0x890489F7, 0x0A55368B), /* ~= 10^-107 */
1471
    U64(0xEADAB0AB, 0xA3B2DBE5), U64(0x2B45AC74, 0xCCEA842E), /* ~= 10^-106 */
1472
    U64(0x92C8AE6B, 0x464FC96F), U64(0x3B0B8BC9, 0x0012929D), /* ~= 10^-105 */
1473
    U64(0xB77ADA06, 0x17E3BBCB), U64(0x09CE6EBB, 0x40173744), /* ~= 10^-104 */
1474
    U64(0xE5599087, 0x9DDCAABD), U64(0xCC420A6A, 0x101D0515), /* ~= 10^-103 */
1475
    U64(0x8F57FA54, 0xC2A9EAB6), U64(0x9FA94682, 0x4A12232D), /* ~= 10^-102 */
1476
    U64(0xB32DF8E9, 0xF3546564), U64(0x47939822, 0xDC96ABF9), /* ~= 10^-101 */
1477
    U64(0xDFF97724, 0x70297EBD), U64(0x59787E2B, 0x93BC56F7), /* ~= 10^-100 */
1478
    U64(0x8BFBEA76, 0xC619EF36), U64(0x57EB4EDB, 0x3C55B65A), /* ~= 10^-99 */
1479
    U64(0xAEFAE514, 0x77A06B03), U64(0xEDE62292, 0x0B6B23F1), /* ~= 10^-98 */
1480
    U64(0xDAB99E59, 0x958885C4), U64(0xE95FAB36, 0x8E45ECED), /* ~= 10^-97 */
1481
    U64(0x88B402F7, 0xFD75539B), U64(0x11DBCB02, 0x18EBB414), /* ~= 10^-96 */
1482
    U64(0xAAE103B5, 0xFCD2A881), U64(0xD652BDC2, 0x9F26A119), /* ~= 10^-95 */
1483
    U64(0xD59944A3, 0x7C0752A2), U64(0x4BE76D33, 0x46F0495F), /* ~= 10^-94 */
1484
    U64(0x857FCAE6, 0x2D8493A5), U64(0x6F70A440, 0x0C562DDB), /* ~= 10^-93 */
1485
    U64(0xA6DFBD9F, 0xB8E5B88E), U64(0xCB4CCD50, 0x0F6BB952), /* ~= 10^-92 */
1486
    U64(0xD097AD07, 0xA71F26B2), U64(0x7E2000A4, 0x1346A7A7), /* ~= 10^-91 */
1487
    U64(0x825ECC24, 0xC873782F), U64(0x8ED40066, 0x8C0C28C8), /* ~= 10^-90 */
1488
    U64(0xA2F67F2D, 0xFA90563B), U64(0x72890080, 0x2F0F32FA), /* ~= 10^-89 */
1489
    U64(0xCBB41EF9, 0x79346BCA), U64(0x4F2B40A0, 0x3AD2FFB9), /* ~= 10^-88 */
1490
    U64(0xFEA126B7, 0xD78186BC), U64(0xE2F610C8, 0x4987BFA8), /* ~= 10^-87 */
1491
    U64(0x9F24B832, 0xE6B0F436), U64(0x0DD9CA7D, 0x2DF4D7C9), /* ~= 10^-86 */
1492
    U64(0xC6EDE63F, 0xA05D3143), U64(0x91503D1C, 0x79720DBB), /* ~= 10^-85 */
1493
    U64(0xF8A95FCF, 0x88747D94), U64(0x75A44C63, 0x97CE912A), /* ~= 10^-84 */
1494
    U64(0x9B69DBE1, 0xB548CE7C), U64(0xC986AFBE, 0x3EE11ABA), /* ~= 10^-83 */
1495
    U64(0xC24452DA, 0x229B021B), U64(0xFBE85BAD, 0xCE996168), /* ~= 10^-82 */
1496
    U64(0xF2D56790, 0xAB41C2A2), U64(0xFAE27299, 0x423FB9C3), /* ~= 10^-81 */
1497
    U64(0x97C560BA, 0x6B0919A5), U64(0xDCCD879F, 0xC967D41A), /* ~= 10^-80 */
1498
    U64(0xBDB6B8E9, 0x05CB600F), U64(0x5400E987, 0xBBC1C920), /* ~= 10^-79 */
1499
    U64(0xED246723, 0x473E3813), U64(0x290123E9, 0xAAB23B68), /* ~= 10^-78 */
1500
    U64(0x9436C076, 0x0C86E30B), U64(0xF9A0B672, 0x0AAF6521), /* ~= 10^-77 */
1501
    U64(0xB9447093, 0x8FA89BCE), U64(0xF808E40E, 0x8D5B3E69), /* ~= 10^-76 */
1502
    U64(0xE7958CB8, 0x7392C2C2), U64(0xB60B1D12, 0x30B20E04), /* ~= 10^-75 */
1503
    U64(0x90BD77F3, 0x483BB9B9), U64(0xB1C6F22B, 0x5E6F48C2), /* ~= 10^-74 */
1504
    U64(0xB4ECD5F0, 0x1A4AA828), U64(0x1E38AEB6, 0x360B1AF3), /* ~= 10^-73 */
1505
    U64(0xE2280B6C, 0x20DD5232), U64(0x25C6DA63, 0xC38DE1B0), /* ~= 10^-72 */
1506
    U64(0x8D590723, 0x948A535F), U64(0x579C487E, 0x5A38AD0E), /* ~= 10^-71 */
1507
    U64(0xB0AF48EC, 0x79ACE837), U64(0x2D835A9D, 0xF0C6D851), /* ~= 10^-70 */
1508
    U64(0xDCDB1B27, 0x98182244), U64(0xF8E43145, 0x6CF88E65), /* ~= 10^-69 */
1509
    U64(0x8A08F0F8, 0xBF0F156B), U64(0x1B8E9ECB, 0x641B58FF), /* ~= 10^-68 */
1510
    U64(0xAC8B2D36, 0xEED2DAC5), U64(0xE272467E, 0x3D222F3F), /* ~= 10^-67 */
1511
    U64(0xD7ADF884, 0xAA879177), U64(0x5B0ED81D, 0xCC6ABB0F), /* ~= 10^-66 */
1512
    U64(0x86CCBB52, 0xEA94BAEA), U64(0x98E94712, 0x9FC2B4E9), /* ~= 10^-65 */
1513
    U64(0xA87FEA27, 0xA539E9A5), U64(0x3F2398D7, 0x47B36224), /* ~= 10^-64 */
1514
    U64(0xD29FE4B1, 0x8E88640E), U64(0x8EEC7F0D, 0x19A03AAD), /* ~= 10^-63 */
1515
    U64(0x83A3EEEE, 0xF9153E89), U64(0x1953CF68, 0x300424AC), /* ~= 10^-62 */
1516
    U64(0xA48CEAAA, 0xB75A8E2B), U64(0x5FA8C342, 0x3C052DD7), /* ~= 10^-61 */
1517
    U64(0xCDB02555, 0x653131B6), U64(0x3792F412, 0xCB06794D), /* ~= 10^-60 */
1518
    U64(0x808E1755, 0x5F3EBF11), U64(0xE2BBD88B, 0xBEE40BD0), /* ~= 10^-59 */
1519
    U64(0xA0B19D2A, 0xB70E6ED6), U64(0x5B6ACEAE, 0xAE9D0EC4), /* ~= 10^-58 */
1520
    U64(0xC8DE0475, 0x64D20A8B), U64(0xF245825A, 0x5A445275), /* ~= 10^-57 */
1521
    U64(0xFB158592, 0xBE068D2E), U64(0xEED6E2F0, 0xF0D56712), /* ~= 10^-56 */
1522
    U64(0x9CED737B, 0xB6C4183D), U64(0x55464DD6, 0x9685606B), /* ~= 10^-55 */
1523
    U64(0xC428D05A, 0xA4751E4C), U64(0xAA97E14C, 0x3C26B886), /* ~= 10^-54 */
1524
    U64(0xF5330471, 0x4D9265DF), U64(0xD53DD99F, 0x4B3066A8), /* ~= 10^-53 */
1525
    U64(0x993FE2C6, 0xD07B7FAB), U64(0xE546A803, 0x8EFE4029), /* ~= 10^-52 */
1526
    U64(0xBF8FDB78, 0x849A5F96), U64(0xDE985204, 0x72BDD033), /* ~= 10^-51 */
1527
    U64(0xEF73D256, 0xA5C0F77C), U64(0x963E6685, 0x8F6D4440), /* ~= 10^-50 */
1528
    U64(0x95A86376, 0x27989AAD), U64(0xDDE70013, 0x79A44AA8), /* ~= 10^-49 */
1529
    U64(0xBB127C53, 0xB17EC159), U64(0x5560C018, 0x580D5D52), /* ~= 10^-48 */
1530
    U64(0xE9D71B68, 0x9DDE71AF), U64(0xAAB8F01E, 0x6E10B4A6), /* ~= 10^-47 */
1531
    U64(0x92267121, 0x62AB070D), U64(0xCAB39613, 0x04CA70E8), /* ~= 10^-46 */
1532
    U64(0xB6B00D69, 0xBB55C8D1), U64(0x3D607B97, 0xC5FD0D22), /* ~= 10^-45 */
1533
    U64(0xE45C10C4, 0x2A2B3B05), U64(0x8CB89A7D, 0xB77C506A), /* ~= 10^-44 */
1534
    U64(0x8EB98A7A, 0x9A5B04E3), U64(0x77F3608E, 0x92ADB242), /* ~= 10^-43 */
1535
    U64(0xB267ED19, 0x40F1C61C), U64(0x55F038B2, 0x37591ED3), /* ~= 10^-42 */
1536
    U64(0xDF01E85F, 0x912E37A3), U64(0x6B6C46DE, 0xC52F6688), /* ~= 10^-41 */
1537
    U64(0x8B61313B, 0xBABCE2C6), U64(0x2323AC4B, 0x3B3DA015), /* ~= 10^-40 */
1538
    U64(0xAE397D8A, 0xA96C1B77), U64(0xABEC975E, 0x0A0D081A), /* ~= 10^-39 */
1539
    U64(0xD9C7DCED, 0x53C72255), U64(0x96E7BD35, 0x8C904A21), /* ~= 10^-38 */
1540
    U64(0x881CEA14, 0x545C7575), U64(0x7E50D641, 0x77DA2E54), /* ~= 10^-37 */
1541
    U64(0xAA242499, 0x697392D2), U64(0xDDE50BD1, 0xD5D0B9E9), /* ~= 10^-36 */
1542
    U64(0xD4AD2DBF, 0xC3D07787), U64(0x955E4EC6, 0x4B44E864), /* ~= 10^-35 */
1543
    U64(0x84EC3C97, 0xDA624AB4), U64(0xBD5AF13B, 0xEF0B113E), /* ~= 10^-34 */
1544
    U64(0xA6274BBD, 0xD0FADD61), U64(0xECB1AD8A, 0xEACDD58E), /* ~= 10^-33 */
1545
    U64(0xCFB11EAD, 0x453994BA), U64(0x67DE18ED, 0xA5814AF2), /* ~= 10^-32 */
1546
    U64(0x81CEB32C, 0x4B43FCF4), U64(0x80EACF94, 0x8770CED7), /* ~= 10^-31 */
1547
    U64(0xA2425FF7, 0x5E14FC31), U64(0xA1258379, 0xA94D028D), /* ~= 10^-30 */
1548
    U64(0xCAD2F7F5, 0x359A3B3E), U64(0x096EE458, 0x13A04330), /* ~= 10^-29 */
1549
    U64(0xFD87B5F2, 0x8300CA0D), U64(0x8BCA9D6E, 0x188853FC), /* ~= 10^-28 */
1550
    U64(0x9E74D1B7, 0x91E07E48), U64(0x775EA264, 0xCF55347D), /* ~= 10^-27 */
1551
    U64(0xC6120625, 0x76589DDA), U64(0x95364AFE, 0x032A819D), /* ~= 10^-26 */
1552
    U64(0xF79687AE, 0xD3EEC551), U64(0x3A83DDBD, 0x83F52204), /* ~= 10^-25 */
1553
    U64(0x9ABE14CD, 0x44753B52), U64(0xC4926A96, 0x72793542), /* ~= 10^-24 */
1554
    U64(0xC16D9A00, 0x95928A27), U64(0x75B7053C, 0x0F178293), /* ~= 10^-23 */
1555
    U64(0xF1C90080, 0xBAF72CB1), U64(0x5324C68B, 0x12DD6338), /* ~= 10^-22 */
1556
    U64(0x971DA050, 0x74DA7BEE), U64(0xD3F6FC16, 0xEBCA5E03), /* ~= 10^-21 */
1557
    U64(0xBCE50864, 0x92111AEA), U64(0x88F4BB1C, 0xA6BCF584), /* ~= 10^-20 */
1558
    U64(0xEC1E4A7D, 0xB69561A5), U64(0x2B31E9E3, 0xD06C32E5), /* ~= 10^-19 */
1559
    U64(0x9392EE8E, 0x921D5D07), U64(0x3AFF322E, 0x62439FCF), /* ~= 10^-18 */
1560
    U64(0xB877AA32, 0x36A4B449), U64(0x09BEFEB9, 0xFAD487C2), /* ~= 10^-17 */
1561
    U64(0xE69594BE, 0xC44DE15B), U64(0x4C2EBE68, 0x7989A9B3), /* ~= 10^-16 */
1562
    U64(0x901D7CF7, 0x3AB0ACD9), U64(0x0F9D3701, 0x4BF60A10), /* ~= 10^-15 */
1563
    U64(0xB424DC35, 0x095CD80F), U64(0x538484C1, 0x9EF38C94), /* ~= 10^-14 */
1564
    U64(0xE12E1342, 0x4BB40E13), U64(0x2865A5F2, 0x06B06FB9), /* ~= 10^-13 */
1565
    U64(0x8CBCCC09, 0x6F5088CB), U64(0xF93F87B7, 0x442E45D3), /* ~= 10^-12 */
1566
    U64(0xAFEBFF0B, 0xCB24AAFE), U64(0xF78F69A5, 0x1539D748), /* ~= 10^-11 */
1567
    U64(0xDBE6FECE, 0xBDEDD5BE), U64(0xB573440E, 0x5A884D1B), /* ~= 10^-10 */
1568
    U64(0x89705F41, 0x36B4A597), U64(0x31680A88, 0xF8953030), /* ~= 10^-9 */
1569
    U64(0xABCC7711, 0x8461CEFC), U64(0xFDC20D2B, 0x36BA7C3D), /* ~= 10^-8 */
1570
    U64(0xD6BF94D5, 0xE57A42BC), U64(0x3D329076, 0x04691B4C), /* ~= 10^-7 */
1571
    U64(0x8637BD05, 0xAF6C69B5), U64(0xA63F9A49, 0xC2C1B10F), /* ~= 10^-6 */
1572
    U64(0xA7C5AC47, 0x1B478423), U64(0x0FCF80DC, 0x33721D53), /* ~= 10^-5 */
1573
    U64(0xD1B71758, 0xE219652B), U64(0xD3C36113, 0x404EA4A8), /* ~= 10^-4 */
1574
    U64(0x83126E97, 0x8D4FDF3B), U64(0x645A1CAC, 0x083126E9), /* ~= 10^-3 */
1575
    U64(0xA3D70A3D, 0x70A3D70A), U64(0x3D70A3D7, 0x0A3D70A3), /* ~= 10^-2 */
1576
    U64(0xCCCCCCCC, 0xCCCCCCCC), U64(0xCCCCCCCC, 0xCCCCCCCC), /* ~= 10^-1 */
1577
    U64(0x80000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^0 */
1578
    U64(0xA0000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^1 */
1579
    U64(0xC8000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^2 */
1580
    U64(0xFA000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^3 */
1581
    U64(0x9C400000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^4 */
1582
    U64(0xC3500000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^5 */
1583
    U64(0xF4240000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^6 */
1584
    U64(0x98968000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^7 */
1585
    U64(0xBEBC2000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^8 */
1586
    U64(0xEE6B2800, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^9 */
1587
    U64(0x9502F900, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^10 */
1588
    U64(0xBA43B740, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^11 */
1589
    U64(0xE8D4A510, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^12 */
1590
    U64(0x9184E72A, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^13 */
1591
    U64(0xB5E620F4, 0x80000000), U64(0x00000000, 0x00000000), /* == 10^14 */
1592
    U64(0xE35FA931, 0xA0000000), U64(0x00000000, 0x00000000), /* == 10^15 */
1593
    U64(0x8E1BC9BF, 0x04000000), U64(0x00000000, 0x00000000), /* == 10^16 */
1594
    U64(0xB1A2BC2E, 0xC5000000), U64(0x00000000, 0x00000000), /* == 10^17 */
1595
    U64(0xDE0B6B3A, 0x76400000), U64(0x00000000, 0x00000000), /* == 10^18 */
1596
    U64(0x8AC72304, 0x89E80000), U64(0x00000000, 0x00000000), /* == 10^19 */
1597
    U64(0xAD78EBC5, 0xAC620000), U64(0x00000000, 0x00000000), /* == 10^20 */
1598
    U64(0xD8D726B7, 0x177A8000), U64(0x00000000, 0x00000000), /* == 10^21 */
1599
    U64(0x87867832, 0x6EAC9000), U64(0x00000000, 0x00000000), /* == 10^22 */
1600
    U64(0xA968163F, 0x0A57B400), U64(0x00000000, 0x00000000), /* == 10^23 */
1601
    U64(0xD3C21BCE, 0xCCEDA100), U64(0x00000000, 0x00000000), /* == 10^24 */
1602
    U64(0x84595161, 0x401484A0), U64(0x00000000, 0x00000000), /* == 10^25 */
1603
    U64(0xA56FA5B9, 0x9019A5C8), U64(0x00000000, 0x00000000), /* == 10^26 */
1604
    U64(0xCECB8F27, 0xF4200F3A), U64(0x00000000, 0x00000000), /* == 10^27 */
1605
    U64(0x813F3978, 0xF8940984), U64(0x40000000, 0x00000000), /* == 10^28 */
1606
    U64(0xA18F07D7, 0x36B90BE5), U64(0x50000000, 0x00000000), /* == 10^29 */
1607
    U64(0xC9F2C9CD, 0x04674EDE), U64(0xA4000000, 0x00000000), /* == 10^30 */
1608
    U64(0xFC6F7C40, 0x45812296), U64(0x4D000000, 0x00000000), /* == 10^31 */
1609
    U64(0x9DC5ADA8, 0x2B70B59D), U64(0xF0200000, 0x00000000), /* == 10^32 */
1610
    U64(0xC5371912, 0x364CE305), U64(0x6C280000, 0x00000000), /* == 10^33 */
1611
    U64(0xF684DF56, 0xC3E01BC6), U64(0xC7320000, 0x00000000), /* == 10^34 */
1612
    U64(0x9A130B96, 0x3A6C115C), U64(0x3C7F4000, 0x00000000), /* == 10^35 */
1613
    U64(0xC097CE7B, 0xC90715B3), U64(0x4B9F1000, 0x00000000), /* == 10^36 */
1614
    U64(0xF0BDC21A, 0xBB48DB20), U64(0x1E86D400, 0x00000000), /* == 10^37 */
1615
    U64(0x96769950, 0xB50D88F4), U64(0x13144480, 0x00000000), /* == 10^38 */
1616
    U64(0xBC143FA4, 0xE250EB31), U64(0x17D955A0, 0x00000000), /* == 10^39 */
1617
    U64(0xEB194F8E, 0x1AE525FD), U64(0x5DCFAB08, 0x00000000), /* == 10^40 */
1618
    U64(0x92EFD1B8, 0xD0CF37BE), U64(0x5AA1CAE5, 0x00000000), /* == 10^41 */
1619
    U64(0xB7ABC627, 0x050305AD), U64(0xF14A3D9E, 0x40000000), /* == 10^42 */
1620
    U64(0xE596B7B0, 0xC643C719), U64(0x6D9CCD05, 0xD0000000), /* == 10^43 */
1621
    U64(0x8F7E32CE, 0x7BEA5C6F), U64(0xE4820023, 0xA2000000), /* == 10^44 */
1622
    U64(0xB35DBF82, 0x1AE4F38B), U64(0xDDA2802C, 0x8A800000), /* == 10^45 */
1623
    U64(0xE0352F62, 0xA19E306E), U64(0xD50B2037, 0xAD200000), /* == 10^46 */
1624
    U64(0x8C213D9D, 0xA502DE45), U64(0x4526F422, 0xCC340000), /* == 10^47 */
1625
    U64(0xAF298D05, 0x0E4395D6), U64(0x9670B12B, 0x7F410000), /* == 10^48 */
1626
    U64(0xDAF3F046, 0x51D47B4C), U64(0x3C0CDD76, 0x5F114000), /* == 10^49 */
1627
    U64(0x88D8762B, 0xF324CD0F), U64(0xA5880A69, 0xFB6AC800), /* == 10^50 */
1628
    U64(0xAB0E93B6, 0xEFEE0053), U64(0x8EEA0D04, 0x7A457A00), /* == 10^51 */
1629
    U64(0xD5D238A4, 0xABE98068), U64(0x72A49045, 0x98D6D880), /* == 10^52 */
1630
    U64(0x85A36366, 0xEB71F041), U64(0x47A6DA2B, 0x7F864750), /* == 10^53 */
1631
    U64(0xA70C3C40, 0xA64E6C51), U64(0x999090B6, 0x5F67D924), /* == 10^54 */
1632
    U64(0xD0CF4B50, 0xCFE20765), U64(0xFFF4B4E3, 0xF741CF6D), /* == 10^55 */
1633
    U64(0x82818F12, 0x81ED449F), U64(0xBFF8F10E, 0x7A8921A4), /* ~= 10^56 */
1634
    U64(0xA321F2D7, 0x226895C7), U64(0xAFF72D52, 0x192B6A0D), /* ~= 10^57 */
1635
    U64(0xCBEA6F8C, 0xEB02BB39), U64(0x9BF4F8A6, 0x9F764490), /* ~= 10^58 */
1636
    U64(0xFEE50B70, 0x25C36A08), U64(0x02F236D0, 0x4753D5B4), /* ~= 10^59 */
1637
    U64(0x9F4F2726, 0x179A2245), U64(0x01D76242, 0x2C946590), /* ~= 10^60 */
1638
    U64(0xC722F0EF, 0x9D80AAD6), U64(0x424D3AD2, 0xB7B97EF5), /* ~= 10^61 */
1639
    U64(0xF8EBAD2B, 0x84E0D58B), U64(0xD2E08987, 0x65A7DEB2), /* ~= 10^62 */
1640
    U64(0x9B934C3B, 0x330C8577), U64(0x63CC55F4, 0x9F88EB2F), /* ~= 10^63 */
1641
    U64(0xC2781F49, 0xFFCFA6D5), U64(0x3CBF6B71, 0xC76B25FB), /* ~= 10^64 */
1642
    U64(0xF316271C, 0x7FC3908A), U64(0x8BEF464E, 0x3945EF7A), /* ~= 10^65 */
1643
    U64(0x97EDD871, 0xCFDA3A56), U64(0x97758BF0, 0xE3CBB5AC), /* ~= 10^66 */
1644
    U64(0xBDE94E8E, 0x43D0C8EC), U64(0x3D52EEED, 0x1CBEA317), /* ~= 10^67 */
1645
    U64(0xED63A231, 0xD4C4FB27), U64(0x4CA7AAA8, 0x63EE4BDD), /* ~= 10^68 */
1646
    U64(0x945E455F, 0x24FB1CF8), U64(0x8FE8CAA9, 0x3E74EF6A), /* ~= 10^69 */
1647
    U64(0xB975D6B6, 0xEE39E436), U64(0xB3E2FD53, 0x8E122B44), /* ~= 10^70 */
1648
    U64(0xE7D34C64, 0xA9C85D44), U64(0x60DBBCA8, 0x7196B616), /* ~= 10^71 */
1649
    U64(0x90E40FBE, 0xEA1D3A4A), U64(0xBC8955E9, 0x46FE31CD), /* ~= 10^72 */
1650
    U64(0xB51D13AE, 0xA4A488DD), U64(0x6BABAB63, 0x98BDBE41), /* ~= 10^73 */
1651
    U64(0xE264589A, 0x4DCDAB14), U64(0xC696963C, 0x7EED2DD1), /* ~= 10^74 */
1652
    U64(0x8D7EB760, 0x70A08AEC), U64(0xFC1E1DE5, 0xCF543CA2), /* ~= 10^75 */
1653
    U64(0xB0DE6538, 0x8CC8ADA8), U64(0x3B25A55F, 0x43294BCB), /* ~= 10^76 */
1654
    U64(0xDD15FE86, 0xAFFAD912), U64(0x49EF0EB7, 0x13F39EBE), /* ~= 10^77 */
1655
    U64(0x8A2DBF14, 0x2DFCC7AB), U64(0x6E356932, 0x6C784337), /* ~= 10^78 */
1656
    U64(0xACB92ED9, 0x397BF996), U64(0x49C2C37F, 0x07965404), /* ~= 10^79 */
1657
    U64(0xD7E77A8F, 0x87DAF7FB), U64(0xDC33745E, 0xC97BE906), /* ~= 10^80 */
1658
    U64(0x86F0AC99, 0xB4E8DAFD), U64(0x69A028BB, 0x3DED71A3), /* ~= 10^81 */
1659
    U64(0xA8ACD7C0, 0x222311BC), U64(0xC40832EA, 0x0D68CE0C), /* ~= 10^82 */
1660
    U64(0xD2D80DB0, 0x2AABD62B), U64(0xF50A3FA4, 0x90C30190), /* ~= 10^83 */
1661
    U64(0x83C7088E, 0x1AAB65DB), U64(0x792667C6, 0xDA79E0FA), /* ~= 10^84 */
1662
    U64(0xA4B8CAB1, 0xA1563F52), U64(0x577001B8, 0x91185938), /* ~= 10^85 */
1663
    U64(0xCDE6FD5E, 0x09ABCF26), U64(0xED4C0226, 0xB55E6F86), /* ~= 10^86 */
1664
    U64(0x80B05E5A, 0xC60B6178), U64(0x544F8158, 0x315B05B4), /* ~= 10^87 */
1665
    U64(0xA0DC75F1, 0x778E39D6), U64(0x696361AE, 0x3DB1C721), /* ~= 10^88 */
1666
    U64(0xC913936D, 0xD571C84C), U64(0x03BC3A19, 0xCD1E38E9), /* ~= 10^89 */
1667
    U64(0xFB587849, 0x4ACE3A5F), U64(0x04AB48A0, 0x4065C723), /* ~= 10^90 */
1668
    U64(0x9D174B2D, 0xCEC0E47B), U64(0x62EB0D64, 0x283F9C76), /* ~= 10^91 */
1669
    U64(0xC45D1DF9, 0x42711D9A), U64(0x3BA5D0BD, 0x324F8394), /* ~= 10^92 */
1670
    U64(0xF5746577, 0x930D6500), U64(0xCA8F44EC, 0x7EE36479), /* ~= 10^93 */
1671
    U64(0x9968BF6A, 0xBBE85F20), U64(0x7E998B13, 0xCF4E1ECB), /* ~= 10^94 */
1672
    U64(0xBFC2EF45, 0x6AE276E8), U64(0x9E3FEDD8, 0xC321A67E), /* ~= 10^95 */
1673
    U64(0xEFB3AB16, 0xC59B14A2), U64(0xC5CFE94E, 0xF3EA101E), /* ~= 10^96 */
1674
    U64(0x95D04AEE, 0x3B80ECE5), U64(0xBBA1F1D1, 0x58724A12), /* ~= 10^97 */
1675
    U64(0xBB445DA9, 0xCA61281F), U64(0x2A8A6E45, 0xAE8EDC97), /* ~= 10^98 */
1676
    U64(0xEA157514, 0x3CF97226), U64(0xF52D09D7, 0x1A3293BD), /* ~= 10^99 */
1677
    U64(0x924D692C, 0xA61BE758), U64(0x593C2626, 0x705F9C56), /* ~= 10^100 */
1678
    U64(0xB6E0C377, 0xCFA2E12E), U64(0x6F8B2FB0, 0x0C77836C), /* ~= 10^101 */
1679
    U64(0xE498F455, 0xC38B997A), U64(0x0B6DFB9C, 0x0F956447), /* ~= 10^102 */
1680
    U64(0x8EDF98B5, 0x9A373FEC), U64(0x4724BD41, 0x89BD5EAC), /* ~= 10^103 */
1681
    U64(0xB2977EE3, 0x00C50FE7), U64(0x58EDEC91, 0xEC2CB657), /* ~= 10^104 */
1682
    U64(0xDF3D5E9B, 0xC0F653E1), U64(0x2F2967B6, 0x6737E3ED), /* ~= 10^105 */
1683
    U64(0x8B865B21, 0x5899F46C), U64(0xBD79E0D2, 0x0082EE74), /* ~= 10^106 */
1684
    U64(0xAE67F1E9, 0xAEC07187), U64(0xECD85906, 0x80A3AA11), /* ~= 10^107 */
1685
    U64(0xDA01EE64, 0x1A708DE9), U64(0xE80E6F48, 0x20CC9495), /* ~= 10^108 */
1686
    U64(0x884134FE, 0x908658B2), U64(0x3109058D, 0x147FDCDD), /* ~= 10^109 */
1687
    U64(0xAA51823E, 0x34A7EEDE), U64(0xBD4B46F0, 0x599FD415), /* ~= 10^110 */
1688
    U64(0xD4E5E2CD, 0xC1D1EA96), U64(0x6C9E18AC, 0x7007C91A), /* ~= 10^111 */
1689
    U64(0x850FADC0, 0x9923329E), U64(0x03E2CF6B, 0xC604DDB0), /* ~= 10^112 */
1690
    U64(0xA6539930, 0xBF6BFF45), U64(0x84DB8346, 0xB786151C), /* ~= 10^113 */
1691
    U64(0xCFE87F7C, 0xEF46FF16), U64(0xE6126418, 0x65679A63), /* ~= 10^114 */
1692
    U64(0x81F14FAE, 0x158C5F6E), U64(0x4FCB7E8F, 0x3F60C07E), /* ~= 10^115 */
1693
    U64(0xA26DA399, 0x9AEF7749), U64(0xE3BE5E33, 0x0F38F09D), /* ~= 10^116 */
1694
    U64(0xCB090C80, 0x01AB551C), U64(0x5CADF5BF, 0xD3072CC5), /* ~= 10^117 */
1695
    U64(0xFDCB4FA0, 0x02162A63), U64(0x73D9732F, 0xC7C8F7F6), /* ~= 10^118 */
1696
    U64(0x9E9F11C4, 0x014DDA7E), U64(0x2867E7FD, 0xDCDD9AFA), /* ~= 10^119 */
1697
    U64(0xC646D635, 0x01A1511D), U64(0xB281E1FD, 0x541501B8), /* ~= 10^120 */
1698
    U64(0xF7D88BC2, 0x4209A565), U64(0x1F225A7C, 0xA91A4226), /* ~= 10^121 */
1699
    U64(0x9AE75759, 0x6946075F), U64(0x3375788D, 0xE9B06958), /* ~= 10^122 */
1700
    U64(0xC1A12D2F, 0xC3978937), U64(0x0052D6B1, 0x641C83AE), /* ~= 10^123 */
1701
    U64(0xF209787B, 0xB47D6B84), U64(0xC0678C5D, 0xBD23A49A), /* ~= 10^124 */
1702
    U64(0x9745EB4D, 0x50CE6332), U64(0xF840B7BA, 0x963646E0), /* ~= 10^125 */
1703
    U64(0xBD176620, 0xA501FBFF), U64(0xB650E5A9, 0x3BC3D898), /* ~= 10^126 */
1704
    U64(0xEC5D3FA8, 0xCE427AFF), U64(0xA3E51F13, 0x8AB4CEBE), /* ~= 10^127 */
1705
    U64(0x93BA47C9, 0x80E98CDF), U64(0xC66F336C, 0x36B10137), /* ~= 10^128 */
1706
    U64(0xB8A8D9BB, 0xE123F017), U64(0xB80B0047, 0x445D4184), /* ~= 10^129 */
1707
    U64(0xE6D3102A, 0xD96CEC1D), U64(0xA60DC059, 0x157491E5), /* ~= 10^130 */
1708
    U64(0x9043EA1A, 0xC7E41392), U64(0x87C89837, 0xAD68DB2F), /* ~= 10^131 */
1709
    U64(0xB454E4A1, 0x79DD1877), U64(0x29BABE45, 0x98C311FB), /* ~= 10^132 */
1710
    U64(0xE16A1DC9, 0xD8545E94), U64(0xF4296DD6, 0xFEF3D67A), /* ~= 10^133 */
1711
    U64(0x8CE2529E, 0x2734BB1D), U64(0x1899E4A6, 0x5F58660C), /* ~= 10^134 */
1712
    U64(0xB01AE745, 0xB101E9E4), U64(0x5EC05DCF, 0xF72E7F8F), /* ~= 10^135 */
1713
    U64(0xDC21A117, 0x1D42645D), U64(0x76707543, 0xF4FA1F73), /* ~= 10^136 */
1714
    U64(0x899504AE, 0x72497EBA), U64(0x6A06494A, 0x791C53A8), /* ~= 10^137 */
1715
    U64(0xABFA45DA, 0x0EDBDE69), U64(0x0487DB9D, 0x17636892), /* ~= 10^138 */
1716
    U64(0xD6F8D750, 0x9292D603), U64(0x45A9D284, 0x5D3C42B6), /* ~= 10^139 */
1717
    U64(0x865B8692, 0x5B9BC5C2), U64(0x0B8A2392, 0xBA45A9B2), /* ~= 10^140 */
1718
    U64(0xA7F26836, 0xF282B732), U64(0x8E6CAC77, 0x68D7141E), /* ~= 10^141 */
1719
    U64(0xD1EF0244, 0xAF2364FF), U64(0x3207D795, 0x430CD926), /* ~= 10^142 */
1720
    U64(0x8335616A, 0xED761F1F), U64(0x7F44E6BD, 0x49E807B8), /* ~= 10^143 */
1721
    U64(0xA402B9C5, 0xA8D3A6E7), U64(0x5F16206C, 0x9C6209A6), /* ~= 10^144 */
1722
    U64(0xCD036837, 0x130890A1), U64(0x36DBA887, 0xC37A8C0F), /* ~= 10^145 */
1723
    U64(0x80222122, 0x6BE55A64), U64(0xC2494954, 0xDA2C9789), /* ~= 10^146 */
1724
    U64(0xA02AA96B, 0x06DEB0FD), U64(0xF2DB9BAA, 0x10B7BD6C), /* ~= 10^147 */
1725
    U64(0xC83553C5, 0xC8965D3D), U64(0x6F928294, 0x94E5ACC7), /* ~= 10^148 */
1726
    U64(0xFA42A8B7, 0x3ABBF48C), U64(0xCB772339, 0xBA1F17F9), /* ~= 10^149 */
1727
    U64(0x9C69A972, 0x84B578D7), U64(0xFF2A7604, 0x14536EFB), /* ~= 10^150 */
1728
    U64(0xC38413CF, 0x25E2D70D), U64(0xFEF51385, 0x19684ABA), /* ~= 10^151 */
1729
    U64(0xF46518C2, 0xEF5B8CD1), U64(0x7EB25866, 0x5FC25D69), /* ~= 10^152 */
1730
    U64(0x98BF2F79, 0xD5993802), U64(0xEF2F773F, 0xFBD97A61), /* ~= 10^153 */
1731
    U64(0xBEEEFB58, 0x4AFF8603), U64(0xAAFB550F, 0xFACFD8FA), /* ~= 10^154 */
1732
    U64(0xEEAABA2E, 0x5DBF6784), U64(0x95BA2A53, 0xF983CF38), /* ~= 10^155 */
1733
    U64(0x952AB45C, 0xFA97A0B2), U64(0xDD945A74, 0x7BF26183), /* ~= 10^156 */
1734
    U64(0xBA756174, 0x393D88DF), U64(0x94F97111, 0x9AEEF9E4), /* ~= 10^157 */
1735
    U64(0xE912B9D1, 0x478CEB17), U64(0x7A37CD56, 0x01AAB85D), /* ~= 10^158 */
1736
    U64(0x91ABB422, 0xCCB812EE), U64(0xAC62E055, 0xC10AB33A), /* ~= 10^159 */
1737
    U64(0xB616A12B, 0x7FE617AA), U64(0x577B986B, 0x314D6009), /* ~= 10^160 */
1738
    U64(0xE39C4976, 0x5FDF9D94), U64(0xED5A7E85, 0xFDA0B80B), /* ~= 10^161 */
1739
    U64(0x8E41ADE9, 0xFBEBC27D), U64(0x14588F13, 0xBE847307), /* ~= 10^162 */
1740
    U64(0xB1D21964, 0x7AE6B31C), U64(0x596EB2D8, 0xAE258FC8), /* ~= 10^163 */
1741
    U64(0xDE469FBD, 0x99A05FE3), U64(0x6FCA5F8E, 0xD9AEF3BB), /* ~= 10^164 */
1742
    U64(0x8AEC23D6, 0x80043BEE), U64(0x25DE7BB9, 0x480D5854), /* ~= 10^165 */
1743
    U64(0xADA72CCC, 0x20054AE9), U64(0xAF561AA7, 0x9A10AE6A), /* ~= 10^166 */
1744
    U64(0xD910F7FF, 0x28069DA4), U64(0x1B2BA151, 0x8094DA04), /* ~= 10^167 */
1745
    U64(0x87AA9AFF, 0x79042286), U64(0x90FB44D2, 0xF05D0842), /* ~= 10^168 */
1746
    U64(0xA99541BF, 0x57452B28), U64(0x353A1607, 0xAC744A53), /* ~= 10^169 */
1747
    U64(0xD3FA922F, 0x2D1675F2), U64(0x42889B89, 0x97915CE8), /* ~= 10^170 */
1748
    U64(0x847C9B5D, 0x7C2E09B7), U64(0x69956135, 0xFEBADA11), /* ~= 10^171 */
1749
    U64(0xA59BC234, 0xDB398C25), U64(0x43FAB983, 0x7E699095), /* ~= 10^172 */
1750
    U64(0xCF02B2C2, 0x1207EF2E), U64(0x94F967E4, 0x5E03F4BB), /* ~= 10^173 */
1751
    U64(0x8161AFB9, 0x4B44F57D), U64(0x1D1BE0EE, 0xBAC278F5), /* ~= 10^174 */
1752
    U64(0xA1BA1BA7, 0x9E1632DC), U64(0x6462D92A, 0x69731732), /* ~= 10^175 */
1753
    U64(0xCA28A291, 0x859BBF93), U64(0x7D7B8F75, 0x03CFDCFE), /* ~= 10^176 */
1754
    U64(0xFCB2CB35, 0xE702AF78), U64(0x5CDA7352, 0x44C3D43E), /* ~= 10^177 */
1755
    U64(0x9DEFBF01, 0xB061ADAB), U64(0x3A088813, 0x6AFA64A7), /* ~= 10^178 */
1756
    U64(0xC56BAEC2, 0x1C7A1916), U64(0x088AAA18, 0x45B8FDD0), /* ~= 10^179 */
1757
    U64(0xF6C69A72, 0xA3989F5B), U64(0x8AAD549E, 0x57273D45), /* ~= 10^180 */
1758
    U64(0x9A3C2087, 0xA63F6399), U64(0x36AC54E2, 0xF678864B), /* ~= 10^181 */
1759
    U64(0xC0CB28A9, 0x8FCF3C7F), U64(0x84576A1B, 0xB416A7DD), /* ~= 10^182 */
1760
    U64(0xF0FDF2D3, 0xF3C30B9F), U64(0x656D44A2, 0xA11C51D5), /* ~= 10^183 */
1761
    U64(0x969EB7C4, 0x7859E743), U64(0x9F644AE5, 0xA4B1B325), /* ~= 10^184 */
1762
    U64(0xBC4665B5, 0x96706114), U64(0x873D5D9F, 0x0DDE1FEE), /* ~= 10^185 */
1763
    U64(0xEB57FF22, 0xFC0C7959), U64(0xA90CB506, 0xD155A7EA), /* ~= 10^186 */
1764
    U64(0x9316FF75, 0xDD87CBD8), U64(0x09A7F124, 0x42D588F2), /* ~= 10^187 */
1765
    U64(0xB7DCBF53, 0x54E9BECE), U64(0x0C11ED6D, 0x538AEB2F), /* ~= 10^188 */
1766
    U64(0xE5D3EF28, 0x2A242E81), U64(0x8F1668C8, 0xA86DA5FA), /* ~= 10^189 */
1767
    U64(0x8FA47579, 0x1A569D10), U64(0xF96E017D, 0x694487BC), /* ~= 10^190 */
1768
    U64(0xB38D92D7, 0x60EC4455), U64(0x37C981DC, 0xC395A9AC), /* ~= 10^191 */
1769
    U64(0xE070F78D, 0x3927556A), U64(0x85BBE253, 0xF47B1417), /* ~= 10^192 */
1770
    U64(0x8C469AB8, 0x43B89562), U64(0x93956D74, 0x78CCEC8E), /* ~= 10^193 */
1771
    U64(0xAF584166, 0x54A6BABB), U64(0x387AC8D1, 0x970027B2), /* ~= 10^194 */
1772
    U64(0xDB2E51BF, 0xE9D0696A), U64(0x06997B05, 0xFCC0319E), /* ~= 10^195 */
1773
    U64(0x88FCF317, 0xF22241E2), U64(0x441FECE3, 0xBDF81F03), /* ~= 10^196 */
1774
    U64(0xAB3C2FDD, 0xEEAAD25A), U64(0xD527E81C, 0xAD7626C3), /* ~= 10^197 */
1775
    U64(0xD60B3BD5, 0x6A5586F1), U64(0x8A71E223, 0xD8D3B074), /* ~= 10^198 */
1776
    U64(0x85C70565, 0x62757456), U64(0xF6872D56, 0x67844E49), /* ~= 10^199 */
1777
    U64(0xA738C6BE, 0xBB12D16C), U64(0xB428F8AC, 0x016561DB), /* ~= 10^200 */
1778
    U64(0xD106F86E, 0x69D785C7), U64(0xE13336D7, 0x01BEBA52), /* ~= 10^201 */
1779
    U64(0x82A45B45, 0x0226B39C), U64(0xECC00246, 0x61173473), /* ~= 10^202 */
1780
    U64(0xA34D7216, 0x42B06084), U64(0x27F002D7, 0xF95D0190), /* ~= 10^203 */
1781
    U64(0xCC20CE9B, 0xD35C78A5), U64(0x31EC038D, 0xF7B441F4), /* ~= 10^204 */
1782
    U64(0xFF290242, 0xC83396CE), U64(0x7E670471, 0x75A15271), /* ~= 10^205 */
1783
    U64(0x9F79A169, 0xBD203E41), U64(0x0F0062C6, 0xE984D386), /* ~= 10^206 */
1784
    U64(0xC75809C4, 0x2C684DD1), U64(0x52C07B78, 0xA3E60868), /* ~= 10^207 */
1785
    U64(0xF92E0C35, 0x37826145), U64(0xA7709A56, 0xCCDF8A82), /* ~= 10^208 */
1786
    U64(0x9BBCC7A1, 0x42B17CCB), U64(0x88A66076, 0x400BB691), /* ~= 10^209 */
1787
    U64(0xC2ABF989, 0x935DDBFE), U64(0x6ACFF893, 0xD00EA435), /* ~= 10^210 */
1788
    U64(0xF356F7EB, 0xF83552FE), U64(0x0583F6B8, 0xC4124D43), /* ~= 10^211 */
1789
    U64(0x98165AF3, 0x7B2153DE), U64(0xC3727A33, 0x7A8B704A), /* ~= 10^212 */
1790
    U64(0xBE1BF1B0, 0x59E9A8D6), U64(0x744F18C0, 0x592E4C5C), /* ~= 10^213 */
1791
    U64(0xEDA2EE1C, 0x7064130C), U64(0x1162DEF0, 0x6F79DF73), /* ~= 10^214 */
1792
    U64(0x9485D4D1, 0xC63E8BE7), U64(0x8ADDCB56, 0x45AC2BA8), /* ~= 10^215 */
1793
    U64(0xB9A74A06, 0x37CE2EE1), U64(0x6D953E2B, 0xD7173692), /* ~= 10^216 */
1794
    U64(0xE8111C87, 0xC5C1BA99), U64(0xC8FA8DB6, 0xCCDD0437), /* ~= 10^217 */
1795
    U64(0x910AB1D4, 0xDB9914A0), U64(0x1D9C9892, 0x400A22A2), /* ~= 10^218 */
1796
    U64(0xB54D5E4A, 0x127F59C8), U64(0x2503BEB6, 0xD00CAB4B), /* ~= 10^219 */
1797
    U64(0xE2A0B5DC, 0x971F303A), U64(0x2E44AE64, 0x840FD61D), /* ~= 10^220 */
1798
    U64(0x8DA471A9, 0xDE737E24), U64(0x5CEAECFE, 0xD289E5D2), /* ~= 10^221 */
1799
    U64(0xB10D8E14, 0x56105DAD), U64(0x7425A83E, 0x872C5F47), /* ~= 10^222 */
1800
    U64(0xDD50F199, 0x6B947518), U64(0xD12F124E, 0x28F77719), /* ~= 10^223 */
1801
    U64(0x8A5296FF, 0xE33CC92F), U64(0x82BD6B70, 0xD99AAA6F), /* ~= 10^224 */
1802
    U64(0xACE73CBF, 0xDC0BFB7B), U64(0x636CC64D, 0x1001550B), /* ~= 10^225 */
1803
    U64(0xD8210BEF, 0xD30EFA5A), U64(0x3C47F7E0, 0x5401AA4E), /* ~= 10^226 */
1804
    U64(0x8714A775, 0xE3E95C78), U64(0x65ACFAEC, 0x34810A71), /* ~= 10^227 */
1805
    U64(0xA8D9D153, 0x5CE3B396), U64(0x7F1839A7, 0x41A14D0D), /* ~= 10^228 */
1806
    U64(0xD31045A8, 0x341CA07C), U64(0x1EDE4811, 0x1209A050), /* ~= 10^229 */
1807
    U64(0x83EA2B89, 0x2091E44D), U64(0x934AED0A, 0xAB460432), /* ~= 10^230 */
1808
    U64(0xA4E4B66B, 0x68B65D60), U64(0xF81DA84D, 0x5617853F), /* ~= 10^231 */
1809
    U64(0xCE1DE406, 0x42E3F4B9), U64(0x36251260, 0xAB9D668E), /* ~= 10^232 */
1810
    U64(0x80D2AE83, 0xE9CE78F3), U64(0xC1D72B7C, 0x6B426019), /* ~= 10^233 */
1811
    U64(0xA1075A24, 0xE4421730), U64(0xB24CF65B, 0x8612F81F), /* ~= 10^234 */
1812
    U64(0xC94930AE, 0x1D529CFC), U64(0xDEE033F2, 0x6797B627), /* ~= 10^235 */
1813
    U64(0xFB9B7CD9, 0xA4A7443C), U64(0x169840EF, 0x017DA3B1), /* ~= 10^236 */
1814
    U64(0x9D412E08, 0x06E88AA5), U64(0x8E1F2895, 0x60EE864E), /* ~= 10^237 */
1815
    U64(0xC491798A, 0x08A2AD4E), U64(0xF1A6F2BA, 0xB92A27E2), /* ~= 10^238 */
1816
    U64(0xF5B5D7EC, 0x8ACB58A2), U64(0xAE10AF69, 0x6774B1DB), /* ~= 10^239 */
1817
    U64(0x9991A6F3, 0xD6BF1765), U64(0xACCA6DA1, 0xE0A8EF29), /* ~= 10^240 */
1818
    U64(0xBFF610B0, 0xCC6EDD3F), U64(0x17FD090A, 0x58D32AF3), /* ~= 10^241 */
1819
    U64(0xEFF394DC, 0xFF8A948E), U64(0xDDFC4B4C, 0xEF07F5B0), /* ~= 10^242 */
1820
    U64(0x95F83D0A, 0x1FB69CD9), U64(0x4ABDAF10, 0x1564F98E), /* ~= 10^243 */
1821
    U64(0xBB764C4C, 0xA7A4440F), U64(0x9D6D1AD4, 0x1ABE37F1), /* ~= 10^244 */
1822
    U64(0xEA53DF5F, 0xD18D5513), U64(0x84C86189, 0x216DC5ED), /* ~= 10^245 */
1823
    U64(0x92746B9B, 0xE2F8552C), U64(0x32FD3CF5, 0xB4E49BB4), /* ~= 10^246 */
1824
    U64(0xB7118682, 0xDBB66A77), U64(0x3FBC8C33, 0x221DC2A1), /* ~= 10^247 */
1825
    U64(0xE4D5E823, 0x92A40515), U64(0x0FABAF3F, 0xEAA5334A), /* ~= 10^248 */
1826
    U64(0x8F05B116, 0x3BA6832D), U64(0x29CB4D87, 0xF2A7400E), /* ~= 10^249 */
1827
    U64(0xB2C71D5B, 0xCA9023F8), U64(0x743E20E9, 0xEF511012), /* ~= 10^250 */
1828
    U64(0xDF78E4B2, 0xBD342CF6), U64(0x914DA924, 0x6B255416), /* ~= 10^251 */
1829
    U64(0x8BAB8EEF, 0xB6409C1A), U64(0x1AD089B6, 0xC2F7548E), /* ~= 10^252 */
1830
    U64(0xAE9672AB, 0xA3D0C320), U64(0xA184AC24, 0x73B529B1), /* ~= 10^253 */
1831
    U64(0xDA3C0F56, 0x8CC4F3E8), U64(0xC9E5D72D, 0x90A2741E), /* ~= 10^254 */
1832
    U64(0x88658996, 0x17FB1871), U64(0x7E2FA67C, 0x7A658892), /* ~= 10^255 */
1833
    U64(0xAA7EEBFB, 0x9DF9DE8D), U64(0xDDBB901B, 0x98FEEAB7), /* ~= 10^256 */
1834
    U64(0xD51EA6FA, 0x85785631), U64(0x552A7422, 0x7F3EA565), /* ~= 10^257 */
1835
    U64(0x8533285C, 0x936B35DE), U64(0xD53A8895, 0x8F87275F), /* ~= 10^258 */
1836
    U64(0xA67FF273, 0xB8460356), U64(0x8A892ABA, 0xF368F137), /* ~= 10^259 */
1837
    U64(0xD01FEF10, 0xA657842C), U64(0x2D2B7569, 0xB0432D85), /* ~= 10^260 */
1838
    U64(0x8213F56A, 0x67F6B29B), U64(0x9C3B2962, 0x0E29FC73), /* ~= 10^261 */
1839
    U64(0xA298F2C5, 0x01F45F42), U64(0x8349F3BA, 0x91B47B8F), /* ~= 10^262 */
1840
    U64(0xCB3F2F76, 0x42717713), U64(0x241C70A9, 0x36219A73), /* ~= 10^263 */
1841
    U64(0xFE0EFB53, 0xD30DD4D7), U64(0xED238CD3, 0x83AA0110), /* ~= 10^264 */
1842
    U64(0x9EC95D14, 0x63E8A506), U64(0xF4363804, 0x324A40AA), /* ~= 10^265 */
1843
    U64(0xC67BB459, 0x7CE2CE48), U64(0xB143C605, 0x3EDCD0D5), /* ~= 10^266 */
1844
    U64(0xF81AA16F, 0xDC1B81DA), U64(0xDD94B786, 0x8E94050A), /* ~= 10^267 */
1845
    U64(0x9B10A4E5, 0xE9913128), U64(0xCA7CF2B4, 0x191C8326), /* ~= 10^268 */
1846
    U64(0xC1D4CE1F, 0x63F57D72), U64(0xFD1C2F61, 0x1F63A3F0), /* ~= 10^269 */
1847
    U64(0xF24A01A7, 0x3CF2DCCF), U64(0xBC633B39, 0x673C8CEC), /* ~= 10^270 */
1848
    U64(0x976E4108, 0x8617CA01), U64(0xD5BE0503, 0xE085D813), /* ~= 10^271 */
1849
    U64(0xBD49D14A, 0xA79DBC82), U64(0x4B2D8644, 0xD8A74E18), /* ~= 10^272 */
1850
    U64(0xEC9C459D, 0x51852BA2), U64(0xDDF8E7D6, 0x0ED1219E), /* ~= 10^273 */
1851
    U64(0x93E1AB82, 0x52F33B45), U64(0xCABB90E5, 0xC942B503), /* ~= 10^274 */
1852
    U64(0xB8DA1662, 0xE7B00A17), U64(0x3D6A751F, 0x3B936243), /* ~= 10^275 */
1853
    U64(0xE7109BFB, 0xA19C0C9D), U64(0x0CC51267, 0x0A783AD4), /* ~= 10^276 */
1854
    U64(0x906A617D, 0x450187E2), U64(0x27FB2B80, 0x668B24C5), /* ~= 10^277 */
1855
    U64(0xB484F9DC, 0x9641E9DA), U64(0xB1F9F660, 0x802DEDF6), /* ~= 10^278 */
1856
    U64(0xE1A63853, 0xBBD26451), U64(0x5E7873F8, 0xA0396973), /* ~= 10^279 */
1857
    U64(0x8D07E334, 0x55637EB2), U64(0xDB0B487B, 0x6423E1E8), /* ~= 10^280 */
1858
    U64(0xB049DC01, 0x6ABC5E5F), U64(0x91CE1A9A, 0x3D2CDA62), /* ~= 10^281 */
1859
    U64(0xDC5C5301, 0xC56B75F7), U64(0x7641A140, 0xCC7810FB), /* ~= 10^282 */
1860
    U64(0x89B9B3E1, 0x1B6329BA), U64(0xA9E904C8, 0x7FCB0A9D), /* ~= 10^283 */
1861
    U64(0xAC2820D9, 0x623BF429), U64(0x546345FA, 0x9FBDCD44), /* ~= 10^284 */
1862
    U64(0xD732290F, 0xBACAF133), U64(0xA97C1779, 0x47AD4095), /* ~= 10^285 */
1863
    U64(0x867F59A9, 0xD4BED6C0), U64(0x49ED8EAB, 0xCCCC485D), /* ~= 10^286 */
1864
    U64(0xA81F3014, 0x49EE8C70), U64(0x5C68F256, 0xBFFF5A74), /* ~= 10^287 */
1865
    U64(0xD226FC19, 0x5C6A2F8C), U64(0x73832EEC, 0x6FFF3111), /* ~= 10^288 */
1866
    U64(0x83585D8F, 0xD9C25DB7), U64(0xC831FD53, 0xC5FF7EAB), /* ~= 10^289 */
1867
    U64(0xA42E74F3, 0xD032F525), U64(0xBA3E7CA8, 0xB77F5E55), /* ~= 10^290 */
1868
    U64(0xCD3A1230, 0xC43FB26F), U64(0x28CE1BD2, 0xE55F35EB), /* ~= 10^291 */
1869
    U64(0x80444B5E, 0x7AA7CF85), U64(0x7980D163, 0xCF5B81B3), /* ~= 10^292 */
1870
    U64(0xA0555E36, 0x1951C366), U64(0xD7E105BC, 0xC332621F), /* ~= 10^293 */
1871
    U64(0xC86AB5C3, 0x9FA63440), U64(0x8DD9472B, 0xF3FEFAA7), /* ~= 10^294 */
1872
    U64(0xFA856334, 0x878FC150), U64(0xB14F98F6, 0xF0FEB951), /* ~= 10^295 */
1873
    U64(0x9C935E00, 0xD4B9D8D2), U64(0x6ED1BF9A, 0x569F33D3), /* ~= 10^296 */
1874
    U64(0xC3B83581, 0x09E84F07), U64(0x0A862F80, 0xEC4700C8), /* ~= 10^297 */
1875
    U64(0xF4A642E1, 0x4C6262C8), U64(0xCD27BB61, 0x2758C0FA), /* ~= 10^298 */
1876
    U64(0x98E7E9CC, 0xCFBD7DBD), U64(0x8038D51C, 0xB897789C), /* ~= 10^299 */
1877
    U64(0xBF21E440, 0x03ACDD2C), U64(0xE0470A63, 0xE6BD56C3), /* ~= 10^300 */
1878
    U64(0xEEEA5D50, 0x04981478), U64(0x1858CCFC, 0xE06CAC74), /* ~= 10^301 */
1879
    U64(0x95527A52, 0x02DF0CCB), U64(0x0F37801E, 0x0C43EBC8), /* ~= 10^302 */
1880
    U64(0xBAA718E6, 0x8396CFFD), U64(0xD3056025, 0x8F54E6BA), /* ~= 10^303 */
1881
    U64(0xE950DF20, 0x247C83FD), U64(0x47C6B82E, 0xF32A2069), /* ~= 10^304 */
1882
    U64(0x91D28B74, 0x16CDD27E), U64(0x4CDC331D, 0x57FA5441), /* ~= 10^305 */
1883
    U64(0xB6472E51, 0x1C81471D), U64(0xE0133FE4, 0xADF8E952), /* ~= 10^306 */
1884
    U64(0xE3D8F9E5, 0x63A198E5), U64(0x58180FDD, 0xD97723A6), /* ~= 10^307 */
1885
    U64(0x8E679C2F, 0x5E44FF8F), U64(0x570F09EA, 0xA7EA7648), /* ~= 10^308 */
1886
    U64(0xB201833B, 0x35D63F73), U64(0x2CD2CC65, 0x51E513DA), /* ~= 10^309 */
1887
    U64(0xDE81E40A, 0x034BCF4F), U64(0xF8077F7E, 0xA65E58D1), /* ~= 10^310 */
1888
    U64(0x8B112E86, 0x420F6191), U64(0xFB04AFAF, 0x27FAF782), /* ~= 10^311 */
1889
    U64(0xADD57A27, 0xD29339F6), U64(0x79C5DB9A, 0xF1F9B563), /* ~= 10^312 */
1890
    U64(0xD94AD8B1, 0xC7380874), U64(0x18375281, 0xAE7822BC), /* ~= 10^313 */
1891
    U64(0x87CEC76F, 0x1C830548), U64(0x8F229391, 0x0D0B15B5), /* ~= 10^314 */
1892
    U64(0xA9C2794A, 0xE3A3C69A), U64(0xB2EB3875, 0x504DDB22), /* ~= 10^315 */
1893
    U64(0xD433179D, 0x9C8CB841), U64(0x5FA60692, 0xA46151EB), /* ~= 10^316 */
1894
    U64(0x849FEEC2, 0x81D7F328), U64(0xDBC7C41B, 0xA6BCD333), /* ~= 10^317 */
1895
    U64(0xA5C7EA73, 0x224DEFF3), U64(0x12B9B522, 0x906C0800), /* ~= 10^318 */
1896
    U64(0xCF39E50F, 0xEAE16BEF), U64(0xD768226B, 0x34870A00), /* ~= 10^319 */
1897
    U64(0x81842F29, 0xF2CCE375), U64(0xE6A11583, 0x00D46640), /* ~= 10^320 */
1898
    U64(0xA1E53AF4, 0x6F801C53), U64(0x60495AE3, 0xC1097FD0), /* ~= 10^321 */
1899
    U64(0xCA5E89B1, 0x8B602368), U64(0x385BB19C, 0xB14BDFC4), /* ~= 10^322 */
1900
    U64(0xFCF62C1D, 0xEE382C42), U64(0x46729E03, 0xDD9ED7B5), /* ~= 10^323 */
1901
    U64(0x9E19DB92, 0xB4E31BA9), U64(0x6C07A2C2, 0x6A8346D1)  /* ~= 10^324 */
1902
};
1903
1904
/**
1905
 Get the cached pow10 value from `pow10_sig_table`.
1906
 @param exp10 The exponent of pow(10, e). This value must be in the range
1907
              `POW10_SIG_TABLE_MIN_EXP` to `POW10_SIG_TABLE_MAX_EXP`.
1908
 @param hi    The highest 64 bits of pow(10, e).
1909
 @param lo    The lower 64 bits after `hi`.
1910
 */
1911
4.44M
static_inline void pow10_table_get_sig(i32 exp10, u64 *hi, u64 *lo) {
1912
4.44M
    i32 idx = exp10 - (POW10_SIG_TABLE_MIN_EXP);
1913
4.44M
    *hi = pow10_sig_table[idx * 2];
1914
4.44M
    *lo = pow10_sig_table[idx * 2 + 1];
1915
4.44M
}
1916
1917
/**
1918
 Get the exponent (base 2) for the highest 64-bit significand in
1919
 `pow10_sig_table`.
1920
 */
1921
290k
static_inline void pow10_table_get_exp(i32 exp10, i32 *exp2) {
1922
    /* e2 = floor(log2(pow(10, e))) - 64 + 1 */
1923
    /*    = floor(e * log2(10) - 63)         */
1924
290k
    *exp2 = (exp10 * 217706 - 4128768) >> 16;
1925
290k
}
1926
1927
#endif
1928
1929
1930
1931
/*==============================================================================
1932
 * MARK: - Number and Bit Utils (Private)
1933
 *============================================================================*/
1934
1935
/** Convert bits to double. */
1936
0
static_inline f64 f64_from_bits(u64 u) {
1937
0
    f64 f;
1938
0
    memcpy(&f, &u, sizeof(u));
1939
0
    return f;
1940
0
}
1941
1942
/** Convert double to bits. */
1943
0
static_inline u64 f64_to_bits(f64 f) {
1944
0
    u64 u;
1945
0
    memcpy(&u, &f, sizeof(u));
1946
0
    return u;
1947
0
}
1948
1949
/** Convert float to bits. */
1950
0
static_inline u32 f32_to_bits(f32 f) {
1951
0
    u32 u;
1952
0
    memcpy(&u, &f, sizeof(u));
1953
0
    return u;
1954
0
}
1955
1956
/** Get 'infinity' bits with sign. */
1957
6.75k
static_inline u64 f64_bits_inf(bool sign) {
1958
6.75k
#if YYJSON_HAS_IEEE_754
1959
6.75k
    return F64_BITS_INF | ((u64)sign << 63);
1960
#else
1961
    return f64_to_bits(sign ? (f64)-INFINITY : (f64)INFINITY);
1962
#endif
1963
6.75k
}
1964
1965
/** Returns whether the double value is infinity (not NaN). */
1966
0
static_inline bool f64_is_inf(f64 val) {
1967
0
#if YYJSON_HAS_IEEE_754
1968
0
    return (f64_to_bits(val) & F64_EXP_MASK) == F64_BITS_INF;
1969
0
#else
1970
0
    return val >= (f64)INFINITY || val <= (f64)-INFINITY;
1971
0
#endif
1972
0
}
1973
1974
/** Get 'nan' bits with sign. */
1975
6.43k
static_inline u64 f64_bits_nan(bool sign) {
1976
6.43k
#if YYJSON_HAS_IEEE_754
1977
6.43k
    return F64_BITS_NAN | ((u64)sign << 63);
1978
#else
1979
    return f64_to_bits(sign ? (f64)-NAN : (f64)NAN);
1980
#endif
1981
6.43k
}
1982
1983
/** Casting double to float, allow overflow. */
1984
#if yyjson_has_attribute(no_sanitize)
1985
__attribute__((no_sanitize("undefined")))
1986
#elif yyjson_gcc_available(4, 9, 0)
1987
__attribute__((__no_sanitize_undefined__))
1988
#endif
1989
0
static_inline f32 f64_to_f32(f64 val) {
1990
0
    return (f32)val;
1991
0
}
1992
1993
/** Returns the number of leading 0-bits in value (input should not be 0). */
1994
681k
static_inline u32 u64_lz_bits(u64 v) {
1995
681k
#if GCC_HAS_CLZLL
1996
681k
    return (u32)__builtin_clzll(v);
1997
#elif MSC_HAS_BIT_SCAN_64
1998
    unsigned long r;
1999
    _BitScanReverse64(&r, v);
2000
    return (u32)63 - (u32)r;
2001
#elif MSC_HAS_BIT_SCAN
2002
    unsigned long hi, lo;
2003
    bool hi_set = _BitScanReverse(&hi, (u32)(v >> 32)) != 0;
2004
    _BitScanReverse(&lo, (u32)v);
2005
    hi |= 32;
2006
    return (u32)63 - (u32)(hi_set ? hi : lo);
2007
#else
2008
    /* branchless, use De Bruijn sequence */
2009
    /* see: https://www.chessprogramming.org/BitScan */
2010
    const u8 table[64] = {
2011
        63, 16, 62,  7, 15, 36, 61,  3,  6, 14, 22, 26, 35, 47, 60,  2,
2012
         9,  5, 28, 11, 13, 21, 42, 19, 25, 31, 34, 40, 46, 52, 59,  1,
2013
        17,  8, 37,  4, 23, 27, 48, 10, 29, 12, 43, 20, 32, 41, 53, 18,
2014
        38, 24, 49, 30, 44, 33, 54, 39, 50, 45, 55, 51, 56, 57, 58,  0
2015
    };
2016
    v |= v >> 1;
2017
    v |= v >> 2;
2018
    v |= v >> 4;
2019
    v |= v >> 8;
2020
    v |= v >> 16;
2021
    v |= v >> 32;
2022
    return table[(v * U64(0x03F79D71, 0xB4CB0A89)) >> 58];
2023
#endif
2024
681k
}
2025
2026
/** Returns the number of trailing 0-bits in value (input should not be 0). */
2027
2.01M
static_inline u32 u64_tz_bits(u64 v) {
2028
2.01M
#if GCC_HAS_CTZLL
2029
2.01M
    return (u32)__builtin_ctzll(v);
2030
#elif MSC_HAS_BIT_SCAN_64
2031
    unsigned long r;
2032
    _BitScanForward64(&r, v);
2033
    return (u32)r;
2034
#elif MSC_HAS_BIT_SCAN
2035
    unsigned long lo, hi;
2036
    bool lo_set = _BitScanForward(&lo, (u32)(v)) != 0;
2037
    _BitScanForward(&hi, (u32)(v >> 32));
2038
    hi += 32;
2039
    return lo_set ? lo : hi;
2040
#else
2041
    /* branchless, use De Bruijn sequence */
2042
    /* see: https://www.chessprogramming.org/BitScan */
2043
    const u8 table[64] = {
2044
         0,  1,  2, 53,  3,  7, 54, 27,  4, 38, 41,  8, 34, 55, 48, 28,
2045
        62,  5, 39, 46, 44, 42, 22,  9, 24, 35, 59, 56, 49, 18, 29, 11,
2046
        63, 52,  6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
2047
        51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12
2048
    };
2049
    return table[((v & (~v + 1)) * U64(0x022FDD63, 0xCC95386D)) >> 58];
2050
#endif
2051
2.01M
}
2052
2053
/** Multiplies two 64-bit unsigned integers (a * b),
2054
    returns the 128-bit result as 'hi' and 'lo'. */
2055
5.18M
static_inline void u128_mul(u64 a, u64 b, u64 *hi, u64 *lo) {
2056
5.18M
#if YYJSON_HAS_INT128
2057
5.18M
    u128 m = (u128)a * b;
2058
5.18M
    *hi = (u64)(m >> 64);
2059
5.18M
    *lo = (u64)(m);
2060
#elif MSC_HAS_UMUL128
2061
    *lo = _umul128(a, b, hi);
2062
#else
2063
    u32 a0 = (u32)(a), a1 = (u32)(a >> 32);
2064
    u32 b0 = (u32)(b), b1 = (u32)(b >> 32);
2065
    u64 p00 = (u64)a0 * b0, p01 = (u64)a0 * b1;
2066
    u64 p10 = (u64)a1 * b0, p11 = (u64)a1 * b1;
2067
    u64 m0 = p01 + (p00 >> 32);
2068
    u32 m00 = (u32)(m0), m01 = (u32)(m0 >> 32);
2069
    u64 m1 = p10 + m00;
2070
    u32 m10 = (u32)(m1), m11 = (u32)(m1 >> 32);
2071
    *hi = p11 + m01 + m11;
2072
    *lo = ((u64)m10 << 32) | (u32)p00;
2073
#endif
2074
5.18M
}
2075
2076
/** Multiplies two 64-bit unsigned integers and add a value (a * b + c),
2077
    returns the 128-bit result as 'hi' and 'lo'. */
2078
15.2M
static_inline void u128_mul_add(u64 a, u64 b, u64 c, u64 *hi, u64 *lo) {
2079
15.2M
#if YYJSON_HAS_INT128
2080
15.2M
    u128 m = (u128)a * b + c;
2081
15.2M
    *hi = (u64)(m >> 64);
2082
15.2M
    *lo = (u64)(m);
2083
#else
2084
    u64 h, l, t;
2085
    u128_mul(a, b, &h, &l);
2086
    t = l + c;
2087
    h += (u64)(((t < l) | (t < c)));
2088
    *hi = h;
2089
    *lo = t;
2090
#endif
2091
15.2M
}
2092
2093
2094
2095
/*==============================================================================
2096
 * MARK: - File Utils (Private)
2097
 * These functions are used to read and write JSON files.
2098
 *============================================================================*/
2099
2100
#if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE
2101
2102
#define YYJSON_FOPEN_E
2103
#if !defined(_MSC_VER) && defined(__GLIBC__) && defined(__GLIBC_PREREQ)
2104
#   if __GLIBC_PREREQ(2, 7)
2105
#       undef YYJSON_FOPEN_E
2106
0
#       define YYJSON_FOPEN_E "e" /* glibc extension to enable O_CLOEXEC */
2107
#   endif
2108
#endif
2109
2110
0
static_inline FILE *fopen_safe(const char *path, const char *mode) {
2111
#if YYJSON_MSC_VER >= 1400
2112
    FILE *file = NULL;
2113
    if (fopen_s(&file, path, mode) != 0) return NULL;
2114
    return file;
2115
#else
2116
0
    return fopen(path, mode);
2117
0
#endif
2118
0
}
2119
2120
0
static_inline FILE *fopen_readonly(const char *path) {
2121
0
    return fopen_safe(path, "rb" YYJSON_FOPEN_E);
2122
0
}
2123
2124
0
static_inline FILE *fopen_writeonly(const char *path) {
2125
0
    return fopen_safe(path, "wb" YYJSON_FOPEN_E);
2126
0
}
2127
2128
0
static_inline usize fread_safe(void *buf, usize size, FILE *file) {
2129
#if YYJSON_MSC_VER >= 1400
2130
    return fread_s(buf, size, 1, size, file);
2131
#else
2132
0
    return fread(buf, 1, size, file);
2133
0
#endif
2134
0
}
2135
2136
#endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */
2137
2138
2139
2140
/*==============================================================================
2141
 * MARK: - Size Utils (Private)
2142
 * These functions are used for memory allocation.
2143
 *============================================================================*/
2144
2145
/** Returns whether the size is overflow after increment. */
2146
0
static_inline bool size_add_is_overflow(usize size, usize add) {
2147
0
    return size > (size + add);
2148
0
}
2149
2150
/** Returns whether the size is power of 2 (size should not be 0). */
2151
36.5k
static_inline bool size_is_pow2(usize size) {
2152
36.5k
    return (size & (size - 1)) == 0;
2153
36.5k
}
2154
2155
/** Align size upwards (may overflow). */
2156
36.5k
static_inline usize size_align_up(usize size, usize align) {
2157
36.5k
    if (size_is_pow2(align)) {
2158
36.5k
        return (size + (align - 1)) & ~(align - 1);
2159
36.5k
    } else {
2160
0
        return size + align - (size + align - 1) % align - 1;
2161
0
    }
2162
36.5k
}
2163
2164
/** Align size downwards. */
2165
0
static_inline usize size_align_down(usize size, usize align) {
2166
0
    if (size_is_pow2(align)) {
2167
0
        return size & ~(align - 1);
2168
0
    } else {
2169
0
        return size - (size % align);
2170
0
    }
2171
0
}
2172
2173
/** Align address upwards (may overflow). */
2174
0
static_inline void *mem_align_up(void *mem, usize align) {
2175
0
    usize size;
2176
0
    memcpy(&size, &mem, sizeof(usize));
2177
0
    size = size_align_up(size, align);
2178
0
    memcpy(&mem, &size, sizeof(usize));
2179
0
    return mem;
2180
0
}
2181
2182
2183
2184
/*==============================================================================
2185
 * MARK: - Null Memory Allocator (Private)
2186
 * This allocator is just a placeholder to ensure that the internal
2187
 * malloc/realloc/free function pointers are not null.
2188
 *============================================================================*/
2189
2190
0
static void *null_malloc(void *ctx, usize size) {
2191
0
    return NULL;
2192
0
}
2193
2194
0
static void *null_realloc(void *ctx, void *ptr, usize old_size, usize size) {
2195
0
    return NULL;
2196
0
}
2197
2198
0
static void null_free(void *ctx, void *ptr) {
2199
0
    return;
2200
0
}
2201
2202
static const yyjson_alc YYJSON_NULL_ALC = {
2203
    null_malloc, null_realloc, null_free, NULL
2204
};
2205
2206
2207
2208
/*==============================================================================
2209
 * MARK: - Default Memory Allocator (Private)
2210
 * This is a simple libc memory allocator wrapper.
2211
 *============================================================================*/
2212
2213
#if defined(YYJSON_CUSTOM_ALC)
2214
2215
/* user-provided via macro */
2216
extern const yyjson_alc YYJSON_CUSTOM_ALC;
2217
#define YYJSON_DEFAULT_ALC YYJSON_CUSTOM_ALC
2218
2219
#elif YYJSON_FREESTANDING
2220
2221
/* null allocator */
2222
static const yyjson_alc YYJSON_DEFAULT_ALC = {
2223
    null_malloc, null_realloc, null_free, NULL
2224
};
2225
2226
#else /* YYJSON_FREESTANDING */
2227
2228
/* default libc allocator */
2229
0
static void *default_malloc(void *ctx, usize size) {
2230
0
    return malloc(size);
2231
0
}
2232
0
static void *default_realloc(void *ctx, void *ptr, usize old_size, usize size) {
2233
0
    return realloc(ptr, size);
2234
0
}
2235
0
static void default_free(void *ctx, void *ptr) {
2236
0
    free(ptr);
2237
0
}
2238
static const yyjson_alc YYJSON_DEFAULT_ALC = {
2239
    default_malloc, default_realloc, default_free, NULL
2240
};
2241
2242
#endif /* YYJSON_FREESTANDING */
2243
2244
2245
2246
/*==============================================================================
2247
 * MARK: - Pool Memory Allocator (Public)
2248
 * This allocator is initialized with a fixed-size buffer.
2249
 * The buffer is split into multiple memory chunks for memory allocation.
2250
 *============================================================================*/
2251
2252
/** memory chunk header */
2253
typedef struct pool_chunk {
2254
    usize size; /* chunk memory size, including chunk header */
2255
    struct pool_chunk *next; /* linked list, nullable */
2256
    /* char mem[]; flexible array member */
2257
} pool_chunk;
2258
2259
/** allocator ctx header */
2260
typedef struct pool_ctx {
2261
    usize size; /* total memory size, including ctx header */
2262
    pool_chunk *free_list; /* linked list, nullable */
2263
    /* pool_chunk chunks[]; flexible array member */
2264
} pool_ctx;
2265
2266
/** align up the input size to chunk size */
2267
0
static_inline void pool_size_align(usize *size) {
2268
0
    *size = size_align_up(*size, sizeof(pool_chunk)) + sizeof(pool_chunk);
2269
0
}
2270
2271
0
static void *pool_malloc(void *ctx_ptr, usize size) {
2272
    /* assert(size != 0) */
2273
0
    pool_ctx *ctx = (pool_ctx *)ctx_ptr;
2274
0
    pool_chunk *next, *prev = NULL, *cur = ctx->free_list;
2275
2276
0
    if (unlikely(size >= ctx->size)) return NULL;
2277
0
    pool_size_align(&size);
2278
2279
0
    while (cur) {
2280
0
        if (cur->size < size) {
2281
            /* not enough space, try next chunk */
2282
0
            prev = cur;
2283
0
            cur = cur->next;
2284
0
            continue;
2285
0
        }
2286
0
        if (cur->size >= size + sizeof(pool_chunk) * 2) {
2287
            /* too much space, split this chunk */
2288
0
            next = (pool_chunk *)(void *)((u8 *)cur + size);
2289
0
            next->size = cur->size - size;
2290
0
            next->next = cur->next;
2291
0
            cur->size = size;
2292
0
        } else {
2293
            /* just enough space, use whole chunk */
2294
0
            next = cur->next;
2295
0
        }
2296
0
        if (prev) prev->next = next;
2297
0
        else ctx->free_list = next;
2298
0
        return (void *)(cur + 1);
2299
0
    }
2300
0
    return NULL;
2301
0
}
2302
2303
0
static void pool_free(void *ctx_ptr, void *ptr) {
2304
    /* assert(ptr != NULL) */
2305
0
    pool_ctx *ctx = (pool_ctx *)ctx_ptr;
2306
0
    pool_chunk *cur = ((pool_chunk *)ptr) - 1;
2307
0
    pool_chunk *prev = NULL, *next = ctx->free_list;
2308
2309
0
    while (next && next < cur) {
2310
0
        prev = next;
2311
0
        next = next->next;
2312
0
    }
2313
0
    if (prev) prev->next = cur;
2314
0
    else ctx->free_list = cur;
2315
0
    cur->next = next;
2316
2317
0
    if (next && ((u8 *)cur + cur->size) == (u8 *)next) {
2318
        /* merge cur to higher chunk */
2319
0
        cur->size += next->size;
2320
0
        cur->next = next->next;
2321
0
    }
2322
0
    if (prev && ((u8 *)prev + prev->size) == (u8 *)cur) {
2323
        /* merge cur to lower chunk */
2324
0
        prev->size += cur->size;
2325
0
        prev->next = cur->next;
2326
0
    }
2327
0
}
2328
2329
static void *pool_realloc(void *ctx_ptr, void *ptr,
2330
0
                          usize old_size, usize size) {
2331
    /* assert(ptr != NULL && size != 0 && old_size < size) */
2332
0
    pool_ctx *ctx = (pool_ctx *)ctx_ptr;
2333
0
    pool_chunk *cur = ((pool_chunk *)ptr) - 1, *prev, *next, *tmp;
2334
2335
    /* check size */
2336
0
    if (unlikely(size >= ctx->size)) return NULL;
2337
0
    pool_size_align(&old_size);
2338
0
    pool_size_align(&size);
2339
0
    if (unlikely(old_size == size)) return ptr;
2340
2341
    /* find next and prev chunk */
2342
0
    prev = NULL;
2343
0
    next = ctx->free_list;
2344
0
    while (next && next < cur) {
2345
0
        prev = next;
2346
0
        next = next->next;
2347
0
    }
2348
2349
0
    if ((u8 *)cur + cur->size == (u8 *)next && cur->size + next->size >= size) {
2350
        /* merge to higher chunk if they are contiguous */
2351
0
        usize free_size = cur->size + next->size - size;
2352
0
        if (free_size > sizeof(pool_chunk) * 2) {
2353
0
            tmp = (pool_chunk *)(void *)((u8 *)cur + size);
2354
0
            if (prev) prev->next = tmp;
2355
0
            else ctx->free_list = tmp;
2356
0
            tmp->next = next->next;
2357
0
            tmp->size = free_size;
2358
0
            cur->size = size;
2359
0
        } else {
2360
0
            if (prev) prev->next = next->next;
2361
0
            else ctx->free_list = next->next;
2362
0
            cur->size += next->size;
2363
0
        }
2364
0
        return ptr;
2365
0
    } else {
2366
        /* fallback to malloc and memcpy */
2367
0
        void *new_ptr = pool_malloc(ctx_ptr, size - sizeof(pool_chunk));
2368
0
        if (new_ptr) {
2369
0
            memcpy(new_ptr, ptr, cur->size - sizeof(pool_chunk));
2370
0
            pool_free(ctx_ptr, ptr);
2371
0
        }
2372
0
        return new_ptr;
2373
0
    }
2374
0
}
2375
2376
0
bool yyjson_alc_pool_init(yyjson_alc *alc, void *buf, usize size) {
2377
0
    pool_chunk *chunk;
2378
0
    pool_ctx *ctx;
2379
2380
0
    if (unlikely(!alc)) return false;
2381
0
    *alc = YYJSON_NULL_ALC;
2382
0
    if (size < sizeof(pool_ctx) * 4) return false;
2383
0
    ctx = (pool_ctx *)mem_align_up(buf, sizeof(pool_ctx));
2384
0
    if (unlikely(!ctx)) return false;
2385
0
    size -= (usize)((u8 *)ctx - (u8 *)buf);
2386
0
    size = size_align_down(size, sizeof(pool_ctx));
2387
2388
0
    chunk = (pool_chunk *)(ctx + 1);
2389
0
    chunk->size = size - sizeof(pool_ctx);
2390
0
    chunk->next = NULL;
2391
0
    ctx->size = size;
2392
0
    ctx->free_list = chunk;
2393
2394
0
    alc->malloc = pool_malloc;
2395
0
    alc->realloc = pool_realloc;
2396
0
    alc->free = pool_free;
2397
0
    alc->ctx = (void *)ctx;
2398
0
    return true;
2399
0
}
2400
2401
2402
2403
/*==============================================================================
2404
 * MARK: - Dynamic Memory Allocator (Public)
2405
 * This allocator allocates memory on demand and does not immediately release
2406
 * unused memory. Instead, it places the unused memory into a freelist for
2407
 * potential reuse in the future. It is only when the entire allocator is
2408
 * destroyed that all previously allocated memory is released at once.
2409
 *============================================================================*/
2410
2411
/** memory chunk header */
2412
typedef struct dyn_chunk {
2413
    usize size; /* chunk size, including header */
2414
    struct dyn_chunk *next;
2415
    /* char mem[]; flexible array member */
2416
} dyn_chunk;
2417
2418
/** allocator ctx header */
2419
typedef struct {
2420
    dyn_chunk free_list; /* dummy header, sorted from small to large */
2421
    dyn_chunk used_list; /* dummy header */
2422
} dyn_ctx;
2423
2424
/** align up the input size to chunk size */
2425
0
static_inline bool dyn_size_align(usize *size) {
2426
0
    usize alc_size = *size + sizeof(dyn_chunk);
2427
0
    alc_size = size_align_up(alc_size, YYJSON_ALC_DYN_MIN_SIZE);
2428
0
    if (unlikely(alc_size < *size)) return false; /* overflow */
2429
0
    *size = alc_size;
2430
0
    return true;
2431
0
}
2432
2433
/** remove a chunk from list (the chunk must already be in the list) */
2434
0
static_inline void dyn_chunk_list_remove(dyn_chunk *list, dyn_chunk *chunk) {
2435
0
    dyn_chunk *prev = list, *cur;
2436
0
    for (cur = prev->next; cur; cur = cur->next) {
2437
0
        if (cur == chunk) {
2438
0
            prev->next = cur->next;
2439
0
            cur->next = NULL;
2440
0
            return;
2441
0
        }
2442
0
        prev = cur;
2443
0
    }
2444
0
}
2445
2446
/** add a chunk to list header (the chunk must not be in the list) */
2447
0
static_inline void dyn_chunk_list_add(dyn_chunk *list, dyn_chunk *chunk) {
2448
0
    chunk->next = list->next;
2449
0
    list->next = chunk;
2450
0
}
2451
2452
0
static void *dyn_malloc(void *ctx_ptr, usize size) {
2453
    /* assert(size != 0) */
2454
0
    const yyjson_alc def = YYJSON_DEFAULT_ALC;
2455
0
    dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
2456
0
    dyn_chunk *chunk, *prev;
2457
0
    if (unlikely(!dyn_size_align(&size))) return NULL;
2458
2459
    /* freelist is empty, create new chunk */
2460
0
    if (!ctx->free_list.next) {
2461
0
        chunk = (dyn_chunk *)def.malloc(def.ctx, size);
2462
0
        if (unlikely(!chunk)) return NULL;
2463
0
        chunk->size = size;
2464
0
        chunk->next = NULL;
2465
0
        dyn_chunk_list_add(&ctx->used_list, chunk);
2466
0
        return (void *)(chunk + 1);
2467
0
    }
2468
2469
    /* find a large enough chunk, or resize the largest chunk */
2470
0
    prev = &ctx->free_list;
2471
0
    while (true) {
2472
0
        chunk = prev->next;
2473
0
        if (chunk->size >= size) { /* enough size, reuse this chunk */
2474
0
            prev->next = chunk->next;
2475
0
            dyn_chunk_list_add(&ctx->used_list, chunk);
2476
0
            return (void *)(chunk + 1);
2477
0
        }
2478
0
        if (!chunk->next) { /* resize the largest chunk */
2479
0
            chunk = (dyn_chunk *)def.realloc(def.ctx, chunk, chunk->size, size);
2480
0
            if (unlikely(!chunk)) return NULL;
2481
0
            prev->next = NULL;
2482
0
            chunk->size = size;
2483
0
            dyn_chunk_list_add(&ctx->used_list, chunk);
2484
0
            return (void *)(chunk + 1);
2485
0
        }
2486
0
        prev = chunk;
2487
0
    }
2488
0
}
2489
2490
static void *dyn_realloc(void *ctx_ptr, void *ptr,
2491
0
                          usize old_size, usize size) {
2492
    /* assert(ptr != NULL && size != 0 && old_size < size) */
2493
0
    const yyjson_alc def = YYJSON_DEFAULT_ALC;
2494
0
    dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
2495
0
    dyn_chunk *new_chunk, *chunk = (dyn_chunk *)ptr - 1;
2496
0
    if (unlikely(!dyn_size_align(&size))) return NULL;
2497
0
    if (chunk->size >= size) return ptr;
2498
2499
0
    dyn_chunk_list_remove(&ctx->used_list, chunk);
2500
0
    new_chunk = (dyn_chunk *)def.realloc(def.ctx, chunk, chunk->size, size);
2501
0
    if (likely(new_chunk)) {
2502
0
        new_chunk->size = size;
2503
0
        chunk = new_chunk;
2504
0
    }
2505
0
    dyn_chunk_list_add(&ctx->used_list, chunk);
2506
0
    return new_chunk ? (void *)(new_chunk + 1) : NULL;
2507
0
}
2508
2509
0
static void dyn_free(void *ctx_ptr, void *ptr) {
2510
    /* assert(ptr != NULL) */
2511
0
    dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
2512
0
    dyn_chunk *chunk = (dyn_chunk *)ptr - 1, *prev;
2513
2514
0
    dyn_chunk_list_remove(&ctx->used_list, chunk);
2515
0
    for (prev = &ctx->free_list; prev; prev = prev->next) {
2516
0
        if (!prev->next || prev->next->size >= chunk->size) {
2517
0
            chunk->next = prev->next;
2518
0
            prev->next = chunk;
2519
0
            break;
2520
0
        }
2521
0
    }
2522
0
}
2523
2524
0
yyjson_alc *yyjson_alc_dyn_new(void) {
2525
0
    const yyjson_alc def = YYJSON_DEFAULT_ALC;
2526
0
    usize hdr_len = sizeof(yyjson_alc) + sizeof(dyn_ctx);
2527
0
    yyjson_alc *alc;
2528
0
    dyn_ctx *ctx;
2529
0
    alc = (yyjson_alc *)def.malloc(def.ctx, hdr_len);
2530
0
    if (unlikely(!alc)) return NULL;
2531
0
    ctx = (dyn_ctx *)(void *)(alc + 1);
2532
0
    alc->malloc = dyn_malloc;
2533
0
    alc->realloc = dyn_realloc;
2534
0
    alc->free = dyn_free;
2535
0
    alc->ctx = alc + 1;
2536
0
    memset(ctx, 0, sizeof(*ctx));
2537
0
    return alc;
2538
0
}
2539
2540
0
void yyjson_alc_dyn_free(yyjson_alc *alc) {
2541
0
    const yyjson_alc def = YYJSON_DEFAULT_ALC;
2542
0
    dyn_ctx *ctx;
2543
0
    dyn_chunk *chunk, *next;
2544
0
    if (unlikely(!alc)) return;
2545
0
    ctx = (dyn_ctx *)(void *)(alc + 1);
2546
0
    for (chunk = ctx->free_list.next; chunk; chunk = next) {
2547
0
        next = chunk->next;
2548
0
        def.free(def.ctx, chunk);
2549
0
    }
2550
0
    for (chunk = ctx->used_list.next; chunk; chunk = next) {
2551
0
        next = chunk->next;
2552
0
        def.free(def.ctx, chunk);
2553
0
    }
2554
0
    def.free(def.ctx, alc);
2555
0
}
2556
2557
2558
2559
/*==============================================================================
2560
 * MARK: - JSON Struct Utils (Public)
2561
 * These functions are used for creating, copying, releasing, and comparing
2562
 * JSON documents and values. They are widely used throughout this library.
2563
 *============================================================================*/
2564
2565
static_inline void unsafe_yyjson_str_pool_release(yyjson_str_pool *pool,
2566
30.5k
                                                  yyjson_alc *alc) {
2567
30.5k
    yyjson_str_chunk *chunk = pool->chunks, *next;
2568
51.0k
    while (chunk) {
2569
20.4k
        next = chunk->next;
2570
20.4k
        alc->free(alc->ctx, chunk);
2571
20.4k
        chunk = next;
2572
20.4k
    }
2573
30.5k
}
2574
2575
static_inline void unsafe_yyjson_val_pool_release(yyjson_val_pool *pool,
2576
30.5k
                                                  yyjson_alc *alc) {
2577
30.5k
    yyjson_val_chunk *chunk = pool->chunks, *next;
2578
76.2k
    while (chunk) {
2579
45.7k
        next = chunk->next;
2580
45.7k
        alc->free(alc->ctx, chunk);
2581
45.7k
        chunk = next;
2582
45.7k
    }
2583
30.5k
}
2584
2585
bool unsafe_yyjson_str_pool_grow(yyjson_str_pool *pool,
2586
20.5k
                                 const yyjson_alc *alc, usize len) {
2587
20.5k
    yyjson_str_chunk *chunk;
2588
20.5k
    usize size, max_len;
2589
2590
    /* create a new chunk */
2591
20.5k
    max_len = USIZE_MAX - sizeof(yyjson_str_chunk);
2592
20.5k
    if (unlikely(len > max_len)) return false;
2593
20.5k
    size = len + sizeof(yyjson_str_chunk);
2594
20.5k
    size = yyjson_max(pool->chunk_size, size);
2595
20.5k
    chunk = (yyjson_str_chunk *)alc->malloc(alc->ctx, size);
2596
20.5k
    if (unlikely(!chunk)) return false;
2597
2598
    /* insert the new chunk as the head of the linked list */
2599
20.4k
    chunk->next = pool->chunks;
2600
20.4k
    chunk->chunk_size = size;
2601
20.4k
    pool->chunks = chunk;
2602
20.4k
    pool->cur = (char *)chunk + sizeof(yyjson_str_chunk);
2603
20.4k
    pool->end = (char *)chunk + size;
2604
2605
    /* the next chunk is twice the size of the current one */
2606
20.4k
    size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max);
2607
20.4k
    if (size < pool->chunk_size) size = pool->chunk_size_max; /* overflow */
2608
20.4k
    pool->chunk_size = size;
2609
20.4k
    return true;
2610
20.5k
}
2611
2612
bool unsafe_yyjson_val_pool_grow(yyjson_val_pool *pool,
2613
45.8k
                                 const yyjson_alc *alc, usize count) {
2614
45.8k
    yyjson_val_chunk *chunk;
2615
45.8k
    usize size, max_count;
2616
2617
    /* create a new chunk */
2618
45.8k
    max_count = USIZE_MAX / sizeof(yyjson_mut_val) - 1;
2619
45.8k
    if (unlikely(count > max_count)) return false;
2620
45.8k
    size = (count + 1) * sizeof(yyjson_mut_val);
2621
45.8k
    size = yyjson_max(pool->chunk_size, size);
2622
45.8k
    chunk = (yyjson_val_chunk *)alc->malloc(alc->ctx, size);
2623
45.8k
    if (unlikely(!chunk)) return false;
2624
2625
    /* insert the new chunk as the head of the linked list */
2626
45.7k
    chunk->next = pool->chunks;
2627
45.7k
    chunk->chunk_size = size;
2628
45.7k
    pool->chunks = chunk;
2629
45.7k
    pool->cur = (yyjson_mut_val *)(void *)((u8 *)chunk) + 1;
2630
45.7k
    pool->end = (yyjson_mut_val *)(void *)((u8 *)chunk + size);
2631
2632
    /* the next chunk is twice the size of the current one */
2633
45.7k
    size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max);
2634
45.7k
    if (size < pool->chunk_size) size = pool->chunk_size_max; /* overflow */
2635
45.7k
    pool->chunk_size = size;
2636
45.7k
    return true;
2637
45.8k
}
2638
2639
0
bool yyjson_mut_doc_set_str_pool_size(yyjson_mut_doc *doc, size_t len) {
2640
0
    usize max_size = USIZE_MAX - sizeof(yyjson_str_chunk);
2641
0
    if (!doc || !len || len > max_size) return false;
2642
0
    doc->str_pool.chunk_size = len + sizeof(yyjson_str_chunk);
2643
0
    return true;
2644
0
}
2645
2646
0
bool yyjson_mut_doc_set_val_pool_size(yyjson_mut_doc *doc, size_t count) {
2647
0
    usize max_count = USIZE_MAX / sizeof(yyjson_mut_val) - 1;
2648
0
    if (!doc || !count || count > max_count) return false;
2649
0
    doc->val_pool.chunk_size = (count + 1) * sizeof(yyjson_mut_val);
2650
0
    return true;
2651
0
}
2652
2653
68.8k
void yyjson_mut_doc_free(yyjson_mut_doc *doc) {
2654
68.8k
    if (doc) {
2655
30.5k
        yyjson_alc alc = doc->alc;
2656
30.5k
        memset(&doc->alc, 0, sizeof(alc));
2657
30.5k
        unsafe_yyjson_str_pool_release(&doc->str_pool, &alc);
2658
30.5k
        unsafe_yyjson_val_pool_release(&doc->val_pool, &alc);
2659
30.5k
        alc.free(alc.ctx, doc);
2660
30.5k
    }
2661
68.8k
}
2662
2663
30.5k
yyjson_mut_doc *yyjson_mut_doc_new(const yyjson_alc *alc) {
2664
30.5k
    yyjson_mut_doc *doc;
2665
30.5k
    if (!alc) alc = &YYJSON_DEFAULT_ALC;
2666
30.5k
    doc = (yyjson_mut_doc *)alc->malloc(alc->ctx, sizeof(yyjson_mut_doc));
2667
30.5k
    if (!doc) return NULL;
2668
30.5k
    memset(doc, 0, sizeof(yyjson_mut_doc));
2669
2670
30.5k
    doc->alc = *alc;
2671
30.5k
    doc->str_pool.chunk_size = YYJSON_MUT_DOC_STR_POOL_INIT_SIZE;
2672
30.5k
    doc->str_pool.chunk_size_max = YYJSON_MUT_DOC_STR_POOL_MAX_SIZE;
2673
30.5k
    doc->val_pool.chunk_size = YYJSON_MUT_DOC_VAL_POOL_INIT_SIZE;
2674
30.5k
    doc->val_pool.chunk_size_max = YYJSON_MUT_DOC_VAL_POOL_MAX_SIZE;
2675
30.5k
    return doc;
2676
30.5k
}
2677
2678
yyjson_mut_doc *yyjson_doc_mut_copy(const yyjson_doc *doc,
2679
49.2k
                                    const yyjson_alc *alc) {
2680
49.2k
    yyjson_mut_doc *m_doc;
2681
49.2k
    yyjson_mut_val *m_val;
2682
2683
49.2k
    if (!doc || !doc->root) return NULL;
2684
11.0k
    m_doc = yyjson_mut_doc_new(alc);
2685
11.0k
    if (!m_doc) return NULL;
2686
11.0k
    m_val = yyjson_val_mut_copy(m_doc, doc->root);
2687
11.0k
    if (!m_val) {
2688
0
        yyjson_mut_doc_free(m_doc);
2689
0
        return NULL;
2690
0
    }
2691
11.0k
    yyjson_mut_doc_set_root(m_doc, m_val);
2692
11.0k
    return m_doc;
2693
11.0k
}
2694
2695
yyjson_mut_doc *yyjson_mut_doc_mut_copy(const yyjson_mut_doc *doc,
2696
0
                                        const yyjson_alc *alc) {
2697
0
    yyjson_mut_doc *m_doc;
2698
0
    yyjson_mut_val *m_val;
2699
2700
0
    if (!doc) return NULL;
2701
0
    if (!doc->root) return yyjson_mut_doc_new(alc);
2702
2703
0
    m_doc = yyjson_mut_doc_new(alc);
2704
0
    if (!m_doc) return NULL;
2705
0
    m_val = yyjson_mut_val_mut_copy(m_doc, doc->root);
2706
0
    if (!m_val) {
2707
0
        yyjson_mut_doc_free(m_doc);
2708
0
        return NULL;
2709
0
    }
2710
0
    yyjson_mut_doc_set_root(m_doc, m_val);
2711
0
    return m_doc;
2712
0
}
2713
2714
yyjson_mut_val *yyjson_val_mut_copy(yyjson_mut_doc *m_doc,
2715
75.3k
                                    const yyjson_val *i_vals) {
2716
    /*
2717
     The immutable object or array stores all sub-values in a contiguous memory,
2718
     We copy them to another contiguous memory as mutable values,
2719
     then reconnect the mutable values with the original relationship.
2720
     */
2721
75.3k
    usize i_vals_len;
2722
75.3k
    yyjson_mut_val *m_vals, *m_val;
2723
75.3k
    yyjson_val *i_val, *i_end;
2724
2725
75.3k
    if (!m_doc || !i_vals) return NULL;
2726
75.3k
    i_end = unsafe_yyjson_get_next(i_vals);
2727
75.3k
    i_vals_len = (usize)(unsafe_yyjson_get_next(i_vals) - i_vals);
2728
75.3k
    m_vals = unsafe_yyjson_mut_val(m_doc, i_vals_len);
2729
75.3k
    if (!m_vals) return NULL;
2730
75.3k
    i_val = constcast(yyjson_val *)i_vals;
2731
75.3k
    m_val = m_vals;
2732
2733
4.20M
    for (; i_val < i_end; i_val++, m_val++) {
2734
4.12M
        yyjson_type type = unsafe_yyjson_get_type(i_val);
2735
4.12M
        m_val->tag = i_val->tag;
2736
4.12M
        m_val->uni.u64 = i_val->uni.u64;
2737
4.12M
        if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
2738
255k
            const char *str = i_val->uni.str;
2739
255k
            usize str_len = unsafe_yyjson_get_len(i_val);
2740
255k
            m_val->uni.str = unsafe_yyjson_mut_strncpy(m_doc, str, str_len);
2741
255k
            if (!m_val->uni.str) return NULL;
2742
3.87M
        } else if (type == YYJSON_TYPE_ARR) {
2743
1.01M
            usize len = unsafe_yyjson_get_len(i_val);
2744
1.01M
            if (len > 0) {
2745
670k
                yyjson_val *ii_val = i_val + 1, *ii_next;
2746
670k
                yyjson_mut_val *mm_val = m_val + 1, *mm_ctn = m_val, *mm_next;
2747
3.76M
                while (len-- > 1) {
2748
3.09M
                    ii_next = unsafe_yyjson_get_next(ii_val);
2749
3.09M
                    mm_next = mm_val + (ii_next - ii_val);
2750
3.09M
                    mm_val->next = mm_next;
2751
3.09M
                    ii_val = ii_next;
2752
3.09M
                    mm_val = mm_next;
2753
3.09M
                }
2754
670k
                mm_val->next = mm_ctn + 1;
2755
670k
                mm_ctn->uni.ptr = mm_val;
2756
670k
            }
2757
2.85M
        } else if (type == YYJSON_TYPE_OBJ) {
2758
55.3k
            usize len = unsafe_yyjson_get_len(i_val);
2759
55.3k
            if (len > 0) {
2760
33.3k
                yyjson_val *ii_key = i_val + 1, *ii_nextkey;
2761
33.3k
                yyjson_mut_val *mm_key = m_val + 1, *mm_ctn = m_val;
2762
33.3k
                yyjson_mut_val *mm_nextkey;
2763
142k
                while (len-- > 1) {
2764
109k
                    ii_nextkey = unsafe_yyjson_get_next(ii_key + 1);
2765
109k
                    mm_nextkey = mm_key + (ii_nextkey - ii_key);
2766
109k
                    mm_key->next = mm_key + 1;
2767
109k
                    mm_key->next->next = mm_nextkey;
2768
109k
                    ii_key = ii_nextkey;
2769
109k
                    mm_key = mm_nextkey;
2770
109k
                }
2771
33.3k
                mm_key->next = mm_key + 1;
2772
33.3k
                mm_key->next->next = mm_ctn + 1;
2773
33.3k
                mm_ctn->uni.ptr = mm_key;
2774
33.3k
            }
2775
55.3k
        }
2776
4.12M
    }
2777
75.3k
    return m_vals;
2778
75.3k
}
2779
2780
static yyjson_mut_val *unsafe_yyjson_mut_val_mut_copy(
2781
3.06G
    yyjson_mut_doc *m_doc, const yyjson_mut_val *m_vals) {
2782
    /*
2783
     The mutable object or array stores all sub-values in a circular linked
2784
     list, so we can traverse them in the same loop. The traversal starts from
2785
     the last item, continues with the first item in a list, and ends with the
2786
     second to last item, which needs to be linked to the last item to close the
2787
     circle.
2788
     */
2789
3.06G
    yyjson_mut_val *m_val = unsafe_yyjson_mut_val(m_doc, 1);
2790
3.06G
    if (unlikely(!m_val)) return NULL;
2791
3.06G
    m_val->tag = m_vals->tag;
2792
2793
3.06G
    switch (unsafe_yyjson_get_type(m_vals)) {
2794
693M
        case YYJSON_TYPE_OBJ:
2795
998M
        case YYJSON_TYPE_ARR:
2796
998M
            if (unsafe_yyjson_get_len(m_vals) > 0) {
2797
907M
                yyjson_mut_val *last = (yyjson_mut_val *)m_vals->uni.ptr;
2798
907M
                yyjson_mut_val *next = last->next, *prev;
2799
907M
                prev = unsafe_yyjson_mut_val_mut_copy(m_doc, last);
2800
907M
                if (!prev) return NULL;
2801
907M
                m_val->uni.ptr = (void *)prev;
2802
3.06G
                while (next != last) {
2803
2.16G
                    prev->next = unsafe_yyjson_mut_val_mut_copy(m_doc, next);
2804
2.16G
                    if (!prev->next) return NULL;
2805
2.16G
                    prev = prev->next;
2806
2.16G
                    next = next->next;
2807
2.16G
                }
2808
907M
                prev->next = (yyjson_mut_val *)m_val->uni.ptr;
2809
907M
            }
2810
998M
            break;
2811
998M
        case YYJSON_TYPE_RAW:
2812
800M
        case YYJSON_TYPE_STR: {
2813
800M
            const char *str = m_vals->uni.str;
2814
800M
            usize str_len = unsafe_yyjson_get_len(m_vals);
2815
800M
            m_val->uni.str = unsafe_yyjson_mut_strncpy(m_doc, str, str_len);
2816
800M
            if (!m_val->uni.str) return NULL;
2817
800M
            break;
2818
800M
        }
2819
1.26G
        default:
2820
1.26G
            m_val->uni = m_vals->uni;
2821
1.26G
            break;
2822
3.06G
    }
2823
3.06G
    return m_val;
2824
3.06G
}
2825
2826
yyjson_mut_val *yyjson_mut_val_mut_copy(yyjson_mut_doc *doc,
2827
59.3k
                                        const yyjson_mut_val *val) {
2828
59.3k
    if (doc && val) return unsafe_yyjson_mut_val_mut_copy(doc, val);
2829
0
    return NULL;
2830
59.3k
}
2831
2832
/* Count the number of values and the total length of the strings. */
2833
static void yyjson_mut_stat(const yyjson_mut_val *val,
2834
0
                            usize *val_sum, usize *str_sum) {
2835
0
    yyjson_type type = unsafe_yyjson_get_type(val);
2836
0
    *val_sum += 1;
2837
0
    if (type == YYJSON_TYPE_ARR || type == YYJSON_TYPE_OBJ) {
2838
0
        yyjson_mut_val *child = (yyjson_mut_val *)val->uni.ptr;
2839
0
        usize len = unsafe_yyjson_get_len(val), i;
2840
0
        len <<= (u8)(type == YYJSON_TYPE_OBJ);
2841
0
        *val_sum += len;
2842
0
        for (i = 0; i < len; i++) {
2843
0
            yyjson_type stype = unsafe_yyjson_get_type(child);
2844
0
            if (stype == YYJSON_TYPE_STR || stype == YYJSON_TYPE_RAW) {
2845
0
                *str_sum += unsafe_yyjson_get_len(child) + 1;
2846
0
            } else if (stype == YYJSON_TYPE_ARR || stype == YYJSON_TYPE_OBJ) {
2847
0
                yyjson_mut_stat(child, val_sum, str_sum);
2848
0
                *val_sum -= 1;
2849
0
            }
2850
0
            child = child->next;
2851
0
        }
2852
0
    } else if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
2853
0
        *str_sum += unsafe_yyjson_get_len(val) + 1;
2854
0
    }
2855
0
}
2856
2857
/* Copy mutable values to immutable value pool. */
2858
static usize yyjson_imut_copy(yyjson_val **val_ptr, char **buf_ptr,
2859
0
                              const yyjson_mut_val *mval) {
2860
0
    yyjson_val *val = *val_ptr;
2861
0
    yyjson_type type = unsafe_yyjson_get_type(mval);
2862
0
    if (type == YYJSON_TYPE_ARR || type == YYJSON_TYPE_OBJ) {
2863
0
        yyjson_mut_val *child = (yyjson_mut_val *)mval->uni.ptr;
2864
0
        usize len = unsafe_yyjson_get_len(mval), i;
2865
0
        usize val_sum = 1;
2866
0
        if (type == YYJSON_TYPE_OBJ) {
2867
0
            if (len) child = child->next->next;
2868
0
            len <<= 1;
2869
0
        } else {
2870
0
            if (len) child = child->next;
2871
0
        }
2872
0
        *val_ptr = val + 1;
2873
0
        for (i = 0; i < len; i++) {
2874
0
            val_sum += yyjson_imut_copy(val_ptr, buf_ptr, child);
2875
0
            child = child->next;
2876
0
        }
2877
0
        val->tag = mval->tag;
2878
0
        val->uni.ofs = val_sum * sizeof(yyjson_val);
2879
0
        return val_sum;
2880
0
    } else if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
2881
0
        char *buf = *buf_ptr;
2882
0
        usize len = unsafe_yyjson_get_len(mval);
2883
0
        memcpy((void *)buf, (const void *)mval->uni.str, len);
2884
0
        buf[len] = '\0';
2885
0
        val->tag = mval->tag;
2886
0
        val->uni.str = buf;
2887
0
        *val_ptr = val + 1;
2888
0
        *buf_ptr = buf + len + 1;
2889
0
        return 1;
2890
0
    } else {
2891
0
        val->tag = mval->tag;
2892
0
        val->uni = mval->uni;
2893
0
        *val_ptr = val + 1;
2894
0
        return 1;
2895
0
    }
2896
0
}
2897
2898
yyjson_doc *yyjson_mut_doc_imut_copy(const yyjson_mut_doc *mdoc,
2899
0
                                     const yyjson_alc *alc) {
2900
0
    if (!mdoc) return NULL;
2901
0
    return yyjson_mut_val_imut_copy(mdoc->root, alc);
2902
0
}
2903
2904
yyjson_doc *yyjson_mut_val_imut_copy(const yyjson_mut_val *mval,
2905
0
                                     const yyjson_alc *alc) {
2906
0
    usize val_num = 0, str_sum = 0, hdr_size, buf_size;
2907
0
    yyjson_doc *doc = NULL;
2908
0
    yyjson_val *val_hdr = NULL;
2909
2910
    /* This value should be NULL here. Setting a non-null value suppresses
2911
       warning from the clang analyzer. */
2912
0
    char *str_hdr = (char *)(void *)&str_sum;
2913
0
    if (!mval) return NULL;
2914
0
    if (!alc) alc = &YYJSON_DEFAULT_ALC;
2915
2916
    /* traverse the input value to get pool size */
2917
0
    yyjson_mut_stat(mval, &val_num, &str_sum);
2918
2919
    /* create doc and val pool */
2920
0
    hdr_size = size_align_up(sizeof(yyjson_doc), sizeof(yyjson_val));
2921
0
    buf_size = hdr_size + val_num * sizeof(yyjson_val);
2922
0
    doc = (yyjson_doc *)alc->malloc(alc->ctx, buf_size);
2923
0
    if (!doc) return NULL;
2924
0
    memset(doc, 0, sizeof(yyjson_doc));
2925
0
    val_hdr = (yyjson_val *)(void *)((char *)(void *)doc + hdr_size);
2926
0
    doc->root = val_hdr;
2927
0
    doc->alc = *alc;
2928
2929
    /* create str pool */
2930
0
    if (str_sum > 0) {
2931
0
        str_hdr = (char *)alc->malloc(alc->ctx, str_sum);
2932
0
        doc->str_pool = str_hdr;
2933
0
        if (!str_hdr) {
2934
0
            alc->free(alc->ctx, (void *)doc);
2935
0
            return NULL;
2936
0
        }
2937
0
    }
2938
2939
    /* copy vals and strs */
2940
0
    doc->val_read = yyjson_imut_copy(&val_hdr, &str_hdr, mval);
2941
0
    doc->dat_read = str_sum + 1;
2942
0
    return doc;
2943
0
}
2944
2945
1.97k
static_inline bool unsafe_yyjson_num_equals(const void *lhs, const void *rhs) {
2946
1.97k
    const yyjson_val_uni *luni = &((const yyjson_val *)lhs)->uni;
2947
1.97k
    const yyjson_val_uni *runi = &((const yyjson_val *)rhs)->uni;
2948
1.97k
    yyjson_subtype lt = unsafe_yyjson_get_subtype(lhs);
2949
1.97k
    yyjson_subtype rt = unsafe_yyjson_get_subtype(rhs);
2950
1.97k
    if (lt == rt) return luni->u64 == runi->u64;
2951
482
    if (lt == YYJSON_SUBTYPE_SINT && rt == YYJSON_SUBTYPE_UINT) {
2952
286
        return luni->i64 >= 0 && luni->u64 == runi->u64;
2953
286
    }
2954
196
    if (lt == YYJSON_SUBTYPE_UINT && rt == YYJSON_SUBTYPE_SINT) {
2955
188
        return runi->i64 >= 0 && luni->u64 == runi->u64;
2956
188
    }
2957
8
    return false;
2958
196
}
2959
2960
274
static_inline bool unsafe_yyjson_str_equals(const void *lhs, const void *rhs) {
2961
274
    usize len = unsafe_yyjson_get_len(lhs);
2962
274
    if (len != unsafe_yyjson_get_len(rhs)) return false;
2963
256
    return !memcmp(unsafe_yyjson_get_str(lhs),
2964
256
                   unsafe_yyjson_get_str(rhs), len);
2965
274
}
2966
2967
0
bool unsafe_yyjson_equals(const yyjson_val *lhs, const yyjson_val *rhs) {
2968
0
    yyjson_type type = unsafe_yyjson_get_type(lhs);
2969
0
    if (type != unsafe_yyjson_get_type(rhs)) return false;
2970
2971
0
    switch (type) {
2972
0
        case YYJSON_TYPE_OBJ: {
2973
0
            usize len = unsafe_yyjson_get_len(lhs);
2974
0
            if (len != unsafe_yyjson_get_len(rhs)) return false;
2975
0
            if (len > 0) {
2976
0
                yyjson_obj_iter iter;
2977
0
                yyjson_obj_iter_init(rhs, &iter);
2978
0
                lhs = unsafe_yyjson_get_first(lhs);
2979
0
                while (len-- > 0) {
2980
0
                    rhs = yyjson_obj_iter_getn(&iter, lhs->uni.str,
2981
0
                                               unsafe_yyjson_get_len(lhs));
2982
0
                    if (!rhs) return false;
2983
0
                    if (!unsafe_yyjson_equals(lhs + 1, rhs)) return false;
2984
0
                    lhs = unsafe_yyjson_get_next(lhs + 1);
2985
0
                }
2986
0
            }
2987
            /* yyjson allows duplicate keys, so the check may be inaccurate */
2988
0
            return true;
2989
0
        }
2990
2991
0
        case YYJSON_TYPE_ARR: {
2992
0
            usize len = unsafe_yyjson_get_len(lhs);
2993
0
            if (len != unsafe_yyjson_get_len(rhs)) return false;
2994
0
            if (len > 0) {
2995
0
                lhs = unsafe_yyjson_get_first(lhs);
2996
0
                rhs = unsafe_yyjson_get_first(rhs);
2997
0
                while (len-- > 0) {
2998
0
                    if (!unsafe_yyjson_equals(lhs, rhs)) return false;
2999
0
                    lhs = unsafe_yyjson_get_next(lhs);
3000
0
                    rhs = unsafe_yyjson_get_next(rhs);
3001
0
                }
3002
0
            }
3003
0
            return true;
3004
0
        }
3005
3006
0
        case YYJSON_TYPE_NUM:
3007
0
            return unsafe_yyjson_num_equals(lhs, rhs);
3008
3009
0
        case YYJSON_TYPE_RAW:
3010
0
        case YYJSON_TYPE_STR:
3011
0
            return unsafe_yyjson_str_equals(lhs, rhs);
3012
3013
0
        case YYJSON_TYPE_NULL:
3014
0
        case YYJSON_TYPE_BOOL:
3015
0
            return lhs->tag == rhs->tag;
3016
3017
0
        default:
3018
0
            return false;
3019
0
    }
3020
0
}
3021
3022
bool unsafe_yyjson_mut_equals(const yyjson_mut_val *lhs,
3023
3.76k
                              const yyjson_mut_val *rhs) {
3024
3.76k
    yyjson_type type = unsafe_yyjson_get_type(lhs);
3025
3.76k
    if (type != unsafe_yyjson_get_type(rhs)) return false;
3026
3027
3.75k
    switch (type) {
3028
831
        case YYJSON_TYPE_OBJ: {
3029
831
            usize len = unsafe_yyjson_get_len(lhs);
3030
831
            if (len != unsafe_yyjson_get_len(rhs)) return false;
3031
820
            if (len > 0) {
3032
758
                yyjson_mut_obj_iter iter;
3033
758
                yyjson_mut_obj_iter_init(constcast(yyjson_mut_val *)rhs, &iter);
3034
758
                lhs = (yyjson_mut_val *)lhs->uni.ptr;
3035
2.41k
                while (len-- > 0) {
3036
1.90k
                    rhs = yyjson_mut_obj_iter_getn(&iter, lhs->uni.str,
3037
1.90k
                                                   unsafe_yyjson_get_len(lhs));
3038
1.90k
                    if (!rhs) return false;
3039
1.76k
                    if (!unsafe_yyjson_mut_equals(lhs->next, rhs)) return false;
3040
1.65k
                    lhs = lhs->next->next;
3041
1.65k
                }
3042
758
            }
3043
            /* yyjson allows duplicate keys, so the check may be inaccurate */
3044
567
            return true;
3045
820
        }
3046
3047
482
        case YYJSON_TYPE_ARR: {
3048
482
            usize len = unsafe_yyjson_get_len(lhs);
3049
482
            if (len != unsafe_yyjson_get_len(rhs)) return false;
3050
454
            if (len > 0) {
3051
174
                lhs = (yyjson_mut_val *)lhs->uni.ptr;
3052
174
                rhs = (yyjson_mut_val *)rhs->uni.ptr;
3053
696
                while (len-- > 0) {
3054
532
                    if (!unsafe_yyjson_mut_equals(lhs, rhs)) return false;
3055
522
                    lhs = lhs->next;
3056
522
                    rhs = rhs->next;
3057
522
                }
3058
174
            }
3059
444
            return true;
3060
454
        }
3061
3062
1.97k
        case YYJSON_TYPE_NUM:
3063
1.97k
            return unsafe_yyjson_num_equals(lhs, rhs);
3064
3065
0
        case YYJSON_TYPE_RAW:
3066
274
        case YYJSON_TYPE_STR:
3067
274
            return unsafe_yyjson_str_equals(lhs, rhs);
3068
3069
72
        case YYJSON_TYPE_NULL:
3070
196
        case YYJSON_TYPE_BOOL:
3071
196
            return lhs->tag == rhs->tag;
3072
3073
0
        default:
3074
0
            return false;
3075
3.75k
    }
3076
3.75k
}
3077
3078
bool yyjson_locate_pos(const char *str, size_t len, size_t pos,
3079
0
                       size_t *line, size_t *col, size_t *chr) {
3080
0
    usize line_sum = 0, line_pos = 0, chr_sum = 0;
3081
0
    const u8 *cur = (const u8 *)str;
3082
0
    const u8 *end = cur + pos;
3083
3084
0
    if (!str || pos > len) {
3085
0
        if (line) *line = 0;
3086
0
        if (col) *col = 0;
3087
0
        if (chr) *chr = 0;
3088
0
        return false;
3089
0
    }
3090
3091
0
    if (pos >= 3 && is_utf8_bom(cur)) cur += 3; /* don't count BOM */
3092
0
    while (cur < end) {
3093
0
        u8 c = *cur;
3094
0
        chr_sum += 1;
3095
0
        if (likely(c < 0x80)) {         /* 0xxxxxxx (0x00-0x7F) ASCII */
3096
0
            if (c == '\n') {
3097
0
                line_sum += 1;
3098
0
                line_pos = chr_sum;
3099
0
            }
3100
0
            cur += 1;
3101
0
        }
3102
0
        else if (c < 0xC0) cur += 1;    /* 10xxxxxx (0x80-0xBF) Invalid */
3103
0
        else if (c < 0xE0) cur += 2;    /* 110xxxxx (0xC0-0xDF) 2-byte UTF-8 */
3104
0
        else if (c < 0xF0) cur += 3;    /* 1110xxxx (0xE0-0xEF) 3-byte UTF-8 */
3105
0
        else if (c < 0xF8) cur += 4;    /* 11110xxx (0xF0-0xF7) 4-byte UTF-8 */
3106
0
        else               cur += 1;    /* 11111xxx (0xF8-0xFF) Invalid */
3107
0
    }
3108
0
    if (line) *line = line_sum + 1;
3109
0
    if (col) *col = chr_sum - line_pos + 1;
3110
0
    if (chr) *chr = chr_sum;
3111
0
    return true;
3112
0
}
3113
3114
3115
3116
#if !YYJSON_DISABLE_READER /* reader begin */
3117
3118
/* Check read flag, avoids `always false` warning when disabled. */
3119
3.86M
#define has_flg(_flg) unlikely(has_rflag(flg, YYJSON_READ_##_flg, 0))
3120
6.16M
#define has_allow(_flg) unlikely(has_rflag(flg, YYJSON_READ_ALLOW_##_flg, 1))
3121
#define YYJSON_READ_ALLOW_TRIVIA (YYJSON_READ_ALLOW_COMMENTS | \
3122
                                  YYJSON_READ_ALLOW_EXT_WHITESPACE)
3123
static_inline bool has_rflag(yyjson_read_flag flg, yyjson_read_flag chk,
3124
10.0M
                             bool non_standard) {
3125
#if YYJSON_DISABLE_NON_STANDARD
3126
    if (non_standard) return false;
3127
#endif
3128
10.0M
    return (flg & chk) != 0;
3129
10.0M
}
3130
3131
3132
3133
/*==============================================================================
3134
 * MARK: - JSON Reader Utils (Private)
3135
 * These functions are used by JSON reader to read literals and comments.
3136
 *============================================================================*/
3137
3138
/** Read `true` literal, `*ptr[0]` should be `t`. */
3139
46.1k
static_inline bool read_true(u8 **ptr, yyjson_val *val) {
3140
46.1k
    u8 *cur = *ptr;
3141
46.1k
    if (likely(byte_match_4(cur, "true"))) {
3142
45.2k
        val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_TRUE;
3143
45.2k
        *ptr = cur + 4;
3144
45.2k
        return true;
3145
45.2k
    }
3146
854
    return false;
3147
46.1k
}
3148
3149
/** Read `false` literal, `*ptr[0]` should be `f`. */
3150
51.4k
static_inline bool read_false(u8 **ptr, yyjson_val *val) {
3151
51.4k
    u8 *cur = *ptr;
3152
51.4k
    if (likely(byte_match_4(cur + 1, "alse"))) {
3153
50.3k
        val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_FALSE;
3154
50.3k
        *ptr = cur + 5;
3155
50.3k
        return true;
3156
50.3k
    }
3157
1.02k
    return false;
3158
51.4k
}
3159
3160
/** Read `null` literal, `*ptr[0]` should be `n`. */
3161
155k
static_inline bool read_null(u8 **ptr, yyjson_val *val) {
3162
155k
    u8 *cur = *ptr;
3163
155k
    if (likely(byte_match_4(cur, "null"))) {
3164
153k
        val->tag = YYJSON_TYPE_NULL;
3165
153k
        *ptr = cur + 4;
3166
153k
        return true;
3167
153k
    }
3168
2.14k
    return false;
3169
155k
}
3170
3171
/** Read `Inf` or `Infinity` literal (ignoring case). */
3172
static_inline bool read_inf(u8 **ptr, u8 **pre,
3173
13.2k
                            yyjson_read_flag flg, yyjson_val *val) {
3174
13.2k
    u8 *hdr = *ptr;
3175
13.2k
    u8 *cur = *ptr;
3176
13.2k
    u8 **end = ptr;
3177
13.2k
    bool sign = (*cur == '-');
3178
13.2k
    if (*cur == '+' && !has_allow(EXT_NUMBER)) return false;
3179
13.2k
    cur += char_is_sign(*cur);
3180
13.2k
    if (char_to_lower(cur[0]) == 'i' &&
3181
6.98k
        char_to_lower(cur[1]) == 'n' &&
3182
6.89k
        char_to_lower(cur[2]) == 'f') {
3183
6.84k
        if (char_to_lower(cur[3]) == 'i') {
3184
2.79k
            if (char_to_lower(cur[4]) == 'n' &&
3185
2.77k
                char_to_lower(cur[5]) == 'i' &&
3186
2.74k
                char_to_lower(cur[6]) == 't' &&
3187
2.72k
                char_to_lower(cur[7]) == 'y') {
3188
2.69k
                cur += 8;
3189
2.69k
            } else {
3190
91
                return false;
3191
91
            }
3192
4.05k
        } else {
3193
4.05k
            cur += 3;
3194
4.05k
        }
3195
6.75k
        *end = cur;
3196
6.75k
        if (has_flg(NUMBER_AS_RAW)) {
3197
0
            **pre = '\0'; /* add null-terminator for previous raw string */
3198
0
            *pre = cur; /* save end position for current raw string */
3199
0
            val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
3200
0
            val->uni.str = (const char *)hdr;
3201
6.75k
        } else {
3202
6.75k
            val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
3203
6.75k
            val->uni.u64 = f64_bits_inf(sign);
3204
6.75k
        }
3205
6.75k
        return true;
3206
6.84k
    }
3207
6.38k
    return false;
3208
13.2k
}
3209
3210
/** Read `NaN` literal (ignoring case). */
3211
static_inline bool read_nan(u8 **ptr, u8 **pre,
3212
8.05k
                            yyjson_read_flag flg, yyjson_val *val) {
3213
8.05k
    u8 *hdr = *ptr;
3214
8.05k
    u8 *cur = *ptr;
3215
8.05k
    u8 **end = ptr;
3216
8.05k
    bool sign = (*cur == '-');
3217
8.05k
    if (*cur == '+' && !has_allow(EXT_NUMBER)) return false;
3218
8.05k
    cur += char_is_sign(*cur);
3219
8.05k
    if (char_to_lower(cur[0]) == 'n' &&
3220
6.72k
        char_to_lower(cur[1]) == 'a' &&
3221
6.47k
        char_to_lower(cur[2]) == 'n') {
3222
6.43k
        cur += 3;
3223
6.43k
        *end = cur;
3224
6.43k
        if (has_flg(NUMBER_AS_RAW)) {
3225
0
            **pre = '\0'; /* add null-terminator for previous raw string */
3226
0
            *pre = cur; /* save end position for current raw string */
3227
0
            val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
3228
0
            val->uni.str = (const char *)hdr;
3229
6.43k
        } else {
3230
6.43k
            val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
3231
6.43k
            val->uni.u64 = f64_bits_nan(sign);
3232
6.43k
        }
3233
6.43k
        return true;
3234
6.43k
    }
3235
1.61k
    return false;
3236
8.05k
}
3237
3238
/** Read `Inf`, `Infinity` or `NaN` literal (ignoring case). */
3239
static_inline bool read_inf_or_nan(u8 **ptr, u8 **pre,
3240
13.2k
                                   yyjson_read_flag flg, yyjson_val *val) {
3241
13.2k
    if (read_inf(ptr, pre, flg, val)) return true;
3242
6.47k
    if (read_nan(ptr, pre, flg, val)) return true;
3243
1.40k
    return false;
3244
6.47k
}
3245
3246
/** Read a JSON number as raw string. */
3247
static_noinline bool read_num_raw(u8 **ptr, u8 **pre, yyjson_read_flag flg,
3248
0
                                  yyjson_val *val, const char **msg) {
3249
0
#define return_err(_pos, _msg) do { \
3250
0
    *msg = _msg; *end = _pos; return false; \
3251
0
} while (false)
3252
3253
0
#define return_raw() do { \
3254
0
    val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
3255
0
    val->uni.str = (const char *)hdr; \
3256
0
    **pre = '\0'; *pre = cur; *end = cur; return true; \
3257
0
} while (false)
3258
3259
0
    u8 *hdr = *ptr;
3260
0
    u8 *cur = *ptr;
3261
0
    u8 **end = ptr;
3262
3263
    /* skip sign */
3264
0
    cur += (*cur == '-');
3265
3266
    /* read first digit, check leading zero */
3267
0
    while (unlikely(!char_is_digit(*cur))) {
3268
0
        if (has_allow(EXT_NUMBER)) {
3269
0
            if (*cur == '+' && cur == hdr) { /* leading `+` sign */
3270
0
                cur++;
3271
0
                continue;
3272
0
            }
3273
0
            if (*cur == '.' && char_is_digit(cur[1])) { /* e.g. '.123' */
3274
0
                goto read_double;
3275
0
            }
3276
0
        }
3277
0
        if (has_allow(INF_AND_NAN)) {
3278
0
            if (read_inf_or_nan(ptr, pre, flg, val)) return true;
3279
0
        }
3280
0
        return_err(cur, "no digit after sign");
3281
0
    }
3282
3283
    /* read integral part */
3284
0
    if (*cur == '0') {
3285
0
        cur++;
3286
0
        if (unlikely(char_is_digit(*cur))) {
3287
0
            return_err(cur - 1, "number with leading zero is not allowed");
3288
0
        }
3289
0
        if (!char_is_fp(*cur)) {
3290
0
            if (has_allow(EXT_NUMBER) && char_to_lower(*cur) == 'x') { /* hex */
3291
0
                if (!char_is_hex(*++cur)) return_err(cur, "invalid hex number");
3292
0
                while(char_is_hex(*cur)) cur++;
3293
0
            }
3294
0
            return_raw();
3295
0
        }
3296
0
    } else {
3297
0
        while (char_is_digit(*cur)) cur++;
3298
0
        if (!char_is_fp(*cur)) return_raw();
3299
0
    }
3300
3301
0
read_double:
3302
    /* read fraction part */
3303
0
    if (*cur == '.') {
3304
0
        cur++;
3305
0
        if (!char_is_digit(*cur)) {
3306
0
            if (has_allow(EXT_NUMBER)) {
3307
0
                if (!char_is_exp(*cur)) return_raw();
3308
0
            } else {
3309
0
                return_err(cur, "no digit after decimal point");
3310
0
            }
3311
0
        }
3312
0
        while (char_is_digit(*cur)) cur++;
3313
0
    }
3314
3315
    /* read exponent part */
3316
0
    if (char_is_exp(*cur)) {
3317
0
        cur += 1 + char_is_sign(cur[1]);
3318
0
        if (!char_is_digit(*cur++)) {
3319
0
            return_err(cur, "no digit after exponent sign");
3320
0
        }
3321
0
        while (char_is_digit(*cur)) cur++;
3322
0
    }
3323
3324
0
    return_raw();
3325
3326
0
#undef return_err
3327
0
#undef return_raw
3328
0
}
3329
3330
/** Read a hex number. */
3331
static_noinline bool read_num_hex(u8 **ptr, u8 **pre, yyjson_read_flag flg,
3332
8.82k
                                  yyjson_val *val, const char **msg) {
3333
8.82k
    u8 *hdr = *ptr;
3334
8.82k
    u8 *cur = *ptr;
3335
8.82k
    u8 **end = ptr;
3336
8.82k
    u64 sig = 0, i = 0;
3337
8.82k
    bool sign;
3338
3339
    /* skip sign and '0x' */
3340
8.82k
    sign = (*cur == '-');
3341
8.82k
    cur += (*cur == '-' || *cur == '+') + 2;
3342
3343
    /* read hex */
3344
75.7k
    for(; i < 16; i++) {
3345
75.1k
        u8 c = hex_conv_table[cur[i]];
3346
75.1k
        if (c == 0xF0) break;
3347
66.9k
        sig <<= 4;
3348
66.9k
        sig |= c;
3349
66.9k
    }
3350
3351
    /* check error */
3352
8.82k
    if (unlikely(i == 0)) {
3353
12
        *msg = "invalid hex number";
3354
12
        return false;
3355
12
    }
3356
3357
    /* check overflow */
3358
8.81k
    if (unlikely(i == 16)) {
3359
637
        if (char_is_hex(cur[16]) || (sign && sig > ((u64)1 << 63))) {
3360
4
            if (!has_flg(BIGNUM_AS_RAW)) {
3361
4
                *msg = "hex number overflow";
3362
4
                return false;
3363
4
            }
3364
0
            cur += 16;
3365
0
            while (char_is_hex(*cur)) cur++;
3366
0
            **pre = '\0';
3367
0
            val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
3368
0
            val->uni.str = (const char *)hdr;
3369
0
            *pre = cur; *end = cur;
3370
0
            return true;
3371
4
        }
3372
637
    }
3373
3374
8.81k
    val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3);
3375
8.81k
    val->uni.u64 = (u64)(sign ? (u64)(~(sig) + 1) : (u64)(sig));
3376
8.81k
    *end = cur + i;
3377
8.81k
    return true;
3378
8.81k
}
3379
3380
/**
3381
 Skip trivia (whitespace and comments).
3382
 This function should be used only when `char_is_trivia()` returns true.
3383
 @param ptr  (inout) Input current position, output end position.
3384
 @param eof  JSON end position.
3385
 @param flg  JSON read flags.
3386
 @return true  if at least one character was skipped.
3387
         false if no characters were skipped,
3388
               or if a multi-line comment is unterminated;
3389
               in the latter case, `ptr` will be set to `eof`.
3390
 */
3391
936k
static_noinline bool skip_trivia(u8 **ptr, u8 *eof, yyjson_read_flag flg) {
3392
936k
    u8 *hdr = *ptr, *cur = *ptr;
3393
936k
    usize len;
3394
3395
1.88M
    while (cur < eof) {
3396
1.87M
        u8 *loop_begin = cur;
3397
3398
        /* skip standard whitespace */
3399
1.89M
        while(char_is_space(*cur)) cur++;
3400
3401
        /* skip extended whitespace */
3402
1.87M
        if (has_allow(EXT_WHITESPACE)) {
3403
3.86M
            while (char_is_space_ext(*cur)) {
3404
2.01M
                cur += (len = ext_space_len(cur));
3405
2.01M
                if (!len) break;
3406
2.01M
            }
3407
1.85M
        }
3408
3409
        /* skip comment, do not validate encoding */
3410
1.87M
        if (has_allow(COMMENTS) && cur[0] == '/') {
3411
12.7k
            if (cur[1] == '/') { /* single-line comment */
3412
8.20k
                cur += 2;
3413
8.20k
                if (has_allow(EXT_WHITESPACE)) {
3414
34.8k
                    while (cur < eof) {
3415
34.7k
                        if (char_is_eol_ext(*cur)) {
3416
1.90k
                            cur += (len = ext_eol_len(cur));
3417
1.90k
                            if (len) break;
3418
1.90k
                        }
3419
33.3k
                        cur++;
3420
33.3k
                    }
3421
6.73k
                } else {
3422
23.0k
                    while (cur < eof && !char_is_eol(*cur)) cur++;
3423
6.73k
                }
3424
8.20k
            } else if (cur[1] == '*') { /* multi-line comment */
3425
4.17k
                cur += 2;
3426
24.2k
                while (!byte_match_2(cur, "*/") && cur < eof) cur++;
3427
4.17k
                if (cur == eof) {
3428
186
                    *ptr = eof;
3429
186
                    return false; /* unclosed comment */
3430
186
                }
3431
3.98k
                cur += 2;
3432
3.98k
            }
3433
12.7k
        }
3434
1.87M
        if (cur == loop_begin) break;
3435
1.87M
    }
3436
936k
    *ptr = cur;
3437
936k
    return cur > hdr;
3438
936k
}
3439
3440
/**
3441
 Check truncated UTF-8 character.
3442
 Return true if `cur` starts a valid UTF-8 sequence that is truncated.
3443
 */
3444
2.37k
static bool is_truncated_utf8(u8 *cur, u8 *eof) {
3445
2.37k
    u8 c0, c1, c2;
3446
2.37k
    usize len = (usize)(eof - cur);
3447
2.37k
    if (cur >= eof || len >= 4) return false;
3448
1.53k
    c0 = cur[0]; c1 = cur[1]; c2 = cur[2];
3449
    /* 1-byte UTF-8, not truncated */
3450
1.53k
    if (c0 < 0x80) return false;
3451
1.37k
    if (len == 1) {
3452
        /* 2-byte UTF-8, truncated */
3453
591
        if ((c0 & 0xE0) == 0xC0 && (c0 & 0x1E) != 0x00) return true;
3454
        /* 3-byte UTF-8, truncated */
3455
445
        if ((c0 & 0xF0) == 0xE0) return true;
3456
        /* 4-byte UTF-8, truncated */
3457
351
        if ((c0 & 0xF8) == 0xF0 && (c0 & 0x07) <= 0x04) return true;
3458
779
    } else if (len == 2) {
3459
        /* 3-byte UTF-8, truncated */
3460
389
        if ((c0 & 0xF0) == 0xE0 && (c1 & 0xC0) == 0x80) {
3461
75
            u8 t = (u8)(((c0 & 0x0F) << 1) | ((c1 & 0x20) >> 5));
3462
75
            return 0x01 <= t && t != 0x1B;
3463
75
        }
3464
        /* 4-byte UTF-8, truncated */
3465
314
        if ((c0 & 0xF8) == 0xF0 && (c1 & 0xC0) == 0x80) {
3466
29
            u8 t = (u8)(((c0 & 0x07) << 2) | ((c1 & 0x30) >> 4));
3467
29
            return 0x01 <= t && t <= 0x10;
3468
29
        }
3469
390
    } else if (len == 3) {
3470
        /* 4 bytes UTF-8, truncated */
3471
390
        if ((c0 & 0xF8) == 0xF0 && (c1 & 0xC0) == 0x80 && (c2 & 0xC0) == 0x80) {
3472
15
            u8 t = (u8)(((c0 & 0x07) << 2) | ((c1 & 0x30) >> 4));
3473
15
            return 0x01 <= t && t <= 0x10;
3474
15
        }
3475
390
    }
3476
982
    return false;
3477
1.37k
}
3478
3479
/**
3480
 Check truncated string.
3481
 Returns true if `cur` match `str` but is truncated.
3482
 The `str` should be lowercase ASCII letters.
3483
 */
3484
static bool is_truncated_str(u8 *cur, u8 *eof, const char *str,
3485
15.9k
                             bool case_sensitive) {
3486
15.9k
    usize len = strlen(str);
3487
15.9k
    if (cur + len <= eof || eof <= cur) return false;
3488
8.97k
    if (case_sensitive) {
3489
3.93k
        return memcmp(cur, str, (usize)(eof - cur)) == 0;
3490
3.93k
    }
3491
5.70k
    for (; cur < eof; cur++, str++) {
3492
5.54k
        if (char_to_lower(*cur) != *(const u8 *)str) return false;
3493
5.54k
    }
3494
153
    return true;
3495
5.04k
}
3496
3497
/**
3498
 Check truncated JSON on parsing errors.
3499
 Returns true if the input is valid but truncated.
3500
 */
3501
static_noinline bool is_truncated_end(u8 *hdr, u8 *cur, u8 *eof,
3502
                                      yyjson_read_code code,
3503
80.2k
                                      yyjson_read_flag flg) {
3504
80.2k
    if (cur >= eof) return true;
3505
40.7k
    if (code == YYJSON_READ_ERROR_LITERAL) {
3506
2.66k
        if (is_truncated_str(cur, eof, "true", true) ||
3507
2.55k
            is_truncated_str(cur, eof, "false", true) ||
3508
2.42k
            is_truncated_str(cur, eof, "null", true)) {
3509
349
            return true;
3510
349
        }
3511
2.66k
    }
3512
40.3k
    if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER ||
3513
14.4k
        code == YYJSON_READ_ERROR_INVALID_NUMBER ||
3514
32.1k
        code == YYJSON_READ_ERROR_LITERAL) {
3515
32.1k
        if (has_allow(INF_AND_NAN)) {
3516
4.04k
            if (*cur == '-') cur++;
3517
4.04k
            if (is_truncated_str(cur, eof, "infinity", false) ||
3518
3.94k
                is_truncated_str(cur, eof, "nan", false)) {
3519
153
                return true;
3520
153
            }
3521
4.04k
        }
3522
32.1k
    }
3523
40.2k
    if (code == YYJSON_READ_ERROR_UNEXPECTED_CONTENT) {
3524
2.65k
        if (has_allow(INF_AND_NAN)) {
3525
332
            if (hdr + 3 <= cur &&
3526
311
                is_truncated_str(cur - 3, eof, "infinity", false)) {
3527
0
                return true; /* e.g. infin would be read as inf + in */
3528
0
            }
3529
332
        }
3530
2.65k
    }
3531
40.2k
    if (code == YYJSON_READ_ERROR_INVALID_STRING) {
3532
5.32k
        usize len = (usize)(eof - cur);
3533
3534
        /* unicode escape sequence */
3535
5.32k
        if (*cur == '\\') {
3536
2.95k
            if (len == 1) return true;
3537
2.79k
            if (len <= 5) {
3538
891
                if (*++cur != 'u') return false;
3539
247
                for (++cur; cur < eof; cur++) {
3540
124
                    if (!char_is_hex(*cur)) return false;
3541
124
                }
3542
123
                return true;
3543
1.90k
            } else if (len <= 11) {
3544
                /* incomplete surrogate pair? */
3545
966
                u16 hi;
3546
966
                if (*++cur != 'u') return false;
3547
631
                if (!hex_load_4(++cur, &hi)) return false;
3548
601
                if ((hi & 0xF800) != 0xD800) return false;
3549
601
                cur += 4;
3550
601
                if (cur >= eof) return true;
3551
                /* valid low surrogate is DC00...DFFF */
3552
511
                if (*cur != '\\') return false;
3553
223
                if (++cur >= eof) return true;
3554
214
                if (*cur != 'u') return false;
3555
160
                if (++cur >= eof) return true;
3556
113
                if (*cur != 'd' && *cur != 'D') return false;
3557
97
                if (++cur >= eof) return true;
3558
77
                if ((*cur < 'c' || *cur > 'f') && (*cur < 'C' || *cur > 'F'))
3559
34
                    return false;
3560
43
                if (++cur >= eof) return true;
3561
19
                if (!char_is_hex(*cur)) return false;
3562
5
                return true;
3563
19
            }
3564
937
            return false;
3565
2.79k
        }
3566
3567
        /* 2 to 4 bytes UTF-8 */
3568
2.37k
        if (is_truncated_utf8(cur, eof)) {
3569
360
            return true;
3570
360
        }
3571
2.37k
    }
3572
36.9k
    if (has_allow(COMMENTS)) {
3573
25.1k
        if (code == YYJSON_READ_ERROR_INVALID_COMMENT) {
3574
            /* unclosed multiline comment */
3575
0
            return true;
3576
0
        }
3577
25.1k
        if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER &&
3578
17.6k
            *cur == '/' && cur + 1 == eof) {
3579
            /* truncated beginning of comment */
3580
133
            return true;
3581
133
        }
3582
25.1k
    }
3583
36.7k
    if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER &&
3584
25.6k
        has_allow(BOM)) {
3585
        /* truncated UTF-8 BOM */
3586
0
        usize len = (usize)(eof - cur);
3587
0
        if (cur == hdr && len < 3 && !memcmp(hdr, "\xEF\xBB\xBF", len)) {
3588
0
            return true;
3589
0
        }
3590
0
    }
3591
36.7k
    return false;
3592
36.7k
}
3593
3594
3595
3596
#if !YYJSON_DISABLE_FAST_FP_CONV /* FP_READER */
3597
3598
/*==============================================================================
3599
 * MARK: - BigInt For Floating Point Number Reader (Private)
3600
 *
3601
 * The bigint algorithm is used by floating-point number reader to get correctly
3602
 * rounded result for numbers with lots of digits. This part of code is rarely
3603
 * used for common numbers.
3604
 *============================================================================*/
3605
3606
/** Unsigned arbitrarily large integer */
3607
typedef struct bigint {
3608
    u32 used; /* used chunks count, should not be 0 */
3609
    u64 bits[64]; /* chunks (58 is enough here) */
3610
} bigint;
3611
3612
/**
3613
 Evaluate 'big += val'.
3614
 @param big A big number (can be 0).
3615
 @param val An unsigned integer (can be 0).
3616
 */
3617
322k
static_inline void bigint_add_u64(bigint *big, u64 val) {
3618
322k
    u32 idx, max;
3619
322k
    u64 num = big->bits[0];
3620
322k
    u64 add = num + val;
3621
322k
    big->bits[0] = add;
3622
322k
    if (likely((add >= num) || (add >= val))) return;
3623
17.1k
    for ((void)(idx = 1), max = big->used; idx < max; idx++) {
3624
15.7k
        if (likely(big->bits[idx] != U64_MAX)) {
3625
14.7k
            big->bits[idx] += 1;
3626
14.7k
            return;
3627
14.7k
        }
3628
942
        big->bits[idx] = 0;
3629
942
    }
3630
1.43k
    big->bits[big->used++] = 1;
3631
1.43k
}
3632
3633
/**
3634
 Evaluate 'big *= val'.
3635
 @param big A big number (can be 0).
3636
 @param val An unsigned integer (cannot be 0).
3637
 */
3638
1.03M
static_inline void bigint_mul_u64(bigint *big, u64 val) {
3639
1.03M
    u32 idx = 0, max = big->used;
3640
1.03M
    u64 hi, lo, carry = 0;
3641
3.35M
    for (; idx < max; idx++) {
3642
3.35M
        if (big->bits[idx]) break;
3643
3.35M
    }
3644
11.3M
    for (; idx < max; idx++) {
3645
10.3M
        u128_mul_add(big->bits[idx], val, carry, &hi, &lo);
3646
10.3M
        big->bits[idx] = lo;
3647
10.3M
        carry = hi;
3648
10.3M
    }
3649
1.03M
    if (carry) big->bits[big->used++] = carry;
3650
1.03M
}
3651
3652
/**
3653
 Evaluate 'big *= 2^exp'.
3654
 @param big A big number (can be 0).
3655
 @param exp An exponent integer (can be 0).
3656
 */
3657
81.7k
static_inline void bigint_mul_pow2(bigint *big, u32 exp) {
3658
81.7k
    u32 shft = exp % 64;
3659
81.7k
    u32 move = exp / 64;
3660
81.7k
    u32 idx = big->used;
3661
81.7k
    if (unlikely(shft == 0)) {
3662
87.5k
        for (; idx > 0; idx--) {
3663
65.2k
            big->bits[idx + move - 1] = big->bits[idx - 1];
3664
65.2k
        }
3665
22.2k
        big->used += move;
3666
100k
        while (move) big->bits[--move] = 0;
3667
59.4k
    } else {
3668
59.4k
        big->bits[idx] = 0;
3669
356k
        for (; idx > 0; idx--) {
3670
296k
            u64 num = big->bits[idx] << shft;
3671
296k
            num |= big->bits[idx - 1] >> (64 - shft);
3672
296k
            big->bits[idx + move] = num;
3673
296k
        }
3674
59.4k
        big->bits[move] = big->bits[0] << shft;
3675
59.4k
        big->used += move + (big->bits[big->used + move] > 0);
3676
363k
        while (move) big->bits[--move] = 0;
3677
59.4k
    }
3678
81.7k
}
3679
3680
/**
3681
 Evaluate 'big *= 10^exp'.
3682
 @param big A big number (can be 0).
3683
 @param exp An exponent integer (cannot be 0).
3684
 */
3685
403k
static_inline void bigint_mul_pow10(bigint *big, i32 exp) {
3686
1.31M
    for (; exp >= U64_POW10_MAX_EXACT_EXP; exp -= U64_POW10_MAX_EXACT_EXP) {
3687
912k
        bigint_mul_u64(big, u64_pow10_table[U64_POW10_MAX_EXACT_EXP]);
3688
912k
    }
3689
403k
    if (exp) {
3690
118k
        bigint_mul_u64(big, u64_pow10_table[exp]);
3691
118k
    }
3692
403k
}
3693
3694
/**
3695
 Compare two bigint.
3696
 @return -1 if 'a < b', +1 if 'a > b', 0 if 'a == b'.
3697
 */
3698
81.7k
static_inline i32 bigint_cmp(bigint *a, bigint *b) {
3699
81.7k
    u32 idx = a->used;
3700
81.7k
    if (a->used < b->used) return -1;
3701
80.2k
    if (a->used > b->used) return +1;
3702
167k
    while (idx-- > 0) {
3703
149k
        u64 av = a->bits[idx];
3704
149k
        u64 bv = b->bits[idx];
3705
149k
        if (av < bv) return -1;
3706
115k
        if (av > bv) return +1;
3707
115k
    }
3708
17.2k
    return 0;
3709
79.9k
}
3710
3711
/**
3712
 Evaluate 'big = val'.
3713
 @param big A big number (can be 0).
3714
 @param val An unsigned integer (can be 0).
3715
 */
3716
113k
static_inline void bigint_set_u64(bigint *big, u64 val) {
3717
113k
    big->used = 1;
3718
113k
    big->bits[0] = val;
3719
113k
}
3720
3721
/** Set a bigint with floating point number string. */
3722
static_noinline void bigint_set_buf(bigint *big, u64 sig, i32 *exp,
3723
81.7k
                                    u8 *sig_cut, u8 *sig_end, u8 *dot_pos) {
3724
3725
81.7k
    if (unlikely(!sig_cut)) {
3726
        /* no digit cut, set significant part only */
3727
31.3k
        bigint_set_u64(big, sig);
3728
31.3k
        return;
3729
3730
50.4k
    } else {
3731
        /* some digits were cut, read them from 'sig_cut' to 'sig_end' */
3732
50.4k
        u8 *hdr = sig_cut;
3733
50.4k
        u8 *cur = hdr;
3734
50.4k
        u32 len = 0;
3735
50.4k
        u64 val = 0;
3736
50.4k
        bool dig_big_cut = false;
3737
50.4k
        bool has_dot = (hdr < dot_pos) & (dot_pos < sig_end);
3738
50.4k
        u32 dig_len_total = U64_SAFE_DIG + (u32)(sig_end - hdr) - has_dot;
3739
3740
50.4k
        sig -= (*sig_cut >= '5'); /* sig was rounded before */
3741
50.4k
        if (dig_len_total > F64_MAX_DEC_DIG) {
3742
1.38k
            dig_big_cut = true;
3743
1.38k
            sig_end -= dig_len_total - (F64_MAX_DEC_DIG + 1);
3744
1.38k
            sig_end -= (dot_pos + 1 == sig_end);
3745
1.38k
            dig_len_total = (F64_MAX_DEC_DIG + 1);
3746
1.38k
        }
3747
50.4k
        *exp -= (i32)dig_len_total - U64_SAFE_DIG;
3748
3749
50.4k
        big->used = 1;
3750
50.4k
        big->bits[0] = sig;
3751
5.54M
        while (cur < sig_end) {
3752
5.49M
            if (likely(cur != dot_pos)) {
3753
5.47M
                val = val * 10 + (u8)(*cur++ - '0');
3754
5.47M
                len++;
3755
5.47M
                if (unlikely(cur == sig_end && dig_big_cut)) {
3756
                    /* The last digit must be non-zero,    */
3757
                    /* set it to '1' for correct rounding. */
3758
1.38k
                    val = val - (val % 10) + 1;
3759
1.38k
                }
3760
5.47M
                if (len == U64_SAFE_DIG || cur == sig_end) {
3761
322k
                    bigint_mul_pow10(big, (i32)len);
3762
322k
                    bigint_add_u64(big, val);
3763
322k
                    val = 0;
3764
322k
                    len = 0;
3765
322k
                }
3766
5.47M
            } else {
3767
12.5k
                cur++;
3768
12.5k
            }
3769
5.49M
        }
3770
50.4k
    }
3771
81.7k
}
3772
3773
3774
3775
/*==============================================================================
3776
 * MARK: - Diy Floating Point (Private)
3777
 *============================================================================*/
3778
3779
/** "Do It Yourself Floating Point" struct. */
3780
typedef struct diy_fp {
3781
    u64 sig; /* significand */
3782
    i32 exp; /* exponent, base 2 */
3783
    i32 pad; /* padding, useless */
3784
} diy_fp;
3785
3786
/** Get cached rounded diy_fp for pow(10, e). The input value must be in the
3787
    range [POW10_SIG_TABLE_MIN_EXP, POW10_SIG_TABLE_MAX_EXP]. */
3788
195k
static_inline diy_fp diy_fp_get_cached_pow10(i32 exp10) {
3789
195k
    diy_fp fp;
3790
195k
    u64 sig_ext;
3791
195k
    pow10_table_get_sig(exp10, &fp.sig, &sig_ext);
3792
195k
    pow10_table_get_exp(exp10, &fp.exp);
3793
195k
    fp.sig += (sig_ext >> 63);
3794
195k
    return fp;
3795
195k
}
3796
3797
/** Returns fp * fp2. */
3798
195k
static_inline diy_fp diy_fp_mul(diy_fp fp, diy_fp fp2) {
3799
195k
    u64 hi, lo;
3800
195k
    u128_mul(fp.sig, fp2.sig, &hi, &lo);
3801
195k
    fp.sig = hi + (lo >> 63);
3802
195k
    fp.exp += fp2.exp + 64;
3803
195k
    return fp;
3804
195k
}
3805
3806
/** Convert diy_fp to IEEE-754 raw value. */
3807
195k
static_inline u64 diy_fp_to_ieee_raw(diy_fp fp) {
3808
195k
    u64 sig = fp.sig;
3809
195k
    i32 exp = fp.exp;
3810
195k
    u32 lz_bits;
3811
195k
    if (unlikely(fp.sig == 0)) return 0;
3812
3813
195k
    lz_bits = u64_lz_bits(sig);
3814
195k
    sig <<= lz_bits;
3815
195k
    sig >>= F64_BITS - F64_SIG_FULL_BITS;
3816
195k
    exp -= (i32)lz_bits;
3817
195k
    exp += F64_BITS - F64_SIG_FULL_BITS;
3818
195k
    exp += F64_SIG_BITS;
3819
3820
195k
    if (unlikely(exp >= F64_MAX_BIN_EXP)) {
3821
        /* overflow */
3822
1.12k
        return F64_BITS_INF;
3823
194k
    } else if (likely(exp >= F64_MIN_BIN_EXP - 1)) {
3824
        /* normal */
3825
159k
        exp += F64_EXP_BIAS;
3826
159k
        return ((u64)exp << F64_SIG_BITS) | (sig & F64_SIG_MASK);
3827
159k
    } else if (likely(exp >= F64_MIN_BIN_EXP - F64_SIG_FULL_BITS)) {
3828
        /* subnormal */
3829
30.2k
        return sig >> (F64_MIN_BIN_EXP - exp - 1);
3830
30.2k
    } else {
3831
        /* underflow */
3832
5.01k
        return 0;
3833
5.01k
    }
3834
195k
}
3835
3836
3837
3838
/*==============================================================================
3839
 * MARK: - Number Reader (Private)
3840
 *============================================================================*/
3841
3842
/**
3843
 Read a JSON number.
3844
3845
 1. This function assume that the floating-point number is in IEEE-754 format.
3846
 2. This function support uint64/int64/double number. If an integer number
3847
    cannot fit in uint64/int64, it will returns as a double number. If a double
3848
    number is infinite, the return value is based on flag.
3849
 3. This function (with inline attribute) may generate a lot of instructions.
3850
 */
3851
static_inline bool read_num(u8 **ptr, u8 **pre, yyjson_read_flag flg,
3852
3.43M
                            yyjson_val *val, const char **msg) {
3853
3.43M
#define return_err(_pos, _msg) do { \
3854
6.45k
    *msg = _msg; \
3855
6.45k
    *end = _pos; \
3856
6.45k
    return false; \
3857
6.45k
} while (false)
3858
3859
3.43M
#define return_0() do { \
3860
27.0k
    val->tag = YYJSON_TYPE_NUM | (u8)((u8)sign << 3); \
3861
27.0k
    val->uni.u64 = 0; \
3862
27.0k
    *end = cur; return true; \
3863
27.0k
} while (false)
3864
3865
3.43M
#define return_i64(_v) do { \
3866
2.24M
    val->tag = YYJSON_TYPE_NUM | (u8)((u8)sign << 3); \
3867
2.24M
    val->uni.u64 = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \
3868
2.24M
    *end = cur; return true; \
3869
2.24M
} while (false)
3870
3871
3.43M
#define return_f64(_v) do { \
3872
837k
    val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
3873
837k
    val->uni.f64 = sign ? -(f64)(_v) : (f64)(_v); \
3874
837k
    *end = cur; return true; \
3875
837k
} while (false)
3876
3877
3.43M
#define return_f64_bin(_v) do { \
3878
303k
    val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
3879
303k
    val->uni.u64 = ((u64)sign << 63) | (u64)(_v); \
3880
303k
    *end = cur; return true; \
3881
303k
} while (false)
3882
3883
3.43M
#define return_inf() do { \
3884
5.89k
    if (has_flg(BIGNUM_AS_RAW)) return_raw(); \
3885
5.89k
    if (has_allow(INF_AND_NAN)) return_f64_bin(F64_BITS_INF); \
3886
5.89k
    else return_err(hdr, "number is infinity when parsed as double"); \
3887
5.89k
} while (false)
3888
3889
3.43M
#define return_raw() do { \
3890
0
    **pre = '\0'; /* add null-terminator for previous raw string */ \
3891
0
    val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
3892
0
    val->uni.str = (const char *)hdr; \
3893
0
    *pre = cur; *end = cur; return true; \
3894
0
} while (false)
3895
3896
3.43M
    u8 *sig_cut = NULL; /* significant part cutting position for long number */
3897
3.43M
    u8 *sig_end = NULL; /* significant part ending position */
3898
3.43M
    u8 *dot_pos = NULL; /* decimal point position */
3899
3900
3.43M
    u64 sig = 0; /* significant part of the number */
3901
3.43M
    i32 exp = 0; /* exponent part of the number */
3902
3903
3.43M
    bool exp_sign; /* temporary exponent sign from literal part */
3904
3.43M
    i64 exp_sig = 0; /* temporary exponent number from significant part */
3905
3.43M
    i64 exp_lit = 0; /* temporary exponent number from exponent literal part */
3906
3.43M
    u64 num; /* temporary number for reading */
3907
3.43M
    u8 *tmp; /* temporary cursor for reading */
3908
3909
3.43M
    u8 *hdr = *ptr;
3910
3.43M
    u8 *cur = *ptr;
3911
3.43M
    u8 **end = ptr;
3912
3.43M
    bool sign;
3913
3914
    /* read number as raw string if has `YYJSON_READ_NUMBER_AS_RAW` flag */
3915
3.43M
    if (has_flg(NUMBER_AS_RAW)) {
3916
0
        return read_num_raw(ptr, pre, flg, val, msg);
3917
0
    }
3918
3919
3.43M
    sign = (*hdr == '-');
3920
3.43M
    cur += sign;
3921
3922
    /* begin with a leading zero or non-digit */
3923
3.43M
    while (unlikely(!char_is_nonzero(*cur))) { /* 0 or non-digit char */
3924
84.7k
        if (unlikely(*cur != '0')) { /* non-digit char */
3925
18.1k
            if (has_allow(EXT_NUMBER)) {
3926
16.6k
                if (*cur == '+' && cur == hdr) { /* leading `+` sign */
3927
5.56k
                    cur++;
3928
5.56k
                    continue;
3929
5.56k
                }
3930
11.1k
                if (*cur == '.' && char_is_digit(cur[1])) { /* e.g. '.123' */
3931
4.88k
                    goto leading_dot;
3932
4.88k
                }
3933
11.1k
            }
3934
7.67k
            if (has_allow(INF_AND_NAN)) {
3935
6.23k
                if (read_inf_or_nan(ptr, pre, flg, val)) return true;
3936
6.23k
            }
3937
1.73k
            return_err(cur, "no digit after sign");
3938
1.73k
        }
3939
        /* begin with 0 */
3940
66.6k
        if (likely(!char_is_digit_or_fp(*++cur))) {
3941
35.9k
            if (has_allow(EXT_NUMBER) && char_to_lower(*cur) == 'x') { /* hex */
3942
8.82k
                return read_num_hex(ptr, pre, flg, val, msg);
3943
8.82k
            }
3944
27.0k
            return_0();
3945
27.0k
        }
3946
30.7k
        if (likely(*cur == '.')) {
3947
31.1k
leading_dot:
3948
31.1k
            dot_pos = cur++;
3949
31.1k
            if (unlikely(!char_is_digit(*cur))) {
3950
2.38k
                if (has_allow(EXT_NUMBER)) {
3951
2.23k
                    if (char_is_exp(*cur)) {
3952
1.27k
                        goto digi_exp_more;
3953
1.27k
                    } else {
3954
960
                        return_f64_bin(0);
3955
960
                    }
3956
2.23k
                }
3957
148
                return_err(cur, "no digit after decimal point");
3958
148
            }
3959
9.56M
            while (unlikely(*cur == '0')) cur++;
3960
28.7k
            if (likely(char_is_digit(*cur))) {
3961
                /* first non-zero digit after decimal point */
3962
24.4k
                sig = (u64)(*cur - '0'); /* read first digit */
3963
24.4k
                cur--;
3964
24.4k
                goto digi_frac_1; /* continue read fraction part */
3965
24.4k
            }
3966
28.7k
        }
3967
8.81k
        if (unlikely(char_is_digit(*cur))) {
3968
242
            return_err(cur - 1, "number with leading zero is not allowed");
3969
242
        }
3970
8.57k
        if (unlikely(char_is_exp(*cur))) { /* 0 with any exponent is still 0 */
3971
4.35k
            cur += (usize)1 + char_is_sign(cur[1]);
3972
4.35k
            if (unlikely(!char_is_digit(*cur))) {
3973
114
                return_err(cur, "no digit after exponent sign");
3974
114
            }
3975
11.3k
            while (char_is_digit(*++cur));
3976
4.24k
        }
3977
8.45k
        return_f64_bin(0);
3978
8.45k
    }
3979
3980
    /* begin with non-zero digit */
3981
3.35M
    sig = (u64)(*cur - '0');
3982
3983
    /*
3984
     Read integral part, same as the following code.
3985
3986
         for (int i = 1; i <= 18; i++) {
3987
            num = cur[i] - '0';
3988
            if (num <= 9) sig = num + sig * 10;
3989
            else goto digi_sepr_i;
3990
         }
3991
     */
3992
3.35M
#define expr_intg(i) \
3993
17.3M
    if (likely((num = (u64)(cur[i] - (u8)'0')) <= 9)) sig = num + sig * 10; \
3994
17.3M
    else { goto digi_sepr_##i; }
3995
17.3M
    repeat_in_1_18(expr_intg)
3996
140k
#undef expr_intg
3997
3998
3999
140k
    cur += 19; /* skip continuous 19 digits */
4000
140k
    if (!char_is_digit_or_fp(*cur)) {
4001
        /* this number is an integer consisting of 19 digits */
4002
18.7k
        if (sign && (sig > ((u64)1 << 63))) { /* overflow */
4003
2.64k
            if (has_flg(BIGNUM_AS_RAW)) return_raw();
4004
2.64k
            return_f64(unsafe_yyjson_u64_to_f64(sig));
4005
2.64k
        }
4006
16.0k
        return_i64(sig);
4007
16.0k
    }
4008
121k
    goto digi_intg_more; /* read more digits in integral part */
4009
4010
4011
    /* process first non-digit character */
4012
121k
#define expr_sepr(i) \
4013
3.21M
    digi_sepr_##i: \
4014
3.21M
    if (likely(!char_is_fp(cur[i]))) { cur += i; return_i64(sig); } \
4015
3.21M
    dot_pos = cur + i; \
4016
991k
    if (likely(cur[i] == '.')) goto digi_frac_##i; \
4017
991k
    cur += i; sig_end = cur; goto digi_exp_more;
4018
4.20M
    repeat_in_1_18(expr_sepr)
4019
0
#undef expr_sepr
4020
4021
4022
    /* read fraction part */
4023
0
#define expr_frac(i) \
4024
3.82M
    digi_frac_##i: \
4025
3.82M
    if (likely((num = (u64)(cur[i + 1] - (u8)'0')) <= 9)) \
4026
3.82M
        sig = num + sig * 10; \
4027
3.82M
    else { goto digi_stop_##i; }
4028
3.82M
    repeat_in_1_18(expr_frac)
4029
38.6k
#undef expr_frac
4030
4031
38.6k
    cur += 20; /* skip 19 digits and 1 decimal point */
4032
38.6k
    if (!char_is_digit(*cur)) goto digi_frac_end; /* fraction part end */
4033
30.6k
    goto digi_frac_more; /* read more digits in fraction part */
4034
4035
4036
    /* significant part end */
4037
30.6k
#define expr_stop(i) \
4038
825k
    digi_stop_##i: \
4039
825k
    cur += i + 1; \
4040
825k
    goto digi_frac_end;
4041
825k
    repeat_in_1_18(expr_stop)
4042
0
#undef expr_stop
4043
4044
4045
    /* read more digits in integral part */
4046
121k
digi_intg_more:
4047
121k
    if (char_is_digit(*cur)) {
4048
108k
        if (!char_is_digit_or_fp(cur[1])) {
4049
            /* this number is an integer consisting of 20 digits */
4050
17.3k
            num = (u64)(*cur - '0');
4051
17.3k
            if ((sig < (U64_MAX / 10)) ||
4052
12.2k
                (sig == (U64_MAX / 10) && num <= (U64_MAX % 10))) {
4053
8.22k
                sig = num + sig * 10;
4054
8.22k
                cur++;
4055
                /* convert to double if overflow */
4056
8.22k
                if (sign) {
4057
2.93k
                    if (has_flg(BIGNUM_AS_RAW)) return_raw();
4058
2.93k
                    return_f64(unsafe_yyjson_u64_to_f64(sig));
4059
2.93k
                }
4060
5.29k
                return_i64(sig);
4061
5.29k
            }
4062
17.3k
        }
4063
108k
    }
4064
4065
113k
    if (char_is_exp(*cur)) {
4066
6.40k
        dot_pos = cur;
4067
6.40k
        goto digi_exp_more;
4068
6.40k
    }
4069
4070
106k
    if (*cur == '.') {
4071
6.59k
        dot_pos = cur++;
4072
6.59k
        if (unlikely(!char_is_digit(*cur))) {
4073
831
            if (has_allow(EXT_NUMBER)) {
4074
781
                goto digi_frac_end;
4075
781
            }
4076
50
            return_err(cur, "no digit after decimal point");
4077
50
        }
4078
6.59k
    }
4079
4080
4081
    /* read more digits in fraction part */
4082
136k
digi_frac_more:
4083
136k
    sig_cut = cur; /* too large to fit in u64, excess digits need to be cut */
4084
136k
    sig += (*cur >= '5'); /* round */
4085
3.54M
    while (char_is_digit(*++cur));
4086
136k
    if (!dot_pos) {
4087
100k
        if (!char_is_fp(*cur) && has_flg(BIGNUM_AS_RAW)) {
4088
0
            return_raw(); /* it's a large integer */
4089
0
        }
4090
100k
        dot_pos = cur;
4091
100k
        if (*cur == '.') {
4092
18.3k
            if (unlikely(!char_is_digit(*++cur))) {
4093
2.56k
                if (!has_allow(EXT_NUMBER)) {
4094
96
                    return_err(cur, "no digit after decimal point");
4095
96
                }
4096
2.56k
            }
4097
2.99M
            while (char_is_digit(*cur)) cur++;
4098
18.2k
        }
4099
100k
    }
4100
136k
    exp_sig = (i64)(dot_pos - sig_cut);
4101
136k
    exp_sig += (dot_pos < sig_cut);
4102
4103
    /* ignore trailing zeros */
4104
136k
    tmp = cur - 1;
4105
667k
    while ((*tmp == '0' || *tmp == '.') && tmp > hdr) tmp--;
4106
136k
    if (tmp < sig_cut) {
4107
8.87k
        sig_cut = NULL;
4108
127k
    } else {
4109
127k
        sig_end = cur;
4110
127k
    }
4111
4112
136k
    if (char_is_exp(*cur)) goto digi_exp_more;
4113
106k
    goto digi_exp_finish;
4114
4115
4116
    /* fraction part end */
4117
833k
digi_frac_end:
4118
833k
    if (unlikely(dot_pos + 1 == cur)) {
4119
41.2k
        if (!has_allow(EXT_NUMBER)) {
4120
1.40k
            return_err(cur, "no digit after decimal point");
4121
1.40k
        }
4122
41.2k
    }
4123
832k
    sig_end = cur;
4124
832k
    exp_sig = -(i64)((u64)(cur - dot_pos) - 1);
4125
832k
    if (likely(!char_is_exp(*cur))) {
4126
806k
        if (unlikely(exp_sig < F64_MIN_DEC_EXP - 19)) {
4127
1.69k
            return_f64_bin(0); /* underflow */
4128
1.69k
        }
4129
804k
        exp = (i32)exp_sig;
4130
804k
        goto digi_finish;
4131
806k
    } else {
4132
26.1k
        goto digi_exp_more;
4133
26.1k
    }
4134
4135
4136
    /* read exponent part */
4137
216k
digi_exp_more:
4138
216k
    exp_sign = (*++cur == '-');
4139
216k
    cur += char_is_sign(*cur);
4140
216k
    if (unlikely(!char_is_digit(*cur))) {
4141
1.70k
        return_err(cur, "no digit after exponent sign");
4142
1.70k
    }
4143
249k
    while (*cur == '0') cur++;
4144
4145
    /* read exponent literal */
4146
214k
    tmp = cur;
4147
3.92M
    while (char_is_digit(*cur)) {
4148
3.71M
        exp_lit = (i64)((u8)(*cur++ - '0') + (u64)exp_lit * 10);
4149
3.71M
    }
4150
214k
    if (unlikely(cur - tmp >= U64_SAFE_DIG)) {
4151
4.31k
        if (exp_sign) {
4152
3.56k
            return_f64_bin(0); /* underflow */
4153
3.56k
        } else {
4154
747
            return_inf(); /* overflow */
4155
747
        }
4156
4.31k
    }
4157
210k
    exp_sig += exp_sign ? -exp_lit : exp_lit;
4158
4159
4160
    /* validate exponent value */
4161
316k
digi_exp_finish:
4162
316k
    if (unlikely(exp_sig < F64_MIN_DEC_EXP - 19)) {
4163
15.3k
        return_f64_bin(0); /* underflow */
4164
15.3k
    }
4165
301k
    if (unlikely(exp_sig > F64_MAX_DEC_EXP)) {
4166
3.41k
        return_inf(); /* overflow */
4167
3.41k
    }
4168
297k
    exp = (i32)exp_sig;
4169
4170
4171
    /* all digit read finished */
4172
1.10M
digi_finish:
4173
4174
    /*
4175
     Fast path 1:
4176
4177
     1. The floating-point number calculation should be accurate, see the
4178
        comments of macro `YYJSON_DOUBLE_MATH_CORRECT`.
4179
     2. Correct rounding should be performed (fegetround() == FE_TONEAREST).
4180
     3. The input to floating-point calculations does not lose precision,
4181
        which means: 64 - leading_zero(input) - trailing_zero(input) < 53.
4182
4183
     We don't check all available inputs here, because that would make the code
4184
     more complicated, and not friendly to branch predictor.
4185
     */
4186
1.10M
#if YYJSON_DOUBLE_MATH_CORRECT
4187
1.10M
    if (sig < ((u64)1 << 53) &&
4188
924k
        exp >= -F64_POW10_MAX_EXACT_EXP &&
4189
882k
        exp <= +F64_POW10_MAX_EXACT_EXP) {
4190
831k
        f64 dbl = (f64)sig;
4191
831k
        if (exp < 0) {
4192
746k
            dbl /= f64_pow10_table[-exp];
4193
746k
        } else {
4194
85.1k
            dbl *= f64_pow10_table[+exp];
4195
85.1k
        }
4196
831k
        return_f64(dbl);
4197
831k
    }
4198
270k
#endif
4199
270k
    if (unlikely(sig == 0)) return_f64_bin(0);
4200
4201
    /*
4202
     Fast path 2:
4203
4204
     To keep it simple, we only accept normal number here,
4205
     let the slow path handle subnormal and infinite numbers.
4206
     */
4207
269k
    if (likely(!sig_cut &&
4208
269k
               exp > -F64_MAX_DEC_EXP + 1 &&
4209
269k
               exp < +F64_MAX_DEC_EXP - 20)) {
4210
        /*
4211
         The result value is exactly equal to (sig * 10^exp),
4212
         the exponent part (10^exp) can be converted to (sig2 * 2^exp2).
4213
4214
         The sig2 can be an infinite length number, only the highest 128 bits
4215
         is cached in the pow10_sig_table.
4216
4217
         Now we have these bits:
4218
         sig1 (normalized 64bit)        : aaaaaaaa
4219
         sig2 (higher 64bit)            : bbbbbbbb
4220
         sig2_ext (lower 64bit)         : cccccccc
4221
         sig2_cut (extra unknown bits)  : dddddddddddd....
4222
4223
         And the calculation process is:
4224
         ----------------------------------------
4225
                 aaaaaaaa *
4226
                 bbbbbbbbccccccccdddddddddddd....
4227
         ----------------------------------------
4228
         abababababababab +
4229
                 acacacacacacacac +
4230
                         adadadadadadadadadad....
4231
         ----------------------------------------
4232
         [hi____][lo____] +
4233
                 [hi2___][lo2___] +
4234
                         [unknown___________....]
4235
         ----------------------------------------
4236
4237
         The addition with carry may affect higher bits, but if there is a 0
4238
         in higher bits, the bits higher than 0 will not be affected.
4239
4240
         `lo2` + `unknown` may get a carry bit and may affect `hi2`, the max
4241
         value of `hi2` is 0xFFFFFFFFFFFFFFFE, so `hi2` will not overflow.
4242
4243
         `lo` + `hi2` may also get a carry bit and may affect `hi`, but only
4244
         the highest significant 53 bits of `hi` is needed. If there is a 0
4245
         in the lower bits of `hi`, then all the following bits can be dropped.
4246
4247
         To convert the result to IEEE-754 double number, we need to perform
4248
         correct rounding:
4249
         1. if bit 54 is 0, round down,
4250
         2. if bit 54 is 1 and any bit beyond bit 54 is 1, round up,
4251
         3. if bit 54 is 1 and all bits beyond bit 54 are 0, round to even,
4252
            as the extra bits is unknown, this case will not be handled here.
4253
         */
4254
4255
94.4k
        u64 raw;
4256
94.4k
        u64 sig1, sig2, sig2_ext, hi, lo, hi2, lo2, add, bits;
4257
94.4k
        i32 exp2;
4258
94.4k
        u32 lz;
4259
94.4k
        bool exact = false, carry, round_up;
4260
4261
        /* convert (10^exp) to (sig2 * 2^exp2) */
4262
94.4k
        pow10_table_get_sig(exp, &sig2, &sig2_ext);
4263
94.4k
        pow10_table_get_exp(exp, &exp2);
4264
4265
        /* normalize and multiply */
4266
94.4k
        lz = u64_lz_bits(sig);
4267
94.4k
        sig1 = sig << lz;
4268
94.4k
        exp2 -= (i32)lz;
4269
94.4k
        u128_mul(sig1, sig2, &hi, &lo);
4270
4271
        /*
4272
         The `hi` is in range [0x4000000000000000, 0xFFFFFFFFFFFFFFFE],
4273
         To get normalized value, `hi` should be shifted to the left by 0 or 1.
4274
4275
         The highest significant 53 bits is used by IEEE-754 double number,
4276
         and the bit 54 is used to detect rounding direction.
4277
4278
         The lowest (64 - 54 - 1) bits is used to check whether it contains 0.
4279
         */
4280
94.4k
        bits = hi & (((u64)1 << (64 - 54 - 1)) - 1);
4281
94.4k
        if (bits - 1 < (((u64)1 << (64 - 54 - 1)) - 2)) {
4282
            /*
4283
             (bits != 0 && bits != 0x1FF) => (bits - 1 < 0x1FF - 1)
4284
             The `bits` is not zero, so we don't need to check `round to even`
4285
             case. The `bits` contains bit `0`, so we can drop the extra bits
4286
             after `0`.
4287
             */
4288
65.1k
            exact = true;
4289
4290
65.1k
        } else {
4291
            /*
4292
             (bits == 0 || bits == 0x1FF)
4293
             The `bits` is filled with all `0` or all `1`, so we need to check
4294
             lower bits with another 64-bit multiplication.
4295
             */
4296
29.2k
            u128_mul(sig1, sig2_ext, &hi2, &lo2);
4297
4298
29.2k
            add = lo + hi2;
4299
29.2k
            if (add + 1 > (u64)1) {
4300
                /*
4301
                 (add != 0 && add != U64_MAX) => (add + 1 > 1)
4302
                 The `add` is not zero, so we don't need to check `round to
4303
                 even` case. The `add` contains bit `0`, so we can drop the
4304
                 extra bits after `0`. The `hi` cannot be U64_MAX, so it will
4305
                 not overflow.
4306
                 */
4307
8.76k
                carry = add < lo || add < hi2;
4308
8.76k
                hi += carry;
4309
8.76k
                exact = true;
4310
8.76k
            }
4311
29.2k
        }
4312
4313
94.4k
        if (exact) {
4314
            /* normalize */
4315
73.9k
            lz = hi < ((u64)1 << 63);
4316
73.9k
            hi <<= lz;
4317
73.9k
            exp2 -= (i32)lz;
4318
73.9k
            exp2 += 64;
4319
4320
            /* test the bit 54 and get rounding direction */
4321
73.9k
            round_up = (hi & ((u64)1 << (64 - 54))) > (u64)0;
4322
73.9k
            hi += (round_up ? ((u64)1 << (64 - 54)) : (u64)0);
4323
4324
            /* test overflow */
4325
73.9k
            if (hi < ((u64)1 << (64 - 54))) {
4326
3.87k
                hi = ((u64)1 << 63);
4327
3.87k
                exp2 += 1;
4328
3.87k
            }
4329
4330
            /* This is a normal number, convert it to IEEE-754 format. */
4331
73.9k
            hi >>= F64_BITS - F64_SIG_FULL_BITS;
4332
73.9k
            exp2 += F64_BITS - F64_SIG_FULL_BITS + F64_SIG_BITS;
4333
73.9k
            exp2 += F64_EXP_BIAS;
4334
73.9k
            raw = ((u64)exp2 << F64_SIG_BITS) | (hi & F64_SIG_MASK);
4335
73.9k
            return_f64_bin(raw);
4336
73.9k
        }
4337
94.4k
    }
4338
4339
    /*
4340
     Slow path: read double number exactly with diyfp.
4341
     1. Use cached diyfp to get an approximation value.
4342
     2. Use bigcomp to check the approximation value if needed.
4343
4344
     This algorithm refers to google's double-conversion project:
4345
     https://github.com/google/double-conversion
4346
     */
4347
195k
    {
4348
195k
        const i32 ERR_ULP_LOG = 3;
4349
195k
        const i32 ERR_ULP = 1 << ERR_ULP_LOG;
4350
195k
        const i32 ERR_CACHED_POW = ERR_ULP / 2;
4351
195k
        const i32 ERR_MUL_FIXED = ERR_ULP / 2;
4352
195k
        const i32 DIY_SIG_BITS = 64;
4353
195k
        const i32 EXP_BIAS = F64_EXP_BIAS + F64_SIG_BITS;
4354
195k
        const i32 EXP_SUBNORMAL = -EXP_BIAS + 1;
4355
4356
195k
        u64 fp_err;
4357
195k
        u32 bits;
4358
195k
        i32 order_of_magnitude;
4359
195k
        i32 effective_significand_size;
4360
195k
        i32 precision_digits_count;
4361
195k
        u64 precision_bits;
4362
195k
        u64 half_way;
4363
4364
195k
        u64 raw;
4365
195k
        diy_fp fp, fp_upper;
4366
195k
        bigint big_full, big_comp;
4367
195k
        i32 cmp;
4368
4369
195k
        fp.sig = sig;
4370
195k
        fp.exp = 0;
4371
195k
        fp_err = sig_cut ? (u64)(ERR_ULP / 2) : (u64)0;
4372
4373
        /* normalize */
4374
195k
        bits = u64_lz_bits(fp.sig);
4375
195k
        fp.sig <<= bits;
4376
195k
        fp.exp -= (i32)bits;
4377
195k
        fp_err <<= bits;
4378
4379
        /* multiply and add error */
4380
195k
        fp = diy_fp_mul(fp, diy_fp_get_cached_pow10(exp));
4381
195k
        fp_err += (u64)ERR_CACHED_POW + (fp_err != 0) + (u64)ERR_MUL_FIXED;
4382
4383
        /* normalize */
4384
195k
        bits = u64_lz_bits(fp.sig);
4385
195k
        fp.sig <<= bits;
4386
195k
        fp.exp -= (i32)bits;
4387
195k
        fp_err <<= bits;
4388
4389
        /* effective significand */
4390
195k
        order_of_magnitude = DIY_SIG_BITS + fp.exp;
4391
195k
        if (likely(order_of_magnitude >= EXP_SUBNORMAL + F64_SIG_FULL_BITS)) {
4392
160k
            effective_significand_size = F64_SIG_FULL_BITS;
4393
160k
        } else if (order_of_magnitude <= EXP_SUBNORMAL) {
4394
5.33k
            effective_significand_size = 0;
4395
29.9k
        } else {
4396
29.9k
            effective_significand_size = order_of_magnitude - EXP_SUBNORMAL;
4397
29.9k
        }
4398
4399
        /* precision digits count */
4400
195k
        precision_digits_count = DIY_SIG_BITS - effective_significand_size;
4401
195k
        if (unlikely(precision_digits_count + ERR_ULP_LOG >= DIY_SIG_BITS)) {
4402
8.72k
            i32 shr = (precision_digits_count + ERR_ULP_LOG) - DIY_SIG_BITS + 1;
4403
8.72k
            fp.sig >>= shr;
4404
8.72k
            fp.exp += shr;
4405
8.72k
            fp_err = (fp_err >> shr) + 1 + (u32)ERR_ULP;
4406
8.72k
            precision_digits_count -= shr;
4407
8.72k
        }
4408
4409
        /* half way */
4410
195k
        precision_bits = fp.sig & (((u64)1 << precision_digits_count) - 1);
4411
195k
        precision_bits *= (u32)ERR_ULP;
4412
195k
        half_way = (u64)1 << (precision_digits_count - 1);
4413
195k
        half_way *= (u32)ERR_ULP;
4414
4415
        /* rounding */
4416
195k
        fp.sig >>= precision_digits_count;
4417
195k
        fp.sig += (precision_bits >= half_way + fp_err);
4418
195k
        fp.exp += precision_digits_count;
4419
4420
        /* get IEEE double raw value */
4421
195k
        raw = diy_fp_to_ieee_raw(fp);
4422
195k
        if (unlikely(raw == F64_BITS_INF)) return_inf();
4423
194k
        if (likely(precision_bits <= half_way - fp_err ||
4424
194k
                   precision_bits >= half_way + fp_err)) {
4425
112k
            return_f64_bin(raw); /* number is accurate */
4426
112k
        }
4427
        /* now the number is the correct value, or the next lower value */
4428
4429
        /* upper boundary */
4430
81.7k
        if (raw & F64_EXP_MASK) {
4431
75.0k
            fp_upper.sig = (raw & F64_SIG_MASK) + ((u64)1 << F64_SIG_BITS);
4432
75.0k
            fp_upper.exp = (i32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
4433
75.0k
        } else {
4434
6.72k
            fp_upper.sig = (raw & F64_SIG_MASK);
4435
6.72k
            fp_upper.exp = 1;
4436
6.72k
        }
4437
81.7k
        fp_upper.exp -= F64_EXP_BIAS + F64_SIG_BITS;
4438
81.7k
        fp_upper.sig <<= 1;
4439
81.7k
        fp_upper.exp -= 1;
4440
81.7k
        fp_upper.sig += 1; /* add half ulp */
4441
4442
        /* compare with bigint */
4443
81.7k
        bigint_set_buf(&big_full, sig, &exp, sig_cut, sig_end, dot_pos);
4444
81.7k
        bigint_set_u64(&big_comp, fp_upper.sig);
4445
81.7k
        if (exp >= 0) {
4446
36.8k
            bigint_mul_pow10(&big_full, +exp);
4447
44.9k
        } else {
4448
44.9k
            bigint_mul_pow10(&big_comp, -exp);
4449
44.9k
        }
4450
81.7k
        if (fp_upper.exp > 0) {
4451
47.6k
            bigint_mul_pow2(&big_comp, (u32)+fp_upper.exp);
4452
47.6k
        } else {
4453
34.1k
            bigint_mul_pow2(&big_full, (u32)-fp_upper.exp);
4454
34.1k
        }
4455
81.7k
        cmp = bigint_cmp(&big_full, &big_comp);
4456
81.7k
        if (likely(cmp != 0)) {
4457
            /* round down or round up */
4458
64.4k
            raw += (cmp > 0);
4459
64.4k
        } else {
4460
            /* falls midway, round to even */
4461
17.2k
            raw += (raw & 1);
4462
17.2k
        }
4463
4464
81.7k
        if (unlikely(raw == F64_BITS_INF)) return_inf();
4465
81.1k
        return_f64_bin(raw);
4466
81.1k
    }
4467
4468
81.1k
#undef return_err
4469
81.1k
#undef return_inf
4470
81.1k
#undef return_0
4471
81.1k
#undef return_i64
4472
81.1k
#undef return_f64
4473
81.1k
#undef return_f64_bin
4474
81.1k
#undef return_raw
4475
81.1k
}
4476
4477
4478
4479
#else /* FP_READER */
4480
4481
/**
4482
 Read a JSON number.
4483
 This is a fallback function if the custom number reader is disabled.
4484
 This function use libc's strtod() to read floating-point number.
4485
 */
4486
static_inline bool read_num(u8 **ptr, u8 **pre, yyjson_read_flag flg,
4487
                            yyjson_val *val, const char **msg) {
4488
#define return_err(_pos, _msg) do { \
4489
    *msg = _msg; \
4490
    *end = _pos; \
4491
    return false; \
4492
} while (false)
4493
4494
#define return_0() do { \
4495
    val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); \
4496
    val->uni.u64 = 0; \
4497
    *end = cur; return true; \
4498
} while (false)
4499
4500
#define return_i64(_v) do { \
4501
    val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); \
4502
    val->uni.u64 = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \
4503
    *end = cur; return true; \
4504
} while (false)
4505
4506
#define return_f64(_v) do { \
4507
    val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
4508
    val->uni.f64 = sign ? -(f64)(_v) : (f64)(_v); \
4509
    *end = cur; return true; \
4510
} while (false)
4511
4512
#define return_f64_bin(_v) do { \
4513
    val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
4514
    val->uni.u64 = ((u64)sign << 63) | (u64)(_v); \
4515
    *end = cur; return true; \
4516
} while (false)
4517
4518
#define return_inf() do { \
4519
    if (has_flg(BIGNUM_AS_RAW)) return_raw(); \
4520
    if (has_allow(INF_AND_NAN)) return_f64_bin(F64_BITS_INF); \
4521
    else return_err(hdr, "number is infinity when parsed as double"); \
4522
} while (false)
4523
4524
#define return_raw() do { \
4525
    val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
4526
    val->uni.str = (const char *)hdr; \
4527
    **pre = '\0'; *pre = cur; *end = cur; return true; \
4528
} while (false)
4529
4530
    u64 sig, num;
4531
    u8 *hdr = *ptr;
4532
    u8 *cur = *ptr;
4533
    u8 **end = ptr;
4534
    u8 *dot = NULL;
4535
    u8 *f64_end = NULL;
4536
    bool sign;
4537
4538
    /* read number as raw string if has `YYJSON_READ_NUMBER_AS_RAW` flag */
4539
    if (has_flg(NUMBER_AS_RAW)) {
4540
        return read_num_raw(ptr, pre, flg, val, msg);
4541
    }
4542
4543
    sign = (*hdr == '-');
4544
    cur += sign;
4545
    sig = (u8)(*cur - '0');
4546
4547
    /* read first digit, check leading zero */
4548
    while (unlikely(!char_is_digit(*cur))) {
4549
        if (has_allow(EXT_NUMBER)) {
4550
            if (*cur == '+' && cur == hdr) { /* leading `+` sign */
4551
                cur++;
4552
                sig = (u8)(*cur - '0');
4553
                continue;
4554
            }
4555
            if (*cur == '.' && char_is_num(cur[1])) { /* no integer part */
4556
                goto read_double; /* e.g. '.123' */
4557
            }
4558
        }
4559
        if (has_allow(INF_AND_NAN)) {
4560
            if (read_inf_or_nan(ptr, pre, flg, val)) return true;
4561
        }
4562
        return_err(cur, "no digit after sign");
4563
    }
4564
    if (*cur == '0') {
4565
        cur++;
4566
        if (unlikely(char_is_digit(*cur))) {
4567
            return_err(cur - 1, "number with leading zero is not allowed");
4568
        }
4569
        if (!char_is_fp(*cur)) {
4570
            if (has_allow(EXT_NUMBER) &&
4571
                (*cur == 'x' || *cur == 'X')) { /* hex integer */
4572
                return read_num_hex(ptr, pre, flg, val, msg);
4573
            }
4574
            return_0();
4575
        }
4576
        goto read_double;
4577
    }
4578
4579
    /* read continuous digits, up to 19 characters */
4580
#define expr_intg(i) \
4581
    if (likely((num = (u64)(cur[i] - (u8)'0')) <= 9)) sig = num + sig * 10; \
4582
    else { cur += i; goto intg_end; }
4583
    repeat_in_1_18(expr_intg)
4584
#undef expr_intg
4585
4586
    /* here are 19 continuous digits, skip them */
4587
    cur += 19;
4588
    if (char_is_digit(cur[0]) && !char_is_digit_or_fp(cur[1])) {
4589
        /* this number is an integer consisting of 20 digits */
4590
        num = (u8)(*cur - '0');
4591
        if ((sig < (U64_MAX / 10)) ||
4592
            (sig == (U64_MAX / 10) && num <= (U64_MAX % 10))) {
4593
            sig = num + sig * 10;
4594
            cur++;
4595
            if (sign) {
4596
                if (has_flg(BIGNUM_AS_RAW)) return_raw();
4597
                return_f64(unsafe_yyjson_u64_to_f64(sig));
4598
            }
4599
            return_i64(sig);
4600
        }
4601
    }
4602
4603
intg_end:
4604
    /* continuous digits ended */
4605
    if (!char_is_digit_or_fp(*cur)) {
4606
        /* this number is an integer consisting of 1 to 19 digits */
4607
        if (sign && (sig > ((u64)1 << 63))) {
4608
            if (has_flg(BIGNUM_AS_RAW)) return_raw();
4609
            return_f64(unsafe_yyjson_u64_to_f64(sig));
4610
        }
4611
        return_i64(sig);
4612
    }
4613
4614
read_double:
4615
    /* this number should be read as double */
4616
    while (char_is_digit(*cur)) cur++;
4617
    if (!char_is_fp(*cur) && has_flg(BIGNUM_AS_RAW)) {
4618
        return_raw(); /* it's a large integer */
4619
    }
4620
    while (*cur == '.') {
4621
        /* skip fraction part */
4622
        dot = cur;
4623
        cur++;
4624
        if (!char_is_digit(*cur)) {
4625
            if (has_allow(EXT_NUMBER)) {
4626
                break;
4627
            } else {
4628
                return_err(cur, "no digit after decimal point");
4629
            }
4630
        }
4631
        cur++;
4632
        while (char_is_digit(*cur)) cur++;
4633
        break;
4634
    }
4635
    if (char_is_exp(*cur)) {
4636
        /* skip exponent part */
4637
        cur += 1 + char_is_sign(cur[1]);
4638
        if (!char_is_digit(*cur)) {
4639
            return_err(cur, "no digit after exponent sign");
4640
        }
4641
        cur++;
4642
        while (char_is_digit(*cur)) cur++;
4643
    }
4644
4645
    /*
4646
     libc's strtod() is used to parse the floating-point number.
4647
4648
     Note that the decimal point character used by strtod() is locale-dependent,
4649
     and the rounding direction may affected by fesetround().
4650
4651
     For currently known locales, (en, zh, ja, ko, am, he, hi) use '.' as the
4652
     decimal point, while other locales use ',' as the decimal point.
4653
4654
     Here strtod() is called twice for different locales, but if another thread
4655
     happens calls setlocale() between two strtod(), parsing may still fail.
4656
     */
4657
    val->uni.f64 = strtod((const char *)hdr, (char **)&f64_end);
4658
    if (unlikely(f64_end != cur)) {
4659
        /* replace '.' with ',' for locale */
4660
        bool cut = (*cur == ',');
4661
        if (cut) *cur = ' ';
4662
        if (dot) *dot = ',';
4663
        val->uni.f64 = strtod((const char *)hdr, (char **)&f64_end);
4664
        /* restore ',' to '.' */
4665
        if (cut) *cur = ',';
4666
        if (dot) *dot = '.';
4667
        if (unlikely(f64_end != cur)) {
4668
            return_err(hdr, "strtod() failed to parse the number");
4669
        }
4670
    }
4671
    if (unlikely(f64_is_inf(val->uni.f64))) {
4672
        return_inf();
4673
    }
4674
    val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
4675
    *end = cur;
4676
    return true;
4677
4678
#undef return_err
4679
#undef return_0
4680
#undef return_i64
4681
#undef return_f64
4682
#undef return_f64_bin
4683
#undef return_inf
4684
#undef return_raw
4685
}
4686
4687
#endif /* FP_READER */
4688
4689
4690
4691
/*==============================================================================
4692
 * MARK: - String Reader (Private)
4693
 *============================================================================*/
4694
4695
/** Read unicode escape sequence. */
4696
31.3k
static_inline bool read_uni_esc(u8 **src_ptr, u8 **dst_ptr, const char **msg) {
4697
31.3k
#define return_err(_end, _msg) *msg = _msg; *src_ptr = _end; return false
4698
4699
31.3k
    u8 *src = *src_ptr;
4700
31.3k
    u8 *dst = *dst_ptr;
4701
31.3k
    u16 hi, lo;
4702
31.3k
    u32 uni;
4703
4704
31.3k
    src += 2; /* skip `\u` */
4705
31.3k
    if (unlikely(!hex_load_4(src, &hi))) {
4706
214
        return_err(src - 2, "invalid escaped sequence in string");
4707
214
    }
4708
31.1k
    src += 4; /* skip hex */
4709
31.1k
    if (likely((hi & 0xF800) != 0xD800)) {
4710
        /* a BMP character */
4711
23.9k
        if (hi >= 0x800) {
4712
8.83k
            *dst++ = (u8)(0xE0 | (hi >> 12));
4713
8.83k
            *dst++ = (u8)(0x80 | ((hi >> 6) & 0x3F));
4714
8.83k
            *dst++ = (u8)(0x80 | (hi & 0x3F));
4715
15.1k
        } else if (hi >= 0x80) {
4716
6.93k
            *dst++ = (u8)(0xC0 | (hi >> 6));
4717
6.93k
            *dst++ = (u8)(0x80 | (hi & 0x3F));
4718
8.21k
        } else {
4719
8.21k
            *dst++ = (u8)hi;
4720
8.21k
        }
4721
23.9k
    } else {
4722
        /* a non-BMP character, represented as a surrogate pair */
4723
7.17k
        if (unlikely((hi & 0xFC00) != 0xD800)) {
4724
98
            return_err(src - 6, "invalid high surrogate in string");
4725
98
        }
4726
7.07k
        if (unlikely(!byte_match_2(src, "\\u"))) {
4727
399
            return_err(src - 6, "no low surrogate in string");
4728
399
        }
4729
6.67k
        if (unlikely(!hex_load_4(src + 2, &lo))) {
4730
155
            return_err(src - 6, "invalid escape in string");
4731
155
        }
4732
6.52k
        if (unlikely((lo & 0xFC00) != 0xDC00)) {
4733
150
            return_err(src - 6, "invalid low surrogate in string");
4734
150
        }
4735
6.37k
        uni = ((((u32)hi - 0xD800) << 10) |
4736
6.37k
                ((u32)lo - 0xDC00)) + 0x10000;
4737
6.37k
        *dst++ = (u8)(0xF0 | (uni >> 18));
4738
6.37k
        *dst++ = (u8)(0x80 | ((uni >> 12) & 0x3F));
4739
6.37k
        *dst++ = (u8)(0x80 | ((uni >> 6) & 0x3F));
4740
6.37k
        *dst++ = (u8)(0x80 | (uni & 0x3F));
4741
6.37k
        src += 6;
4742
6.37k
    }
4743
30.3k
    *src_ptr = src;
4744
30.3k
    *dst_ptr = dst;
4745
30.3k
    return true;
4746
31.1k
#undef return_err
4747
31.1k
}
4748
4749
/**
4750
 Read a JSON string.
4751
 @param quo The quote character (single quote or double quote).
4752
 @param ptr The head pointer of string before quote (inout).
4753
 @param eof JSON end position.
4754
 @param flg JSON read flag.
4755
 @param val The string value to be written.
4756
 @param msg The error message pointer.
4757
 @param con Continuation for incremental parsing.
4758
 @return Whether success.
4759
 */
4760
static_inline bool read_str_opt(u8 quo, u8 **ptr, u8 *eof, yyjson_read_flag flg,
4761
524k
                                yyjson_val *val, const char **msg, u8 *con[2]) {
4762
    /*
4763
     GCC may sometimes load variables into registers too early, causing
4764
     unnecessary instructions and performance degradation. This inline assembly
4765
     serves as a hint to GCC: 'This variable will be modified, so avoid loading
4766
     it too early.' Other compilers like MSVC, Clang, and ICC can generate the
4767
     expected instructions without needing this hint.
4768
4769
     Check out this example: https://godbolt.org/z/YG6a5W5Ec
4770
     */
4771
524k
#define return_err(_end, _msg) do { \
4772
18.9k
    *msg = _msg; \
4773
18.9k
    *end = _end; \
4774
18.9k
    if (con) { con[0] = _end; con[1] = dst; } \
4775
18.9k
    return false; \
4776
18.9k
} while (false)
4777
4778
524k
    u8 *hdr = *ptr + 1;
4779
524k
    u8 **end = ptr;
4780
524k
    u8 *src = hdr, *dst = NULL, *pos;
4781
524k
    u32 uni, tmp;
4782
4783
    /* Resume incremental parsing. */
4784
524k
    if (con && unlikely(con[0])) {
4785
0
        src = con[0];
4786
0
        dst = con[1];
4787
0
        if (dst) goto copy_ascii;
4788
0
    }
4789
4790
1.51M
skip_ascii:
4791
    /*
4792
     Most strings have no escaped characters, so we can jump them quickly.
4793
4794
     We want to make loop unrolling, as shown in the following code. Some
4795
     compiler may not generate instructions as expected, so we rewrite it with
4796
     explicit goto statements. We hope the compiler can generate instructions
4797
     like this: https://godbolt.org/z/8vjsYq
4798
4799
     while (true) repeat16({
4800
        if (likely((char_is_ascii_skip(*src)))) src++;
4801
        else break;
4802
     })
4803
     */
4804
1.51M
    if (quo == '"') {
4805
1.50M
#define expr_jump(i) \
4806
10.6M
    if (likely(char_is_ascii_skip(src[i]))) {} \
4807
10.6M
    else goto skip_ascii_stop##i;
4808
4809
1.50M
#define expr_stop(i) \
4810
1.50M
    skip_ascii_stop##i: \
4811
1.20M
    src += i; \
4812
1.20M
    goto skip_ascii_end;
4813
4814
10.6M
    repeat16_incr(expr_jump)
4815
292k
    src += 16;
4816
292k
    goto skip_ascii;
4817
1.20M
    repeat16_incr(expr_stop)
4818
4819
0
#undef expr_jump
4820
0
#undef expr_stop
4821
10.0k
    } else {
4822
10.0k
#define expr_jump(i) \
4823
45.4k
    if (likely(char_is_ascii_skip_sq(src[i]))) {} \
4824
45.4k
    else goto skip_ascii_stop_sq##i;
4825
4826
10.0k
#define expr_stop(i) \
4827
10.0k
    skip_ascii_stop_sq##i: \
4828
9.74k
    src += i; \
4829
9.74k
    goto skip_ascii_end;
4830
4831
45.4k
    repeat16_incr(expr_jump)
4832
332
    src += 16;
4833
332
    goto skip_ascii;
4834
9.74k
    repeat16_incr(expr_stop)
4835
4836
0
#undef expr_jump
4837
0
#undef expr_stop
4838
0
    }
4839
4840
1.21M
skip_ascii_end:
4841
1.21M
    gcc_store_barrier(*src);
4842
1.21M
    if (likely(*src == quo)) {
4843
433k
        val->tag = ((u64)(src - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR |
4844
433k
                        (quo == '"' ? YYJSON_SUBTYPE_NOESC : 0);
4845
433k
        val->uni.str = (const char *)hdr;
4846
433k
        *src = '\0';
4847
433k
        *end = src + 1;
4848
433k
        if (con) con[0] = con[1] = NULL;
4849
433k
        return true;
4850
433k
    }
4851
4852
786k
skip_utf8:
4853
786k
    if (*src & 0x80) { /* non-ASCII character */
4854
        /*
4855
         Non-ASCII character appears here, which means that the text is likely
4856
         to be written in non-English or emoticons. According to some common
4857
         data set statistics, byte sequences of the same length may appear
4858
         consecutively. We process the byte sequences of the same length in each
4859
         loop, which is more friendly to branch prediction.
4860
         */
4861
696k
        pos = src;
4862
#if YYJSON_DISABLE_UTF8_VALIDATION
4863
        while (true) repeat8({
4864
            if (likely((*src & 0xF0) == 0xE0)) src += 3;
4865
            else break;
4866
        })
4867
        if (*src < 0x80) goto skip_ascii;
4868
        while (true) repeat8({
4869
            if (likely((*src & 0xE0) == 0xC0)) src += 2;
4870
            else break;
4871
        })
4872
        while (true) repeat8({
4873
            if (likely((*src & 0xF8) == 0xF0)) src += 4;
4874
            else break;
4875
        })
4876
#else
4877
696k
        uni = byte_load_4(src);
4878
715k
        while (is_utf8_seq3(uni)) {
4879
18.4k
            src += 3;
4880
18.4k
            uni = byte_load_4(src);
4881
18.4k
        }
4882
696k
        if (is_utf8_seq1(uni)) goto skip_ascii;
4883
1.10M
        while (is_utf8_seq2(uni)) {
4884
420k
            src += 2;
4885
420k
            uni = byte_load_4(src);
4886
420k
        }
4887
718k
        while (is_utf8_seq4(uni)) {
4888
31.5k
            src += 4;
4889
31.5k
            uni = byte_load_4(src);
4890
31.5k
        }
4891
687k
#endif
4892
687k
        if (unlikely(pos == src)) {
4893
269k
            if (has_allow(INVALID_UNICODE)) ++src;
4894
965
            else return_err(src, "invalid UTF-8 encoding in string");
4895
269k
        }
4896
686k
        goto skip_ascii;
4897
687k
    }
4898
4899
    /* The escape character appears, we need to copy it. */
4900
89.8k
    dst = src;
4901
602k
copy_escape:
4902
602k
    if (likely(*src == '\\')) {
4903
227k
        switch (*++src) {
4904
7.91k
            case '"':  *dst++ = '"';  src++; break;
4905
13.6k
            case '\\': *dst++ = '\\'; src++; break;
4906
6.08k
            case '/':  *dst++ = '/';  src++; break;
4907
50.2k
            case 'b':  *dst++ = '\b'; src++; break;
4908
19.0k
            case 'f':  *dst++ = '\f'; src++; break;
4909
20.1k
            case 'n':  *dst++ = '\n'; src++; break;
4910
26.6k
            case 'r':  *dst++ = '\r'; src++; break;
4911
18.5k
            case 't':  *dst++ = '\t'; src++; break;
4912
27.8k
            case 'u':
4913
27.8k
                src--;
4914
27.8k
                if (!read_uni_esc(&src, &dst, msg)) return_err(src, *msg);
4915
26.8k
                break;
4916
37.8k
            default: {
4917
37.8k
                if (has_allow(EXT_ESCAPE)) {
4918
                    /* read extended escape (non-standard) */
4919
36.1k
                    switch (*src) {
4920
2.49k
                        case '\'': *dst++ = '\''; src++; break;
4921
2.46k
                        case 'a':  *dst++ = '\a'; src++; break;
4922
2.16k
                        case 'v':  *dst++ = '\v'; src++; break;
4923
1.97k
                        case '?':  *dst++ = '\?'; src++; break;
4924
3.01k
                        case 'e':  *dst++ = 0x1B; src++; break;
4925
2.90k
                        case '0':
4926
2.90k
                            if (!char_is_digit(src[1])) {
4927
2.89k
                                *dst++ = '\0'; src++; break;
4928
2.89k
                            }
4929
12
                            return_err(src - 1, "octal escape is not allowed");
4930
35
                        case '1': case '2': case '3': case '4':
4931
74
                        case '5': case '6': case '7': case '8': case '9':
4932
74
                            return_err(src - 1, "invalid number escape");
4933
2.96k
                        case 'x': {
4934
2.96k
                            u8 c;
4935
2.96k
                            if (hex_load_2(src + 1, &c)) {
4936
2.93k
                                src += 3;
4937
2.93k
                                if (c <= 0x7F) { /* 1-byte ASCII */
4938
1.72k
                                    *dst++ = c;
4939
1.72k
                                } else { /* 2-byte UTF-8 */
4940
1.21k
                                    *dst++ = (u8)(0xC0 | (c >> 6));
4941
1.21k
                                    *dst++ = (u8)(0x80 | (c & 0x3F));
4942
1.21k
                                }
4943
2.93k
                                break;
4944
2.93k
                            }
4945
30
                            return_err(src - 1, "invalid hex escape");
4946
30
                        }
4947
2.00k
                        case '\n': src++; break;
4948
1.97k
                        case '\r': src++; src += (*src == '\n'); break;
4949
6.23k
                        case 0xE2: /* Line terminator: U+2028, U+2029 */
4950
6.23k
                            if ((src[1] == 0x80 && src[2] == 0xA8) ||
4951
4.45k
                                (src[1] == 0x80 && src[2] == 0xA9)) {
4952
3.22k
                                src += 3;
4953
3.22k
                            }
4954
6.23k
                            break;
4955
7.84k
                        default:
4956
7.84k
                            break; /* skip */
4957
36.1k
                    }
4958
36.1k
                } else if (quo == '\'' && *src == '\'') {
4959
0
                    *dst++ = '\''; src++; break;
4960
1.78k
                } else {
4961
1.78k
                    return_err(src - 1, "invalid escaped sequence in string");
4962
1.78k
                }
4963
37.8k
            }
4964
227k
        }
4965
374k
    } else if (likely(*src == quo)) {
4966
71.7k
        val->tag = ((u64)(dst - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR;
4967
71.7k
        val->uni.str = (const char *)hdr;
4968
71.7k
        *dst = '\0';
4969
71.7k
        *end = src + 1;
4970
71.7k
        if (con) con[0] = con[1] = NULL;
4971
71.7k
        return true;
4972
302k
    } else {
4973
302k
        if (!has_allow(INVALID_UNICODE)) {
4974
5.86k
            return_err(src, "unexpected control character in string");
4975
5.86k
        }
4976
296k
        if (src >= eof) return_err(src, "unclosed string");
4977
288k
        *dst++ = *src++;
4978
288k
    }
4979
4980
2.25M
copy_ascii:
4981
    /*
4982
     Copy continuous ASCII, loop unrolling, same as the following code:
4983
4984
     while (true) repeat16({
4985
        if (char_is_ascii_skip(*src)) *dst++ = *src++;
4986
        else break;
4987
     })
4988
     */
4989
2.25M
    if (quo == '"') {
4990
2.20M
#define expr_jump(i) \
4991
21.6M
    if (likely((char_is_ascii_skip(src[i])))) {} \
4992
21.6M
    else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; }
4993
21.6M
    repeat16_incr(expr_jump)
4994
19.4M
#undef expr_jump
4995
19.4M
    } else {
4996
47.2k
#define expr_jump(i) \
4997
444k
    if (likely((char_is_ascii_skip_sq(src[i])))) {} \
4998
444k
    else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; }
4999
444k
    repeat16_incr(expr_jump)
5000
397k
#undef expr_jump
5001
397k
    }
5002
5003
655k
    byte_move_16(dst, src);
5004
655k
    dst += 16; src += 16;
5005
655k
    goto copy_ascii;
5006
5007
    /*
5008
     The memory is copied forward since `dst < src`.
5009
     So it's safe to move one extra byte to reduce instruction count.
5010
     */
5011
0
#define expr_jump(i) \
5012
1.81M
    copy_ascii_stop_##i: \
5013
1.81M
    byte_move_forward(dst, src, i); \
5014
1.81M
    dst += i; src += i; \
5015
1.81M
    goto copy_utf8;
5016
1.81M
    repeat16_incr(expr_jump)
5017
0
#undef expr_jump
5018
5019
1.81M
copy_utf8:
5020
1.81M
    if (*src & 0x80) { /* non-ASCII character */
5021
1.30M
        pos = src;
5022
1.30M
        uni = byte_load_4(src);
5023
#if YYJSON_DISABLE_UTF8_VALIDATION
5024
        while (true) repeat4({
5025
            if ((uni & utf8_seq(b3_mask)) == utf8_seq(b3_patt)) {
5026
                byte_copy_4(dst, &uni);
5027
                dst += 3; src += 3;
5028
                uni = byte_load_4(src);
5029
            } else break;
5030
        })
5031
        if ((uni & utf8_seq(b1_mask)) == utf8_seq(b1_patt)) goto copy_ascii;
5032
        while (true) repeat4({
5033
            if ((uni & utf8_seq(b2_mask)) == utf8_seq(b2_patt)) {
5034
                byte_copy_2(dst, &uni);
5035
                dst += 2; src += 2;
5036
                uni = byte_load_4(src);
5037
            } else break;
5038
        })
5039
        while (true) repeat4({
5040
            if ((uni & utf8_seq(b4_mask)) == utf8_seq(b4_patt)) {
5041
                byte_copy_4(dst, &uni);
5042
                dst += 4; src += 4;
5043
                uni = byte_load_4(src);
5044
            } else break;
5045
        })
5046
#else
5047
1.32M
        while (is_utf8_seq3(uni)) {
5048
26.5k
            byte_copy_4(dst, &uni);
5049
26.5k
            dst += 3; src += 3;
5050
26.5k
            uni = byte_load_4(src);
5051
26.5k
        }
5052
1.30M
        if (is_utf8_seq1(uni)) goto copy_ascii;
5053
2.32M
        while (is_utf8_seq2(uni)) {
5054
1.03M
            byte_copy_2(dst, &uni);
5055
1.03M
            dst += 2; src += 2;
5056
1.03M
            uni = byte_load_4(src);
5057
1.03M
        }
5058
1.33M
        while (is_utf8_seq4(uni)) {
5059
48.5k
            byte_copy_4(dst, &uni);
5060
48.5k
            dst += 4; src += 4;
5061
48.5k
            uni = byte_load_4(src);
5062
48.5k
        }
5063
1.28M
#endif
5064
1.28M
        if (unlikely(pos == src)) {
5065
215k
            if (!has_allow(INVALID_UNICODE)) {
5066
814
                return_err(src, MSG_ERR_UTF8);
5067
814
            }
5068
214k
            goto copy_ascii_stop_1;
5069
215k
        }
5070
1.07M
        goto copy_ascii;
5071
1.28M
    }
5072
512k
    goto copy_escape;
5073
5074
1.81M
#undef return_err
5075
1.81M
}
5076
5077
static_inline bool read_str(u8 **ptr, u8 *eof, yyjson_read_flag flg,
5078
518k
                            yyjson_val *val, const char **msg) {
5079
518k
    return read_str_opt('\"', ptr, eof, flg, val, msg, NULL);
5080
518k
}
5081
5082
static_inline bool read_str_con(u8 **ptr, u8 *eof, yyjson_read_flag flg,
5083
0
                                yyjson_val *val, const char **msg, u8 **con) {
5084
0
    return read_str_opt('\"', ptr, eof, flg, val, msg, con);
5085
0
}
5086
5087
static_noinline bool read_str_sq(u8 **ptr, u8 *eof, yyjson_read_flag flg,
5088
5.31k
                                 yyjson_val *val, const char **msg) {
5089
5.31k
    return read_str_opt('\'', ptr, eof, flg, val, msg, NULL);
5090
5.31k
}
5091
5092
/** Read unquoted key (identifier name). */
5093
static_noinline bool read_str_id(u8 **ptr, u8 *eof, yyjson_read_flag flg,
5094
23.8k
                                 u8 **pre, yyjson_val *val, const char **msg) {
5095
23.8k
#define return_err(_end, _msg) do { \
5096
429
    *msg = _msg; \
5097
429
    *end = _end; \
5098
429
    return false; \
5099
429
} while (false)
5100
5101
23.8k
#define return_suc(_str_end, _cur_end) do { \
5102
23.3k
    val->tag = ((u64)(_str_end - hdr) << YYJSON_TAG_BIT) | \
5103
23.3k
                (u64)(YYJSON_TYPE_STR); \
5104
23.3k
    val->uni.str = (const char *)hdr; \
5105
23.3k
    *pre = _str_end; *end = _cur_end; \
5106
23.3k
    return true; \
5107
23.3k
} while (false)
5108
5109
23.8k
    u8 *hdr = *ptr;
5110
23.8k
    u8 **end = ptr;
5111
23.8k
    u8 *src = hdr, *dst = NULL;
5112
23.8k
    u32 uni, tmp;
5113
5114
    /* add null-terminator for previous raw string */
5115
23.8k
    **pre = '\0';
5116
5117
28.1k
skip_ascii:
5118
28.1k
#define expr_jump(i) \
5119
137k
    if (likely(char_is_id_ascii(src[i]))) {} \
5120
137k
    else goto skip_ascii_stop##i;
5121
5122
28.1k
#define expr_stop(i) \
5123
28.1k
    skip_ascii_stop##i: \
5124
27.2k
    src += i; \
5125
27.2k
    goto skip_ascii_end;
5126
5127
137k
    repeat16_incr(expr_jump)
5128
830
    src += 16;
5129
830
    goto skip_ascii;
5130
27.2k
    repeat16_incr(expr_stop)
5131
5132
0
#undef expr_jump
5133
0
#undef expr_stop
5134
5135
27.2k
skip_ascii_end:
5136
27.2k
    gcc_store_barrier(*src);
5137
27.2k
    if (likely(!char_is_id_next(*src))) {
5138
17.4k
        return_suc(src, src);
5139
17.4k
    }
5140
5141
9.87k
skip_utf8:
5142
14.7k
    while (*src >= 0x80) {
5143
8.52k
        if (has_allow(EXT_WHITESPACE)) {
5144
8.52k
            if (char_is_space_ext(*src) && ext_space_len(src)) {
5145
3.38k
                return_suc(src, src);
5146
3.38k
            }
5147
8.52k
        }
5148
5.13k
        uni = byte_load_4(src);
5149
5.13k
        if (is_utf8_seq2(uni)) {
5150
3.53k
            src += 2;
5151
3.53k
        } else if (is_utf8_seq3(uni)) {
5152
860
            src += 3;
5153
860
        } else if (is_utf8_seq4(uni)) {
5154
523
            src += 4;
5155
523
        } else {
5156
217
#if !YYJSON_DISABLE_UTF8_VALIDATION
5157
217
            if (!has_allow(INVALID_UNICODE)) return_err(src, MSG_ERR_UTF8);
5158
0
#endif
5159
0
            src += 1;
5160
0
        }
5161
5.13k
    }
5162
6.27k
    if (char_is_id_ascii(*src)) goto skip_ascii;
5163
5164
    /* The escape character appears, we need to copy it. */
5165
2.78k
    dst = src;
5166
4.39k
copy_escape:
5167
4.39k
    if (byte_match_2(src, "\\u")) {
5168
3.53k
        if (!read_uni_esc(&src, &dst, msg)) return_err(src, *msg);
5169
3.53k
    } else {
5170
855
        if (!char_is_id_next(*src)) return_suc(dst, src);
5171
38
        return_err(src, "unexpected character in key");
5172
38
    }
5173
5174
10.8k
copy_ascii:
5175
    /*
5176
     Copy continuous ASCII, loop unrolling, same as the following code:
5177
5178
     while (true) repeat16({
5179
        if (char_is_ascii_skip(*src)) *dst++ = *src++;
5180
        else break;
5181
     })
5182
     */
5183
10.8k
#define expr_jump(i) \
5184
63.3k
    if (likely((char_is_id_ascii(src[i])))) {} \
5185
63.3k
    else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; }
5186
63.3k
    repeat16_incr(expr_jump)
5187
367
#undef expr_jump
5188
5189
367
    byte_move_16(dst, src);
5190
367
    dst += 16; src += 16;
5191
367
    goto copy_ascii;
5192
5193
0
#define expr_jump(i) \
5194
10.5k
    copy_ascii_stop_##i: \
5195
10.5k
    byte_move_forward(dst, src, i); \
5196
10.5k
    dst += i; src += i; \
5197
10.5k
    goto copy_utf8;
5198
10.5k
    repeat16_incr(expr_jump)
5199
0
#undef expr_jump
5200
5201
10.5k
copy_utf8:
5202
18.4k
    while (*src >= 0x80) { /* non-ASCII character */
5203
9.79k
        if (has_allow(EXT_WHITESPACE)) {
5204
9.79k
            if (char_is_space_ext(*src) && ext_space_len(src)) {
5205
1.75k
                return_suc(dst, src);
5206
1.75k
            }
5207
9.79k
        }
5208
8.03k
        uni = byte_load_4(src);
5209
8.03k
        if (is_utf8_seq2(uni)) {
5210
6.97k
            byte_copy_2(dst, &uni);
5211
6.97k
            dst += 2; src += 2;
5212
6.97k
        } else if (is_utf8_seq3(uni)) {
5213
550
            byte_copy_4(dst, &uni);
5214
550
            dst += 3; src += 3;
5215
550
        } else if (is_utf8_seq4(uni)) {
5216
388
            byte_copy_4(dst, &uni);
5217
388
            dst += 4; src += 4;
5218
388
        } else {
5219
123
#if !YYJSON_DISABLE_UTF8_VALIDATION
5220
123
            if (!has_allow(INVALID_UNICODE)) return_err(src, MSG_ERR_UTF8);
5221
0
#endif
5222
0
            *dst = *src;
5223
0
            dst += 1; src += 1;
5224
0
        }
5225
8.03k
    }
5226
8.62k
    if (char_is_id_ascii(*src)) goto copy_ascii;
5227
1.60k
    goto copy_escape;
5228
5229
8.62k
#undef return_err
5230
8.62k
#undef return_suc
5231
8.62k
}
5232
5233
5234
5235
/*==============================================================================
5236
 * MARK: - JSON Reader Implementation (Private)
5237
 *
5238
 * We use goto statements to build the finite state machine (FSM).
5239
 * The FSM's state was held by program counter (PC) and the 'goto' make the
5240
 * state transitions.
5241
 *============================================================================*/
5242
5243
/** Read single value JSON document. */
5244
static_noinline yyjson_doc *read_root_single(u8 *hdr, u8 *cur, u8 *eof,
5245
                                             yyjson_alc alc,
5246
                                             yyjson_read_flag flg,
5247
32.1k
                                             yyjson_read_err *err) {
5248
32.1k
#define return_err(_pos, _code, _msg) do { \
5249
15.6k
    if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \
5250
3.17k
        err->pos = (usize)(eof - hdr); \
5251
3.17k
        err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
5252
3.17k
        err->msg = MSG_NOT_END; \
5253
12.4k
    } else { \
5254
12.4k
        err->pos = (usize)(_pos - hdr); \
5255
12.4k
        err->code = YYJSON_READ_ERROR_##_code; \
5256
12.4k
        err->msg = _msg; \
5257
12.4k
    } \
5258
15.6k
    if (val_hdr) alc.free(alc.ctx, val_hdr); \
5259
15.6k
    return NULL; \
5260
15.6k
} while (false)
5261
5262
32.1k
    usize hdr_len; /* value count used by doc */
5263
32.1k
    usize alc_num; /* value count capacity */
5264
32.1k
    yyjson_val *val_hdr; /* the head of allocated values */
5265
32.1k
    yyjson_val *val; /* current value */
5266
32.1k
    yyjson_doc *doc; /* the JSON document, equals to val_hdr */
5267
32.1k
    const char *msg; /* error message */
5268
5269
32.1k
    u8 raw_end[1]; /* raw end for null-terminator */
5270
32.1k
    u8 *raw_ptr = raw_end;
5271
32.1k
    u8 **pre = &raw_ptr; /* previous raw end pointer */
5272
5273
32.1k
    hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
5274
32.1k
    hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
5275
32.1k
    alc_num = hdr_len + 1; /* single value */
5276
5277
32.1k
    val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_num * sizeof(yyjson_val));
5278
32.1k
    if (unlikely(!val_hdr)) goto fail_alloc;
5279
32.1k
    val = val_hdr + hdr_len;
5280
5281
32.1k
    if (char_is_num(*cur)) {
5282
18.8k
        if (likely(read_num(&cur, pre, flg, val, &msg))) goto doc_end;
5283
1.41k
        goto fail_number;
5284
18.8k
    }
5285
13.3k
    if (*cur == '"') {
5286
4.17k
        if (likely(read_str(&cur, eof, flg, val, &msg))) goto doc_end;
5287
2.86k
        goto fail_string;
5288
4.17k
    }
5289
9.13k
    if (*cur == 't') {
5290
352
        if (likely(read_true(&cur, val))) goto doc_end;
5291
339
        goto fail_literal_true;
5292
352
    }
5293
8.78k
    if (*cur == 'f') {
5294
443
        if (likely(read_false(&cur, val))) goto doc_end;
5295
368
        goto fail_literal_false;
5296
443
    }
5297
8.34k
    if (*cur == 'n') {
5298
218
        if (likely(read_null(&cur, val))) goto doc_end;
5299
206
        if (has_allow(INF_AND_NAN)) {
5300
42
            if (read_nan(&cur, pre, flg, val)) goto doc_end;
5301
42
        }
5302
203
        goto fail_literal_null;
5303
206
    }
5304
8.12k
    if (has_allow(INF_AND_NAN)) {
5305
964
        if (read_inf_or_nan(&cur, pre, flg, val)) goto doc_end;
5306
964
    }
5307
8.11k
    if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
5308
711
        if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto doc_end;
5309
653
        goto fail_string;
5310
711
    }
5311
7.40k
    goto fail_character;
5312
5313
18.9k
doc_end:
5314
    /* check invalid contents after json document */
5315
18.9k
    if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) {
5316
3.61k
        while (char_is_space(*cur)) cur++;
5317
2.71k
        if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5318
107
            if (!skip_trivia(&cur, eof, flg) && cur == eof) {
5319
9
                goto fail_comment;
5320
9
            }
5321
107
        }
5322
2.70k
        if (unlikely(cur < eof)) goto fail_garbage;
5323
2.70k
    }
5324
5325
16.4k
    **pre = '\0';
5326
16.4k
    doc = (yyjson_doc *)val_hdr;
5327
16.4k
    doc->root = val_hdr + hdr_len;
5328
16.4k
    doc->alc = alc;
5329
16.4k
    doc->dat_read = (usize)(cur - hdr);
5330
16.4k
    doc->val_read = 1;
5331
16.4k
    doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
5332
16.4k
    return doc;
5333
5334
3.51k
fail_string:        return_err(cur, INVALID_STRING, msg);
5335
1.41k
fail_number:        return_err(cur, INVALID_NUMBER, msg);
5336
0
fail_alloc:         return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
5337
339
fail_literal_true:  return_err(cur, LITERAL, MSG_CHAR_T);
5338
368
fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F);
5339
203
fail_literal_null:  return_err(cur, LITERAL, MSG_CHAR_N);
5340
7.40k
fail_character:     return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
5341
9
fail_comment:       return_err(cur, INVALID_COMMENT, MSG_COMMENT);
5342
2.41k
fail_garbage:       return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
5343
0
fail_depth:         return_err(cur, DEPTH, MSG_DEPTH);
5344
5345
0
#undef return_err
5346
0
}
5347
5348
/** Read JSON document (accept all style, but optimized for minify). */
5349
static_inline yyjson_doc *read_root_minify(u8 *hdr, u8 *cur, u8 *eof,
5350
                                           yyjson_alc alc,
5351
                                           yyjson_read_flag flg,
5352
51.1k
                                           yyjson_read_err *err) {
5353
51.1k
#define return_err(_pos, _code, _msg) do { \
5354
33.4k
    if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \
5355
19.0k
        err->pos = (usize)(eof - hdr); \
5356
19.0k
        err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
5357
19.0k
        err->msg = MSG_NOT_END; \
5358
19.0k
    } else { \
5359
14.3k
        err->pos = (usize)(_pos - hdr); \
5360
14.3k
        err->code = YYJSON_READ_ERROR_##_code; \
5361
14.3k
        err->msg = _msg; \
5362
14.3k
    } \
5363
33.4k
    if (val_hdr) alc.free(alc.ctx, val_hdr); \
5364
33.4k
    return NULL; \
5365
33.4k
} while (false)
5366
5367
4.11M
#define val_incr() do { \
5368
4.11M
    val++; \
5369
4.11M
    if (unlikely(val >= val_end)) { \
5370
6.37k
        usize alc_old = alc_len; \
5371
6.37k
        usize val_ofs = (usize)(val - val_hdr); \
5372
6.37k
        usize ctn_ofs = (usize)(ctn - val_hdr); \
5373
6.37k
        alc_len += alc_len / 2; \
5374
6.37k
        if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \
5375
6.37k
        val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
5376
6.37k
            alc_old * sizeof(yyjson_val), \
5377
6.37k
            alc_len * sizeof(yyjson_val)); \
5378
6.37k
        if ((!val_tmp)) goto fail_alloc; \
5379
6.37k
        val = val_tmp + val_ofs; \
5380
6.37k
        ctn = val_tmp + ctn_ofs; \
5381
6.37k
        val_hdr = val_tmp; \
5382
6.37k
        val_end = val_tmp + (alc_len - 2); \
5383
6.37k
    } \
5384
4.11M
} while (false)
5385
5386
51.1k
    usize dat_len; /* data length in bytes, hint for allocator */
5387
51.1k
    usize hdr_len; /* value count used by yyjson_doc */
5388
51.1k
    usize alc_len; /* value count allocated */
5389
51.1k
    usize alc_max; /* maximum value count for allocator */
5390
51.1k
    usize ctn_len; /* the number of elements in current container */
5391
51.1k
    yyjson_val *val_hdr; /* the head of allocated values */
5392
51.1k
    yyjson_val *val_end; /* the end of allocated values */
5393
51.1k
    yyjson_val *val_tmp; /* temporary pointer for realloc */
5394
51.1k
    yyjson_val *val; /* current JSON value */
5395
51.1k
    yyjson_val *ctn; /* current container */
5396
51.1k
    yyjson_val *ctn_parent; /* parent of current container */
5397
51.1k
    yyjson_doc *doc; /* the JSON document, equals to val_hdr */
5398
51.1k
    const char *msg; /* error message */
5399
5400
51.1k
    u8 raw_end[1]; /* raw end for null-terminator */
5401
51.1k
    u8 *raw_ptr = raw_end;
5402
51.1k
    u8 **pre = &raw_ptr; /* previous raw end pointer */
5403
5404
#if YYJSON_READER_DEPTH_LIMIT
5405
    u32 container_depth = 0; /* current array/object depth */
5406
#endif
5407
5408
51.1k
    dat_len = has_flg(STOP_WHEN_DONE) ? 256 : (usize)(eof - cur);
5409
51.1k
    hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
5410
51.1k
    hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
5411
51.1k
    alc_max = USIZE_MAX / sizeof(yyjson_val);
5412
51.1k
    alc_len = hdr_len + (dat_len / YYJSON_READER_ESTIMATED_MINIFY_RATIO) + 4;
5413
51.1k
    alc_len = yyjson_min(alc_len, alc_max);
5414
5415
51.1k
    val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_len * sizeof(yyjson_val));
5416
51.1k
    if (unlikely(!val_hdr)) goto fail_alloc;
5417
51.1k
    val_end = val_hdr + (alc_len - 2); /* padding for key-value pair reading */
5418
51.1k
    val = val_hdr + hdr_len;
5419
51.1k
    ctn = val;
5420
51.1k
    ctn_len = 0;
5421
5422
51.1k
    if (*cur++ == '{') {
5423
19.0k
        ctn->tag = YYJSON_TYPE_OBJ;
5424
19.0k
        ctn->uni.ofs = 0;
5425
19.0k
        goto obj_key_begin;
5426
32.0k
    } else {
5427
32.0k
        ctn->tag = YYJSON_TYPE_ARR;
5428
32.0k
        ctn->uni.ofs = 0;
5429
32.0k
        goto arr_val_begin;
5430
32.0k
    }
5431
5432
1.07M
arr_begin:
5433
#if YYJSON_READER_DEPTH_LIMIT
5434
    container_depth++;
5435
    if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) {
5436
        goto fail_depth;
5437
    }
5438
#endif
5439
    /* save current container */
5440
1.07M
    ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
5441
1.07M
               (ctn->tag & YYJSON_TAG_MASK);
5442
5443
    /* create a new array value, save parent container offset */
5444
1.07M
    val_incr();
5445
1.07M
    val->tag = YYJSON_TYPE_ARR;
5446
1.07M
    val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
5447
5448
    /* push the new array value as current container */
5449
1.07M
    ctn = val;
5450
1.07M
    ctn_len = 0;
5451
5452
4.28M
arr_val_begin:
5453
4.28M
    if (*cur == '{') {
5454
30.6k
        cur++;
5455
30.6k
        goto obj_begin;
5456
30.6k
    }
5457
4.25M
    if (*cur == '[') {
5458
1.06M
        cur++;
5459
1.06M
        goto arr_begin;
5460
1.06M
    }
5461
3.19M
    if (char_is_num(*cur)) {
5462
2.49M
        val_incr();
5463
2.49M
        ctn_len++;
5464
2.49M
        if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_end;
5465
1.58k
        goto fail_number;
5466
2.49M
    }
5467
693k
    if (*cur == '"') {
5468
32.5k
        val_incr();
5469
32.5k
        ctn_len++;
5470
32.5k
        if (likely(read_str(&cur, eof, flg, val, &msg))) goto arr_val_end;
5471
2.68k
        goto fail_string;
5472
32.5k
    }
5473
661k
    if (*cur == 't') {
5474
12.4k
        val_incr();
5475
12.4k
        ctn_len++;
5476
12.4k
        if (likely(read_true(&cur, val))) goto arr_val_end;
5477
182
        goto fail_literal_true;
5478
12.4k
    }
5479
648k
    if (*cur == 'f') {
5480
18.3k
        val_incr();
5481
18.3k
        ctn_len++;
5482
18.3k
        if (likely(read_false(&cur, val))) goto arr_val_end;
5483
237
        goto fail_literal_false;
5484
18.3k
    }
5485
630k
    if (*cur == 'n') {
5486
137k
        val_incr();
5487
137k
        ctn_len++;
5488
137k
        if (likely(read_null(&cur, val))) goto arr_val_end;
5489
509
        if (has_allow(INF_AND_NAN)) {
5490
384
            if (read_nan(&cur, pre, flg, val)) goto arr_val_end;
5491
384
        }
5492
169
        goto fail_literal_null;
5493
509
    }
5494
492k
    if (*cur == ']') {
5495
352k
        cur++;
5496
352k
        if (likely(ctn_len == 0)) goto arr_end;
5497
823
        if (has_allow(TRAILING_COMMAS)) goto arr_end;
5498
772
        do { cur--; } while (*cur != ',');
5499
92
        goto fail_trailing_comma;
5500
823
    }
5501
140k
    if (char_is_space(*cur)) {
5502
284k
        while (char_is_space(*++cur));
5503
91.0k
        goto arr_val_begin;
5504
91.0k
    }
5505
49.5k
    if (has_allow(INF_AND_NAN) &&
5506
46.2k
        (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
5507
1.09k
        val_incr();
5508
1.09k
        ctn_len++;
5509
1.09k
        if (read_inf_or_nan(&cur, pre, flg, val)) goto arr_val_end;
5510
49
        goto fail_character_val;
5511
1.09k
    }
5512
48.4k
    if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
5513
2.35k
        val_incr();
5514
2.35k
        ctn_len++;
5515
2.35k
        if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto arr_val_end;
5516
22
        goto fail_string;
5517
2.35k
    }
5518
46.0k
    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5519
43.7k
        if (skip_trivia(&cur, eof, flg)) goto arr_val_begin;
5520
74
        if (cur == eof) goto fail_comment;
5521
74
    }
5522
2.37k
    goto fail_character_val;
5523
5524
4.79M
arr_val_end:
5525
4.79M
    if (*cur == ',') {
5526
3.04M
        cur++;
5527
3.04M
        goto arr_val_begin;
5528
3.04M
    }
5529
1.75M
    if (*cur == ']') {
5530
661k
        cur++;
5531
661k
        goto arr_end;
5532
661k
    }
5533
1.09M
    if (char_is_space(*cur)) {
5534
352k
        while (char_is_space(*++cur));
5535
289k
        goto arr_val_end;
5536
289k
    }
5537
800k
    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5538
792k
        if (skip_trivia(&cur, eof, flg)) goto arr_val_end;
5539
73
        if (cur == eof) goto fail_comment;
5540
73
    }
5541
7.88k
    goto fail_character_arr_end;
5542
5543
1.01M
arr_end:
5544
#if YYJSON_READER_DEPTH_LIMIT
5545
    container_depth--;
5546
#endif
5547
    /* get parent container */
5548
1.01M
    ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
5549
5550
    /* save the next sibling value offset */
5551
1.01M
    ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
5552
1.01M
    ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
5553
1.01M
    if (unlikely(ctn == ctn_parent)) goto doc_end;
5554
5555
    /* pop parent as current container */
5556
998k
    ctn = ctn_parent;
5557
998k
    ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
5558
998k
    if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
5559
5.94k
        goto obj_val_end;
5560
992k
    } else {
5561
992k
        goto arr_val_end;
5562
992k
    }
5563
5564
60.0k
obj_begin:
5565
#if YYJSON_READER_DEPTH_LIMIT
5566
    container_depth++;
5567
    if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) {
5568
        goto fail_depth;
5569
    }
5570
#endif
5571
    /* push container */
5572
60.0k
    ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
5573
60.0k
               (ctn->tag & YYJSON_TAG_MASK);
5574
60.0k
    val_incr();
5575
60.0k
    val->tag = YYJSON_TYPE_OBJ;
5576
    /* offset to the parent */
5577
60.0k
    val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
5578
60.0k
    ctn = val;
5579
60.0k
    ctn_len = 0;
5580
5581
319k
obj_key_begin:
5582
319k
    if (likely(*cur == '"')) {
5583
259k
        val_incr();
5584
259k
        ctn_len++;
5585
259k
        if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_key_end;
5586
2.82k
        goto fail_string;
5587
259k
    }
5588
59.5k
    if (likely(*cur == '}')) {
5589
17.8k
        cur++;
5590
17.8k
        if (likely(ctn_len == 0)) goto obj_end;
5591
265
        if (has_allow(TRAILING_COMMAS)) goto obj_end;
5592
760
        do { cur--; } while (*cur != ',');
5593
37
        goto fail_trailing_comma;
5594
265
    }
5595
41.7k
    if (char_is_space(*cur)) {
5596
42.4k
        while (char_is_space(*++cur));
5597
20.5k
        goto obj_key_begin;
5598
20.5k
    }
5599
21.2k
    if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
5600
704
        val_incr();
5601
704
        ctn_len++;
5602
704
        if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_key_end;
5603
22
        goto fail_string;
5604
704
    }
5605
20.4k
    if (has_allow(UNQUOTED_KEY) && char_is_id_start(*cur)) {
5606
15.1k
        val_incr();
5607
15.1k
        ctn_len++;
5608
15.1k
        if (read_str_id(&cur, eof, flg, pre, val, &msg)) goto obj_key_end;
5609
356
        goto fail_string;
5610
15.1k
    }
5611
5.30k
    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5612
1.95k
        if (skip_trivia(&cur, eof, flg)) goto obj_key_begin;
5613
28
        if (cur == eof) goto fail_comment;
5614
28
    }
5615
3.36k
    goto fail_character_obj_key;
5616
5617
281k
obj_key_end:
5618
281k
    if (*cur == ':') {
5619
271k
        cur++;
5620
271k
        goto obj_val_begin;
5621
271k
    }
5622
9.69k
    if (char_is_space(*cur)) {
5623
3.93k
        while (char_is_space(*++cur));
5624
2.70k
        goto obj_key_end;
5625
2.70k
    }
5626
6.99k
    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5627
6.07k
        if (skip_trivia(&cur, eof, flg)) goto obj_key_end;
5628
40
        if (cur == eof) goto fail_comment;
5629
40
    }
5630
955
    goto fail_character_obj_sep;
5631
5632
286k
obj_val_begin:
5633
286k
    if (*cur == '"') {
5634
59.0k
        val++;
5635
59.0k
        ctn_len++;
5636
59.0k
        if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_val_end;
5637
2.33k
        goto fail_string;
5638
59.0k
    }
5639
227k
    if (char_is_num(*cur)) {
5640
168k
        val++;
5641
168k
        ctn_len++;
5642
168k
        if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_end;
5643
1.04k
        goto fail_number;
5644
168k
    }
5645
59.5k
    if (*cur == '{') {
5646
29.3k
        cur++;
5647
29.3k
        goto obj_begin;
5648
29.3k
    }
5649
30.1k
    if (*cur == '[') {
5650
7.86k
        cur++;
5651
7.86k
        goto arr_begin;
5652
7.86k
    }
5653
22.3k
    if (*cur == 't') {
5654
1.99k
        val++;
5655
1.99k
        ctn_len++;
5656
1.99k
        if (likely(read_true(&cur, val))) goto obj_val_end;
5657
56
        goto fail_literal_true;
5658
1.99k
    }
5659
20.3k
    if (*cur == 'f') {
5660
1.05k
        val++;
5661
1.05k
        ctn_len++;
5662
1.05k
        if (likely(read_false(&cur, val))) goto obj_val_end;
5663
111
        goto fail_literal_false;
5664
1.05k
    }
5665
19.2k
    if (*cur == 'n') {
5666
1.57k
        val++;
5667
1.57k
        ctn_len++;
5668
1.57k
        if (likely(read_null(&cur, val))) goto obj_val_end;
5669
337
        if (has_allow(INF_AND_NAN)) {
5670
269
            if (read_nan(&cur, pre, flg, val)) goto obj_val_end;
5671
269
        }
5672
111
        goto fail_literal_null;
5673
337
    }
5674
17.6k
    if (char_is_space(*cur)) {
5675
18.0k
        while (char_is_space(*++cur));
5676
14.2k
        goto obj_val_begin;
5677
14.2k
    }
5678
3.45k
    if (has_allow(INF_AND_NAN) &&
5679
2.39k
        (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
5680
1.59k
        val++;
5681
1.59k
        ctn_len++;
5682
1.59k
        if (read_inf_or_nan(&cur, pre, flg, val)) goto obj_val_end;
5683
32
        goto fail_character_val;
5684
1.59k
    }
5685
1.85k
    if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
5686
385
        val++;
5687
385
        ctn_len++;
5688
385
        if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_val_end;
5689
4
        goto fail_string;
5690
385
    }
5691
1.46k
    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5692
1.12k
        if (skip_trivia(&cur, eof, flg)) goto obj_val_begin;
5693
21
        if (cur == eof) goto fail_comment;
5694
21
    }
5695
362
    goto fail_character_val;
5696
5697
267k
obj_val_end:
5698
267k
    if (likely(*cur == ',')) {
5699
217k
        cur++;
5700
217k
        goto obj_key_begin;
5701
217k
    }
5702
49.5k
    if (likely(*cur == '}')) {
5703
31.3k
        cur++;
5704
31.3k
        goto obj_end;
5705
31.3k
    }
5706
18.2k
    if (char_is_space(*cur)) {
5707
13.5k
        while (char_is_space(*++cur));
5708
10.4k
        goto obj_val_end;
5709
10.4k
    }
5710
7.76k
    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5711
1.49k
        if (skip_trivia(&cur, eof, flg)) goto obj_val_end;
5712
63
        if (cur == eof) goto fail_comment;
5713
63
    }
5714
6.32k
    goto fail_character_obj_end;
5715
5716
49.0k
obj_end:
5717
#if YYJSON_READER_DEPTH_LIMIT
5718
    container_depth--;
5719
#endif
5720
    /* pop container */
5721
49.0k
    ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
5722
    /* point to the next value */
5723
49.0k
    ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
5724
49.0k
    ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
5725
49.0k
    if (unlikely(ctn == ctn_parent)) goto doc_end;
5726
46.3k
    ctn = ctn_parent;
5727
46.3k
    ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
5728
46.3k
    if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
5729
19.2k
        goto obj_val_end;
5730
27.0k
    } else {
5731
27.0k
        goto arr_val_end;
5732
27.0k
    }
5733
5734
17.8k
doc_end:
5735
    /* check invalid contents after json document */
5736
17.8k
    if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) {
5737
1.26k
        while (char_is_space(*cur)) cur++;
5738
357
        if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5739
44
            if (!skip_trivia(&cur, eof, flg) && cur == eof) {
5740
7
                goto fail_comment;
5741
7
            }
5742
44
        }
5743
350
        if (unlikely(cur < eof)) goto fail_garbage;
5744
350
    }
5745
5746
17.6k
    **pre = '\0';
5747
17.6k
    doc = (yyjson_doc *)val_hdr;
5748
17.6k
    doc->root = val_hdr + hdr_len;
5749
17.6k
    doc->alc = alc;
5750
17.6k
    doc->dat_read = (usize)(cur - hdr);
5751
17.6k
    doc->val_read = (usize)((val - doc->root) + 1);
5752
17.6k
    doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
5753
17.6k
    return doc;
5754
5755
8.24k
fail_string:            return_err(cur, INVALID_STRING, msg);
5756
2.62k
fail_number:            return_err(cur, INVALID_NUMBER, msg);
5757
0
fail_alloc:             return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
5758
129
fail_trailing_comma:    return_err(cur, JSON_STRUCTURE, MSG_COMMA);
5759
238
fail_literal_true:      return_err(cur, LITERAL, MSG_CHAR_T);
5760
348
fail_literal_false:     return_err(cur, LITERAL, MSG_CHAR_F);
5761
280
fail_literal_null:      return_err(cur, LITERAL, MSG_CHAR_N);
5762
2.82k
fail_character_val:     return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
5763
7.88k
fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END);
5764
3.36k
fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY);
5765
955
fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
5766
6.32k
fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
5767
60
fail_comment:           return_err(cur, INVALID_COMMENT, MSG_COMMENT);
5768
180
fail_garbage:           return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
5769
0
fail_depth:             return_err(cur, DEPTH, MSG_DEPTH);
5770
5771
0
#undef val_incr
5772
0
#undef return_err
5773
0
}
5774
5775
/** Read JSON document (accept all style, but optimized for pretty). */
5776
static_inline yyjson_doc *read_root_pretty(u8 *hdr, u8 *cur, u8 *eof,
5777
                                           yyjson_alc alc,
5778
                                           yyjson_read_flag flg,
5779
31.5k
                                           yyjson_read_err *err) {
5780
31.5k
#define return_err(_pos, _code, _msg) do { \
5781
31.1k
    if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \
5782
18.7k
        err->pos = (usize)(eof - hdr); \
5783
18.7k
        err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
5784
18.7k
        err->msg = MSG_NOT_END; \
5785
18.7k
    } else { \
5786
12.4k
        err->pos = (usize)(_pos - hdr); \
5787
12.4k
        err->code = YYJSON_READ_ERROR_##_code; \
5788
12.4k
        err->msg = _msg; \
5789
12.4k
    } \
5790
31.1k
    if (val_hdr) alc.free(alc.ctx, val_hdr); \
5791
31.1k
    return NULL; \
5792
31.1k
} while (false)
5793
5794
1.03M
#define val_incr() do { \
5795
1.03M
    val++; \
5796
1.03M
    if (unlikely(val >= val_end)) { \
5797
11.1k
        usize alc_old = alc_len; \
5798
11.1k
        usize val_ofs = (usize)(val - val_hdr); \
5799
11.1k
        usize ctn_ofs = (usize)(ctn - val_hdr); \
5800
11.1k
        alc_len += alc_len / 2; \
5801
11.1k
        if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \
5802
11.1k
        val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
5803
11.1k
            alc_old * sizeof(yyjson_val), \
5804
11.1k
            alc_len * sizeof(yyjson_val)); \
5805
11.1k
        if ((!val_tmp)) goto fail_alloc; \
5806
11.1k
        val = val_tmp + val_ofs; \
5807
11.1k
        ctn = val_tmp + ctn_ofs; \
5808
11.1k
        val_hdr = val_tmp; \
5809
11.1k
        val_end = val_tmp + (alc_len - 2); \
5810
11.1k
    } \
5811
1.03M
} while (false)
5812
5813
31.5k
    usize dat_len; /* data length in bytes, hint for allocator */
5814
31.5k
    usize hdr_len; /* value count used by yyjson_doc */
5815
31.5k
    usize alc_len; /* value count allocated */
5816
31.5k
    usize alc_max; /* maximum value count for allocator */
5817
31.5k
    usize ctn_len; /* the number of elements in current container */
5818
31.5k
    yyjson_val *val_hdr; /* the head of allocated values */
5819
31.5k
    yyjson_val *val_end; /* the end of allocated values */
5820
31.5k
    yyjson_val *val_tmp; /* temporary pointer for realloc */
5821
31.5k
    yyjson_val *val; /* current JSON value */
5822
31.5k
    yyjson_val *ctn; /* current container */
5823
31.5k
    yyjson_val *ctn_parent; /* parent of current container */
5824
31.5k
    yyjson_doc *doc; /* the JSON document, equals to val_hdr */
5825
31.5k
    const char *msg; /* error message */
5826
5827
31.5k
    u8 raw_end[1]; /* raw end for null-terminator */
5828
31.5k
    u8 *raw_ptr = raw_end;
5829
31.5k
    u8 **pre = &raw_ptr; /* previous raw end pointer */
5830
#if YYJSON_READER_DEPTH_LIMIT
5831
    u32 container_depth = 0; /* current array/object depth */
5832
#endif
5833
5834
31.5k
    dat_len = has_flg(STOP_WHEN_DONE) ? 256 : (usize)(eof - cur);
5835
31.5k
    hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
5836
31.5k
    hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
5837
31.5k
    alc_max = USIZE_MAX / sizeof(yyjson_val);
5838
31.5k
    alc_len = hdr_len + (dat_len / YYJSON_READER_ESTIMATED_PRETTY_RATIO) + 4;
5839
31.5k
    alc_len = yyjson_min(alc_len, alc_max);
5840
5841
31.5k
    val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_len * sizeof(yyjson_val));
5842
31.5k
    if (unlikely(!val_hdr)) goto fail_alloc;
5843
31.5k
    val_end = val_hdr + (alc_len - 2); /* padding for key-value pair reading */
5844
31.5k
    val = val_hdr + hdr_len;
5845
31.5k
    ctn = val;
5846
31.5k
    ctn_len = 0;
5847
5848
31.5k
    if (*cur++ == '{') {
5849
12.5k
        ctn->tag = YYJSON_TYPE_OBJ;
5850
12.5k
        ctn->uni.ofs = 0;
5851
12.5k
        if (*cur == '\n') cur++;
5852
12.5k
        goto obj_key_begin;
5853
19.0k
    } else {
5854
19.0k
        ctn->tag = YYJSON_TYPE_ARR;
5855
19.0k
        ctn->uni.ofs = 0;
5856
19.0k
        if (*cur == '\n') cur++;
5857
19.0k
        goto arr_val_begin;
5858
19.0k
    }
5859
5860
121k
arr_begin:
5861
#if YYJSON_READER_DEPTH_LIMIT
5862
    container_depth++;
5863
    if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) {
5864
        goto fail_depth;
5865
    }
5866
#endif
5867
5868
    /* save current container */
5869
121k
    ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
5870
121k
               (ctn->tag & YYJSON_TAG_MASK);
5871
5872
    /* create a new array value, save parent container offset */
5873
121k
    val_incr();
5874
121k
    val->tag = YYJSON_TYPE_ARR;
5875
121k
    val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
5876
5877
    /* push the new array value as current container */
5878
121k
    ctn = val;
5879
121k
    ctn_len = 0;
5880
121k
    if (*cur == '\n') cur++;
5881
5882
1.01M
arr_val_begin:
5883
#if YYJSON_IS_REAL_GCC
5884
    while (true) repeat16({
5885
        if (byte_match_2(cur, "  ")) cur += 2;
5886
        else break;
5887
    })
5888
#else
5889
1.02M
    while (true) repeat16({
5890
1.01M
        if (likely(byte_match_2(cur, "  "))) cur += 2;
5891
1.01M
        else break;
5892
1.01M
    })
5893
1.01M
#endif
5894
5895
1.01M
    if (*cur == '{') {
5896
21.1k
        cur++;
5897
21.1k
        goto obj_begin;
5898
21.1k
    }
5899
997k
    if (*cur == '[') {
5900
117k
        cur++;
5901
117k
        goto arr_begin;
5902
117k
    }
5903
880k
    if (char_is_num(*cur)) {
5904
626k
        val_incr();
5905
626k
        ctn_len++;
5906
626k
        if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_end;
5907
1.40k
        goto fail_number;
5908
626k
    }
5909
254k
    if (*cur == '"') {
5910
6.66k
        val_incr();
5911
6.66k
        ctn_len++;
5912
6.66k
        if (likely(read_str(&cur, eof, flg, val, &msg))) goto arr_val_end;
5913
2.55k
        goto fail_string;
5914
6.66k
    }
5915
247k
    if (*cur == 't') {
5916
30.6k
        val_incr();
5917
30.6k
        ctn_len++;
5918
30.6k
        if (likely(read_true(&cur, val))) goto arr_val_end;
5919
183
        goto fail_literal_true;
5920
30.6k
    }
5921
216k
    if (*cur == 'f') {
5922
30.8k
        val_incr();
5923
30.8k
        ctn_len++;
5924
30.8k
        if (likely(read_false(&cur, val))) goto arr_val_end;
5925
194
        goto fail_literal_false;
5926
30.8k
    }
5927
185k
    if (*cur == 'n') {
5928
15.1k
        val_incr();
5929
15.1k
        ctn_len++;
5930
15.1k
        if (likely(read_null(&cur, val))) goto arr_val_end;
5931
763
        if (has_allow(INF_AND_NAN)) {
5932
617
            if (read_nan(&cur, pre, flg, val)) goto arr_val_end;
5933
617
        }
5934
192
        goto fail_literal_null;
5935
763
    }
5936
170k
    if (*cur == ']') {
5937
51.8k
        cur++;
5938
51.8k
        if (likely(ctn_len == 0)) goto arr_end;
5939
935
        if (has_allow(TRAILING_COMMAS)) goto arr_end;
5940
770
        do { cur--; } while (*cur != ',');
5941
46
        goto fail_trailing_comma;
5942
935
    }
5943
118k
    if (char_is_space(*cur)) {
5944
235k
        while (char_is_space(*++cur));
5945
109k
        goto arr_val_begin;
5946
109k
    }
5947
9.80k
    if (has_allow(INF_AND_NAN) &&
5948
7.49k
        (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
5949
1.70k
        val_incr();
5950
1.70k
        ctn_len++;
5951
1.70k
        if (read_inf_or_nan(&cur, pre, flg, val)) goto arr_val_end;
5952
48
        goto fail_character_val;
5953
1.70k
    }
5954
8.10k
    if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
5955
378
        val_incr();
5956
378
        ctn_len++;
5957
378
        if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto arr_val_end;
5958
14
        goto fail_string;
5959
378
    }
5960
7.72k
    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5961
5.52k
        if (skip_trivia(&cur, eof, flg)) goto arr_val_begin;
5962
39
        if (cur == eof) goto fail_comment;
5963
39
    }
5964
2.23k
    goto fail_character_val;
5965
5966
903k
arr_val_end:
5967
903k
    if (byte_match_2(cur, ",\n")) {
5968
200k
        cur += 2;
5969
200k
        goto arr_val_begin;
5970
200k
    }
5971
703k
    if (*cur == ',') {
5972
563k
        cur++;
5973
563k
        goto arr_val_begin;
5974
563k
    }
5975
140k
    if (*cur == ']') {
5976
22.8k
        cur++;
5977
22.8k
        goto arr_end;
5978
22.8k
    }
5979
117k
    if (char_is_space(*cur)) {
5980
41.0k
        while (char_is_space(*++cur));
5981
31.5k
        goto arr_val_end;
5982
31.5k
    }
5983
85.9k
    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5984
78.5k
        if (skip_trivia(&cur, eof, flg)) goto arr_val_end;
5985
63
        if (cur == eof) goto fail_comment;
5986
63
    }
5987
7.49k
    goto fail_character_arr_end;
5988
5989
74.6k
arr_end:
5990
#if YYJSON_READER_DEPTH_LIMIT
5991
    container_depth--;
5992
#endif
5993
    /* get parent container */
5994
74.6k
    ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
5995
5996
    /* save the next sibling value offset */
5997
74.6k
    ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
5998
74.6k
    ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
5999
74.6k
    if (unlikely(ctn == ctn_parent)) goto doc_end;
6000
6001
    /* pop parent as current container */
6002
74.2k
    ctn = ctn_parent;
6003
74.2k
    ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
6004
74.2k
    if (*cur == '\n') cur++;
6005
74.2k
    if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
6006
1.68k
        goto obj_val_end;
6007
72.6k
    } else {
6008
72.6k
        goto arr_val_end;
6009
72.6k
    }
6010
6011
36.8k
obj_begin:
6012
#if YYJSON_READER_DEPTH_LIMIT
6013
    container_depth++;
6014
    if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) {
6015
        goto fail_depth;
6016
    }
6017
#endif
6018
6019
    /* push container */
6020
36.8k
    ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
6021
36.8k
               (ctn->tag & YYJSON_TAG_MASK);
6022
36.8k
    val_incr();
6023
36.8k
    val->tag = YYJSON_TYPE_OBJ;
6024
    /* offset to the parent */
6025
36.8k
    val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
6026
36.8k
    ctn = val;
6027
36.8k
    ctn_len = 0;
6028
36.8k
    if (*cur == '\n') cur++;
6029
6030
200k
obj_key_begin:
6031
#if YYJSON_IS_REAL_GCC
6032
    while (true) repeat16({
6033
        if (byte_match_2(cur, "  ")) cur += 2;
6034
        else break;
6035
    })
6036
#else
6037
202k
    while (true) repeat16({
6038
200k
        if (likely(byte_match_2(cur, "  "))) cur += 2;
6039
200k
        else break;
6040
200k
    })
6041
200k
#endif
6042
200k
    if (likely(*cur == '"')) {
6043
151k
        val_incr();
6044
151k
        ctn_len++;
6045
151k
        if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_key_end;
6046
2.73k
        goto fail_string;
6047
151k
    }
6048
49.1k
    if (likely(*cur == '}')) {
6049
14.0k
        cur++;
6050
14.0k
        if (likely(ctn_len == 0)) goto obj_end;
6051
282
        if (has_allow(TRAILING_COMMAS)) goto obj_end;
6052
512
        do { cur--; } while (*cur != ',');
6053
30
        goto fail_trailing_comma;
6054
282
    }
6055
35.1k
    if (char_is_space(*cur)) {
6056
33.3k
        while (char_is_space(*++cur));
6057
21.8k
        goto obj_key_begin;
6058
21.8k
    }
6059
13.3k
    if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
6060
464
        val_incr();
6061
464
        ctn_len++;
6062
464
        if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_key_end;
6063
19
        goto fail_string;
6064
464
    }
6065
12.8k
    if (has_allow(UNQUOTED_KEY) && char_is_id_start(*cur)) {
6066
8.60k
        val_incr();
6067
8.60k
        ctn_len++;
6068
8.60k
        if (read_str_id(&cur, eof, flg, pre, val, &msg)) goto obj_key_end;
6069
73
        goto fail_string;
6070
8.60k
    }
6071
4.26k
    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
6072
1.26k
        if (skip_trivia(&cur, eof, flg)) goto obj_key_begin;
6073
23
        if (cur == eof) goto fail_comment;
6074
23
    }
6075
3.01k
    goto fail_character_obj_key;
6076
6077
161k
obj_key_end:
6078
161k
    if (byte_match_2(cur, ": ")) {
6079
15.6k
        cur += 2;
6080
15.6k
        goto obj_val_begin;
6081
15.6k
    }
6082
146k
    if (*cur == ':') {
6083
141k
        cur++;
6084
141k
        goto obj_val_begin;
6085
141k
    }
6086
4.48k
    if (char_is_space(*cur)) {
6087
3.77k
        while (char_is_space(*++cur));
6088
2.83k
        goto obj_key_end;
6089
2.83k
    }
6090
1.65k
    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
6091
1.16k
        if (skip_trivia(&cur, eof, flg)) goto obj_key_end;
6092
22
        if (cur == eof) goto fail_comment;
6093
22
    }
6094
500
    goto fail_character_obj_sep;
6095
6096
164k
obj_val_begin:
6097
164k
    if (*cur == '"') {
6098
4.89k
        val++;
6099
4.89k
        ctn_len++;
6100
4.89k
        if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_val_end;
6101
2.26k
        goto fail_string;
6102
4.89k
    }
6103
159k
    if (char_is_num(*cur)) {
6104
128k
        val++;
6105
128k
        ctn_len++;
6106
128k
        if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_end;
6107
1.03k
        goto fail_number;
6108
128k
    }
6109
31.4k
    if (*cur == '{') {
6110
15.6k
        cur++;
6111
15.6k
        goto obj_begin;
6112
15.6k
    }
6113
15.7k
    if (*cur == '[') {
6114
4.14k
        cur++;
6115
4.14k
        goto arr_begin;
6116
4.14k
    }
6117
11.5k
    if (*cur == 't') {
6118
674
        val++;
6119
674
        ctn_len++;
6120
674
        if (likely(read_true(&cur, val))) goto obj_val_end;
6121
94
        goto fail_literal_true;
6122
674
    }
6123
10.8k
    if (*cur == 'f') {
6124
717
        val++;
6125
717
        ctn_len++;
6126
717
        if (likely(read_false(&cur, val))) goto obj_val_end;
6127
118
        goto fail_literal_false;
6128
717
    }
6129
10.1k
    if (*cur == 'n') {
6130
944
        val++;
6131
944
        ctn_len++;
6132
944
        if (likely(read_null(&cur, val))) goto obj_val_end;
6133
334
        if (has_allow(INF_AND_NAN)) {
6134
263
            if (read_nan(&cur, pre, flg, val)) goto obj_val_end;
6135
263
        }
6136
110
        goto fail_literal_null;
6137
334
    }
6138
9.22k
    if (char_is_space(*cur)) {
6139
9.69k
        while (char_is_space(*++cur));
6140
6.06k
        goto obj_val_begin;
6141
6.06k
    }
6142
3.16k
    if (has_allow(INF_AND_NAN) &&
6143
2.25k
        (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
6144
1.63k
        val++;
6145
1.63k
        ctn_len++;
6146
1.63k
        if (read_inf_or_nan(&cur, pre, flg, val)) goto obj_val_end;
6147
27
        goto fail_character_val;
6148
1.63k
    }
6149
1.53k
    if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
6150
321
        val++;
6151
321
        ctn_len++;
6152
321
        if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_val_end;
6153
9
        goto fail_string;
6154
321
    }
6155
1.21k
    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
6156
923
        if (skip_trivia(&cur, eof, flg)) goto obj_val_begin;
6157
15
        if (cur == eof) goto fail_comment;
6158
15
    }
6159
295
    goto fail_character_val;
6160
6161
144k
obj_val_end:
6162
144k
    if (byte_match_2(cur, ",\n")) {
6163
7.49k
        cur += 2;
6164
7.49k
        goto obj_key_begin;
6165
7.49k
    }
6166
136k
    if (likely(*cur == ',')) {
6167
120k
        cur++;
6168
120k
        goto obj_key_begin;
6169
120k
    }
6170
16.0k
    if (likely(*cur == '}')) {
6171
1.42k
        cur++;
6172
1.42k
        goto obj_end;
6173
1.42k
    }
6174
14.6k
    if (char_is_space(*cur)) {
6175
9.63k
        while (char_is_space(*++cur));
6176
7.20k
        goto obj_val_end;
6177
7.20k
    }
6178
7.40k
    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
6179
1.07k
        if (skip_trivia(&cur, eof, flg)) goto obj_val_end;
6180
64
        if (cur == eof) goto fail_comment;
6181
64
    }
6182
6.38k
    goto fail_character_obj_end;
6183
6184
15.4k
obj_end:
6185
#if YYJSON_READER_DEPTH_LIMIT
6186
    container_depth--;
6187
#endif
6188
6189
    /* pop container */
6190
15.4k
    ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
6191
    /* point to the next value */
6192
15.4k
    ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
6193
15.4k
    ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
6194
15.4k
    if (unlikely(ctn == ctn_parent)) goto doc_end;
6195
15.3k
    ctn = ctn_parent;
6196
15.3k
    ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
6197
15.3k
    if (*cur == '\n') cur++;
6198
15.3k
    if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
6199
879
        goto obj_val_end;
6200
14.4k
    } else {
6201
14.4k
        goto arr_val_end;
6202
14.4k
    }
6203
6204
471
doc_end:
6205
    /* check invalid contents after json document */
6206
471
    if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) {
6207
803
        while (char_is_space(*cur)) cur++;
6208
126
        if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
6209
26
            if (!skip_trivia(&cur, eof, flg) && cur == eof) {
6210
7
                goto fail_comment;
6211
7
            }
6212
26
        }
6213
119
        if (unlikely(cur < eof)) goto fail_garbage;
6214
119
    }
6215
6216
407
    **pre = '\0';
6217
407
    doc = (yyjson_doc *)val_hdr;
6218
407
    doc->root = val_hdr + hdr_len;
6219
407
    doc->alc = alc;
6220
407
    doc->dat_read = (usize)(cur - hdr);
6221
407
    doc->val_read = (usize)((val - doc->root) + 1);
6222
407
    doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
6223
407
    return doc;
6224
6225
7.65k
fail_string:            return_err(cur, INVALID_STRING, msg);
6226
2.44k
fail_number:            return_err(cur, INVALID_NUMBER, msg);
6227
0
fail_alloc:             return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
6228
76
fail_trailing_comma:    return_err(cur, JSON_STRUCTURE, MSG_COMMA);
6229
277
fail_literal_true:      return_err(cur, LITERAL, MSG_CHAR_T);
6230
312
fail_literal_false:     return_err(cur, LITERAL, MSG_CHAR_F);
6231
302
fail_literal_null:      return_err(cur, LITERAL, MSG_CHAR_N);
6232
2.60k
fail_character_val:     return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
6233
7.49k
fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END);
6234
3.01k
fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY);
6235
500
fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
6236
6.38k
fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
6237
54
fail_comment:           return_err(cur, INVALID_COMMENT, MSG_COMMENT);
6238
57
fail_garbage:           return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
6239
0
fail_depth:             return_err(cur, DEPTH, MSG_DEPTH);
6240
6241
0
#undef val_incr
6242
0
#undef return_err
6243
0
}
6244
6245
6246
6247
/*==============================================================================
6248
 * MARK: - JSON Reader (Public)
6249
 *============================================================================*/
6250
6251
yyjson_doc *yyjson_read_opts(char *dat, usize len,
6252
                             yyjson_read_flag flg,
6253
                             const yyjson_alc *alc_ptr,
6254
136k
                             yyjson_read_err *err) {
6255
136k
#define return_err(_pos, _code, _msg) do { \
6256
21.5k
    err->pos = (usize)(_pos); \
6257
21.5k
    err->msg = _msg; \
6258
21.5k
    err->code = YYJSON_READ_ERROR_##_code; \
6259
21.5k
    if (!has_flg(INSITU) && hdr) alc.free(alc.ctx, (void *)hdr); \
6260
21.5k
    return NULL; \
6261
21.5k
} while (false)
6262
6263
136k
    yyjson_read_err tmp_err;
6264
136k
    yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
6265
136k
    yyjson_doc *doc;
6266
136k
    u8 *hdr = NULL, *eof, *cur;
6267
6268
    /* validate input parameters */
6269
136k
    if (!err) err = &tmp_err;
6270
136k
    if (unlikely(!dat)) return_err(0, INVALID_PARAMETER, "input data is NULL");
6271
136k
    if (unlikely(!len)) return_err(0, INVALID_PARAMETER, "input length is 0");
6272
6273
    /* add 4-byte zero padding for input data if necessary */
6274
115k
    if (has_flg(INSITU)) {
6275
0
        hdr = (u8 *)dat;
6276
0
        eof = (u8 *)dat + len;
6277
0
        cur = (u8 *)dat;
6278
115k
    } else {
6279
115k
        if (unlikely(len >= USIZE_MAX - YYJSON_PADDING_SIZE)) {
6280
0
            return_err(0, MEMORY_ALLOCATION, MSG_MALLOC);
6281
0
        }
6282
115k
        hdr = (u8 *)alc.malloc(alc.ctx, len + YYJSON_PADDING_SIZE);
6283
115k
        if (unlikely(!hdr)) {
6284
0
            return_err(0, MEMORY_ALLOCATION, MSG_MALLOC);
6285
0
        }
6286
115k
        eof = hdr + len;
6287
115k
        cur = hdr;
6288
115k
        memcpy(hdr, dat, len);
6289
115k
    }
6290
115k
    memset(eof, 0, YYJSON_PADDING_SIZE);
6291
6292
115k
    if (has_allow(BOM)) {
6293
0
        if (len >= 3 && is_utf8_bom(cur)) cur += 3;
6294
0
    }
6295
6296
    /* skip empty contents before json document */
6297
115k
    if (unlikely(!char_is_ctn(*cur))) {
6298
43.8k
        while (char_is_space(*cur)) cur++;
6299
35.6k
        if (unlikely(!char_is_ctn(*cur))) {
6300
33.1k
            if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
6301
1.03k
                if (!skip_trivia(&cur, eof, flg) && cur == eof) {
6302
63
                    return_err(cur - hdr, INVALID_COMMENT, MSG_COMMENT);
6303
63
                }
6304
1.03k
            }
6305
33.1k
        }
6306
35.5k
        if (unlikely(cur >= eof)) {
6307
611
            return_err(0, EMPTY_CONTENT, "input data is empty");
6308
611
        }
6309
35.5k
    }
6310
6311
    /* read json document */
6312
114k
    if (likely(char_is_ctn(*cur))) {
6313
82.6k
        if (char_is_space(cur[1]) && char_is_space(cur[2])) {
6314
31.5k
            doc = read_root_pretty(hdr, cur, eof, alc, flg, err);
6315
51.1k
        } else {
6316
51.1k
            doc = read_root_minify(hdr, cur, eof, alc, flg, err);
6317
51.1k
        }
6318
82.6k
    } else {
6319
32.1k
        doc = read_root_single(hdr, cur, eof, alc, flg, err);
6320
32.1k
    }
6321
6322
    /* check result */
6323
114k
    if (likely(doc)) {
6324
34.5k
        memset(err, 0, sizeof(yyjson_read_err));
6325
80.2k
    } else {
6326
        /* RFC 8259: JSON text MUST be encoded using UTF-8 */
6327
80.2k
        if (err->pos == 0 && err->code != YYJSON_READ_ERROR_MEMORY_ALLOCATION) {
6328
8.58k
            if (is_utf8_bom(hdr)) err->msg = MSG_ERR_BOM;
6329
8.57k
            else if (len >= 4 && is_utf32_bom(hdr)) err->msg = MSG_ERR_UTF32;
6330
8.55k
            else if (len >= 2 && is_utf16_bom(hdr)) err->msg = MSG_ERR_UTF16;
6331
8.58k
        }
6332
80.2k
        if (!has_flg(INSITU)) alc.free(alc.ctx, hdr);
6333
80.2k
    }
6334
114k
    return doc;
6335
6336
115k
#undef return_err
6337
115k
}
6338
6339
#if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE
6340
6341
yyjson_doc *yyjson_read_file(const char *path,
6342
                             yyjson_read_flag flg,
6343
                             const yyjson_alc *alc_ptr,
6344
0
                             yyjson_read_err *err) {
6345
0
#define return_err(_code, _msg) do { \
6346
0
    err->pos = 0; \
6347
0
    err->msg = _msg; \
6348
0
    err->code = YYJSON_READ_ERROR_##_code; \
6349
0
    return NULL; \
6350
0
} while (false)
6351
6352
0
    yyjson_read_err tmp_err;
6353
0
    yyjson_doc *doc;
6354
0
    FILE *file;
6355
6356
0
    if (!err) err = &tmp_err;
6357
0
    if (unlikely(!path)) return_err(INVALID_PARAMETER, "input path is NULL");
6358
6359
0
    file = fopen_readonly(path);
6360
0
    if (unlikely(!file)) return_err(FILE_OPEN, MSG_FREAD);
6361
6362
0
    doc = yyjson_read_fp(file, flg, alc_ptr, err);
6363
0
    fclose(file);
6364
0
    return doc;
6365
6366
0
#undef return_err
6367
0
}
6368
6369
yyjson_doc *yyjson_read_fp(FILE *file,
6370
                           yyjson_read_flag flg,
6371
                           const yyjson_alc *alc_ptr,
6372
0
                           yyjson_read_err *err) {
6373
0
#define return_err(_code, _msg) do { \
6374
0
    err->pos = 0; \
6375
0
    err->msg = _msg; \
6376
0
    err->code = YYJSON_READ_ERROR_##_code; \
6377
0
    if (buf) alc.free(alc.ctx, buf); \
6378
0
    return NULL; \
6379
0
} while (false)
6380
6381
0
    yyjson_read_err tmp_err;
6382
0
    yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
6383
0
    yyjson_doc *doc;
6384
6385
0
    long file_size = 0, file_pos;
6386
0
    void *buf = NULL;
6387
0
    usize buf_size = 0;
6388
0
    usize dat_size = 0;
6389
6390
    /* validate input parameters */
6391
0
    if (!err) err = &tmp_err;
6392
0
    if (unlikely(!file)) return_err(INVALID_PARAMETER, "input file is NULL");
6393
6394
    /* get current position */
6395
0
    file_pos = ftell(file);
6396
0
    if (file_pos != -1) {
6397
        /* get total file size, may fail */
6398
0
        if (fseek(file, 0, SEEK_END) == 0) {
6399
0
            file_size = ftell(file);
6400
0
            if (file_size == -1) file_size = 0;
6401
0
        }
6402
        /* reset to original position, may fail */
6403
0
        if (fseek(file, file_pos, SEEK_SET) != 0) file_size = 0;
6404
        /* get file size from current position to end */
6405
0
        if (file_size > 0) file_size -= file_pos;
6406
0
    }
6407
6408
    /* read file */
6409
0
    if (file_size > 0) {
6410
        /* read the entire file in one call */
6411
0
        dat_size = (usize)file_size;
6412
0
        buf_size = dat_size + YYJSON_PADDING_SIZE;
6413
0
        buf = alc.malloc(alc.ctx, buf_size);
6414
0
        if (buf == NULL) {
6415
0
            return_err(MEMORY_ALLOCATION, MSG_MALLOC);
6416
0
        }
6417
0
        if (fread_safe(buf, dat_size, file) != dat_size) {
6418
0
            return_err(FILE_READ, MSG_FREAD);
6419
0
        }
6420
0
    } else {
6421
        /* failed to get file size, read it as a stream */
6422
0
        usize chunk_min = (usize)64;
6423
0
        usize chunk_max = (usize)512 * 1024 * 1024;
6424
0
        usize chunk_now = chunk_min;
6425
0
        usize read_size;
6426
0
        void *tmp;
6427
6428
0
        buf_size = YYJSON_PADDING_SIZE;
6429
0
        while (true) {
6430
0
            if (buf_size + chunk_now < buf_size) { /* overflow */
6431
0
                return_err(MEMORY_ALLOCATION, MSG_MALLOC);
6432
0
            }
6433
0
            buf_size += chunk_now;
6434
0
            if (!buf) {
6435
0
                buf = alc.malloc(alc.ctx, buf_size);
6436
0
                if (!buf) return_err(MEMORY_ALLOCATION, MSG_MALLOC);
6437
0
            } else {
6438
0
                tmp = alc.realloc(alc.ctx, buf, buf_size - chunk_now, buf_size);
6439
0
                if (!tmp) return_err(MEMORY_ALLOCATION, MSG_MALLOC);
6440
0
                buf = tmp;
6441
0
            }
6442
0
            tmp = ((u8 *)buf) + buf_size - YYJSON_PADDING_SIZE - chunk_now;
6443
0
            read_size = fread_safe(tmp, chunk_now, file);
6444
0
            dat_size += read_size;
6445
0
            if (read_size != chunk_now) {
6446
0
                if (ferror(file)) return_err(FILE_READ, MSG_FREAD);
6447
0
                break;
6448
0
            }
6449
6450
0
            chunk_now *= 2;
6451
0
            if (chunk_now > chunk_max) chunk_now = chunk_max;
6452
0
        }
6453
0
    }
6454
6455
    /* read JSON */
6456
0
    memset((u8 *)buf + dat_size, 0, YYJSON_PADDING_SIZE);
6457
0
    flg |= YYJSON_READ_INSITU;
6458
0
    doc = yyjson_read_opts((char *)buf, dat_size, flg, &alc, err);
6459
0
    if (doc) {
6460
0
        doc->str_pool = (char *)buf;
6461
0
        return doc;
6462
0
    } else {
6463
0
        alc.free(alc.ctx, buf);
6464
0
        return NULL;
6465
0
    }
6466
6467
0
#undef return_err
6468
0
}
6469
6470
#endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */
6471
6472
const char *yyjson_read_number(const char *dat,
6473
                               yyjson_val *val,
6474
                               yyjson_read_flag flg,
6475
                               const yyjson_alc *alc,
6476
0
                               yyjson_read_err *err) {
6477
0
#define return_err(_pos, _code, _msg) do { \
6478
0
    err->pos = _pos > hdr ? (usize)(_pos - hdr) : 0; \
6479
0
    err->msg = _msg; \
6480
0
    err->code = YYJSON_READ_ERROR_##_code; \
6481
0
    return NULL; \
6482
0
} while (false)
6483
6484
0
    u8 *hdr = constcast(u8 *)dat, *cur = hdr;
6485
0
    u8 raw_end[1]; /* raw end for null-terminator */
6486
0
    u8 *raw_ptr = raw_end;
6487
0
    u8 **pre = &raw_ptr; /* previous raw end pointer */
6488
0
    const char *msg;
6489
0
    yyjson_read_err tmp_err;
6490
6491
#if YYJSON_DISABLE_FAST_FP_CONV
6492
    u8 buf[128];
6493
    usize dat_len;
6494
#endif
6495
6496
0
    if (!err) err = &tmp_err;
6497
0
    if (unlikely(!dat)) {
6498
0
        return_err(cur, INVALID_PARAMETER, "input data is NULL");
6499
0
    }
6500
0
    if (unlikely(!val)) {
6501
0
        return_err(cur, INVALID_PARAMETER, "output value is NULL");
6502
0
    }
6503
6504
#if YYJSON_DISABLE_FAST_FP_CONV
6505
    if (!alc) alc = &YYJSON_DEFAULT_ALC;
6506
    dat_len = strlen(dat);
6507
    if (dat_len < sizeof(buf)) {
6508
        memcpy(buf, dat, dat_len + 1);
6509
        hdr = buf;
6510
        cur = hdr;
6511
    } else {
6512
        hdr = (u8 *)alc->malloc(alc->ctx, dat_len + 1);
6513
        cur = hdr;
6514
        if (unlikely(!hdr)) {
6515
            return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
6516
        }
6517
        memcpy(hdr, dat, dat_len + 1);
6518
    }
6519
    hdr[dat_len] = 0;
6520
#endif
6521
6522
#if YYJSON_DISABLE_FAST_FP_CONV
6523
    if (!read_num(&cur, pre, flg, val, &msg)) {
6524
        if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr);
6525
        return_err(cur, INVALID_NUMBER, msg);
6526
    }
6527
    if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr);
6528
    if (yyjson_is_raw(val)) val->uni.str = dat;
6529
    return dat + (cur - hdr);
6530
#else
6531
0
    if (!read_num(&cur, pre, flg, val, &msg)) {
6532
0
        return_err(cur, INVALID_NUMBER, msg);
6533
0
    }
6534
0
    return (const char *)cur;
6535
0
#endif
6536
6537
0
#undef return_err
6538
0
}
6539
6540
6541
6542
/*==============================================================================
6543
 * MARK: - Incremental JSON Reader (Public)
6544
 *============================================================================*/
6545
6546
#if !YYJSON_DISABLE_INCR_READER
6547
6548
/* labels within yyjson_incr_read() to resume incremental parsing */
6549
0
#define LABEL_doc_begin     0
6550
0
#define LABEL_arr_val_begin 1
6551
0
#define LABEL_arr_val_end   2
6552
0
#define LABEL_obj_key_begin 3
6553
0
#define LABEL_obj_key_end   4
6554
0
#define LABEL_obj_val_begin 5
6555
0
#define LABEL_obj_val_end   6
6556
0
#define LABEL_doc_end       7
6557
6558
/** State for incremental JSON reader, opaque in the API. */
6559
struct yyjson_incr_state {
6560
    u32 label; /* current parser goto label */
6561
    yyjson_alc alc; /* allocator */
6562
    yyjson_read_flag flg; /* read flags */
6563
    u8 *hdr; /* JSON data header */
6564
    u8 *cur; /* current position in JSON data */
6565
    usize buf_len; /* total buffer length (without padding) */
6566
    usize hdr_len; /* value count used by yyjson_doc */
6567
    usize alc_len; /* value count allocated */
6568
    usize ctn_len; /* the number of elements in current container */
6569
#if YYJSON_READER_DEPTH_LIMIT
6570
    u32 ctn_depth; /* current array/object depth */
6571
#endif
6572
    yyjson_val *val_hdr; /* the head of allocated values */
6573
    yyjson_val *val_end; /* the end of allocated values */
6574
    yyjson_val *val; /* current JSON value */
6575
    yyjson_val *ctn; /* current container */
6576
    u8 *str_con[2]; /* string parser incremental state */
6577
    u8 *raw_ptr; /* pending position for a deferred raw null-terminator */
6578
    u8 raw_end[1]; /* dummy target for the first deferred null-terminator */
6579
};
6580
6581
yyjson_incr_state *yyjson_incr_new(char *buf, size_t buf_len,
6582
                                   yyjson_read_flag flg,
6583
0
                                   const yyjson_alc *alc_ptr) {
6584
0
    yyjson_incr_state *state = NULL;
6585
0
    yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
6586
6587
    /* remove non-standard flags */
6588
0
    flg &= ~YYJSON_READ_JSON5;
6589
0
    flg &= ~YYJSON_READ_ALLOW_BOM;
6590
0
    flg &= ~YYJSON_READ_ALLOW_INVALID_UNICODE;
6591
6592
0
    if (unlikely(!buf)) return NULL;
6593
0
    if (unlikely(buf_len >= USIZE_MAX - YYJSON_PADDING_SIZE)) return NULL;
6594
0
    state = (yyjson_incr_state *)alc.malloc(alc.ctx, sizeof(*state));
6595
0
    if (!state) return NULL;
6596
0
    memset(state, 0, sizeof(yyjson_incr_state));
6597
0
    state->alc = alc;
6598
0
    state->flg = flg;
6599
0
    state->buf_len = buf_len;
6600
6601
    /* add 4-byte zero padding for input data if necessary */
6602
0
    if (has_flg(INSITU)) {
6603
0
        state->hdr = (u8 *)buf;
6604
0
    } else {
6605
0
        state->hdr = (u8 *)alc.malloc(alc.ctx, buf_len + YYJSON_PADDING_SIZE);
6606
0
        if (unlikely(!state->hdr)) {
6607
0
            alc.free(alc.ctx, state);
6608
0
            return NULL;
6609
0
        }
6610
0
        memcpy(state->hdr, buf, buf_len);
6611
0
    }
6612
0
    memset(state->hdr + buf_len, 0, YYJSON_PADDING_SIZE);
6613
0
    state->cur = state->hdr;
6614
0
    state->raw_ptr = state->raw_end;
6615
0
    state->label = LABEL_doc_begin;
6616
0
    return state;
6617
0
}
6618
6619
0
void yyjson_incr_free(yyjson_incr_state *state) {
6620
0
    if (state) {
6621
0
        yyjson_alc alc = state->alc;
6622
0
        memset(&state->alc, 0, sizeof(alc));
6623
0
        if (state->val_hdr) {
6624
0
            alc.free(alc.ctx, (void *)state->val_hdr);
6625
0
        }
6626
0
        if (state->hdr && !(state->flg & YYJSON_READ_INSITU)) {
6627
0
            alc.free(alc.ctx, state->hdr);
6628
0
        }
6629
0
        alc.free(alc.ctx, state);
6630
0
    }
6631
0
}
6632
6633
yyjson_doc *yyjson_incr_read(yyjson_incr_state *state, size_t len,
6634
0
                             yyjson_read_err *err) {
6635
0
#define return_err_inv_param(_msg) do { \
6636
0
    err->pos = 0; \
6637
0
    err->msg = _msg; \
6638
0
    err->code = YYJSON_READ_ERROR_INVALID_PARAMETER; \
6639
0
    return NULL; \
6640
0
} while (false)
6641
6642
0
#define return_err(_pos, _code, _msg) do { \
6643
0
    if (is_truncated_end(hdr, _pos, end, YYJSON_READ_ERROR_##_code, flg)) { \
6644
0
        goto unexpected_end; \
6645
0
    } else { \
6646
0
        err->pos = (usize)(_pos - hdr); \
6647
0
        err->code = YYJSON_READ_ERROR_##_code; \
6648
0
        err->msg = _msg; \
6649
0
    } \
6650
0
    return NULL; \
6651
0
} while (false)
6652
6653
0
#define val_incr() do { \
6654
0
    val++; \
6655
0
    if (unlikely(val >= val_end)) { \
6656
0
        usize alc_old = alc_len; \
6657
0
        alc_len += alc_len / 2; \
6658
0
        if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \
6659
0
        val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
6660
0
                                            alc_old * sizeof(yyjson_val), \
6661
0
                                            alc_len * sizeof(yyjson_val)); \
6662
0
        if ((!val_tmp)) goto fail_alloc; \
6663
0
        val = val_tmp + (usize)(val - val_hdr); \
6664
0
        ctn = val_tmp + (usize)(ctn - val_hdr); \
6665
0
        state->val = val_tmp + (usize)(state->val - val_hdr); \
6666
0
        state->val_hdr = val_hdr = val_tmp; \
6667
0
        val_end = val_tmp + (alc_len - 2); \
6668
0
        state->val_end = val_end; \
6669
0
    } \
6670
0
} while (false)
6671
6672
    /* save position where it's possible to resume incremental parsing */
6673
#if YYJSON_READER_DEPTH_LIMIT
6674
#define save_incr_depth() (state->ctn_depth = container_depth)
6675
#else
6676
0
#define save_incr_depth() ((void)0)
6677
0
#endif
6678
0
#define save_incr_state(_label) do { \
6679
0
    state->label = LABEL_##_label; \
6680
0
    state->cur = cur; \
6681
0
    state->val = val; \
6682
0
    state->ctn_len = ctn_len; \
6683
0
    save_incr_depth(); \
6684
0
    state->hdr_len = hdr_len; \
6685
0
    state->raw_ptr = raw_ptr; \
6686
0
    if (unlikely(cur >= end)) goto unexpected_end; \
6687
0
} while (false)
6688
6689
0
#define check_maybe_truncated_number() do { \
6690
0
    if (unlikely(cur >= end)) { \
6691
0
        if (unlikely(cur > state->cur + INCR_NUM_MAX_LEN)) { \
6692
0
            msg = "number too long"; \
6693
0
            goto fail_number; \
6694
0
        } \
6695
0
        goto unexpected_end; \
6696
0
    } \
6697
0
} while (false)
6698
6699
0
    u8 *hdr = NULL, *end = NULL, *cur = NULL;
6700
0
    yyjson_read_flag flg;
6701
0
    yyjson_alc alc;
6702
0
    usize dat_len; /* data length in bytes, hint for allocator */
6703
0
    usize hdr_len; /* value count used by yyjson_doc */
6704
0
    usize alc_len; /* value count allocated */
6705
0
    usize alc_max; /* maximum value count for allocator */
6706
0
    usize ctn_len; /* the number of elements in current container */
6707
0
    yyjson_val *val_hdr; /* the head of allocated values */
6708
0
    yyjson_val *val_end; /* the end of allocated values */
6709
0
    yyjson_val *val_tmp; /* temporary pointer for realloc */
6710
0
    yyjson_val *val; /* current JSON value */
6711
0
    yyjson_val *ctn; /* current container */
6712
0
    yyjson_val *ctn_parent; /* parent of current container */
6713
0
    yyjson_doc *doc; /* the JSON document, equals to val_hdr */
6714
0
    const char *msg; /* error message */
6715
6716
0
    yyjson_read_err tmp_err;
6717
0
    u8 *raw_ptr; /* deferred raw null-terminator position, committed at save */
6718
0
    u8 **pre = &raw_ptr; /* previous raw end pointer */
6719
0
    u8 **con = NULL; /* for incremental string parsing */
6720
0
    u8 saved_end = '\0'; /* saved end char */
6721
6722
#if YYJSON_READER_DEPTH_LIMIT
6723
    u32 container_depth = 0; /* current array/object depth */
6724
#endif
6725
6726
    /* validate input parameters */
6727
0
    if (!err) err = &tmp_err;
6728
0
    if (unlikely(!state)) {
6729
0
        return_err_inv_param("input state is NULL");
6730
0
    }
6731
0
    if (unlikely(!len)) {
6732
0
        return_err_inv_param("input length is 0");
6733
0
    }
6734
0
    if (unlikely(len > state->buf_len)) {
6735
0
        return_err_inv_param("length is greater than total input length");
6736
0
    }
6737
6738
    /* restore state saved from the previous call */
6739
0
    hdr = state->hdr;
6740
0
    end = state->hdr + len;
6741
0
    cur = state->cur;
6742
0
    flg = state->flg;
6743
0
    alc = state->alc;
6744
0
    ctn_len = state->ctn_len;
6745
#if YYJSON_READER_DEPTH_LIMIT
6746
    container_depth = state->ctn_depth;
6747
#endif
6748
0
    hdr_len = state->hdr_len;
6749
0
    alc_len = state->alc_len;
6750
0
    val = state->val;
6751
0
    val_hdr = state->val_hdr;
6752
0
    val_end = state->val_end;
6753
0
    ctn = state->ctn;
6754
0
    con = state->str_con;
6755
0
    raw_ptr = state->raw_ptr;
6756
0
    alc_max = USIZE_MAX / sizeof(yyjson_val);
6757
6758
    /* insert null terminator to make us stop at the specified end, even if
6759
       the data contains more valid JSON */
6760
0
    saved_end = *end;
6761
0
    *end = '\0';
6762
6763
    /* resume parsing from the last save point */
6764
0
    switch (state->label) {
6765
0
    case LABEL_doc_begin: goto doc_begin;
6766
0
    case LABEL_arr_val_begin: goto arr_val_begin;
6767
0
    case LABEL_arr_val_end: goto arr_val_end;
6768
0
    case LABEL_obj_key_begin: goto obj_key_begin;
6769
0
    case LABEL_obj_key_end: goto obj_key_end;
6770
0
    case LABEL_obj_val_begin: goto obj_val_begin;
6771
0
    case LABEL_obj_val_end: goto obj_val_end;
6772
0
    case LABEL_doc_end: goto doc_end;
6773
0
    default: return_err_inv_param("invalid incremental state");
6774
0
    }
6775
6776
0
doc_begin:
6777
    /* skip empty contents before json document */
6778
0
    if (unlikely(!char_is_ctn(*cur))) {
6779
0
        while (char_is_space(*cur)) cur++;
6780
0
        if (unlikely(cur >= end)) goto unexpected_end; /* input data is empty */
6781
0
    }
6782
6783
    /* allocate memory for document */
6784
0
    if (!val_hdr) {
6785
0
        hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
6786
0
        hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
6787
0
        if (likely(char_is_ctn(*cur))) {
6788
0
            dat_len = has_flg(STOP_WHEN_DONE) ? 256 : state->buf_len;
6789
0
            alc_len = hdr_len +
6790
0
                    (dat_len / YYJSON_READER_ESTIMATED_MINIFY_RATIO) + 4;
6791
0
            alc_len = yyjson_min(alc_len, alc_max);
6792
0
        } else {
6793
0
            alc_len = hdr_len + 1; /* single value */
6794
0
        }
6795
0
        val_hdr = (yyjson_val *)alc.malloc(alc.ctx,
6796
0
                                           alc_len * sizeof(yyjson_val));
6797
0
        if (unlikely(!val_hdr)) goto fail_alloc;
6798
0
        val_end = val_hdr + (alc_len - 2); /* padding for kv pair reading */
6799
0
        val = val_hdr + hdr_len;
6800
0
        ctn = val;
6801
0
        ctn_len = 0;
6802
0
        state->val_hdr = val_hdr;
6803
0
        state->val_end = val_end;
6804
0
        save_incr_state(doc_begin);
6805
0
    }
6806
6807
    /* read json document */
6808
0
    if (*cur == '{') {
6809
0
        cur++;
6810
0
        ctn->tag = YYJSON_TYPE_OBJ;
6811
0
        ctn->uni.ofs = 0;
6812
0
        goto obj_key_begin;
6813
0
    }
6814
0
    if (*cur == '[') {
6815
0
        cur++;
6816
0
        ctn->tag = YYJSON_TYPE_ARR;
6817
0
        ctn->uni.ofs = 0;
6818
0
        goto arr_val_begin;
6819
0
    }
6820
0
    if (char_is_num(*cur)) {
6821
0
        if (likely(read_num(&cur, pre, flg, val, &msg))) {
6822
            /* a root number may continue with more digits in a later chunk */
6823
0
            if (unlikely(len < state->buf_len)) check_maybe_truncated_number();
6824
0
            goto doc_end;
6825
0
        }
6826
0
        goto fail_number;
6827
0
    }
6828
0
    if (*cur == '"') {
6829
0
        if (likely(read_str_con(&cur, end, flg, val, &msg, con))) goto doc_end;
6830
0
        goto fail_string;
6831
0
    }
6832
0
    if (*cur == 't') {
6833
0
        if (likely(read_true(&cur, val))) goto doc_end;
6834
0
        goto fail_literal_true;
6835
0
    }
6836
0
    if (*cur == 'f') {
6837
0
        if (likely(read_false(&cur, val))) goto doc_end;
6838
0
        goto fail_literal_false;
6839
0
    }
6840
0
    if (*cur == 'n') {
6841
0
        if (likely(read_null(&cur, val))) goto doc_end;
6842
0
        goto fail_literal_null;
6843
0
    }
6844
6845
0
    msg = "unexpected character, expected a valid root value";
6846
0
    if (cur == hdr) {
6847
        /* RFC 8259: JSON text MUST be encoded using UTF-8 */
6848
0
        if (is_utf8_bom(hdr)) msg = MSG_ERR_BOM;
6849
0
        else if (len >= 4 && is_utf32_bom(hdr)) msg = MSG_ERR_UTF32;
6850
0
        else if (len >= 2 && is_utf16_bom(hdr)) msg = MSG_ERR_UTF16;
6851
0
    }
6852
0
    return_err(cur, UNEXPECTED_CHARACTER, msg);
6853
6854
0
arr_begin:
6855
#if YYJSON_READER_DEPTH_LIMIT
6856
    container_depth++;
6857
    if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) {
6858
        goto fail_depth;
6859
    }
6860
#endif
6861
6862
    /* save current container */
6863
0
    ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
6864
0
               (ctn->tag & YYJSON_TAG_MASK);
6865
6866
    /* create a new array value, save parent container offset */
6867
0
    val_incr();
6868
0
    val->tag = YYJSON_TYPE_ARR;
6869
0
    val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
6870
6871
    /* push the new array value as current container */
6872
0
    ctn = val;
6873
0
    ctn_len = 0;
6874
6875
0
arr_val_begin:
6876
0
    save_incr_state(arr_val_begin);
6877
0
arr_val_continue:
6878
0
    if (*cur == '{') {
6879
0
        cur++;
6880
0
        goto obj_begin;
6881
0
    }
6882
0
    if (*cur == '[') {
6883
0
        cur++;
6884
0
        goto arr_begin;
6885
0
    }
6886
0
    if (char_is_num(*cur)) {
6887
0
        val_incr();
6888
0
        ctn_len++;
6889
0
        if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_maybe_end;
6890
0
        goto fail_number;
6891
0
    }
6892
0
    if (*cur == '"') {
6893
0
        val_incr();
6894
0
        ctn_len++;
6895
0
        if (likely(read_str_con(&cur, end, flg, val, &msg, con)))
6896
0
            goto arr_val_end;
6897
0
        goto fail_string;
6898
0
    }
6899
0
    if (*cur == 't') {
6900
0
        val_incr();
6901
0
        ctn_len++;
6902
0
        if (likely(read_true(&cur, val))) goto arr_val_end;
6903
0
        goto fail_literal_true;
6904
0
    }
6905
0
    if (*cur == 'f') {
6906
0
        val_incr();
6907
0
        ctn_len++;
6908
0
        if (likely(read_false(&cur, val))) goto arr_val_end;
6909
0
        goto fail_literal_false;
6910
0
    }
6911
0
    if (*cur == 'n') {
6912
0
        val_incr();
6913
0
        ctn_len++;
6914
0
        if (likely(read_null(&cur, val))) goto arr_val_end;
6915
0
        goto fail_literal_null;
6916
0
    }
6917
0
    if (*cur == ']') {
6918
0
        cur++;
6919
0
        if (likely(ctn_len == 0)) goto arr_end;
6920
0
        do { cur--; } while (*cur != ',');
6921
0
        goto fail_trailing_comma;
6922
0
    }
6923
0
    if (char_is_space(*cur)) {
6924
0
        while (char_is_space(*++cur));
6925
0
        goto arr_val_continue;
6926
0
    }
6927
0
    goto fail_character_val;
6928
6929
0
arr_val_maybe_end:
6930
    /* if incremental parsing stops in the middle of a number, it may continue
6931
       with more digits, so arr val maybe didn't end yet */
6932
0
    check_maybe_truncated_number();
6933
6934
0
arr_val_end:
6935
0
    save_incr_state(arr_val_end);
6936
0
    if (*cur == ',') {
6937
0
        cur++;
6938
0
        goto arr_val_begin;
6939
0
    }
6940
0
    if (*cur == ']') {
6941
0
        cur++;
6942
0
        goto arr_end;
6943
0
    }
6944
0
    if (char_is_space(*cur)) {
6945
0
        while (char_is_space(*++cur));
6946
0
        goto arr_val_end;
6947
0
    }
6948
0
    goto fail_character_arr_end;
6949
6950
0
arr_end:
6951
#if YYJSON_READER_DEPTH_LIMIT
6952
    container_depth--;
6953
#endif
6954
    /* get parent container */
6955
0
    ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
6956
6957
    /* save the next sibling value offset */
6958
0
    ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
6959
0
    ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
6960
0
    if (unlikely(ctn == ctn_parent)) goto doc_end;
6961
6962
    /* pop parent as current container */
6963
0
    ctn = ctn_parent;
6964
0
    ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
6965
0
    if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
6966
0
        goto obj_val_end;
6967
0
    } else {
6968
0
        goto arr_val_end;
6969
0
    }
6970
6971
0
obj_begin:
6972
#if YYJSON_READER_DEPTH_LIMIT
6973
    container_depth++;
6974
    if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) {
6975
        goto fail_depth;
6976
    }
6977
#endif
6978
6979
    /* push container */
6980
0
    ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
6981
0
               (ctn->tag & YYJSON_TAG_MASK);
6982
0
    val_incr();
6983
0
    val->tag = YYJSON_TYPE_OBJ;
6984
    /* offset to the parent */
6985
0
    val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
6986
0
    ctn = val;
6987
0
    ctn_len = 0;
6988
6989
0
obj_key_begin:
6990
0
    save_incr_state(obj_key_begin);
6991
0
obj_key_continue:
6992
0
    if (likely(*cur == '"')) {
6993
0
        val_incr();
6994
0
        ctn_len++;
6995
0
        if (likely(read_str_con(&cur, end, flg, val, &msg, con)))
6996
0
            goto obj_key_end;
6997
0
        goto fail_string;
6998
0
    }
6999
0
    if (likely(*cur == '}')) {
7000
0
        cur++;
7001
0
        if (likely(ctn_len == 0)) goto obj_end;
7002
0
        do { cur--; } while (*cur != ',');
7003
0
        goto fail_trailing_comma;
7004
0
    }
7005
0
    if (char_is_space(*cur)) {
7006
0
        while (char_is_space(*++cur));
7007
0
        goto obj_key_continue;
7008
0
    }
7009
0
    goto fail_character_obj_key;
7010
7011
0
obj_key_end:
7012
0
    save_incr_state(obj_key_end);
7013
0
    if (*cur == ':') {
7014
0
        cur++;
7015
0
        goto obj_val_begin;
7016
0
    }
7017
0
    if (char_is_space(*cur)) {
7018
0
        while (char_is_space(*++cur));
7019
0
        goto obj_key_end;
7020
0
    }
7021
0
    goto fail_character_obj_sep;
7022
7023
0
obj_val_begin:
7024
0
    save_incr_state(obj_val_begin);
7025
0
obj_val_continue:
7026
0
    if (*cur == '"') {
7027
0
        val++;
7028
0
        ctn_len++;
7029
0
        if (likely(read_str_con(&cur, end, flg, val, &msg, con)))
7030
0
            goto obj_val_end;
7031
0
        goto fail_string;
7032
0
    }
7033
0
    if (char_is_num(*cur)) {
7034
0
        val++;
7035
0
        ctn_len++;
7036
0
        if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_maybe_end;
7037
0
        goto fail_number;
7038
0
    }
7039
0
    if (*cur == '{') {
7040
0
        cur++;
7041
0
        goto obj_begin;
7042
0
    }
7043
0
    if (*cur == '[') {
7044
0
        cur++;
7045
0
        goto arr_begin;
7046
0
    }
7047
0
    if (*cur == 't') {
7048
0
        val++;
7049
0
        ctn_len++;
7050
0
        if (likely(read_true(&cur, val))) goto obj_val_end;
7051
0
        goto fail_literal_true;
7052
0
    }
7053
0
    if (*cur == 'f') {
7054
0
        val++;
7055
0
        ctn_len++;
7056
0
        if (likely(read_false(&cur, val))) goto obj_val_end;
7057
0
        goto fail_literal_false;
7058
0
    }
7059
0
    if (*cur == 'n') {
7060
0
        val++;
7061
0
        ctn_len++;
7062
0
        if (likely(read_null(&cur, val))) goto obj_val_end;
7063
0
        goto fail_literal_null;
7064
0
    }
7065
0
    if (char_is_space(*cur)) {
7066
0
        while (char_is_space(*++cur));
7067
0
        goto obj_val_continue;
7068
0
    }
7069
0
    goto fail_character_val;
7070
7071
0
obj_val_maybe_end:
7072
    /* if incremental parsing stops in the middle of a number, it may continue
7073
       with more digits, so obj val maybe didn't end yet */
7074
0
    check_maybe_truncated_number();
7075
7076
0
obj_val_end:
7077
0
    save_incr_state(obj_val_end);
7078
0
    if (likely(*cur == ',')) {
7079
0
        cur++;
7080
0
        goto obj_key_begin;
7081
0
    }
7082
0
    if (likely(*cur == '}')) {
7083
0
        cur++;
7084
0
        goto obj_end;
7085
0
    }
7086
0
    if (char_is_space(*cur)) {
7087
0
        while (char_is_space(*++cur));
7088
0
        goto obj_val_end;
7089
0
    }
7090
0
    goto fail_character_obj_end;
7091
7092
0
obj_end:
7093
#if YYJSON_READER_DEPTH_LIMIT
7094
    container_depth--;
7095
#endif
7096
7097
    /* pop container */
7098
0
    ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
7099
    /* point to the next value */
7100
0
    ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
7101
0
    ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
7102
0
    if (unlikely(ctn == ctn_parent)) goto doc_end;
7103
0
    ctn = ctn_parent;
7104
0
    ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
7105
0
    if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
7106
0
        goto obj_val_end;
7107
0
    } else {
7108
0
        goto arr_val_end;
7109
0
    }
7110
7111
0
doc_end:
7112
    /* check invalid contents after json document */
7113
0
    if (unlikely(cur < end || len < state->buf_len) &&
7114
0
        !has_flg(STOP_WHEN_DONE)) {
7115
0
        save_incr_state(doc_end);
7116
0
        while (char_is_space(*cur)) cur++;
7117
0
        if (unlikely(cur < end)) goto fail_garbage;
7118
        /* the document is complete for the bytes seen so far, but more input
7119
           is still pending; it may hold trailing content that has to be
7120
           rejected, so request the remaining data before finalizing */
7121
0
        if (unlikely(len < state->buf_len)) goto unexpected_end;
7122
0
    }
7123
7124
0
    **pre = '\0';
7125
0
    doc = (yyjson_doc *)val_hdr;
7126
0
    doc->root = val_hdr + hdr_len;
7127
0
    doc->alc = alc;
7128
0
    doc->dat_read = (usize)(cur - hdr);
7129
0
    doc->val_read = (usize)((val - doc->root) + 1);
7130
0
    doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
7131
0
    state->hdr = NULL;
7132
0
    state->val_hdr = NULL;
7133
0
    memset(err, 0, sizeof(yyjson_read_err));
7134
0
    return doc;
7135
7136
0
unexpected_end:
7137
0
    err->pos = len;
7138
    /* if no more data, stop the incr read */
7139
0
    if (unlikely(len >= state->buf_len)) {
7140
0
        err->code = YYJSON_READ_ERROR_UNEXPECTED_END;
7141
0
        err->msg = MSG_NOT_END;
7142
0
        return NULL;
7143
0
    }
7144
    /* save parser state in extended error struct, in addition to what was
7145
     * stored in the last save_incr_state */
7146
0
    err->code = YYJSON_READ_ERROR_MORE;
7147
0
    err->msg = "need more data";
7148
0
    state->val_end = val_end;
7149
0
    state->ctn = ctn;
7150
0
    state->alc_len = alc_len;
7151
    /* restore the end where we've inserted a null terminator */
7152
0
    *end = saved_end;
7153
0
    return NULL;
7154
7155
0
fail_string:            return_err(cur, INVALID_STRING, msg);
7156
0
fail_number:            return_err(cur, INVALID_NUMBER, msg);
7157
0
fail_alloc:             return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
7158
0
fail_trailing_comma:    return_err(cur, JSON_STRUCTURE, MSG_COMMA);
7159
0
fail_literal_true:      return_err(cur, LITERAL, MSG_CHAR_T);
7160
0
fail_literal_false:     return_err(cur, LITERAL, MSG_CHAR_F);
7161
0
fail_literal_null:      return_err(cur, LITERAL, MSG_CHAR_N);
7162
0
fail_character_val:     return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
7163
0
fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END);
7164
0
fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY);
7165
0
fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
7166
0
fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
7167
0
fail_garbage:           return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
7168
0
fail_depth:             return_err(cur, DEPTH, MSG_DEPTH);
7169
7170
0
#undef val_incr
7171
0
#undef return_err
7172
0
#undef return_err_inv_param
7173
0
#undef save_incr_state
7174
0
#undef save_incr_depth
7175
0
#undef check_maybe_truncated_number
7176
0
}
7177
7178
#endif /* YYJSON_DISABLE_INCR_READER */
7179
7180
#undef has_flg
7181
#undef has_allow
7182
#endif /* YYJSON_DISABLE_READER */
7183
7184
7185
7186
#if !YYJSON_DISABLE_WRITER /* writer begin */
7187
7188
/* Check write flag, avoids `always false` warning when disabled. */
7189
199k
#define has_flg(_flg) unlikely(has_wflag(flg, YYJSON_WRITE_##_flg, 0))
7190
40.8k
#define has_allow(_flg) unlikely(has_wflag(flg, YYJSON_WRITE_ALLOW_##_flg, 1))
7191
static_inline bool has_wflag(yyjson_write_flag flg, yyjson_write_flag chk,
7192
240k
                             bool non_standard) {
7193
#if YYJSON_DISABLE_NON_STANDARD
7194
    if (non_standard) return false;
7195
#endif
7196
240k
    return (flg & chk) != 0;
7197
240k
}
7198
7199
/*==============================================================================
7200
 * MARK: - Integer Writer (Private)
7201
 *
7202
 * The maximum value of uint32_t is 4294967295 (10 digits),
7203
 * these digits are named as 'aabbccddee' here.
7204
 *
7205
 * Although most compilers may convert the "division by constant value" into
7206
 * "multiply and shift", manual conversion can still help some compilers
7207
 * generate fewer and better instructions.
7208
 *
7209
 * Reference:
7210
 * Division by Invariant Integers using Multiplication, 1994.
7211
 * https://gmplib.org/~tege/divcnst-pldi94.pdf
7212
 * Improved division by invariant integers, 2011.
7213
 * https://gmplib.org/~tege/division-paper.pdf
7214
 *============================================================================*/
7215
7216
/** Digit table from 00 to 99. */
7217
yyjson_align(2)
7218
static const char digit_table[200] = {
7219
    '0', '0', '0', '1', '0', '2', '0', '3', '0', '4',
7220
    '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
7221
    '1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
7222
    '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
7223
    '2', '0', '2', '1', '2', '2', '2', '3', '2', '4',
7224
    '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
7225
    '3', '0', '3', '1', '3', '2', '3', '3', '3', '4',
7226
    '3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
7227
    '4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
7228
    '4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
7229
    '5', '0', '5', '1', '5', '2', '5', '3', '5', '4',
7230
    '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
7231
    '6', '0', '6', '1', '6', '2', '6', '3', '6', '4',
7232
    '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
7233
    '7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
7234
    '7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
7235
    '8', '0', '8', '1', '8', '2', '8', '3', '8', '4',
7236
    '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
7237
    '9', '0', '9', '1', '9', '2', '9', '3', '9', '4',
7238
    '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'
7239
};
7240
7241
2.09M
static_inline u8 *write_u32_len_8(u32 val, u8 *buf) {
7242
2.09M
    u32 aa, bb, cc, dd, aabb, ccdd;                 /* 8 digits: aabbccdd */
7243
2.09M
    aabb = (u32)(((u64)val * 109951163) >> 40);     /* (val / 10000) */
7244
2.09M
    ccdd = val - aabb * 10000;                      /* (val % 10000) */
7245
2.09M
    aa = (aabb * 5243) >> 19;                       /* (aabb / 100) */
7246
2.09M
    cc = (ccdd * 5243) >> 19;                       /* (ccdd / 100) */
7247
2.09M
    bb = aabb - aa * 100;                           /* (aabb % 100) */
7248
2.09M
    dd = ccdd - cc * 100;                           /* (ccdd % 100) */
7249
2.09M
    byte_copy_2(buf + 0, digit_table + aa * 2);
7250
2.09M
    byte_copy_2(buf + 2, digit_table + bb * 2);
7251
2.09M
    byte_copy_2(buf + 4, digit_table + cc * 2);
7252
2.09M
    byte_copy_2(buf + 6, digit_table + dd * 2);
7253
2.09M
    return buf + 8;
7254
2.09M
}
7255
7256
153k
static_inline u8 *write_u32_len_4(u32 val, u8 *buf) {
7257
153k
    u32 aa, bb;                                     /* 4 digits: aabb */
7258
153k
    aa = (val * 5243) >> 19;                        /* (val / 100) */
7259
153k
    bb = val - aa * 100;                            /* (val % 100) */
7260
153k
    byte_copy_2(buf + 0, digit_table + aa * 2);
7261
153k
    byte_copy_2(buf + 2, digit_table + bb * 2);
7262
153k
    return buf + 4;
7263
153k
}
7264
7265
84.6M
static_inline u8 *write_u32_len_1_to_8(u32 val, u8 *buf) {
7266
84.6M
    u32 aa, bb, cc, dd, aabb, bbcc, ccdd, lz;
7267
7268
84.6M
    if (val < 100) {                                /* 1-2 digits: aa */
7269
76.7M
        lz = val < 10;                              /* leading zero: 0 or 1 */
7270
76.7M
        byte_copy_2(buf + 0, digit_table + val * 2 + lz);
7271
76.7M
        buf -= lz;
7272
76.7M
        return buf + 2;
7273
7274
76.7M
    } else if (val < 10000) {                       /* 3-4 digits: aabb */
7275
4.07M
        aa = (val * 5243) >> 19;                    /* (val / 100) */
7276
4.07M
        bb = val - aa * 100;                        /* (val % 100) */
7277
4.07M
        lz = aa < 10;                               /* leading zero: 0 or 1 */
7278
4.07M
        byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7279
4.07M
        buf -= lz;
7280
4.07M
        byte_copy_2(buf + 2, digit_table + bb * 2);
7281
4.07M
        return buf + 4;
7282
7283
4.07M
    } else if (val < 1000000) {                     /* 5-6 digits: aabbcc */
7284
3.20M
        aa = (u32)(((u64)val * 429497) >> 32);      /* (val / 10000) */
7285
3.20M
        bbcc = val - aa * 10000;                    /* (val % 10000) */
7286
3.20M
        bb = (bbcc * 5243) >> 19;                   /* (bbcc / 100) */
7287
3.20M
        cc = bbcc - bb * 100;                       /* (bbcc % 100) */
7288
3.20M
        lz = aa < 10;                               /* leading zero: 0 or 1 */
7289
3.20M
        byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7290
3.20M
        buf -= lz;
7291
3.20M
        byte_copy_2(buf + 2, digit_table + bb * 2);
7292
3.20M
        byte_copy_2(buf + 4, digit_table + cc * 2);
7293
3.20M
        return buf + 6;
7294
7295
3.20M
    } else {                                        /* 7-8 digits: aabbccdd */
7296
615k
        aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
7297
615k
        ccdd = val - aabb * 10000;                  /* (val % 10000) */
7298
615k
        aa = (aabb * 5243) >> 19;                   /* (aabb / 100) */
7299
615k
        cc = (ccdd * 5243) >> 19;                   /* (ccdd / 100) */
7300
615k
        bb = aabb - aa * 100;                       /* (aabb % 100) */
7301
615k
        dd = ccdd - cc * 100;                       /* (ccdd % 100) */
7302
615k
        lz = aa < 10;                               /* leading zero: 0 or 1 */
7303
615k
        byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7304
615k
        buf -= lz;
7305
615k
        byte_copy_2(buf + 2, digit_table + bb * 2);
7306
615k
        byte_copy_2(buf + 4, digit_table + cc * 2);
7307
615k
        byte_copy_2(buf + 6, digit_table + dd * 2);
7308
615k
        return buf + 8;
7309
615k
    }
7310
84.6M
}
7311
7312
153k
static_inline u8 *write_u32_len_5_to_8(u32 val, u8 *buf) {
7313
153k
    u32 aa, bb, cc, dd, aabb, bbcc, ccdd, lz;
7314
7315
153k
    if (val < 1000000) {                            /* 5-6 digits: aabbcc */
7316
131k
        aa = (u32)(((u64)val * 429497) >> 32);      /* (val / 10000) */
7317
131k
        bbcc = val - aa * 10000;                    /* (val % 10000) */
7318
131k
        bb = (bbcc * 5243) >> 19;                   /* (bbcc / 100) */
7319
131k
        cc = bbcc - bb * 100;                       /* (bbcc % 100) */
7320
131k
        lz = aa < 10;                               /* leading zero: 0 or 1 */
7321
131k
        byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7322
131k
        buf -= lz;
7323
131k
        byte_copy_2(buf + 2, digit_table + bb * 2);
7324
131k
        byte_copy_2(buf + 4, digit_table + cc * 2);
7325
131k
        return buf + 6;
7326
7327
131k
    } else {                                        /* 7-8 digits: aabbccdd */
7328
21.6k
        aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
7329
21.6k
        ccdd = val - aabb * 10000;                  /* (val % 10000) */
7330
21.6k
        aa = (aabb * 5243) >> 19;                   /* (aabb / 100) */
7331
21.6k
        cc = (ccdd * 5243) >> 19;                   /* (ccdd / 100) */
7332
21.6k
        bb = aabb - aa * 100;                       /* (aabb % 100) */
7333
21.6k
        dd = ccdd - cc * 100;                       /* (ccdd % 100) */
7334
21.6k
        lz = aa < 10;                               /* leading zero: 0 or 1 */
7335
21.6k
        byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7336
21.6k
        buf -= lz;
7337
21.6k
        byte_copy_2(buf + 2, digit_table + bb * 2);
7338
21.6k
        byte_copy_2(buf + 4, digit_table + cc * 2);
7339
21.6k
        byte_copy_2(buf + 6, digit_table + dd * 2);
7340
21.6k
        return buf + 8;
7341
21.6k
    }
7342
153k
}
7343
7344
83.5M
static_inline u8 *write_u64(u64 val, u8 *buf) {
7345
83.5M
    u64 tmp, hgh;
7346
83.5M
    u32 mid, low;
7347
7348
83.5M
    if (val < 100000000) {                          /* 1-8 digits */
7349
81.7M
        buf = write_u32_len_1_to_8((u32)val, buf);
7350
81.7M
        return buf;
7351
7352
81.7M
    } else if (val < (u64)100000000 * 100000000) {  /* 9-16 digits */
7353
1.60M
        hgh = val / 100000000;                      /* (val / 100000000) */
7354
1.60M
        low = (u32)(val - hgh * 100000000);         /* (val % 100000000) */
7355
1.60M
        buf = write_u32_len_1_to_8((u32)hgh, buf);
7356
1.60M
        buf = write_u32_len_8(low, buf);
7357
1.60M
        return buf;
7358
7359
1.60M
    } else {                                        /* 17-20 digits */
7360
153k
        tmp = val / 100000000;                      /* (val / 100000000) */
7361
153k
        low = (u32)(val - tmp * 100000000);         /* (val % 100000000) */
7362
153k
        hgh = (u32)(tmp / 10000);                   /* (tmp / 10000) */
7363
153k
        mid = (u32)(tmp - hgh * 10000);             /* (tmp % 10000) */
7364
153k
        buf = write_u32_len_5_to_8((u32)hgh, buf);
7365
153k
        buf = write_u32_len_4(mid, buf);
7366
153k
        buf = write_u32_len_8(low, buf);
7367
153k
        return buf;
7368
153k
    }
7369
83.5M
}
7370
7371
7372
7373
/*==============================================================================
7374
 * MARK: - Number Writer (Private)
7375
 *============================================================================*/
7376
7377
#if !YYJSON_DISABLE_FAST_FP_CONV  /* FP_WRITER */
7378
7379
/** Trailing zero count table for number 0 to 99.
7380
    (generated with misc/make_tables.c) */
7381
static const u8 dec_trailing_zero_table[] = {
7382
    2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7383
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7384
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7385
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7386
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7387
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7388
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7389
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7390
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7391
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0
7392
};
7393
7394
588k
static_inline u8 *write_u64_len_1_to_16(u64 val, u8 *buf) {
7395
588k
    u64 hgh;
7396
588k
    u32 low;
7397
588k
    if (val < 100000000) {                          /* 1-8 digits */
7398
470k
        buf = write_u32_len_1_to_8((u32)val, buf);
7399
470k
        return buf;
7400
470k
    } else {                                        /* 9-16 digits */
7401
118k
        hgh = val / 100000000;                      /* (val / 100000000) */
7402
118k
        low = (u32)(val - hgh * 100000000);         /* (val % 100000000) */
7403
118k
        buf = write_u32_len_1_to_8((u32)hgh, buf);
7404
118k
        buf = write_u32_len_8(low, buf);
7405
118k
        return buf;
7406
118k
    }
7407
588k
}
7408
7409
710k
static_inline u8 *write_u64_len_1_to_17(u64 val, u8 *buf) {
7410
710k
    u64 hgh;
7411
710k
    u32 mid, low, one;
7412
710k
    if (val >= (u64)100000000 * 10000000) {         /* len: 16 to 17 */
7413
5.38k
        hgh = val / 100000000;                      /* (val / 100000000) */
7414
5.38k
        low = (u32)(val - hgh * 100000000);         /* (val % 100000000) */
7415
5.38k
        one = (u32)(hgh / 100000000);               /* (hgh / 100000000) */
7416
5.38k
        mid = (u32)(hgh - (u64)one * 100000000);    /* (hgh % 100000000) */
7417
5.38k
        *buf = (u8)((u8)one + (u8)'0');
7418
5.38k
        buf += one > 0;
7419
5.38k
        buf = write_u32_len_8(mid, buf);
7420
5.38k
        buf = write_u32_len_8(low, buf);
7421
5.38k
        return buf;
7422
704k
    } else if (val >= (u64)100000000){              /* len: 9 to 15 */
7423
206k
        hgh = val / 100000000;                      /* (val / 100000000) */
7424
206k
        low = (u32)(val - hgh * 100000000);         /* (val % 100000000) */
7425
206k
        buf = write_u32_len_1_to_8((u32)hgh, buf);
7426
206k
        buf = write_u32_len_8(low, buf);
7427
206k
        return buf;
7428
498k
    } else {                                        /* len: 1 to 8 */
7429
498k
        buf = write_u32_len_1_to_8((u32)val, buf);
7430
498k
        return buf;
7431
498k
    }
7432
710k
}
7433
7434
/**
7435
 Write an unsigned integer with a length of 7 to 9 with trailing zero trimmed.
7436
 These digits are named as "abbccddee" here.
7437
 For example, input 123456000, output "123456".
7438
 */
7439
0
static_inline u8 *write_u32_len_7_to_9_trim(u32 val, u8 *buf) {
7440
0
    bool lz;
7441
0
    u32 tz, tz1, tz2;
7442
7443
0
    u32 abbcc = val / 10000;                        /* (abbccddee / 10000) */
7444
0
    u32 ddee = val - abbcc * 10000;                 /* (abbccddee % 10000) */
7445
0
    u32 abb = (u32)(((u64)abbcc * 167773) >> 24);   /* (abbcc / 100) */
7446
0
    u32 a = (abb * 41) >> 12;                       /* (abb / 100) */
7447
0
    u32 bb = abb - a * 100;                         /* (abb % 100) */
7448
0
    u32 cc = abbcc - abb * 100;                     /* (abbcc % 100) */
7449
7450
    /* write abbcc */
7451
0
    buf[0] = (u8)(a + '0');
7452
0
    buf += a > 0;
7453
0
    lz = bb < 10 && a == 0;
7454
0
    byte_copy_2(buf + 0, digit_table + bb * 2 + lz);
7455
0
    buf -= lz;
7456
0
    byte_copy_2(buf + 2, digit_table + cc * 2);
7457
7458
0
    if (ddee) {
7459
0
        u32 dd = (ddee * 5243) >> 19;               /* (ddee / 100) */
7460
0
        u32 ee = ddee - dd * 100;                   /* (ddee % 100) */
7461
0
        byte_copy_2(buf + 4, digit_table + dd * 2);
7462
0
        byte_copy_2(buf + 6, digit_table + ee * 2);
7463
0
        tz1 = dec_trailing_zero_table[dd];
7464
0
        tz2 = dec_trailing_zero_table[ee];
7465
0
        tz = ee ? tz2 : (tz1 + 2);
7466
0
        buf += 8 - tz;
7467
0
        return buf;
7468
0
    } else {
7469
0
        tz1 = dec_trailing_zero_table[bb];
7470
0
        tz2 = dec_trailing_zero_table[cc];
7471
0
        tz = cc ? tz2 : (tz1 + tz2);
7472
0
        buf += 4 - tz;
7473
0
        return buf;
7474
0
    }
7475
0
}
7476
7477
/**
7478
 Write an unsigned integer with a length of 16 or 17 with trailing zero trimmed.
7479
 These digits are named as "abbccddeeffgghhii" here.
7480
 For example, input 1234567890123000, output "1234567890123".
7481
 */
7482
3.08M
static_inline u8 *write_u64_len_16_to_17_trim(u64 val, u8 *buf) {
7483
3.08M
    u32 tz, tz1, tz2;
7484
7485
3.08M
    u32 abbccddee = (u32)(val / 100000000);
7486
3.08M
    u32 ffgghhii = (u32)(val - (u64)abbccddee * 100000000);
7487
3.08M
    u32 abbcc = abbccddee / 10000;
7488
3.08M
    u32 ddee = abbccddee - abbcc * 10000;
7489
3.08M
    u32 abb = (u32)(((u64)abbcc * 167773) >> 24);   /* (abbcc / 100) */
7490
3.08M
    u32 a = (abb * 41) >> 12;                       /* (abb / 100) */
7491
3.08M
    u32 bb = abb - a * 100;                         /* (abb % 100) */
7492
3.08M
    u32 cc = abbcc - abb * 100;                     /* (abbcc % 100) */
7493
3.08M
    buf[0] = (u8)(a + '0');
7494
3.08M
    buf += a > 0;
7495
3.08M
    byte_copy_2(buf + 0, digit_table + bb * 2);
7496
3.08M
    byte_copy_2(buf + 2, digit_table + cc * 2);
7497
7498
3.08M
    if (ffgghhii) {
7499
1.28M
        u32 dd = (ddee * 5243) >> 19;               /* (ddee / 100) */
7500
1.28M
        u32 ee = ddee - dd * 100;                   /* (ddee % 100) */
7501
1.28M
        u32 ffgg = (u32)(((u64)ffgghhii * 109951163) >> 40); /* (val / 10000) */
7502
1.28M
        u32 hhii = ffgghhii - ffgg * 10000;         /* (val % 10000) */
7503
1.28M
        u32 ff = (ffgg * 5243) >> 19;               /* (aabb / 100) */
7504
1.28M
        u32 gg = ffgg - ff * 100;                   /* (aabb % 100) */
7505
1.28M
        byte_copy_2(buf + 4, digit_table + dd * 2);
7506
1.28M
        byte_copy_2(buf + 6, digit_table + ee * 2);
7507
1.28M
        byte_copy_2(buf + 8, digit_table + ff * 2);
7508
1.28M
        byte_copy_2(buf + 10, digit_table + gg * 2);
7509
1.28M
        if (hhii) {
7510
821k
            u32 hh = (hhii * 5243) >> 19;           /* (ccdd / 100) */
7511
821k
            u32 ii = hhii - hh * 100;               /* (ccdd % 100) */
7512
821k
            byte_copy_2(buf + 12, digit_table + hh * 2);
7513
821k
            byte_copy_2(buf + 14, digit_table + ii * 2);
7514
821k
            tz1 = dec_trailing_zero_table[hh];
7515
821k
            tz2 = dec_trailing_zero_table[ii];
7516
821k
            tz = ii ? tz2 : (tz1 + 2);
7517
821k
            return buf + 16 - tz;
7518
821k
        } else {
7519
459k
            tz1 = dec_trailing_zero_table[ff];
7520
459k
            tz2 = dec_trailing_zero_table[gg];
7521
459k
            tz = gg ? tz2 : (tz1 + 2);
7522
459k
            return buf + 12 - tz;
7523
459k
        }
7524
1.80M
    } else {
7525
1.80M
        if (ddee) {
7526
891k
            u32 dd = (ddee * 5243) >> 19;           /* (ddee / 100) */
7527
891k
            u32 ee = ddee - dd * 100;               /* (ddee % 100) */
7528
891k
            byte_copy_2(buf + 4, digit_table + dd * 2);
7529
891k
            byte_copy_2(buf + 6, digit_table + ee * 2);
7530
891k
            tz1 = dec_trailing_zero_table[dd];
7531
891k
            tz2 = dec_trailing_zero_table[ee];
7532
891k
            tz = ee ? tz2 : (tz1 + 2);
7533
891k
            return buf + 8 - tz;
7534
914k
        } else {
7535
914k
            tz1 = dec_trailing_zero_table[bb];
7536
914k
            tz2 = dec_trailing_zero_table[cc];
7537
914k
            tz = cc ? tz2 : (tz1 + tz2);
7538
914k
            return buf + 4 - tz;
7539
914k
        }
7540
1.80M
    }
7541
3.08M
}
7542
7543
/** Write exponent part in range `e-45` to `e38`. */
7544
0
static_inline u8 *write_f32_exp(i32 exp, u8 *buf) {
7545
0
    bool lz;
7546
0
    byte_copy_2(buf, "e-");
7547
0
    buf += 2 - (exp >= 0);
7548
0
    exp = exp < 0 ? -exp : exp;
7549
0
    lz = exp < 10;
7550
0
    byte_copy_2(buf + 0, digit_table + (u32)exp * 2 + lz);
7551
0
    return buf + 2 - lz;
7552
0
}
7553
7554
/** Write exponent part in range `e-324` to `e308`. */
7555
1.97M
static_inline u8 *write_f64_exp(i32 exp, u8 *buf) {
7556
1.97M
    byte_copy_2(buf, "e-");
7557
1.97M
    buf += 2 - (exp >= 0);
7558
1.97M
    exp = exp < 0 ? -exp : exp;
7559
1.97M
    if (exp < 100) {
7560
1.20M
        bool lz = exp < 10;
7561
1.20M
        byte_copy_2(buf + 0, digit_table + (u32)exp * 2 + lz);
7562
1.20M
        return buf + 2 - lz;
7563
1.20M
    } else {
7564
763k
        u32 hi = ((u32)exp * 656) >> 16;    /* exp / 100 */
7565
763k
        u32 lo = (u32)exp - hi * 100;       /* exp % 100 */
7566
763k
        buf[0] = (u8)((u8)hi + (u8)'0');
7567
763k
        byte_copy_2(buf + 1, digit_table + lo * 2);
7568
763k
        return buf + 3;
7569
763k
    }
7570
1.97M
}
7571
7572
/** Magic number for fast `divide by power of 10`. */
7573
typedef struct {
7574
    u64 p10, mul;
7575
    u32 shr1, shr2;
7576
} div_pow10_magic;
7577
7578
/** Generated with llvm, see https://github.com/llvm/llvm-project/
7579
    blob/main/llvm/lib/Support/DivisionByConstantInfo.cpp */
7580
static const div_pow10_magic div_pow10_table[] = {
7581
    { U64(0x00000000, 0x00000001), U64(0x00000000, 0x00000000), 0,  0  },
7582
    { U64(0x00000000, 0x0000000A), U64(0xCCCCCCCC, 0xCCCCCCCD), 0,  3  },
7583
    { U64(0x00000000, 0x00000064), U64(0x28F5C28F, 0x5C28F5C3), 2,  2  },
7584
    { U64(0x00000000, 0x000003E8), U64(0x20C49BA5, 0xE353F7CF), 3,  4  },
7585
    { U64(0x00000000, 0x00002710), U64(0x346DC5D6, 0x3886594B), 0,  11 },
7586
    { U64(0x00000000, 0x000186A0), U64(0x0A7C5AC4, 0x71B47843), 5,  7  },
7587
    { U64(0x00000000, 0x000F4240), U64(0x431BDE82, 0xD7B634DB), 0,  18 },
7588
    { U64(0x00000000, 0x00989680), U64(0xD6BF94D5, 0xE57A42BD), 0,  23 },
7589
    { U64(0x00000000, 0x05F5E100), U64(0xABCC7711, 0x8461CEFD), 0,  26 },
7590
    { U64(0x00000000, 0x3B9ACA00), U64(0x0044B82F, 0xA09B5A53), 9,  11 },
7591
    { U64(0x00000002, 0x540BE400), U64(0xDBE6FECE, 0xBDEDD5BF), 0,  33 },
7592
    { U64(0x00000017, 0x4876E800), U64(0xAFEBFF0B, 0xCB24AAFF), 0,  36 },
7593
    { U64(0x000000E8, 0xD4A51000), U64(0x232F3302, 0x5BD42233), 0,  37 },
7594
    { U64(0x00000918, 0x4E72A000), U64(0x384B84D0, 0x92ED0385), 0,  41 },
7595
    { U64(0x00005AF3, 0x107A4000), U64(0x0B424DC3, 0x5095CD81), 0,  42 },
7596
    { U64(0x00038D7E, 0xA4C68000), U64(0x00024075, 0xF3DCEAC3), 15, 20 },
7597
    { U64(0x002386F2, 0x6FC10000), U64(0x39A5652F, 0xB1137857), 0,  51 },
7598
    { U64(0x01634578, 0x5D8A0000), U64(0x00005C3B, 0xD5191B53), 17, 22 },
7599
    { U64(0x0DE0B6B3, 0xA7640000), U64(0x000049C9, 0x7747490F), 18, 24 },
7600
    { U64(0x8AC72304, 0x89E80000), U64(0x760F253E, 0xDB4AB0d3), 0,  62 },
7601
};
7602
7603
/** Divide a number by power of 10. */
7604
0
static_inline void div_pow10(u64 num, u32 exp, u64 *div, u64 *mod, u64 *p10) {
7605
0
    u64 hi, lo;
7606
0
    div_pow10_magic m = div_pow10_table[exp];
7607
0
    u128_mul(num >> m.shr1, m.mul, &hi, &lo);
7608
0
    *div = hi >> m.shr2;
7609
0
    *mod = num - (*div * m.p10);
7610
0
    *p10 = m.p10;
7611
0
}
7612
7613
/** Multiplies 64-bit integer and returns highest 64-bit rounded value. */
7614
0
static_inline u32 u64_round_to_odd(u64 u, u32 cp) {
7615
0
    u64 hi, lo;
7616
0
    u32 y_hi, y_lo;
7617
0
    u128_mul(cp, u, &hi, &lo);
7618
0
    y_hi = (u32)hi;
7619
0
    y_lo = (u32)(lo >> 32);
7620
0
    return y_hi | (y_lo > 1);
7621
0
}
7622
7623
/** Multiplies 128-bit integer and returns highest 64-bit rounded value. */
7624
1.07M
static_inline u64 u128_round_to_odd(u64 hi, u64 lo, u64 cp) {
7625
1.07M
    u64 x_hi, x_lo, y_hi, y_lo;
7626
1.07M
    u128_mul(cp, lo, &x_hi, &x_lo);
7627
1.07M
    u128_mul_add(cp, hi, x_hi, &y_hi, &y_lo);
7628
1.07M
    return y_hi | (y_lo > 1);
7629
1.07M
}
7630
7631
/** Convert f32 from binary to decimal (shortest but may have trailing zeros).
7632
    The input should not be 0, inf or nan. */
7633
static_inline void f32_bin_to_dec(u32 sig_raw, u32 exp_raw,
7634
                                  u32 sig_bin, i32 exp_bin,
7635
0
                                  u32 *sig_dec, i32 *exp_dec) {
7636
7637
0
    bool is_even, irregular, round_up, trim;
7638
0
    bool u0_inside, u1_inside, w0_inside, w1_inside;
7639
0
    u64 p10_hi, p10_lo, hi, lo;
7640
0
    u32 s, sp, cb, cbl, cbr, vb, vbl, vbr, upper, lower, mid;
7641
0
    i32 k, h;
7642
7643
    /* Fast path, see f64_bin_to_dec(). */
7644
0
    while (likely(sig_raw)) {
7645
0
        u32 mod, dec, add_1, add_10, s_hi, s_lo;
7646
0
        u32 c, half_ulp, t0, t1;
7647
7648
        /* k = floor(exp_bin * log10(2)); */
7649
        /* h = exp_bin + floor(log2(10) * -k); (h = 0/1/2/3) */
7650
0
        k = (i32)(exp_bin * 315653) >> 20;
7651
0
        h = exp_bin + ((-k * 217707) >> 16);
7652
0
        pow10_table_get_sig(-k, &p10_hi, &p10_lo);
7653
7654
        /* sig_bin << (1/2/3/4) */
7655
0
        cb = sig_bin << (h + 1);
7656
0
        u128_mul(cb, p10_hi, &hi, &lo);
7657
0
        s_hi = (u32)(hi);
7658
0
        s_lo = (u32)(lo >> 32);
7659
0
        mod = s_hi % 10;
7660
0
        dec = s_hi - mod;
7661
7662
        /* right shift 4 to fit in u32 */
7663
0
        c = (mod << (32 - 4)) | (s_lo >> 4);
7664
0
        half_ulp = (u32)(p10_hi >> (32 + 4 - h));
7665
7666
        /* check w1, u0, w0 range */
7667
0
        w1_inside = (s_lo >= ((u32)1 << 31));
7668
0
        if (unlikely(s_lo == ((u32)1 << 31))) break;
7669
0
        u0_inside = (half_ulp >= c);
7670
0
        if (unlikely(half_ulp == c)) break;
7671
0
        t0 = (u32)10 << (32 - 4);
7672
0
        t1 = c + half_ulp;
7673
0
        w0_inside = (t1 >= t0);
7674
0
        if (unlikely(t0 - t1 <= (u32)1)) break;
7675
7676
0
        trim = (u0_inside | w0_inside);
7677
0
        add_10 = (w0_inside ? 10 : 0);
7678
0
        add_1 = mod + w1_inside;
7679
0
        *sig_dec = dec + (trim ? add_10 : add_1);
7680
0
        *exp_dec = k;
7681
0
        return;
7682
0
    }
7683
7684
    /* Schubfach algorithm, see f64_bin_to_dec(). */
7685
0
    irregular = (sig_raw == 0 && exp_raw > 1);
7686
0
    is_even = !(sig_bin & 1);
7687
0
    cbl = 4 * sig_bin - 2 + irregular;
7688
0
    cb  = 4 * sig_bin;
7689
0
    cbr = 4 * sig_bin + 2;
7690
7691
    /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */
7692
    /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */
7693
0
    k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20;
7694
0
    h = exp_bin + ((-k * 217707) >> 16) + 1;
7695
0
    pow10_table_get_sig(-k, &p10_hi, &p10_lo);
7696
0
    p10_hi += 1;
7697
7698
0
    vbl = u64_round_to_odd(p10_hi, cbl << h);
7699
0
    vb  = u64_round_to_odd(p10_hi, cb  << h);
7700
0
    vbr = u64_round_to_odd(p10_hi, cbr << h);
7701
0
    lower = vbl + !is_even;
7702
0
    upper = vbr - !is_even;
7703
7704
0
    s = vb / 4;
7705
0
    if (s >= 10) {
7706
0
        sp = s / 10;
7707
0
        u0_inside = (lower <= 40 * sp);
7708
0
        w0_inside = (upper >= 40 * sp + 40);
7709
0
        if (u0_inside != w0_inside) {
7710
0
            *sig_dec = sp * 10 + (w0_inside ? 10 : 0);
7711
0
            *exp_dec = k;
7712
0
            return;
7713
0
        }
7714
0
    }
7715
0
    u1_inside = (lower <= 4 * s);
7716
0
    w1_inside = (upper >= 4 * s + 4);
7717
0
    mid = 4 * s + 2;
7718
0
    round_up = (vb > mid) || (vb == mid && (s & 1) != 0);
7719
0
    *sig_dec = s + ((u1_inside != w1_inside) ? w1_inside : round_up);
7720
0
    *exp_dec = k;
7721
0
}
7722
7723
/** Convert f64 from binary to decimal (shortest but may have trailing zeros).
7724
    The input should not be 0, inf or nan. */
7725
static_inline void f64_bin_to_dec(u64 sig_raw, u32 exp_raw,
7726
                                  u64 sig_bin, i32 exp_bin,
7727
3.79M
                                  u64 *sig_dec, i32 *exp_dec) {
7728
7729
3.79M
    bool is_even, irregular, round_up, trim;
7730
3.79M
    bool u0_inside, u1_inside, w0_inside, w1_inside;
7731
3.79M
    u64 s, sp, cb, cbl, cbr, vb, vbl, vbr, p10_hi, p10_lo, upper, lower, mid;
7732
3.79M
    i32 k, h;
7733
7734
    /*
7735
     Fast path:
7736
     For regular spacing significand 'c', there are 4 candidates:
7737
7738
             u0             u1 c  w1                            w0
7739
     ----|----|----|----|----|-*--|----|----|----|----|----|----|----|----
7740
         9    0    1    2    3    4    5    6    7    8    9    0    1
7741
           |___________________|___________________|
7742
                             1ulp
7743
7744
     The `1ulp` is in the range [1.0, 10.0).
7745
     If (c - 0.5ulp < u0), trim the last digit and round down.
7746
     If (c + 0.5ulp > w0), trim the last digit and round up.
7747
     If (c - 0.5ulp < u1), round down.
7748
     If (c + 0.5ulp > w1), round up.
7749
     */
7750
3.79M
    while (likely(sig_raw)) {
7751
3.79M
        u64 mod, dec, add_1, add_10, s_hi, s_lo;
7752
3.79M
        u64 c, half_ulp, t0, t1;
7753
7754
        /* k = floor(exp_bin * log10(2)); */
7755
        /* h = exp_bin + floor(log2(10) * -k); (h = 0/1/2/3) */
7756
3.79M
        k = (i32)(exp_bin * 315653) >> 20;
7757
3.79M
        h = exp_bin + ((-k * 217707) >> 16);
7758
3.79M
        pow10_table_get_sig(-k, &p10_hi, &p10_lo);
7759
7760
        /* sig_bin << (1/2/3/4) */
7761
3.79M
        cb = sig_bin << (h + 1);
7762
3.79M
        u128_mul(cb, p10_lo, &s_hi, &s_lo);
7763
3.79M
        u128_mul_add(cb, p10_hi, s_hi, &s_hi, &s_lo);
7764
3.79M
        mod = s_hi % 10;
7765
3.79M
        dec = s_hi - mod;
7766
7767
        /* right shift 4 to fit in u64 */
7768
3.79M
        c = (mod << (64 - 4)) | (s_lo >> 4);
7769
3.79M
        half_ulp = p10_hi >> (4 - h);
7770
7771
        /* check w1, u0, w0 range */
7772
3.79M
        w1_inside = (s_lo >= ((u64)1 << 63));
7773
3.79M
        if (unlikely(s_lo == ((u64)1 << 63))) break;
7774
3.69M
        u0_inside = (half_ulp >= c);
7775
3.69M
        if (unlikely(half_ulp == c)) break;
7776
3.44M
        t0 = ((u64)10 << (64 - 4));
7777
3.44M
        t1 = c + half_ulp;
7778
3.44M
        w0_inside = (t1 >= t0);
7779
3.44M
        if (unlikely(t0 - t1 <= (u64)1)) break;
7780
7781
3.43M
        trim = (u0_inside | w0_inside);
7782
3.43M
        add_10 = (w0_inside ? 10 : 0);
7783
3.43M
        add_1 = mod + w1_inside;
7784
3.43M
        *sig_dec = dec + (trim ? add_10 : add_1);
7785
3.43M
        *exp_dec = k;
7786
3.43M
        return;
7787
3.44M
    }
7788
7789
    /*
7790
     Schubfach algorithm:
7791
     Raffaello Giulietti, The Schubfach way to render doubles, 2022.
7792
     https://drive.google.com/file/d/1gp5xv4CAa78SVgCeWfGqqI4FfYYYuNFb (Paper)
7793
     https://github.com/openjdk/jdk/pull/3402 (Java implementation)
7794
     https://github.com/abolz/Drachennest (C++ implementation)
7795
     */
7796
357k
    irregular = (sig_raw == 0 && exp_raw > 1);
7797
357k
    is_even = !(sig_bin & 1);
7798
357k
    cbl = 4 * sig_bin - 2 + irregular;
7799
357k
    cb  = 4 * sig_bin;
7800
357k
    cbr = 4 * sig_bin + 2;
7801
7802
    /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */
7803
    /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */
7804
357k
    k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20;
7805
357k
    h = exp_bin + ((-k * 217707) >> 16) + 1;
7806
357k
    pow10_table_get_sig(-k, &p10_hi, &p10_lo);
7807
357k
    p10_lo += 1;
7808
7809
357k
    vbl = u128_round_to_odd(p10_hi, p10_lo, cbl << h);
7810
357k
    vb  = u128_round_to_odd(p10_hi, p10_lo, cb  << h);
7811
357k
    vbr = u128_round_to_odd(p10_hi, p10_lo, cbr << h);
7812
357k
    lower = vbl + !is_even;
7813
357k
    upper = vbr - !is_even;
7814
7815
357k
    s = vb / 4;
7816
357k
    if (s >= 10) {
7817
357k
        sp = s / 10;
7818
357k
        u0_inside = (lower <= 40 * sp);
7819
357k
        w0_inside = (upper >= 40 * sp + 40);
7820
357k
        if (u0_inside != w0_inside) {
7821
246k
            *sig_dec = sp * 10 + (w0_inside ? 10 : 0);
7822
246k
            *exp_dec = k;
7823
246k
            return;
7824
246k
        }
7825
357k
    }
7826
111k
    u1_inside = (lower <= 4 * s);
7827
111k
    w1_inside = (upper >= 4 * s + 4);
7828
111k
    mid = 4 * s + 2;
7829
111k
    round_up = (vb > mid) || (vb == mid && (s & 1) != 0);
7830
111k
    *sig_dec = s + ((u1_inside != w1_inside) ? w1_inside : round_up);
7831
111k
    *exp_dec = k;
7832
111k
}
7833
7834
/** Convert f64 from binary to decimal (fast but not the shortest).
7835
    The input should not be 0, inf, nan. */
7836
static_inline void f64_bin_to_dec_fast(u64 sig_raw, u32 exp_raw,
7837
                                       u64 sig_bin, i32 exp_bin,
7838
                                       u64 *sig_dec, i32 *exp_dec,
7839
0
                                       bool *round_up) {
7840
0
    u64 cb, p10_hi, p10_lo, s_hi, s_lo;
7841
0
    i32 k, h;
7842
0
    bool irregular, u;
7843
7844
0
    irregular = (sig_raw == 0 && exp_raw > 1);
7845
7846
    /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */
7847
    /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */
7848
0
    k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20;
7849
0
    h = exp_bin + ((-k * 217707) >> 16);
7850
0
    pow10_table_get_sig(-k, &p10_hi, &p10_lo);
7851
7852
    /* sig_bin << (1/2/3/4) */
7853
0
    cb = sig_bin << (h + 1);
7854
0
    u128_mul(cb, p10_lo, &s_hi, &s_lo);
7855
0
    u128_mul_add(cb, p10_hi, s_hi, &s_hi, &s_lo);
7856
7857
    /* round up */
7858
0
    u = s_lo >= (irregular ? U64(0x55555555, 0x55555555) : ((u64)1 << 63));
7859
7860
0
    *sig_dec = s_hi + u;
7861
0
    *exp_dec = k;
7862
0
    *round_up = u;
7863
0
    return;
7864
0
}
7865
7866
/** Write inf/nan if allowed. */
7867
static_inline u8 *write_inf_or_nan(u8 *buf, yyjson_write_flag flg,
7868
2.51k
                                   u64 sig_raw, bool sign) {
7869
2.51k
    if (has_flg(INF_AND_NAN_AS_NULL)) {
7870
0
        byte_copy_4(buf, "null");
7871
0
        return buf + 4;
7872
0
    }
7873
2.51k
    if (has_allow(INF_AND_NAN)) {
7874
2.51k
        if (sig_raw == 0) {
7875
1.63k
            buf[0] = '-';
7876
1.63k
            buf += sign;
7877
1.63k
            byte_copy_8(buf, "Infinity");
7878
1.63k
            return buf + 8;
7879
1.63k
        } else {
7880
876
            byte_copy_4(buf, "NaN");
7881
876
            return buf + 3;
7882
876
        }
7883
2.51k
    }
7884
0
    return NULL;
7885
2.51k
}
7886
7887
/**
7888
 Write a float number (requires 40 bytes buffer).
7889
 We follow the ECMAScript specification for printing floating-point numbers,
7890
 similar to `Number.prototype.toString()`, but with the following changes:
7891
 1. Keep the negative sign of `-0.0` to preserve input information.
7892
 2. Keep the decimal point to indicate that the number is floating-point.
7893
 3. Remove positive sign in the exponent part.
7894
 */
7895
static_noinline u8 *write_f32_raw(u8 *buf, u64 raw_f64,
7896
0
                                  yyjson_write_flag flg) {
7897
0
    u32 sig_bin, sig_dec, sig_raw;
7898
0
    i32 exp_bin, exp_dec, sig_len, dot_ofs;
7899
0
    u32 exp_raw, raw;
7900
0
    u8 *end;
7901
0
    bool sign;
7902
7903
    /* cast double to float */
7904
0
    raw = f32_to_bits(f64_to_f32(f64_from_bits(raw_f64)));
7905
7906
    /* decode raw bytes from IEEE-754 double format. */
7907
0
    sign = (bool)(raw >> (F32_BITS - 1));
7908
0
    sig_raw = raw & F32_SIG_MASK;
7909
0
    exp_raw = (raw & F32_EXP_MASK) >> F32_SIG_BITS;
7910
7911
    /* return inf or nan */
7912
0
    if (unlikely(exp_raw == ((u32)1 << F32_EXP_BITS) - 1)) {
7913
0
        return write_inf_or_nan(buf, flg, sig_raw, sign);
7914
0
    }
7915
7916
    /* add sign for all finite number */
7917
0
    buf[0] = '-';
7918
0
    buf += sign;
7919
7920
    /* return zero */
7921
0
    if ((raw << 1) == 0) {
7922
0
        byte_copy_4(buf, "0.0");
7923
0
        return buf + 3;
7924
0
    }
7925
7926
0
    if (likely(exp_raw != 0)) {
7927
        /* normal number */
7928
0
        sig_bin = sig_raw | ((u32)1 << F32_SIG_BITS);
7929
0
        exp_bin = (i32)exp_raw - F32_EXP_BIAS - F32_SIG_BITS;
7930
7931
        /* fast path for small integer number without fraction */
7932
0
        if ((-F32_SIG_BITS <= exp_bin && exp_bin <= 0) &&
7933
0
            (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) {
7934
0
            sig_dec = sig_bin >> -exp_bin; /* range: [1, 0xFFFFFF] */
7935
0
            buf = write_u32_len_1_to_8(sig_dec, buf);
7936
0
            byte_copy_2(buf, ".0");
7937
0
            return buf + 2;
7938
0
        }
7939
7940
        /* binary to decimal */
7941
0
        f32_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
7942
7943
        /* the sig length is 7 or 9 */
7944
0
        sig_len = 7 + (sig_dec >= (u32)10000000) + (sig_dec >= (u32)100000000);
7945
7946
        /* the decimal point offset relative to the first digit */
7947
0
        dot_ofs = sig_len + exp_dec;
7948
7949
0
        if (-6 < dot_ofs && dot_ofs <= 21) {
7950
0
            i32 num_sep_pos, dot_set_pos, pre_ofs;
7951
0
            u8 *num_hdr, *num_end, *num_sep, *dot_end;
7952
0
            bool no_pre_zero;
7953
7954
            /* fill zeros */
7955
0
            memset(buf, '0', 32);
7956
7957
            /* not prefixed with zero, e.g. 1.234, 1234.0 */
7958
0
            no_pre_zero = (dot_ofs > 0);
7959
7960
            /* write the number as digits */
7961
0
            pre_ofs = no_pre_zero ? 0 : (2 - dot_ofs);
7962
0
            num_hdr = buf + pre_ofs;
7963
0
            num_end = write_u32_len_7_to_9_trim(sig_dec, num_hdr);
7964
7965
            /* separate these digits to leave a space for dot */
7966
0
            num_sep_pos = no_pre_zero ? dot_ofs : 0;
7967
0
            num_sep = num_hdr + num_sep_pos;
7968
0
            byte_move_8(num_sep + no_pre_zero, num_sep);
7969
0
            num_end += no_pre_zero;
7970
7971
            /* write the dot */
7972
0
            dot_set_pos = yyjson_max(dot_ofs, 1);
7973
0
            buf[dot_set_pos] = '.';
7974
7975
            /* return the ending */
7976
0
            dot_end = buf + dot_ofs + 2;
7977
0
            return yyjson_max(dot_end, num_end);
7978
7979
0
        } else {
7980
            /* write with scientific notation, e.g. 1.234e56 */
7981
0
            end = write_u32_len_7_to_9_trim(sig_dec, buf + 1);
7982
0
            end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */
7983
0
            exp_dec += sig_len - 1;
7984
0
            buf[0] = buf[1];
7985
0
            buf[1] = '.';
7986
0
            return write_f32_exp(exp_dec, end);
7987
0
        }
7988
7989
0
    } else {
7990
        /* subnormal number */
7991
0
        sig_bin = sig_raw;
7992
0
        exp_bin = 1 - F32_EXP_BIAS - F32_SIG_BITS;
7993
7994
        /* binary to decimal */
7995
0
        f32_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
7996
7997
        /* write significand part */
7998
0
        end = write_u32_len_1_to_8(sig_dec, buf + 1);
7999
0
        buf[0] = buf[1];
8000
0
        buf[1] = '.';
8001
0
        exp_dec += (i32)(end - buf) - 2;
8002
8003
        /* trim trailing zeros */
8004
0
        end -= *(end - 1) == '0'; /* branchless for last zero */
8005
0
        end -= *(end - 1) == '0'; /* branchless for second last zero */
8006
0
        while (*(end - 1) == '0') end--; /* for unlikely more zeros */
8007
0
        end -= *(end - 1) == '.'; /* remove dot, e.g. 2.e-321 -> 2e-321 */
8008
8009
        /* write exponent part */
8010
0
        return write_f32_exp(exp_dec, end);
8011
0
    }
8012
0
}
8013
8014
/**
8015
 Write a double number (requires 40 bytes buffer).
8016
 We follow the ECMAScript specification for printing floating-point numbers,
8017
 similar to `Number.prototype.toString()`, but with the following changes:
8018
 1. Keep the negative sign of `-0.0` to preserve input information.
8019
 2. Keep the decimal point to indicate that the number is floating-point.
8020
 3. Remove positive sign in the exponent part.
8021
 */
8022
4.41M
static_noinline u8 *write_f64_raw(u8 *buf, u64 raw, yyjson_write_flag flg) {
8023
4.41M
    u64 sig_bin, sig_dec, sig_raw;
8024
4.41M
    i32 exp_bin, exp_dec, sig_len, dot_ofs;
8025
4.41M
    u32 exp_raw;
8026
4.41M
    u8 *end;
8027
4.41M
    bool sign;
8028
8029
    /* decode raw bytes from IEEE-754 double format. */
8030
4.41M
    sign = (bool)(raw >> (F64_BITS - 1));
8031
4.41M
    sig_raw = raw & F64_SIG_MASK;
8032
4.41M
    exp_raw = (u32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
8033
8034
    /* return inf or nan */
8035
4.41M
    if (unlikely(exp_raw == ((u32)1 << F64_EXP_BITS) - 1)) {
8036
2.51k
        return write_inf_or_nan(buf, flg, sig_raw, sign);
8037
2.51k
    }
8038
8039
    /* add sign for all finite number */
8040
4.40M
    buf[0] = '-';
8041
4.40M
    buf += sign;
8042
8043
    /* return zero */
8044
4.40M
    if ((raw << 1) == 0) {
8045
24.0k
        byte_copy_4(buf, "0.0");
8046
24.0k
        return buf + 3;
8047
24.0k
    }
8048
8049
4.38M
    if (likely(exp_raw != 0)) {
8050
        /* normal number */
8051
3.67M
        sig_bin = sig_raw | ((u64)1 << F64_SIG_BITS);
8052
3.67M
        exp_bin = (i32)exp_raw - F64_EXP_BIAS - F64_SIG_BITS;
8053
8054
        /* fast path for small integer number without fraction */
8055
3.67M
        if ((-F64_SIG_BITS <= exp_bin && exp_bin <= 0) &&
8056
2.01M
            (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) {
8057
588k
            sig_dec = sig_bin >> -exp_bin; /* range: [1, 0x1FFFFFFFFFFFFF] */
8058
588k
            buf = write_u64_len_1_to_16(sig_dec, buf);
8059
588k
            byte_copy_2(buf, ".0");
8060
588k
            return buf + 2;
8061
588k
        }
8062
8063
        /* binary to decimal */
8064
3.08M
        f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
8065
8066
        /* the sig length is 16 or 17 */
8067
3.08M
        sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
8068
8069
        /* the decimal point offset relative to the first digit */
8070
3.08M
        dot_ofs = sig_len + exp_dec;
8071
8072
3.08M
        if (-6 < dot_ofs && dot_ofs <= 21) {
8073
1.82M
            i32 num_sep_pos, dot_set_pos, pre_ofs;
8074
1.82M
            u8 *num_hdr, *num_end, *num_sep, *dot_end;
8075
1.82M
            bool no_pre_zero;
8076
8077
            /* fill zeros */
8078
1.82M
            memset(buf, '0', 32);
8079
8080
            /* not prefixed with zero, e.g. 1.234, 1234.0 */
8081
1.82M
            no_pre_zero = (dot_ofs > 0);
8082
8083
            /* write the number as digits */
8084
1.82M
            pre_ofs = no_pre_zero ? 0 : (2 - dot_ofs);
8085
1.82M
            num_hdr = buf + pre_ofs;
8086
1.82M
            num_end = write_u64_len_16_to_17_trim(sig_dec, num_hdr);
8087
8088
            /* separate these digits to leave a space for dot */
8089
1.82M
            num_sep_pos = no_pre_zero ? dot_ofs : 0;
8090
1.82M
            num_sep = num_hdr + num_sep_pos;
8091
1.82M
            byte_move_16(num_sep + no_pre_zero, num_sep);
8092
1.82M
            num_end += no_pre_zero;
8093
8094
            /* write the dot */
8095
1.82M
            dot_set_pos = yyjson_max(dot_ofs, 1);
8096
1.82M
            buf[dot_set_pos] = '.';
8097
8098
            /* return the ending */
8099
1.82M
            dot_end = buf + dot_ofs + 2;
8100
1.82M
            return yyjson_max(dot_end, num_end);
8101
8102
1.82M
        } else {
8103
            /* write with scientific notation, e.g. 1.234e56 */
8104
1.26M
            end = write_u64_len_16_to_17_trim(sig_dec, buf + 1);
8105
1.26M
            end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */
8106
1.26M
            exp_dec += sig_len - 1;
8107
1.26M
            buf[0] = buf[1];
8108
1.26M
            buf[1] = '.';
8109
1.26M
            return write_f64_exp(exp_dec, end);
8110
1.26M
        }
8111
8112
3.08M
    } else {
8113
        /* subnormal number */
8114
710k
        sig_bin = sig_raw;
8115
710k
        exp_bin = 1 - F64_EXP_BIAS - F64_SIG_BITS;
8116
8117
        /* binary to decimal */
8118
710k
        f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
8119
8120
        /* write significand part */
8121
710k
        end = write_u64_len_1_to_17(sig_dec, buf + 1);
8122
710k
        buf[0] = buf[1];
8123
710k
        buf[1] = '.';
8124
710k
        exp_dec += (i32)(end - buf) - 2;
8125
8126
        /* trim trailing zeros */
8127
710k
        end -= *(end - 1) == '0'; /* branchless for last zero */
8128
710k
        end -= *(end - 1) == '0'; /* branchless for second last zero */
8129
1.64M
        while (*(end - 1) == '0') end--; /* for unlikely more zeros */
8130
710k
        end -= *(end - 1) == '.'; /* remove dot, e.g. 2.e-321 -> 2e-321 */
8131
8132
        /* write exponent part */
8133
710k
        return write_f64_exp(exp_dec, end);
8134
710k
    }
8135
4.38M
}
8136
8137
/**
8138
 Write a double number using fixed-point notation (requires 40 bytes buffer).
8139
8140
 We follow the ECMAScript specification for printing floating-point numbers,
8141
 similar to `Number.prototype.toFixed(prec)`, but with the following changes:
8142
 1. Keep the negative sign of `-0.0` to preserve input information.
8143
 2. Keep the decimal point to indicate that the number is floating-point.
8144
 3. Remove positive sign in the exponent part.
8145
 4. Remove trailing zeros and reduce unnecessary precision.
8146
 */
8147
static_noinline u8 *write_f64_raw_fixed(u8 *buf, u64 raw, yyjson_write_flag flg,
8148
0
                                        u32 prec) {
8149
0
    u64 sig_bin, sig_dec, sig_raw;
8150
0
    i32 exp_bin, exp_dec, sig_len, dot_ofs;
8151
0
    u32 exp_raw;
8152
0
    u8 *end;
8153
0
    bool sign;
8154
8155
    /* decode raw bytes from IEEE-754 double format. */
8156
0
    sign = (bool)(raw >> (F64_BITS - 1));
8157
0
    sig_raw = raw & F64_SIG_MASK;
8158
0
    exp_raw = (u32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
8159
8160
    /* return inf or nan */
8161
0
    if (unlikely(exp_raw == ((u32)1 << F64_EXP_BITS) - 1)) {
8162
0
        return write_inf_or_nan(buf, flg, sig_raw, sign);
8163
0
    }
8164
8165
    /* add sign for all finite number */
8166
0
    buf[0] = '-';
8167
0
    buf += sign;
8168
8169
    /* return zero */
8170
0
    if ((raw << 1) == 0) {
8171
0
        byte_copy_4(buf, "0.0");
8172
0
        return buf + 3;
8173
0
    }
8174
8175
0
    if (likely(exp_raw != 0)) {
8176
        /* normal number */
8177
0
        sig_bin = sig_raw | ((u64)1 << F64_SIG_BITS);
8178
0
        exp_bin = (i32)exp_raw - F64_EXP_BIAS - F64_SIG_BITS;
8179
8180
        /* fast path for small integer number without fraction */
8181
0
        if ((-F64_SIG_BITS <= exp_bin && exp_bin <= 0) &&
8182
0
            (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) {
8183
0
            sig_dec = sig_bin >> -exp_bin; /* range: [1, 0x1FFFFFFFFFFFFF] */
8184
0
            buf = write_u64_len_1_to_16(sig_dec, buf);
8185
0
            byte_copy_2(buf, ".0");
8186
0
            return buf + 2;
8187
0
        }
8188
8189
        /* only `fabs(num) < 1e21` are processed here. */
8190
0
        if ((raw << 1) < (U64(0x444B1AE4, 0xD6E2EF50) << 1)) {
8191
0
            i32 num_sep_pos, dot_set_pos, pre_ofs;
8192
0
            u8 *num_hdr, *num_end, *num_sep;
8193
0
            bool round_up, no_pre_zero;
8194
8195
            /* binary to decimal */
8196
0
            f64_bin_to_dec_fast(sig_raw, exp_raw, sig_bin, exp_bin,
8197
0
                                &sig_dec, &exp_dec, &round_up);
8198
8199
            /* the sig length is 16 or 17 */
8200
0
            sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
8201
8202
            /* limit the length of digits after the decimal point */
8203
0
            if (exp_dec < -1) {
8204
0
                i32 sig_len_cut = -exp_dec - (i32)prec;
8205
0
                if (sig_len_cut > sig_len) {
8206
0
                    byte_copy_4(buf, "0.0");
8207
0
                    return buf + 3;
8208
0
                }
8209
0
                if (sig_len_cut > 0) {
8210
0
                    u64 div, mod, p10;
8211
8212
                    /* remove round up */
8213
0
                    sig_dec -= round_up;
8214
0
                    sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
8215
8216
                    /* cut off some digits */
8217
0
                    div_pow10(sig_dec, (u32)sig_len_cut, &div, &mod, &p10);
8218
8219
                    /* add round up */
8220
0
                    sig_dec = div + (mod >= p10 / 2);
8221
8222
                    /* update exp and sig length */
8223
0
                    exp_dec += sig_len_cut;
8224
0
                    sig_len -= sig_len_cut;
8225
0
                    sig_len += (sig_len >= 0) &&
8226
0
                               (sig_dec >= div_pow10_table[sig_len].p10);
8227
0
                }
8228
0
                if (sig_len <= 0) {
8229
0
                    byte_copy_4(buf, "0.0");
8230
0
                    return buf + 3;
8231
0
                }
8232
0
            }
8233
8234
            /* fill zeros */
8235
0
            memset(buf, '0', 32);
8236
8237
            /* the decimal point offset relative to the first digit */
8238
0
            dot_ofs = sig_len + exp_dec;
8239
8240
            /* not prefixed with zero, e.g. 1.234, 1234.0 */
8241
0
            no_pre_zero = (dot_ofs > 0);
8242
8243
            /* write the number as digits */
8244
0
            pre_ofs = no_pre_zero ? 0 : (1 - dot_ofs);
8245
0
            num_hdr = buf + pre_ofs;
8246
0
            num_end = write_u64_len_1_to_17(sig_dec, num_hdr);
8247
8248
            /* separate these digits to leave a space for dot */
8249
0
            num_sep_pos = no_pre_zero ? dot_ofs : -dot_ofs;
8250
0
            num_sep = buf + num_sep_pos;
8251
0
            byte_move_16(num_sep + 1, num_sep);
8252
0
            num_end += (exp_dec < 0);
8253
8254
            /* write the dot */
8255
0
            dot_set_pos = yyjson_max(dot_ofs, 1);
8256
0
            buf[dot_set_pos] = '.';
8257
8258
            /* remove trailing zeros */
8259
0
            buf += dot_set_pos + 2;
8260
0
            buf = yyjson_max(buf, num_end);
8261
0
            buf -= *(buf - 1) == '0'; /* branchless for last zero */
8262
0
            buf -= *(buf - 1) == '0'; /* branchless for second last zero */
8263
0
            while (*(buf - 1) == '0') buf--; /* for unlikely more zeros */
8264
0
            buf += *(buf - 1) == '.'; /* keep a zero after dot */
8265
0
            return buf;
8266
8267
0
        } else {
8268
            /* binary to decimal */
8269
0
            f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin,
8270
0
                           &sig_dec, &exp_dec);
8271
8272
            /* the sig length is 16 or 17 */
8273
0
            sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
8274
8275
            /* write with scientific notation, e.g. 1.234e56 */
8276
0
            end = write_u64_len_16_to_17_trim(sig_dec, buf + 1);
8277
0
            end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */
8278
0
            exp_dec += sig_len - 1;
8279
0
            buf[0] = buf[1];
8280
0
            buf[1] = '.';
8281
0
            return write_f64_exp(exp_dec, end);
8282
0
        }
8283
0
    } else {
8284
        /* subnormal number */
8285
0
        byte_copy_4(buf, "0.0");
8286
0
        return buf + 3;
8287
0
    }
8288
0
}
8289
8290
#else /* FP_WRITER */
8291
8292
#if YYJSON_MSC_VER >= 1400
8293
#define snprintf_num(buf, len, fmt, dig, val) \
8294
    sprintf_s((char *)buf, len, fmt, dig, val)
8295
#elif defined(snprintf) || (YYJSON_STDC_VER >= 199901L)
8296
#define snprintf_num(buf, len, fmt, dig, val) \
8297
    snprintf((char *)buf, len, fmt, dig, val)
8298
#else
8299
#define snprintf_num(buf, len, fmt, dig, val) \
8300
    sprintf((char *)buf, fmt, dig, val)
8301
#endif
8302
8303
static_noinline u8 *write_fp_reformat(u8 *buf, int len,
8304
                                    yyjson_write_flag flg, bool fixed) {
8305
    u8 *cur = buf;
8306
    if (unlikely(len < 1)) return NULL;
8307
    cur += (*cur == '-');
8308
    if (unlikely(!char_is_digit(*cur))) {
8309
        /* nan, inf, or bad output */
8310
        if (has_flg(INF_AND_NAN_AS_NULL)) {
8311
            byte_copy_4(buf, "null");
8312
            return buf + 4;
8313
        } else if (has_allow(INF_AND_NAN)) {
8314
            if (*cur == 'i') {
8315
                byte_copy_8(cur, "Infinity");
8316
                return cur + 8;
8317
            } else if (*cur == 'n') {
8318
                byte_copy_4(buf, "NaN");
8319
                return buf + 3;
8320
            }
8321
        }
8322
        return NULL;
8323
    } else {
8324
        /* finite number */
8325
        u8 *end = buf + len, *dot = NULL, *exp = NULL;
8326
8327
        /*
8328
         The snprintf() function is locale-dependent. For currently known
8329
         locales, (en, zh, ja, ko, am, he, hi) use '.' as the decimal point,
8330
         while other locales use ',' as the decimal point. we need to replace
8331
         ',' with '.' to avoid the locale setting.
8332
         */
8333
        for (; cur < end; cur++) {
8334
            switch (*cur) {
8335
                case ',': *cur = '.'; /* fallthrough */
8336
                case '.': dot = cur; break;
8337
                case 'e': exp = cur; break;
8338
                default: break;
8339
            }
8340
        }
8341
        if (fixed) {
8342
            /* remove trailing zeros */
8343
            while (*(end - 1) == '0') end--;
8344
            end += *(end - 1) == '.';
8345
        } else {
8346
            if (!dot && !exp) {
8347
                /* add decimal point, e.g. 123 -> 123.0 */
8348
                byte_copy_2(end, ".0");
8349
                end += 2;
8350
            } else if (exp) {
8351
                cur = exp + 1;
8352
                /* remove positive sign in the exponent part */
8353
                if (*cur == '+') {
8354
                    memmove(cur, cur + 1, (usize)(end - cur - 1));
8355
                    end--;
8356
                }
8357
                cur += (*cur == '-');
8358
                /* remove leading zeros in the exponent part */
8359
                if (*cur == '0') {
8360
                    u8 *hdr = cur++;
8361
                    while (*cur == '0') cur++;
8362
                    memmove(hdr, cur, (usize)(end - cur));
8363
                    end -= (usize)(cur - hdr);
8364
                }
8365
            }
8366
        }
8367
        return end;
8368
    }
8369
}
8370
8371
/** Write a double number (requires 40 bytes buffer). */
8372
static_noinline u8 *write_f64_raw(u8 *buf, u64 raw, yyjson_write_flag flg) {
8373
#if defined(DBL_DECIMAL_DIG) && DBL_DECIMAL_DIG < F64_DEC_DIG
8374
    int dig = DBL_DECIMAL_DIG;
8375
#else
8376
    int dig = F64_DEC_DIG;
8377
#endif
8378
    f64 val = f64_from_bits(raw);
8379
    int len = snprintf_num(buf, FP_BUF_LEN, "%.*g", dig, val);
8380
    return write_fp_reformat(buf, len, flg, false);
8381
}
8382
8383
/** Write a double number (requires 40 bytes buffer). */
8384
static_noinline u8 *write_f32_raw(u8 *buf, u64 raw, yyjson_write_flag flg) {
8385
#if defined(FLT_DECIMAL_DIG) && FLT_DECIMAL_DIG < F32_DEC_DIG
8386
    int dig = FLT_DECIMAL_DIG;
8387
#else
8388
    int dig = F32_DEC_DIG;
8389
#endif
8390
    f64 val = (f64)f64_to_f32(f64_from_bits(raw));
8391
    int len = snprintf_num(buf, FP_BUF_LEN, "%.*g", dig, val);
8392
    return write_fp_reformat(buf, len, flg, false);
8393
}
8394
8395
/** Write a double number (requires 40 bytes buffer). */
8396
static_noinline u8 *write_f64_raw_fixed(u8 *buf, u64 raw,
8397
                                        yyjson_write_flag flg, u32 prec) {
8398
    f64 val = (f64)f64_from_bits(raw);
8399
    if (-1e21 < val && val < 1e21) {
8400
        int len = snprintf_num(buf, FP_BUF_LEN, "%.*f", (int)prec, val);
8401
        return write_fp_reformat(buf, len, flg, true);
8402
    } else {
8403
        return write_f64_raw(buf, raw, flg);
8404
    }
8405
}
8406
8407
#endif /* FP_WRITER */
8408
8409
/** Write a JSON number (requires 40 bytes buffer). */
8410
87.9M
static_inline u8 *write_num(u8 *cur, yyjson_val *val, yyjson_write_flag flg) {
8411
87.9M
    if (!(val->tag & YYJSON_SUBTYPE_REAL)) {
8412
83.5M
        u64 pos = val->uni.u64;
8413
83.5M
        u64 neg = ~pos + 1;
8414
83.5M
        usize sign = ((val->tag & YYJSON_SUBTYPE_SINT) > 0) & ((i64)pos < 0);
8415
83.5M
        *cur = '-';
8416
83.5M
        return write_u64(sign ? neg : pos, cur + sign);
8417
83.5M
    } else {
8418
4.41M
        u64 raw = val->uni.u64;
8419
4.41M
        u32 val_fmt = (u32)(val->tag >> 32);
8420
4.41M
        u32 all_fmt = flg;
8421
4.41M
        u32 fmt = val_fmt | all_fmt;
8422
4.41M
        if (likely(!(fmt >> (32 - YYJSON_WRITE_FP_FLAG_BITS)))) {
8423
            /* double to shortest */
8424
4.41M
            return write_f64_raw(cur, raw, flg);
8425
4.41M
        } else if (fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS)) {
8426
            /* double to fixed */
8427
0
            u32 val_prec = val_fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS);
8428
0
            u32 all_prec = all_fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS);
8429
0
            u32 prec = val_prec ? val_prec : all_prec;
8430
0
            return write_f64_raw_fixed(cur, raw, flg, prec);
8431
0
        } else {
8432
0
            if (fmt & YYJSON_WRITE_FP_TO_FLOAT) {
8433
                /* float to shortest */
8434
0
                return write_f32_raw(cur, raw, flg);
8435
0
            } else {
8436
                /* double to shortest */
8437
0
                return write_f64_raw(cur, raw, flg);
8438
0
            }
8439
0
        }
8440
4.41M
    }
8441
87.9M
}
8442
8443
0
char *yyjson_write_number(const yyjson_val *val, char *buf) {
8444
0
    if (unlikely(!val || !buf)) return NULL;
8445
0
    switch (val->tag & YYJSON_TAG_MASK) {
8446
0
        case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_UINT: {
8447
0
            buf = (char *)write_u64(val->uni.u64, (u8 *)buf);
8448
0
            *buf = '\0';
8449
0
            return buf;
8450
0
        }
8451
0
        case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_SINT: {
8452
0
            u64 pos = val->uni.u64;
8453
0
            u64 neg = ~pos + 1;
8454
0
            usize sign = ((i64)pos < 0);
8455
0
            *buf = '-';
8456
0
            buf = (char *)write_u64(sign ? neg : pos, (u8 *)buf + sign);
8457
0
            *buf = '\0';
8458
0
            return buf;
8459
0
        }
8460
0
        case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL: {
8461
0
            u64 raw = val->uni.u64;
8462
0
            u32 fmt = (u32)(val->tag >> 32);
8463
0
            u32 flg = YYJSON_WRITE_ALLOW_INF_AND_NAN;
8464
0
            if (likely(!(fmt >> (32 - YYJSON_WRITE_FP_FLAG_BITS)))) {
8465
0
                buf = (char *)write_f64_raw((u8 *)buf, raw, flg);
8466
0
            } else if (fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS)) {
8467
0
                u32 prec = fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS);
8468
0
                buf = (char *)write_f64_raw_fixed((u8 *)buf, raw, flg, prec);
8469
0
            } else {
8470
0
                if (fmt & YYJSON_WRITE_FP_TO_FLOAT) {
8471
0
                    buf = (char *)write_f32_raw((u8 *)buf, raw, flg);
8472
0
                } else {
8473
0
                    buf = (char *)write_f64_raw((u8 *)buf, raw, flg);
8474
0
                }
8475
0
            }
8476
0
            if (buf) *buf = '\0';
8477
0
            return buf;
8478
0
        }
8479
0
        default: return NULL;
8480
0
    }
8481
0
}
8482
8483
8484
8485
/*==============================================================================
8486
 * MARK: - String Writer (Private)
8487
 *============================================================================*/
8488
8489
/** Character encode type, if (type > CHAR_ENC_ERR_1) bytes = type / 2; */
8490
typedef u8 char_enc_type;
8491
38.5M
#define CHAR_ENC_CPY_1  0 /* 1-byte UTF-8, copy. */
8492
863
#define CHAR_ENC_ERR_1  1 /* 1-byte UTF-8, error. */
8493
137M
#define CHAR_ENC_ESC_A  2 /* 1-byte ASCII, escaped as '\x'. */
8494
487M
#define CHAR_ENC_ESC_1  3 /* 1-byte UTF-8, escaped as '\uXXXX'. */
8495
1.26M
#define CHAR_ENC_CPY_2  4 /* 2-byte UTF-8, copy. */
8496
1.35M
#define CHAR_ENC_ESC_2  5 /* 2-byte UTF-8, escaped as '\uXXXX'. */
8497
527k
#define CHAR_ENC_CPY_3  6 /* 3-byte UTF-8, copy. */
8498
12.2k
#define CHAR_ENC_ESC_3  7 /* 3-byte UTF-8, escaped as '\uXXXX'. */
8499
1.51M
#define CHAR_ENC_CPY_4  8 /* 4-byte UTF-8, copy. */
8500
39.4k
#define CHAR_ENC_ESC_4  9 /* 4-byte UTF-8, escaped as '\uXXXX\uXXXX'. */
8501
8502
/** Character encode type table: don't escape unicode, don't escape '/'.
8503
    (generated with misc/make_tables.c) */
8504
static const char_enc_type enc_table_cpy[256] = {
8505
    3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
8506
    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
8507
    0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8508
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8509
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8510
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
8511
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8512
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8513
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8514
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8515
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8516
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8517
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
8518
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
8519
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
8520
    8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1
8521
};
8522
8523
/** Character encode type table: don't escape unicode, escape '/'.
8524
    (generated with misc/make_tables.c) */
8525
static const char_enc_type enc_table_cpy_slash[256] = {
8526
    3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
8527
    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
8528
    0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
8529
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8530
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8531
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
8532
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8533
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8534
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8535
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8536
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8537
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8538
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
8539
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
8540
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
8541
    8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1
8542
};
8543
8544
/** Character encode type table: escape unicode, don't escape '/'.
8545
    (generated with misc/make_tables.c) */
8546
static const char_enc_type enc_table_esc[256] = {
8547
    3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
8548
    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
8549
    0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8550
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8551
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8552
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
8553
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8554
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8555
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8556
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8557
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8558
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8559
    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
8560
    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
8561
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
8562
    9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1
8563
};
8564
8565
/** Character encode type table: escape unicode, escape '/'.
8566
    (generated with misc/make_tables.c) */
8567
static const char_enc_type enc_table_esc_slash[256] = {
8568
    3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
8569
    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
8570
    0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
8571
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8572
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8573
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
8574
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8575
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8576
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8577
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8578
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8579
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8580
    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
8581
    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
8582
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
8583
    9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1
8584
};
8585
8586
/** Escaped hex character table: ["00" "01" "02" ... "FD" "FE" "FF"].
8587
    (generated with misc/make_tables.c) */
8588
yyjson_align(2)
8589
static const u8 esc_hex_char_table[512] = {
8590
    '0', '0', '0', '1', '0', '2', '0', '3',
8591
    '0', '4', '0', '5', '0', '6', '0', '7',
8592
    '0', '8', '0', '9', '0', 'A', '0', 'B',
8593
    '0', 'C', '0', 'D', '0', 'E', '0', 'F',
8594
    '1', '0', '1', '1', '1', '2', '1', '3',
8595
    '1', '4', '1', '5', '1', '6', '1', '7',
8596
    '1', '8', '1', '9', '1', 'A', '1', 'B',
8597
    '1', 'C', '1', 'D', '1', 'E', '1', 'F',
8598
    '2', '0', '2', '1', '2', '2', '2', '3',
8599
    '2', '4', '2', '5', '2', '6', '2', '7',
8600
    '2', '8', '2', '9', '2', 'A', '2', 'B',
8601
    '2', 'C', '2', 'D', '2', 'E', '2', 'F',
8602
    '3', '0', '3', '1', '3', '2', '3', '3',
8603
    '3', '4', '3', '5', '3', '6', '3', '7',
8604
    '3', '8', '3', '9', '3', 'A', '3', 'B',
8605
    '3', 'C', '3', 'D', '3', 'E', '3', 'F',
8606
    '4', '0', '4', '1', '4', '2', '4', '3',
8607
    '4', '4', '4', '5', '4', '6', '4', '7',
8608
    '4', '8', '4', '9', '4', 'A', '4', 'B',
8609
    '4', 'C', '4', 'D', '4', 'E', '4', 'F',
8610
    '5', '0', '5', '1', '5', '2', '5', '3',
8611
    '5', '4', '5', '5', '5', '6', '5', '7',
8612
    '5', '8', '5', '9', '5', 'A', '5', 'B',
8613
    '5', 'C', '5', 'D', '5', 'E', '5', 'F',
8614
    '6', '0', '6', '1', '6', '2', '6', '3',
8615
    '6', '4', '6', '5', '6', '6', '6', '7',
8616
    '6', '8', '6', '9', '6', 'A', '6', 'B',
8617
    '6', 'C', '6', 'D', '6', 'E', '6', 'F',
8618
    '7', '0', '7', '1', '7', '2', '7', '3',
8619
    '7', '4', '7', '5', '7', '6', '7', '7',
8620
    '7', '8', '7', '9', '7', 'A', '7', 'B',
8621
    '7', 'C', '7', 'D', '7', 'E', '7', 'F',
8622
    '8', '0', '8', '1', '8', '2', '8', '3',
8623
    '8', '4', '8', '5', '8', '6', '8', '7',
8624
    '8', '8', '8', '9', '8', 'A', '8', 'B',
8625
    '8', 'C', '8', 'D', '8', 'E', '8', 'F',
8626
    '9', '0', '9', '1', '9', '2', '9', '3',
8627
    '9', '4', '9', '5', '9', '6', '9', '7',
8628
    '9', '8', '9', '9', '9', 'A', '9', 'B',
8629
    '9', 'C', '9', 'D', '9', 'E', '9', 'F',
8630
    'A', '0', 'A', '1', 'A', '2', 'A', '3',
8631
    'A', '4', 'A', '5', 'A', '6', 'A', '7',
8632
    'A', '8', 'A', '9', 'A', 'A', 'A', 'B',
8633
    'A', 'C', 'A', 'D', 'A', 'E', 'A', 'F',
8634
    'B', '0', 'B', '1', 'B', '2', 'B', '3',
8635
    'B', '4', 'B', '5', 'B', '6', 'B', '7',
8636
    'B', '8', 'B', '9', 'B', 'A', 'B', 'B',
8637
    'B', 'C', 'B', 'D', 'B', 'E', 'B', 'F',
8638
    'C', '0', 'C', '1', 'C', '2', 'C', '3',
8639
    'C', '4', 'C', '5', 'C', '6', 'C', '7',
8640
    'C', '8', 'C', '9', 'C', 'A', 'C', 'B',
8641
    'C', 'C', 'C', 'D', 'C', 'E', 'C', 'F',
8642
    'D', '0', 'D', '1', 'D', '2', 'D', '3',
8643
    'D', '4', 'D', '5', 'D', '6', 'D', '7',
8644
    'D', '8', 'D', '9', 'D', 'A', 'D', 'B',
8645
    'D', 'C', 'D', 'D', 'D', 'E', 'D', 'F',
8646
    'E', '0', 'E', '1', 'E', '2', 'E', '3',
8647
    'E', '4', 'E', '5', 'E', '6', 'E', '7',
8648
    'E', '8', 'E', '9', 'E', 'A', 'E', 'B',
8649
    'E', 'C', 'E', 'D', 'E', 'E', 'E', 'F',
8650
    'F', '0', 'F', '1', 'F', '2', 'F', '3',
8651
    'F', '4', 'F', '5', 'F', '6', 'F', '7',
8652
    'F', '8', 'F', '9', 'F', 'A', 'F', 'B',
8653
    'F', 'C', 'F', 'D', 'F', 'E', 'F', 'F'
8654
};
8655
8656
/** Lowercase variant of esc_hex_char_table. */
8657
yyjson_align(2)
8658
static const u8 esc_hex_char_table_lower[512] = {
8659
    '0', '0', '0', '1', '0', '2', '0', '3',
8660
    '0', '4', '0', '5', '0', '6', '0', '7',
8661
    '0', '8', '0', '9', '0', 'a', '0', 'b',
8662
    '0', 'c', '0', 'd', '0', 'e', '0', 'f',
8663
    '1', '0', '1', '1', '1', '2', '1', '3',
8664
    '1', '4', '1', '5', '1', '6', '1', '7',
8665
    '1', '8', '1', '9', '1', 'a', '1', 'b',
8666
    '1', 'c', '1', 'd', '1', 'e', '1', 'f',
8667
    '2', '0', '2', '1', '2', '2', '2', '3',
8668
    '2', '4', '2', '5', '2', '6', '2', '7',
8669
    '2', '8', '2', '9', '2', 'a', '2', 'b',
8670
    '2', 'c', '2', 'd', '2', 'e', '2', 'f',
8671
    '3', '0', '3', '1', '3', '2', '3', '3',
8672
    '3', '4', '3', '5', '3', '6', '3', '7',
8673
    '3', '8', '3', '9', '3', 'a', '3', 'b',
8674
    '3', 'c', '3', 'd', '3', 'e', '3', 'f',
8675
    '4', '0', '4', '1', '4', '2', '4', '3',
8676
    '4', '4', '4', '5', '4', '6', '4', '7',
8677
    '4', '8', '4', '9', '4', 'a', '4', 'b',
8678
    '4', 'c', '4', 'd', '4', 'e', '4', 'f',
8679
    '5', '0', '5', '1', '5', '2', '5', '3',
8680
    '5', '4', '5', '5', '5', '6', '5', '7',
8681
    '5', '8', '5', '9', '5', 'a', '5', 'b',
8682
    '5', 'c', '5', 'd', '5', 'e', '5', 'f',
8683
    '6', '0', '6', '1', '6', '2', '6', '3',
8684
    '6', '4', '6', '5', '6', '6', '6', '7',
8685
    '6', '8', '6', '9', '6', 'a', '6', 'b',
8686
    '6', 'c', '6', 'd', '6', 'e', '6', 'f',
8687
    '7', '0', '7', '1', '7', '2', '7', '3',
8688
    '7', '4', '7', '5', '7', '6', '7', '7',
8689
    '7', '8', '7', '9', '7', 'a', '7', 'b',
8690
    '7', 'c', '7', 'd', '7', 'e', '7', 'f',
8691
    '8', '0', '8', '1', '8', '2', '8', '3',
8692
    '8', '4', '8', '5', '8', '6', '8', '7',
8693
    '8', '8', '8', '9', '8', 'a', '8', 'b',
8694
    '8', 'c', '8', 'd', '8', 'e', '8', 'f',
8695
    '9', '0', '9', '1', '9', '2', '9', '3',
8696
    '9', '4', '9', '5', '9', '6', '9', '7',
8697
    '9', '8', '9', '9', '9', 'a', '9', 'b',
8698
    '9', 'c', '9', 'd', '9', 'e', '9', 'f',
8699
    'a', '0', 'a', '1', 'a', '2', 'a', '3',
8700
    'a', '4', 'a', '5', 'a', '6', 'a', '7',
8701
    'a', '8', 'a', '9', 'a', 'a', 'a', 'b',
8702
    'a', 'c', 'a', 'd', 'a', 'e', 'a', 'f',
8703
    'b', '0', 'b', '1', 'b', '2', 'b', '3',
8704
    'b', '4', 'b', '5', 'b', '6', 'b', '7',
8705
    'b', '8', 'b', '9', 'b', 'a', 'b', 'b',
8706
    'b', 'c', 'b', 'd', 'b', 'e', 'b', 'f',
8707
    'c', '0', 'c', '1', 'c', '2', 'c', '3',
8708
    'c', '4', 'c', '5', 'c', '6', 'c', '7',
8709
    'c', '8', 'c', '9', 'c', 'a', 'c', 'b',
8710
    'c', 'c', 'c', 'd', 'c', 'e', 'c', 'f',
8711
    'd', '0', 'd', '1', 'd', '2', 'd', '3',
8712
    'd', '4', 'd', '5', 'd', '6', 'd', '7',
8713
    'd', '8', 'd', '9', 'd', 'a', 'd', 'b',
8714
    'd', 'c', 'd', 'd', 'd', 'e', 'd', 'f',
8715
    'e', '0', 'e', '1', 'e', '2', 'e', '3',
8716
    'e', '4', 'e', '5', 'e', '6', 'e', '7',
8717
    'e', '8', 'e', '9', 'e', 'a', 'e', 'b',
8718
    'e', 'c', 'e', 'd', 'e', 'e', 'e', 'f',
8719
    'f', '0', 'f', '1', 'f', '2', 'f', '3',
8720
    'f', '4', 'f', '5', 'f', '6', 'f', '7',
8721
    'f', '8', 'f', '9', 'f', 'a', 'f', 'b',
8722
    'f', 'c', 'f', 'd', 'f', 'e', 'f', 'f'
8723
};
8724
8725
/** Escaped single character table. (generated with misc/make_tables.c) */
8726
yyjson_align(2)
8727
static const u8 esc_single_char_table[512] = {
8728
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8729
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8730
    '\\', 'b', '\\', 't', '\\', 'n', ' ', ' ',
8731
    '\\', 'f', '\\', 'r', ' ', ' ', ' ', ' ',
8732
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8733
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8734
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8735
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8736
    ' ', ' ', ' ', ' ', '\\', '"', ' ', ' ',
8737
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8738
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8739
    ' ', ' ', ' ', ' ', ' ', ' ', '\\', '/',
8740
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8741
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8742
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8743
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8744
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8745
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8746
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8747
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8748
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8749
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8750
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8751
    '\\', '\\', ' ', ' ', ' ', ' ', ' ', ' ',
8752
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8753
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8754
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8755
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8756
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8757
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8758
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8759
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8760
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8761
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8762
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8763
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8764
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8765
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8766
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8767
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8768
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8769
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8770
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8771
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8772
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8773
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8774
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8775
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8776
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8777
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8778
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8779
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8780
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8781
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8782
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8783
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8784
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8785
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8786
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8787
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8788
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8789
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8790
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8791
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
8792
};
8793
8794
/** Returns the hex digit table to use for \uXXXX escapes. */
8795
38.3k
static_inline const u8 *get_hex_table_with_flag(yyjson_write_flag flg) {
8796
38.3k
    return has_flg(LOWERCASE_HEX)
8797
38.3k
        ? esc_hex_char_table_lower
8798
38.3k
        : esc_hex_char_table;
8799
38.3k
}
8800
8801
/** Returns the encode table with options. */
8802
static_inline const char_enc_type *get_enc_table_with_flag(
8803
38.3k
    yyjson_write_flag flg) {
8804
38.3k
    if (has_flg(ESCAPE_UNICODE)) {
8805
12.4k
        if (has_flg(ESCAPE_SLASHES)) {
8806
12.4k
            return enc_table_esc_slash;
8807
12.4k
        } else {
8808
0
            return enc_table_esc;
8809
0
        }
8810
25.9k
    } else {
8811
25.9k
        if (has_flg(ESCAPE_SLASHES)) {
8812
0
            return enc_table_cpy_slash;
8813
25.9k
        } else {
8814
25.9k
            return enc_table_cpy;
8815
25.9k
        }
8816
25.9k
    }
8817
38.3k
}
8818
8819
/** Write raw string. */
8820
0
static_inline u8 *write_raw(u8 *cur, const u8 *raw, usize raw_len) {
8821
0
    memcpy(cur, raw, raw_len);
8822
0
    return cur + raw_len;
8823
0
}
8824
8825
/**
8826
 Write string no-escape.
8827
 @param cur Buffer cursor.
8828
 @param str A UTF-8 string, null-terminator is not required.
8829
 @param str_len Length of string in bytes.
8830
 @return The buffer cursor after string.
8831
 */
8832
21.7M
static_inline u8 *write_str_noesc(u8 *cur, const u8 *str, usize str_len) {
8833
21.7M
    *cur++ = '"';
8834
43.9M
    while (str_len >= 16) {
8835
22.1M
        byte_copy_16(cur, str);
8836
22.1M
        cur += 16;
8837
22.1M
        str += 16;
8838
22.1M
        str_len -= 16;
8839
22.1M
    }
8840
33.5M
    while (str_len >= 4) {
8841
11.7M
        byte_copy_4(cur, str);
8842
11.7M
        cur += 4;
8843
11.7M
        str += 4;
8844
11.7M
        str_len -= 4;
8845
11.7M
    }
8846
49.3M
    while (str_len) {
8847
27.5M
        *cur++ = *str++;
8848
27.5M
        str_len -= 1;
8849
27.5M
    }
8850
21.7M
    *cur++ = '"';
8851
21.7M
    return cur;
8852
21.7M
}
8853
8854
/**
8855
 Write UTF-8 string (requires len * 6 + 2 bytes buffer).
8856
 @param cur Buffer cursor.
8857
 @param esc Escape unicode.
8858
 @param inv Allow invalid unicode.
8859
 @param str A UTF-8 string, null-terminator is not required.
8860
 @param str_len Length of string in bytes.
8861
 @param enc_table Encode type table for character.
8862
 @return The buffer cursor after string, or NULL on invalid unicode.
8863
 */
8864
static_inline u8 *write_str(u8 *cur, bool esc, bool inv,
8865
                            const u8 *str, usize str_len,
8866
                            const char_enc_type *enc_table,
8867
28.6M
                            const u8 *hex_table) {
8868
    /* The replacement character U+FFFD, used to indicate invalid character.
8869
       Looked up via hex_table so that LOWERCASE_HEX produces "fffd" while
8870
       the default produces "FFFD". */
8871
28.6M
    const v32 pre = {{ '\\', 'u', '0', '0' }};
8872
8873
28.6M
    const u8 *src = str;
8874
28.6M
    const u8 *end = str + str_len;
8875
28.6M
    *cur++ = '"';
8876
8877
67.1M
copy_ascii:
8878
    /*
8879
     Copy continuous ASCII, loop unrolling, same as the following code:
8880
8881
         while (end > src) (
8882
            if (unlikely(enc_table[*src])) break;
8883
            *cur++ = *src++;
8884
         );
8885
     */
8886
67.1M
#define expr_jump(i) \
8887
289M
    if (unlikely(enc_table[src[i]])) goto stop_char_##i;
8888
8889
67.1M
#define expr_stop(i) \
8890
67.1M
    stop_char_##i: \
8891
41.1M
    memcpy(cur, src, i); \
8892
41.1M
    cur += i; src += i; goto copy_utf8;
8893
8894
75.4M
    while (end - src >= 16) {
8895
219M
        repeat16_incr(expr_jump)
8896
8.28M
        byte_copy_16(cur, src);
8897
8.28M
        cur += 16; src += 16;
8898
8.28M
    }
8899
8900
52.7M
    while (end - src >= 4) {
8901
43.0M
        repeat4_incr(expr_jump)
8902
6.29M
        byte_copy_4(cur, src);
8903
6.29M
        cur += 4; src += 4;
8904
6.29M
    }
8905
8906
53.2M
    while (end > src) {
8907
27.1M
        expr_jump(0)
8908
21.7M
        *cur++ = *src++;
8909
21.7M
    }
8910
8911
26.0M
    *cur++ = '"';
8912
26.0M
    return cur;
8913
8914
41.1M
    repeat16_incr(expr_stop)
8915
8916
0
#undef expr_jump
8917
0
#undef expr_stop
8918
8919
670M
copy_utf8:
8920
670M
    if (unlikely(src + 4 > end)) {
8921
46.9M
        if (end == src) goto copy_end;
8922
44.3M
        if (end - src < enc_table[*src] / 2) goto err_one;
8923
44.3M
    }
8924
668M
    switch (enc_table[*src]) {
8925
38.5M
        case CHAR_ENC_CPY_1: {
8926
38.5M
            *cur++ = *src++;
8927
38.5M
            goto copy_ascii;
8928
0
        }
8929
1.26M
        case CHAR_ENC_CPY_2: {
8930
#if YYJSON_DISABLE_UTF8_VALIDATION
8931
            byte_copy_2(cur, src);
8932
#else
8933
1.26M
            u32 uni = 0;
8934
1.26M
            byte_copy_2(&uni, src);
8935
1.26M
            if (unlikely(!is_utf8_seq2(uni))) goto err_cpy;
8936
1.26M
            byte_copy_2(cur, &uni);
8937
1.26M
#endif
8938
1.26M
            cur += 2;
8939
1.26M
            src += 2;
8940
1.26M
            goto copy_utf8;
8941
1.26M
        }
8942
527k
        case CHAR_ENC_CPY_3: {
8943
#if YYJSON_DISABLE_UTF8_VALIDATION
8944
            if (likely(src + 4 <= end)) {
8945
                byte_copy_4(cur, src);
8946
            } else {
8947
                byte_copy_2(cur, src);
8948
                cur[2] = src[2];
8949
            }
8950
#else
8951
527k
            u32 uni, tmp;
8952
527k
            if (likely(src + 4 <= end)) {
8953
526k
                uni = byte_load_4(src);
8954
526k
                if (unlikely(!is_utf8_seq3(uni))) goto err_cpy;
8955
526k
                byte_copy_4(cur, src);
8956
526k
            } else {
8957
1.37k
                uni = byte_load_3(src);
8958
1.37k
                if (unlikely(!is_utf8_seq3(uni))) goto err_cpy;
8959
1.23k
                byte_copy_4(cur, &uni);
8960
1.23k
            }
8961
527k
#endif
8962
527k
            cur += 3;
8963
527k
            src += 3;
8964
527k
            goto copy_utf8;
8965
527k
        }
8966
1.51M
        case CHAR_ENC_CPY_4: {
8967
#if YYJSON_DISABLE_UTF8_VALIDATION
8968
            byte_copy_4(cur, src);
8969
#else
8970
1.51M
            u32 uni, tmp;
8971
1.51M
            uni = byte_load_4(src);
8972
1.51M
            if (unlikely(!is_utf8_seq4(uni))) goto err_cpy;
8973
1.51M
            byte_copy_4(cur, src);
8974
1.51M
#endif
8975
1.51M
            cur += 4;
8976
1.51M
            src += 4;
8977
1.51M
            goto copy_utf8;
8978
1.51M
        }
8979
137M
        case CHAR_ENC_ESC_A: {
8980
137M
            byte_copy_2(cur, &esc_single_char_table[*src * 2]);
8981
137M
            cur += 2;
8982
137M
            src += 1;
8983
137M
            goto copy_utf8;
8984
1.51M
        }
8985
487M
        case CHAR_ENC_ESC_1: {
8986
487M
            byte_copy_4(cur + 0, &pre);
8987
487M
            byte_copy_2(cur + 4, &hex_table[*src * 2]);
8988
487M
            cur += 6;
8989
487M
            src += 1;
8990
487M
            goto copy_utf8;
8991
1.51M
        }
8992
1.35M
        case CHAR_ENC_ESC_2: {
8993
1.35M
            u16 u;
8994
1.35M
#if !YYJSON_DISABLE_UTF8_VALIDATION
8995
1.35M
            u32 v4 = 0;
8996
1.35M
            u16 v2 = byte_load_2(src);
8997
1.35M
            byte_copy_2(&v4, &v2);
8998
1.35M
            if (unlikely(!is_utf8_seq2(v4))) goto err_esc;
8999
1.35M
#endif
9000
1.35M
            u = (u16)(((u16)(src[0] & 0x1F) << 6) |
9001
1.35M
                      ((u16)(src[1] & 0x3F) << 0));
9002
1.35M
            byte_copy_2(cur + 0, &pre);
9003
1.35M
            byte_copy_2(cur + 2, &hex_table[(u >> 8) * 2]);
9004
1.35M
            byte_copy_2(cur + 4, &hex_table[(u & 0xFF) * 2]);
9005
1.35M
            cur += 6;
9006
1.35M
            src += 2;
9007
1.35M
            goto copy_utf8;
9008
1.35M
        }
9009
12.2k
        case CHAR_ENC_ESC_3: {
9010
12.2k
            u16 u;
9011
12.2k
            u32 v, tmp;
9012
12.2k
#if !YYJSON_DISABLE_UTF8_VALIDATION
9013
12.2k
            v = byte_load_3(src);
9014
12.2k
            if (unlikely(!is_utf8_seq3(v))) goto err_esc;
9015
12.2k
#endif
9016
12.2k
            u = (u16)(((u16)(src[0] & 0x0F) << 12) |
9017
12.2k
                      ((u16)(src[1] & 0x3F) << 6) |
9018
12.2k
                      ((u16)(src[2] & 0x3F) << 0));
9019
12.2k
            byte_copy_2(cur + 0, &pre);
9020
12.2k
            byte_copy_2(cur + 2, &hex_table[(u >> 8) * 2]);
9021
12.2k
            byte_copy_2(cur + 4, &hex_table[(u & 0xFF) * 2]);
9022
12.2k
            cur += 6;
9023
12.2k
            src += 3;
9024
12.2k
            goto copy_utf8;
9025
12.2k
        }
9026
39.4k
        case CHAR_ENC_ESC_4: {
9027
39.4k
            u32 hi, lo, u, v, tmp;
9028
39.4k
#if !YYJSON_DISABLE_UTF8_VALIDATION
9029
39.4k
            v = byte_load_4(src);
9030
39.4k
            if (unlikely(!is_utf8_seq4(v))) goto err_esc;
9031
39.4k
#endif
9032
39.4k
            u = ((u32)(src[0] & 0x07) << 18) |
9033
39.4k
                ((u32)(src[1] & 0x3F) << 12) |
9034
39.4k
                ((u32)(src[2] & 0x3F) << 6) |
9035
39.4k
                ((u32)(src[3] & 0x3F) << 0);
9036
39.4k
            u -= 0x10000;
9037
39.4k
            hi = (u >> 10) + 0xD800;
9038
39.4k
            lo = (u & 0x3FF) + 0xDC00;
9039
39.4k
            byte_copy_2(cur + 0, &pre);
9040
39.4k
            byte_copy_2(cur + 2, &hex_table[(hi >> 8) * 2]);
9041
39.4k
            byte_copy_2(cur + 4, &hex_table[(hi & 0xFF) * 2]);
9042
39.4k
            byte_copy_2(cur + 6, &pre);
9043
39.4k
            byte_copy_2(cur + 8, &hex_table[(lo >> 8) * 2]);
9044
39.4k
            byte_copy_2(cur + 10, &hex_table[(lo & 0xFF) * 2]);
9045
39.4k
            cur += 12;
9046
39.4k
            src += 4;
9047
39.4k
            goto copy_utf8;
9048
39.4k
        }
9049
863
        case CHAR_ENC_ERR_1: {
9050
863
            goto err_one;
9051
39.4k
        }
9052
0
        default: break; /* unreachable */
9053
668M
    }
9054
9055
2.59M
copy_end:
9056
2.59M
    *cur++ = '"';
9057
2.59M
    return cur;
9058
9059
942
err_one:
9060
942
    if (esc) goto err_esc;
9061
942
    else goto err_cpy;
9062
9063
1.63k
err_cpy:
9064
1.63k
    if (!inv) return NULL;
9065
0
    *cur++ = *src++;
9066
0
    goto copy_utf8;
9067
9068
0
err_esc:
9069
0
    if (!inv) return NULL;
9070
0
    byte_copy_2(cur + 0, &pre);
9071
    /* U+FFFD = 0xFFFD, written as two pairs from hex_table so that
9072
       LOWERCASE_HEX produces "fffd". Replaces a single byte_copy_4
9073
       from a hardcoded uppercase "FFFD" v32; same total output, one
9074
       extra load on the (rare) invalid-UTF-8-with-ALLOW path. */
9075
0
    byte_copy_2(cur + 2, &hex_table[0xFF * 2]);
9076
0
    byte_copy_2(cur + 4, &hex_table[0xFD * 2]);
9077
0
    cur += 6;
9078
0
    src += 1;
9079
0
    goto copy_utf8;
9080
0
}
9081
9082
9083
9084
/*==============================================================================
9085
 * MARK: - JSON Writer Utilities (Private)
9086
 *============================================================================*/
9087
9088
/** Write null (requires 8 bytes buffer). */
9089
263k
static_inline u8 *write_null(u8 *cur) {
9090
263k
    v64 v = {{ 'n', 'u', 'l', 'l', ',', '\n', 0, 0 }};
9091
263k
    byte_copy_8(cur, &v);
9092
263k
    return cur + 4;
9093
263k
}
9094
9095
/** Write bool (requires 8 bytes buffer). */
9096
407k
static_inline u8 *write_bool(u8 *cur, bool val) {
9097
407k
    v64 v0 = {{ 'f', 'a', 'l', 's', 'e', ',', '\n', 0 }};
9098
407k
    v64 v1 = {{ 't', 'r', 'u', 'e', ',', '\n', 0, 0 }};
9099
407k
    if (val) {
9100
334k
        byte_copy_8(cur, &v1);
9101
334k
    } else {
9102
73.2k
        byte_copy_8(cur, &v0);
9103
73.2k
    }
9104
407k
    return cur + 5 - val;
9105
407k
}
9106
9107
/** Write indent (requires level x 4 bytes buffer).
9108
    Param spaces should not larger than 4. */
9109
7.21M
static_inline u8 *write_indent(u8 *cur, usize level, usize spaces) {
9110
7.38G
    while (level-- > 0) {
9111
7.37G
        byte_copy_4(cur, "    ");
9112
7.37G
        cur += spaces;
9113
7.37G
    }
9114
7.21M
    return cur;
9115
7.21M
}
9116
9117
#if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE
9118
9119
/** Write data to file pointer. */
9120
static bool write_dat_to_fp(FILE *fp, u8 *dat, usize len,
9121
0
                            yyjson_write_err *err) {
9122
0
    if (fwrite(dat, 1, len, fp) != len) {
9123
0
        err->msg = "file writing failed";
9124
0
        err->code = YYJSON_WRITE_ERROR_FILE_WRITE;
9125
0
        return false;
9126
0
    }
9127
0
    return true;
9128
0
}
9129
9130
/** Write data to file. */
9131
static bool write_dat_to_file(const char *path, u8 *dat, usize len,
9132
0
                              yyjson_write_err *err) {
9133
0
#define return_err(_code, _msg) do { \
9134
0
    err->msg = _msg; \
9135
0
    err->code = YYJSON_WRITE_ERROR_##_code; \
9136
0
    if (file) fclose(file); \
9137
0
    return false; \
9138
0
} while (false)
9139
9140
0
    FILE *file = fopen_writeonly(path);
9141
0
    if (file == NULL) {
9142
0
        return_err(FILE_OPEN, MSG_FOPEN);
9143
0
    }
9144
0
    if (fwrite(dat, 1, len, file) != len) {
9145
0
        return_err(FILE_WRITE, MSG_FWRITE);
9146
0
    }
9147
0
    if (fclose(file) != 0) {
9148
0
        file = NULL;
9149
0
        return_err(FILE_WRITE, MSG_FCLOSE);
9150
0
    }
9151
0
    return true;
9152
9153
0
#undef return_err
9154
0
}
9155
9156
#endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */
9157
9158
9159
9160
/*==============================================================================
9161
 * MARK: - JSON Writer Implementation (Private)
9162
 *============================================================================*/
9163
9164
typedef struct yyjson_write_ctx {
9165
    usize tag;
9166
} yyjson_write_ctx;
9167
9168
static_inline void yyjson_write_ctx_set(yyjson_write_ctx *ctx,
9169
534k
                                        usize size, bool is_obj) {
9170
534k
    ctx->tag = (size << 1) | (usize)is_obj;
9171
534k
}
9172
9173
static_inline void yyjson_write_ctx_get(yyjson_write_ctx *ctx,
9174
184k
                                        usize *size, bool *is_obj) {
9175
184k
    usize tag = ctx->tag;
9176
184k
    *size = tag >> 1;
9177
184k
    *is_obj = (bool)(tag & 1);
9178
184k
}
9179
9180
/** Write single JSON value. */
9181
static_inline u8 *write_root_single(yyjson_val *val,
9182
                                    yyjson_write_flag flg,
9183
                                    yyjson_alc alc,
9184
                                    char *buf, usize *dat_len,
9185
22.1k
                                    yyjson_write_err *err) {
9186
22.1k
#define return_err(_code, _msg) do { \
9187
502
    if (hdr) alc.free(alc.ctx, (void *)hdr); \
9188
502
    *dat_len = 0; \
9189
502
    err->code = YYJSON_WRITE_ERROR_##_code; \
9190
502
    err->msg = _msg; \
9191
502
    return NULL; \
9192
502
} while (false)
9193
9194
22.1k
#define incr_len(_len) do { \
9195
22.1k
    if (buf) hdr = *dat_len >= _len ? (u8 *)buf : (u8 *)NULL; \
9196
22.1k
    else hdr = (u8 *)alc.malloc(alc.ctx, _len); \
9197
22.1k
    if (!hdr) goto fail_alloc; \
9198
22.1k
    cur = hdr; \
9199
22.1k
} while (false)
9200
9201
22.1k
#define check_str_len(_len) do { \
9202
2.59k
    if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
9203
2.59k
        goto fail_alloc; \
9204
2.59k
} while (false)
9205
9206
22.1k
    u8 *hdr = NULL, *cur;
9207
22.1k
    usize str_len;
9208
22.1k
    const u8 *str_ptr;
9209
22.1k
    const char_enc_type *enc_table = get_enc_table_with_flag(flg);
9210
22.1k
    const u8 *hex_table = get_hex_table_with_flag(flg);
9211
22.1k
    bool cpy = (enc_table == enc_table_cpy);
9212
22.1k
    bool esc = has_flg(ESCAPE_UNICODE) != 0;
9213
22.1k
    bool inv = has_allow(INVALID_UNICODE) != 0;
9214
22.1k
    bool newline = has_flg(NEWLINE_AT_END) != 0;
9215
22.1k
    const usize end_len = 2; /* '\n' and '\0' */
9216
9217
22.1k
    switch (unsafe_yyjson_get_type(val)) {
9218
0
        case YYJSON_TYPE_RAW:
9219
0
            str_len = unsafe_yyjson_get_len(val);
9220
0
            str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9221
0
            check_str_len(str_len);
9222
0
            incr_len(str_len + end_len);
9223
0
            cur = write_raw(cur, str_ptr, str_len);
9224
0
            break;
9225
9226
2.59k
        case YYJSON_TYPE_STR:
9227
2.59k
            str_len = unsafe_yyjson_get_len(val);
9228
2.59k
            str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9229
2.59k
            check_str_len(str_len);
9230
2.59k
            incr_len(str_len * 6 + 2 + end_len);
9231
2.59k
            if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
9232
318
                cur = write_str_noesc(cur, str_ptr, str_len);
9233
2.27k
            } else {
9234
2.27k
                cur = write_str(cur, esc, inv, str_ptr, str_len,
9235
2.27k
                                enc_table, hex_table);
9236
2.27k
                if (unlikely(!cur)) goto fail_str;
9237
2.27k
            }
9238
2.09k
            break;
9239
9240
19.3k
        case YYJSON_TYPE_NUM:
9241
19.3k
            incr_len(FP_BUF_LEN + end_len);
9242
19.3k
            cur = write_num(cur, val, flg);
9243
19.3k
            if (unlikely(!cur)) goto fail_num;
9244
19.3k
            break;
9245
9246
19.3k
        case YYJSON_TYPE_BOOL:
9247
22
            incr_len(8);
9248
22
            cur = write_bool(cur, unsafe_yyjson_get_bool(val));
9249
22
            break;
9250
9251
12
        case YYJSON_TYPE_NULL:
9252
12
            incr_len(8);
9253
12
            cur = write_null(cur);
9254
12
            break;
9255
9256
108
        case YYJSON_TYPE_ARR:
9257
108
            incr_len(2 + end_len);
9258
108
            byte_copy_2(cur, "[]");
9259
108
            cur += 2;
9260
108
            break;
9261
9262
56
        case YYJSON_TYPE_OBJ:
9263
56
            incr_len(2 + end_len);
9264
56
            byte_copy_2(cur, "{}");
9265
56
            cur += 2;
9266
56
            break;
9267
9268
0
        default:
9269
0
            goto fail_type;
9270
22.1k
    }
9271
9272
21.6k
    if (newline) *cur++ = '\n';
9273
21.6k
    *cur = '\0';
9274
21.6k
    *dat_len = (usize)(cur - hdr);
9275
21.6k
    memset(err, 0, sizeof(yyjson_write_err));
9276
21.6k
    return hdr;
9277
9278
0
fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
9279
0
fail_type:  return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
9280
0
fail_num:   return_err(NAN_OR_INF, MSG_NAN_INF);
9281
502
fail_str:   return_err(INVALID_STRING, MSG_ERR_UTF8);
9282
9283
502
#undef return_err
9284
502
#undef check_str_len
9285
502
#undef incr_len
9286
502
}
9287
9288
/** Write JSON document minify.
9289
    The root of this document should be a non-empty container. */
9290
static_inline u8 *write_root_minify(const yyjson_val *root,
9291
                                    const yyjson_write_flag flg,
9292
                                    const yyjson_alc alc,
9293
                                    char *buf, usize *dat_len,
9294
2.00k
                                    yyjson_write_err *err) {
9295
2.00k
#define return_err(_code, _msg) do { \
9296
0
    *dat_len = 0; \
9297
0
    err->code = YYJSON_WRITE_ERROR_##_code; \
9298
0
    err->msg = _msg; \
9299
0
    if (hdr) alc.free(alc.ctx, hdr); \
9300
0
    return NULL; \
9301
0
} while (false)
9302
9303
72.1k
#define incr_len(_len) do { \
9304
72.1k
    ext_len = (usize)(_len); \
9305
72.1k
    if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
9306
464
        usize ctx_pos = (usize)((u8 *)ctx - hdr); \
9307
464
        usize cur_pos = (usize)(cur - hdr); \
9308
464
        yyjson_assume((u8 *)ctx <= (u8 *)end); \
9309
464
        ctx_len = (usize)((u8 *)end - (u8 *)ctx); \
9310
464
        alc_inc = yyjson_max(alc_len / 2, ext_len); \
9311
464
        alc_inc = size_align_up(alc_inc, sizeof(yyjson_write_ctx)); \
9312
464
        if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
9313
464
            goto fail_alloc; \
9314
464
        alc_len += alc_inc; \
9315
464
        tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
9316
464
        if (unlikely(!tmp)) goto fail_alloc; \
9317
464
        ctx_tmp = (yyjson_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
9318
464
        memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
9319
464
        ctx = ctx_tmp; \
9320
464
        cur = tmp + cur_pos; \
9321
464
        end = tmp + alc_len; \
9322
464
        hdr = tmp; \
9323
464
    } \
9324
72.1k
} while (false)
9325
9326
25.0k
#define check_str_len(_len) do { \
9327
25.0k
    if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
9328
25.0k
        goto fail_alloc; \
9329
25.0k
} while (false)
9330
9331
2.00k
    yyjson_val *val;
9332
2.00k
    yyjson_type val_type;
9333
2.00k
    usize ctn_len, ctn_len_tmp;
9334
2.00k
    bool ctn_obj, ctn_obj_tmp, is_key;
9335
2.00k
    u8 *hdr, *cur, *end, *tmp;
9336
2.00k
    yyjson_write_ctx *ctx, *ctx_tmp;
9337
2.00k
    usize alc_len, alc_inc, ctx_len, ext_len, str_len;
9338
2.00k
    const u8 *str_ptr;
9339
2.00k
    const char_enc_type *enc_table = get_enc_table_with_flag(flg);
9340
2.00k
    const u8 *hex_table = get_hex_table_with_flag(flg);
9341
2.00k
    bool cpy = (enc_table == enc_table_cpy);
9342
2.00k
    bool esc = has_flg(ESCAPE_UNICODE) != 0;
9343
2.00k
    bool inv = has_allow(INVALID_UNICODE) != 0;
9344
2.00k
    bool newline = has_flg(NEWLINE_AT_END) != 0;
9345
9346
2.00k
    if (buf) {
9347
0
        hdr = (u8 *)buf;
9348
0
        alc_len = *dat_len;
9349
0
        alc_len = size_align_down(alc_len, sizeof(yyjson_write_ctx));
9350
0
        if (alc_len <= sizeof(yyjson_write_ctx)) goto fail_alloc;
9351
2.00k
    } else {
9352
2.00k
        alc_len = root->uni.ofs / sizeof(yyjson_val);
9353
2.00k
        alc_len = alc_len * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64;
9354
2.00k
        alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx));
9355
2.00k
        hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
9356
2.00k
        if (!hdr) goto fail_alloc;
9357
2.00k
    }
9358
2.00k
    cur = hdr;
9359
2.00k
    end = hdr + alc_len;
9360
2.00k
    ctx = (yyjson_write_ctx *)(void *)end;
9361
9362
2.00k
doc_begin:
9363
2.00k
    val = constcast(yyjson_val *)root;
9364
2.00k
    val_type = unsafe_yyjson_get_type(val);
9365
2.00k
    ctn_obj = (val_type == YYJSON_TYPE_OBJ);
9366
2.00k
    ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
9367
2.00k
    *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9368
2.00k
    val++;
9369
9370
72.1k
val_begin:
9371
72.1k
    val_type = unsafe_yyjson_get_type(val);
9372
72.1k
    if (val_type == YYJSON_TYPE_STR) {
9373
25.0k
        is_key = ((u8)ctn_obj & (u8)~ctn_len);
9374
25.0k
        str_len = unsafe_yyjson_get_len(val);
9375
25.0k
        str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9376
25.0k
        check_str_len(str_len);
9377
25.0k
        incr_len(str_len * 6 + 16);
9378
25.0k
        if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
9379
13.6k
            cur = write_str_noesc(cur, str_ptr, str_len);
9380
13.6k
        } else {
9381
11.3k
            cur = write_str(cur, esc, inv, str_ptr, str_len,
9382
11.3k
                            enc_table, hex_table);
9383
11.3k
            if (unlikely(!cur)) goto fail_str;
9384
11.3k
        }
9385
25.0k
        *cur++ = is_key ? ':' : ',';
9386
25.0k
        goto val_end;
9387
25.0k
    }
9388
47.1k
    if (val_type == YYJSON_TYPE_NUM) {
9389
37.4k
        incr_len(FP_BUF_LEN);
9390
37.4k
        cur = write_num(cur, val, flg);
9391
37.4k
        if (unlikely(!cur)) goto fail_num;
9392
37.4k
        *cur++ = ',';
9393
37.4k
        goto val_end;
9394
37.4k
    }
9395
9.62k
    if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
9396
9.62k
                    (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
9397
7.53k
        ctn_len_tmp = unsafe_yyjson_get_len(val);
9398
7.53k
        ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
9399
7.53k
        incr_len(2 * sizeof(*ctx));
9400
7.53k
        if (unlikely(ctn_len_tmp == 0)) {
9401
            /* write empty container */
9402
1.44k
            *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
9403
1.44k
            *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
9404
1.44k
            *cur++ = ',';
9405
1.44k
            goto val_end;
9406
6.08k
        } else {
9407
            /* push context, setup new container */
9408
6.08k
            yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj);
9409
6.08k
            ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
9410
6.08k
            ctn_obj = ctn_obj_tmp;
9411
6.08k
            *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9412
6.08k
            val++;
9413
6.08k
            goto val_begin;
9414
6.08k
        }
9415
7.53k
    }
9416
2.09k
    if (val_type == YYJSON_TYPE_BOOL) {
9417
1.40k
        incr_len(16);
9418
1.40k
        cur = write_bool(cur, unsafe_yyjson_get_bool(val));
9419
1.40k
        cur++;
9420
1.40k
        goto val_end;
9421
1.40k
    }
9422
683
    if (val_type == YYJSON_TYPE_NULL) {
9423
683
        incr_len(16);
9424
683
        cur = write_null(cur);
9425
683
        cur++;
9426
683
        goto val_end;
9427
683
    }
9428
0
    if (val_type == YYJSON_TYPE_RAW) {
9429
0
        str_len = unsafe_yyjson_get_len(val);
9430
0
        str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9431
0
        check_str_len(str_len);
9432
0
        incr_len(str_len + 2);
9433
0
        cur = write_raw(cur, str_ptr, str_len);
9434
0
        *cur++ = ',';
9435
0
        goto val_end;
9436
0
    }
9437
0
    goto fail_type;
9438
9439
66.0k
val_end:
9440
66.0k
    val++;
9441
66.0k
    ctn_len--;
9442
66.0k
    if (unlikely(ctn_len == 0)) goto ctn_end;
9443
63.3k
    goto val_begin;
9444
9445
63.3k
ctn_end:
9446
8.09k
    cur--;
9447
8.09k
    *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
9448
8.09k
    *cur++ = ',';
9449
8.09k
    if (unlikely((u8 *)ctx >= end)) goto doc_end;
9450
6.08k
    yyjson_write_ctx_get(ctx++, &ctn_len, &ctn_obj);
9451
6.08k
    ctn_len--;
9452
6.08k
    if (likely(ctn_len > 0)) {
9453
664
        goto val_begin;
9454
5.42k
    } else {
9455
5.42k
        goto ctn_end;
9456
5.42k
    }
9457
9458
2.00k
doc_end:
9459
2.00k
    if (newline) {
9460
0
        incr_len(2);
9461
0
        *(cur - 1) = '\n';
9462
0
        cur++;
9463
0
    }
9464
2.00k
    *--cur = '\0';
9465
2.00k
    *dat_len = (usize)(cur - hdr);
9466
2.00k
    memset(err, 0, sizeof(yyjson_write_err));
9467
2.00k
    return hdr;
9468
9469
0
fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
9470
0
fail_type:  return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
9471
0
fail_num:   return_err(NAN_OR_INF, MSG_NAN_INF);
9472
0
fail_str:   return_err(INVALID_STRING, MSG_ERR_UTF8);
9473
9474
0
#undef return_err
9475
0
#undef incr_len
9476
0
#undef check_str_len
9477
0
}
9478
9479
/** Write JSON document pretty.
9480
    The root of this document should be a non-empty container. */
9481
static_inline u8 *write_root_pretty(const yyjson_val *root,
9482
                                    const yyjson_write_flag flg,
9483
                                    const yyjson_alc alc,
9484
                                    char *buf, usize *dat_len,
9485
2.55k
                                    yyjson_write_err *err) {
9486
2.55k
#define return_err(_code, _msg) do { \
9487
23
    *dat_len = 0; \
9488
23
    err->code = YYJSON_WRITE_ERROR_##_code; \
9489
23
    err->msg = _msg; \
9490
23
    if (hdr) alc.free(alc.ctx, hdr); \
9491
23
    return NULL; \
9492
23
} while (false)
9493
9494
3.60M
#define incr_len(_len) do { \
9495
6.85M
    ext_len = (usize)(_len); \
9496
3.60M
    if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
9497
2.24k
        usize ctx_pos = (usize)((u8 *)ctx - hdr); \
9498
2.24k
        usize cur_pos = (usize)(cur - hdr); \
9499
2.24k
        yyjson_assume((u8 *)ctx <= (u8 *)end); \
9500
2.24k
        ctx_len = (usize)((u8 *)end - (u8 *)ctx); \
9501
2.24k
        alc_inc = yyjson_max(alc_len / 2, ext_len); \
9502
2.24k
        alc_inc = size_align_up(alc_inc, sizeof(yyjson_write_ctx)); \
9503
2.24k
        if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
9504
2.24k
            goto fail_alloc; \
9505
2.24k
        alc_len += alc_inc; \
9506
2.24k
        tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
9507
2.24k
        if (unlikely(!tmp)) goto fail_alloc; \
9508
2.24k
        ctx_tmp = (yyjson_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
9509
2.22k
        memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
9510
2.22k
        ctx = ctx_tmp; \
9511
2.22k
        cur = tmp + cur_pos; \
9512
2.22k
        end = tmp + alc_len; \
9513
2.22k
        hdr = tmp; \
9514
2.22k
    } \
9515
3.60M
} while (false)
9516
9517
40.2k
#define check_str_len(_len) do { \
9518
40.2k
    if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
9519
40.2k
        goto fail_alloc; \
9520
40.2k
} while (false)
9521
9522
2.55k
    yyjson_val *val;
9523
2.55k
    yyjson_type val_type;
9524
2.55k
    usize ctn_len, ctn_len_tmp;
9525
2.55k
    bool ctn_obj, ctn_obj_tmp, is_key, no_indent;
9526
2.55k
    u8 *hdr, *cur, *end, *tmp;
9527
2.55k
    yyjson_write_ctx *ctx, *ctx_tmp;
9528
2.55k
    usize alc_len, alc_inc, ctx_len, ext_len, str_len, level;
9529
2.55k
    const u8 *str_ptr;
9530
2.55k
    const char_enc_type *enc_table = get_enc_table_with_flag(flg);
9531
2.55k
    const u8 *hex_table = get_hex_table_with_flag(flg);
9532
2.55k
    bool cpy = (enc_table == enc_table_cpy);
9533
2.55k
    bool esc = has_flg(ESCAPE_UNICODE) != 0;
9534
2.55k
    bool inv = has_allow(INVALID_UNICODE) != 0;
9535
2.55k
    usize spaces = has_flg(PRETTY_TWO_SPACES) ? 2 : 4;
9536
2.55k
    bool newline = has_flg(NEWLINE_AT_END) != 0;
9537
9538
2.55k
    if (buf) {
9539
0
        hdr = (u8 *)buf;
9540
0
        alc_len = *dat_len;
9541
0
        alc_len = size_align_down(alc_len, sizeof(yyjson_write_ctx));
9542
0
        if (alc_len <= sizeof(yyjson_write_ctx)) goto fail_alloc;
9543
2.55k
    } else {
9544
2.55k
        alc_len = root->uni.ofs / sizeof(yyjson_val);
9545
2.55k
        alc_len = alc_len * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64;
9546
2.55k
        alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx));
9547
2.55k
        hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
9548
2.55k
        if (!hdr) goto fail_alloc;
9549
2.55k
    }
9550
2.55k
    cur = hdr;
9551
2.55k
    end = hdr + alc_len;
9552
2.55k
    ctx = (yyjson_write_ctx *)(void *)end;
9553
9554
2.55k
doc_begin:
9555
2.55k
    val = constcast(yyjson_val *)root;
9556
2.55k
    val_type = unsafe_yyjson_get_type(val);
9557
2.55k
    ctn_obj = (val_type == YYJSON_TYPE_OBJ);
9558
2.55k
    ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
9559
2.55k
    *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9560
2.55k
    *cur++ = '\n';
9561
2.55k
    val++;
9562
2.55k
    level = 1;
9563
9564
3.42M
val_begin:
9565
3.42M
    val_type = unsafe_yyjson_get_type(val);
9566
3.42M
    if (val_type == YYJSON_TYPE_STR) {
9567
40.2k
        is_key = (bool)((u8)ctn_obj & (u8)~ctn_len);
9568
40.2k
        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9569
40.2k
        str_len = unsafe_yyjson_get_len(val);
9570
40.2k
        str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9571
40.2k
        check_str_len(str_len);
9572
40.2k
        if ((sizeof(usize) < 8) && !no_indent &&
9573
0
            level > (USIZE_MAX - 16 - str_len * 6) / 4) goto fail_alloc;
9574
40.2k
        incr_len(str_len * 6 + 16 + (no_indent ? 0 : level * 4));
9575
40.2k
        cur = write_indent(cur, no_indent ? 0 : level, spaces);
9576
40.2k
        if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
9577
0
            cur = write_str_noesc(cur, str_ptr, str_len);
9578
40.2k
        } else {
9579
40.2k
            cur = write_str(cur, esc, inv, str_ptr, str_len,
9580
40.2k
                            enc_table, hex_table);
9581
40.2k
            if (unlikely(!cur)) goto fail_str;
9582
40.2k
        }
9583
40.2k
        *cur++ = is_key ? ':' : ',';
9584
40.2k
        *cur++ = is_key ? ' ' : '\n';
9585
40.2k
        goto val_end;
9586
40.2k
    }
9587
3.38M
    if (val_type == YYJSON_TYPE_NUM) {
9588
2.31M
        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9589
2.31M
        incr_len(FP_BUF_LEN + (no_indent ? 0 : level * 4));
9590
2.31M
        cur = write_indent(cur, no_indent ? 0 : level, spaces);
9591
2.31M
        cur = write_num(cur, val, flg);
9592
2.31M
        if (unlikely(!cur)) goto fail_num;
9593
2.31M
        *cur++ = ',';
9594
2.31M
        *cur++ = '\n';
9595
2.31M
        goto val_end;
9596
2.31M
    }
9597
1.07M
    if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
9598
1.07M
                    (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
9599
876k
        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9600
876k
        ctn_len_tmp = unsafe_yyjson_get_len(val);
9601
876k
        ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
9602
876k
        incr_len(2 * sizeof(*ctx) + (no_indent ? 0 : level * 4));
9603
876k
        if (unlikely(ctn_len_tmp == 0)) {
9604
            /* write empty container */
9605
347k
            cur = write_indent(cur, no_indent ? 0 : level, spaces);
9606
347k
            *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
9607
347k
            *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
9608
347k
            *cur++ = ',';
9609
347k
            *cur++ = '\n';
9610
347k
            goto val_end;
9611
528k
        } else {
9612
            /* push context, setup new container */
9613
528k
            yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj);
9614
528k
            ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
9615
528k
            ctn_obj = ctn_obj_tmp;
9616
528k
            cur = write_indent(cur, no_indent ? 0 : level, spaces);
9617
528k
            level++;
9618
528k
            *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9619
528k
            *cur++ = '\n';
9620
528k
            val++;
9621
528k
            goto val_begin;
9622
528k
        }
9623
876k
    }
9624
195k
    if (val_type == YYJSON_TYPE_BOOL) {
9625
65.6k
        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9626
65.6k
        incr_len(16 + (no_indent ? 0 : level * 4));
9627
65.6k
        cur = write_indent(cur, no_indent ? 0 : level, spaces);
9628
65.6k
        cur = write_bool(cur, unsafe_yyjson_get_bool(val));
9629
65.6k
        cur += 2;
9630
65.6k
        goto val_end;
9631
65.6k
    }
9632
130k
    if (val_type == YYJSON_TYPE_NULL) {
9633
130k
        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9634
130k
        incr_len(16 + (no_indent ? 0 : level * 4));
9635
130k
        cur = write_indent(cur, no_indent ? 0 : level, spaces);
9636
130k
        cur = write_null(cur);
9637
130k
        cur += 2;
9638
130k
        goto val_end;
9639
130k
    }
9640
0
    if (val_type == YYJSON_TYPE_RAW) {
9641
0
        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9642
0
        str_len = unsafe_yyjson_get_len(val);
9643
0
        str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9644
0
        check_str_len(str_len);
9645
0
        incr_len(str_len + 3 + (no_indent ? 0 : level * 4));
9646
0
        cur = write_indent(cur, no_indent ? 0 : level, spaces);
9647
0
        cur = write_raw(cur, str_ptr, str_len);
9648
0
        *cur++ = ',';
9649
0
        *cur++ = '\n';
9650
0
        goto val_end;
9651
0
    }
9652
0
    goto fail_type;
9653
9654
2.89M
val_end:
9655
2.89M
    val++;
9656
2.89M
    ctn_len--;
9657
2.89M
    if (unlikely(ctn_len == 0)) goto ctn_end;
9658
2.76M
    goto val_begin;
9659
9660
2.76M
ctn_end:
9661
180k
    cur -= 2;
9662
180k
    *cur++ = '\n';
9663
180k
    incr_len(level * 4);
9664
180k
    cur = write_indent(cur, --level, spaces);
9665
180k
    *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
9666
180k
    if (unlikely((u8 *)ctx >= end)) goto doc_end;
9667
178k
    yyjson_write_ctx_get(ctx++, &ctn_len, &ctn_obj);
9668
178k
    ctn_len--;
9669
178k
    *cur++ = ',';
9670
178k
    *cur++ = '\n';
9671
178k
    if (likely(ctn_len > 0)) {
9672
130k
        goto val_begin;
9673
130k
    } else {
9674
48.2k
        goto ctn_end;
9675
48.2k
    }
9676
9677
2.53k
doc_end:
9678
2.53k
    if (newline) {
9679
0
        incr_len(2);
9680
0
        *cur++ = '\n';
9681
0
    }
9682
2.53k
    *cur = '\0';
9683
2.53k
    *dat_len = (usize)(cur - hdr);
9684
2.53k
    memset(err, 0, sizeof(yyjson_write_err));
9685
2.53k
    return hdr;
9686
9687
23
fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
9688
0
fail_type:  return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
9689
0
fail_num:   return_err(NAN_OR_INF, MSG_NAN_INF);
9690
0
fail_str:   return_err(INVALID_STRING, MSG_ERR_UTF8);
9691
9692
0
#undef return_err
9693
0
#undef incr_len
9694
0
#undef check_str_len
9695
0
}
9696
9697
static char *write_root(const yyjson_val *val,
9698
                        yyjson_write_flag flg,
9699
                        const yyjson_alc *alc_ptr,
9700
                        char *buf, usize *dat_len,
9701
49.2k
                        yyjson_write_err *err) {
9702
49.2k
    yyjson_write_err tmp_err;
9703
49.2k
    usize tmp_dat_len;
9704
49.2k
    yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
9705
49.2k
    yyjson_val *root = constcast(yyjson_val *)val;
9706
9707
49.2k
    if (!err) err = &tmp_err;
9708
49.2k
    if (!dat_len) dat_len = &tmp_dat_len;
9709
9710
49.2k
    if (unlikely(!root)) {
9711
38.2k
        *dat_len = 0;
9712
38.2k
        err->msg = "input JSON is NULL";
9713
38.2k
        err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
9714
38.2k
        return NULL;
9715
38.2k
    }
9716
9717
11.0k
    if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) {
9718
6.44k
        return (char *)write_root_single(root, flg, alc, buf, dat_len, err);
9719
6.44k
    } else if (flg & (YYJSON_WRITE_PRETTY | YYJSON_WRITE_PRETTY_TWO_SPACES)) {
9720
2.55k
        return (char *)write_root_pretty(root, flg, alc, buf, dat_len, err);
9721
2.55k
    } else {
9722
2.00k
        return (char *)write_root_minify(root, flg, alc, buf, dat_len, err);
9723
2.00k
    }
9724
11.0k
}
9725
9726
9727
9728
/*==============================================================================
9729
 * MARK: - JSON Writer (Public)
9730
 *============================================================================*/
9731
9732
char *yyjson_val_write_opts(const yyjson_val *val,
9733
                            yyjson_write_flag flg,
9734
                            const yyjson_alc *alc_ptr,
9735
                            usize *dat_len,
9736
0
                            yyjson_write_err *err) {
9737
0
    return write_root(val, flg, alc_ptr, NULL, dat_len, err);
9738
0
}
9739
9740
char *yyjson_write_opts(const yyjson_doc *doc,
9741
                        yyjson_write_flag flg,
9742
                        const yyjson_alc *alc_ptr,
9743
                        usize *dat_len,
9744
49.2k
                        yyjson_write_err *err) {
9745
49.2k
    yyjson_val *root = doc ? doc->root : NULL;
9746
49.2k
    return write_root(root, flg, alc_ptr, NULL, dat_len, err);
9747
49.2k
}
9748
9749
#if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE
9750
9751
bool yyjson_val_write_file(const char *path,
9752
                           const yyjson_val *val,
9753
                           yyjson_write_flag flg,
9754
                           const yyjson_alc *alc_ptr,
9755
0
                           yyjson_write_err *err) {
9756
0
    yyjson_write_err tmp_err;
9757
0
    yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
9758
0
    u8 *dat;
9759
0
    usize dat_len = 0;
9760
0
    yyjson_val *root = constcast(yyjson_val *)val;
9761
0
    bool suc;
9762
9763
0
    if (!err) err = &tmp_err;
9764
0
    if (unlikely(!path || !*path)) {
9765
0
        err->msg = "input path is invalid";
9766
0
        err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
9767
0
        return false;
9768
0
    }
9769
9770
0
    dat = (u8 *)write_root(root, flg, &alc, NULL, &dat_len, err);
9771
0
    if (unlikely(!dat)) return false;
9772
0
    suc = write_dat_to_file(path, dat, dat_len, err);
9773
0
    alc.free(alc.ctx, dat);
9774
0
    return suc;
9775
0
}
9776
9777
bool yyjson_val_write_fp(FILE *fp,
9778
                         const yyjson_val *val,
9779
                         yyjson_write_flag flg,
9780
                         const yyjson_alc *alc_ptr,
9781
0
                         yyjson_write_err *err) {
9782
0
    yyjson_write_err tmp_err;
9783
0
    yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
9784
0
    u8 *dat;
9785
0
    usize dat_len = 0;
9786
0
    yyjson_val *root = constcast(yyjson_val *)val;
9787
0
    bool suc;
9788
9789
0
    if (!err) err = &tmp_err;
9790
0
    if (unlikely(!fp)) {
9791
0
        err->msg = "input fp is invalid";
9792
0
        err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
9793
0
        return false;
9794
0
    }
9795
9796
0
    dat = (u8 *)write_root(root, flg, &alc, NULL, &dat_len, err);
9797
0
    if (unlikely(!dat)) return false;
9798
0
    suc = write_dat_to_fp(fp, dat, dat_len, err);
9799
0
    alc.free(alc.ctx, dat);
9800
0
    return suc;
9801
0
}
9802
9803
bool yyjson_write_file(const char *path,
9804
                       const yyjson_doc *doc,
9805
                       yyjson_write_flag flg,
9806
                       const yyjson_alc *alc_ptr,
9807
0
                       yyjson_write_err *err) {
9808
0
    yyjson_val *root = doc ? doc->root : NULL;
9809
0
    return yyjson_val_write_file(path, root, flg, alc_ptr, err);
9810
0
}
9811
9812
bool yyjson_write_fp(FILE *fp,
9813
                     const yyjson_doc *doc,
9814
                     yyjson_write_flag flg,
9815
                     const yyjson_alc *alc_ptr,
9816
0
                     yyjson_write_err *err) {
9817
0
    yyjson_val *root = doc ? doc->root : NULL;
9818
0
    return yyjson_val_write_fp(fp, root, flg, alc_ptr, err);
9819
0
}
9820
9821
#endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */
9822
9823
size_t yyjson_val_write_buf(char *buf, size_t buf_len,
9824
                            const yyjson_val *val,
9825
                            yyjson_write_flag flg,
9826
0
                            yyjson_write_err *err) {
9827
0
    if (unlikely(!buf || !buf_len)) {
9828
0
        if (err) err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
9829
0
        if (err) err->msg = "input buf or buf_len is invalid";
9830
0
        return 0;
9831
0
    } else {
9832
0
        write_root(val, flg, &YYJSON_NULL_ALC, buf, &buf_len, err);
9833
0
        return buf_len;
9834
0
    }
9835
0
}
9836
9837
size_t yyjson_write_buf(char *buf, size_t buf_len,
9838
                        const yyjson_doc *doc,
9839
                        yyjson_write_flag flg,
9840
0
                        yyjson_write_err *err) {
9841
0
    yyjson_val *root = doc ? doc->root : NULL;
9842
0
    return yyjson_val_write_buf(buf, buf_len, root, flg, err);
9843
0
}
9844
9845
9846
9847
/*==============================================================================
9848
 * MARK: - Mutable JSON Writer Implementation (Private)
9849
 *============================================================================*/
9850
9851
typedef struct yyjson_mut_write_ctx {
9852
    usize tag;
9853
    yyjson_mut_val *ctn;
9854
} yyjson_mut_write_ctx;
9855
9856
static_inline void yyjson_mut_write_ctx_set(yyjson_mut_write_ctx *ctx,
9857
                                            yyjson_mut_val *ctn,
9858
51.2M
                                            usize size, bool is_obj) {
9859
51.2M
    ctx->tag = (size << 1) | (usize)is_obj;
9860
51.2M
    ctx->ctn = ctn;
9861
51.2M
}
9862
9863
static_inline void yyjson_mut_write_ctx_get(yyjson_mut_write_ctx *ctx,
9864
                                            yyjson_mut_val **ctn,
9865
50.9M
                                            usize *size, bool *is_obj) {
9866
50.9M
    usize tag = ctx->tag;
9867
50.9M
    *size = tag >> 1;
9868
50.9M
    *is_obj = (bool)(tag & 1);
9869
50.9M
    *ctn = ctx->ctn;
9870
50.9M
}
9871
9872
/** Get the estimated number of values for the mutable JSON document. */
9873
static_inline usize yyjson_mut_doc_estimated_val_num(
9874
11.0k
    const yyjson_mut_doc *doc) {
9875
11.0k
    usize sum = 0;
9876
11.0k
    yyjson_val_chunk *chunk = doc->val_pool.chunks;
9877
22.0k
    while (chunk) {
9878
11.0k
        sum += chunk->chunk_size / sizeof(yyjson_mut_val) - 1;
9879
11.0k
        if (chunk == doc->val_pool.chunks) {
9880
11.0k
            sum -= (usize)(doc->val_pool.end - doc->val_pool.cur);
9881
11.0k
        }
9882
11.0k
        chunk = chunk->next;
9883
11.0k
    }
9884
11.0k
    return sum;
9885
11.0k
}
9886
9887
/** Write single JSON value. */
9888
static_inline u8 *mut_write_root_single(yyjson_mut_val *val,
9889
                                        yyjson_write_flag flg,
9890
                                        yyjson_alc alc,
9891
                                        char *buf, usize *dat_len,
9892
15.7k
                                        yyjson_write_err *err) {
9893
15.7k
    return write_root_single((yyjson_val *)val, flg, alc, buf, dat_len, err);
9894
15.7k
}
9895
9896
/** Write JSON document minify.
9897
    The root of this document should be a non-empty container. */
9898
static_inline u8 *mut_write_root_minify(const yyjson_mut_val *root,
9899
                                        usize estimated_val_num,
9900
                                        yyjson_write_flag flg,
9901
                                        yyjson_alc alc,
9902
                                        char *buf, usize *dat_len,
9903
9.10k
                                        yyjson_write_err *err) {
9904
9.10k
#define return_err(_code, _msg) do { \
9905
1.16k
    *dat_len = 0; \
9906
1.16k
    err->code = YYJSON_WRITE_ERROR_##_code; \
9907
1.16k
    err->msg = _msg; \
9908
1.16k
    if (hdr) alc.free(alc.ctx, hdr); \
9909
1.16k
    return NULL; \
9910
1.16k
} while (false)
9911
9912
184M
#define incr_len(_len) do { \
9913
184M
    ext_len = (usize)(_len); \
9914
184M
    if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
9915
15.3k
        usize ctx_pos = (usize)((u8 *)ctx - hdr); \
9916
15.3k
        usize cur_pos = (usize)(cur - hdr); \
9917
15.3k
        yyjson_assume((u8 *)ctx <= (u8 *)end); \
9918
15.3k
        ctx_len = (usize)((u8 *)end - (u8 *)ctx); \
9919
15.3k
        alc_inc = yyjson_max(alc_len / 2, ext_len); \
9920
15.3k
        alc_inc = size_align_up(alc_inc, sizeof(yyjson_mut_write_ctx)); \
9921
15.3k
        if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
9922
15.3k
            goto fail_alloc; \
9923
15.3k
        alc_len += alc_inc; \
9924
15.3k
        tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
9925
15.3k
        if (unlikely(!tmp)) goto fail_alloc; \
9926
15.3k
        ctx_tmp = (yyjson_mut_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
9927
15.3k
        memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
9928
15.3k
        ctx = ctx_tmp; \
9929
15.3k
        cur = tmp + cur_pos; \
9930
15.3k
        end = tmp + alc_len; \
9931
15.3k
        hdr = tmp; \
9932
15.3k
    } \
9933
184M
} while (false)
9934
9935
50.3M
#define check_str_len(_len) do { \
9936
50.3M
    if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
9937
50.3M
        goto fail_alloc; \
9938
50.3M
} while (false)
9939
9940
9.10k
    yyjson_mut_val *val, *ctn;
9941
9.10k
    yyjson_type val_type;
9942
9.10k
    usize ctn_len, ctn_len_tmp;
9943
9.10k
    bool ctn_obj, ctn_obj_tmp, is_key;
9944
9.10k
    u8 *hdr, *cur, *end, *tmp;
9945
9.10k
    yyjson_mut_write_ctx *ctx, *ctx_tmp;
9946
9.10k
    usize alc_len, alc_inc, ctx_len, ext_len, str_len;
9947
9.10k
    const u8 *str_ptr;
9948
9.10k
    const char_enc_type *enc_table = get_enc_table_with_flag(flg);
9949
9.10k
    const u8 *hex_table = get_hex_table_with_flag(flg);
9950
9.10k
    bool cpy = (enc_table == enc_table_cpy);
9951
9.10k
    bool esc = has_flg(ESCAPE_UNICODE) != 0;
9952
9.10k
    bool inv = has_allow(INVALID_UNICODE) != 0;
9953
9.10k
    bool newline = has_flg(NEWLINE_AT_END) != 0;
9954
9955
9.10k
    if (buf) {
9956
0
        hdr = (u8 *)buf;
9957
0
        alc_len = *dat_len;
9958
0
        alc_len = size_align_down(alc_len, sizeof(yyjson_mut_write_ctx));
9959
0
        if (alc_len <= sizeof(yyjson_mut_write_ctx)) goto fail_alloc;
9960
9.10k
    } else {
9961
9.10k
        alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64;
9962
9.10k
        alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx));
9963
9.10k
        hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
9964
9.10k
        if (!hdr) goto fail_alloc;
9965
9.10k
    }
9966
9.10k
    cur = hdr;
9967
9.10k
    end = hdr + alc_len;
9968
9.10k
    ctx = (yyjson_mut_write_ctx *)(void *)end;
9969
9970
9.10k
doc_begin:
9971
9.10k
    val = constcast(yyjson_mut_val *)root;
9972
9.10k
    val_type = unsafe_yyjson_get_type(val);
9973
9.10k
    ctn_obj = (val_type == YYJSON_TYPE_OBJ);
9974
9.10k
    ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
9975
9.10k
    *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9976
9.10k
    ctn = val;
9977
9.10k
    val = (yyjson_mut_val *)val->uni.ptr; /* tail */
9978
9.10k
    val = ctn_obj ? val->next->next : val->next;
9979
9980
184M
val_begin:
9981
184M
    val_type = unsafe_yyjson_get_type(val);
9982
184M
    if (val_type == YYJSON_TYPE_STR) {
9983
50.3M
        is_key = ((u8)ctn_obj & (u8)~ctn_len);
9984
50.3M
        str_len = unsafe_yyjson_get_len(val);
9985
50.3M
        str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9986
50.3M
        check_str_len(str_len);
9987
50.3M
        incr_len(str_len * 6 + 16);
9988
50.3M
        if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
9989
21.7M
            cur = write_str_noesc(cur, str_ptr, str_len);
9990
28.5M
        } else {
9991
28.5M
            cur = write_str(cur, esc, inv, str_ptr, str_len,
9992
28.5M
                            enc_table, hex_table);
9993
28.5M
            if (unlikely(!cur)) goto fail_str;
9994
28.5M
        }
9995
50.3M
        *cur++ = is_key ? ':' : ',';
9996
50.3M
        goto val_end;
9997
50.3M
    }
9998
134M
    if (val_type == YYJSON_TYPE_NUM) {
9999
83.2M
        incr_len(FP_BUF_LEN);
10000
83.2M
        cur = write_num(cur, (yyjson_val *)val, flg);
10001
83.2M
        if (unlikely(!cur)) goto fail_num;
10002
83.2M
        *cur++ = ',';
10003
83.2M
        goto val_end;
10004
83.2M
    }
10005
51.3M
    if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
10006
51.3M
                    (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
10007
51.0M
        ctn_len_tmp = unsafe_yyjson_get_len(val);
10008
51.0M
        ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
10009
51.0M
        incr_len(2 * sizeof(*ctx));
10010
51.0M
        if (unlikely(ctn_len_tmp == 0)) {
10011
            /* write empty container */
10012
296k
            *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
10013
296k
            *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
10014
296k
            *cur++ = ',';
10015
296k
            goto val_end;
10016
50.7M
        } else {
10017
            /* push context, setup new container */
10018
50.7M
            yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj);
10019
50.7M
            ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
10020
50.7M
            ctn_obj = ctn_obj_tmp;
10021
50.7M
            *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
10022
50.7M
            ctn = val;
10023
50.7M
            val = (yyjson_mut_val *)ctn->uni.ptr; /* tail */
10024
50.7M
            val = ctn_obj ? val->next->next : val->next;
10025
50.7M
            goto val_begin;
10026
50.7M
        }
10027
51.0M
    }
10028
277k
    if (val_type == YYJSON_TYPE_BOOL) {
10029
274k
        incr_len(16);
10030
274k
        cur = write_bool(cur, unsafe_yyjson_get_bool(val));
10031
274k
        cur++;
10032
274k
        goto val_end;
10033
274k
    }
10034
3.04k
    if (val_type == YYJSON_TYPE_NULL) {
10035
3.04k
        incr_len(16);
10036
3.04k
        cur = write_null(cur);
10037
3.04k
        cur++;
10038
3.04k
        goto val_end;
10039
3.04k
    }
10040
0
    if (val_type == YYJSON_TYPE_RAW) {
10041
0
        str_len = unsafe_yyjson_get_len(val);
10042
0
        str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
10043
0
        check_str_len(str_len);
10044
0
        incr_len(str_len + 2);
10045
0
        cur = write_raw(cur, str_ptr, str_len);
10046
0
        *cur++ = ',';
10047
0
        goto val_end;
10048
0
    }
10049
0
    goto fail_type;
10050
10051
134M
val_end:
10052
134M
    ctn_len--;
10053
134M
    if (unlikely(ctn_len == 0)) goto ctn_end;
10054
104M
    val = val->next;
10055
104M
    goto val_begin;
10056
10057
50.7M
ctn_end:
10058
50.7M
    cur--;
10059
50.7M
    *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
10060
50.7M
    *cur++ = ',';
10061
50.7M
    if (unlikely((u8 *)ctx >= end)) goto doc_end;
10062
50.7M
    val = ctn->next;
10063
50.7M
    yyjson_mut_write_ctx_get(ctx++, &ctn, &ctn_len, &ctn_obj);
10064
50.7M
    ctn_len--;
10065
50.7M
    if (likely(ctn_len > 0)) {
10066
29.6M
        goto val_begin;
10067
29.6M
    } else {
10068
21.0M
        goto ctn_end;
10069
21.0M
    }
10070
10071
7.94k
doc_end:
10072
7.94k
    if (newline) {
10073
0
        incr_len(2);
10074
0
        *(cur - 1) = '\n';
10075
0
        cur++;
10076
0
    }
10077
7.94k
    *--cur = '\0';
10078
7.94k
    *dat_len = (usize)(cur - hdr);
10079
7.94k
    err->code = YYJSON_WRITE_SUCCESS;
10080
7.94k
    err->msg = NULL;
10081
7.94k
    return hdr;
10082
10083
28
fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
10084
0
fail_type:  return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
10085
0
fail_num:   return_err(NAN_OR_INF, MSG_NAN_INF);
10086
1.13k
fail_str:   return_err(INVALID_STRING, MSG_ERR_UTF8);
10087
10088
1.13k
#undef return_err
10089
1.13k
#undef incr_len
10090
1.13k
#undef check_str_len
10091
1.13k
}
10092
10093
/** Write JSON document pretty.
10094
    The root of this document should be a non-empty container. */
10095
static_inline u8 *mut_write_root_pretty(const yyjson_mut_val *root,
10096
                                        usize estimated_val_num,
10097
                                        yyjson_write_flag flg,
10098
                                        yyjson_alc alc,
10099
                                        char *buf, usize *dat_len,
10100
2.55k
                                        yyjson_write_err *err) {
10101
2.55k
#define return_err(_code, _msg) do { \
10102
23
    *dat_len = 0; \
10103
23
    err->code = YYJSON_WRITE_ERROR_##_code; \
10104
23
    err->msg = _msg; \
10105
23
    if (hdr) alc.free(alc.ctx, hdr); \
10106
23
    return NULL; \
10107
23
} while (false)
10108
10109
3.60M
#define incr_len(_len) do { \
10110
6.85M
    ext_len = (usize)(_len); \
10111
3.60M
    if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
10112
2.25k
        usize ctx_pos = (usize)((u8 *)ctx - hdr); \
10113
2.25k
        usize cur_pos = (usize)(cur - hdr); \
10114
2.25k
        yyjson_assume((u8 *)ctx <= (u8 *)end); \
10115
2.25k
        ctx_len = (usize)((u8 *)end - (u8 *)ctx); \
10116
2.25k
        alc_inc = yyjson_max(alc_len / 2, ext_len); \
10117
2.25k
        alc_inc = size_align_up(alc_inc, sizeof(yyjson_mut_write_ctx)); \
10118
2.25k
        if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
10119
2.25k
            goto fail_alloc; \
10120
2.25k
        alc_len += alc_inc; \
10121
2.25k
        tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
10122
2.25k
        if (unlikely(!tmp)) goto fail_alloc; \
10123
2.25k
        ctx_tmp = (yyjson_mut_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
10124
2.22k
        memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
10125
2.22k
        ctx = ctx_tmp; \
10126
2.22k
        cur = tmp + cur_pos; \
10127
2.22k
        end = tmp + alc_len; \
10128
2.22k
        hdr = tmp; \
10129
2.22k
    } \
10130
3.60M
} while (false)
10131
10132
40.2k
#define check_str_len(_len) do { \
10133
40.2k
    if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
10134
40.2k
        goto fail_alloc; \
10135
40.2k
} while (false)
10136
10137
2.55k
    yyjson_mut_val *val, *ctn;
10138
2.55k
    yyjson_type val_type;
10139
2.55k
    usize ctn_len, ctn_len_tmp;
10140
2.55k
    bool ctn_obj, ctn_obj_tmp, is_key, no_indent;
10141
2.55k
    u8 *hdr, *cur, *end, *tmp;
10142
2.55k
    yyjson_mut_write_ctx *ctx, *ctx_tmp;
10143
2.55k
    usize alc_len, alc_inc, ctx_len, ext_len, str_len, level;
10144
2.55k
    const u8 *str_ptr;
10145
2.55k
    const char_enc_type *enc_table = get_enc_table_with_flag(flg);
10146
2.55k
    const u8 *hex_table = get_hex_table_with_flag(flg);
10147
2.55k
    bool cpy = (enc_table == enc_table_cpy);
10148
2.55k
    bool esc = has_flg(ESCAPE_UNICODE) != 0;
10149
2.55k
    bool inv = has_allow(INVALID_UNICODE) != 0;
10150
2.55k
    usize spaces = has_flg(PRETTY_TWO_SPACES) ? 2 : 4;
10151
2.55k
    bool newline = has_flg(NEWLINE_AT_END) != 0;
10152
10153
2.55k
    if (buf) {
10154
0
        hdr = (u8 *)buf;
10155
0
        alc_len = *dat_len;
10156
0
        alc_len = size_align_down(alc_len, sizeof(yyjson_mut_write_ctx));
10157
0
        if (alc_len <= sizeof(yyjson_mut_write_ctx)) goto fail_alloc;
10158
2.55k
    } else {
10159
2.55k
        alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64;
10160
2.55k
        alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx));
10161
2.55k
        hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
10162
2.55k
        if (!hdr) goto fail_alloc;
10163
2.55k
    }
10164
2.55k
    cur = hdr;
10165
2.55k
    end = hdr + alc_len;
10166
2.55k
    ctx = (yyjson_mut_write_ctx *)(void *)end;
10167
10168
2.55k
doc_begin:
10169
2.55k
    val = constcast(yyjson_mut_val *)root;
10170
2.55k
    val_type = unsafe_yyjson_get_type(val);
10171
2.55k
    ctn_obj = (val_type == YYJSON_TYPE_OBJ);
10172
2.55k
    ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
10173
2.55k
    *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
10174
2.55k
    *cur++ = '\n';
10175
2.55k
    ctn = val;
10176
2.55k
    val = (yyjson_mut_val *)val->uni.ptr; /* tail */
10177
2.55k
    val = ctn_obj ? val->next->next : val->next;
10178
2.55k
    level = 1;
10179
10180
3.42M
val_begin:
10181
3.42M
    val_type = unsafe_yyjson_get_type(val);
10182
3.42M
    if (val_type == YYJSON_TYPE_STR) {
10183
40.2k
        is_key = (bool)((u8)ctn_obj & (u8)~ctn_len);
10184
40.2k
        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10185
40.2k
        str_len = unsafe_yyjson_get_len(val);
10186
40.2k
        str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
10187
40.2k
        check_str_len(str_len);
10188
40.2k
        if ((sizeof(usize) < 8) && !no_indent &&
10189
0
            level > (USIZE_MAX - 16 - str_len * 6) / 4) goto fail_alloc;
10190
40.2k
        incr_len(str_len * 6 + 16 + (no_indent ? 0 : level * 4));
10191
40.2k
        cur = write_indent(cur, no_indent ? 0 : level, spaces);
10192
40.2k
        if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
10193
0
            cur = write_str_noesc(cur, str_ptr, str_len);
10194
40.2k
        } else {
10195
40.2k
            cur = write_str(cur, esc, inv, str_ptr, str_len,
10196
40.2k
                            enc_table, hex_table);
10197
40.2k
            if (unlikely(!cur)) goto fail_str;
10198
40.2k
        }
10199
40.2k
        *cur++ = is_key ? ':' : ',';
10200
40.2k
        *cur++ = is_key ? ' ' : '\n';
10201
40.2k
        goto val_end;
10202
40.2k
    }
10203
3.38M
    if (val_type == YYJSON_TYPE_NUM) {
10204
2.31M
        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10205
2.31M
        incr_len(FP_BUF_LEN + (no_indent ? 0 : level * 4));
10206
2.31M
        cur = write_indent(cur, no_indent ? 0 : level, spaces);
10207
2.31M
        cur = write_num(cur, (yyjson_val *)val, flg);
10208
2.31M
        if (unlikely(!cur)) goto fail_num;
10209
2.31M
        *cur++ = ',';
10210
2.31M
        *cur++ = '\n';
10211
2.31M
        goto val_end;
10212
2.31M
    }
10213
1.07M
    if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
10214
1.07M
                    (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
10215
876k
        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10216
876k
        ctn_len_tmp = unsafe_yyjson_get_len(val);
10217
876k
        ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
10218
876k
        incr_len(2 * sizeof(*ctx) + (no_indent ? 0 : level * 4));
10219
876k
        if (unlikely(ctn_len_tmp == 0)) {
10220
            /* write empty container */
10221
347k
            cur = write_indent(cur, no_indent ? 0 : level, spaces);
10222
347k
            *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
10223
347k
            *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
10224
347k
            *cur++ = ',';
10225
347k
            *cur++ = '\n';
10226
347k
            goto val_end;
10227
528k
        } else {
10228
            /* push context, setup new container */
10229
528k
            yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj);
10230
528k
            ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
10231
528k
            ctn_obj = ctn_obj_tmp;
10232
528k
            cur = write_indent(cur, no_indent ? 0 : level, spaces);
10233
528k
            level++;
10234
528k
            *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
10235
528k
            *cur++ = '\n';
10236
528k
            ctn = val;
10237
528k
            val = (yyjson_mut_val *)ctn->uni.ptr; /* tail */
10238
528k
            val = ctn_obj ? val->next->next : val->next;
10239
528k
            goto val_begin;
10240
528k
        }
10241
876k
    }
10242
195k
    if (val_type == YYJSON_TYPE_BOOL) {
10243
65.6k
        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10244
65.6k
        incr_len(16 + (no_indent ? 0 : level * 4));
10245
65.6k
        cur = write_indent(cur, no_indent ? 0 : level, spaces);
10246
65.6k
        cur = write_bool(cur, unsafe_yyjson_get_bool(val));
10247
65.6k
        cur += 2;
10248
65.6k
        goto val_end;
10249
65.6k
    }
10250
130k
    if (val_type == YYJSON_TYPE_NULL) {
10251
130k
        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10252
130k
        incr_len(16 + (no_indent ? 0 : level * 4));
10253
130k
        cur = write_indent(cur, no_indent ? 0 : level, spaces);
10254
130k
        cur = write_null(cur);
10255
130k
        cur += 2;
10256
130k
        goto val_end;
10257
130k
    }
10258
0
    if (val_type == YYJSON_TYPE_RAW) {
10259
0
        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10260
0
        str_len = unsafe_yyjson_get_len(val);
10261
0
        str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
10262
0
        check_str_len(str_len);
10263
0
        incr_len(str_len + 3 + (no_indent ? 0 : level * 4));
10264
0
        cur = write_indent(cur, no_indent ? 0 : level, spaces);
10265
0
        cur = write_raw(cur, str_ptr, str_len);
10266
0
        *cur++ = ',';
10267
0
        *cur++ = '\n';
10268
0
        goto val_end;
10269
0
    }
10270
0
    goto fail_type;
10271
10272
2.89M
val_end:
10273
2.89M
    ctn_len--;
10274
2.89M
    if (unlikely(ctn_len == 0)) goto ctn_end;
10275
2.76M
    val = val->next;
10276
2.76M
    goto val_begin;
10277
10278
180k
ctn_end:
10279
180k
    cur -= 2;
10280
180k
    *cur++ = '\n';
10281
180k
    incr_len(level * 4);
10282
180k
    cur = write_indent(cur, --level, spaces);
10283
180k
    *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
10284
180k
    if (unlikely((u8 *)ctx >= end)) goto doc_end;
10285
178k
    val = ctn->next;
10286
178k
    yyjson_mut_write_ctx_get(ctx++, &ctn, &ctn_len, &ctn_obj);
10287
178k
    ctn_len--;
10288
178k
    *cur++ = ',';
10289
178k
    *cur++ = '\n';
10290
178k
    if (likely(ctn_len > 0)) {
10291
130k
        goto val_begin;
10292
130k
    } else {
10293
48.2k
        goto ctn_end;
10294
48.2k
    }
10295
10296
2.53k
doc_end:
10297
2.53k
    if (newline) {
10298
0
        incr_len(2);
10299
0
        *cur++ = '\n';
10300
0
    }
10301
2.53k
    *cur = '\0';
10302
2.53k
    *dat_len = (usize)(cur - hdr);
10303
2.53k
    err->code = YYJSON_WRITE_SUCCESS;
10304
2.53k
    err->msg = NULL;
10305
2.53k
    return hdr;
10306
10307
23
fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
10308
0
fail_type:  return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
10309
0
fail_num:   return_err(NAN_OR_INF, MSG_NAN_INF);
10310
0
fail_str:   return_err(INVALID_STRING, MSG_ERR_UTF8);
10311
10312
0
#undef return_err
10313
0
#undef incr_len
10314
0
#undef check_str_len
10315
0
}
10316
10317
static char *mut_write_root(const yyjson_mut_val *val,
10318
                            usize estimated_val_num,
10319
                            yyjson_write_flag flg,
10320
                            const yyjson_alc *alc_ptr,
10321
                            char *buf, usize *dat_len,
10322
65.6k
                            yyjson_write_err *err) {
10323
65.6k
    yyjson_write_err tmp_err;
10324
65.6k
    usize tmp_dat_len;
10325
65.6k
    yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
10326
65.6k
    yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
10327
10328
65.6k
    if (!err) err = &tmp_err;
10329
65.6k
    if (!dat_len) dat_len = &tmp_dat_len;
10330
10331
65.6k
    if (unlikely(!root)) {
10332
38.2k
        *dat_len = 0;
10333
38.2k
        err->msg = "input JSON is NULL";
10334
38.2k
        err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
10335
38.2k
        return NULL;
10336
38.2k
    }
10337
10338
27.3k
    if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) {
10339
15.7k
        return (char *)mut_write_root_single(root, flg, alc, buf, dat_len, err);
10340
15.7k
    } else if (flg & (YYJSON_WRITE_PRETTY | YYJSON_WRITE_PRETTY_TWO_SPACES)) {
10341
2.55k
        return (char *)mut_write_root_pretty(root, estimated_val_num,
10342
2.55k
                                             flg, alc, buf, dat_len, err);
10343
9.10k
    } else {
10344
9.10k
        return (char *)mut_write_root_minify(root, estimated_val_num,
10345
9.10k
                                             flg, alc, buf, dat_len, err);
10346
9.10k
    }
10347
27.3k
}
10348
10349
10350
10351
/*==============================================================================
10352
 * MARK: - Mutable JSON Writer (Public)
10353
 *============================================================================*/
10354
10355
char *yyjson_mut_val_write_opts(const yyjson_mut_val *val,
10356
                                yyjson_write_flag flg,
10357
                                const yyjson_alc *alc_ptr,
10358
                                usize *dat_len,
10359
16.3k
                                yyjson_write_err *err) {
10360
16.3k
    return mut_write_root(val, 0, flg, alc_ptr, NULL, dat_len, err);
10361
16.3k
}
10362
10363
char *yyjson_mut_write_opts(const yyjson_mut_doc *doc,
10364
                            yyjson_write_flag flg,
10365
                            const yyjson_alc *alc_ptr,
10366
                            usize *dat_len,
10367
49.2k
                            yyjson_write_err *err) {
10368
49.2k
    yyjson_mut_val *root;
10369
49.2k
    usize estimated_val_num;
10370
49.2k
    if (likely(doc)) {
10371
11.0k
        root = doc->root;
10372
11.0k
        estimated_val_num = yyjson_mut_doc_estimated_val_num(doc);
10373
38.2k
    } else {
10374
38.2k
        root = NULL;
10375
38.2k
        estimated_val_num = 0;
10376
38.2k
    }
10377
49.2k
    return mut_write_root(root, estimated_val_num,
10378
49.2k
                          flg, alc_ptr, NULL, dat_len, err);
10379
49.2k
}
10380
10381
size_t yyjson_mut_val_write_buf(char *buf, size_t buf_len,
10382
                                const yyjson_mut_val *val,
10383
                                yyjson_write_flag flg,
10384
0
                                yyjson_write_err *err) {
10385
0
    if (unlikely(!buf || !buf_len)) {
10386
0
        if (err) err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
10387
0
        if (err) err->msg = "input buf or buf_len is invalid";
10388
0
        return 0;
10389
0
    } else {
10390
0
        mut_write_root(val, 0, flg, &YYJSON_NULL_ALC, buf, &buf_len, err);
10391
0
        return buf_len;
10392
0
    }
10393
0
}
10394
10395
size_t yyjson_mut_write_buf(char *buf, size_t buf_len,
10396
                            const yyjson_mut_doc *doc,
10397
                            yyjson_write_flag flg,
10398
0
                            yyjson_write_err *err) {
10399
0
    yyjson_mut_val *root = doc ? doc->root : NULL;
10400
0
    return yyjson_mut_val_write_buf(buf, buf_len, root, flg, err);
10401
0
}
10402
10403
#if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE
10404
10405
bool yyjson_mut_val_write_file(const char *path,
10406
                               const yyjson_mut_val *val,
10407
                               yyjson_write_flag flg,
10408
                               const yyjson_alc *alc_ptr,
10409
0
                               yyjson_write_err *err) {
10410
0
    yyjson_write_err tmp_err;
10411
0
    yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
10412
0
    u8 *dat;
10413
0
    usize dat_len = 0;
10414
0
    yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
10415
0
    bool suc;
10416
10417
0
    if (!err) err = &tmp_err;
10418
0
    if (unlikely(!path || !*path)) {
10419
0
        err->msg = "input path is invalid";
10420
0
        err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
10421
0
        return false;
10422
0
    }
10423
10424
0
    dat = (u8 *)yyjson_mut_val_write_opts(root, flg, &alc, &dat_len, err);
10425
0
    if (unlikely(!dat)) return false;
10426
0
    suc = write_dat_to_file(path, dat, dat_len, err);
10427
0
    alc.free(alc.ctx, dat);
10428
0
    return suc;
10429
0
}
10430
10431
bool yyjson_mut_val_write_fp(FILE *fp,
10432
                             const yyjson_mut_val *val,
10433
                             yyjson_write_flag flg,
10434
                             const yyjson_alc *alc_ptr,
10435
0
                             yyjson_write_err *err) {
10436
0
    yyjson_write_err tmp_err;
10437
0
    yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
10438
0
    u8 *dat;
10439
0
    usize dat_len = 0;
10440
0
    yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
10441
0
    bool suc;
10442
10443
0
    if (!err) err = &tmp_err;
10444
0
    if (unlikely(!fp)) {
10445
0
        err->msg = "input fp is invalid";
10446
0
        err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
10447
0
        return false;
10448
0
    }
10449
10450
0
    dat = (u8 *)yyjson_mut_val_write_opts(root, flg, &alc, &dat_len, err);
10451
0
    if (unlikely(!dat)) return false;
10452
0
    suc = write_dat_to_fp(fp, dat, dat_len, err);
10453
0
    alc.free(alc.ctx, dat);
10454
0
    return suc;
10455
0
}
10456
10457
bool yyjson_mut_write_file(const char *path,
10458
                           const yyjson_mut_doc *doc,
10459
                           yyjson_write_flag flg,
10460
                           const yyjson_alc *alc_ptr,
10461
0
                           yyjson_write_err *err) {
10462
0
    yyjson_mut_val *root = doc ? doc->root : NULL;
10463
0
    return yyjson_mut_val_write_file(path, root, flg, alc_ptr, err);
10464
0
}
10465
10466
bool yyjson_mut_write_fp(FILE *fp,
10467
                         const yyjson_mut_doc *doc,
10468
                         yyjson_write_flag flg,
10469
                         const yyjson_alc *alc_ptr,
10470
0
                         yyjson_write_err *err) {
10471
0
    yyjson_mut_val *root = doc ? doc->root : NULL;
10472
0
    return yyjson_mut_val_write_fp(fp, root, flg, alc_ptr, err);
10473
0
}
10474
10475
#endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */
10476
10477
#undef has_flg
10478
#undef has_allow
10479
#endif /* YYJSON_DISABLE_WRITER */
10480
10481
10482
10483
#if !YYJSON_DISABLE_UTILS
10484
10485
/*==============================================================================
10486
 * MARK: - JSON Pointer API (RFC 6901) (Public)
10487
 *============================================================================*/
10488
10489
/**
10490
 Get a token from JSON pointer string.
10491
 @param ptr [in]  string that points to current token prefix `/`
10492
            [out] string that points to next token prefix `/`, or string end
10493
 @param end [in] end of the entire JSON Pointer string
10494
 @param len [out] unescaped token length
10495
 @param esc [out] number of escaped characters in this token
10496
 @return head of the token, or NULL if syntax error
10497
 */
10498
static_inline const char *ptr_next_token(const char **ptr, const char *end,
10499
35.1k
                                         usize *len, usize *esc) {
10500
35.1k
    const char *hdr = *ptr + 1;
10501
35.1k
    const char *cur = hdr;
10502
    /* skip unescaped characters */
10503
442k
    while (cur < end && *cur != '/' && *cur != '~') cur++;
10504
35.1k
    if (likely(cur == end || *cur != '~')) {
10505
        /* no escaped characters, return */
10506
32.1k
        *ptr = cur;
10507
32.1k
        *len = (usize)(cur - hdr);
10508
32.1k
        *esc = 0;
10509
32.1k
        return hdr;
10510
32.1k
    } else {
10511
        /* handle escaped characters */
10512
2.92k
        usize esc_num = 0;
10513
74.9k
        while (cur < end && *cur != '/') {
10514
72.0k
            if (*cur++ == '~') {
10515
5.38k
                if (cur == end || (*cur != '0' && *cur != '1')) {
10516
54
                    *ptr = cur - 1;
10517
54
                    return NULL;
10518
54
                }
10519
5.32k
                esc_num++;
10520
5.32k
            }
10521
72.0k
        }
10522
2.87k
        *ptr = cur;
10523
2.87k
        *len = (usize)(cur - hdr) - esc_num;
10524
2.87k
        *esc = esc_num;
10525
2.87k
        return hdr;
10526
2.92k
    }
10527
35.1k
}
10528
10529
/**
10530
 Convert token string to index.
10531
 @param cur [in]  token head
10532
 @param len [in]  token length
10533
 @param idx [out] the index number, or USIZE_MAX if token is '-'
10534
 @return true if token is a valid array index
10535
 */
10536
22.0k
static_inline bool ptr_token_to_idx(const char *cur, usize len, usize *idx) {
10537
22.0k
    const char *end = cur + len;
10538
22.0k
    usize num = 0, add;
10539
22.0k
    if (unlikely(len == 0 || len > USIZE_SAFE_DIG)) return false;
10540
21.9k
    if (*cur == '0') {
10541
4.78k
        if (unlikely(len > 1)) return false;
10542
4.77k
        *idx = 0;
10543
4.77k
        return true;
10544
4.78k
    }
10545
17.1k
    if (*cur == '-') {
10546
1.25k
        if (unlikely(len > 1)) return false;
10547
1.24k
        *idx = USIZE_MAX;
10548
1.24k
        return true;
10549
1.25k
    }
10550
36.5k
    for (; cur < end && (add = (usize)((u8)*cur - (u8)'0')) <= 9; cur++) {
10551
20.6k
        num = num * 10 + add;
10552
20.6k
    }
10553
15.9k
    if (unlikely(num == 0 || cur < end)) return false;
10554
15.8k
    *idx = num;
10555
15.8k
    return true;
10556
15.9k
}
10557
10558
/**
10559
 Compare JSON key with token.
10560
 @param key a string key (yyjson_val or yyjson_mut_val)
10561
 @param token a JSON pointer token
10562
 @param len unescaped token length
10563
 @param esc number of escaped characters in this token
10564
 @return true if `str` is equal to `token`
10565
 */
10566
static_inline bool ptr_token_eq(void *key,
10567
66.7k
                                const char *token, usize len, usize esc) {
10568
66.7k
    yyjson_val *val = (yyjson_val *)key;
10569
66.7k
    if (unsafe_yyjson_get_len(val) != len) return false;
10570
15.5k
    if (likely(!esc)) {
10571
10.6k
        return memcmp(val->uni.str, token, len) == 0;
10572
10.6k
    } else {
10573
4.93k
        const char *str = val->uni.str;
10574
33.1k
        for (; len-- > 0; token++, str++) {
10575
31.4k
            if (*token == '~') {
10576
4.21k
                if (*str != (*++token == '0' ? '~' : '/')) return false;
10577
27.1k
            } else {
10578
27.1k
                if (*str != *token) return false;
10579
27.1k
            }
10580
31.4k
        }
10581
1.70k
        return true;
10582
4.93k
    }
10583
15.5k
}
10584
10585
/**
10586
 Get a value from array by token.
10587
 @param arr   an array, should not be NULL or non-array type
10588
 @param token a JSON pointer token
10589
 @param len   unescaped token length
10590
 @param esc   number of escaped characters in this token
10591
 @return value at index, or NULL if token is not index or index is out of range
10592
 */
10593
static_inline yyjson_val *ptr_arr_get(const yyjson_val *arr, const char *token,
10594
0
                                      usize len, usize esc) {
10595
0
    yyjson_val *val = unsafe_yyjson_get_first(arr);
10596
0
    usize num = unsafe_yyjson_get_len(arr), idx = 0;
10597
0
    if (unlikely(num == 0)) return NULL;
10598
0
    if (unlikely(!ptr_token_to_idx(token, len, &idx))) return NULL;
10599
0
    if (unlikely(idx >= num)) return NULL;
10600
0
    if (unsafe_yyjson_arr_is_flat(arr)) {
10601
0
        return val + idx;
10602
0
    } else {
10603
0
        while (idx-- > 0) val = unsafe_yyjson_get_next(val);
10604
0
        return val;
10605
0
    }
10606
0
}
10607
10608
/**
10609
 Get a value from object by token.
10610
 @param obj   [in] an object, should not be NULL or non-object type
10611
 @param token [in] a JSON pointer token
10612
 @param len   [in] unescaped token length
10613
 @param esc   [in] number of escaped characters in this token
10614
 @return value associated with the token, or NULL if no value
10615
 */
10616
static_inline yyjson_val *ptr_obj_get(const yyjson_val *obj, const char *token,
10617
0
                                      usize len, usize esc) {
10618
0
    yyjson_val *key = unsafe_yyjson_get_first(obj);
10619
0
    usize num = unsafe_yyjson_get_len(obj);
10620
0
    if (unlikely(num == 0)) return NULL;
10621
0
    for (; num > 0; num--, key = unsafe_yyjson_get_next(key + 1)) {
10622
0
        if (ptr_token_eq(key, token, len, esc)) return key + 1;
10623
0
    }
10624
0
    return NULL;
10625
0
}
10626
10627
/**
10628
 Get a value from array by token.
10629
 @param arr   [in] an array, should not be NULL or non-array type
10630
 @param token [in] a JSON pointer token
10631
 @param len   [in] unescaped token length
10632
 @param esc   [in] number of escaped characters in this token
10633
 @param pre   [out] previous (sibling) value of the returned value
10634
 @param last  [out] whether index is last
10635
 @return value at index, or NULL if token is not index or index is out of range
10636
 */
10637
static_inline yyjson_mut_val *ptr_mut_arr_get(const yyjson_mut_val *arr,
10638
                                              const char *token,
10639
                                              usize len, usize esc,
10640
                                              yyjson_mut_val **pre,
10641
22.4k
                                              bool *last) {
10642
22.4k
    yyjson_mut_val *val = (yyjson_mut_val *)arr->uni.ptr; /* last (tail) */
10643
22.4k
    usize num = unsafe_yyjson_get_len(arr), idx;
10644
22.4k
    if (last) *last = false;
10645
22.4k
    if (pre) *pre = NULL;
10646
22.4k
    if (unlikely(num == 0)) {
10647
434
        if (last && len == 1 && (*token == '0' || *token == '-')) *last = true;
10648
434
        return NULL;
10649
434
    }
10650
22.0k
    if (unlikely(!ptr_token_to_idx(token, len, &idx))) return NULL;
10651
21.8k
    if (last) *last = (idx == num || idx == USIZE_MAX);
10652
21.8k
    if (unlikely(idx >= num)) return NULL;
10653
65.1k
    while (idx-- > 0) val = val->next;
10654
18.9k
    if (pre) *pre = val;
10655
18.9k
    return val->next;
10656
21.8k
}
10657
10658
/**
10659
 Get a value from object by token.
10660
 @param obj   [in] an object, should not be NULL or non-object type
10661
 @param token [in] a JSON pointer token
10662
 @param len   [in] unescaped token length
10663
 @param esc   [in] number of escaped characters in this token
10664
 @param pre   [out] previous (sibling) key of the returned value's key
10665
 @return value associated with the token, or NULL if no value
10666
 */
10667
static_inline yyjson_mut_val *ptr_mut_obj_get(const yyjson_mut_val *obj,
10668
                                              const char *token,
10669
                                              usize len, usize esc,
10670
12.5k
                                              yyjson_mut_val **pre) {
10671
12.5k
    yyjson_mut_val *pre_key = (yyjson_mut_val *)obj->uni.ptr, *key;
10672
12.5k
    usize num = unsafe_yyjson_get_len(obj);
10673
12.5k
    if (pre) *pre = NULL;
10674
12.5k
    if (unlikely(num == 0)) return NULL;
10675
71.8k
    for (; num > 0; num--, pre_key = key) {
10676
66.7k
        key = pre_key->next->next;
10677
66.7k
        if (ptr_token_eq(key, token, len, esc)) {
10678
6.73k
            if (pre) *pre = pre_key;
10679
6.73k
            return key->next;
10680
6.73k
        }
10681
66.7k
    }
10682
5.16k
    return NULL;
10683
11.8k
}
10684
10685
/**
10686
 Create a string value with JSON pointer token.
10687
 @param token [in] a JSON pointer token
10688
 @param len   [in] unescaped token length
10689
 @param esc   [in] number of escaped characters in this token
10690
 @param doc   [in] used for memory allocation when creating value
10691
 @return new string value, or NULL if memory allocation failed
10692
 */
10693
static_inline yyjson_mut_val *ptr_new_key(const char *token,
10694
                                          usize len, usize esc,
10695
10.1k
                                          yyjson_mut_doc *doc) {
10696
10.1k
    const char *src = token;
10697
10.1k
    if (likely(!esc)) {
10698
7.97k
        return yyjson_mut_strncpy(doc, src, len);
10699
7.97k
    } else {
10700
2.13k
        const char *end = src + len + esc;
10701
2.13k
        char *dst = unsafe_yyjson_mut_str_alc(doc, len + esc);
10702
2.13k
        char *str = dst;
10703
2.13k
        if (unlikely(!dst)) return NULL;
10704
80.5k
        for (; src < end; src++, dst++) {
10705
78.4k
            if (*src != '~') *dst = *src;
10706
2.85k
            else *dst = (*++src == '0' ? '~' : '/');
10707
78.4k
        }
10708
2.12k
        *dst = '\0';
10709
2.12k
        return yyjson_mut_strn(doc, str, len);
10710
2.13k
    }
10711
10.1k
}
10712
10713
/* macros for yyjson_ptr */
10714
995
#define return_err(_ret, _code, _pos, _msg) do { \
10715
995
    if (err) { \
10716
995
        err->code = YYJSON_PTR_ERR_##_code; \
10717
995
        err->msg = _msg; \
10718
995
        err->pos = (usize)(_pos); \
10719
995
    } \
10720
995
    return _ret; \
10721
995
} while (false)
10722
10723
#define return_err_resolve(_ret, _pos) \
10724
934
    return_err(_ret, RESOLVE, _pos, "JSON pointer cannot be resolved")
10725
#define return_err_syntax(_ret, _pos) \
10726
54
    return_err(_ret, SYNTAX, _pos, "invalid escaped character")
10727
#define return_err_alloc(_ret) \
10728
7
    return_err(_ret, MEMORY_ALLOCATION, 0, "failed to create value")
10729
10730
yyjson_val *unsafe_yyjson_ptr_getx(const yyjson_val *val,
10731
                                   const char *ptr, size_t ptr_len,
10732
0
                                   yyjson_ptr_err *err) {
10733
10734
0
    const char *hdr = ptr, *end = ptr + ptr_len, *token;
10735
0
    usize len, esc;
10736
0
    yyjson_type type;
10737
10738
0
    while (true) {
10739
0
        token = ptr_next_token(&ptr, end, &len, &esc);
10740
0
        if (unlikely(!token)) return_err_syntax(NULL, ptr - hdr);
10741
0
        type = unsafe_yyjson_get_type(val);
10742
0
        if (type == YYJSON_TYPE_OBJ) {
10743
0
            val = ptr_obj_get(val, token, len, esc);
10744
0
        } else if (type == YYJSON_TYPE_ARR) {
10745
0
            val = ptr_arr_get(val, token, len, esc);
10746
0
        } else {
10747
0
            val = NULL;
10748
0
        }
10749
0
        if (!val) return_err_resolve(NULL, token - hdr);
10750
0
        if (ptr == end) return constcast(yyjson_val *)val;
10751
0
    }
10752
0
}
10753
10754
yyjson_mut_val *unsafe_yyjson_mut_ptr_getx(
10755
    const yyjson_mut_val *val, const char *ptr, size_t ptr_len,
10756
10.0k
    yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
10757
10758
10.0k
    const char *hdr = ptr, *end = ptr + ptr_len, *token;
10759
10.0k
    usize len, esc;
10760
10.0k
    yyjson_mut_val *ctn, *pre = NULL;
10761
10.0k
    yyjson_type type;
10762
10.0k
    bool idx_is_last = false;
10763
10764
10.6k
    while (true) {
10765
10.6k
        token = ptr_next_token(&ptr, end, &len, &esc);
10766
10.6k
        if (unlikely(!token)) return_err_syntax(NULL, ptr - hdr);
10767
10.6k
        ctn = constcast(yyjson_mut_val *)val;
10768
10.6k
        type = unsafe_yyjson_get_type(val);
10769
10.6k
        if (type == YYJSON_TYPE_OBJ) {
10770
1.92k
            val = ptr_mut_obj_get(val, token, len, esc, &pre);
10771
8.68k
        } else if (type == YYJSON_TYPE_ARR) {
10772
8.67k
            val = ptr_mut_arr_get(val, token, len, esc, &pre, &idx_is_last);
10773
8.67k
        } else {
10774
14
            val = NULL;
10775
14
        }
10776
10.6k
        if (ctx && (ptr == end)) {
10777
5.07k
            if (type == YYJSON_TYPE_OBJ ||
10778
4.81k
                (type == YYJSON_TYPE_ARR && (val || idx_is_last))) {
10779
4.81k
                ctx->ctn = ctn;
10780
4.81k
                ctx->pre = pre;
10781
4.81k
            }
10782
5.07k
        }
10783
10.6k
        if (!val) return_err_resolve(NULL, token - hdr);
10784
10.0k
        if (ptr == end) return constcast(yyjson_mut_val *)val;
10785
10.0k
    }
10786
10.0k
}
10787
10788
bool unsafe_yyjson_mut_ptr_putx(
10789
    yyjson_mut_val *val, const char *ptr, size_t ptr_len,
10790
    yyjson_mut_val *new_val, yyjson_mut_doc *doc, bool create_parent,
10791
21.8k
    bool insert_new, yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
10792
10793
21.8k
    const char *hdr = ptr, *end = ptr + ptr_len, *token;
10794
21.8k
    usize token_len, esc, ctn_len;
10795
21.8k
    yyjson_mut_val *ctn, *key, *pre = NULL;
10796
21.8k
    yyjson_mut_val *sep_ctn = NULL, *sep_key = NULL, *sep_val = NULL;
10797
21.8k
    yyjson_type ctn_type;
10798
21.8k
    bool idx_is_last = false;
10799
10800
    /* skip exist parent nodes */
10801
24.4k
    while (true) {
10802
24.4k
        token = ptr_next_token(&ptr, end, &token_len, &esc);
10803
24.4k
        if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
10804
24.4k
        ctn = val;
10805
24.4k
        ctn_type = unsafe_yyjson_get_type(ctn);
10806
24.4k
        if (ctn_type == YYJSON_TYPE_OBJ) {
10807
10.6k
            val = ptr_mut_obj_get(ctn, token, token_len, esc, &pre);
10808
13.8k
        } else if (ctn_type == YYJSON_TYPE_ARR) {
10809
13.8k
            val = ptr_mut_arr_get(ctn, token, token_len, esc, &pre,
10810
13.8k
                                  &idx_is_last);
10811
13.8k
        } else return_err_resolve(false, token - hdr);
10812
24.4k
        if (!val) break;
10813
15.6k
        if (ptr == end) break; /* is last token */
10814
15.6k
    }
10815
10816
    /* create parent nodes if not exist */
10817
21.8k
    if (unlikely(ptr != end)) { /* not last token */
10818
81
        if (!create_parent) return_err_resolve(false, token - hdr);
10819
10820
        /* add value at last index if container is array */
10821
0
        if (ctn_type == YYJSON_TYPE_ARR) {
10822
0
            if (!idx_is_last || !insert_new) {
10823
0
                return_err_resolve(false, token - hdr);
10824
0
            }
10825
0
            val = yyjson_mut_obj(doc);
10826
0
            if (!val) return_err_alloc(false);
10827
10828
            /* delay attaching until all operations are completed */
10829
0
            sep_ctn = ctn;
10830
0
            sep_key = NULL;
10831
0
            sep_val = val;
10832
10833
            /* move to next token */
10834
0
            ctn = val;
10835
0
            val = NULL;
10836
0
            ctn_type = YYJSON_TYPE_OBJ;
10837
0
            token = ptr_next_token(&ptr, end, &token_len, &esc);
10838
0
            if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
10839
0
        }
10840
10841
        /* container is object, create parent nodes */
10842
0
        while (ptr != end) { /* not last token */
10843
0
            key = ptr_new_key(token, token_len, esc, doc);
10844
0
            if (!key) return_err_alloc(false);
10845
0
            val = yyjson_mut_obj(doc);
10846
0
            if (!val) return_err_alloc(false);
10847
10848
            /* delay attaching until all operations are completed */
10849
0
            if (!sep_ctn) {
10850
0
                sep_ctn = ctn;
10851
0
                sep_key = key;
10852
0
                sep_val = val;
10853
0
            } else {
10854
0
                yyjson_mut_obj_add(ctn, key, val);
10855
0
            }
10856
10857
            /* move to next token */
10858
0
            ctn = val;
10859
0
            val = NULL;
10860
0
            token = ptr_next_token(&ptr, end, &token_len, &esc);
10861
0
            if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
10862
0
        }
10863
0
    }
10864
10865
    /* JSON pointer is resolved, insert or replace target value */
10866
21.7k
    ctn_len = unsafe_yyjson_get_len(ctn);
10867
21.7k
    if (ctn_type == YYJSON_TYPE_OBJ) {
10868
10.1k
        if (ctx) ctx->ctn = ctn;
10869
10.1k
        if (!val || insert_new) {
10870
            /* insert new key-value pair */
10871
10.1k
            key = ptr_new_key(token, token_len, esc, doc);
10872
10.1k
            if (unlikely(!key)) return_err_alloc(false);
10873
10.0k
            if (ctx) ctx->pre = ctn_len ? (yyjson_mut_val *)ctn->uni.ptr : key;
10874
10.0k
            unsafe_yyjson_mut_obj_add(ctn, key, new_val, ctn_len);
10875
10.0k
        } else {
10876
            /* replace exist value */
10877
0
            key = pre->next->next;
10878
0
            if (ctx) ctx->pre = pre;
10879
0
            if (ctx) ctx->old = val;
10880
0
            yyjson_mut_obj_put(ctn, key, new_val);
10881
0
        }
10882
11.6k
    } else {
10883
        /* array */
10884
11.6k
        if (ctx && (val || idx_is_last)) ctx->ctn = ctn;
10885
11.6k
        if (insert_new) {
10886
            /* append new value */
10887
11.6k
            if (val) {
10888
8.50k
                pre->next = new_val;
10889
8.50k
                new_val->next = val;
10890
8.50k
                if (ctx) ctx->pre = pre;
10891
8.50k
                unsafe_yyjson_set_len(ctn, ctn_len + 1);
10892
8.50k
            } else if (idx_is_last) {
10893
2.87k
                if (ctx) ctx->pre = ctn_len ?
10894
0
                    (yyjson_mut_val *)ctn->uni.ptr : new_val;
10895
2.87k
                yyjson_mut_arr_append(ctn, new_val);
10896
2.87k
            } else {
10897
258
                return_err_resolve(false, token - hdr);
10898
258
            }
10899
11.6k
        } else {
10900
            /* replace exist value */
10901
0
            if (!val) return_err_resolve(false, token - hdr);
10902
0
            if (ctn_len > 1) {
10903
0
                new_val->next = val->next;
10904
0
                pre->next = new_val;
10905
0
                if (ctn->uni.ptr == val) ctn->uni.ptr = new_val;
10906
0
            } else {
10907
0
                new_val->next = new_val;
10908
0
                ctn->uni.ptr = new_val;
10909
0
                pre = new_val;
10910
0
            }
10911
0
            if (ctx) ctx->pre = pre;
10912
0
            if (ctx) ctx->old = val;
10913
0
        }
10914
11.6k
    }
10915
10916
    /* all operations are completed, attach the new components to the target */
10917
21.4k
    if (unlikely(sep_ctn)) {
10918
0
        if (sep_key) yyjson_mut_obj_add(sep_ctn, sep_key, sep_val);
10919
0
        else yyjson_mut_arr_append(sep_ctn, sep_val);
10920
0
    }
10921
21.4k
    return true;
10922
21.7k
}
10923
10924
yyjson_mut_val *unsafe_yyjson_mut_ptr_replacex(
10925
    yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val,
10926
2.90k
    yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
10927
10928
2.90k
    yyjson_mut_val *cur_val;
10929
2.90k
    yyjson_ptr_ctx cur_ctx;
10930
2.90k
    memset(&cur_ctx, 0, sizeof(cur_ctx));
10931
2.90k
    if (!ctx) ctx = &cur_ctx;
10932
2.90k
    cur_val = unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err);
10933
2.90k
    if (!cur_val) return NULL;
10934
10935
2.86k
    if (yyjson_mut_is_obj(ctx->ctn)) {
10936
396
        yyjson_mut_val *key = ctx->pre->next->next;
10937
396
        yyjson_mut_obj_put(ctx->ctn, key, new_val);
10938
2.46k
    } else {
10939
2.46k
        yyjson_ptr_ctx_replace(ctx, new_val);
10940
2.46k
    }
10941
2.86k
    ctx->old = cur_val;
10942
2.86k
    return cur_val;
10943
2.90k
}
10944
10945
yyjson_mut_val *unsafe_yyjson_mut_ptr_removex(
10946
    yyjson_mut_val *val, const char *ptr, size_t len,
10947
2.24k
    yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
10948
10949
2.24k
    yyjson_mut_val *cur_val;
10950
2.24k
    yyjson_ptr_ctx cur_ctx;
10951
2.24k
    memset(&cur_ctx, 0, sizeof(cur_ctx));
10952
2.24k
    if (!ctx) ctx = &cur_ctx;
10953
2.24k
    cur_val = unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err);
10954
2.24k
    if (cur_val) {
10955
1.87k
        if (yyjson_mut_is_obj(ctx->ctn)) {
10956
456
            yyjson_mut_val *key = ctx->pre->next->next;
10957
456
            yyjson_mut_obj_put(ctx->ctn, key, NULL);
10958
1.41k
        } else {
10959
1.41k
            yyjson_ptr_ctx_remove(ctx);
10960
1.41k
        }
10961
1.87k
        ctx->pre = NULL;
10962
1.87k
        ctx->old = cur_val;
10963
1.87k
    }
10964
2.24k
    return cur_val;
10965
2.24k
}
10966
10967
/* macros for yyjson_ptr */
10968
#undef return_err
10969
#undef return_err_resolve
10970
#undef return_err_syntax
10971
#undef return_err_alloc
10972
10973
10974
10975
/*==============================================================================
10976
 * MARK: - JSON Patch API (RFC 6902) (Public)
10977
 *============================================================================*/
10978
10979
/* JSON Patch operation */
10980
typedef enum patch_op {
10981
    PATCH_OP_ADD,       /* path, value */
10982
    PATCH_OP_REMOVE,    /* path */
10983
    PATCH_OP_REPLACE,   /* path, value */
10984
    PATCH_OP_MOVE,      /* from, path */
10985
    PATCH_OP_COPY,      /* from, path */
10986
    PATCH_OP_TEST,      /* path, value */
10987
    PATCH_OP_NONE       /* invalid */
10988
} patch_op;
10989
10990
29.5k
static patch_op patch_op_get(yyjson_val *op) {
10991
29.5k
    const char *str = op->uni.str;
10992
29.5k
    switch (unsafe_yyjson_get_len(op)) {
10993
7.49k
        case 3:
10994
7.49k
            if (!memcmp(str, "add", 3)) return PATCH_OP_ADD;
10995
16
            return PATCH_OP_NONE;
10996
17.9k
        case 4:
10997
17.9k
            if (!memcmp(str, "move", 4)) return PATCH_OP_MOVE;
10998
16.4k
            if (!memcmp(str, "copy", 4)) return PATCH_OP_COPY;
10999
1.72k
            if (!memcmp(str, "test", 4)) return PATCH_OP_TEST;
11000
35
            return PATCH_OP_NONE;
11001
966
        case 6:
11002
966
            if (!memcmp(str, "remove", 6)) return PATCH_OP_REMOVE;
11003
19
            return PATCH_OP_NONE;
11004
3.10k
        case 7:
11005
3.10k
            if (!memcmp(str, "replace", 7)) return PATCH_OP_REPLACE;
11006
31
            return PATCH_OP_NONE;
11007
84
        default:
11008
84
            return PATCH_OP_NONE;
11009
29.5k
    }
11010
29.5k
}
11011
11012
/* macros for yyjson_patch */
11013
3.17k
#define return_err(_code, _msg) do { \
11014
3.17k
    if (err->ptr.code == YYJSON_PTR_ERR_MEMORY_ALLOCATION) { \
11015
7
        err->code = YYJSON_PATCH_ERROR_MEMORY_ALLOCATION; \
11016
7
        err->msg = _msg; \
11017
7
        memset(&err->ptr, 0, sizeof(yyjson_ptr_err)); \
11018
3.16k
    } else { \
11019
3.16k
        err->code = YYJSON_PATCH_ERROR_##_code; \
11020
3.16k
        err->msg = _msg; \
11021
3.16k
        err->idx = iter.idx ? iter.idx - 1 : 0; \
11022
3.16k
    } \
11023
3.17k
    return NULL; \
11024
3.17k
} while (false)
11025
11026
#define return_err_copy() \
11027
205
    return_err(MEMORY_ALLOCATION, "failed to copy value")
11028
#define return_err_key(_key) \
11029
752
    return_err(MISSING_KEY, "missing key " _key)
11030
#define return_err_val(_key) \
11031
16
    return_err(INVALID_MEMBER, "invalid member " _key)
11032
11033
16.3k
#define ptr_get(_ptr) yyjson_mut_ptr_getx( \
11034
16.3k
    root, _ptr->uni.str, _ptr##_len, NULL, &err->ptr)
11035
#define ptr_add(_ptr, _val) yyjson_mut_ptr_addx( \
11036
    root, _ptr->uni.str, _ptr##_len, _val, doc, false, NULL, &err->ptr)
11037
1.35k
#define ptr_remove(_ptr) yyjson_mut_ptr_removex( \
11038
1.35k
    root, _ptr->uni.str, _ptr##_len, NULL, &err->ptr)
11039
#define ptr_replace(_ptr, _val)yyjson_mut_ptr_replacex( \
11040
    root, _ptr->uni.str, _ptr##_len, _val, NULL, &err->ptr)
11041
11042
yyjson_mut_val *yyjson_patch(yyjson_mut_doc *doc,
11043
                             const yyjson_val *orig,
11044
                             const yyjson_val *patch,
11045
5.79k
                             yyjson_patch_err *err) {
11046
11047
5.79k
    yyjson_mut_val *root;
11048
5.79k
    yyjson_val *obj;
11049
5.79k
    yyjson_arr_iter iter;
11050
5.79k
    yyjson_patch_err err_tmp;
11051
5.79k
    if (!err) err = &err_tmp;
11052
5.79k
    memset(err, 0, sizeof(*err));
11053
5.79k
    memset(&iter, 0, sizeof(iter));
11054
11055
5.79k
    if (unlikely(!doc || !orig || !patch)) {
11056
0
        return_err(INVALID_PARAMETER, "input parameter is NULL");
11057
0
    }
11058
5.79k
    if (unlikely(!yyjson_is_arr(patch))) {
11059
115
        return_err(INVALID_PARAMETER, "input patch is not array");
11060
115
    }
11061
5.67k
    root = yyjson_val_mut_copy(doc, orig);
11062
5.67k
    if (unlikely(!root)) return_err_copy();
11063
11064
    /* iterate through the patch array */
11065
5.67k
    yyjson_arr_iter_init(patch, &iter);
11066
19.2k
    while ((obj = yyjson_arr_iter_next(&iter))) {
11067
15.0k
        patch_op op_enum;
11068
15.0k
        yyjson_val *op, *path, *from = NULL, *value;
11069
15.0k
        yyjson_mut_val *val = NULL, *test;
11070
15.0k
        usize path_len, from_len = 0;
11071
15.0k
        if (unlikely(!unsafe_yyjson_is_obj(obj))) {
11072
19
            return_err(INVALID_OPERATION, "JSON patch operation is not object");
11073
19
        }
11074
11075
        /* get required member: op */
11076
14.9k
        op = yyjson_obj_get(obj, "op");
11077
14.9k
        if (unlikely(!op)) return_err_key("`op`");
11078
14.8k
        if (unlikely(!yyjson_is_str(op))) return_err_val("`op`");
11079
14.8k
        op_enum = patch_op_get(op);
11080
11081
        /* get required member: path */
11082
14.8k
        path = yyjson_obj_get(obj, "path");
11083
14.8k
        if (unlikely(!path)) return_err_key("`path`");
11084
14.6k
        if (unlikely(!yyjson_is_str(path))) return_err_val("`path`");
11085
14.6k
        path_len = unsafe_yyjson_get_len(path);
11086
11087
        /* get required member: value, from */
11088
14.6k
        switch ((int)op_enum) {
11089
6.09k
            case PATCH_OP_ADD: case PATCH_OP_REPLACE: case PATCH_OP_TEST:
11090
6.09k
                value = yyjson_obj_get(obj, "value");
11091
6.09k
                if (unlikely(!value)) return_err_key("`value`");
11092
6.03k
                val = yyjson_val_mut_copy(doc, value);
11093
6.03k
                if (unlikely(!val)) return_err_copy();
11094
6.03k
                break;
11095
8.10k
            case PATCH_OP_MOVE: case PATCH_OP_COPY:
11096
8.10k
                from = yyjson_obj_get(obj, "from");
11097
8.10k
                if (unlikely(!from)) return_err_key("`from`");
11098
8.06k
                if (unlikely(!yyjson_is_str(from))) return_err_val("`from`");
11099
8.06k
                from_len = unsafe_yyjson_get_len(from);
11100
8.06k
                break;
11101
498
            default:
11102
498
                break;
11103
14.6k
        }
11104
11105
        /* perform an operation */
11106
14.6k
        switch ((int)op_enum) {
11107
3.67k
            case PATCH_OP_ADD: /* add(path, val) */
11108
3.67k
                if (unlikely(path_len == 0)) { root = val; break; }
11109
3.20k
                if (unlikely(!ptr_add(path, val))) {
11110
121
                    return_err(POINTER, "failed to add `path`");
11111
121
                }
11112
3.08k
                break;
11113
3.08k
            case PATCH_OP_REMOVE: /* remove(path) */
11114
468
                if (unlikely(!ptr_remove(path))) {
11115
162
                    return_err(POINTER, "failed to remove `path`");
11116
162
                }
11117
306
                break;
11118
1.53k
            case PATCH_OP_REPLACE: /* replace(path, val) */
11119
1.53k
                if (unlikely(path_len == 0)) { root = val; break; }
11120
1.45k
                if (unlikely(!ptr_replace(path, val))) {
11121
27
                    return_err(POINTER, "failed to replace `path`");
11122
27
                }
11123
1.43k
                break;
11124
1.43k
            case PATCH_OP_MOVE: /* val = remove(from), add(path, val) */
11125
723
                if (unlikely(from_len == 0 && path_len == 0)) break;
11126
687
                val = ptr_remove(from);
11127
687
                if (unlikely(!val)) {
11128
52
                    return_err(POINTER, "failed to remove `from`");
11129
52
                }
11130
635
                if (unlikely(path_len == 0)) { root = val; break; }
11131
596
                if (unlikely(!ptr_add(path, val))) {
11132
41
                    return_err(POINTER, "failed to add `path`");
11133
41
                }
11134
555
                break;
11135
7.34k
            case PATCH_OP_COPY: /* val = get(from).copy, add(path, val) */
11136
7.34k
                val = ptr_get(from);
11137
7.34k
                if (unlikely(!val)) {
11138
29
                    return_err(POINTER, "failed to get `from`");
11139
29
                }
11140
7.31k
                if (unlikely(path_len == 0)) { root = val; break; }
11141
7.26k
                val = yyjson_mut_val_mut_copy(doc, val);
11142
7.26k
                if (unlikely(!val)) return_err_copy();
11143
7.24k
                if (unlikely(!ptr_add(path, val))) {
11144
74
                    return_err(POINTER, "failed to add `path`");
11145
74
                }
11146
7.17k
                break;
11147
7.17k
            case PATCH_OP_TEST: /* test = get(path), test.eq(val) */
11148
825
                test = ptr_get(path);
11149
825
                if (unlikely(!test)) {
11150
89
                    return_err(POINTER, "failed to get `path`");
11151
89
                }
11152
736
                if (unlikely(!yyjson_mut_equals(val, test))) {
11153
368
                    return_err(EQUAL, "failed to test equal");
11154
368
                }
11155
368
                break;
11156
368
            default:
11157
30
                return_err(INVALID_MEMBER, "unsupported `op`");
11158
14.6k
        }
11159
14.6k
    }
11160
4.25k
    return root;
11161
5.67k
}
11162
11163
yyjson_mut_val *yyjson_mut_patch(yyjson_mut_doc *doc,
11164
                                 const yyjson_mut_val *orig,
11165
                                 const yyjson_mut_val *patch,
11166
5.79k
                                 yyjson_patch_err *err) {
11167
5.79k
    yyjson_mut_val *root, *obj;
11168
5.79k
    yyjson_mut_arr_iter iter;
11169
5.79k
    yyjson_patch_err err_tmp;
11170
5.79k
    if (!err) err = &err_tmp;
11171
5.79k
    memset(err, 0, sizeof(*err));
11172
5.79k
    memset(&iter, 0, sizeof(iter));
11173
11174
5.79k
    if (unlikely(!doc || !orig || !patch)) {
11175
0
        return_err(INVALID_PARAMETER, "input parameter is NULL");
11176
0
    }
11177
5.79k
    if (unlikely(!yyjson_mut_is_arr(patch))) {
11178
115
        return_err(INVALID_PARAMETER, "input patch is not array");
11179
115
    }
11180
5.67k
    root = yyjson_mut_val_mut_copy(doc, orig);
11181
5.67k
    if (unlikely(!root)) return_err_copy();
11182
11183
    /* iterate through the patch array */
11184
5.67k
    yyjson_mut_arr_iter_init(constcast(yyjson_mut_val *)patch, &iter);
11185
19.1k
    while ((obj = yyjson_mut_arr_iter_next(&iter))) {
11186
14.9k
        patch_op op_enum;
11187
14.9k
        yyjson_mut_val *op, *path, *from = NULL, *value;
11188
14.9k
        yyjson_mut_val *val = NULL, *test;
11189
14.9k
        usize path_len, from_len = 0;
11190
14.9k
        if (!unsafe_yyjson_is_obj(obj)) {
11191
19
            return_err(INVALID_OPERATION, "JSON patch operation is not object");
11192
19
        }
11193
11194
        /* get required member: op */
11195
14.9k
        op = yyjson_mut_obj_get(obj, "op");
11196
14.9k
        if (unlikely(!op)) return_err_key("`op`");
11197
14.7k
        if (unlikely(!yyjson_mut_is_str(op))) return_err_val("`op`");
11198
14.7k
        op_enum = patch_op_get((yyjson_val *)(void *)op);
11199
11200
        /* get required member: path */
11201
14.7k
        path = yyjson_mut_obj_get(obj, "path");
11202
14.7k
        if (unlikely(!path)) return_err_key("`path`");
11203
14.6k
        if (unlikely(!yyjson_mut_is_str(path))) return_err_val("`path`");
11204
14.6k
        path_len = unsafe_yyjson_get_len(path);
11205
11206
        /* get required member: value, from */
11207
14.6k
        switch ((int)op_enum) {
11208
6.08k
            case PATCH_OP_ADD: case PATCH_OP_REPLACE: case PATCH_OP_TEST:
11209
6.08k
                value = yyjson_mut_obj_get(obj, "value");
11210
6.08k
                if (unlikely(!value)) return_err_key("`value`");
11211
6.02k
                val = yyjson_mut_val_mut_copy(doc, value);
11212
6.02k
                if (unlikely(!val)) return_err_copy();
11213
6.02k
                break;
11214
8.07k
            case PATCH_OP_MOVE: case PATCH_OP_COPY:
11215
8.07k
                from = yyjson_mut_obj_get(obj, "from");
11216
8.07k
                if (unlikely(!from)) return_err_key("`from`");
11217
8.04k
                if (unlikely(!yyjson_mut_is_str(from))) {
11218
1
                    return_err_val("`from`");
11219
1
                }
11220
8.04k
                from_len = unsafe_yyjson_get_len(from);
11221
8.04k
                break;
11222
487
            default:
11223
487
                break;
11224
14.6k
        }
11225
11226
        /* perform an operation */
11227
14.5k
        switch ((int)op_enum) {
11228
3.67k
            case PATCH_OP_ADD: /* add(path, val) */
11229
3.67k
                if (unlikely(path_len == 0)) { root = val; break; }
11230
3.20k
                if (unlikely(!ptr_add(path, val))) {
11231
120
                    return_err(POINTER, "failed to add `path`");
11232
120
                }
11233
3.08k
                break;
11234
3.08k
            case PATCH_OP_REMOVE: /* remove(path) */
11235
465
                if (unlikely(!ptr_remove(path))) {
11236
161
                    return_err(POINTER, "failed to remove `path`");
11237
161
                }
11238
304
                break;
11239
1.53k
            case PATCH_OP_REPLACE: /* replace(path, val) */
11240
1.53k
                if (unlikely(path_len == 0)) { root = val; break; }
11241
1.45k
                if (unlikely(!ptr_replace(path, val))) {
11242
25
                    return_err(POINTER, "failed to replace `path`");
11243
25
                }
11244
1.43k
                break;
11245
1.43k
            case PATCH_OP_MOVE: /* val = remove(from), add(path, val) */
11246
705
                if (unlikely(from_len == 0 && path_len == 0)) break;
11247
669
                val = ptr_remove(from);
11248
669
                if (unlikely(!val)) {
11249
39
                    return_err(POINTER, "failed to remove `from`");
11250
39
                }
11251
630
                if (unlikely(path_len == 0)) { root = val; break; }
11252
591
                if (unlikely(!ptr_add(path, val))) {
11253
41
                    return_err(POINTER, "failed to add `path`");
11254
41
                }
11255
550
                break;
11256
7.33k
            case PATCH_OP_COPY: /* val = get(from).copy, add(path, val) */
11257
7.33k
                val = ptr_get(from);
11258
7.33k
                if (unlikely(!val)) {
11259
26
                    return_err(POINTER, "failed to get `from`");
11260
26
                }
11261
7.31k
                if (unlikely(path_len == 0)) { root = val; break; }
11262
7.26k
                val = yyjson_mut_val_mut_copy(doc, val);
11263
7.26k
                if (unlikely(!val)) return_err_copy();
11264
7.07k
                if (unlikely(!ptr_add(path, val))) {
11265
53
                    return_err(POINTER, "failed to add `path`");
11266
53
                }
11267
7.02k
                break;
11268
7.02k
            case PATCH_OP_TEST: /* test = get(path), test.eq(val) */
11269
819
                test = ptr_get(path);
11270
819
                if (unlikely(!test)) {
11271
89
                    return_err(POINTER, "failed to get `path`");
11272
89
                }
11273
730
                if (unlikely(!yyjson_mut_equals(val, test))) {
11274
363
                    return_err(EQUAL, "failed to test equal");
11275
363
                }
11276
367
                break;
11277
367
            default:
11278
22
                return_err(INVALID_MEMBER, "unsupported `op`");
11279
14.5k
        }
11280
14.5k
    }
11281
4.15k
    return root;
11282
5.67k
}
11283
11284
/* macros for yyjson_patch */
11285
#undef return_err
11286
#undef return_err_copy
11287
#undef return_err_key
11288
#undef return_err_val
11289
#undef ptr_get
11290
#undef ptr_add
11291
#undef ptr_remove
11292
#undef ptr_replace
11293
11294
11295
11296
/*==============================================================================
11297
 * MARK: - JSON Merge-Patch API (RFC 7386) (Public)
11298
 *============================================================================*/
11299
11300
yyjson_mut_val *yyjson_merge_patch(yyjson_mut_doc *doc,
11301
                                   const yyjson_val *orig,
11302
18.6k
                                   const yyjson_val *patch) {
11303
18.6k
    usize idx, max;
11304
18.6k
    yyjson_val *key, *orig_val, *patch_val, local_orig;
11305
18.6k
    yyjson_mut_val *builder, *mut_key, *mut_val, *merged_val;
11306
11307
18.6k
    if (unlikely(!yyjson_is_obj(patch))) {
11308
9.08k
        return yyjson_val_mut_copy(doc, patch);
11309
9.08k
    }
11310
11311
9.56k
    builder = yyjson_mut_obj(doc);
11312
9.56k
    if (unlikely(!builder)) return NULL;
11313
11314
9.56k
    memset(&local_orig, 0, sizeof(local_orig));
11315
9.56k
    if (!yyjson_is_obj(orig)) {
11316
4.75k
        local_orig.tag = builder->tag;
11317
4.75k
        local_orig.uni = builder->uni;
11318
4.75k
        orig = &local_orig;
11319
4.75k
    }
11320
11321
    /* If orig is contributing, copy any items not modified by the patch */
11322
9.56k
    if (orig != &local_orig) {
11323
5.11k
        yyjson_obj_foreach(orig, idx, max, key, orig_val) {
11324
5.11k
            patch_val = yyjson_obj_getn(patch,
11325
5.11k
                                        unsafe_yyjson_get_str(key),
11326
5.11k
                                        unsafe_yyjson_get_len(key));
11327
5.11k
            if (!patch_val) {
11328
4.69k
                mut_key = yyjson_val_mut_copy(doc, key);
11329
4.69k
                mut_val = yyjson_val_mut_copy(doc, orig_val);
11330
4.69k
                if (!yyjson_mut_obj_add(builder, mut_key, mut_val)) return NULL;
11331
4.69k
            }
11332
5.11k
        }
11333
4.81k
    }
11334
11335
    /* Merge items modified by the patch. */
11336
14.8k
    yyjson_obj_foreach(patch, idx, max, key, patch_val) {
11337
        /* null indicates the field is removed. */
11338
14.8k
        if (unsafe_yyjson_is_null(patch_val)) {
11339
200
            continue;
11340
200
        }
11341
14.6k
        mut_key = yyjson_val_mut_copy(doc, key);
11342
14.6k
        orig_val = yyjson_obj_getn(orig,
11343
14.6k
                                   unsafe_yyjson_get_str(key),
11344
14.6k
                                   unsafe_yyjson_get_len(key));
11345
14.6k
        merged_val = yyjson_merge_patch(doc, orig_val, patch_val);
11346
14.6k
        if (!yyjson_mut_obj_add(builder, mut_key, merged_val)) return NULL;
11347
14.6k
    }
11348
11349
9.56k
    return builder;
11350
9.56k
}
11351
11352
yyjson_mut_val *yyjson_mut_merge_patch(yyjson_mut_doc *doc,
11353
                                       const yyjson_mut_val *orig,
11354
18.6k
                                       const yyjson_mut_val *patch) {
11355
18.6k
    usize idx, max;
11356
18.6k
    yyjson_mut_val *key, *orig_val, *patch_val, local_orig;
11357
18.6k
    yyjson_mut_val *builder, *mut_key, *mut_val, *merged_val;
11358
11359
18.6k
    if (unlikely(!yyjson_mut_is_obj(patch))) {
11360
9.08k
        return yyjson_mut_val_mut_copy(doc, patch);
11361
9.08k
    }
11362
11363
9.56k
    builder = yyjson_mut_obj(doc);
11364
9.56k
    if (unlikely(!builder)) return NULL;
11365
11366
9.56k
    memset(&local_orig, 0, sizeof(local_orig));
11367
9.56k
    if (!yyjson_mut_is_obj(orig)) {
11368
4.75k
        local_orig.tag = builder->tag;
11369
4.75k
        local_orig.uni = builder->uni;
11370
4.75k
        orig = &local_orig;
11371
4.75k
    }
11372
11373
    /* If orig is contributing, copy any items not modified by the patch */
11374
9.56k
    if (orig != &local_orig) {
11375
5.11k
        yyjson_mut_obj_foreach(orig, idx, max, key, orig_val) {
11376
5.11k
            patch_val = yyjson_mut_obj_getn(patch,
11377
5.11k
                                            unsafe_yyjson_get_str(key),
11378
5.11k
                                            unsafe_yyjson_get_len(key));
11379
5.11k
            if (!patch_val) {
11380
4.69k
                mut_key = yyjson_mut_val_mut_copy(doc, key);
11381
4.69k
                mut_val = yyjson_mut_val_mut_copy(doc, orig_val);
11382
4.69k
                if (!yyjson_mut_obj_add(builder, mut_key, mut_val)) return NULL;
11383
4.69k
            }
11384
5.11k
        }
11385
4.81k
    }
11386
11387
    /* Merge items modified by the patch. */
11388
14.8k
    yyjson_mut_obj_foreach(patch, idx, max, key, patch_val) {
11389
        /* null indicates the field is removed. */
11390
14.8k
        if (unsafe_yyjson_is_null(patch_val)) {
11391
200
            continue;
11392
200
        }
11393
14.6k
        mut_key = yyjson_mut_val_mut_copy(doc, key);
11394
14.6k
        orig_val = yyjson_mut_obj_getn(orig,
11395
14.6k
                                       unsafe_yyjson_get_str(key),
11396
14.6k
                                       unsafe_yyjson_get_len(key));
11397
14.6k
        merged_val = yyjson_mut_merge_patch(doc, orig_val, patch_val);
11398
14.6k
        if (!yyjson_mut_obj_add(builder, mut_key, merged_val)) return NULL;
11399
14.6k
    }
11400
11401
9.56k
    return builder;
11402
9.56k
}
11403
11404
#endif /* YYJSON_DISABLE_UTILS */