File Coverage

yyjson.c
Criterion Covered Total %
statement 1513 3688 41.0
branch 1329 9478 14.0
condition n/a
subroutine n/a
pod n/a
total 2842 13166 21.5


line stmt bran cond sub pod time code
1             /*==============================================================================
2             Copyright (c) 2020 YaoYuan
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             #include
25              
26              
27              
28             /*==============================================================================
29             * Warning Suppress
30             *============================================================================*/
31              
32             #if defined(__clang__)
33             # pragma clang diagnostic ignored "-Wunused-function"
34             # pragma clang diagnostic ignored "-Wunused-parameter"
35             # pragma clang diagnostic ignored "-Wunused-label"
36             # pragma clang diagnostic ignored "-Wunused-macros"
37             # pragma clang diagnostic ignored "-Wunused-variable"
38             #elif defined(__GNUC__)
39             # pragma GCC diagnostic ignored "-Wunused-function"
40             # pragma GCC diagnostic ignored "-Wunused-parameter"
41             # pragma GCC diagnostic ignored "-Wunused-label"
42             # pragma GCC diagnostic ignored "-Wunused-macros"
43             # pragma GCC diagnostic ignored "-Wunused-variable"
44             #elif defined(_MSC_VER)
45             # pragma warning(disable:4100) /* unreferenced formal parameter */
46             # pragma warning(disable:4101) /* unreferenced variable */
47             # pragma warning(disable:4102) /* unreferenced label */
48             # pragma warning(disable:4127) /* conditional expression is constant */
49             # pragma warning(disable:4706) /* assignment within conditional expression */
50             #endif
51              
52              
53              
54             /*==============================================================================
55             * Version
56             *============================================================================*/
57              
58 0           uint32_t yyjson_version(void) {
59 0           return YYJSON_VERSION_HEX;
60             }
61              
62              
63              
64             /*==============================================================================
65             * Flags
66             *============================================================================*/
67              
68             /* msvc intrinsic */
69             #if YYJSON_MSC_VER >= 1400
70             # include
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             #if defined(__SIZEOF_INT128__) && (__SIZEOF_INT128__ == 16) && \
113             (defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER))
114             # define YYJSON_HAS_INT128 1
115             #else
116             # define YYJSON_HAS_INT128 0
117             #endif
118              
119             /* IEEE 754 floating-point binary representation */
120             #if defined(__STDC_IEC_559__) || defined(__STDC_IEC_60559_BFP__)
121             # define YYJSON_HAS_IEEE_754 1
122             #elif (FLT_RADIX == 2) && (DBL_MANT_DIG == 53) && (DBL_DIG == 15) && \
123             (DBL_MIN_EXP == -1021) && (DBL_MAX_EXP == 1024) && \
124             (DBL_MIN_10_EXP == -307) && (DBL_MAX_10_EXP == 308)
125             # define YYJSON_HAS_IEEE_754 1
126             #else
127             # define YYJSON_HAS_IEEE_754 0
128             #endif
129              
130             /*
131             Correct rounding in double number computations.
132            
133             On the x86 architecture, some compilers may use x87 FPU instructions for
134             floating-point arithmetic. The x87 FPU loads all floating point number as
135             80-bit double-extended precision internally, then rounds the result to original
136             precision, which may produce inaccurate results. For a more detailed
137             explanation, see the paper: https://arxiv.org/abs/cs/0701192
138            
139             Here are some examples of double precision calculation error:
140            
141             2877.0 / 1e6 == 0.002877, but x87 returns 0.0028770000000000002
142             43683.0 * 1e21 == 4.3683e25, but x87 returns 4.3683000000000004e25
143            
144             Here are some examples of compiler flags to generate x87 instructions on x86:
145            
146             clang -m32 -mno-sse
147             gcc/icc -m32 -mfpmath=387
148             msvc /arch:SSE or /arch:IA32
149            
150             If we are sure that there's no similar error described above, we can define the
151             YYJSON_DOUBLE_MATH_CORRECT as 1 to enable the fast path calculation. This is
152             not an accurate detection, it's just try to avoid the error at compile-time.
153             An accurate detection can be done at run-time:
154            
155             bool is_double_math_correct(void) {
156             volatile double r = 43683.0;
157             r *= 1e21;
158             return r == 4.3683e25;
159             }
160            
161             See also: utils.h in https://github.com/google/double-conversion/
162             */
163             #if !defined(FLT_EVAL_METHOD) && defined(__FLT_EVAL_METHOD__)
164             # define FLT_EVAL_METHOD __FLT_EVAL_METHOD__
165             #endif
166              
167             #if defined(FLT_EVAL_METHOD) && FLT_EVAL_METHOD != 0 && FLT_EVAL_METHOD != 1
168             # define YYJSON_DOUBLE_MATH_CORRECT 0
169             #elif defined(i386) || defined(__i386) || defined(__i386__) || \
170             defined(_X86_) || defined(__X86__) || defined(_M_IX86) || \
171             defined(__I86__) || defined(__IA32__) || defined(__THW_INTEL)
172             # if (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP == 2) || \
173             (defined(__SSE2_MATH__) && __SSE2_MATH__)
174             # define YYJSON_DOUBLE_MATH_CORRECT 1
175             # else
176             # define YYJSON_DOUBLE_MATH_CORRECT 0
177             # endif
178             #elif defined(__mc68000__) || defined(__pnacl__) || defined(__native_client__)
179             # define YYJSON_DOUBLE_MATH_CORRECT 0
180             #else
181             # define YYJSON_DOUBLE_MATH_CORRECT 1
182             #endif
183              
184             /* endian */
185             #if yyjson_has_include()
186             # include /* POSIX */
187             #endif
188             #if yyjson_has_include()
189             # include /* Linux */
190             #elif yyjson_has_include()
191             # include /* BSD, Android */
192             #elif yyjson_has_include()
193             # include /* BSD, Darwin */
194             #endif
195              
196             #define YYJSON_BIG_ENDIAN 4321
197             #define YYJSON_LITTLE_ENDIAN 1234
198              
199             #if defined(BYTE_ORDER) && BYTE_ORDER
200             # if defined(BIG_ENDIAN) && (BYTE_ORDER == BIG_ENDIAN)
201             # define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
202             # elif defined(LITTLE_ENDIAN) && (BYTE_ORDER == LITTLE_ENDIAN)
203             # define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
204             # endif
205              
206             #elif defined(__BYTE_ORDER) && __BYTE_ORDER
207             # if defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN)
208             # define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
209             # elif defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN)
210             # define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
211             # endif
212              
213             #elif defined(__BYTE_ORDER__) && __BYTE_ORDER__
214             # if defined(__ORDER_BIG_ENDIAN__) && \
215             (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
216             # define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
217             # elif defined(__ORDER_LITTLE_ENDIAN__) && \
218             (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
219             # define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
220             # endif
221              
222             #elif (defined(__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__ == 1) || \
223             defined(__i386) || defined(__i386__) || \
224             defined(_X86_) || defined(__X86__) || \
225             defined(_M_IX86) || defined(__THW_INTEL__) || \
226             defined(__x86_64) || defined(__x86_64__) || \
227             defined(__amd64) || defined(__amd64__) || \
228             defined(_M_AMD64) || defined(_M_X64) || \
229             defined(_M_ARM) || defined(_M_ARM64) || \
230             defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \
231             defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || \
232             defined(__EMSCRIPTEN__) || defined(__wasm__) || \
233             defined(__loongarch__)
234             # define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
235              
236             #elif (defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ == 1) || \
237             defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \
238             defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) || \
239             defined(__or1k__) || defined(__OR1K__)
240             # define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
241              
242             #else
243             # define YYJSON_ENDIAN 0 /* unknown endian, detect at run-time */
244             #endif
245              
246             /*
247             This macro controls how yyjson handles unaligned memory accesses.
248            
249             By default, yyjson uses `memcpy()` for memory copying. This takes advantage of
250             the compiler's automatic optimizations to generate unaligned memory access
251             instructions when the target architecture supports it.
252            
253             However, for some older compilers or architectures where `memcpy()` isn't
254             optimized well and may generate unnecessary function calls, consider defining
255             this macro as 1. In such cases, yyjson switches to manual byte-by-byte access,
256             potentially improving performance. An example of the generated assembly code on
257             the ARM platform can be found here: https://godbolt.org/z/334jjhxPT
258            
259             As this flag has already been enabled for some common architectures in the
260             following code, users typically don't need to manually specify it. If users are
261             unsure about it, please review the generated assembly code or perform actual
262             benchmark to make an informed decision.
263             */
264             #ifndef YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
265             # if defined(__ia64) || defined(_IA64) || defined(__IA64__) || \
266             defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
267             # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* Itanium */
268             # elif (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) && \
269             (defined(__GNUC__) || defined(__clang__)) && \
270             (!defined(__ARM_FEATURE_UNALIGNED) || !__ARM_FEATURE_UNALIGNED)
271             # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* ARM */
272             # elif defined(__sparc) || defined(__sparc__)
273             # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* SPARC */
274             # elif defined(__mips) || defined(__mips__) || defined(__MIPS__)
275             # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* MIPS */
276             # elif defined(__m68k__) || defined(M68000)
277             # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* M68K */
278             # else
279             # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 0
280             # endif
281             #endif
282              
283             /*
284             Estimated initial ratio of the JSON data (data_size / value_count).
285             For example:
286            
287             data: {"id":12345678,"name":"Harry"}
288             data_size: 30
289             value_count: 5
290             ratio: 6
291            
292             yyjson uses dynamic memory with a growth factor of 1.5 when reading and writing
293             JSON, the ratios below are used to determine the initial memory size.
294            
295             A too large ratio will waste memory, and a too small ratio will cause multiple
296             memory growths and degrade performance. Currently, these ratios are generated
297             with some commonly used JSON datasets.
298             */
299             #define YYJSON_READER_ESTIMATED_PRETTY_RATIO 16
300             #define YYJSON_READER_ESTIMATED_MINIFY_RATIO 6
301             #define YYJSON_WRITER_ESTIMATED_PRETTY_RATIO 32
302             #define YYJSON_WRITER_ESTIMATED_MINIFY_RATIO 18
303              
304             /* The initial and maximum size of the memory pool's chunk in yyjson_mut_doc. */
305             #define YYJSON_MUT_DOC_STR_POOL_INIT_SIZE 0x100
306             #define YYJSON_MUT_DOC_STR_POOL_MAX_SIZE 0x10000000
307             #define YYJSON_MUT_DOC_VAL_POOL_INIT_SIZE (0x10 * sizeof(yyjson_mut_val))
308             #define YYJSON_MUT_DOC_VAL_POOL_MAX_SIZE (0x1000000 * sizeof(yyjson_mut_val))
309              
310             /* The minimum size of the dynamic allocator's chunk. */
311             #define YYJSON_ALC_DYN_MIN_SIZE 0x1000
312              
313             /* Default value for compile-time options. */
314             #ifndef YYJSON_DISABLE_READER
315             #define YYJSON_DISABLE_READER 0
316             #endif
317             #ifndef YYJSON_DISABLE_WRITER
318             #define YYJSON_DISABLE_WRITER 0
319             #endif
320             #ifndef YYJSON_DISABLE_UTILS
321             #define YYJSON_DISABLE_UTILS 0
322             #endif
323             #ifndef YYJSON_DISABLE_FAST_FP_CONV
324             #define YYJSON_DISABLE_FAST_FP_CONV 0
325             #endif
326             #ifndef YYJSON_DISABLE_NON_STANDARD
327             #define YYJSON_DISABLE_NON_STANDARD 0
328             #endif
329             #ifndef YYJSON_DISABLE_UTF8_VALIDATION
330             #define YYJSON_DISABLE_UTF8_VALIDATION 0
331             #endif
332              
333              
334              
335             /*==============================================================================
336             * Macros
337             *============================================================================*/
338              
339             /* Macros used for loop unrolling and other purpose. */
340             #define repeat2(x) { x x }
341             #define repeat3(x) { x x x }
342             #define repeat4(x) { x x x x }
343             #define repeat8(x) { x x x x x x x x }
344             #define repeat16(x) { x x x x x x x x x x x x x x x x }
345              
346             #define repeat2_incr(x) { x(0) x(1) }
347             #define repeat4_incr(x) { x(0) x(1) x(2) x(3) }
348             #define repeat8_incr(x) { x(0) x(1) x(2) x(3) x(4) x(5) x(6) x(7) }
349             #define repeat16_incr(x) { x(0) x(1) x(2) x(3) x(4) x(5) x(6) x(7) \
350             x(8) x(9) x(10) x(11) x(12) x(13) x(14) x(15) }
351              
352             #define repeat_in_1_18(x) { x(1) x(2) x(3) x(4) x(5) x(6) x(7) x(8) \
353             x(9) x(10) x(11) x(12) x(13) x(14) x(15) x(16) \
354             x(17) x(18) }
355              
356             /* Macros used to provide branch prediction information for compiler. */
357             #undef likely
358             #define likely(x) yyjson_likely(x)
359             #undef unlikely
360             #define unlikely(x) yyjson_unlikely(x)
361              
362             /* Macros used to provide inline information for compiler. */
363             #undef static_inline
364             #define static_inline static yyjson_inline
365             #undef static_noinline
366             #define static_noinline static yyjson_noinline
367              
368             /* Macros for min and max. */
369             #undef yyjson_min
370             #define yyjson_min(x, y) ((x) < (y) ? (x) : (y))
371             #undef yyjson_max
372             #define yyjson_max(x, y) ((x) > (y) ? (x) : (y))
373              
374             /* Used to write u64 literal for C89 which doesn't support "ULL" suffix. */
375             #undef U64
376             #define U64(hi, lo) ((((u64)hi##UL) << 32U) + lo##UL)
377              
378             /* Used to cast away (remove) const qualifier. */
379             #define constcast(type) (type)(void *)(size_t)(const void *)
380              
381             /* flag test */
382             #define has_read_flag(_flag) unlikely(read_flag_eq(flg, YYJSON_READ_##_flag))
383             #define has_write_flag(_flag) unlikely(write_flag_eq(flg, YYJSON_WRITE_##_flag))
384              
385             static_inline bool read_flag_eq(yyjson_read_flag flg, yyjson_read_flag chk) {
386             #if YYJSON_DISABLE_NON_STANDARD
387             if (chk == YYJSON_READ_ALLOW_INF_AND_NAN ||
388             chk == YYJSON_READ_ALLOW_COMMENTS ||
389             chk == YYJSON_READ_ALLOW_TRAILING_COMMAS ||
390             chk == YYJSON_READ_ALLOW_INVALID_UNICODE)
391             return false; /* this should be evaluated at compile-time */
392             #endif
393 51485           return (flg & chk) != 0;
394             }
395              
396             static_inline bool write_flag_eq(yyjson_write_flag flg, yyjson_write_flag chk) {
397             #if YYJSON_DISABLE_NON_STANDARD
398             if (chk == YYJSON_WRITE_ALLOW_INF_AND_NAN ||
399             chk == YYJSON_WRITE_ALLOW_INVALID_UNICODE)
400             return false; /* this should be evaluated at compile-time */
401             #endif
402 5770           return (flg & chk) != 0;
403             }
404              
405              
406              
407             /*==============================================================================
408             * Integer Constants
409             *============================================================================*/
410              
411             /* U64 constant values */
412             #undef U64_MAX
413             #define U64_MAX U64(0xFFFFFFFF, 0xFFFFFFFF)
414             #undef I64_MAX
415             #define I64_MAX U64(0x7FFFFFFF, 0xFFFFFFFF)
416             #undef USIZE_MAX
417             #define USIZE_MAX ((usize)(~(usize)0))
418              
419             /* Maximum number of digits for reading u32/u64/usize safety (not overflow). */
420             #undef U32_SAFE_DIG
421             #define U32_SAFE_DIG 9 /* u32 max is 4294967295, 10 digits */
422             #undef U64_SAFE_DIG
423             #define U64_SAFE_DIG 19 /* u64 max is 18446744073709551615, 20 digits */
424             #undef USIZE_SAFE_DIG
425             #define USIZE_SAFE_DIG (sizeof(usize) == 8 ? U64_SAFE_DIG : U32_SAFE_DIG)
426              
427              
428              
429             /*==============================================================================
430             * IEEE-754 Double Number Constants
431             *============================================================================*/
432              
433             /* Inf raw value (positive) */
434             #define F64_RAW_INF U64(0x7FF00000, 0x00000000)
435              
436             /* NaN raw value (quiet NaN, no payload, no sign) */
437             #if defined(__hppa__) || (defined(__mips__) && !defined(__mips_nan2008))
438             #define F64_RAW_NAN U64(0x7FF7FFFF, 0xFFFFFFFF)
439             #else
440             #define F64_RAW_NAN U64(0x7FF80000, 0x00000000)
441             #endif
442              
443             /* double number bits */
444             #define F64_BITS 64
445              
446             /* double number exponent part bits */
447             #define F64_EXP_BITS 11
448              
449             /* double number significand part bits */
450             #define F64_SIG_BITS 52
451              
452             /* double number significand part bits (with 1 hidden bit) */
453             #define F64_SIG_FULL_BITS 53
454              
455             /* double number significand bit mask */
456             #define F64_SIG_MASK U64(0x000FFFFF, 0xFFFFFFFF)
457              
458             /* double number exponent bit mask */
459             #define F64_EXP_MASK U64(0x7FF00000, 0x00000000)
460              
461             /* double number exponent bias */
462             #define F64_EXP_BIAS 1023
463              
464             /* double number significant digits count in decimal */
465             #define F64_DEC_DIG 17
466              
467             /* max significant digits count in decimal when reading double number */
468             #define F64_MAX_DEC_DIG 768
469              
470             /* maximum decimal power of double number (1.7976931348623157e308) */
471             #define F64_MAX_DEC_EXP 308
472              
473             /* minimum decimal power of double number (4.9406564584124654e-324) */
474             #define F64_MIN_DEC_EXP (-324)
475              
476             /* maximum binary power of double number */
477             #define F64_MAX_BIN_EXP 1024
478              
479             /* minimum binary power of double number */
480             #define F64_MIN_BIN_EXP (-1021)
481              
482              
483              
484             /*==============================================================================
485             * Types
486             *============================================================================*/
487              
488             /** Type define for primitive types. */
489             typedef float f32;
490             typedef double f64;
491             typedef int8_t i8;
492             typedef uint8_t u8;
493             typedef int16_t i16;
494             typedef uint16_t u16;
495             typedef int32_t i32;
496             typedef uint32_t u32;
497             typedef int64_t i64;
498             typedef uint64_t u64;
499             typedef size_t usize;
500              
501             /** 128-bit integer, used by floating-point number reader and writer. */
502             #if YYJSON_HAS_INT128
503             __extension__ typedef __int128 i128;
504             __extension__ typedef unsigned __int128 u128;
505             #endif
506              
507             /** 16/32/64-bit vector */
508             typedef struct v16 { char c[2]; } v16;
509             typedef struct v32 { char c[4]; } v32;
510             typedef struct v64 { char c[8]; } v64;
511              
512             /** 16/32/64-bit vector union */
513             typedef union v16_uni { v16 v; u16 u; } v16_uni;
514             typedef union v32_uni { v32 v; u32 u; } v32_uni;
515             typedef union v64_uni { v64 v; u64 u; } v64_uni;
516              
517              
518              
519             /*==============================================================================
520             * Load/Store Utils
521             *============================================================================*/
522              
523             #if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
524              
525             #define byte_move_idx(x) ((char *)dst)[x] = ((const char *)src)[x];
526              
527             static_inline void byte_copy_2(void *dst, const void *src) {
528             repeat2_incr(byte_move_idx)
529             }
530              
531             static_inline void byte_copy_4(void *dst, const void *src) {
532             repeat4_incr(byte_move_idx)
533             }
534              
535             static_inline void byte_copy_8(void *dst, const void *src) {
536             repeat8_incr(byte_move_idx)
537             }
538              
539             static_inline void byte_copy_16(void *dst, const void *src) {
540             repeat16_incr(byte_move_idx)
541             }
542              
543             static_inline void byte_move_2(void *dst, const void *src) {
544             repeat2_incr(byte_move_idx)
545             }
546              
547             static_inline void byte_move_4(void *dst, const void *src) {
548             repeat4_incr(byte_move_idx)
549             }
550              
551             static_inline void byte_move_8(void *dst, const void *src) {
552             repeat8_incr(byte_move_idx)
553             }
554              
555             static_inline void byte_move_16(void *dst, const void *src) {
556             repeat16_incr(byte_move_idx)
557             }
558              
559             static_inline bool byte_match_2(void *buf, const char *pat) {
560             return
561             ((char *)buf)[0] == ((const char *)pat)[0] &&
562             ((char *)buf)[1] == ((const char *)pat)[1];
563             }
564              
565             static_inline bool byte_match_4(void *buf, const char *pat) {
566             return
567             ((char *)buf)[0] == ((const char *)pat)[0] &&
568             ((char *)buf)[1] == ((const char *)pat)[1] &&
569             ((char *)buf)[2] == ((const char *)pat)[2] &&
570             ((char *)buf)[3] == ((const char *)pat)[3];
571             }
572              
573             static_inline u16 byte_load_2(const void *src) {
574             v16_uni uni;
575             uni.v.c[0] = ((const char *)src)[0];
576             uni.v.c[1] = ((const char *)src)[1];
577             return uni.u;
578             }
579              
580             static_inline u32 byte_load_3(const void *src) {
581             v32_uni uni;
582             uni.v.c[0] = ((const char *)src)[0];
583             uni.v.c[1] = ((const char *)src)[1];
584             uni.v.c[2] = ((const char *)src)[2];
585             uni.v.c[3] = 0;
586             return uni.u;
587             }
588              
589             static_inline u32 byte_load_4(const void *src) {
590             v32_uni uni;
591             uni.v.c[0] = ((const char *)src)[0];
592             uni.v.c[1] = ((const char *)src)[1];
593             uni.v.c[2] = ((const char *)src)[2];
594             uni.v.c[3] = ((const char *)src)[3];
595             return uni.u;
596             }
597              
598             #undef byte_move_expr
599              
600             #else
601              
602             static_inline void byte_copy_2(void *dst, const void *src) {
603 20771           memcpy(dst, src, 2);
604 3           }
605              
606             static_inline void byte_copy_4(void *dst, const void *src) {
607 44574           memcpy(dst, src, 4);
608 44570           }
609              
610             static_inline void byte_copy_8(void *dst, const void *src) {
611 31           memcpy(dst, src, 8);
612 15           }
613              
614             static_inline void byte_copy_16(void *dst, const void *src) {
615 8275           memcpy(dst, src, 16);
616 8275           }
617              
618             static_inline void byte_move_2(void *dst, const void *src) {
619             u16 tmp;
620 11           memcpy(&tmp, src, 2);
621 11           memcpy(dst, &tmp, 2);
622 11           }
623              
624             static_inline void byte_move_4(void *dst, const void *src) {
625             u32 tmp;
626 2           memcpy(&tmp, src, 4);
627 2           memcpy(dst, &tmp, 4);
628 2           }
629              
630             static_inline void byte_move_8(void *dst, const void *src) {
631             u64 tmp;
632 2           memcpy(&tmp, src, 8);
633 2           memcpy(dst, &tmp, 8);
634 2           }
635              
636             static_inline void byte_move_16(void *dst, const void *src) {
637 3           char *pdst = (char *)dst;
638 3           const char *psrc = (const char *)src;
639             u64 tmp1, tmp2;
640 3           memcpy(&tmp1, psrc, 8);
641 3           memcpy(&tmp2, psrc + 8, 8);
642 3           memcpy(pdst, &tmp1, 8);
643 3           memcpy(pdst + 8, &tmp2, 8);
644 3           }
645              
646             static_inline bool byte_match_2(void *buf, const char *pat) {
647             v16_uni u1, u2;
648 1474           memcpy(&u1, buf, 2);
649 1474           memcpy(&u2, pat, 2);
650 27           return u1.u == u2.u;
651             }
652              
653             static_inline bool byte_match_4(void *buf, const char *pat) {
654             v32_uni u1, u2;
655 44           memcpy(&u1, buf, 4);
656 44           memcpy(&u2, pat, 4);
657 44           return u1.u == u2.u;
658             }
659              
660             static_inline u16 byte_load_2(const void *src) {
661             v16_uni uni;
662 3           memcpy(&uni, src, 2);
663 3           return uni.u;
664             }
665              
666             static_inline u32 byte_load_3(const void *src) {
667             v32_uni uni;
668 1           memcpy(&uni, src, 2);
669 1           uni.v.c[2] = ((const char *)src)[2];
670 1           uni.v.c[3] = 0;
671 1           return uni.u;
672             }
673              
674             static_inline u32 byte_load_4(const void *src) {
675             v32_uni uni;
676 26           memcpy(&uni, src, 4);
677 2           return uni.u;
678             }
679              
680             #endif
681              
682              
683              
684             /*==============================================================================
685             * Number Utils
686             * These functions are used to detect and convert NaN and Inf numbers.
687             *============================================================================*/
688              
689             /** Convert raw binary to double. */
690             static_inline f64 f64_from_raw(u64 u) {
691             /* use memcpy to avoid violating the strict aliasing rule */
692             f64 f;
693             memcpy(&f, &u, 8);
694             return f;
695             }
696              
697             /** Convert double to raw binary. */
698             static_inline u64 f64_to_raw(f64 f) {
699             /* use memcpy to avoid violating the strict aliasing rule */
700             u64 u;
701             memcpy(&u, &f, 8);
702             return u;
703             }
704              
705             /** Get raw 'infinity' with sign. */
706             static_inline u64 f64_raw_get_inf(bool sign) {
707             #if YYJSON_HAS_IEEE_754
708 2           return F64_RAW_INF | ((u64)sign << 63);
709             #elif defined(INFINITY)
710             return f64_to_raw(sign ? -INFINITY : INFINITY);
711             #else
712             return f64_to_raw(sign ? -HUGE_VAL : HUGE_VAL);
713             #endif
714             }
715              
716             /** Get raw 'nan' with sign. */
717             static_inline u64 f64_raw_get_nan(bool sign) {
718             #if YYJSON_HAS_IEEE_754
719 1           return F64_RAW_NAN | ((u64)sign << 63);
720             #elif defined(NAN)
721             return f64_to_raw(sign ? (f64)-NAN : (f64)NAN);
722             #else
723             return f64_to_raw((sign ? -0.0 : 0.0) / 0.0);
724             #endif
725             }
726              
727             /**
728             Convert normalized u64 (highest bit is 1) to f64.
729            
730             Some compiler (such as Microsoft Visual C++ 6.0) do not support converting
731             number from u64 to f64. This function will first convert u64 to i64 and then
732             to f64, with `to nearest` rounding mode.
733             */
734             static_inline f64 normalized_u64_to_f64(u64 val) {
735             #if YYJSON_U64_TO_F64_NO_IMPL
736             i64 sig = (i64)((val >> 1) | (val & 1));
737             return ((f64)sig) * (f64)2.0;
738             #else
739 0           return (f64)val;
740             #endif
741             }
742              
743              
744              
745             /*==============================================================================
746             * Size Utils
747             * These functions are used for memory allocation.
748             *============================================================================*/
749              
750             /** Returns whether the size is overflow after increment. */
751             static_inline bool size_add_is_overflow(usize size, usize add) {
752             return size > (size + add);
753             }
754              
755             /** Returns whether the size is power of 2 (size should not be 0). */
756             static_inline bool size_is_pow2(usize size) {
757 0           return (size & (size - 1)) == 0;
758             }
759              
760             /** Align size upwards (may overflow). */
761             static_inline usize size_align_up(usize size, usize align) {
762 1124 50         if (size_is_pow2(align)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
763 1124           return (size + (align - 1)) & ~(align - 1);
764             } else {
765 0           return size + align - (size + align - 1) % align - 1;
766             }
767             }
768              
769             /** Align size downwards. */
770             static_inline usize size_align_down(usize size, usize align) {
771 0 0         if (size_is_pow2(align)) {
772 0           return size & ~(align - 1);
773             } else {
774 0           return size - (size % align);
775             }
776             }
777              
778             /** Align address upwards (may overflow). */
779             static_inline void *mem_align_up(void *mem, usize align) {
780             usize size;
781 0           memcpy(&size, &mem, sizeof(usize));
782 0           size = size_align_up(size, align);
783 0           memcpy(&mem, &size, sizeof(usize));
784 0           return mem;
785             }
786              
787              
788              
789             /*==============================================================================
790             * Bits Utils
791             * These functions are used by the floating-point number reader and writer.
792             *============================================================================*/
793              
794             /** Returns the number of leading 0-bits in value (input should not be 0). */
795             static_inline u32 u64_lz_bits(u64 v) {
796             #if GCC_HAS_CLZLL
797 14           return (u32)__builtin_clzll(v);
798             #elif MSC_HAS_BIT_SCAN_64
799             unsigned long r;
800             _BitScanReverse64(&r, v);
801             return (u32)63 - (u32)r;
802             #elif MSC_HAS_BIT_SCAN
803             unsigned long hi, lo;
804             bool hi_set = _BitScanReverse(&hi, (u32)(v >> 32)) != 0;
805             _BitScanReverse(&lo, (u32)v);
806             hi |= 32;
807             return (u32)63 - (u32)(hi_set ? hi : lo);
808             #else
809             /*
810             branchless, use de Bruijn sequences
811             see: https://www.chessprogramming.org/BitScan
812             */
813             const u8 table[64] = {
814             63, 16, 62, 7, 15, 36, 61, 3, 6, 14, 22, 26, 35, 47, 60, 2,
815             9, 5, 28, 11, 13, 21, 42, 19, 25, 31, 34, 40, 46, 52, 59, 1,
816             17, 8, 37, 4, 23, 27, 48, 10, 29, 12, 43, 20, 32, 41, 53, 18,
817             38, 24, 49, 30, 44, 33, 54, 39, 50, 45, 55, 51, 56, 57, 58, 0
818             };
819             v |= v >> 1;
820             v |= v >> 2;
821             v |= v >> 4;
822             v |= v >> 8;
823             v |= v >> 16;
824             v |= v >> 32;
825             return table[(v * U64(0x03F79D71, 0xB4CB0A89)) >> 58];
826             #endif
827             }
828              
829             /** Returns the number of trailing 0-bits in value (input should not be 0). */
830             static_inline u32 u64_tz_bits(u64 v) {
831             #if GCC_HAS_CTZLL
832 6010           return (u32)__builtin_ctzll(v);
833             #elif MSC_HAS_BIT_SCAN_64
834             unsigned long r;
835             _BitScanForward64(&r, v);
836             return (u32)r;
837             #elif MSC_HAS_BIT_SCAN
838             unsigned long lo, hi;
839             bool lo_set = _BitScanForward(&lo, (u32)(v)) != 0;
840             _BitScanForward(&hi, (u32)(v >> 32));
841             hi += 32;
842             return lo_set ? lo : hi;
843             #else
844             /*
845             branchless, use de Bruijn sequences
846             see: https://www.chessprogramming.org/BitScan
847             */
848             const u8 table[64] = {
849             0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28,
850             62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11,
851             63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
852             51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12
853             };
854             return table[((v & (~v + 1)) * U64(0x022FDD63, 0xCC95386D)) >> 58];
855             #endif
856             }
857              
858              
859              
860             /*==============================================================================
861             * 128-bit Integer Utils
862             * These functions are used by the floating-point number reader and writer.
863             *============================================================================*/
864              
865             /** Multiplies two 64-bit unsigned integers (a * b),
866             returns the 128-bit result as 'hi' and 'lo'. */
867             static_inline void u128_mul(u64 a, u64 b, u64 *hi, u64 *lo) {
868             #if YYJSON_HAS_INT128
869 3054           u128 m = (u128)a * b;
870 3054           *hi = (u64)(m >> 64);
871 3054           *lo = (u64)(m);
872             #elif MSC_HAS_UMUL128
873             *lo = _umul128(a, b, hi);
874             #else
875             u32 a0 = (u32)(a), a1 = (u32)(a >> 32);
876             u32 b0 = (u32)(b), b1 = (u32)(b >> 32);
877             u64 p00 = (u64)a0 * b0, p01 = (u64)a0 * b1;
878             u64 p10 = (u64)a1 * b0, p11 = (u64)a1 * b1;
879             u64 m0 = p01 + (p00 >> 32);
880             u32 m00 = (u32)(m0), m01 = (u32)(m0 >> 32);
881             u64 m1 = p10 + m00;
882             u32 m10 = (u32)(m1), m11 = (u32)(m1 >> 32);
883             *hi = p11 + m01 + m11;
884             *lo = ((u64)m10 << 32) | (u32)p00;
885             #endif
886 3054           }
887              
888             /** Multiplies two 64-bit unsigned integers and add a value (a * b + c),
889             returns the 128-bit result as 'hi' and 'lo'. */
890             static_inline void u128_mul_add(u64 a, u64 b, u64 c, u64 *hi, u64 *lo) {
891             #if YYJSON_HAS_INT128
892 3048           u128 m = (u128)a * b + c;
893 3048           *hi = (u64)(m >> 64);
894 3048           *lo = (u64)(m);
895             #else
896             u64 h, l, t;
897             u128_mul(a, b, &h, &l);
898             t = l + c;
899             h += (u64)(((t < l) | (t < c)));
900             *hi = h;
901             *lo = t;
902             #endif
903 3048           }
904              
905              
906              
907             /*==============================================================================
908             * File Utils
909             * These functions are used to read and write JSON files.
910             *============================================================================*/
911              
912             #define YYJSON_FOPEN_EXT
913             #if !defined(_MSC_VER) && defined(__GLIBC__) && defined(__GLIBC_PREREQ)
914             # if __GLIBC_PREREQ(2, 7)
915             # undef YYJSON_FOPEN_EXT
916             # define YYJSON_FOPEN_EXT "e" /* glibc extension to enable O_CLOEXEC */
917             # endif
918             #endif
919              
920             static_inline FILE *fopen_safe(const char *path, const char *mode) {
921             #if YYJSON_MSC_VER >= 1400
922             FILE *file = NULL;
923             if (fopen_s(&file, path, mode) != 0) return NULL;
924             return file;
925             #else
926 0           return fopen(path, mode);
927             #endif
928             }
929              
930             static_inline FILE *fopen_readonly(const char *path) {
931 0           return fopen_safe(path, "rb" YYJSON_FOPEN_EXT);
932             }
933              
934             static_inline FILE *fopen_writeonly(const char *path) {
935 0           return fopen_safe(path, "wb" YYJSON_FOPEN_EXT);
936             }
937              
938             static_inline usize fread_safe(void *buf, usize size, FILE *file) {
939             #if YYJSON_MSC_VER >= 1400
940             return fread_s(buf, size, 1, size, file);
941             #else
942 0           return fread(buf, 1, size, file);
943             #endif
944             }
945              
946              
947              
948             /*==============================================================================
949             * Default Memory Allocator
950             * This is a simple libc memory allocator wrapper.
951             *============================================================================*/
952              
953 16599           static void *default_malloc(void *ctx, usize size) {
954 16599           return malloc(size);
955             }
956              
957 7           static void *default_realloc(void *ctx, void *ptr, usize old_size, usize size) {
958 7           return realloc(ptr, size);
959             }
960              
961 15442           static void default_free(void *ctx, void *ptr) {
962 15442           free(ptr);
963 15442           }
964              
965             static const yyjson_alc YYJSON_DEFAULT_ALC = {
966             default_malloc,
967             default_realloc,
968             default_free,
969             NULL
970             };
971              
972              
973              
974             /*==============================================================================
975             * Null Memory Allocator
976             *
977             * This allocator is just a placeholder to ensure that the internal
978             * malloc/realloc/free function pointers are not null.
979             *============================================================================*/
980              
981 0           static void *null_malloc(void *ctx, usize size) {
982 0           return NULL;
983             }
984              
985 0           static void *null_realloc(void *ctx, void *ptr, usize old_size, usize size) {
986 0           return NULL;
987             }
988              
989 0           static void null_free(void *ctx, void *ptr) {
990 0           return;
991             }
992              
993             static const yyjson_alc YYJSON_NULL_ALC = {
994             null_malloc,
995             null_realloc,
996             null_free,
997             NULL
998             };
999              
1000              
1001              
1002             /*==============================================================================
1003             * Pool Memory Allocator
1004             *
1005             * This allocator is initialized with a fixed-size buffer.
1006             * The buffer is split into multiple memory chunks for memory allocation.
1007             *============================================================================*/
1008              
1009             /** memory chunk header */
1010             typedef struct pool_chunk {
1011             usize size; /* chunk memory size, include chunk header */
1012             struct pool_chunk *next; /* linked list, nullable */
1013             /* char mem[]; flexible array member */
1014             } pool_chunk;
1015              
1016             /** allocator ctx header */
1017             typedef struct pool_ctx {
1018             usize size; /* total memory size, include ctx header */
1019             pool_chunk *free_list; /* linked list, nullable */
1020             /* pool_chunk chunks[]; flexible array member */
1021             } pool_ctx;
1022              
1023             /** align up the input size to chunk size */
1024             static_inline void pool_size_align(usize *size) {
1025 0           *size = size_align_up(*size, sizeof(pool_chunk)) + sizeof(pool_chunk);
1026 0           }
1027              
1028 0           static void *pool_malloc(void *ctx_ptr, usize size) {
1029             /* assert(size != 0) */
1030 0           pool_ctx *ctx = (pool_ctx *)ctx_ptr;
1031 0           pool_chunk *next, *prev = NULL, *cur = ctx->free_list;
1032            
1033 0 0         if (unlikely(size >= ctx->size)) return NULL;
1034             pool_size_align(&size);
1035            
1036 0 0         while (cur) {
1037 0 0         if (cur->size < size) {
1038             /* not enough space, try next chunk */
1039 0           prev = cur;
1040 0           cur = cur->next;
1041 0           continue;
1042             }
1043 0 0         if (cur->size >= size + sizeof(pool_chunk) * 2) {
1044             /* too much space, split this chunk */
1045 0           next = (pool_chunk *)(void *)((u8 *)cur + size);
1046 0           next->size = cur->size - size;
1047 0           next->next = cur->next;
1048 0           cur->size = size;
1049             } else {
1050             /* just enough space, use whole chunk */
1051 0           next = cur->next;
1052             }
1053 0 0         if (prev) prev->next = next;
1054 0           else ctx->free_list = next;
1055 0           return (void *)(cur + 1);
1056             }
1057 0           return NULL;
1058             }
1059              
1060 0           static void pool_free(void *ctx_ptr, void *ptr) {
1061             /* assert(ptr != NULL) */
1062 0           pool_ctx *ctx = (pool_ctx *)ctx_ptr;
1063 0           pool_chunk *cur = ((pool_chunk *)ptr) - 1;
1064 0           pool_chunk *prev = NULL, *next = ctx->free_list;
1065            
1066 0 0         while (next && next < cur) {
    0          
1067 0           prev = next;
1068 0           next = next->next;
1069             }
1070 0 0         if (prev) prev->next = cur;
1071 0           else ctx->free_list = cur;
1072 0           cur->next = next;
1073            
1074 0 0         if (next && ((u8 *)cur + cur->size) == (u8 *)next) {
    0          
1075             /* merge cur to higher chunk */
1076 0           cur->size += next->size;
1077 0           cur->next = next->next;
1078             }
1079 0 0         if (prev && ((u8 *)prev + prev->size) == (u8 *)cur) {
    0          
1080             /* merge cur to lower chunk */
1081 0           prev->size += cur->size;
1082 0           prev->next = cur->next;
1083             }
1084 0           }
1085              
1086 0           static void *pool_realloc(void *ctx_ptr, void *ptr,
1087             usize old_size, usize size) {
1088             /* assert(ptr != NULL && size != 0 && old_size < size) */
1089 0           pool_ctx *ctx = (pool_ctx *)ctx_ptr;
1090 0           pool_chunk *cur = ((pool_chunk *)ptr) - 1, *prev, *next, *tmp;
1091            
1092             /* check size */
1093 0 0         if (unlikely(size >= ctx->size)) return NULL;
1094             pool_size_align(&old_size);
1095             pool_size_align(&size);
1096 0 0         if (unlikely(old_size == size)) return ptr;
1097            
1098             /* find next and prev chunk */
1099 0           prev = NULL;
1100 0           next = ctx->free_list;
1101 0 0         while (next && next < cur) {
    0          
1102 0           prev = next;
1103 0           next = next->next;
1104             }
1105            
1106 0 0         if ((u8 *)cur + cur->size == (u8 *)next && cur->size + next->size >= size) {
    0          
1107             /* merge to higher chunk if they are contiguous */
1108 0           usize free_size = cur->size + next->size - size;
1109 0 0         if (free_size > sizeof(pool_chunk) * 2) {
1110 0           tmp = (pool_chunk *)(void *)((u8 *)cur + size);
1111 0 0         if (prev) prev->next = tmp;
1112 0           else ctx->free_list = tmp;
1113 0           tmp->next = next->next;
1114 0           tmp->size = free_size;
1115 0           cur->size = size;
1116             } else {
1117 0 0         if (prev) prev->next = next->next;
1118 0           else ctx->free_list = next->next;
1119 0           cur->size += next->size;
1120             }
1121 0           return ptr;
1122             } else {
1123             /* fallback to malloc and memcpy */
1124 0           void *new_ptr = pool_malloc(ctx_ptr, size - sizeof(pool_chunk));
1125 0 0         if (new_ptr) {
1126 0           memcpy(new_ptr, ptr, cur->size - sizeof(pool_chunk));
1127 0           pool_free(ctx_ptr, ptr);
1128             }
1129 0           return new_ptr;
1130             }
1131             }
1132              
1133 0           bool yyjson_alc_pool_init(yyjson_alc *alc, void *buf, usize size) {
1134             pool_chunk *chunk;
1135             pool_ctx *ctx;
1136            
1137 0 0         if (unlikely(!alc)) return false;
1138 0           *alc = YYJSON_NULL_ALC;
1139 0 0         if (size < sizeof(pool_ctx) * 4) return false;
1140 0           ctx = (pool_ctx *)mem_align_up(buf, sizeof(pool_ctx));
1141 0 0         if (unlikely(!ctx)) return false;
1142 0           size -= (usize)((u8 *)ctx - (u8 *)buf);
1143 0           size = size_align_down(size, sizeof(pool_ctx));
1144            
1145 0           chunk = (pool_chunk *)(ctx + 1);
1146 0           chunk->size = size - sizeof(pool_ctx);
1147 0           chunk->next = NULL;
1148 0           ctx->size = size;
1149 0           ctx->free_list = chunk;
1150            
1151 0           alc->malloc = pool_malloc;
1152 0           alc->realloc = pool_realloc;
1153 0           alc->free = pool_free;
1154 0           alc->ctx = (void *)ctx;
1155 0           return true;
1156             }
1157              
1158              
1159              
1160             /*==============================================================================
1161             * Dynamic Memory Allocator
1162             *
1163             * This allocator allocates memory on demand and does not immediately release
1164             * unused memory. Instead, it places the unused memory into a freelist for
1165             * potential reuse in the future. It is only when the entire allocator is
1166             * destroyed that all previously allocated memory is released at once.
1167             *============================================================================*/
1168              
1169             /** memory chunk header */
1170             typedef struct dyn_chunk {
1171             usize size; /* chunk size, include header */
1172             struct dyn_chunk *next;
1173             /* char mem[]; flexible array member */
1174             } dyn_chunk;
1175              
1176             /** allocator ctx header */
1177             typedef struct {
1178             dyn_chunk free_list; /* dummy header, sorted from small to large */
1179             dyn_chunk used_list; /* dummy header */
1180             } dyn_ctx;
1181              
1182             /** align up the input size to chunk size */
1183             static_inline bool dyn_size_align(usize *size) {
1184 0           usize alc_size = *size + sizeof(dyn_chunk);
1185 0           alc_size = size_align_up(alc_size, YYJSON_ALC_DYN_MIN_SIZE);
1186 0 0         if (unlikely(alc_size < *size)) return false; /* overflow */
    0          
1187 0           *size = alc_size;
1188 0           return true;
1189             }
1190              
1191             /** remove a chunk from list (the chunk must already be in the list) */
1192             static_inline void dyn_chunk_list_remove(dyn_chunk *list, dyn_chunk *chunk) {
1193 0           dyn_chunk *prev = list, *cur;
1194 0 0         for (cur = prev->next; cur; cur = cur->next) {
    0          
1195 0 0         if (cur == chunk) {
    0          
1196 0           prev->next = cur->next;
1197 0           cur->next = NULL;
1198 0           return;
1199             }
1200 0           prev = cur;
1201             }
1202             }
1203              
1204             /** add a chunk to list header (the chunk must not be in the list) */
1205             static_inline void dyn_chunk_list_add(dyn_chunk *list, dyn_chunk *chunk) {
1206 0           chunk->next = list->next;
1207 0           list->next = chunk;
1208 0           }
1209              
1210 0           static void *dyn_malloc(void *ctx_ptr, usize size) {
1211             /* assert(size != 0) */
1212 0           const yyjson_alc def = YYJSON_DEFAULT_ALC;
1213 0           dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
1214             dyn_chunk *chunk, *prev, *next;
1215 0 0         if (unlikely(!dyn_size_align(&size))) return NULL;
1216            
1217             /* freelist is empty, create new chunk */
1218 0 0         if (!ctx->free_list.next) {
1219 0           chunk = (dyn_chunk *)def.malloc(def.ctx, size);
1220 0 0         if (unlikely(!chunk)) return NULL;
1221 0           chunk->size = size;
1222 0           chunk->next = NULL;
1223 0           dyn_chunk_list_add(&ctx->used_list, chunk);
1224 0           return (void *)(chunk + 1);
1225             }
1226            
1227             /* find a large enough chunk, or resize the largest chunk */
1228 0           prev = &ctx->free_list;
1229             while (true) {
1230 0           chunk = prev->next;
1231 0 0         if (chunk->size >= size) { /* enough size, reuse this chunk */
1232 0           prev->next = chunk->next;
1233 0           dyn_chunk_list_add(&ctx->used_list, chunk);
1234 0           return (void *)(chunk + 1);
1235             }
1236 0 0         if (!chunk->next) { /* resize the largest chunk */
1237 0           chunk = (dyn_chunk *)def.realloc(def.ctx, chunk, chunk->size, size);
1238 0 0         if (unlikely(!chunk)) return NULL;
1239 0           prev->next = NULL;
1240 0           chunk->size = size;
1241 0           dyn_chunk_list_add(&ctx->used_list, chunk);
1242 0           return (void *)(chunk + 1);
1243             }
1244 0           prev = chunk;
1245             }
1246             }
1247              
1248 0           static void *dyn_realloc(void *ctx_ptr, void *ptr,
1249             usize old_size, usize size) {
1250             /* assert(ptr != NULL && size != 0 && old_size < size) */
1251 0           const yyjson_alc def = YYJSON_DEFAULT_ALC;
1252 0           dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
1253             dyn_chunk *prev, *next, *new_chunk;
1254 0           dyn_chunk *chunk = (dyn_chunk *)ptr - 1;
1255 0 0         if (unlikely(!dyn_size_align(&size))) return NULL;
1256 0 0         if (chunk->size >= size) return ptr;
1257            
1258 0           dyn_chunk_list_remove(&ctx->used_list, chunk);
1259 0           new_chunk = (dyn_chunk *)def.realloc(def.ctx, chunk, chunk->size, size);
1260 0 0         if (likely(new_chunk)) {
1261 0           new_chunk->size = size;
1262 0           chunk = new_chunk;
1263             }
1264 0           dyn_chunk_list_add(&ctx->used_list, chunk);
1265 0 0         return new_chunk ? (void *)(new_chunk + 1) : NULL;
1266             }
1267              
1268 0           static void dyn_free(void *ctx_ptr, void *ptr) {
1269             /* assert(ptr != NULL) */
1270 0           dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
1271 0           dyn_chunk *chunk = (dyn_chunk *)ptr - 1, *prev;
1272            
1273 0           dyn_chunk_list_remove(&ctx->used_list, chunk);
1274 0 0         for (prev = &ctx->free_list; prev; prev = prev->next) {
1275 0 0         if (!prev->next || prev->next->size >= chunk->size) {
    0          
1276 0           chunk->next = prev->next;
1277 0           prev->next = chunk;
1278 0           break;
1279             }
1280             }
1281 0           }
1282              
1283 0           yyjson_alc *yyjson_alc_dyn_new(void) {
1284 0           const yyjson_alc def = YYJSON_DEFAULT_ALC;
1285 0           usize hdr_len = sizeof(yyjson_alc) + sizeof(dyn_ctx);
1286 0           yyjson_alc *alc = (yyjson_alc *)def.malloc(def.ctx, hdr_len);
1287 0           dyn_ctx *ctx = (dyn_ctx *)(void *)(alc + 1);
1288 0 0         if (unlikely(!alc)) return NULL;
1289 0           alc->malloc = dyn_malloc;
1290 0           alc->realloc = dyn_realloc;
1291 0           alc->free = dyn_free;
1292 0           alc->ctx = alc + 1;
1293 0           memset(ctx, 0, sizeof(*ctx));
1294 0           return alc;
1295             }
1296              
1297 0           void yyjson_alc_dyn_free(yyjson_alc *alc) {
1298 0           const yyjson_alc def = YYJSON_DEFAULT_ALC;
1299 0           dyn_ctx *ctx = (dyn_ctx *)(void *)(alc + 1);
1300             dyn_chunk *chunk, *next;
1301 0 0         if (unlikely(!alc)) return;
1302 0 0         for (chunk = ctx->free_list.next; chunk; chunk = next) {
1303 0           next = chunk->next;
1304 0           def.free(def.ctx, chunk);
1305             }
1306 0 0         for (chunk = ctx->used_list.next; chunk; chunk = next) {
1307 0           next = chunk->next;
1308 0           def.free(def.ctx, chunk);
1309             }
1310 0           def.free(def.ctx, alc);
1311             }
1312              
1313              
1314              
1315             /*==============================================================================
1316             * JSON document and value
1317             *============================================================================*/
1318              
1319             static_inline void unsafe_yyjson_str_pool_release(yyjson_str_pool *pool,
1320             yyjson_alc *alc) {
1321 1150           yyjson_str_chunk *chunk = pool->chunks, *next;
1322 1150 50         while (chunk) {
1323 0           next = chunk->next;
1324 0           alc->free(alc->ctx, chunk);
1325 0           chunk = next;
1326             }
1327 1150           }
1328              
1329             static_inline void unsafe_yyjson_val_pool_release(yyjson_val_pool *pool,
1330             yyjson_alc *alc) {
1331 1150           yyjson_val_chunk *chunk = pool->chunks, *next;
1332 3360 100         while (chunk) {
1333 2210           next = chunk->next;
1334 2210           alc->free(alc->ctx, chunk);
1335 2210           chunk = next;
1336             }
1337 1150           }
1338              
1339 0           bool unsafe_yyjson_str_pool_grow(yyjson_str_pool *pool,
1340             const yyjson_alc *alc, usize len) {
1341             yyjson_str_chunk *chunk;
1342             usize size, max_len;
1343            
1344             /* create a new chunk */
1345 0           max_len = USIZE_MAX - sizeof(yyjson_str_chunk);
1346 0 0         if (unlikely(len > max_len)) return false;
1347 0           size = len + sizeof(yyjson_str_chunk);
1348 0           size = yyjson_max(pool->chunk_size, size);
1349 0           chunk = (yyjson_str_chunk *)alc->malloc(alc->ctx, size);
1350 0 0         if (unlikely(!chunk)) return false;
1351            
1352             /* insert the new chunk as the head of the linked list */
1353 0           chunk->next = pool->chunks;
1354 0           chunk->chunk_size = size;
1355 0           pool->chunks = chunk;
1356 0           pool->cur = (char *)chunk + sizeof(yyjson_str_chunk);
1357 0           pool->end = (char *)chunk + size;
1358            
1359             /* the next chunk is twice the size of the current one */
1360 0           size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max);
1361 0 0         if (size < pool->chunk_size) size = pool->chunk_size_max; /* overflow */
1362 0           pool->chunk_size = size;
1363 0           return true;
1364             }
1365              
1366 2212           bool unsafe_yyjson_val_pool_grow(yyjson_val_pool *pool,
1367             const yyjson_alc *alc, usize count) {
1368             yyjson_val_chunk *chunk;
1369             usize size, max_count;
1370            
1371             /* create a new chunk */
1372 2212           max_count = USIZE_MAX / sizeof(yyjson_mut_val) - 1;
1373 2212 50         if (unlikely(count > max_count)) return false;
1374 2212           size = (count + 1) * sizeof(yyjson_mut_val);
1375 2212           size = yyjson_max(pool->chunk_size, size);
1376 2212           chunk = (yyjson_val_chunk *)alc->malloc(alc->ctx, size);
1377 2212 50         if (unlikely(!chunk)) return false;
1378            
1379             /* insert the new chunk as the head of the linked list */
1380 2212           chunk->next = pool->chunks;
1381 2212           chunk->chunk_size = size;
1382 2212           pool->chunks = chunk;
1383 2212           pool->cur = (yyjson_mut_val *)(void *)((u8 *)chunk) + 1;
1384 2212           pool->end = (yyjson_mut_val *)(void *)((u8 *)chunk + size);
1385            
1386             /* the next chunk is twice the size of the current one */
1387 2212           size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max);
1388 2212 50         if (size < pool->chunk_size) size = pool->chunk_size_max; /* overflow */
1389 2212           pool->chunk_size = size;
1390 2212           return true;
1391             }
1392              
1393 0           bool yyjson_mut_doc_set_str_pool_size(yyjson_mut_doc *doc, size_t len) {
1394 0           usize max_size = USIZE_MAX - sizeof(yyjson_str_chunk);
1395 0 0         if (!doc || !len || len > max_size) return false;
    0          
    0          
1396 0           doc->str_pool.chunk_size = len + sizeof(yyjson_str_chunk);
1397 0           return true;
1398             }
1399              
1400 0           bool yyjson_mut_doc_set_val_pool_size(yyjson_mut_doc *doc, size_t count) {
1401 0           usize max_count = USIZE_MAX / sizeof(yyjson_mut_val) - 1;
1402 0 0         if (!doc || !count || count > max_count) return false;
    0          
    0          
1403 0           doc->val_pool.chunk_size = (count + 1) * sizeof(yyjson_mut_val);
1404 0           return true;
1405             }
1406              
1407 1150           void yyjson_mut_doc_free(yyjson_mut_doc *doc) {
1408 1150 50         if (doc) {
1409 1150           yyjson_alc alc = doc->alc;
1410 1150           memset(&doc->alc, 0, sizeof(alc));
1411 1150           unsafe_yyjson_str_pool_release(&doc->str_pool, &alc);
1412 1150           unsafe_yyjson_val_pool_release(&doc->val_pool, &alc);
1413 1150           alc.free(alc.ctx, doc);
1414             }
1415 1150           }
1416              
1417 1155           yyjson_mut_doc *yyjson_mut_doc_new(const yyjson_alc *alc) {
1418             yyjson_mut_doc *doc;
1419 1155 50         if (!alc) alc = &YYJSON_DEFAULT_ALC;
1420 1155           doc = (yyjson_mut_doc *)alc->malloc(alc->ctx, sizeof(yyjson_mut_doc));
1421 1155 50         if (!doc) return NULL;
1422 1155           memset(doc, 0, sizeof(yyjson_mut_doc));
1423            
1424 1155           doc->alc = *alc;
1425 1155           doc->str_pool.chunk_size = YYJSON_MUT_DOC_STR_POOL_INIT_SIZE;
1426 1155           doc->str_pool.chunk_size_max = YYJSON_MUT_DOC_STR_POOL_MAX_SIZE;
1427 1155           doc->val_pool.chunk_size = YYJSON_MUT_DOC_VAL_POOL_INIT_SIZE;
1428 1155           doc->val_pool.chunk_size_max = YYJSON_MUT_DOC_VAL_POOL_MAX_SIZE;
1429 1155           return doc;
1430             }
1431              
1432 0           yyjson_mut_doc *yyjson_doc_mut_copy(yyjson_doc *doc, const yyjson_alc *alc) {
1433             yyjson_mut_doc *m_doc;
1434             yyjson_mut_val *m_val;
1435            
1436 0 0         if (!doc || !doc->root) return NULL;
    0          
1437 0           m_doc = yyjson_mut_doc_new(alc);
1438 0 0         if (!m_doc) return NULL;
1439 0           m_val = yyjson_val_mut_copy(m_doc, doc->root);
1440 0 0         if (!m_val) {
1441 0           yyjson_mut_doc_free(m_doc);
1442 0           return NULL;
1443             }
1444             yyjson_mut_doc_set_root(m_doc, m_val);
1445 0           return m_doc;
1446             }
1447              
1448 0           yyjson_mut_doc *yyjson_mut_doc_mut_copy(yyjson_mut_doc *doc,
1449             const yyjson_alc *alc) {
1450             yyjson_mut_doc *m_doc;
1451             yyjson_mut_val *m_val;
1452            
1453 0 0         if (!doc) return NULL;
1454 0 0         if (!doc->root) return yyjson_mut_doc_new(alc);
1455            
1456 0           m_doc = yyjson_mut_doc_new(alc);
1457 0 0         if (!m_doc) return NULL;
1458 0           m_val = yyjson_mut_val_mut_copy(m_doc, doc->root);
1459 0 0         if (!m_val) {
1460 0           yyjson_mut_doc_free(m_doc);
1461 0           return NULL;
1462             }
1463             yyjson_mut_doc_set_root(m_doc, m_val);
1464 0           return m_doc;
1465             }
1466              
1467 0           yyjson_mut_val *yyjson_val_mut_copy(yyjson_mut_doc *m_doc,
1468             yyjson_val *i_vals) {
1469             /*
1470             The immutable object or array stores all sub-values in a contiguous memory,
1471             We copy them to another contiguous memory as mutable values,
1472             then reconnect the mutable values with the original relationship.
1473             */
1474             usize i_vals_len;
1475             yyjson_mut_val *m_vals, *m_val;
1476             yyjson_val *i_val, *i_end;
1477            
1478 0 0         if (!m_doc || !i_vals) return NULL;
    0          
1479 0           i_end = unsafe_yyjson_get_next(i_vals);
1480 0 0         i_vals_len = (usize)(unsafe_yyjson_get_next(i_vals) - i_vals);
1481 0           m_vals = unsafe_yyjson_mut_val(m_doc, i_vals_len);
1482 0 0         if (!m_vals) return NULL;
1483 0           i_val = i_vals;
1484 0           m_val = m_vals;
1485            
1486 0 0         for (; i_val < i_end; i_val++, m_val++) {
1487 0           yyjson_type type = unsafe_yyjson_get_type(i_val);
1488 0           m_val->tag = i_val->tag;
1489 0           m_val->uni.u64 = i_val->uni.u64;
1490 0 0         if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
    0          
1491 0           const char *str = i_val->uni.str;
1492 0 0         usize str_len = unsafe_yyjson_get_len(i_val);
1493 0           m_val->uni.str = unsafe_yyjson_mut_strncpy(m_doc, str, str_len);
1494 0 0         if (!m_val->uni.str) return NULL;
1495 0 0         } else if (type == YYJSON_TYPE_ARR) {
1496 0           usize len = unsafe_yyjson_get_len(i_val);
1497 0 0         if (len > 0) {
1498 0           yyjson_val *ii_val = i_val + 1, *ii_next;
1499 0           yyjson_mut_val *mm_val = m_val + 1, *mm_ctn = m_val, *mm_next;
1500 0 0         while (len-- > 1) {
1501 0           ii_next = unsafe_yyjson_get_next(ii_val);
1502 0           mm_next = mm_val + (ii_next - ii_val);
1503 0           mm_val->next = mm_next;
1504 0           ii_val = ii_next;
1505 0           mm_val = mm_next;
1506             }
1507 0           mm_val->next = mm_ctn + 1;
1508 0           mm_ctn->uni.ptr = mm_val;
1509             }
1510 0 0         } else if (type == YYJSON_TYPE_OBJ) {
1511 0           usize len = unsafe_yyjson_get_len(i_val);
1512 0 0         if (len > 0) {
1513 0           yyjson_val *ii_key = i_val + 1, *ii_nextkey;
1514 0           yyjson_mut_val *mm_key = m_val + 1, *mm_ctn = m_val;
1515             yyjson_mut_val *mm_nextkey;
1516 0 0         while (len-- > 1) {
1517 0           ii_nextkey = unsafe_yyjson_get_next(ii_key + 1);
1518 0           mm_nextkey = mm_key + (ii_nextkey - ii_key);
1519 0           mm_key->next = mm_key + 1;
1520 0           mm_key->next->next = mm_nextkey;
1521 0           ii_key = ii_nextkey;
1522 0           mm_key = mm_nextkey;
1523             }
1524 0           mm_key->next = mm_key + 1;
1525 0           mm_key->next->next = mm_ctn + 1;
1526 0           mm_ctn->uni.ptr = mm_key;
1527             }
1528             }
1529             }
1530            
1531 0           return m_vals;
1532             }
1533              
1534 0 0         static yyjson_mut_val *unsafe_yyjson_mut_val_mut_copy(yyjson_mut_doc *m_doc,
1535             yyjson_mut_val *m_vals) {
1536             /*
1537             The mutable object or array stores all sub-values in a circular linked
1538             list, so we can traverse them in the same loop. The traversal starts from
1539             the last item, continues with the first item in a list, and ends with the
1540             second to last item, which needs to be linked to the last item to close the
1541             circle.
1542             */
1543 0           yyjson_mut_val *m_val = unsafe_yyjson_mut_val(m_doc, 1);
1544 0 0         if (unlikely(!m_val)) return NULL;
1545 0           m_val->tag = m_vals->tag;
1546            
1547 0           switch (unsafe_yyjson_get_type(m_vals)) {
1548 0           case YYJSON_TYPE_OBJ:
1549             case YYJSON_TYPE_ARR:
1550 0 0         if (unsafe_yyjson_get_len(m_vals) > 0) {
1551 0           yyjson_mut_val *last = (yyjson_mut_val *)m_vals->uni.ptr;
1552 0           yyjson_mut_val *next = last->next, *prev;
1553 0           prev = unsafe_yyjson_mut_val_mut_copy(m_doc, last);
1554 0 0         if (!prev) return NULL;
1555 0           m_val->uni.ptr = (void *)prev;
1556 0 0         while (next != last) {
1557 0           prev->next = unsafe_yyjson_mut_val_mut_copy(m_doc, next);
1558 0 0         if (!prev->next) return NULL;
1559 0           prev = prev->next;
1560 0           next = next->next;
1561             }
1562 0           prev->next = (yyjson_mut_val *)m_val->uni.ptr;
1563             }
1564 0           break;
1565            
1566 0           case YYJSON_TYPE_RAW:
1567             case YYJSON_TYPE_STR: {
1568 0           const char *str = m_vals->uni.str;
1569 0 0         usize str_len = unsafe_yyjson_get_len(m_vals);
1570 0           m_val->uni.str = unsafe_yyjson_mut_strncpy(m_doc, str, str_len);
1571 0 0         if (!m_val->uni.str) return NULL;
1572 0           break;
1573             }
1574            
1575 0           default:
1576 0           m_val->uni = m_vals->uni;
1577 0           break;
1578             }
1579            
1580 0           return m_val;
1581             }
1582              
1583 0           yyjson_mut_val *yyjson_mut_val_mut_copy(yyjson_mut_doc *doc,
1584             yyjson_mut_val *val) {
1585 0 0         if (doc && val) return unsafe_yyjson_mut_val_mut_copy(doc, val);
    0          
1586 0           return NULL;
1587             }
1588              
1589             /* Count the number of values and the total length of the strings. */
1590 0           static void yyjson_mut_stat(yyjson_mut_val *val,
1591             usize *val_sum, usize *str_sum) {
1592 0           yyjson_type type = unsafe_yyjson_get_type(val);
1593 0           *val_sum += 1;
1594 0 0         if (type == YYJSON_TYPE_ARR || type == YYJSON_TYPE_OBJ) {
    0          
1595 0           yyjson_mut_val *child = (yyjson_mut_val *)val->uni.ptr;
1596 0           usize len = unsafe_yyjson_get_len(val), i;
1597 0           len <<= (u8)(type == YYJSON_TYPE_OBJ);
1598 0           *val_sum += len;
1599 0 0         for (i = 0; i < len; i++) {
1600 0           yyjson_type stype = unsafe_yyjson_get_type(child);
1601 0 0         if (stype == YYJSON_TYPE_STR || stype == YYJSON_TYPE_RAW) {
    0          
1602 0           *str_sum += unsafe_yyjson_get_len(child) + 1;
1603 0 0         } else if (stype == YYJSON_TYPE_ARR || stype == YYJSON_TYPE_OBJ) {
    0          
1604 0           yyjson_mut_stat(child, val_sum, str_sum);
1605 0           *val_sum -= 1;
1606             }
1607 0           child = child->next;
1608             }
1609 0 0         } else if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
    0          
1610 0           *str_sum += unsafe_yyjson_get_len(val) + 1;
1611             }
1612 0           }
1613              
1614             /* Copy mutable values to immutable value pool. */
1615 0           static usize yyjson_imut_copy(yyjson_val **val_ptr, char **buf_ptr,
1616             yyjson_mut_val *mval) {
1617 0           yyjson_val *val = *val_ptr;
1618 0           yyjson_type type = unsafe_yyjson_get_type(mval);
1619 0 0         if (type == YYJSON_TYPE_ARR || type == YYJSON_TYPE_OBJ) {
    0          
1620 0           yyjson_mut_val *child = (yyjson_mut_val *)mval->uni.ptr;
1621 0           usize len = unsafe_yyjson_get_len(mval), i;
1622 0           usize val_sum = 1;
1623 0 0         if (type == YYJSON_TYPE_OBJ) {
1624 0 0         if (len) child = child->next->next;
1625 0           len <<= 1;
1626             } else {
1627 0 0         if (len) child = child->next;
1628             }
1629 0           *val_ptr = val + 1;
1630 0 0         for (i = 0; i < len; i++) {
1631 0           val_sum += yyjson_imut_copy(val_ptr, buf_ptr, child);
1632 0           child = child->next;
1633             }
1634 0           val->tag = mval->tag;
1635 0           val->uni.ofs = val_sum * sizeof(yyjson_val);
1636 0           return val_sum;
1637 0 0         } else if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
    0          
1638 0           char *buf = *buf_ptr;
1639 0           usize len = unsafe_yyjson_get_len(mval);
1640 0           memcpy((void *)buf, (const void *)mval->uni.str, len);
1641 0           buf[len] = '\0';
1642 0           val->tag = mval->tag;
1643 0           val->uni.str = buf;
1644 0           *val_ptr = val + 1;
1645 0           *buf_ptr = buf + len + 1;
1646 0           return 1;
1647             } else {
1648 0           val->tag = mval->tag;
1649 0           val->uni = mval->uni;
1650 0           *val_ptr = val + 1;
1651 0           return 1;
1652             }
1653             }
1654              
1655 0           yyjson_doc *yyjson_mut_doc_imut_copy(yyjson_mut_doc *mdoc,
1656             const yyjson_alc *alc) {
1657 0 0         if (!mdoc) return NULL;
1658 0           return yyjson_mut_val_imut_copy(mdoc->root, alc);
1659             }
1660              
1661 0           yyjson_doc *yyjson_mut_val_imut_copy(yyjson_mut_val *mval,
1662             const yyjson_alc *alc) {
1663 0           usize val_num = 0, str_sum = 0, hdr_size, buf_size;
1664 0           yyjson_doc *doc = NULL;
1665 0           yyjson_val *val_hdr = NULL;
1666            
1667             /* This value should be NULL here. Setting a non-null value suppresses
1668             warning from the clang analyzer. */
1669 0           char *str_hdr = (char *)(void *)&str_sum;
1670 0 0         if (!mval) return NULL;
1671 0 0         if (!alc) alc = &YYJSON_DEFAULT_ALC;
1672            
1673             /* traverse the input value to get pool size */
1674 0           yyjson_mut_stat(mval, &val_num, &str_sum);
1675            
1676             /* create doc and val pool */
1677 0           hdr_size = size_align_up(sizeof(yyjson_doc), sizeof(yyjson_val));
1678 0           buf_size = hdr_size + val_num * sizeof(yyjson_val);
1679 0           doc = (yyjson_doc *)alc->malloc(alc->ctx, buf_size);
1680 0 0         if (!doc) return NULL;
1681 0           memset(doc, 0, sizeof(yyjson_doc));
1682 0           val_hdr = (yyjson_val *)(void *)((char *)(void *)doc + hdr_size);
1683 0           doc->root = val_hdr;
1684 0           doc->alc = *alc;
1685            
1686             /* create str pool */
1687 0 0         if (str_sum > 0) {
1688 0           str_hdr = (char *)alc->malloc(alc->ctx, str_sum);
1689 0           doc->str_pool = str_hdr;
1690 0 0         if (!str_hdr) {
1691 0           alc->free(alc->ctx, (void *)doc);
1692 0           return NULL;
1693             }
1694             }
1695            
1696             /* copy vals and strs */
1697 0           doc->val_read = yyjson_imut_copy(&val_hdr, &str_hdr, mval);
1698 0           doc->dat_read = str_sum + 1;
1699 0           return doc;
1700             }
1701              
1702             static_inline bool unsafe_yyjson_num_equals(void *lhs, void *rhs) {
1703 0           yyjson_val_uni *luni = &((yyjson_val *)lhs)->uni;
1704 0           yyjson_val_uni *runi = &((yyjson_val *)rhs)->uni;
1705 0           yyjson_subtype lt = unsafe_yyjson_get_subtype(lhs);
1706 0           yyjson_subtype rt = unsafe_yyjson_get_subtype(rhs);
1707 0 0         if (lt == rt) return luni->u64 == runi->u64;
    0          
1708 0 0         if (lt == YYJSON_SUBTYPE_SINT && rt == YYJSON_SUBTYPE_UINT) {
    0          
    0          
    0          
1709 0 0         return luni->i64 >= 0 && luni->u64 == runi->u64;
    0          
    0          
    0          
1710             }
1711 0 0         if (lt == YYJSON_SUBTYPE_UINT && rt == YYJSON_SUBTYPE_SINT) {
    0          
    0          
    0          
1712 0 0         return runi->i64 >= 0 && luni->u64 == runi->u64;
    0          
    0          
    0          
1713             }
1714 0           return false;
1715             }
1716              
1717             static_inline bool unsafe_yyjson_str_equals(void *lhs, void *rhs) {
1718 0           usize len = unsafe_yyjson_get_len(lhs);
1719 0 0         if (len != unsafe_yyjson_get_len(rhs)) return false;
    0          
1720 0           return !memcmp(unsafe_yyjson_get_str(lhs),
1721 0           unsafe_yyjson_get_str(rhs), len);
1722             }
1723              
1724 0           bool unsafe_yyjson_equals(yyjson_val *lhs, yyjson_val *rhs) {
1725 0           yyjson_type type = unsafe_yyjson_get_type(lhs);
1726 0 0         if (type != unsafe_yyjson_get_type(rhs)) return false;
1727            
1728 0           switch (type) {
1729 0           case YYJSON_TYPE_OBJ: {
1730 0           usize len = unsafe_yyjson_get_len(lhs);
1731 0 0         if (len != unsafe_yyjson_get_len(rhs)) return false;
1732 0 0         if (len > 0) {
1733             yyjson_obj_iter iter;
1734             yyjson_obj_iter_init(rhs, &iter);
1735 0           lhs = unsafe_yyjson_get_first(lhs);
1736 0 0         while (len-- > 0) {
1737 0 0         rhs = yyjson_obj_iter_getn(&iter, lhs->uni.str,
1738             unsafe_yyjson_get_len(lhs));
1739 0 0         if (!rhs) return false;
1740 0 0         if (!unsafe_yyjson_equals(lhs + 1, rhs)) return false;
1741 0           lhs = unsafe_yyjson_get_next(lhs + 1);
1742             }
1743             }
1744             /* yyjson allows duplicate keys, so the check may be inaccurate */
1745 0           return true;
1746             }
1747            
1748 0           case YYJSON_TYPE_ARR: {
1749 0           usize len = unsafe_yyjson_get_len(lhs);
1750 0 0         if (len != unsafe_yyjson_get_len(rhs)) return false;
1751 0 0         if (len > 0) {
1752 0           lhs = unsafe_yyjson_get_first(lhs);
1753 0           rhs = unsafe_yyjson_get_first(rhs);
1754 0 0         while (len-- > 0) {
1755 0 0         if (!unsafe_yyjson_equals(lhs, rhs)) return false;
1756 0           lhs = unsafe_yyjson_get_next(lhs);
1757 0           rhs = unsafe_yyjson_get_next(rhs);
1758             }
1759             }
1760 0           return true;
1761             }
1762            
1763 0           case YYJSON_TYPE_NUM:
1764 0           return unsafe_yyjson_num_equals(lhs, rhs);
1765            
1766 0           case YYJSON_TYPE_RAW:
1767             case YYJSON_TYPE_STR:
1768 0           return unsafe_yyjson_str_equals(lhs, rhs);
1769            
1770 0           case YYJSON_TYPE_NULL:
1771             case YYJSON_TYPE_BOOL:
1772 0           return lhs->tag == rhs->tag;
1773            
1774 0           default:
1775 0           return false;
1776             }
1777             }
1778              
1779 0           bool unsafe_yyjson_mut_equals(yyjson_mut_val *lhs, yyjson_mut_val *rhs) {
1780 0           yyjson_type type = unsafe_yyjson_get_type(lhs);
1781 0 0         if (type != unsafe_yyjson_get_type(rhs)) return false;
1782            
1783 0           switch (type) {
1784 0           case YYJSON_TYPE_OBJ: {
1785 0           usize len = unsafe_yyjson_get_len(lhs);
1786 0 0         if (len != unsafe_yyjson_get_len(rhs)) return false;
1787 0 0         if (len > 0) {
1788             yyjson_mut_obj_iter iter;
1789             yyjson_mut_obj_iter_init(rhs, &iter);
1790 0           lhs = (yyjson_mut_val *)lhs->uni.ptr;
1791 0 0         while (len-- > 0) {
1792 0 0         rhs = yyjson_mut_obj_iter_getn(&iter, lhs->uni.str,
1793             unsafe_yyjson_get_len(lhs));
1794 0 0         if (!rhs) return false;
1795 0 0         if (!unsafe_yyjson_mut_equals(lhs->next, rhs)) return false;
1796 0           lhs = lhs->next->next;
1797             }
1798             }
1799             /* yyjson allows duplicate keys, so the check may be inaccurate */
1800 0           return true;
1801             }
1802            
1803 0           case YYJSON_TYPE_ARR: {
1804 0           usize len = unsafe_yyjson_get_len(lhs);
1805 0 0         if (len != unsafe_yyjson_get_len(rhs)) return false;
1806 0 0         if (len > 0) {
1807 0           lhs = (yyjson_mut_val *)lhs->uni.ptr;
1808 0           rhs = (yyjson_mut_val *)rhs->uni.ptr;
1809 0 0         while (len-- > 0) {
1810 0 0         if (!unsafe_yyjson_mut_equals(lhs, rhs)) return false;
1811 0           lhs = lhs->next;
1812 0           rhs = rhs->next;
1813             }
1814             }
1815 0           return true;
1816             }
1817            
1818 0           case YYJSON_TYPE_NUM:
1819 0           return unsafe_yyjson_num_equals(lhs, rhs);
1820            
1821 0           case YYJSON_TYPE_RAW:
1822             case YYJSON_TYPE_STR:
1823 0           return unsafe_yyjson_str_equals(lhs, rhs);
1824            
1825 0           case YYJSON_TYPE_NULL:
1826             case YYJSON_TYPE_BOOL:
1827 0           return lhs->tag == rhs->tag;
1828            
1829 0           default:
1830 0           return false;
1831             }
1832             }
1833              
1834 0           bool yyjson_locate_pos(const char *str, size_t len, size_t pos,
1835             size_t *line, size_t *col, size_t *chr) {
1836 0           usize line_sum = 0, line_pos = 0, chr_sum = 0;
1837 0           const u8 *cur = (const u8 *)str;
1838 0           const u8 *end = cur + pos;
1839            
1840 0 0         if (!str || pos > len) {
    0          
1841 0 0         if (line) *line = 0;
1842 0 0         if (col) *col = 0;
1843 0 0         if (chr) *chr = 0;
1844 0           return false;
1845             }
1846            
1847 0 0         while (cur < end) {
1848 0           u8 c = *cur;
1849 0           chr_sum += 1;
1850 0 0         if (likely(c < 0x80)) { /* 0xxxxxxx (0x00-0x7F) ASCII */
1851 0 0         if (c == '\n') {
1852 0           line_sum += 1;
1853 0           line_pos = chr_sum;
1854             }
1855 0           cur += 1;
1856             }
1857 0 0         else if (c < 0xC0) cur += 1; /* 10xxxxxx (0x80-0xBF) Invalid */
1858 0 0         else if (c < 0xE0) cur += 2; /* 110xxxxx (0xC0-0xDF) 2-byte UTF-8 */
1859 0 0         else if (c < 0xF0) cur += 3; /* 1110xxxx (0xE0-0xEF) 3-byte UTF-8 */
1860 0 0         else if (c < 0xF8) cur += 4; /* 11110xxx (0xF0-0xF7) 4-byte UTF-8 */
1861 0           else cur += 1; /* 11111xxx (0xF8-0xFF) Invalid */
1862             }
1863            
1864 0 0         if (line) *line = line_sum + 1;
1865 0 0         if (col) *col = chr_sum - line_pos + 1;
1866 0 0         if (chr) *chr = chr_sum;
1867 0           return true;
1868             }
1869              
1870              
1871              
1872             #if !YYJSON_DISABLE_UTILS
1873              
1874             /*==============================================================================
1875             * JSON Pointer API (RFC 6901)
1876             *============================================================================*/
1877              
1878             /**
1879             Get a token from JSON pointer string.
1880             @param ptr [in,out]
1881             in: string that points to current token prefix `/`
1882             out: string that points to next token prefix `/`, or string end
1883             @param end [in] end of the entire JSON Pointer string
1884             @param len [out] unescaped token length
1885             @param esc [out] number of escaped characters in this token
1886             @return head of the token, or NULL if syntax error
1887             */
1888             static_inline const char *ptr_next_token(const char **ptr, const char *end,
1889             usize *len, usize *esc) {
1890 0           const char *hdr = *ptr + 1;
1891 0           const char *cur = hdr;
1892             /* skip unescaped characters */
1893 0 0         while (cur < end && *cur != '/' && *cur != '~') cur++;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1894 0 0         if (likely(cur == end || *cur != '~')) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1895             /* no escaped characters, return */
1896 0           *ptr = cur;
1897 0           *len = (usize)(cur - hdr);
1898 0           *esc = 0;
1899 0           return hdr;
1900             } else {
1901             /* handle escaped characters */
1902 0           usize esc_num = 0;
1903 0 0         while (cur < end && *cur != '/') {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1904 0 0         if (*cur++ == '~') {
    0          
    0          
    0          
    0          
1905 0 0         if (cur == end || (*cur != '0' && *cur != '1')) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1906 0           *ptr = cur - 1;
1907 0           return NULL;
1908             }
1909 0           esc_num++;
1910             }
1911             }
1912 0           *ptr = cur;
1913 0           *len = (usize)(cur - hdr) - esc_num;
1914 0           *esc = esc_num;
1915 0           return hdr;
1916             }
1917             }
1918              
1919             /**
1920             Convert token string to index.
1921             @param cur [in] token head
1922             @param len [in] token length
1923             @param idx [out] the index number, or USIZE_MAX if token is '-'
1924             @return true if token is a valid array index
1925             */
1926             static_inline bool ptr_token_to_idx(const char *cur, usize len, usize *idx) {
1927 0           const char *end = cur + len;
1928 0           usize num = 0, add;
1929 0 0         if (unlikely(len == 0 || len > USIZE_SAFE_DIG)) return false;
    0          
    0          
    0          
    0          
    0          
1930 0 0         if (*cur == '0') {
    0          
    0          
1931 0 0         if (unlikely(len > 1)) return false;
    0          
    0          
1932 0           *idx = 0;
1933 0           return true;
1934             }
1935 0 0         if (*cur == '-') {
    0          
    0          
1936 0 0         if (unlikely(len > 1)) return false;
    0          
    0          
1937 0           *idx = USIZE_MAX;
1938 0           return true;
1939             }
1940 0 0         for (; cur < end && (add = (usize)((u8)*cur - (u8)'0')) <= 9; cur++) {
    0          
    0          
    0          
    0          
    0          
1941 0           num = num * 10 + add;
1942             }
1943 0 0         if (unlikely(num == 0 || cur < end)) return false;
    0          
    0          
    0          
    0          
    0          
1944 0           *idx = num;
1945 0           return true;
1946             }
1947              
1948             /**
1949             Compare JSON key with token.
1950             @param key a string key (yyjson_val or yyjson_mut_val)
1951             @param token a JSON pointer token
1952             @param len unescaped token length
1953             @param esc number of escaped characters in this token
1954             @return true if `str` is equals to `token`
1955             */
1956             static_inline bool ptr_token_eq(void *key,
1957             const char *token, usize len, usize esc) {
1958 0           yyjson_val *val = (yyjson_val *)key;
1959 0 0         if (unsafe_yyjson_get_len(val) != len) return false;
    0          
    0          
1960 0 0         if (likely(!esc)) {
    0          
    0          
1961 0           return memcmp(val->uni.str, token, len) == 0;
1962             } else {
1963 0           const char *str = val->uni.str;
1964 0 0         for (; len-- > 0; token++, str++) {
    0          
    0          
1965 0 0         if (*token == '~') {
    0          
    0          
1966 0 0         if (*str != (*++token == '0' ? '~' : '/')) return false;
    0          
    0          
    0          
    0          
    0          
1967             } else {
1968 0 0         if (*str != *token) return false;
    0          
    0          
1969             }
1970             }
1971 0           return true;
1972             }
1973             }
1974              
1975             /**
1976             Get a value from array by token.
1977             @param arr an array, should not be NULL or non-array type
1978             @param token a JSON pointer token
1979             @param len unescaped token length
1980             @param esc number of escaped characters in this token
1981             @return value at index, or NULL if token is not index or index is out of range
1982             */
1983             static_inline yyjson_val *ptr_arr_get(yyjson_val *arr, const char *token,
1984             usize len, usize esc) {
1985 0           yyjson_val *val = unsafe_yyjson_get_first(arr);
1986 0           usize num = unsafe_yyjson_get_len(arr), idx = 0;
1987 0 0         if (unlikely(num == 0)) return NULL;
1988 0 0         if (unlikely(!ptr_token_to_idx(token, len, &idx))) return NULL;
1989 0 0         if (unlikely(idx >= num)) return NULL;
1990 0 0         if (unsafe_yyjson_arr_is_flat(arr)) {
1991 0           return val + idx;
1992             } else {
1993 0 0         while (idx-- > 0) val = unsafe_yyjson_get_next(val);
1994 0           return val;
1995             }
1996             }
1997              
1998             /**
1999             Get a value from object by token.
2000             @param obj [in] an object, should not be NULL or non-object type
2001             @param token [in] a JSON pointer token
2002             @param len [in] unescaped token length
2003             @param esc [in] number of escaped characters in this token
2004             @return value associated with the token, or NULL if no value
2005             */
2006             static_inline yyjson_val *ptr_obj_get(yyjson_val *obj, const char *token,
2007             usize len, usize esc) {
2008 0           yyjson_val *key = unsafe_yyjson_get_first(obj);
2009 0           usize num = unsafe_yyjson_get_len(obj);
2010 0 0         if (unlikely(num == 0)) return NULL;
2011 0 0         for (; num > 0; num--, key = unsafe_yyjson_get_next(key + 1)) {
2012 0 0         if (ptr_token_eq(key, token, len, esc)) return key + 1;
2013             }
2014 0           return NULL;
2015             }
2016              
2017             /**
2018             Get a value from array by token.
2019             @param arr [in] an array, should not be NULL or non-array type
2020             @param token [in] a JSON pointer token
2021             @param len [in] unescaped token length
2022             @param esc [in] number of escaped characters in this token
2023             @param pre [out] previous (sibling) value of the returned value
2024             @param last [out] whether index is last
2025             @return value at index, or NULL if token is not index or index is out of range
2026             */
2027             static_inline yyjson_mut_val *ptr_mut_arr_get(yyjson_mut_val *arr,
2028             const char *token,
2029             usize len, usize esc,
2030             yyjson_mut_val **pre,
2031             bool *last) {
2032 0           yyjson_mut_val *val = (yyjson_mut_val *)arr->uni.ptr; /* last (tail) */
2033 0           usize num = unsafe_yyjson_get_len(arr), idx;
2034 0 0         if (last) *last = false;
    0          
2035 0 0         if (pre) *pre = NULL;
    0          
2036 0 0         if (unlikely(num == 0)) {
    0          
2037 0 0         if (last && len == 1 && (*token == '0' || *token == '-')) *last = true;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2038 0           return NULL;
2039             }
2040 0 0         if (unlikely(!ptr_token_to_idx(token, len, &idx))) return NULL;
    0          
2041 0 0         if (last) *last = (idx == num || idx == USIZE_MAX);
    0          
    0          
    0          
    0          
    0          
2042 0 0         if (unlikely(idx >= num)) return NULL;
    0          
2043 0 0         while (idx-- > 0) val = val->next;
    0          
2044 0           *pre = val;
2045 0           return val->next;
2046             }
2047              
2048             /**
2049             Get a value from object by token.
2050             @param obj [in] an object, should not be NULL or non-object type
2051             @param token [in] a JSON pointer token
2052             @param len [in] unescaped token length
2053             @param esc [in] number of escaped characters in this token
2054             @param pre [out] previous (sibling) key of the returned value's key
2055             @return value associated with the token, or NULL if no value
2056             */
2057             static_inline yyjson_mut_val *ptr_mut_obj_get(yyjson_mut_val *obj,
2058             const char *token,
2059             usize len, usize esc,
2060             yyjson_mut_val **pre) {
2061 0           yyjson_mut_val *pre_key = (yyjson_mut_val *)obj->uni.ptr, *key;
2062 0           usize num = unsafe_yyjson_get_len(obj);
2063 0 0         if (pre) *pre = NULL;
    0          
2064 0 0         if (unlikely(num == 0)) return NULL;
    0          
2065 0 0         for (; num > 0; num--, pre_key = key) {
    0          
2066 0           key = pre_key->next->next;
2067 0 0         if (ptr_token_eq(key, token, len, esc)) {
    0          
2068 0           *pre = pre_key;
2069 0           return key->next;
2070             }
2071             }
2072 0           return NULL;
2073             }
2074              
2075             /**
2076             Create a string value with JSON pointer token.
2077             @param token [in] a JSON pointer token
2078             @param len [in] unescaped token length
2079             @param esc [in] number of escaped characters in this token
2080             @param doc [in] used for memory allocation when creating value
2081             @return new string value, or NULL if memory allocation failed
2082             */
2083             static_inline yyjson_mut_val *ptr_new_key(const char *token,
2084             usize len, usize esc,
2085             yyjson_mut_doc *doc) {
2086 0           const char *src = token;
2087 0           if (likely(!esc)) {
2088 0           return yyjson_mut_strncpy(doc, src, len);
2089             } else {
2090 0           const char *end = src + len + esc;
2091 0 0         char *dst = unsafe_yyjson_mut_str_alc(doc, len + esc);
    0          
2092 0           char *str = dst;
2093 0 0         if (unlikely(!dst)) return NULL;
    0          
2094 0 0         for (; src < end; src++, dst++) {
    0          
2095 0 0         if (*src != '~') *dst = *src;
    0          
2096 0 0         else *dst = (*++src == '0' ? '~' : '/');
    0          
2097             }
2098 0 0         *dst = '\0';
    0          
2099 0           return yyjson_mut_strn(doc, str, len);
2100             }
2101             }
2102              
2103             /* macros for yyjson_ptr */
2104             #define return_err(_ret, _code, _pos, _msg) do { \
2105             if (err) { \
2106             err->code = YYJSON_PTR_ERR_##_code; \
2107             err->msg = _msg; \
2108             err->pos = (usize)(_pos); \
2109             } \
2110             return _ret; \
2111             } while (false)
2112              
2113             #define return_err_resolve(_ret, _pos) \
2114             return_err(_ret, RESOLVE, _pos, "JSON pointer cannot be resolved")
2115             #define return_err_syntax(_ret, _pos) \
2116             return_err(_ret, SYNTAX, _pos, "invalid escaped character")
2117             #define return_err_alloc(_ret) \
2118             return_err(_ret, MEMORY_ALLOCATION, 0, "failed to create value")
2119              
2120 0           yyjson_val *unsafe_yyjson_ptr_getx(yyjson_val *val,
2121             const char *ptr, size_t ptr_len,
2122             yyjson_ptr_err *err) {
2123            
2124 0           const char *hdr = ptr, *end = ptr + ptr_len, *token;
2125             usize len, esc;
2126             yyjson_type type;
2127            
2128             while (true) {
2129 0           token = ptr_next_token(&ptr, end, &len, &esc);
2130 0 0         if (unlikely(!token)) return_err_syntax(NULL, ptr - hdr);
    0          
2131 0           type = unsafe_yyjson_get_type(val);
2132 0 0         if (type == YYJSON_TYPE_OBJ) {
2133 0           val = ptr_obj_get(val, token, len, esc);
2134 0 0         } else if (type == YYJSON_TYPE_ARR) {
2135 0           val = ptr_arr_get(val, token, len, esc);
2136             } else {
2137 0           val = NULL;
2138             }
2139 0 0         if (!val) return_err_resolve(NULL, token - hdr);
    0          
2140 0 0         if (ptr == end) return val;
2141             }
2142             }
2143              
2144 0           yyjson_mut_val *unsafe_yyjson_mut_ptr_getx(yyjson_mut_val *val,
2145             const char *ptr,
2146             size_t ptr_len,
2147             yyjson_ptr_ctx *ctx,
2148             yyjson_ptr_err *err) {
2149            
2150 0           const char *hdr = ptr, *end = ptr + ptr_len, *token;
2151             usize len, esc;
2152 0           yyjson_mut_val *ctn, *pre = NULL;
2153             yyjson_type type;
2154 0           bool idx_is_last = false;
2155            
2156             while (true) {
2157 0           token = ptr_next_token(&ptr, end, &len, &esc);
2158 0 0         if (unlikely(!token)) return_err_syntax(NULL, ptr - hdr);
    0          
2159 0           ctn = val;
2160 0           type = unsafe_yyjson_get_type(val);
2161 0 0         if (type == YYJSON_TYPE_OBJ) {
2162 0           val = ptr_mut_obj_get(val, token, len, esc, &pre);
2163 0 0         } else if (type == YYJSON_TYPE_ARR) {
2164 0           val = ptr_mut_arr_get(val, token, len, esc, &pre, &idx_is_last);
2165             } else {
2166 0           val = NULL;
2167             }
2168 0 0         if (ctx && (ptr == end)) {
    0          
2169 0 0         if (type == YYJSON_TYPE_OBJ ||
    0          
2170 0 0         (type == YYJSON_TYPE_ARR && (val || idx_is_last))) {
    0          
2171 0           ctx->ctn = ctn;
2172 0           ctx->pre = pre;
2173             }
2174             }
2175 0 0         if (!val) return_err_resolve(NULL, token - hdr);
    0          
2176 0 0         if (ptr == end) return val;
2177             }
2178             }
2179              
2180 0           bool unsafe_yyjson_mut_ptr_putx(yyjson_mut_val *val,
2181             const char *ptr, size_t ptr_len,
2182             yyjson_mut_val *new_val,
2183             yyjson_mut_doc *doc,
2184             bool create_parent, bool insert_new,
2185             yyjson_ptr_ctx *ctx,
2186             yyjson_ptr_err *err) {
2187            
2188 0           const char *hdr = ptr, *end = ptr + ptr_len, *token;
2189             usize token_len, esc, ctn_len;
2190 0           yyjson_mut_val *ctn, *key, *pre = NULL;
2191 0           yyjson_mut_val *sep_ctn = NULL, *sep_key = NULL, *sep_val = NULL;
2192             yyjson_type ctn_type;
2193 0           bool idx_is_last = false;
2194            
2195             /* skip exist parent nodes */
2196             while (true) {
2197 0           token = ptr_next_token(&ptr, end, &token_len, &esc);
2198 0 0         if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
    0          
2199 0           ctn = val;
2200 0           ctn_type = unsafe_yyjson_get_type(ctn);
2201 0 0         if (ctn_type == YYJSON_TYPE_OBJ) {
2202 0           val = ptr_mut_obj_get(ctn, token, token_len, esc, &pre);
2203 0 0         } else if (ctn_type == YYJSON_TYPE_ARR) {
2204 0           val = ptr_mut_arr_get(ctn, token, token_len, esc, &pre,
2205             &idx_is_last);
2206 0 0         } else return_err_resolve(false, token - hdr);
2207 0 0         if (!val) break;
2208 0 0         if (ptr == end) break; /* is last token */
2209             }
2210            
2211             /* create parent nodes if not exist */
2212 0 0         if (unlikely(ptr != end)) { /* not last token */
2213 0 0         if (!create_parent) return_err_resolve(false, token - hdr);
    0          
2214            
2215             /* add value at last index if container is array */
2216 0 0         if (ctn_type == YYJSON_TYPE_ARR) {
2217 0 0         if (!idx_is_last || !insert_new) {
    0          
2218 0 0         return_err_resolve(false, token - hdr);
2219             }
2220 0           val = yyjson_mut_obj(doc);
2221 0 0         if (!val) return_err_alloc(false);
    0          
2222            
2223             /* delay attaching until all operations are completed */
2224 0           sep_ctn = ctn;
2225 0           sep_key = NULL;
2226 0           sep_val = val;
2227            
2228             /* move to next token */
2229 0           ctn = val;
2230 0           val = NULL;
2231 0           ctn_type = YYJSON_TYPE_OBJ;
2232 0           token = ptr_next_token(&ptr, end, &token_len, &esc);
2233 0 0         if (unlikely(!token)) return_err_resolve(false, token - hdr);
    0          
2234             }
2235            
2236             /* container is object, create parent nodes */
2237 0 0         while (ptr != end) { /* not last token */
2238 0 0         key = ptr_new_key(token, token_len, esc, doc);
2239 0 0         if (!key) return_err_alloc(false);
    0          
2240 0           val = yyjson_mut_obj(doc);
2241 0 0         if (!val) return_err_alloc(false);
    0          
2242            
2243             /* delay attaching until all operations are completed */
2244 0 0         if (!sep_ctn) {
2245 0           sep_ctn = ctn;
2246 0           sep_key = key;
2247 0           sep_val = val;
2248             } else {
2249             yyjson_mut_obj_add(ctn, key, val);
2250             }
2251            
2252             /* move to next token */
2253 0           ctn = val;
2254 0           val = NULL;
2255 0           token = ptr_next_token(&ptr, end, &token_len, &esc);
2256 0 0         if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
    0          
2257             }
2258             }
2259            
2260             /* JSON pointer is resolved, insert or replace target value */
2261 0           ctn_len = unsafe_yyjson_get_len(ctn);
2262 0 0         if (ctn_type == YYJSON_TYPE_OBJ) {
2263 0 0         if (ctx) ctx->ctn = ctn;
2264 0 0         if (!val || insert_new) {
    0          
2265             /* insert new key-value pair */
2266 0 0         key = ptr_new_key(token, token_len, esc, doc);
2267 0 0         if (unlikely(!key)) return_err_alloc(false);
    0          
2268 0 0         if (ctx) ctx->pre = ctn_len ? (yyjson_mut_val *)ctn->uni.ptr : key;
    0          
2269 0           unsafe_yyjson_mut_obj_add(ctn, key, new_val, ctn_len);
2270             } else {
2271             /* replace exist value */
2272 0           key = pre->next->next;
2273 0 0         if (ctx) ctx->pre = pre;
2274 0 0         if (ctx) ctx->old = val;
2275             yyjson_mut_obj_put(ctn, key, new_val);
2276             }
2277             } else {
2278             /* array */
2279 0 0         if (ctx && (val || idx_is_last)) ctx->ctn = ctn;
    0          
    0          
2280 0 0         if (insert_new) {
2281             /* append new value */
2282 0 0         if (val) {
2283 0           pre->next = new_val;
2284 0           new_val->next = val;
2285 0 0         if (ctx) ctx->pre = pre;
2286 0           unsafe_yyjson_set_len(ctn, ctn_len + 1);
2287 0 0         } else if (idx_is_last) {
2288 0 0         if (ctx) ctx->pre = ctn_len ?
2289 0 0         (yyjson_mut_val *)ctn->uni.ptr : new_val;
2290             yyjson_mut_arr_append(ctn, new_val);
2291             } else {
2292 0 0         return_err_resolve(false, token - hdr);
2293             }
2294             } else {
2295             /* replace exist value */
2296 0 0         if (!val) return_err_resolve(false, token - hdr);
    0          
2297 0 0         if (ctn_len > 1) {
2298 0           new_val->next = val->next;
2299 0           pre->next = new_val;
2300 0 0         if (ctn->uni.ptr == val) ctn->uni.ptr = new_val;
2301             } else {
2302 0           new_val->next = new_val;
2303 0           ctn->uni.ptr = new_val;
2304 0           pre = new_val;
2305             }
2306 0 0         if (ctx) ctx->pre = pre;
2307 0 0         if (ctx) ctx->old = val;
2308             }
2309             }
2310            
2311             /* all operations are completed, attach the new components to the target */
2312 0 0         if (unlikely(sep_ctn)) {
2313 0 0         if (sep_key) yyjson_mut_obj_add(sep_ctn, sep_key, sep_val);
2314             else yyjson_mut_arr_append(sep_ctn, sep_val);
2315             }
2316 0           return true;
2317             }
2318              
2319 0           yyjson_mut_val *unsafe_yyjson_mut_ptr_replacex(
2320             yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val,
2321             yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
2322            
2323             yyjson_mut_val *cur_val;
2324             yyjson_ptr_ctx cur_ctx;
2325 0           memset(&cur_ctx, 0, sizeof(cur_ctx));
2326 0 0         if (!ctx) ctx = &cur_ctx;
2327 0           cur_val = unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err);
2328 0 0         if (!cur_val) return NULL;
2329            
2330 0 0         if (yyjson_mut_is_obj(ctx->ctn)) {
    0          
2331 0           yyjson_mut_val *key = ctx->pre->next->next;
2332 0 0         yyjson_mut_obj_put(ctx->ctn, key, new_val);
2333             } else {
2334             yyjson_ptr_ctx_replace(ctx, new_val);
2335             }
2336 0           ctx->old = cur_val;
2337 0           return cur_val;
2338             }
2339              
2340 0           yyjson_mut_val *unsafe_yyjson_mut_ptr_removex(yyjson_mut_val *val,
2341             const char *ptr,
2342             size_t len,
2343             yyjson_ptr_ctx *ctx,
2344             yyjson_ptr_err *err) {
2345             yyjson_mut_val *cur_val;
2346             yyjson_ptr_ctx cur_ctx;
2347 0           memset(&cur_ctx, 0, sizeof(cur_ctx));
2348 0 0         if (!ctx) ctx = &cur_ctx;
2349 0           cur_val = unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err);
2350 0 0         if (cur_val) {
2351 0 0         if (yyjson_mut_is_obj(ctx->ctn)) {
    0          
2352 0           yyjson_mut_val *key = ctx->pre->next->next;
2353 0 0         yyjson_mut_obj_put(ctx->ctn, key, NULL);
2354             } else {
2355             yyjson_ptr_ctx_remove(ctx);
2356             }
2357 0           ctx->pre = NULL;
2358 0           ctx->old = cur_val;
2359             }
2360 0           return cur_val;
2361             }
2362              
2363             /* macros for yyjson_ptr */
2364             #undef return_err
2365             #undef return_err_resolve
2366             #undef return_err_syntax
2367             #undef return_err_alloc
2368              
2369              
2370              
2371             /*==============================================================================
2372             * JSON Patch API (RFC 6902)
2373             *============================================================================*/
2374              
2375             /* JSON Patch operation */
2376             typedef enum patch_op {
2377             PATCH_OP_ADD, /* path, value */
2378             PATCH_OP_REMOVE, /* path */
2379             PATCH_OP_REPLACE, /* path, value */
2380             PATCH_OP_MOVE, /* from, path */
2381             PATCH_OP_COPY, /* from, path */
2382             PATCH_OP_TEST, /* path, value */
2383             PATCH_OP_NONE /* invalid */
2384             } patch_op;
2385              
2386 0           static patch_op patch_op_get(yyjson_val *op) {
2387 0           const char *str = op->uni.str;
2388 0           switch (unsafe_yyjson_get_len(op)) {
2389 0           case 3:
2390 0 0         if (!memcmp(str, "add", 3)) return PATCH_OP_ADD;
2391 0           return PATCH_OP_NONE;
2392 0           case 4:
2393 0 0         if (!memcmp(str, "move", 4)) return PATCH_OP_MOVE;
2394 0 0         if (!memcmp(str, "copy", 4)) return PATCH_OP_COPY;
2395 0 0         if (!memcmp(str, "test", 4)) return PATCH_OP_TEST;
2396 0           return PATCH_OP_NONE;
2397 0           case 6:
2398 0 0         if (!memcmp(str, "remove", 6)) return PATCH_OP_REMOVE;
2399 0           return PATCH_OP_NONE;
2400 0           case 7:
2401 0 0         if (!memcmp(str, "replace", 7)) return PATCH_OP_REPLACE;
2402 0           return PATCH_OP_NONE;
2403 0           default:
2404 0           return PATCH_OP_NONE;
2405             }
2406             }
2407              
2408             /* macros for yyjson_patch */
2409             #define return_err(_code, _msg) do { \
2410             if (err->ptr.code == YYJSON_PTR_ERR_MEMORY_ALLOCATION) { \
2411             err->code = YYJSON_PATCH_ERROR_MEMORY_ALLOCATION; \
2412             err->msg = _msg; \
2413             memset(&err->ptr, 0, sizeof(yyjson_ptr_err)); \
2414             } else { \
2415             err->code = YYJSON_PATCH_ERROR_##_code; \
2416             err->msg = _msg; \
2417             err->idx = iter.idx ? iter.idx - 1 : 0; \
2418             } \
2419             return NULL; \
2420             } while (false)
2421              
2422             #define return_err_copy() \
2423             return_err(MEMORY_ALLOCATION, "failed to copy value")
2424             #define return_err_key(_key) \
2425             return_err(MISSING_KEY, "missing key " _key)
2426             #define return_err_val(_key) \
2427             return_err(INVALID_MEMBER, "invalid member " _key)
2428              
2429             #define ptr_get(_ptr) yyjson_mut_ptr_getx( \
2430             root, _ptr->uni.str, _ptr##_len, NULL, &err->ptr)
2431             #define ptr_add(_ptr, _val) yyjson_mut_ptr_addx( \
2432             root, _ptr->uni.str, _ptr##_len, _val, doc, false, NULL, &err->ptr)
2433             #define ptr_remove(_ptr) yyjson_mut_ptr_removex( \
2434             root, _ptr->uni.str, _ptr##_len, NULL, &err->ptr)
2435             #define ptr_replace(_ptr, _val)yyjson_mut_ptr_replacex( \
2436             root, _ptr->uni.str, _ptr##_len, _val, NULL, &err->ptr)
2437            
2438 0           yyjson_mut_val *yyjson_patch(yyjson_mut_doc *doc,
2439             yyjson_val *orig,
2440             yyjson_val *patch,
2441             yyjson_patch_err *err) {
2442              
2443             yyjson_mut_val *root;
2444             yyjson_val *obj;
2445             yyjson_arr_iter iter;
2446             yyjson_patch_err err_tmp;
2447 0 0         if (!err) err = &err_tmp;
2448 0           memset(err, 0, sizeof(*err));
2449 0           memset(&iter, 0, sizeof(iter));
2450            
2451 0 0         if (unlikely(!doc || !orig || !patch)) {
    0          
    0          
    0          
2452 0 0         return_err(INVALID_PARAMETER, "input parameter is NULL");
    0          
2453             }
2454 0 0         if (unlikely(!yyjson_is_arr(patch))) {
2455 0 0         return_err(INVALID_PARAMETER, "input patch is not array");
    0          
2456             }
2457 0           root = yyjson_val_mut_copy(doc, orig);
2458 0 0         if (unlikely(!root)) return_err_copy();
    0          
    0          
2459            
2460             /* iterate through the patch array */
2461             yyjson_arr_iter_init(patch, &iter);
2462 0 0         while ((obj = yyjson_arr_iter_next(&iter))) {
2463             patch_op op_enum;
2464 0           yyjson_val *op, *path, *from = NULL, *value;
2465 0           yyjson_mut_val *val = NULL, *test;
2466 0           usize path_len, from_len = 0;
2467 0 0         if (unlikely(!unsafe_yyjson_is_obj(obj))) {
2468 0 0         return_err(INVALID_OPERATION, "JSON patch operation is not object");
    0          
2469             }
2470            
2471             /* get required member: op */
2472 0           op = yyjson_obj_get(obj, "op");
2473 0 0         if (unlikely(!op)) return_err_key("`op`");
    0          
    0          
2474 0 0         if (unlikely(!yyjson_is_str(op))) return_err_val("`op`");
    0          
    0          
2475 0           op_enum = patch_op_get(op);
2476            
2477             /* get required member: path */
2478 0           path = yyjson_obj_get(obj, "path");
2479 0 0         if (unlikely(!path)) return_err_key("`path`");
    0          
    0          
2480 0 0         if (unlikely(!yyjson_is_str(path))) return_err_val("`path`");
    0          
    0          
2481 0           path_len = unsafe_yyjson_get_len(path);
2482            
2483             /* get required member: value, from */
2484 0           switch ((int)op_enum) {
2485 0 0         case PATCH_OP_ADD: case PATCH_OP_REPLACE: case PATCH_OP_TEST:
2486 0           value = yyjson_obj_get(obj, "value");
2487 0 0         if (unlikely(!value)) return_err_key("`value`");
    0          
    0          
2488 0           val = yyjson_val_mut_copy(doc, value);
2489 0 0         if (unlikely(!val)) return_err_copy();
    0          
    0          
2490 0           break;
2491 0 0         case PATCH_OP_MOVE: case PATCH_OP_COPY:
2492 0           from = yyjson_obj_get(obj, "from");
2493 0 0         if (unlikely(!from)) return_err_key("`from`");
    0          
    0          
2494 0 0         if (unlikely(!yyjson_is_str(from))) return_err_val("`from`");
    0          
    0          
2495 0           from_len = unsafe_yyjson_get_len(from);
2496 0           break;
2497 0           default:
2498 0           break;
2499             }
2500            
2501             /* perform an operation */
2502 0           switch ((int)op_enum) {
2503 0           case PATCH_OP_ADD: /* add(path, val) */
2504 0 0         if (unlikely(path_len == 0)) { root = val; break; }
2505 0 0         if (unlikely(!ptr_add(path, val))) {
    0          
2506 0 0         return_err(POINTER, "failed to add `path`");
    0          
2507             }
2508 0           break;
2509 0           case PATCH_OP_REMOVE: /* remove(path) */
2510 0 0         if (unlikely(!ptr_remove(path))) {
    0          
2511 0 0         return_err(POINTER, "failed to remove `path`");
    0          
2512             }
2513 0           break;
2514 0           case PATCH_OP_REPLACE: /* replace(path, val) */
2515 0 0         if (unlikely(path_len == 0)) { root = val; break; }
2516 0 0         if (unlikely(!ptr_replace(path, val))) {
    0          
2517 0 0         return_err(POINTER, "failed to replace `path`");
    0          
2518             }
2519 0           break;
2520 0           case PATCH_OP_MOVE: /* val = remove(from), add(path, val) */
2521 0 0         if (unlikely(from_len == 0 && path_len == 0)) break;
    0          
2522 0 0         val = ptr_remove(from);
2523 0 0         if (unlikely(!val)) {
2524 0 0         return_err(POINTER, "failed to remove `from`");
    0          
2525             }
2526 0 0         if (unlikely(path_len == 0)) { root = val; break; }
2527 0 0         if (unlikely(!ptr_add(path, val))) {
    0          
2528 0 0         return_err(POINTER, "failed to add `path`");
    0          
2529             }
2530 0           break;
2531 0           case PATCH_OP_COPY: /* val = get(from).copy, add(path, val) */
2532 0 0         val = ptr_get(from);
2533 0 0         if (unlikely(!val)) {
2534 0 0         return_err(POINTER, "failed to get `from`");
    0          
2535             }
2536 0 0         if (unlikely(path_len == 0)) { root = val; break; }
2537 0           val = yyjson_mut_val_mut_copy(doc, val);
2538 0 0         if (unlikely(!val)) return_err_copy();
    0          
    0          
2539 0 0         if (unlikely(!ptr_add(path, val))) {
    0          
2540 0 0         return_err(POINTER, "failed to add `path`");
    0          
2541             }
2542 0           break;
2543 0           case PATCH_OP_TEST: /* test = get(path), test.eq(val) */
2544 0 0         test = ptr_get(path);
2545 0 0         if (unlikely(!test)) {
2546 0 0         return_err(POINTER, "failed to get `path`");
    0          
2547             }
2548 0 0         if (unlikely(!yyjson_mut_equals(val, test))) {
2549 0 0         return_err(EQUAL, "failed to test equal");
    0          
2550             }
2551 0           break;
2552 0           default:
2553 0 0         return_err(INVALID_MEMBER, "unsupported `op`");
    0          
2554             }
2555             }
2556 0           return root;
2557             }
2558              
2559 0           yyjson_mut_val *yyjson_mut_patch(yyjson_mut_doc *doc,
2560             yyjson_mut_val *orig,
2561             yyjson_mut_val *patch,
2562             yyjson_patch_err *err) {
2563             yyjson_mut_val *root, *obj;
2564             yyjson_mut_arr_iter iter;
2565             yyjson_patch_err err_tmp;
2566 0 0         if (!err) err = &err_tmp;
2567 0           memset(err, 0, sizeof(*err));
2568 0           memset(&iter, 0, sizeof(iter));
2569            
2570 0 0         if (unlikely(!doc || !orig || !patch)) {
    0          
    0          
    0          
2571 0 0         return_err(INVALID_PARAMETER, "input parameter is NULL");
    0          
2572             }
2573 0 0         if (unlikely(!yyjson_mut_is_arr(patch))) {
2574 0 0         return_err(INVALID_PARAMETER, "input patch is not array");
    0          
2575             }
2576 0           root = yyjson_mut_val_mut_copy(doc, orig);
2577 0 0         if (unlikely(!root)) return_err_copy();
    0          
    0          
2578            
2579             /* iterate through the patch array */
2580             yyjson_mut_arr_iter_init(patch, &iter);
2581 0 0         while ((obj = yyjson_mut_arr_iter_next(&iter))) {
2582             patch_op op_enum;
2583 0           yyjson_mut_val *op, *path, *from = NULL, *value;
2584 0           yyjson_mut_val *val = NULL, *test;
2585 0           usize path_len, from_len = 0;
2586 0 0         if (!unsafe_yyjson_is_obj(obj)) {
2587 0 0         return_err(INVALID_OPERATION, "JSON patch operation is not object");
    0          
2588             }
2589            
2590             /* get required member: op */
2591 0           op = yyjson_mut_obj_get(obj, "op");
2592 0 0         if (unlikely(!op)) return_err_key("`op`");
    0          
    0          
2593 0 0         if (unlikely(!yyjson_mut_is_str(op))) return_err_val("`op`");
    0          
    0          
2594 0           op_enum = patch_op_get((yyjson_val *)(void *)op);
2595            
2596             /* get required member: path */
2597 0           path = yyjson_mut_obj_get(obj, "path");
2598 0 0         if (unlikely(!path)) return_err_key("`path`");
    0          
    0          
2599 0 0         if (unlikely(!yyjson_mut_is_str(path))) return_err_val("`path`");
    0          
    0          
2600 0           path_len = unsafe_yyjson_get_len(path);
2601            
2602             /* get required member: value, from */
2603 0           switch ((int)op_enum) {
2604 0 0         case PATCH_OP_ADD: case PATCH_OP_REPLACE: case PATCH_OP_TEST:
2605 0           value = yyjson_mut_obj_get(obj, "value");
2606 0 0         if (unlikely(!value)) return_err_key("`value`");
    0          
    0          
2607 0           val = yyjson_mut_val_mut_copy(doc, value);
2608 0 0         if (unlikely(!val)) return_err_copy();
    0          
    0          
2609 0           break;
2610 0 0         case PATCH_OP_MOVE: case PATCH_OP_COPY:
2611 0           from = yyjson_mut_obj_get(obj, "from");
2612 0 0         if (unlikely(!from)) return_err_key("`from`");
    0          
    0          
2613 0 0         if (unlikely(!yyjson_mut_is_str(from))) {
2614 0 0         return_err_val("`from`");
    0          
2615             }
2616 0           from_len = unsafe_yyjson_get_len(from);
2617 0           break;
2618 0           default:
2619 0           break;
2620             }
2621            
2622             /* perform an operation */
2623 0           switch ((int)op_enum) {
2624 0           case PATCH_OP_ADD: /* add(path, val) */
2625 0 0         if (unlikely(path_len == 0)) { root = val; break; }
2626 0 0         if (unlikely(!ptr_add(path, val))) {
    0          
2627 0 0         return_err(POINTER, "failed to add `path`");
    0          
2628             }
2629 0           break;
2630 0           case PATCH_OP_REMOVE: /* remove(path) */
2631 0 0         if (unlikely(!ptr_remove(path))) {
    0          
2632 0 0         return_err(POINTER, "failed to remove `path`");
    0          
2633             }
2634 0           break;
2635 0           case PATCH_OP_REPLACE: /* replace(path, val) */
2636 0 0         if (unlikely(path_len == 0)) { root = val; break; }
2637 0 0         if (unlikely(!ptr_replace(path, val))) {
    0          
2638 0 0         return_err(POINTER, "failed to replace `path`");
    0          
2639             }
2640 0           break;
2641 0           case PATCH_OP_MOVE: /* val = remove(from), add(path, val) */
2642 0 0         if (unlikely(from_len == 0 && path_len == 0)) break;
    0          
2643 0 0         val = ptr_remove(from);
2644 0 0         if (unlikely(!val)) {
2645 0 0         return_err(POINTER, "failed to remove `from`");
    0          
2646             }
2647 0 0         if (unlikely(path_len == 0)) { root = val; break; }
2648 0 0         if (unlikely(!ptr_add(path, val))) {
    0          
2649 0 0         return_err(POINTER, "failed to add `path`");
    0          
2650             }
2651 0           break;
2652 0           case PATCH_OP_COPY: /* val = get(from).copy, add(path, val) */
2653 0 0         val = ptr_get(from);
2654 0 0         if (unlikely(!val)) {
2655 0 0         return_err(POINTER, "failed to get `from`");
    0          
2656             }
2657 0 0         if (unlikely(path_len == 0)) { root = val; break; }
2658 0           val = yyjson_mut_val_mut_copy(doc, val);
2659 0 0         if (unlikely(!val)) return_err_copy();
    0          
    0          
2660 0 0         if (unlikely(!ptr_add(path, val))) {
    0          
2661 0 0         return_err(POINTER, "failed to add `path`");
    0          
2662             }
2663 0           break;
2664 0           case PATCH_OP_TEST: /* test = get(path), test.eq(val) */
2665 0 0         test = ptr_get(path);
2666 0 0         if (unlikely(!test)) {
2667 0 0         return_err(POINTER, "failed to get `path`");
    0          
2668             }
2669 0 0         if (unlikely(!yyjson_mut_equals(val, test))) {
2670 0 0         return_err(EQUAL, "failed to test equal");
    0          
2671             }
2672 0           break;
2673 0           default:
2674 0 0         return_err(INVALID_MEMBER, "unsupported `op`");
    0          
2675             }
2676             }
2677 0           return root;
2678             }
2679              
2680             /* macros for yyjson_patch */
2681             #undef return_err
2682             #undef return_err_copy
2683             #undef return_err_key
2684             #undef return_err_val
2685             #undef ptr_get
2686             #undef ptr_add
2687             #undef ptr_remove
2688             #undef ptr_replace
2689              
2690              
2691              
2692             /*==============================================================================
2693             * JSON Merge-Patch API (RFC 7386)
2694             *============================================================================*/
2695              
2696 0 0         yyjson_mut_val *yyjson_merge_patch(yyjson_mut_doc *doc,
2697             yyjson_val *orig,
2698             yyjson_val *patch) {
2699             usize idx, max;
2700             yyjson_val *key, *orig_val, *patch_val, local_orig;
2701             yyjson_mut_val *builder, *mut_key, *mut_val, *merged_val;
2702            
2703 0 0         if (unlikely(!yyjson_is_obj(patch))) {
2704 0           return yyjson_val_mut_copy(doc, patch);
2705             }
2706            
2707 0           builder = yyjson_mut_obj(doc);
2708 0 0         if (unlikely(!builder)) return NULL;
2709            
2710 0 0         memset(&local_orig, 0, sizeof(local_orig));
2711 0 0         if (!yyjson_is_obj(orig)) {
2712 0           orig = &local_orig;
2713 0           orig->tag = builder->tag;
2714 0           orig->uni = builder->uni;
2715             }
2716            
2717             /* If orig is contributing, copy any items not modified by the patch */
2718 0 0         if (orig != &local_orig) {
2719 0 0         yyjson_obj_foreach(orig, idx, max, key, orig_val) {
    0          
    0          
2720 0 0         patch_val = yyjson_obj_getn(patch,
2721             unsafe_yyjson_get_str(key),
2722             unsafe_yyjson_get_len(key));
2723 0 0         if (!patch_val) {
2724 0           mut_key = yyjson_val_mut_copy(doc, key);
2725 0           mut_val = yyjson_val_mut_copy(doc, orig_val);
2726 0 0         if (!yyjson_mut_obj_add(builder, mut_key, mut_val)) return NULL;
2727             }
2728             }
2729             }
2730              
2731             /* Merge items modified by the patch. */
2732 0 0         yyjson_obj_foreach(patch, idx, max, key, patch_val) {
    0          
    0          
2733             /* null indicates the field is removed. */
2734 0 0         if (unsafe_yyjson_is_null(patch_val)) {
2735 0           continue;
2736             }
2737 0           mut_key = yyjson_val_mut_copy(doc, key);
2738 0 0         orig_val = yyjson_obj_getn(orig,
2739             unsafe_yyjson_get_str(key),
2740             unsafe_yyjson_get_len(key));
2741 0           merged_val = yyjson_merge_patch(doc, orig_val, patch_val);
2742 0 0         if (!yyjson_mut_obj_add(builder, mut_key, merged_val)) return NULL;
2743             }
2744            
2745 0           return builder;
2746             }
2747              
2748 0 0         yyjson_mut_val *yyjson_mut_merge_patch(yyjson_mut_doc *doc,
2749             yyjson_mut_val *orig,
2750             yyjson_mut_val *patch) {
2751             usize idx, max;
2752             yyjson_mut_val *key, *orig_val, *patch_val, local_orig;
2753             yyjson_mut_val *builder, *mut_key, *mut_val, *merged_val;
2754            
2755 0 0         if (unlikely(!yyjson_mut_is_obj(patch))) {
2756 0           return yyjson_mut_val_mut_copy(doc, patch);
2757             }
2758            
2759 0           builder = yyjson_mut_obj(doc);
2760 0 0         if (unlikely(!builder)) return NULL;
2761            
2762 0 0         memset(&local_orig, 0, sizeof(local_orig));
2763 0 0         if (!yyjson_mut_is_obj(orig)) {
2764 0           orig = &local_orig;
2765 0           orig->tag = builder->tag;
2766 0           orig->uni = builder->uni;
2767             }
2768            
2769             /* If orig is contributing, copy any items not modified by the patch */
2770 0 0         if (orig != &local_orig) {
2771 0 0         yyjson_mut_obj_foreach(orig, idx, max, key, orig_val) {
    0          
    0          
    0          
2772 0 0         patch_val = yyjson_mut_obj_getn(patch,
2773             unsafe_yyjson_get_str(key),
2774             unsafe_yyjson_get_len(key));
2775 0 0         if (!patch_val) {
2776 0           mut_key = yyjson_mut_val_mut_copy(doc, key);
2777 0           mut_val = yyjson_mut_val_mut_copy(doc, orig_val);
2778 0 0         if (!yyjson_mut_obj_add(builder, mut_key, mut_val)) return NULL;
2779             }
2780             }
2781             }
2782              
2783             /* Merge items modified by the patch. */
2784 0 0         yyjson_mut_obj_foreach(patch, idx, max, key, patch_val) {
    0          
    0          
    0          
2785             /* null indicates the field is removed. */
2786 0 0         if (unsafe_yyjson_is_null(patch_val)) {
2787 0           continue;
2788             }
2789 0           mut_key = yyjson_mut_val_mut_copy(doc, key);
2790 0 0         orig_val = yyjson_mut_obj_getn(orig,
2791             unsafe_yyjson_get_str(key),
2792             unsafe_yyjson_get_len(key));
2793 0           merged_val = yyjson_mut_merge_patch(doc, orig_val, patch_val);
2794 0 0         if (!yyjson_mut_obj_add(builder, mut_key, merged_val)) return NULL;
2795             }
2796            
2797 0           return builder;
2798             }
2799              
2800             #endif /* YYJSON_DISABLE_UTILS */
2801              
2802              
2803              
2804             /*==============================================================================
2805             * Power10 Lookup Table
2806             * These data are used by the floating-point number reader and writer.
2807             *============================================================================*/
2808              
2809             #if (!YYJSON_DISABLE_READER || !YYJSON_DISABLE_WRITER) && \
2810             (!YYJSON_DISABLE_FAST_FP_CONV)
2811              
2812             /** Minimum decimal exponent in pow10_sig_table. */
2813             #define POW10_SIG_TABLE_MIN_EXP -343
2814              
2815             /** Maximum decimal exponent in pow10_sig_table. */
2816             #define POW10_SIG_TABLE_MAX_EXP 324
2817              
2818             /** Minimum exact decimal exponent in pow10_sig_table */
2819             #define POW10_SIG_TABLE_MIN_EXACT_EXP 0
2820              
2821             /** Maximum exact decimal exponent in pow10_sig_table */
2822             #define POW10_SIG_TABLE_MAX_EXACT_EXP 55
2823              
2824             /** Normalized significant 128 bits of pow10, no rounded up (size: 10.4KB).
2825             This lookup table is used by both the double number reader and writer.
2826             (generate with misc/make_tables.c) */
2827             static const u64 pow10_sig_table[] = {
2828             U64(0xBF29DCAB, 0xA82FDEAE), U64(0x7432EE87, 0x3880FC33), /* ~= 10^-343 */
2829             U64(0xEEF453D6, 0x923BD65A), U64(0x113FAA29, 0x06A13B3F), /* ~= 10^-342 */
2830             U64(0x9558B466, 0x1B6565F8), U64(0x4AC7CA59, 0xA424C507), /* ~= 10^-341 */
2831             U64(0xBAAEE17F, 0xA23EBF76), U64(0x5D79BCF0, 0x0D2DF649), /* ~= 10^-340 */
2832             U64(0xE95A99DF, 0x8ACE6F53), U64(0xF4D82C2C, 0x107973DC), /* ~= 10^-339 */
2833             U64(0x91D8A02B, 0xB6C10594), U64(0x79071B9B, 0x8A4BE869), /* ~= 10^-338 */
2834             U64(0xB64EC836, 0xA47146F9), U64(0x9748E282, 0x6CDEE284), /* ~= 10^-337 */
2835             U64(0xE3E27A44, 0x4D8D98B7), U64(0xFD1B1B23, 0x08169B25), /* ~= 10^-336 */
2836             U64(0x8E6D8C6A, 0xB0787F72), U64(0xFE30F0F5, 0xE50E20F7), /* ~= 10^-335 */
2837             U64(0xB208EF85, 0x5C969F4F), U64(0xBDBD2D33, 0x5E51A935), /* ~= 10^-334 */
2838             U64(0xDE8B2B66, 0xB3BC4723), U64(0xAD2C7880, 0x35E61382), /* ~= 10^-333 */
2839             U64(0x8B16FB20, 0x3055AC76), U64(0x4C3BCB50, 0x21AFCC31), /* ~= 10^-332 */
2840             U64(0xADDCB9E8, 0x3C6B1793), U64(0xDF4ABE24, 0x2A1BBF3D), /* ~= 10^-331 */
2841             U64(0xD953E862, 0x4B85DD78), U64(0xD71D6DAD, 0x34A2AF0D), /* ~= 10^-330 */
2842             U64(0x87D4713D, 0x6F33AA6B), U64(0x8672648C, 0x40E5AD68), /* ~= 10^-329 */
2843             U64(0xA9C98D8C, 0xCB009506), U64(0x680EFDAF, 0x511F18C2), /* ~= 10^-328 */
2844             U64(0xD43BF0EF, 0xFDC0BA48), U64(0x0212BD1B, 0x2566DEF2), /* ~= 10^-327 */
2845             U64(0x84A57695, 0xFE98746D), U64(0x014BB630, 0xF7604B57), /* ~= 10^-326 */
2846             U64(0xA5CED43B, 0x7E3E9188), U64(0x419EA3BD, 0x35385E2D), /* ~= 10^-325 */
2847             U64(0xCF42894A, 0x5DCE35EA), U64(0x52064CAC, 0x828675B9), /* ~= 10^-324 */
2848             U64(0x818995CE, 0x7AA0E1B2), U64(0x7343EFEB, 0xD1940993), /* ~= 10^-323 */
2849             U64(0xA1EBFB42, 0x19491A1F), U64(0x1014EBE6, 0xC5F90BF8), /* ~= 10^-322 */
2850             U64(0xCA66FA12, 0x9F9B60A6), U64(0xD41A26E0, 0x77774EF6), /* ~= 10^-321 */
2851             U64(0xFD00B897, 0x478238D0), U64(0x8920B098, 0x955522B4), /* ~= 10^-320 */
2852             U64(0x9E20735E, 0x8CB16382), U64(0x55B46E5F, 0x5D5535B0), /* ~= 10^-319 */
2853             U64(0xC5A89036, 0x2FDDBC62), U64(0xEB2189F7, 0x34AA831D), /* ~= 10^-318 */
2854             U64(0xF712B443, 0xBBD52B7B), U64(0xA5E9EC75, 0x01D523E4), /* ~= 10^-317 */
2855             U64(0x9A6BB0AA, 0x55653B2D), U64(0x47B233C9, 0x2125366E), /* ~= 10^-316 */
2856             U64(0xC1069CD4, 0xEABE89F8), U64(0x999EC0BB, 0x696E840A), /* ~= 10^-315 */
2857             U64(0xF148440A, 0x256E2C76), U64(0xC00670EA, 0x43CA250D), /* ~= 10^-314 */
2858             U64(0x96CD2A86, 0x5764DBCA), U64(0x38040692, 0x6A5E5728), /* ~= 10^-313 */
2859             U64(0xBC807527, 0xED3E12BC), U64(0xC6050837, 0x04F5ECF2), /* ~= 10^-312 */
2860             U64(0xEBA09271, 0xE88D976B), U64(0xF7864A44, 0xC633682E), /* ~= 10^-311 */
2861             U64(0x93445B87, 0x31587EA3), U64(0x7AB3EE6A, 0xFBE0211D), /* ~= 10^-310 */
2862             U64(0xB8157268, 0xFDAE9E4C), U64(0x5960EA05, 0xBAD82964), /* ~= 10^-309 */
2863             U64(0xE61ACF03, 0x3D1A45DF), U64(0x6FB92487, 0x298E33BD), /* ~= 10^-308 */
2864             U64(0x8FD0C162, 0x06306BAB), U64(0xA5D3B6D4, 0x79F8E056), /* ~= 10^-307 */
2865             U64(0xB3C4F1BA, 0x87BC8696), U64(0x8F48A489, 0x9877186C), /* ~= 10^-306 */
2866             U64(0xE0B62E29, 0x29ABA83C), U64(0x331ACDAB, 0xFE94DE87), /* ~= 10^-305 */
2867             U64(0x8C71DCD9, 0xBA0B4925), U64(0x9FF0C08B, 0x7F1D0B14), /* ~= 10^-304 */
2868             U64(0xAF8E5410, 0x288E1B6F), U64(0x07ECF0AE, 0x5EE44DD9), /* ~= 10^-303 */
2869             U64(0xDB71E914, 0x32B1A24A), U64(0xC9E82CD9, 0xF69D6150), /* ~= 10^-302 */
2870             U64(0x892731AC, 0x9FAF056E), U64(0xBE311C08, 0x3A225CD2), /* ~= 10^-301 */
2871             U64(0xAB70FE17, 0xC79AC6CA), U64(0x6DBD630A, 0x48AAF406), /* ~= 10^-300 */
2872             U64(0xD64D3D9D, 0xB981787D), U64(0x092CBBCC, 0xDAD5B108), /* ~= 10^-299 */
2873             U64(0x85F04682, 0x93F0EB4E), U64(0x25BBF560, 0x08C58EA5), /* ~= 10^-298 */
2874             U64(0xA76C5823, 0x38ED2621), U64(0xAF2AF2B8, 0x0AF6F24E), /* ~= 10^-297 */
2875             U64(0xD1476E2C, 0x07286FAA), U64(0x1AF5AF66, 0x0DB4AEE1), /* ~= 10^-296 */
2876             U64(0x82CCA4DB, 0x847945CA), U64(0x50D98D9F, 0xC890ED4D), /* ~= 10^-295 */
2877             U64(0xA37FCE12, 0x6597973C), U64(0xE50FF107, 0xBAB528A0), /* ~= 10^-294 */
2878             U64(0xCC5FC196, 0xFEFD7D0C), U64(0x1E53ED49, 0xA96272C8), /* ~= 10^-293 */
2879             U64(0xFF77B1FC, 0xBEBCDC4F), U64(0x25E8E89C, 0x13BB0F7A), /* ~= 10^-292 */
2880             U64(0x9FAACF3D, 0xF73609B1), U64(0x77B19161, 0x8C54E9AC), /* ~= 10^-291 */
2881             U64(0xC795830D, 0x75038C1D), U64(0xD59DF5B9, 0xEF6A2417), /* ~= 10^-290 */
2882             U64(0xF97AE3D0, 0xD2446F25), U64(0x4B057328, 0x6B44AD1D), /* ~= 10^-289 */
2883             U64(0x9BECCE62, 0x836AC577), U64(0x4EE367F9, 0x430AEC32), /* ~= 10^-288 */
2884             U64(0xC2E801FB, 0x244576D5), U64(0x229C41F7, 0x93CDA73F), /* ~= 10^-287 */
2885             U64(0xF3A20279, 0xED56D48A), U64(0x6B435275, 0x78C1110F), /* ~= 10^-286 */
2886             U64(0x9845418C, 0x345644D6), U64(0x830A1389, 0x6B78AAA9), /* ~= 10^-285 */
2887             U64(0xBE5691EF, 0x416BD60C), U64(0x23CC986B, 0xC656D553), /* ~= 10^-284 */
2888             U64(0xEDEC366B, 0x11C6CB8F), U64(0x2CBFBE86, 0xB7EC8AA8), /* ~= 10^-283 */
2889             U64(0x94B3A202, 0xEB1C3F39), U64(0x7BF7D714, 0x32F3D6A9), /* ~= 10^-282 */
2890             U64(0xB9E08A83, 0xA5E34F07), U64(0xDAF5CCD9, 0x3FB0CC53), /* ~= 10^-281 */
2891             U64(0xE858AD24, 0x8F5C22C9), U64(0xD1B3400F, 0x8F9CFF68), /* ~= 10^-280 */
2892             U64(0x91376C36, 0xD99995BE), U64(0x23100809, 0xB9C21FA1), /* ~= 10^-279 */
2893             U64(0xB5854744, 0x8FFFFB2D), U64(0xABD40A0C, 0x2832A78A), /* ~= 10^-278 */
2894             U64(0xE2E69915, 0xB3FFF9F9), U64(0x16C90C8F, 0x323F516C), /* ~= 10^-277 */
2895             U64(0x8DD01FAD, 0x907FFC3B), U64(0xAE3DA7D9, 0x7F6792E3), /* ~= 10^-276 */
2896             U64(0xB1442798, 0xF49FFB4A), U64(0x99CD11CF, 0xDF41779C), /* ~= 10^-275 */
2897             U64(0xDD95317F, 0x31C7FA1D), U64(0x40405643, 0xD711D583), /* ~= 10^-274 */
2898             U64(0x8A7D3EEF, 0x7F1CFC52), U64(0x482835EA, 0x666B2572), /* ~= 10^-273 */
2899             U64(0xAD1C8EAB, 0x5EE43B66), U64(0xDA324365, 0x0005EECF), /* ~= 10^-272 */
2900             U64(0xD863B256, 0x369D4A40), U64(0x90BED43E, 0x40076A82), /* ~= 10^-271 */
2901             U64(0x873E4F75, 0xE2224E68), U64(0x5A7744A6, 0xE804A291), /* ~= 10^-270 */
2902             U64(0xA90DE353, 0x5AAAE202), U64(0x711515D0, 0xA205CB36), /* ~= 10^-269 */
2903             U64(0xD3515C28, 0x31559A83), U64(0x0D5A5B44, 0xCA873E03), /* ~= 10^-268 */
2904             U64(0x8412D999, 0x1ED58091), U64(0xE858790A, 0xFE9486C2), /* ~= 10^-267 */
2905             U64(0xA5178FFF, 0x668AE0B6), U64(0x626E974D, 0xBE39A872), /* ~= 10^-266 */
2906             U64(0xCE5D73FF, 0x402D98E3), U64(0xFB0A3D21, 0x2DC8128F), /* ~= 10^-265 */
2907             U64(0x80FA687F, 0x881C7F8E), U64(0x7CE66634, 0xBC9D0B99), /* ~= 10^-264 */
2908             U64(0xA139029F, 0x6A239F72), U64(0x1C1FFFC1, 0xEBC44E80), /* ~= 10^-263 */
2909             U64(0xC9874347, 0x44AC874E), U64(0xA327FFB2, 0x66B56220), /* ~= 10^-262 */
2910             U64(0xFBE91419, 0x15D7A922), U64(0x4BF1FF9F, 0x0062BAA8), /* ~= 10^-261 */
2911             U64(0x9D71AC8F, 0xADA6C9B5), U64(0x6F773FC3, 0x603DB4A9), /* ~= 10^-260 */
2912             U64(0xC4CE17B3, 0x99107C22), U64(0xCB550FB4, 0x384D21D3), /* ~= 10^-259 */
2913             U64(0xF6019DA0, 0x7F549B2B), U64(0x7E2A53A1, 0x46606A48), /* ~= 10^-258 */
2914             U64(0x99C10284, 0x4F94E0FB), U64(0x2EDA7444, 0xCBFC426D), /* ~= 10^-257 */
2915             U64(0xC0314325, 0x637A1939), U64(0xFA911155, 0xFEFB5308), /* ~= 10^-256 */
2916             U64(0xF03D93EE, 0xBC589F88), U64(0x793555AB, 0x7EBA27CA), /* ~= 10^-255 */
2917             U64(0x96267C75, 0x35B763B5), U64(0x4BC1558B, 0x2F3458DE), /* ~= 10^-254 */
2918             U64(0xBBB01B92, 0x83253CA2), U64(0x9EB1AAED, 0xFB016F16), /* ~= 10^-253 */
2919             U64(0xEA9C2277, 0x23EE8BCB), U64(0x465E15A9, 0x79C1CADC), /* ~= 10^-252 */
2920             U64(0x92A1958A, 0x7675175F), U64(0x0BFACD89, 0xEC191EC9), /* ~= 10^-251 */
2921             U64(0xB749FAED, 0x14125D36), U64(0xCEF980EC, 0x671F667B), /* ~= 10^-250 */
2922             U64(0xE51C79A8, 0x5916F484), U64(0x82B7E127, 0x80E7401A), /* ~= 10^-249 */
2923             U64(0x8F31CC09, 0x37AE58D2), U64(0xD1B2ECB8, 0xB0908810), /* ~= 10^-248 */
2924             U64(0xB2FE3F0B, 0x8599EF07), U64(0x861FA7E6, 0xDCB4AA15), /* ~= 10^-247 */
2925             U64(0xDFBDCECE, 0x67006AC9), U64(0x67A791E0, 0x93E1D49A), /* ~= 10^-246 */
2926             U64(0x8BD6A141, 0x006042BD), U64(0xE0C8BB2C, 0x5C6D24E0), /* ~= 10^-245 */
2927             U64(0xAECC4991, 0x4078536D), U64(0x58FAE9F7, 0x73886E18), /* ~= 10^-244 */
2928             U64(0xDA7F5BF5, 0x90966848), U64(0xAF39A475, 0x506A899E), /* ~= 10^-243 */
2929             U64(0x888F9979, 0x7A5E012D), U64(0x6D8406C9, 0x52429603), /* ~= 10^-242 */
2930             U64(0xAAB37FD7, 0xD8F58178), U64(0xC8E5087B, 0xA6D33B83), /* ~= 10^-241 */
2931             U64(0xD5605FCD, 0xCF32E1D6), U64(0xFB1E4A9A, 0x90880A64), /* ~= 10^-240 */
2932             U64(0x855C3BE0, 0xA17FCD26), U64(0x5CF2EEA0, 0x9A55067F), /* ~= 10^-239 */
2933             U64(0xA6B34AD8, 0xC9DFC06F), U64(0xF42FAA48, 0xC0EA481E), /* ~= 10^-238 */
2934             U64(0xD0601D8E, 0xFC57B08B), U64(0xF13B94DA, 0xF124DA26), /* ~= 10^-237 */
2935             U64(0x823C1279, 0x5DB6CE57), U64(0x76C53D08, 0xD6B70858), /* ~= 10^-236 */
2936             U64(0xA2CB1717, 0xB52481ED), U64(0x54768C4B, 0x0C64CA6E), /* ~= 10^-235 */
2937             U64(0xCB7DDCDD, 0xA26DA268), U64(0xA9942F5D, 0xCF7DFD09), /* ~= 10^-234 */
2938             U64(0xFE5D5415, 0x0B090B02), U64(0xD3F93B35, 0x435D7C4C), /* ~= 10^-233 */
2939             U64(0x9EFA548D, 0x26E5A6E1), U64(0xC47BC501, 0x4A1A6DAF), /* ~= 10^-232 */
2940             U64(0xC6B8E9B0, 0x709F109A), U64(0x359AB641, 0x9CA1091B), /* ~= 10^-231 */
2941             U64(0xF867241C, 0x8CC6D4C0), U64(0xC30163D2, 0x03C94B62), /* ~= 10^-230 */
2942             U64(0x9B407691, 0xD7FC44F8), U64(0x79E0DE63, 0x425DCF1D), /* ~= 10^-229 */
2943             U64(0xC2109436, 0x4DFB5636), U64(0x985915FC, 0x12F542E4), /* ~= 10^-228 */
2944             U64(0xF294B943, 0xE17A2BC4), U64(0x3E6F5B7B, 0x17B2939D), /* ~= 10^-227 */
2945             U64(0x979CF3CA, 0x6CEC5B5A), U64(0xA705992C, 0xEECF9C42), /* ~= 10^-226 */
2946             U64(0xBD8430BD, 0x08277231), U64(0x50C6FF78, 0x2A838353), /* ~= 10^-225 */
2947             U64(0xECE53CEC, 0x4A314EBD), U64(0xA4F8BF56, 0x35246428), /* ~= 10^-224 */
2948             U64(0x940F4613, 0xAE5ED136), U64(0x871B7795, 0xE136BE99), /* ~= 10^-223 */
2949             U64(0xB9131798, 0x99F68584), U64(0x28E2557B, 0x59846E3F), /* ~= 10^-222 */
2950             U64(0xE757DD7E, 0xC07426E5), U64(0x331AEADA, 0x2FE589CF), /* ~= 10^-221 */
2951             U64(0x9096EA6F, 0x3848984F), U64(0x3FF0D2C8, 0x5DEF7621), /* ~= 10^-220 */
2952             U64(0xB4BCA50B, 0x065ABE63), U64(0x0FED077A, 0x756B53A9), /* ~= 10^-219 */
2953             U64(0xE1EBCE4D, 0xC7F16DFB), U64(0xD3E84959, 0x12C62894), /* ~= 10^-218 */
2954             U64(0x8D3360F0, 0x9CF6E4BD), U64(0x64712DD7, 0xABBBD95C), /* ~= 10^-217 */
2955             U64(0xB080392C, 0xC4349DEC), U64(0xBD8D794D, 0x96AACFB3), /* ~= 10^-216 */
2956             U64(0xDCA04777, 0xF541C567), U64(0xECF0D7A0, 0xFC5583A0), /* ~= 10^-215 */
2957             U64(0x89E42CAA, 0xF9491B60), U64(0xF41686C4, 0x9DB57244), /* ~= 10^-214 */
2958             U64(0xAC5D37D5, 0xB79B6239), U64(0x311C2875, 0xC522CED5), /* ~= 10^-213 */
2959             U64(0xD77485CB, 0x25823AC7), U64(0x7D633293, 0x366B828B), /* ~= 10^-212 */
2960             U64(0x86A8D39E, 0xF77164BC), U64(0xAE5DFF9C, 0x02033197), /* ~= 10^-211 */
2961             U64(0xA8530886, 0xB54DBDEB), U64(0xD9F57F83, 0x0283FDFC), /* ~= 10^-210 */
2962             U64(0xD267CAA8, 0x62A12D66), U64(0xD072DF63, 0xC324FD7B), /* ~= 10^-209 */
2963             U64(0x8380DEA9, 0x3DA4BC60), U64(0x4247CB9E, 0x59F71E6D), /* ~= 10^-208 */
2964             U64(0xA4611653, 0x8D0DEB78), U64(0x52D9BE85, 0xF074E608), /* ~= 10^-207 */
2965             U64(0xCD795BE8, 0x70516656), U64(0x67902E27, 0x6C921F8B), /* ~= 10^-206 */
2966             U64(0x806BD971, 0x4632DFF6), U64(0x00BA1CD8, 0xA3DB53B6), /* ~= 10^-205 */
2967             U64(0xA086CFCD, 0x97BF97F3), U64(0x80E8A40E, 0xCCD228A4), /* ~= 10^-204 */
2968             U64(0xC8A883C0, 0xFDAF7DF0), U64(0x6122CD12, 0x8006B2CD), /* ~= 10^-203 */
2969             U64(0xFAD2A4B1, 0x3D1B5D6C), U64(0x796B8057, 0x20085F81), /* ~= 10^-202 */
2970             U64(0x9CC3A6EE, 0xC6311A63), U64(0xCBE33036, 0x74053BB0), /* ~= 10^-201 */
2971             U64(0xC3F490AA, 0x77BD60FC), U64(0xBEDBFC44, 0x11068A9C), /* ~= 10^-200 */
2972             U64(0xF4F1B4D5, 0x15ACB93B), U64(0xEE92FB55, 0x15482D44), /* ~= 10^-199 */
2973             U64(0x99171105, 0x2D8BF3C5), U64(0x751BDD15, 0x2D4D1C4A), /* ~= 10^-198 */
2974             U64(0xBF5CD546, 0x78EEF0B6), U64(0xD262D45A, 0x78A0635D), /* ~= 10^-197 */
2975             U64(0xEF340A98, 0x172AACE4), U64(0x86FB8971, 0x16C87C34), /* ~= 10^-196 */
2976             U64(0x9580869F, 0x0E7AAC0E), U64(0xD45D35E6, 0xAE3D4DA0), /* ~= 10^-195 */
2977             U64(0xBAE0A846, 0xD2195712), U64(0x89748360, 0x59CCA109), /* ~= 10^-194 */
2978             U64(0xE998D258, 0x869FACD7), U64(0x2BD1A438, 0x703FC94B), /* ~= 10^-193 */
2979             U64(0x91FF8377, 0x5423CC06), U64(0x7B6306A3, 0x4627DDCF), /* ~= 10^-192 */
2980             U64(0xB67F6455, 0x292CBF08), U64(0x1A3BC84C, 0x17B1D542), /* ~= 10^-191 */
2981             U64(0xE41F3D6A, 0x7377EECA), U64(0x20CABA5F, 0x1D9E4A93), /* ~= 10^-190 */
2982             U64(0x8E938662, 0x882AF53E), U64(0x547EB47B, 0x7282EE9C), /* ~= 10^-189 */
2983             U64(0xB23867FB, 0x2A35B28D), U64(0xE99E619A, 0x4F23AA43), /* ~= 10^-188 */
2984             U64(0xDEC681F9, 0xF4C31F31), U64(0x6405FA00, 0xE2EC94D4), /* ~= 10^-187 */
2985             U64(0x8B3C113C, 0x38F9F37E), U64(0xDE83BC40, 0x8DD3DD04), /* ~= 10^-186 */
2986             U64(0xAE0B158B, 0x4738705E), U64(0x9624AB50, 0xB148D445), /* ~= 10^-185 */
2987             U64(0xD98DDAEE, 0x19068C76), U64(0x3BADD624, 0xDD9B0957), /* ~= 10^-184 */
2988             U64(0x87F8A8D4, 0xCFA417C9), U64(0xE54CA5D7, 0x0A80E5D6), /* ~= 10^-183 */
2989             U64(0xA9F6D30A, 0x038D1DBC), U64(0x5E9FCF4C, 0xCD211F4C), /* ~= 10^-182 */
2990             U64(0xD47487CC, 0x8470652B), U64(0x7647C320, 0x0069671F), /* ~= 10^-181 */
2991             U64(0x84C8D4DF, 0xD2C63F3B), U64(0x29ECD9F4, 0x0041E073), /* ~= 10^-180 */
2992             U64(0xA5FB0A17, 0xC777CF09), U64(0xF4681071, 0x00525890), /* ~= 10^-179 */
2993             U64(0xCF79CC9D, 0xB955C2CC), U64(0x7182148D, 0x4066EEB4), /* ~= 10^-178 */
2994             U64(0x81AC1FE2, 0x93D599BF), U64(0xC6F14CD8, 0x48405530), /* ~= 10^-177 */
2995             U64(0xA21727DB, 0x38CB002F), U64(0xB8ADA00E, 0x5A506A7C), /* ~= 10^-176 */
2996             U64(0xCA9CF1D2, 0x06FDC03B), U64(0xA6D90811, 0xF0E4851C), /* ~= 10^-175 */
2997             U64(0xFD442E46, 0x88BD304A), U64(0x908F4A16, 0x6D1DA663), /* ~= 10^-174 */
2998             U64(0x9E4A9CEC, 0x15763E2E), U64(0x9A598E4E, 0x043287FE), /* ~= 10^-173 */
2999             U64(0xC5DD4427, 0x1AD3CDBA), U64(0x40EFF1E1, 0x853F29FD), /* ~= 10^-172 */
3000             U64(0xF7549530, 0xE188C128), U64(0xD12BEE59, 0xE68EF47C), /* ~= 10^-171 */
3001             U64(0x9A94DD3E, 0x8CF578B9), U64(0x82BB74F8, 0x301958CE), /* ~= 10^-170 */
3002             U64(0xC13A148E, 0x3032D6E7), U64(0xE36A5236, 0x3C1FAF01), /* ~= 10^-169 */
3003             U64(0xF18899B1, 0xBC3F8CA1), U64(0xDC44E6C3, 0xCB279AC1), /* ~= 10^-168 */
3004             U64(0x96F5600F, 0x15A7B7E5), U64(0x29AB103A, 0x5EF8C0B9), /* ~= 10^-167 */
3005             U64(0xBCB2B812, 0xDB11A5DE), U64(0x7415D448, 0xF6B6F0E7), /* ~= 10^-166 */
3006             U64(0xEBDF6617, 0x91D60F56), U64(0x111B495B, 0x3464AD21), /* ~= 10^-165 */
3007             U64(0x936B9FCE, 0xBB25C995), U64(0xCAB10DD9, 0x00BEEC34), /* ~= 10^-164 */
3008             U64(0xB84687C2, 0x69EF3BFB), U64(0x3D5D514F, 0x40EEA742), /* ~= 10^-163 */
3009             U64(0xE65829B3, 0x046B0AFA), U64(0x0CB4A5A3, 0x112A5112), /* ~= 10^-162 */
3010             U64(0x8FF71A0F, 0xE2C2E6DC), U64(0x47F0E785, 0xEABA72AB), /* ~= 10^-161 */
3011             U64(0xB3F4E093, 0xDB73A093), U64(0x59ED2167, 0x65690F56), /* ~= 10^-160 */
3012             U64(0xE0F218B8, 0xD25088B8), U64(0x306869C1, 0x3EC3532C), /* ~= 10^-159 */
3013             U64(0x8C974F73, 0x83725573), U64(0x1E414218, 0xC73A13FB), /* ~= 10^-158 */
3014             U64(0xAFBD2350, 0x644EEACF), U64(0xE5D1929E, 0xF90898FA), /* ~= 10^-157 */
3015             U64(0xDBAC6C24, 0x7D62A583), U64(0xDF45F746, 0xB74ABF39), /* ~= 10^-156 */
3016             U64(0x894BC396, 0xCE5DA772), U64(0x6B8BBA8C, 0x328EB783), /* ~= 10^-155 */
3017             U64(0xAB9EB47C, 0x81F5114F), U64(0x066EA92F, 0x3F326564), /* ~= 10^-154 */
3018             U64(0xD686619B, 0xA27255A2), U64(0xC80A537B, 0x0EFEFEBD), /* ~= 10^-153 */
3019             U64(0x8613FD01, 0x45877585), U64(0xBD06742C, 0xE95F5F36), /* ~= 10^-152 */
3020             U64(0xA798FC41, 0x96E952E7), U64(0x2C481138, 0x23B73704), /* ~= 10^-151 */
3021             U64(0xD17F3B51, 0xFCA3A7A0), U64(0xF75A1586, 0x2CA504C5), /* ~= 10^-150 */
3022             U64(0x82EF8513, 0x3DE648C4), U64(0x9A984D73, 0xDBE722FB), /* ~= 10^-149 */
3023             U64(0xA3AB6658, 0x0D5FDAF5), U64(0xC13E60D0, 0xD2E0EBBA), /* ~= 10^-148 */
3024             U64(0xCC963FEE, 0x10B7D1B3), U64(0x318DF905, 0x079926A8), /* ~= 10^-147 */
3025             U64(0xFFBBCFE9, 0x94E5C61F), U64(0xFDF17746, 0x497F7052), /* ~= 10^-146 */
3026             U64(0x9FD561F1, 0xFD0F9BD3), U64(0xFEB6EA8B, 0xEDEFA633), /* ~= 10^-145 */
3027             U64(0xC7CABA6E, 0x7C5382C8), U64(0xFE64A52E, 0xE96B8FC0), /* ~= 10^-144 */
3028             U64(0xF9BD690A, 0x1B68637B), U64(0x3DFDCE7A, 0xA3C673B0), /* ~= 10^-143 */
3029             U64(0x9C1661A6, 0x51213E2D), U64(0x06BEA10C, 0xA65C084E), /* ~= 10^-142 */
3030             U64(0xC31BFA0F, 0xE5698DB8), U64(0x486E494F, 0xCFF30A62), /* ~= 10^-141 */
3031             U64(0xF3E2F893, 0xDEC3F126), U64(0x5A89DBA3, 0xC3EFCCFA), /* ~= 10^-140 */
3032             U64(0x986DDB5C, 0x6B3A76B7), U64(0xF8962946, 0x5A75E01C), /* ~= 10^-139 */
3033             U64(0xBE895233, 0x86091465), U64(0xF6BBB397, 0xF1135823), /* ~= 10^-138 */
3034             U64(0xEE2BA6C0, 0x678B597F), U64(0x746AA07D, 0xED582E2C), /* ~= 10^-137 */
3035             U64(0x94DB4838, 0x40B717EF), U64(0xA8C2A44E, 0xB4571CDC), /* ~= 10^-136 */
3036             U64(0xBA121A46, 0x50E4DDEB), U64(0x92F34D62, 0x616CE413), /* ~= 10^-135 */
3037             U64(0xE896A0D7, 0xE51E1566), U64(0x77B020BA, 0xF9C81D17), /* ~= 10^-134 */
3038             U64(0x915E2486, 0xEF32CD60), U64(0x0ACE1474, 0xDC1D122E), /* ~= 10^-133 */
3039             U64(0xB5B5ADA8, 0xAAFF80B8), U64(0x0D819992, 0x132456BA), /* ~= 10^-132 */
3040             U64(0xE3231912, 0xD5BF60E6), U64(0x10E1FFF6, 0x97ED6C69), /* ~= 10^-131 */
3041             U64(0x8DF5EFAB, 0xC5979C8F), U64(0xCA8D3FFA, 0x1EF463C1), /* ~= 10^-130 */
3042             U64(0xB1736B96, 0xB6FD83B3), U64(0xBD308FF8, 0xA6B17CB2), /* ~= 10^-129 */
3043             U64(0xDDD0467C, 0x64BCE4A0), U64(0xAC7CB3F6, 0xD05DDBDE), /* ~= 10^-128 */
3044             U64(0x8AA22C0D, 0xBEF60EE4), U64(0x6BCDF07A, 0x423AA96B), /* ~= 10^-127 */
3045             U64(0xAD4AB711, 0x2EB3929D), U64(0x86C16C98, 0xD2C953C6), /* ~= 10^-126 */
3046             U64(0xD89D64D5, 0x7A607744), U64(0xE871C7BF, 0x077BA8B7), /* ~= 10^-125 */
3047             U64(0x87625F05, 0x6C7C4A8B), U64(0x11471CD7, 0x64AD4972), /* ~= 10^-124 */
3048             U64(0xA93AF6C6, 0xC79B5D2D), U64(0xD598E40D, 0x3DD89BCF), /* ~= 10^-123 */
3049             U64(0xD389B478, 0x79823479), U64(0x4AFF1D10, 0x8D4EC2C3), /* ~= 10^-122 */
3050             U64(0x843610CB, 0x4BF160CB), U64(0xCEDF722A, 0x585139BA), /* ~= 10^-121 */
3051             U64(0xA54394FE, 0x1EEDB8FE), U64(0xC2974EB4, 0xEE658828), /* ~= 10^-120 */
3052             U64(0xCE947A3D, 0xA6A9273E), U64(0x733D2262, 0x29FEEA32), /* ~= 10^-119 */
3053             U64(0x811CCC66, 0x8829B887), U64(0x0806357D, 0x5A3F525F), /* ~= 10^-118 */
3054             U64(0xA163FF80, 0x2A3426A8), U64(0xCA07C2DC, 0xB0CF26F7), /* ~= 10^-117 */
3055             U64(0xC9BCFF60, 0x34C13052), U64(0xFC89B393, 0xDD02F0B5), /* ~= 10^-116 */
3056             U64(0xFC2C3F38, 0x41F17C67), U64(0xBBAC2078, 0xD443ACE2), /* ~= 10^-115 */
3057             U64(0x9D9BA783, 0x2936EDC0), U64(0xD54B944B, 0x84AA4C0D), /* ~= 10^-114 */
3058             U64(0xC5029163, 0xF384A931), U64(0x0A9E795E, 0x65D4DF11), /* ~= 10^-113 */
3059             U64(0xF64335BC, 0xF065D37D), U64(0x4D4617B5, 0xFF4A16D5), /* ~= 10^-112 */
3060             U64(0x99EA0196, 0x163FA42E), U64(0x504BCED1, 0xBF8E4E45), /* ~= 10^-111 */
3061             U64(0xC06481FB, 0x9BCF8D39), U64(0xE45EC286, 0x2F71E1D6), /* ~= 10^-110 */
3062             U64(0xF07DA27A, 0x82C37088), U64(0x5D767327, 0xBB4E5A4C), /* ~= 10^-109 */
3063             U64(0x964E858C, 0x91BA2655), U64(0x3A6A07F8, 0xD510F86F), /* ~= 10^-108 */
3064             U64(0xBBE226EF, 0xB628AFEA), U64(0x890489F7, 0x0A55368B), /* ~= 10^-107 */
3065             U64(0xEADAB0AB, 0xA3B2DBE5), U64(0x2B45AC74, 0xCCEA842E), /* ~= 10^-106 */
3066             U64(0x92C8AE6B, 0x464FC96F), U64(0x3B0B8BC9, 0x0012929D), /* ~= 10^-105 */
3067             U64(0xB77ADA06, 0x17E3BBCB), U64(0x09CE6EBB, 0x40173744), /* ~= 10^-104 */
3068             U64(0xE5599087, 0x9DDCAABD), U64(0xCC420A6A, 0x101D0515), /* ~= 10^-103 */
3069             U64(0x8F57FA54, 0xC2A9EAB6), U64(0x9FA94682, 0x4A12232D), /* ~= 10^-102 */
3070             U64(0xB32DF8E9, 0xF3546564), U64(0x47939822, 0xDC96ABF9), /* ~= 10^-101 */
3071             U64(0xDFF97724, 0x70297EBD), U64(0x59787E2B, 0x93BC56F7), /* ~= 10^-100 */
3072             U64(0x8BFBEA76, 0xC619EF36), U64(0x57EB4EDB, 0x3C55B65A), /* ~= 10^-99 */
3073             U64(0xAEFAE514, 0x77A06B03), U64(0xEDE62292, 0x0B6B23F1), /* ~= 10^-98 */
3074             U64(0xDAB99E59, 0x958885C4), U64(0xE95FAB36, 0x8E45ECED), /* ~= 10^-97 */
3075             U64(0x88B402F7, 0xFD75539B), U64(0x11DBCB02, 0x18EBB414), /* ~= 10^-96 */
3076             U64(0xAAE103B5, 0xFCD2A881), U64(0xD652BDC2, 0x9F26A119), /* ~= 10^-95 */
3077             U64(0xD59944A3, 0x7C0752A2), U64(0x4BE76D33, 0x46F0495F), /* ~= 10^-94 */
3078             U64(0x857FCAE6, 0x2D8493A5), U64(0x6F70A440, 0x0C562DDB), /* ~= 10^-93 */
3079             U64(0xA6DFBD9F, 0xB8E5B88E), U64(0xCB4CCD50, 0x0F6BB952), /* ~= 10^-92 */
3080             U64(0xD097AD07, 0xA71F26B2), U64(0x7E2000A4, 0x1346A7A7), /* ~= 10^-91 */
3081             U64(0x825ECC24, 0xC873782F), U64(0x8ED40066, 0x8C0C28C8), /* ~= 10^-90 */
3082             U64(0xA2F67F2D, 0xFA90563B), U64(0x72890080, 0x2F0F32FA), /* ~= 10^-89 */
3083             U64(0xCBB41EF9, 0x79346BCA), U64(0x4F2B40A0, 0x3AD2FFB9), /* ~= 10^-88 */
3084             U64(0xFEA126B7, 0xD78186BC), U64(0xE2F610C8, 0x4987BFA8), /* ~= 10^-87 */
3085             U64(0x9F24B832, 0xE6B0F436), U64(0x0DD9CA7D, 0x2DF4D7C9), /* ~= 10^-86 */
3086             U64(0xC6EDE63F, 0xA05D3143), U64(0x91503D1C, 0x79720DBB), /* ~= 10^-85 */
3087             U64(0xF8A95FCF, 0x88747D94), U64(0x75A44C63, 0x97CE912A), /* ~= 10^-84 */
3088             U64(0x9B69DBE1, 0xB548CE7C), U64(0xC986AFBE, 0x3EE11ABA), /* ~= 10^-83 */
3089             U64(0xC24452DA, 0x229B021B), U64(0xFBE85BAD, 0xCE996168), /* ~= 10^-82 */
3090             U64(0xF2D56790, 0xAB41C2A2), U64(0xFAE27299, 0x423FB9C3), /* ~= 10^-81 */
3091             U64(0x97C560BA, 0x6B0919A5), U64(0xDCCD879F, 0xC967D41A), /* ~= 10^-80 */
3092             U64(0xBDB6B8E9, 0x05CB600F), U64(0x5400E987, 0xBBC1C920), /* ~= 10^-79 */
3093             U64(0xED246723, 0x473E3813), U64(0x290123E9, 0xAAB23B68), /* ~= 10^-78 */
3094             U64(0x9436C076, 0x0C86E30B), U64(0xF9A0B672, 0x0AAF6521), /* ~= 10^-77 */
3095             U64(0xB9447093, 0x8FA89BCE), U64(0xF808E40E, 0x8D5B3E69), /* ~= 10^-76 */
3096             U64(0xE7958CB8, 0x7392C2C2), U64(0xB60B1D12, 0x30B20E04), /* ~= 10^-75 */
3097             U64(0x90BD77F3, 0x483BB9B9), U64(0xB1C6F22B, 0x5E6F48C2), /* ~= 10^-74 */
3098             U64(0xB4ECD5F0, 0x1A4AA828), U64(0x1E38AEB6, 0x360B1AF3), /* ~= 10^-73 */
3099             U64(0xE2280B6C, 0x20DD5232), U64(0x25C6DA63, 0xC38DE1B0), /* ~= 10^-72 */
3100             U64(0x8D590723, 0x948A535F), U64(0x579C487E, 0x5A38AD0E), /* ~= 10^-71 */
3101             U64(0xB0AF48EC, 0x79ACE837), U64(0x2D835A9D, 0xF0C6D851), /* ~= 10^-70 */
3102             U64(0xDCDB1B27, 0x98182244), U64(0xF8E43145, 0x6CF88E65), /* ~= 10^-69 */
3103             U64(0x8A08F0F8, 0xBF0F156B), U64(0x1B8E9ECB, 0x641B58FF), /* ~= 10^-68 */
3104             U64(0xAC8B2D36, 0xEED2DAC5), U64(0xE272467E, 0x3D222F3F), /* ~= 10^-67 */
3105             U64(0xD7ADF884, 0xAA879177), U64(0x5B0ED81D, 0xCC6ABB0F), /* ~= 10^-66 */
3106             U64(0x86CCBB52, 0xEA94BAEA), U64(0x98E94712, 0x9FC2B4E9), /* ~= 10^-65 */
3107             U64(0xA87FEA27, 0xA539E9A5), U64(0x3F2398D7, 0x47B36224), /* ~= 10^-64 */
3108             U64(0xD29FE4B1, 0x8E88640E), U64(0x8EEC7F0D, 0x19A03AAD), /* ~= 10^-63 */
3109             U64(0x83A3EEEE, 0xF9153E89), U64(0x1953CF68, 0x300424AC), /* ~= 10^-62 */
3110             U64(0xA48CEAAA, 0xB75A8E2B), U64(0x5FA8C342, 0x3C052DD7), /* ~= 10^-61 */
3111             U64(0xCDB02555, 0x653131B6), U64(0x3792F412, 0xCB06794D), /* ~= 10^-60 */
3112             U64(0x808E1755, 0x5F3EBF11), U64(0xE2BBD88B, 0xBEE40BD0), /* ~= 10^-59 */
3113             U64(0xA0B19D2A, 0xB70E6ED6), U64(0x5B6ACEAE, 0xAE9D0EC4), /* ~= 10^-58 */
3114             U64(0xC8DE0475, 0x64D20A8B), U64(0xF245825A, 0x5A445275), /* ~= 10^-57 */
3115             U64(0xFB158592, 0xBE068D2E), U64(0xEED6E2F0, 0xF0D56712), /* ~= 10^-56 */
3116             U64(0x9CED737B, 0xB6C4183D), U64(0x55464DD6, 0x9685606B), /* ~= 10^-55 */
3117             U64(0xC428D05A, 0xA4751E4C), U64(0xAA97E14C, 0x3C26B886), /* ~= 10^-54 */
3118             U64(0xF5330471, 0x4D9265DF), U64(0xD53DD99F, 0x4B3066A8), /* ~= 10^-53 */
3119             U64(0x993FE2C6, 0xD07B7FAB), U64(0xE546A803, 0x8EFE4029), /* ~= 10^-52 */
3120             U64(0xBF8FDB78, 0x849A5F96), U64(0xDE985204, 0x72BDD033), /* ~= 10^-51 */
3121             U64(0xEF73D256, 0xA5C0F77C), U64(0x963E6685, 0x8F6D4440), /* ~= 10^-50 */
3122             U64(0x95A86376, 0x27989AAD), U64(0xDDE70013, 0x79A44AA8), /* ~= 10^-49 */
3123             U64(0xBB127C53, 0xB17EC159), U64(0x5560C018, 0x580D5D52), /* ~= 10^-48 */
3124             U64(0xE9D71B68, 0x9DDE71AF), U64(0xAAB8F01E, 0x6E10B4A6), /* ~= 10^-47 */
3125             U64(0x92267121, 0x62AB070D), U64(0xCAB39613, 0x04CA70E8), /* ~= 10^-46 */
3126             U64(0xB6B00D69, 0xBB55C8D1), U64(0x3D607B97, 0xC5FD0D22), /* ~= 10^-45 */
3127             U64(0xE45C10C4, 0x2A2B3B05), U64(0x8CB89A7D, 0xB77C506A), /* ~= 10^-44 */
3128             U64(0x8EB98A7A, 0x9A5B04E3), U64(0x77F3608E, 0x92ADB242), /* ~= 10^-43 */
3129             U64(0xB267ED19, 0x40F1C61C), U64(0x55F038B2, 0x37591ED3), /* ~= 10^-42 */
3130             U64(0xDF01E85F, 0x912E37A3), U64(0x6B6C46DE, 0xC52F6688), /* ~= 10^-41 */
3131             U64(0x8B61313B, 0xBABCE2C6), U64(0x2323AC4B, 0x3B3DA015), /* ~= 10^-40 */
3132             U64(0xAE397D8A, 0xA96C1B77), U64(0xABEC975E, 0x0A0D081A), /* ~= 10^-39 */
3133             U64(0xD9C7DCED, 0x53C72255), U64(0x96E7BD35, 0x8C904A21), /* ~= 10^-38 */
3134             U64(0x881CEA14, 0x545C7575), U64(0x7E50D641, 0x77DA2E54), /* ~= 10^-37 */
3135             U64(0xAA242499, 0x697392D2), U64(0xDDE50BD1, 0xD5D0B9E9), /* ~= 10^-36 */
3136             U64(0xD4AD2DBF, 0xC3D07787), U64(0x955E4EC6, 0x4B44E864), /* ~= 10^-35 */
3137             U64(0x84EC3C97, 0xDA624AB4), U64(0xBD5AF13B, 0xEF0B113E), /* ~= 10^-34 */
3138             U64(0xA6274BBD, 0xD0FADD61), U64(0xECB1AD8A, 0xEACDD58E), /* ~= 10^-33 */
3139             U64(0xCFB11EAD, 0x453994BA), U64(0x67DE18ED, 0xA5814AF2), /* ~= 10^-32 */
3140             U64(0x81CEB32C, 0x4B43FCF4), U64(0x80EACF94, 0x8770CED7), /* ~= 10^-31 */
3141             U64(0xA2425FF7, 0x5E14FC31), U64(0xA1258379, 0xA94D028D), /* ~= 10^-30 */
3142             U64(0xCAD2F7F5, 0x359A3B3E), U64(0x096EE458, 0x13A04330), /* ~= 10^-29 */
3143             U64(0xFD87B5F2, 0x8300CA0D), U64(0x8BCA9D6E, 0x188853FC), /* ~= 10^-28 */
3144             U64(0x9E74D1B7, 0x91E07E48), U64(0x775EA264, 0xCF55347D), /* ~= 10^-27 */
3145             U64(0xC6120625, 0x76589DDA), U64(0x95364AFE, 0x032A819D), /* ~= 10^-26 */
3146             U64(0xF79687AE, 0xD3EEC551), U64(0x3A83DDBD, 0x83F52204), /* ~= 10^-25 */
3147             U64(0x9ABE14CD, 0x44753B52), U64(0xC4926A96, 0x72793542), /* ~= 10^-24 */
3148             U64(0xC16D9A00, 0x95928A27), U64(0x75B7053C, 0x0F178293), /* ~= 10^-23 */
3149             U64(0xF1C90080, 0xBAF72CB1), U64(0x5324C68B, 0x12DD6338), /* ~= 10^-22 */
3150             U64(0x971DA050, 0x74DA7BEE), U64(0xD3F6FC16, 0xEBCA5E03), /* ~= 10^-21 */
3151             U64(0xBCE50864, 0x92111AEA), U64(0x88F4BB1C, 0xA6BCF584), /* ~= 10^-20 */
3152             U64(0xEC1E4A7D, 0xB69561A5), U64(0x2B31E9E3, 0xD06C32E5), /* ~= 10^-19 */
3153             U64(0x9392EE8E, 0x921D5D07), U64(0x3AFF322E, 0x62439FCF), /* ~= 10^-18 */
3154             U64(0xB877AA32, 0x36A4B449), U64(0x09BEFEB9, 0xFAD487C2), /* ~= 10^-17 */
3155             U64(0xE69594BE, 0xC44DE15B), U64(0x4C2EBE68, 0x7989A9B3), /* ~= 10^-16 */
3156             U64(0x901D7CF7, 0x3AB0ACD9), U64(0x0F9D3701, 0x4BF60A10), /* ~= 10^-15 */
3157             U64(0xB424DC35, 0x095CD80F), U64(0x538484C1, 0x9EF38C94), /* ~= 10^-14 */
3158             U64(0xE12E1342, 0x4BB40E13), U64(0x2865A5F2, 0x06B06FB9), /* ~= 10^-13 */
3159             U64(0x8CBCCC09, 0x6F5088CB), U64(0xF93F87B7, 0x442E45D3), /* ~= 10^-12 */
3160             U64(0xAFEBFF0B, 0xCB24AAFE), U64(0xF78F69A5, 0x1539D748), /* ~= 10^-11 */
3161             U64(0xDBE6FECE, 0xBDEDD5BE), U64(0xB573440E, 0x5A884D1B), /* ~= 10^-10 */
3162             U64(0x89705F41, 0x36B4A597), U64(0x31680A88, 0xF8953030), /* ~= 10^-9 */
3163             U64(0xABCC7711, 0x8461CEFC), U64(0xFDC20D2B, 0x36BA7C3D), /* ~= 10^-8 */
3164             U64(0xD6BF94D5, 0xE57A42BC), U64(0x3D329076, 0x04691B4C), /* ~= 10^-7 */
3165             U64(0x8637BD05, 0xAF6C69B5), U64(0xA63F9A49, 0xC2C1B10F), /* ~= 10^-6 */
3166             U64(0xA7C5AC47, 0x1B478423), U64(0x0FCF80DC, 0x33721D53), /* ~= 10^-5 */
3167             U64(0xD1B71758, 0xE219652B), U64(0xD3C36113, 0x404EA4A8), /* ~= 10^-4 */
3168             U64(0x83126E97, 0x8D4FDF3B), U64(0x645A1CAC, 0x083126E9), /* ~= 10^-3 */
3169             U64(0xA3D70A3D, 0x70A3D70A), U64(0x3D70A3D7, 0x0A3D70A3), /* ~= 10^-2 */
3170             U64(0xCCCCCCCC, 0xCCCCCCCC), U64(0xCCCCCCCC, 0xCCCCCCCC), /* ~= 10^-1 */
3171             U64(0x80000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^0 */
3172             U64(0xA0000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^1 */
3173             U64(0xC8000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^2 */
3174             U64(0xFA000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^3 */
3175             U64(0x9C400000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^4 */
3176             U64(0xC3500000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^5 */
3177             U64(0xF4240000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^6 */
3178             U64(0x98968000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^7 */
3179             U64(0xBEBC2000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^8 */
3180             U64(0xEE6B2800, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^9 */
3181             U64(0x9502F900, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^10 */
3182             U64(0xBA43B740, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^11 */
3183             U64(0xE8D4A510, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^12 */
3184             U64(0x9184E72A, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^13 */
3185             U64(0xB5E620F4, 0x80000000), U64(0x00000000, 0x00000000), /* == 10^14 */
3186             U64(0xE35FA931, 0xA0000000), U64(0x00000000, 0x00000000), /* == 10^15 */
3187             U64(0x8E1BC9BF, 0x04000000), U64(0x00000000, 0x00000000), /* == 10^16 */
3188             U64(0xB1A2BC2E, 0xC5000000), U64(0x00000000, 0x00000000), /* == 10^17 */
3189             U64(0xDE0B6B3A, 0x76400000), U64(0x00000000, 0x00000000), /* == 10^18 */
3190             U64(0x8AC72304, 0x89E80000), U64(0x00000000, 0x00000000), /* == 10^19 */
3191             U64(0xAD78EBC5, 0xAC620000), U64(0x00000000, 0x00000000), /* == 10^20 */
3192             U64(0xD8D726B7, 0x177A8000), U64(0x00000000, 0x00000000), /* == 10^21 */
3193             U64(0x87867832, 0x6EAC9000), U64(0x00000000, 0x00000000), /* == 10^22 */
3194             U64(0xA968163F, 0x0A57B400), U64(0x00000000, 0x00000000), /* == 10^23 */
3195             U64(0xD3C21BCE, 0xCCEDA100), U64(0x00000000, 0x00000000), /* == 10^24 */
3196             U64(0x84595161, 0x401484A0), U64(0x00000000, 0x00000000), /* == 10^25 */
3197             U64(0xA56FA5B9, 0x9019A5C8), U64(0x00000000, 0x00000000), /* == 10^26 */
3198             U64(0xCECB8F27, 0xF4200F3A), U64(0x00000000, 0x00000000), /* == 10^27 */
3199             U64(0x813F3978, 0xF8940984), U64(0x40000000, 0x00000000), /* == 10^28 */
3200             U64(0xA18F07D7, 0x36B90BE5), U64(0x50000000, 0x00000000), /* == 10^29 */
3201             U64(0xC9F2C9CD, 0x04674EDE), U64(0xA4000000, 0x00000000), /* == 10^30 */
3202             U64(0xFC6F7C40, 0x45812296), U64(0x4D000000, 0x00000000), /* == 10^31 */
3203             U64(0x9DC5ADA8, 0x2B70B59D), U64(0xF0200000, 0x00000000), /* == 10^32 */
3204             U64(0xC5371912, 0x364CE305), U64(0x6C280000, 0x00000000), /* == 10^33 */
3205             U64(0xF684DF56, 0xC3E01BC6), U64(0xC7320000, 0x00000000), /* == 10^34 */
3206             U64(0x9A130B96, 0x3A6C115C), U64(0x3C7F4000, 0x00000000), /* == 10^35 */
3207             U64(0xC097CE7B, 0xC90715B3), U64(0x4B9F1000, 0x00000000), /* == 10^36 */
3208             U64(0xF0BDC21A, 0xBB48DB20), U64(0x1E86D400, 0x00000000), /* == 10^37 */
3209             U64(0x96769950, 0xB50D88F4), U64(0x13144480, 0x00000000), /* == 10^38 */
3210             U64(0xBC143FA4, 0xE250EB31), U64(0x17D955A0, 0x00000000), /* == 10^39 */
3211             U64(0xEB194F8E, 0x1AE525FD), U64(0x5DCFAB08, 0x00000000), /* == 10^40 */
3212             U64(0x92EFD1B8, 0xD0CF37BE), U64(0x5AA1CAE5, 0x00000000), /* == 10^41 */
3213             U64(0xB7ABC627, 0x050305AD), U64(0xF14A3D9E, 0x40000000), /* == 10^42 */
3214             U64(0xE596B7B0, 0xC643C719), U64(0x6D9CCD05, 0xD0000000), /* == 10^43 */
3215             U64(0x8F7E32CE, 0x7BEA5C6F), U64(0xE4820023, 0xA2000000), /* == 10^44 */
3216             U64(0xB35DBF82, 0x1AE4F38B), U64(0xDDA2802C, 0x8A800000), /* == 10^45 */
3217             U64(0xE0352F62, 0xA19E306E), U64(0xD50B2037, 0xAD200000), /* == 10^46 */
3218             U64(0x8C213D9D, 0xA502DE45), U64(0x4526F422, 0xCC340000), /* == 10^47 */
3219             U64(0xAF298D05, 0x0E4395D6), U64(0x9670B12B, 0x7F410000), /* == 10^48 */
3220             U64(0xDAF3F046, 0x51D47B4C), U64(0x3C0CDD76, 0x5F114000), /* == 10^49 */
3221             U64(0x88D8762B, 0xF324CD0F), U64(0xA5880A69, 0xFB6AC800), /* == 10^50 */
3222             U64(0xAB0E93B6, 0xEFEE0053), U64(0x8EEA0D04, 0x7A457A00), /* == 10^51 */
3223             U64(0xD5D238A4, 0xABE98068), U64(0x72A49045, 0x98D6D880), /* == 10^52 */
3224             U64(0x85A36366, 0xEB71F041), U64(0x47A6DA2B, 0x7F864750), /* == 10^53 */
3225             U64(0xA70C3C40, 0xA64E6C51), U64(0x999090B6, 0x5F67D924), /* == 10^54 */
3226             U64(0xD0CF4B50, 0xCFE20765), U64(0xFFF4B4E3, 0xF741CF6D), /* == 10^55 */
3227             U64(0x82818F12, 0x81ED449F), U64(0xBFF8F10E, 0x7A8921A4), /* ~= 10^56 */
3228             U64(0xA321F2D7, 0x226895C7), U64(0xAFF72D52, 0x192B6A0D), /* ~= 10^57 */
3229             U64(0xCBEA6F8C, 0xEB02BB39), U64(0x9BF4F8A6, 0x9F764490), /* ~= 10^58 */
3230             U64(0xFEE50B70, 0x25C36A08), U64(0x02F236D0, 0x4753D5B4), /* ~= 10^59 */
3231             U64(0x9F4F2726, 0x179A2245), U64(0x01D76242, 0x2C946590), /* ~= 10^60 */
3232             U64(0xC722F0EF, 0x9D80AAD6), U64(0x424D3AD2, 0xB7B97EF5), /* ~= 10^61 */
3233             U64(0xF8EBAD2B, 0x84E0D58B), U64(0xD2E08987, 0x65A7DEB2), /* ~= 10^62 */
3234             U64(0x9B934C3B, 0x330C8577), U64(0x63CC55F4, 0x9F88EB2F), /* ~= 10^63 */
3235             U64(0xC2781F49, 0xFFCFA6D5), U64(0x3CBF6B71, 0xC76B25FB), /* ~= 10^64 */
3236             U64(0xF316271C, 0x7FC3908A), U64(0x8BEF464E, 0x3945EF7A), /* ~= 10^65 */
3237             U64(0x97EDD871, 0xCFDA3A56), U64(0x97758BF0, 0xE3CBB5AC), /* ~= 10^66 */
3238             U64(0xBDE94E8E, 0x43D0C8EC), U64(0x3D52EEED, 0x1CBEA317), /* ~= 10^67 */
3239             U64(0xED63A231, 0xD4C4FB27), U64(0x4CA7AAA8, 0x63EE4BDD), /* ~= 10^68 */
3240             U64(0x945E455F, 0x24FB1CF8), U64(0x8FE8CAA9, 0x3E74EF6A), /* ~= 10^69 */
3241             U64(0xB975D6B6, 0xEE39E436), U64(0xB3E2FD53, 0x8E122B44), /* ~= 10^70 */
3242             U64(0xE7D34C64, 0xA9C85D44), U64(0x60DBBCA8, 0x7196B616), /* ~= 10^71 */
3243             U64(0x90E40FBE, 0xEA1D3A4A), U64(0xBC8955E9, 0x46FE31CD), /* ~= 10^72 */
3244             U64(0xB51D13AE, 0xA4A488DD), U64(0x6BABAB63, 0x98BDBE41), /* ~= 10^73 */
3245             U64(0xE264589A, 0x4DCDAB14), U64(0xC696963C, 0x7EED2DD1), /* ~= 10^74 */
3246             U64(0x8D7EB760, 0x70A08AEC), U64(0xFC1E1DE5, 0xCF543CA2), /* ~= 10^75 */
3247             U64(0xB0DE6538, 0x8CC8ADA8), U64(0x3B25A55F, 0x43294BCB), /* ~= 10^76 */
3248             U64(0xDD15FE86, 0xAFFAD912), U64(0x49EF0EB7, 0x13F39EBE), /* ~= 10^77 */
3249             U64(0x8A2DBF14, 0x2DFCC7AB), U64(0x6E356932, 0x6C784337), /* ~= 10^78 */
3250             U64(0xACB92ED9, 0x397BF996), U64(0x49C2C37F, 0x07965404), /* ~= 10^79 */
3251             U64(0xD7E77A8F, 0x87DAF7FB), U64(0xDC33745E, 0xC97BE906), /* ~= 10^80 */
3252             U64(0x86F0AC99, 0xB4E8DAFD), U64(0x69A028BB, 0x3DED71A3), /* ~= 10^81 */
3253             U64(0xA8ACD7C0, 0x222311BC), U64(0xC40832EA, 0x0D68CE0C), /* ~= 10^82 */
3254             U64(0xD2D80DB0, 0x2AABD62B), U64(0xF50A3FA4, 0x90C30190), /* ~= 10^83 */
3255             U64(0x83C7088E, 0x1AAB65DB), U64(0x792667C6, 0xDA79E0FA), /* ~= 10^84 */
3256             U64(0xA4B8CAB1, 0xA1563F52), U64(0x577001B8, 0x91185938), /* ~= 10^85 */
3257             U64(0xCDE6FD5E, 0x09ABCF26), U64(0xED4C0226, 0xB55E6F86), /* ~= 10^86 */
3258             U64(0x80B05E5A, 0xC60B6178), U64(0x544F8158, 0x315B05B4), /* ~= 10^87 */
3259             U64(0xA0DC75F1, 0x778E39D6), U64(0x696361AE, 0x3DB1C721), /* ~= 10^88 */
3260             U64(0xC913936D, 0xD571C84C), U64(0x03BC3A19, 0xCD1E38E9), /* ~= 10^89 */
3261             U64(0xFB587849, 0x4ACE3A5F), U64(0x04AB48A0, 0x4065C723), /* ~= 10^90 */
3262             U64(0x9D174B2D, 0xCEC0E47B), U64(0x62EB0D64, 0x283F9C76), /* ~= 10^91 */
3263             U64(0xC45D1DF9, 0x42711D9A), U64(0x3BA5D0BD, 0x324F8394), /* ~= 10^92 */
3264             U64(0xF5746577, 0x930D6500), U64(0xCA8F44EC, 0x7EE36479), /* ~= 10^93 */
3265             U64(0x9968BF6A, 0xBBE85F20), U64(0x7E998B13, 0xCF4E1ECB), /* ~= 10^94 */
3266             U64(0xBFC2EF45, 0x6AE276E8), U64(0x9E3FEDD8, 0xC321A67E), /* ~= 10^95 */
3267             U64(0xEFB3AB16, 0xC59B14A2), U64(0xC5CFE94E, 0xF3EA101E), /* ~= 10^96 */
3268             U64(0x95D04AEE, 0x3B80ECE5), U64(0xBBA1F1D1, 0x58724A12), /* ~= 10^97 */
3269             U64(0xBB445DA9, 0xCA61281F), U64(0x2A8A6E45, 0xAE8EDC97), /* ~= 10^98 */
3270             U64(0xEA157514, 0x3CF97226), U64(0xF52D09D7, 0x1A3293BD), /* ~= 10^99 */
3271             U64(0x924D692C, 0xA61BE758), U64(0x593C2626, 0x705F9C56), /* ~= 10^100 */
3272             U64(0xB6E0C377, 0xCFA2E12E), U64(0x6F8B2FB0, 0x0C77836C), /* ~= 10^101 */
3273             U64(0xE498F455, 0xC38B997A), U64(0x0B6DFB9C, 0x0F956447), /* ~= 10^102 */
3274             U64(0x8EDF98B5, 0x9A373FEC), U64(0x4724BD41, 0x89BD5EAC), /* ~= 10^103 */
3275             U64(0xB2977EE3, 0x00C50FE7), U64(0x58EDEC91, 0xEC2CB657), /* ~= 10^104 */
3276             U64(0xDF3D5E9B, 0xC0F653E1), U64(0x2F2967B6, 0x6737E3ED), /* ~= 10^105 */
3277             U64(0x8B865B21, 0x5899F46C), U64(0xBD79E0D2, 0x0082EE74), /* ~= 10^106 */
3278             U64(0xAE67F1E9, 0xAEC07187), U64(0xECD85906, 0x80A3AA11), /* ~= 10^107 */
3279             U64(0xDA01EE64, 0x1A708DE9), U64(0xE80E6F48, 0x20CC9495), /* ~= 10^108 */
3280             U64(0x884134FE, 0x908658B2), U64(0x3109058D, 0x147FDCDD), /* ~= 10^109 */
3281             U64(0xAA51823E, 0x34A7EEDE), U64(0xBD4B46F0, 0x599FD415), /* ~= 10^110 */
3282             U64(0xD4E5E2CD, 0xC1D1EA96), U64(0x6C9E18AC, 0x7007C91A), /* ~= 10^111 */
3283             U64(0x850FADC0, 0x9923329E), U64(0x03E2CF6B, 0xC604DDB0), /* ~= 10^112 */
3284             U64(0xA6539930, 0xBF6BFF45), U64(0x84DB8346, 0xB786151C), /* ~= 10^113 */
3285             U64(0xCFE87F7C, 0xEF46FF16), U64(0xE6126418, 0x65679A63), /* ~= 10^114 */
3286             U64(0x81F14FAE, 0x158C5F6E), U64(0x4FCB7E8F, 0x3F60C07E), /* ~= 10^115 */
3287             U64(0xA26DA399, 0x9AEF7749), U64(0xE3BE5E33, 0x0F38F09D), /* ~= 10^116 */
3288             U64(0xCB090C80, 0x01AB551C), U64(0x5CADF5BF, 0xD3072CC5), /* ~= 10^117 */
3289             U64(0xFDCB4FA0, 0x02162A63), U64(0x73D9732F, 0xC7C8F7F6), /* ~= 10^118 */
3290             U64(0x9E9F11C4, 0x014DDA7E), U64(0x2867E7FD, 0xDCDD9AFA), /* ~= 10^119 */
3291             U64(0xC646D635, 0x01A1511D), U64(0xB281E1FD, 0x541501B8), /* ~= 10^120 */
3292             U64(0xF7D88BC2, 0x4209A565), U64(0x1F225A7C, 0xA91A4226), /* ~= 10^121 */
3293             U64(0x9AE75759, 0x6946075F), U64(0x3375788D, 0xE9B06958), /* ~= 10^122 */
3294             U64(0xC1A12D2F, 0xC3978937), U64(0x0052D6B1, 0x641C83AE), /* ~= 10^123 */
3295             U64(0xF209787B, 0xB47D6B84), U64(0xC0678C5D, 0xBD23A49A), /* ~= 10^124 */
3296             U64(0x9745EB4D, 0x50CE6332), U64(0xF840B7BA, 0x963646E0), /* ~= 10^125 */
3297             U64(0xBD176620, 0xA501FBFF), U64(0xB650E5A9, 0x3BC3D898), /* ~= 10^126 */
3298             U64(0xEC5D3FA8, 0xCE427AFF), U64(0xA3E51F13, 0x8AB4CEBE), /* ~= 10^127 */
3299             U64(0x93BA47C9, 0x80E98CDF), U64(0xC66F336C, 0x36B10137), /* ~= 10^128 */
3300             U64(0xB8A8D9BB, 0xE123F017), U64(0xB80B0047, 0x445D4184), /* ~= 10^129 */
3301             U64(0xE6D3102A, 0xD96CEC1D), U64(0xA60DC059, 0x157491E5), /* ~= 10^130 */
3302             U64(0x9043EA1A, 0xC7E41392), U64(0x87C89837, 0xAD68DB2F), /* ~= 10^131 */
3303             U64(0xB454E4A1, 0x79DD1877), U64(0x29BABE45, 0x98C311FB), /* ~= 10^132 */
3304             U64(0xE16A1DC9, 0xD8545E94), U64(0xF4296DD6, 0xFEF3D67A), /* ~= 10^133 */
3305             U64(0x8CE2529E, 0x2734BB1D), U64(0x1899E4A6, 0x5F58660C), /* ~= 10^134 */
3306             U64(0xB01AE745, 0xB101E9E4), U64(0x5EC05DCF, 0xF72E7F8F), /* ~= 10^135 */
3307             U64(0xDC21A117, 0x1D42645D), U64(0x76707543, 0xF4FA1F73), /* ~= 10^136 */
3308             U64(0x899504AE, 0x72497EBA), U64(0x6A06494A, 0x791C53A8), /* ~= 10^137 */
3309             U64(0xABFA45DA, 0x0EDBDE69), U64(0x0487DB9D, 0x17636892), /* ~= 10^138 */
3310             U64(0xD6F8D750, 0x9292D603), U64(0x45A9D284, 0x5D3C42B6), /* ~= 10^139 */
3311             U64(0x865B8692, 0x5B9BC5C2), U64(0x0B8A2392, 0xBA45A9B2), /* ~= 10^140 */
3312             U64(0xA7F26836, 0xF282B732), U64(0x8E6CAC77, 0x68D7141E), /* ~= 10^141 */
3313             U64(0xD1EF0244, 0xAF2364FF), U64(0x3207D795, 0x430CD926), /* ~= 10^142 */
3314             U64(0x8335616A, 0xED761F1F), U64(0x7F44E6BD, 0x49E807B8), /* ~= 10^143 */
3315             U64(0xA402B9C5, 0xA8D3A6E7), U64(0x5F16206C, 0x9C6209A6), /* ~= 10^144 */
3316             U64(0xCD036837, 0x130890A1), U64(0x36DBA887, 0xC37A8C0F), /* ~= 10^145 */
3317             U64(0x80222122, 0x6BE55A64), U64(0xC2494954, 0xDA2C9789), /* ~= 10^146 */
3318             U64(0xA02AA96B, 0x06DEB0FD), U64(0xF2DB9BAA, 0x10B7BD6C), /* ~= 10^147 */
3319             U64(0xC83553C5, 0xC8965D3D), U64(0x6F928294, 0x94E5ACC7), /* ~= 10^148 */
3320             U64(0xFA42A8B7, 0x3ABBF48C), U64(0xCB772339, 0xBA1F17F9), /* ~= 10^149 */
3321             U64(0x9C69A972, 0x84B578D7), U64(0xFF2A7604, 0x14536EFB), /* ~= 10^150 */
3322             U64(0xC38413CF, 0x25E2D70D), U64(0xFEF51385, 0x19684ABA), /* ~= 10^151 */
3323             U64(0xF46518C2, 0xEF5B8CD1), U64(0x7EB25866, 0x5FC25D69), /* ~= 10^152 */
3324             U64(0x98BF2F79, 0xD5993802), U64(0xEF2F773F, 0xFBD97A61), /* ~= 10^153 */
3325             U64(0xBEEEFB58, 0x4AFF8603), U64(0xAAFB550F, 0xFACFD8FA), /* ~= 10^154 */
3326             U64(0xEEAABA2E, 0x5DBF6784), U64(0x95BA2A53, 0xF983CF38), /* ~= 10^155 */
3327             U64(0x952AB45C, 0xFA97A0B2), U64(0xDD945A74, 0x7BF26183), /* ~= 10^156 */
3328             U64(0xBA756174, 0x393D88DF), U64(0x94F97111, 0x9AEEF9E4), /* ~= 10^157 */
3329             U64(0xE912B9D1, 0x478CEB17), U64(0x7A37CD56, 0x01AAB85D), /* ~= 10^158 */
3330             U64(0x91ABB422, 0xCCB812EE), U64(0xAC62E055, 0xC10AB33A), /* ~= 10^159 */
3331             U64(0xB616A12B, 0x7FE617AA), U64(0x577B986B, 0x314D6009), /* ~= 10^160 */
3332             U64(0xE39C4976, 0x5FDF9D94), U64(0xED5A7E85, 0xFDA0B80B), /* ~= 10^161 */
3333             U64(0x8E41ADE9, 0xFBEBC27D), U64(0x14588F13, 0xBE847307), /* ~= 10^162 */
3334             U64(0xB1D21964, 0x7AE6B31C), U64(0x596EB2D8, 0xAE258FC8), /* ~= 10^163 */
3335             U64(0xDE469FBD, 0x99A05FE3), U64(0x6FCA5F8E, 0xD9AEF3BB), /* ~= 10^164 */
3336             U64(0x8AEC23D6, 0x80043BEE), U64(0x25DE7BB9, 0x480D5854), /* ~= 10^165 */
3337             U64(0xADA72CCC, 0x20054AE9), U64(0xAF561AA7, 0x9A10AE6A), /* ~= 10^166 */
3338             U64(0xD910F7FF, 0x28069DA4), U64(0x1B2BA151, 0x8094DA04), /* ~= 10^167 */
3339             U64(0x87AA9AFF, 0x79042286), U64(0x90FB44D2, 0xF05D0842), /* ~= 10^168 */
3340             U64(0xA99541BF, 0x57452B28), U64(0x353A1607, 0xAC744A53), /* ~= 10^169 */
3341             U64(0xD3FA922F, 0x2D1675F2), U64(0x42889B89, 0x97915CE8), /* ~= 10^170 */
3342             U64(0x847C9B5D, 0x7C2E09B7), U64(0x69956135, 0xFEBADA11), /* ~= 10^171 */
3343             U64(0xA59BC234, 0xDB398C25), U64(0x43FAB983, 0x7E699095), /* ~= 10^172 */
3344             U64(0xCF02B2C2, 0x1207EF2E), U64(0x94F967E4, 0x5E03F4BB), /* ~= 10^173 */
3345             U64(0x8161AFB9, 0x4B44F57D), U64(0x1D1BE0EE, 0xBAC278F5), /* ~= 10^174 */
3346             U64(0xA1BA1BA7, 0x9E1632DC), U64(0x6462D92A, 0x69731732), /* ~= 10^175 */
3347             U64(0xCA28A291, 0x859BBF93), U64(0x7D7B8F75, 0x03CFDCFE), /* ~= 10^176 */
3348             U64(0xFCB2CB35, 0xE702AF78), U64(0x5CDA7352, 0x44C3D43E), /* ~= 10^177 */
3349             U64(0x9DEFBF01, 0xB061ADAB), U64(0x3A088813, 0x6AFA64A7), /* ~= 10^178 */
3350             U64(0xC56BAEC2, 0x1C7A1916), U64(0x088AAA18, 0x45B8FDD0), /* ~= 10^179 */
3351             U64(0xF6C69A72, 0xA3989F5B), U64(0x8AAD549E, 0x57273D45), /* ~= 10^180 */
3352             U64(0x9A3C2087, 0xA63F6399), U64(0x36AC54E2, 0xF678864B), /* ~= 10^181 */
3353             U64(0xC0CB28A9, 0x8FCF3C7F), U64(0x84576A1B, 0xB416A7DD), /* ~= 10^182 */
3354             U64(0xF0FDF2D3, 0xF3C30B9F), U64(0x656D44A2, 0xA11C51D5), /* ~= 10^183 */
3355             U64(0x969EB7C4, 0x7859E743), U64(0x9F644AE5, 0xA4B1B325), /* ~= 10^184 */
3356             U64(0xBC4665B5, 0x96706114), U64(0x873D5D9F, 0x0DDE1FEE), /* ~= 10^185 */
3357             U64(0xEB57FF22, 0xFC0C7959), U64(0xA90CB506, 0xD155A7EA), /* ~= 10^186 */
3358             U64(0x9316FF75, 0xDD87CBD8), U64(0x09A7F124, 0x42D588F2), /* ~= 10^187 */
3359             U64(0xB7DCBF53, 0x54E9BECE), U64(0x0C11ED6D, 0x538AEB2F), /* ~= 10^188 */
3360             U64(0xE5D3EF28, 0x2A242E81), U64(0x8F1668C8, 0xA86DA5FA), /* ~= 10^189 */
3361             U64(0x8FA47579, 0x1A569D10), U64(0xF96E017D, 0x694487BC), /* ~= 10^190 */
3362             U64(0xB38D92D7, 0x60EC4455), U64(0x37C981DC, 0xC395A9AC), /* ~= 10^191 */
3363             U64(0xE070F78D, 0x3927556A), U64(0x85BBE253, 0xF47B1417), /* ~= 10^192 */
3364             U64(0x8C469AB8, 0x43B89562), U64(0x93956D74, 0x78CCEC8E), /* ~= 10^193 */
3365             U64(0xAF584166, 0x54A6BABB), U64(0x387AC8D1, 0x970027B2), /* ~= 10^194 */
3366             U64(0xDB2E51BF, 0xE9D0696A), U64(0x06997B05, 0xFCC0319E), /* ~= 10^195 */
3367             U64(0x88FCF317, 0xF22241E2), U64(0x441FECE3, 0xBDF81F03), /* ~= 10^196 */
3368             U64(0xAB3C2FDD, 0xEEAAD25A), U64(0xD527E81C, 0xAD7626C3), /* ~= 10^197 */
3369             U64(0xD60B3BD5, 0x6A5586F1), U64(0x8A71E223, 0xD8D3B074), /* ~= 10^198 */
3370             U64(0x85C70565, 0x62757456), U64(0xF6872D56, 0x67844E49), /* ~= 10^199 */
3371             U64(0xA738C6BE, 0xBB12D16C), U64(0xB428F8AC, 0x016561DB), /* ~= 10^200 */
3372             U64(0xD106F86E, 0x69D785C7), U64(0xE13336D7, 0x01BEBA52), /* ~= 10^201 */
3373             U64(0x82A45B45, 0x0226B39C), U64(0xECC00246, 0x61173473), /* ~= 10^202 */
3374             U64(0xA34D7216, 0x42B06084), U64(0x27F002D7, 0xF95D0190), /* ~= 10^203 */
3375             U64(0xCC20CE9B, 0xD35C78A5), U64(0x31EC038D, 0xF7B441F4), /* ~= 10^204 */
3376             U64(0xFF290242, 0xC83396CE), U64(0x7E670471, 0x75A15271), /* ~= 10^205 */
3377             U64(0x9F79A169, 0xBD203E41), U64(0x0F0062C6, 0xE984D386), /* ~= 10^206 */
3378             U64(0xC75809C4, 0x2C684DD1), U64(0x52C07B78, 0xA3E60868), /* ~= 10^207 */
3379             U64(0xF92E0C35, 0x37826145), U64(0xA7709A56, 0xCCDF8A82), /* ~= 10^208 */
3380             U64(0x9BBCC7A1, 0x42B17CCB), U64(0x88A66076, 0x400BB691), /* ~= 10^209 */
3381             U64(0xC2ABF989, 0x935DDBFE), U64(0x6ACFF893, 0xD00EA435), /* ~= 10^210 */
3382             U64(0xF356F7EB, 0xF83552FE), U64(0x0583F6B8, 0xC4124D43), /* ~= 10^211 */
3383             U64(0x98165AF3, 0x7B2153DE), U64(0xC3727A33, 0x7A8B704A), /* ~= 10^212 */
3384             U64(0xBE1BF1B0, 0x59E9A8D6), U64(0x744F18C0, 0x592E4C5C), /* ~= 10^213 */
3385             U64(0xEDA2EE1C, 0x7064130C), U64(0x1162DEF0, 0x6F79DF73), /* ~= 10^214 */
3386             U64(0x9485D4D1, 0xC63E8BE7), U64(0x8ADDCB56, 0x45AC2BA8), /* ~= 10^215 */
3387             U64(0xB9A74A06, 0x37CE2EE1), U64(0x6D953E2B, 0xD7173692), /* ~= 10^216 */
3388             U64(0xE8111C87, 0xC5C1BA99), U64(0xC8FA8DB6, 0xCCDD0437), /* ~= 10^217 */
3389             U64(0x910AB1D4, 0xDB9914A0), U64(0x1D9C9892, 0x400A22A2), /* ~= 10^218 */
3390             U64(0xB54D5E4A, 0x127F59C8), U64(0x2503BEB6, 0xD00CAB4B), /* ~= 10^219 */
3391             U64(0xE2A0B5DC, 0x971F303A), U64(0x2E44AE64, 0x840FD61D), /* ~= 10^220 */
3392             U64(0x8DA471A9, 0xDE737E24), U64(0x5CEAECFE, 0xD289E5D2), /* ~= 10^221 */
3393             U64(0xB10D8E14, 0x56105DAD), U64(0x7425A83E, 0x872C5F47), /* ~= 10^222 */
3394             U64(0xDD50F199, 0x6B947518), U64(0xD12F124E, 0x28F77719), /* ~= 10^223 */
3395             U64(0x8A5296FF, 0xE33CC92F), U64(0x82BD6B70, 0xD99AAA6F), /* ~= 10^224 */
3396             U64(0xACE73CBF, 0xDC0BFB7B), U64(0x636CC64D, 0x1001550B), /* ~= 10^225 */
3397             U64(0xD8210BEF, 0xD30EFA5A), U64(0x3C47F7E0, 0x5401AA4E), /* ~= 10^226 */
3398             U64(0x8714A775, 0xE3E95C78), U64(0x65ACFAEC, 0x34810A71), /* ~= 10^227 */
3399             U64(0xA8D9D153, 0x5CE3B396), U64(0x7F1839A7, 0x41A14D0D), /* ~= 10^228 */
3400             U64(0xD31045A8, 0x341CA07C), U64(0x1EDE4811, 0x1209A050), /* ~= 10^229 */
3401             U64(0x83EA2B89, 0x2091E44D), U64(0x934AED0A, 0xAB460432), /* ~= 10^230 */
3402             U64(0xA4E4B66B, 0x68B65D60), U64(0xF81DA84D, 0x5617853F), /* ~= 10^231 */
3403             U64(0xCE1DE406, 0x42E3F4B9), U64(0x36251260, 0xAB9D668E), /* ~= 10^232 */
3404             U64(0x80D2AE83, 0xE9CE78F3), U64(0xC1D72B7C, 0x6B426019), /* ~= 10^233 */
3405             U64(0xA1075A24, 0xE4421730), U64(0xB24CF65B, 0x8612F81F), /* ~= 10^234 */
3406             U64(0xC94930AE, 0x1D529CFC), U64(0xDEE033F2, 0x6797B627), /* ~= 10^235 */
3407             U64(0xFB9B7CD9, 0xA4A7443C), U64(0x169840EF, 0x017DA3B1), /* ~= 10^236 */
3408             U64(0x9D412E08, 0x06E88AA5), U64(0x8E1F2895, 0x60EE864E), /* ~= 10^237 */
3409             U64(0xC491798A, 0x08A2AD4E), U64(0xF1A6F2BA, 0xB92A27E2), /* ~= 10^238 */
3410             U64(0xF5B5D7EC, 0x8ACB58A2), U64(0xAE10AF69, 0x6774B1DB), /* ~= 10^239 */
3411             U64(0x9991A6F3, 0xD6BF1765), U64(0xACCA6DA1, 0xE0A8EF29), /* ~= 10^240 */
3412             U64(0xBFF610B0, 0xCC6EDD3F), U64(0x17FD090A, 0x58D32AF3), /* ~= 10^241 */
3413             U64(0xEFF394DC, 0xFF8A948E), U64(0xDDFC4B4C, 0xEF07F5B0), /* ~= 10^242 */
3414             U64(0x95F83D0A, 0x1FB69CD9), U64(0x4ABDAF10, 0x1564F98E), /* ~= 10^243 */
3415             U64(0xBB764C4C, 0xA7A4440F), U64(0x9D6D1AD4, 0x1ABE37F1), /* ~= 10^244 */
3416             U64(0xEA53DF5F, 0xD18D5513), U64(0x84C86189, 0x216DC5ED), /* ~= 10^245 */
3417             U64(0x92746B9B, 0xE2F8552C), U64(0x32FD3CF5, 0xB4E49BB4), /* ~= 10^246 */
3418             U64(0xB7118682, 0xDBB66A77), U64(0x3FBC8C33, 0x221DC2A1), /* ~= 10^247 */
3419             U64(0xE4D5E823, 0x92A40515), U64(0x0FABAF3F, 0xEAA5334A), /* ~= 10^248 */
3420             U64(0x8F05B116, 0x3BA6832D), U64(0x29CB4D87, 0xF2A7400E), /* ~= 10^249 */
3421             U64(0xB2C71D5B, 0xCA9023F8), U64(0x743E20E9, 0xEF511012), /* ~= 10^250 */
3422             U64(0xDF78E4B2, 0xBD342CF6), U64(0x914DA924, 0x6B255416), /* ~= 10^251 */
3423             U64(0x8BAB8EEF, 0xB6409C1A), U64(0x1AD089B6, 0xC2F7548E), /* ~= 10^252 */
3424             U64(0xAE9672AB, 0xA3D0C320), U64(0xA184AC24, 0x73B529B1), /* ~= 10^253 */
3425             U64(0xDA3C0F56, 0x8CC4F3E8), U64(0xC9E5D72D, 0x90A2741E), /* ~= 10^254 */
3426             U64(0x88658996, 0x17FB1871), U64(0x7E2FA67C, 0x7A658892), /* ~= 10^255 */
3427             U64(0xAA7EEBFB, 0x9DF9DE8D), U64(0xDDBB901B, 0x98FEEAB7), /* ~= 10^256 */
3428             U64(0xD51EA6FA, 0x85785631), U64(0x552A7422, 0x7F3EA565), /* ~= 10^257 */
3429             U64(0x8533285C, 0x936B35DE), U64(0xD53A8895, 0x8F87275F), /* ~= 10^258 */
3430             U64(0xA67FF273, 0xB8460356), U64(0x8A892ABA, 0xF368F137), /* ~= 10^259 */
3431             U64(0xD01FEF10, 0xA657842C), U64(0x2D2B7569, 0xB0432D85), /* ~= 10^260 */
3432             U64(0x8213F56A, 0x67F6B29B), U64(0x9C3B2962, 0x0E29FC73), /* ~= 10^261 */
3433             U64(0xA298F2C5, 0x01F45F42), U64(0x8349F3BA, 0x91B47B8F), /* ~= 10^262 */
3434             U64(0xCB3F2F76, 0x42717713), U64(0x241C70A9, 0x36219A73), /* ~= 10^263 */
3435             U64(0xFE0EFB53, 0xD30DD4D7), U64(0xED238CD3, 0x83AA0110), /* ~= 10^264 */
3436             U64(0x9EC95D14, 0x63E8A506), U64(0xF4363804, 0x324A40AA), /* ~= 10^265 */
3437             U64(0xC67BB459, 0x7CE2CE48), U64(0xB143C605, 0x3EDCD0D5), /* ~= 10^266 */
3438             U64(0xF81AA16F, 0xDC1B81DA), U64(0xDD94B786, 0x8E94050A), /* ~= 10^267 */
3439             U64(0x9B10A4E5, 0xE9913128), U64(0xCA7CF2B4, 0x191C8326), /* ~= 10^268 */
3440             U64(0xC1D4CE1F, 0x63F57D72), U64(0xFD1C2F61, 0x1F63A3F0), /* ~= 10^269 */
3441             U64(0xF24A01A7, 0x3CF2DCCF), U64(0xBC633B39, 0x673C8CEC), /* ~= 10^270 */
3442             U64(0x976E4108, 0x8617CA01), U64(0xD5BE0503, 0xE085D813), /* ~= 10^271 */
3443             U64(0xBD49D14A, 0xA79DBC82), U64(0x4B2D8644, 0xD8A74E18), /* ~= 10^272 */
3444             U64(0xEC9C459D, 0x51852BA2), U64(0xDDF8E7D6, 0x0ED1219E), /* ~= 10^273 */
3445             U64(0x93E1AB82, 0x52F33B45), U64(0xCABB90E5, 0xC942B503), /* ~= 10^274 */
3446             U64(0xB8DA1662, 0xE7B00A17), U64(0x3D6A751F, 0x3B936243), /* ~= 10^275 */
3447             U64(0xE7109BFB, 0xA19C0C9D), U64(0x0CC51267, 0x0A783AD4), /* ~= 10^276 */
3448             U64(0x906A617D, 0x450187E2), U64(0x27FB2B80, 0x668B24C5), /* ~= 10^277 */
3449             U64(0xB484F9DC, 0x9641E9DA), U64(0xB1F9F660, 0x802DEDF6), /* ~= 10^278 */
3450             U64(0xE1A63853, 0xBBD26451), U64(0x5E7873F8, 0xA0396973), /* ~= 10^279 */
3451             U64(0x8D07E334, 0x55637EB2), U64(0xDB0B487B, 0x6423E1E8), /* ~= 10^280 */
3452             U64(0xB049DC01, 0x6ABC5E5F), U64(0x91CE1A9A, 0x3D2CDA62), /* ~= 10^281 */
3453             U64(0xDC5C5301, 0xC56B75F7), U64(0x7641A140, 0xCC7810FB), /* ~= 10^282 */
3454             U64(0x89B9B3E1, 0x1B6329BA), U64(0xA9E904C8, 0x7FCB0A9D), /* ~= 10^283 */
3455             U64(0xAC2820D9, 0x623BF429), U64(0x546345FA, 0x9FBDCD44), /* ~= 10^284 */
3456             U64(0xD732290F, 0xBACAF133), U64(0xA97C1779, 0x47AD4095), /* ~= 10^285 */
3457             U64(0x867F59A9, 0xD4BED6C0), U64(0x49ED8EAB, 0xCCCC485D), /* ~= 10^286 */
3458             U64(0xA81F3014, 0x49EE8C70), U64(0x5C68F256, 0xBFFF5A74), /* ~= 10^287 */
3459             U64(0xD226FC19, 0x5C6A2F8C), U64(0x73832EEC, 0x6FFF3111), /* ~= 10^288 */
3460             U64(0x83585D8F, 0xD9C25DB7), U64(0xC831FD53, 0xC5FF7EAB), /* ~= 10^289 */
3461             U64(0xA42E74F3, 0xD032F525), U64(0xBA3E7CA8, 0xB77F5E55), /* ~= 10^290 */
3462             U64(0xCD3A1230, 0xC43FB26F), U64(0x28CE1BD2, 0xE55F35EB), /* ~= 10^291 */
3463             U64(0x80444B5E, 0x7AA7CF85), U64(0x7980D163, 0xCF5B81B3), /* ~= 10^292 */
3464             U64(0xA0555E36, 0x1951C366), U64(0xD7E105BC, 0xC332621F), /* ~= 10^293 */
3465             U64(0xC86AB5C3, 0x9FA63440), U64(0x8DD9472B, 0xF3FEFAA7), /* ~= 10^294 */
3466             U64(0xFA856334, 0x878FC150), U64(0xB14F98F6, 0xF0FEB951), /* ~= 10^295 */
3467             U64(0x9C935E00, 0xD4B9D8D2), U64(0x6ED1BF9A, 0x569F33D3), /* ~= 10^296 */
3468             U64(0xC3B83581, 0x09E84F07), U64(0x0A862F80, 0xEC4700C8), /* ~= 10^297 */
3469             U64(0xF4A642E1, 0x4C6262C8), U64(0xCD27BB61, 0x2758C0FA), /* ~= 10^298 */
3470             U64(0x98E7E9CC, 0xCFBD7DBD), U64(0x8038D51C, 0xB897789C), /* ~= 10^299 */
3471             U64(0xBF21E440, 0x03ACDD2C), U64(0xE0470A63, 0xE6BD56C3), /* ~= 10^300 */
3472             U64(0xEEEA5D50, 0x04981478), U64(0x1858CCFC, 0xE06CAC74), /* ~= 10^301 */
3473             U64(0x95527A52, 0x02DF0CCB), U64(0x0F37801E, 0x0C43EBC8), /* ~= 10^302 */
3474             U64(0xBAA718E6, 0x8396CFFD), U64(0xD3056025, 0x8F54E6BA), /* ~= 10^303 */
3475             U64(0xE950DF20, 0x247C83FD), U64(0x47C6B82E, 0xF32A2069), /* ~= 10^304 */
3476             U64(0x91D28B74, 0x16CDD27E), U64(0x4CDC331D, 0x57FA5441), /* ~= 10^305 */
3477             U64(0xB6472E51, 0x1C81471D), U64(0xE0133FE4, 0xADF8E952), /* ~= 10^306 */
3478             U64(0xE3D8F9E5, 0x63A198E5), U64(0x58180FDD, 0xD97723A6), /* ~= 10^307 */
3479             U64(0x8E679C2F, 0x5E44FF8F), U64(0x570F09EA, 0xA7EA7648), /* ~= 10^308 */
3480             U64(0xB201833B, 0x35D63F73), U64(0x2CD2CC65, 0x51E513DA), /* ~= 10^309 */
3481             U64(0xDE81E40A, 0x034BCF4F), U64(0xF8077F7E, 0xA65E58D1), /* ~= 10^310 */
3482             U64(0x8B112E86, 0x420F6191), U64(0xFB04AFAF, 0x27FAF782), /* ~= 10^311 */
3483             U64(0xADD57A27, 0xD29339F6), U64(0x79C5DB9A, 0xF1F9B563), /* ~= 10^312 */
3484             U64(0xD94AD8B1, 0xC7380874), U64(0x18375281, 0xAE7822BC), /* ~= 10^313 */
3485             U64(0x87CEC76F, 0x1C830548), U64(0x8F229391, 0x0D0B15B5), /* ~= 10^314 */
3486             U64(0xA9C2794A, 0xE3A3C69A), U64(0xB2EB3875, 0x504DDB22), /* ~= 10^315 */
3487             U64(0xD433179D, 0x9C8CB841), U64(0x5FA60692, 0xA46151EB), /* ~= 10^316 */
3488             U64(0x849FEEC2, 0x81D7F328), U64(0xDBC7C41B, 0xA6BCD333), /* ~= 10^317 */
3489             U64(0xA5C7EA73, 0x224DEFF3), U64(0x12B9B522, 0x906C0800), /* ~= 10^318 */
3490             U64(0xCF39E50F, 0xEAE16BEF), U64(0xD768226B, 0x34870A00), /* ~= 10^319 */
3491             U64(0x81842F29, 0xF2CCE375), U64(0xE6A11583, 0x00D46640), /* ~= 10^320 */
3492             U64(0xA1E53AF4, 0x6F801C53), U64(0x60495AE3, 0xC1097FD0), /* ~= 10^321 */
3493             U64(0xCA5E89B1, 0x8B602368), U64(0x385BB19C, 0xB14BDFC4), /* ~= 10^322 */
3494             U64(0xFCF62C1D, 0xEE382C42), U64(0x46729E03, 0xDD9ED7B5), /* ~= 10^323 */
3495             U64(0x9E19DB92, 0xB4E31BA9), U64(0x6C07A2C2, 0x6A8346D1) /* ~= 10^324 */
3496             };
3497              
3498             /**
3499             Get the cached pow10 value from pow10_sig_table.
3500             @param exp10 The exponent of pow(10, e). This value must in range
3501             POW10_SIG_TABLE_MIN_EXP to POW10_SIG_TABLE_MAX_EXP.
3502             @param hi The highest 64 bits of pow(10, e).
3503             @param lo The lower 64 bits after `hi`.
3504             */
3505             static_inline void pow10_table_get_sig(i32 exp10, u64 *hi, u64 *lo) {
3506 1022           i32 idx = exp10 - (POW10_SIG_TABLE_MIN_EXP);
3507 1022           *hi = pow10_sig_table[idx * 2];
3508 1022           *lo = pow10_sig_table[idx * 2 + 1];
3509 1022           }
3510              
3511             /**
3512             Get the exponent (base 2) for highest 64 bits significand in pow10_sig_table.
3513             */
3514             static_inline void pow10_table_get_exp(i32 exp10, i32 *exp2) {
3515             /* e2 = floor(log2(pow(10, e))) - 64 + 1 */
3516             /* = floor(e * log2(10) - 63) */
3517 6           *exp2 = (exp10 * 217706 - 4128768) >> 16;
3518 4           }
3519              
3520             #endif
3521              
3522              
3523              
3524             /*==============================================================================
3525             * JSON Character Matcher
3526             *============================================================================*/
3527              
3528             /** Character type */
3529             typedef u8 char_type;
3530              
3531             /** Whitespace character: ' ', '\\t', '\\n', '\\r'. */
3532             static const char_type CHAR_TYPE_SPACE = 1 << 0;
3533              
3534             /** Number character: '-', [0-9]. */
3535             static const char_type CHAR_TYPE_NUMBER = 1 << 1;
3536              
3537             /** JSON Escaped character: '"', '\', [0x00-0x1F]. */
3538             static const char_type CHAR_TYPE_ESC_ASCII = 1 << 2;
3539              
3540             /** Non-ASCII character: [0x80-0xFF]. */
3541             static const char_type CHAR_TYPE_NON_ASCII = 1 << 3;
3542              
3543             /** JSON container character: '{', '['. */
3544             static const char_type CHAR_TYPE_CONTAINER = 1 << 4;
3545              
3546             /** Comment character: '/'. */
3547             static const char_type CHAR_TYPE_COMMENT = 1 << 5;
3548              
3549             /** Line end character: '\\n', '\\r', '\0'. */
3550             static const char_type CHAR_TYPE_LINE_END = 1 << 6;
3551              
3552             /** Hexadecimal numeric character: [0-9a-fA-F]. */
3553             static const char_type CHAR_TYPE_HEX = 1 << 7;
3554              
3555             /** Character type table (generate with misc/make_tables.c) */
3556             static const char_type char_table[256] = {
3557             0x44, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
3558             0x04, 0x05, 0x45, 0x04, 0x04, 0x45, 0x04, 0x04,
3559             0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
3560             0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
3561             0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
3562             0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x20,
3563             0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
3564             0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3565             0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
3566             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3567             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3568             0x00, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00,
3569             0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
3570             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3571             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3572             0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
3573             0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3574             0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3575             0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3576             0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3577             0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3578             0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3579             0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3580             0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3581             0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3582             0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3583             0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3584             0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3585             0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3586             0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3587             0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3588             0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
3589             };
3590              
3591             /** Match a character with specified type. */
3592             static_inline bool char_is_type(u8 c, char_type type) {
3593 529783           return (char_table[c] & type) != 0;
3594             }
3595              
3596             /** Match a whitespace: ' ', '\\t', '\\n', '\\r'. */
3597             static_inline bool char_is_space(u8 c) {
3598 6813           return char_is_type(c, (char_type)CHAR_TYPE_SPACE);
3599             }
3600              
3601             /** Match a whitespace or comment: ' ', '\\t', '\\n', '\\r', '/'. */
3602             static_inline bool char_is_space_or_comment(u8 c) {
3603 6274           return char_is_type(c, (char_type)(CHAR_TYPE_SPACE | CHAR_TYPE_COMMENT));
3604             }
3605              
3606             /** Match a JSON number: '-', [0-9]. */
3607             static_inline bool char_is_number(u8 c) {
3608 32343           return char_is_type(c, (char_type)CHAR_TYPE_NUMBER);
3609             }
3610              
3611             /** Match a JSON container: '{', '['. */
3612             static_inline bool char_is_container(u8 c) {
3613 6274           return char_is_type(c, (char_type)CHAR_TYPE_CONTAINER);
3614             }
3615              
3616             /** Match a stop character in ASCII string: '"', '\', [0x00-0x1F,0x80-0xFF]. */
3617             static_inline bool char_is_ascii_stop(u8 c) {
3618 478064           return char_is_type(c, (char_type)(CHAR_TYPE_ESC_ASCII |
3619             CHAR_TYPE_NON_ASCII));
3620             }
3621              
3622             /** Match a line end character: '\\n', '\\r', '\0'. */
3623             static_inline bool char_is_line_end(u8 c) {
3624 15           return char_is_type(c, (char_type)CHAR_TYPE_LINE_END);
3625             }
3626              
3627             /** Match a hexadecimal numeric character: [0-9a-fA-F]. */
3628             static_inline bool char_is_hex(u8 c) {
3629 0           return char_is_type(c, (char_type)CHAR_TYPE_HEX);
3630             }
3631              
3632              
3633              
3634             /*==============================================================================
3635             * Digit Character Matcher
3636             *============================================================================*/
3637              
3638             /** Digit type */
3639             typedef u8 digi_type;
3640              
3641             /** Digit: '0'. */
3642             static const digi_type DIGI_TYPE_ZERO = 1 << 0;
3643              
3644             /** Digit: [1-9]. */
3645             static const digi_type DIGI_TYPE_NONZERO = 1 << 1;
3646              
3647             /** Plus sign (positive): '+'. */
3648             static const digi_type DIGI_TYPE_POS = 1 << 2;
3649              
3650             /** Minus sign (negative): '-'. */
3651             static const digi_type DIGI_TYPE_NEG = 1 << 3;
3652              
3653             /** Decimal point: '.' */
3654             static const digi_type DIGI_TYPE_DOT = 1 << 4;
3655              
3656             /** Exponent sign: 'e, 'E'. */
3657             static const digi_type DIGI_TYPE_EXP = 1 << 5;
3658              
3659             /** Digit type table (generate with misc/make_tables.c) */
3660             static const digi_type digi_table[256] = {
3661             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3662             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3663             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3664             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3665             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3666             0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x10, 0x00,
3667             0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
3668             0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3669             0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
3670             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3671             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3672             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3673             0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
3674             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3675             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3676             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
3677             };
3678              
3679             /** Match a character with specified type. */
3680             static_inline bool digi_is_type(u8 d, digi_type type) {
3681 33770           return (digi_table[d] & type) != 0;
3682             }
3683              
3684             /** Match a sign: '+', '-' */
3685             static_inline bool digi_is_sign(u8 d) {
3686 6           return digi_is_type(d, (digi_type)(DIGI_TYPE_POS | DIGI_TYPE_NEG));
3687             }
3688              
3689             /** Match a none zero digit: [1-9] */
3690             static_inline bool digi_is_nonzero(u8 d) {
3691 13847           return digi_is_type(d, (digi_type)DIGI_TYPE_NONZERO);
3692             }
3693              
3694             /** Match a digit: [0-9] */
3695             static_inline bool digi_is_digit(u8 d) {
3696 45           return digi_is_type(d, (digi_type)(DIGI_TYPE_ZERO | DIGI_TYPE_NONZERO));
3697             }
3698              
3699             /** Match an exponent sign: 'e', 'E'. */
3700             static_inline bool digi_is_exp(u8 d) {
3701 6025           return digi_is_type(d, (digi_type)DIGI_TYPE_EXP);
3702             }
3703              
3704             /** Match a floating point indicator: '.', 'e', 'E'. */
3705             static_inline bool digi_is_fp(u8 d) {
3706 13805           return digi_is_type(d, (digi_type)(DIGI_TYPE_DOT | DIGI_TYPE_EXP));
3707             }
3708              
3709             /** Match a digit or floating point indicator: [0-9], '.', 'e', 'E'. */
3710             static_inline bool digi_is_digit_or_fp(u8 d) {
3711 42           return digi_is_type(d, (digi_type)(DIGI_TYPE_ZERO | DIGI_TYPE_NONZERO |
3712             DIGI_TYPE_DOT | DIGI_TYPE_EXP));
3713             }
3714              
3715              
3716              
3717             #if !YYJSON_DISABLE_READER
3718              
3719             /*==============================================================================
3720             * Hex Character Reader
3721             * This function is used by JSON reader to read escaped characters.
3722             *============================================================================*/
3723              
3724             /**
3725             This table is used to convert 4 hex character sequence to a number.
3726             A valid hex character [0-9A-Fa-f] will mapped to it's raw number [0x00, 0x0F],
3727             an invalid hex character will mapped to [0xF0].
3728             (generate with misc/make_tables.c)
3729             */
3730             static const u8 hex_conv_table[256] = {
3731             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3732             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3733             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3734             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3735             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3736             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3737             0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
3738             0x08, 0x09, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3739             0xF0, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF0,
3740             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3741             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3742             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3743             0xF0, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF0,
3744             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3745             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3746             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3747             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3748             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3749             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3750             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3751             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3752             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3753             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3754             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3755             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3756             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3757             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3758             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3759             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3760             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3761             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3762             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0
3763             };
3764              
3765             /**
3766             Scans an escaped character sequence as a UTF-16 code unit (branchless).
3767             e.g. "\\u005C" should pass "005C" as `cur`.
3768            
3769             This requires the string has 4-byte zero padding.
3770             */
3771             static_inline bool read_hex_u16(const u8 *cur, u16 *val) {
3772             u16 c0, c1, c2, c3, t0, t1;
3773 11           c0 = hex_conv_table[cur[0]];
3774 11           c1 = hex_conv_table[cur[1]];
3775 11           c2 = hex_conv_table[cur[2]];
3776 11           c3 = hex_conv_table[cur[3]];
3777 11           t0 = (u16)((c0 << 8) | c2);
3778 11           t1 = (u16)((c1 << 8) | c3);
3779 11           *val = (u16)((t0 << 4) | t1);
3780 11           return ((t0 | t1) & (u16)0xF0F0) == 0;
3781             }
3782              
3783              
3784              
3785             /*==============================================================================
3786             * JSON Reader Utils
3787             * These functions are used by JSON reader to read literals and comments.
3788             *============================================================================*/
3789              
3790             /** Read 'true' literal, '*cur' should be 't'. */
3791             static_inline bool read_true(u8 **ptr, yyjson_val *val) {
3792 13           u8 *cur = *ptr;
3793 2           u8 **end = ptr;
3794 13 0         if (likely(byte_match_4(cur, "true"))) {
    50          
    50          
    50          
    50          
3795 13           val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_TRUE;
3796 13           *end = cur + 4;
3797 13           return true;
3798             }
3799 0           return false;
3800             }
3801              
3802             /** Read 'false' literal, '*cur' should be 'f'. */
3803             static_inline bool read_false(u8 **ptr, yyjson_val *val) {
3804 10           u8 *cur = *ptr;
3805 10           u8 **end = ptr;
3806 12 0         if (likely(byte_match_4(cur + 1, "alse"))) {
    50          
    50          
    50          
    50          
3807 10           val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_FALSE;
3808 10           *end = cur + 5;
3809 10           return true;
3810             }
3811 0           return false;
3812             }
3813              
3814             /** Read 'null' literal, '*cur' should be 'n'. */
3815             static_inline bool read_null(u8 **ptr, yyjson_val *val) {
3816 21           u8 *cur = *ptr;
3817 3           u8 **end = ptr;
3818 21 0         if (likely(byte_match_4(cur, "null"))) {
    50          
    50          
    50          
    100          
3819 20           val->tag = YYJSON_TYPE_NULL;
3820 20           *end = cur + 4;
3821 20           return true;
3822             }
3823 1           return false;
3824             }
3825              
3826             /** Read 'Inf' or 'Infinity' literal (ignoring case). */
3827             static_inline bool read_inf(bool sign, u8 **ptr, u8 **pre, yyjson_val *val) {
3828 3           u8 *hdr = *ptr - sign;
3829 3           u8 *cur = *ptr;
3830 3           u8 **end = ptr;
3831 1 0         if ((cur[0] == 'I' || cur[0] == 'i') &&
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
3832 2 0         (cur[1] == 'N' || cur[1] == 'n') &&
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3833 2 0         (cur[2] == 'F' || cur[2] == 'f')) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3834 2 0         if ((cur[3] == 'I' || cur[3] == 'i') &&
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3835 2 0         (cur[4] == 'N' || cur[4] == 'n') &&
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3836 2 0         (cur[5] == 'I' || cur[5] == 'i') &&
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3837 2 0         (cur[6] == 'T' || cur[6] == 't') &&
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3838 2 0         (cur[7] == 'Y' || cur[7] == 'y')) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3839 2           cur += 8;
3840             } else {
3841 0           cur += 3;
3842             }
3843 2           *end = cur;
3844 2 0         if (pre) {
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
3845             /* add null-terminator for previous raw string */
3846 0 0         if (*pre) **pre = '\0';
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3847 0           *pre = cur;
3848 0           val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
3849 0           val->uni.str = (const char *)hdr;
3850             } else {
3851 2           val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
3852 4           val->uni.u64 = f64_raw_get_inf(sign);
3853             }
3854 2           return true;
3855             }
3856 1           return false;
3857             }
3858              
3859             /** Read 'NaN' literal (ignoring case). */
3860             static_inline bool read_nan(bool sign, u8 **ptr, u8 **pre, yyjson_val *val) {
3861 1           u8 *hdr = *ptr - sign;
3862 1           u8 *cur = *ptr;
3863 1           u8 **end = ptr;
3864 0 0         if ((cur[0] == 'N' || cur[0] == 'n') &&
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3865 1 0         (cur[1] == 'A' || cur[1] == 'a') &&
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3866 1 0         (cur[2] == 'N' || cur[2] == 'n')) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3867 1           cur += 3;
3868 1           *end = cur;
3869 1 0         if (pre) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3870             /* add null-terminator for previous raw string */
3871 0 0         if (*pre) **pre = '\0';
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3872 0           *pre = cur;
3873 0           val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
3874 0           val->uni.str = (const char *)hdr;
3875             } else {
3876 1           val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
3877 2           val->uni.u64 = f64_raw_get_nan(sign);
3878             }
3879 1           return true;
3880             }
3881 0           return false;
3882             }
3883              
3884             /** Read 'Inf', 'Infinity' or 'NaN' literal (ignoring case). */
3885             static_inline bool read_inf_or_nan(bool sign, u8 **ptr, u8 **pre,
3886             yyjson_val *val) {
3887 3 0         if (read_inf(sign, ptr, pre, val)) return true;
    0          
    0          
    0          
    0          
    50          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
3888 2 0         if (read_nan(sign, ptr, pre, val)) return true;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3889 0           return false;
3890             }
3891              
3892             /** Read a JSON number as raw string. */
3893 0           static_noinline bool read_number_raw(u8 **ptr,
3894             u8 **pre,
3895             yyjson_read_flag flg,
3896             yyjson_val *val,
3897             const char **msg) {
3898            
3899             #define return_err(_pos, _msg) do { \
3900             *msg = _msg; \
3901             *end = _pos; \
3902             return false; \
3903             } while (false)
3904            
3905             #define return_raw() do { \
3906             val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
3907             val->uni.str = (const char *)hdr; \
3908             *pre = cur; *end = cur; return true; \
3909             } while (false)
3910            
3911 0           u8 *hdr = *ptr;
3912 0           u8 *cur = *ptr;
3913 0           u8 **end = ptr;
3914            
3915             /* add null-terminator for previous raw string */
3916 0 0         if (*pre) **pre = '\0';
3917            
3918             /* skip sign */
3919 0           cur += (*cur == '-');
3920            
3921             /* read first digit, check leading zero */
3922 0 0         if (unlikely(!digi_is_digit(*cur))) {
3923 0 0         if (has_read_flag(ALLOW_INF_AND_NAN)) {
3924 0 0         if (read_inf_or_nan(*hdr == '-', &cur, pre, val)) return_raw();
    0          
3925             }
3926 0           return_err(cur, "no digit after minus sign");
3927             }
3928            
3929             /* read integral part */
3930 0 0         if (*cur == '0') {
3931 0           cur++;
3932 0 0         if (unlikely(digi_is_digit(*cur))) {
3933 0           return_err(cur - 1, "number with leading zero is not allowed");
3934             }
3935 0 0         if (!digi_is_fp(*cur)) return_raw();
3936             } else {
3937 0 0         while (digi_is_digit(*cur)) cur++;
3938 0 0         if (!digi_is_fp(*cur)) return_raw();
3939             }
3940            
3941             /* read fraction part */
3942 0 0         if (*cur == '.') {
3943 0           cur++;
3944 0 0         if (!digi_is_digit(*cur++)) {
3945 0           return_err(cur, "no digit after decimal point");
3946             }
3947 0 0         while (digi_is_digit(*cur)) cur++;
3948             }
3949            
3950             /* read exponent part */
3951 0 0         if (digi_is_exp(*cur)) {
3952 0           cur += 1 + digi_is_sign(cur[1]);
3953 0 0         if (!digi_is_digit(*cur++)) {
3954 0           return_err(cur, "no digit after exponent sign");
3955             }
3956 0 0         while (digi_is_digit(*cur)) cur++;
3957             }
3958            
3959 0           return_raw();
3960            
3961             #undef return_err
3962             #undef return_raw
3963             }
3964              
3965             /**
3966             Skips spaces and comments as many as possible.
3967            
3968             It will return false in these cases:
3969             1. No character is skipped. The 'end' pointer is set as input cursor.
3970             2. A multiline comment is not closed. The 'end' pointer is set as the head
3971             of this comment block.
3972             */
3973 3           static_noinline bool skip_spaces_and_comments(u8 **ptr) {
3974 3           u8 *hdr = *ptr;
3975 3           u8 *cur = *ptr;
3976 3           u8 **end = ptr;
3977             while (true) {
3978 9 100         if (byte_match_2(cur, "/*")) {
3979 1           hdr = cur;
3980 1           cur += 2;
3981             while (true) {
3982 8 100         if (byte_match_2(cur, "*/")) {
3983 1           cur += 2;
3984 1           break;
3985             }
3986 7 50         if (*cur == 0) {
3987 0           *end = hdr;
3988 0           return false;
3989             }
3990 7           cur++;
3991             }
3992 1           continue;
3993             }
3994 8 100         if (byte_match_2(cur, "//")) {
3995 2           cur += 2;
3996 17 100         while (!char_is_line_end(*cur)) cur++;
3997 2           continue;
3998             }
3999 12 100         if (char_is_space(*cur)) {
4000 3           cur += 1;
4001 8 100         while (char_is_space(*cur)) cur++;
4002 3           continue;
4003             }
4004 3           break;
4005             }
4006 3           *end = cur;
4007 3           return hdr != cur;
4008             }
4009              
4010             /**
4011             Check truncated string.
4012             Returns true if `cur` match `str` but is truncated.
4013             */
4014             static_inline bool is_truncated_str(u8 *cur, u8 *end,
4015             const char *str,
4016             bool case_sensitive) {
4017 3           usize len = strlen(str);
4018 3 50         if (cur + len <= end || end <= cur) return false;
    0          
    50          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
4019 0 0         if (case_sensitive) {
    0          
    0          
    0          
    0          
    0          
4020 0           return memcmp(cur, str, (usize)(end - cur)) == 0;
4021             }
4022 0 0         for (; cur < end; cur++, str++) {
    0          
    0          
    0          
    0          
    0          
4023 0 0         if ((*cur != (u8)*str) && (*cur != (u8)*str - 'a' + 'A')) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4024 0           return false;
4025             }
4026             }
4027 0           return true;
4028             }
4029              
4030             /**
4031             Check truncated JSON on parsing errors.
4032             Returns true if the input is valid but truncated.
4033             */
4034 6           static_noinline bool is_truncated_end(u8 *hdr, u8 *cur, u8 *end,
4035             yyjson_read_code code,
4036             yyjson_read_flag flg) {
4037 6 100         if (cur >= end) return true;
4038 5 100         if (code == YYJSON_READ_ERROR_LITERAL) {
4039 1 50         if (is_truncated_str(cur, end, "true", true) ||
4040 1 50         is_truncated_str(cur, end, "false", true) ||
4041 1 50         is_truncated_str(cur, end, "null", true)) {
4042 0           return true;
4043             }
4044             }
4045 5 100         if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER ||
4046 2 50         code == YYJSON_READ_ERROR_INVALID_NUMBER ||
4047 2 100         code == YYJSON_READ_ERROR_LITERAL) {
4048 8 50         if (has_read_flag(ALLOW_INF_AND_NAN)) {
4049 0 0         if (*cur == '-') cur++;
4050 0 0         if (is_truncated_str(cur, end, "infinity", false) ||
4051 0 0         is_truncated_str(cur, end, "nan", false)) {
4052 0           return true;
4053             }
4054             }
4055             }
4056 5 50         if (code == YYJSON_READ_ERROR_UNEXPECTED_CONTENT) {
4057 0 0         if (has_read_flag(ALLOW_INF_AND_NAN)) {
4058 0 0         if (hdr + 3 <= cur &&
4059 0 0         is_truncated_str(cur - 3, end, "infinity", false)) {
    0          
4060 0           return true; /* e.g. infin would be read as inf + in */
4061             }
4062             }
4063             }
4064 5 50         if (code == YYJSON_READ_ERROR_INVALID_STRING) {
4065 0           usize len = (usize)(end - cur);
4066            
4067             /* unicode escape sequence */
4068 0 0         if (*cur == '\\') {
4069 0 0         if (len == 1) return true;
4070 0 0         if (len <= 5) {
4071 0 0         if (*++cur != 'u') return false;
4072 0 0         for (++cur; cur < end; cur++) {
4073 0 0         if (!char_is_hex(*cur)) return false;
4074             }
4075 0           return true;
4076             }
4077 0           return false;
4078             }
4079            
4080             /* 2 to 4 bytes UTF-8, see `read_string()` for details. */
4081 0 0         if (*cur & 0x80) {
4082 0           u8 c0 = cur[0], c1 = cur[1], c2 = cur[2];
4083 0 0         if (len == 1) {
4084             /* 2 bytes UTF-8, truncated */
4085 0 0         if ((c0 & 0xE0) == 0xC0 && (c0 & 0x1E) != 0x00) return true;
    0          
4086             /* 3 bytes UTF-8, truncated */
4087 0 0         if ((c0 & 0xF0) == 0xE0) return true;
4088             /* 4 bytes UTF-8, truncated */
4089 0 0         if ((c0 & 0xF8) == 0xF0 && (c0 & 0x07) <= 0x04) return true;
    0          
4090             }
4091 0 0         if (len == 2) {
4092             /* 3 bytes UTF-8, truncated */
4093 0 0         if ((c0 & 0xF0) == 0xE0 &&
4094 0 0         (c1 & 0xC0) == 0x80) {
4095 0           u8 pat = (u8)(((c0 & 0x0F) << 1) | ((c1 & 0x20) >> 5));
4096 0 0         return 0x01 <= pat && pat != 0x1B;
    0          
4097             }
4098             /* 4 bytes UTF-8, truncated */
4099 0 0         if ((c0 & 0xF8) == 0xF0 &&
4100 0 0         (c1 & 0xC0) == 0x80) {
4101 0           u8 pat = (u8)(((c0 & 0x07) << 2) | ((c1 & 0x30) >> 4));
4102 0 0         return 0x01 <= pat && pat <= 0x10;
    0          
4103             }
4104             }
4105 0 0         if (len == 3) {
4106             /* 4 bytes UTF-8, truncated */
4107 0 0         if ((c0 & 0xF8) == 0xF0 &&
4108 0 0         (c1 & 0xC0) == 0x80 &&
4109 0 0         (c2 & 0xC0) == 0x80) {
4110 0           u8 pat = (u8)(((c0 & 0x07) << 2) | ((c1 & 0x30) >> 4));
4111 0 0         return 0x01 <= pat && pat <= 0x10;
    0          
4112             }
4113             }
4114             }
4115             }
4116 5           return false;
4117             }
4118              
4119              
4120              
4121             #if YYJSON_HAS_IEEE_754 && !YYJSON_DISABLE_FAST_FP_CONV /* FP_READER */
4122              
4123             /*==============================================================================
4124             * BigInt For Floating Point Number Reader
4125             *
4126             * The bigint algorithm is used by floating-point number reader to get correctly
4127             * rounded result for numbers with lots of digits. This part of code is rarely
4128             * used for common numbers.
4129             *============================================================================*/
4130              
4131             /** Maximum exponent of exact pow10 */
4132             #define U64_POW10_MAX_EXP 19
4133              
4134             /** Table: [ 10^0, ..., 10^19 ] (generate with misc/make_tables.c) */
4135             static const u64 u64_pow10_table[U64_POW10_MAX_EXP + 1] = {
4136             U64(0x00000000, 0x00000001), U64(0x00000000, 0x0000000A),
4137             U64(0x00000000, 0x00000064), U64(0x00000000, 0x000003E8),
4138             U64(0x00000000, 0x00002710), U64(0x00000000, 0x000186A0),
4139             U64(0x00000000, 0x000F4240), U64(0x00000000, 0x00989680),
4140             U64(0x00000000, 0x05F5E100), U64(0x00000000, 0x3B9ACA00),
4141             U64(0x00000002, 0x540BE400), U64(0x00000017, 0x4876E800),
4142             U64(0x000000E8, 0xD4A51000), U64(0x00000918, 0x4E72A000),
4143             U64(0x00005AF3, 0x107A4000), U64(0x00038D7E, 0xA4C68000),
4144             U64(0x002386F2, 0x6FC10000), U64(0x01634578, 0x5D8A0000),
4145             U64(0x0DE0B6B3, 0xA7640000), U64(0x8AC72304, 0x89E80000)
4146             };
4147              
4148             /** Maximum numbers of chunks used by a bigint (58 is enough here). */
4149             #define BIGINT_MAX_CHUNKS 64
4150              
4151             /** Unsigned arbitrarily large integer */
4152             typedef struct bigint {
4153             u32 used; /* used chunks count, should not be 0 */
4154             u64 bits[BIGINT_MAX_CHUNKS]; /* chunks */
4155             } bigint;
4156              
4157             /**
4158             Evaluate 'big += val'.
4159             @param big A big number (can be 0).
4160             @param val An unsigned integer (can be 0).
4161             */
4162             static_inline void bigint_add_u64(bigint *big, u64 val) {
4163             u32 idx, max;
4164 0           u64 num = big->bits[0];
4165 0           u64 add = num + val;
4166 0           big->bits[0] = add;
4167 0 0         if (likely((add >= num) || (add >= val))) return;
    0          
4168 0 0         for ((void)(idx = 1), max = big->used; idx < max; idx++) {
4169 0 0         if (likely(big->bits[idx] != U64_MAX)) {
4170 0           big->bits[idx] += 1;
4171 0           return;
4172             }
4173 0           big->bits[idx] = 0;
4174             }
4175 0           big->bits[big->used++] = 1;
4176             }
4177              
4178             /**
4179             Evaluate 'big *= val'.
4180             @param big A big number (can be 0).
4181             @param val An unsigned integer (cannot be 0).
4182             */
4183             static_inline void bigint_mul_u64(bigint *big, u64 val) {
4184 0           u32 idx = 0, max = big->used;
4185 0           u64 hi, lo, carry = 0;
4186 0 0         for (; idx < max; idx++) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4187 0 0         if (big->bits[idx]) break;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4188             }
4189 0 0         for (; idx < max; idx++) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4190 0           u128_mul_add(big->bits[idx], val, carry, &hi, &lo);
4191 0           big->bits[idx] = lo;
4192 0           carry = hi;
4193             }
4194 0 0         if (carry) big->bits[big->used++] = carry;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4195 0           }
4196              
4197             /**
4198             Evaluate 'big *= 2^exp'.
4199             @param big A big number (can be 0).
4200             @param exp An exponent integer (can be 0).
4201             */
4202             static_inline void bigint_mul_pow2(bigint *big, u32 exp) {
4203 0           u32 shft = exp % 64;
4204 0           u32 move = exp / 64;
4205 0           u32 idx = big->used;
4206 0           if (unlikely(shft == 0)) {
4207 0 0         for (; idx > 0; idx--) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4208 0           big->bits[idx + move - 1] = big->bits[idx - 1];
4209             }
4210 0           big->used += move;
4211 0 0         while (move) big->bits[--move] = 0;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4212             } else {
4213 0           big->bits[idx] = 0;
4214 0 0         for (; idx > 0; idx--) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4215 0           u64 num = big->bits[idx] << shft;
4216 0           num |= big->bits[idx - 1] >> (64 - shft);
4217 0           big->bits[idx + move] = num;
4218             }
4219 0           big->bits[move] = big->bits[0] << shft;
4220 0           big->used += move + (big->bits[big->used + move] > 0);
4221 0 0         while (move) big->bits[--move] = 0;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4222             }
4223 0           }
4224              
4225             /**
4226             Evaluate 'big *= 10^exp'.
4227             @param big A big number (can be 0).
4228             @param exp An exponent integer (cannot be 0).
4229             */
4230             static_inline void bigint_mul_pow10(bigint *big, i32 exp) {
4231 0 0         for (; exp >= U64_POW10_MAX_EXP; exp -= U64_POW10_MAX_EXP) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4232 0           bigint_mul_u64(big, u64_pow10_table[U64_POW10_MAX_EXP]);
4233             }
4234 0 0         if (exp) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4235 0           bigint_mul_u64(big, u64_pow10_table[exp]);
4236             }
4237 0           }
4238              
4239             /**
4240             Compare two bigint.
4241             @return -1 if 'a < b', +1 if 'a > b', 0 if 'a == b'.
4242             */
4243             static_inline i32 bigint_cmp(bigint *a, bigint *b) {
4244 0           u32 idx = a->used;
4245 0 0         if (a->used < b->used) return -1;
    0          
    0          
    0          
    0          
    0          
4246 0 0         if (a->used > b->used) return +1;
    0          
    0          
    0          
    0          
    0          
4247 0 0         while (idx-- > 0) {
    0          
    0          
    0          
    0          
    0          
4248 0           u64 av = a->bits[idx];
4249 0           u64 bv = b->bits[idx];
4250 0 0         if (av < bv) return -1;
    0          
    0          
    0          
    0          
    0          
4251 0 0         if (av > bv) return +1;
    0          
    0          
    0          
    0          
    0          
4252             }
4253 0           return 0;
4254             }
4255              
4256             /**
4257             Evaluate 'big = val'.
4258             @param big A big number (can be 0).
4259             @param val An unsigned integer (can be 0).
4260             */
4261             static_inline void bigint_set_u64(bigint *big, u64 val) {
4262 0           big->used = 1;
4263 0           big->bits[0] = val;
4264 0           }
4265              
4266             /** Set a bigint with floating point number string. */
4267 0           static_noinline void bigint_set_buf(bigint *big, u64 sig, i32 *exp,
4268             u8 *sig_cut, u8 *sig_end, u8 *dot_pos) {
4269            
4270 0 0         if (unlikely(!sig_cut)) {
4271             /* no digit cut, set significant part only */
4272             bigint_set_u64(big, sig);
4273 0           return;
4274            
4275             } else {
4276             /* some digits were cut, read them from 'sig_cut' to 'sig_end' */
4277 0           u8 *hdr = sig_cut;
4278 0           u8 *cur = hdr;
4279 0           u32 len = 0;
4280 0           u64 val = 0;
4281 0           bool dig_big_cut = false;
4282 0           bool has_dot = (hdr < dot_pos) & (dot_pos < sig_end);
4283 0           u32 dig_len_total = U64_SAFE_DIG + (u32)(sig_end - hdr) - has_dot;
4284            
4285 0           sig -= (*sig_cut >= '5'); /* sig was rounded before */
4286 0 0         if (dig_len_total > F64_MAX_DEC_DIG) {
4287 0           dig_big_cut = true;
4288 0           sig_end -= dig_len_total - (F64_MAX_DEC_DIG + 1);
4289 0           sig_end -= (dot_pos + 1 == sig_end);
4290 0           dig_len_total = (F64_MAX_DEC_DIG + 1);
4291             }
4292 0           *exp -= (i32)dig_len_total - U64_SAFE_DIG;
4293            
4294 0           big->used = 1;
4295 0           big->bits[0] = sig;
4296 0 0         while (cur < sig_end) {
4297 0 0         if (likely(cur != dot_pos)) {
4298 0           val = val * 10 + (u8)(*cur++ - '0');
4299 0           len++;
4300 0 0         if (unlikely(cur == sig_end && dig_big_cut)) {
    0          
4301             /* The last digit must be non-zero, */
4302             /* set it to '1' for correct rounding. */
4303 0           val = val - (val % 10) + 1;
4304             }
4305 0 0         if (len == U64_SAFE_DIG || cur == sig_end) {
    0          
4306 0           bigint_mul_pow10(big, (i32)len);
4307             bigint_add_u64(big, val);
4308 0           val = 0;
4309 0           len = 0;
4310             }
4311             } else {
4312 0           cur++;
4313             }
4314             }
4315             }
4316             }
4317              
4318              
4319              
4320             /*==============================================================================
4321             * Diy Floating Point
4322             *============================================================================*/
4323              
4324             /** "Do It Yourself Floating Point" struct. */
4325             typedef struct diy_fp {
4326             u64 sig; /* significand */
4327             i32 exp; /* exponent, base 2 */
4328             i32 pad; /* padding, useless */
4329             } diy_fp;
4330              
4331             /** Get cached rounded diy_fp with pow(10, e) The input value must in range
4332             [POW10_SIG_TABLE_MIN_EXP, POW10_SIG_TABLE_MAX_EXP]. */
4333             static_inline diy_fp diy_fp_get_cached_pow10(i32 exp10) {
4334             diy_fp fp;
4335             u64 sig_ext;
4336             pow10_table_get_sig(exp10, &fp.sig, &sig_ext);
4337             pow10_table_get_exp(exp10, &fp.exp);
4338 4           fp.sig += (sig_ext >> 63);
4339 4           return fp;
4340             }
4341              
4342             /** Returns fp * fp2. */
4343             static_inline diy_fp diy_fp_mul(diy_fp fp, diy_fp fp2) {
4344             u64 hi, lo;
4345 4           u128_mul(fp.sig, fp2.sig, &hi, &lo);
4346 4           fp.sig = hi + (lo >> 63);
4347 4           fp.exp += fp2.exp + 64;
4348 4           return fp;
4349             }
4350              
4351             /** Convert diy_fp to IEEE-754 raw value. */
4352             static_inline u64 diy_fp_to_ieee_raw(diy_fp fp) {
4353 4           u64 sig = fp.sig;
4354 4           i32 exp = fp.exp;
4355             u32 lz_bits;
4356 0           if (unlikely(fp.sig == 0)) return 0;
4357            
4358 4           lz_bits = u64_lz_bits(sig);
4359 4           sig <<= lz_bits;
4360 4           sig >>= F64_BITS - F64_SIG_FULL_BITS;
4361 4           exp -= (i32)lz_bits;
4362 4           exp += F64_BITS - F64_SIG_FULL_BITS;
4363 4           exp += F64_SIG_BITS;
4364            
4365 4 0         if (unlikely(exp >= F64_MAX_BIN_EXP)) {
    0          
    0          
    50          
    0          
    0          
4366             /* overflow */
4367 0           return F64_RAW_INF;
4368 4 0         } else if (likely(exp >= F64_MIN_BIN_EXP - 1)) {
    0          
    0          
    50          
    0          
    0          
4369             /* normal */
4370 4           exp += F64_EXP_BIAS;
4371 4           return ((u64)exp << F64_SIG_BITS) | (sig & F64_SIG_MASK);
4372 0 0         } else if (likely(exp >= F64_MIN_BIN_EXP - F64_SIG_FULL_BITS)) {
    0          
    0          
    0          
    0          
    0          
4373             /* subnormal */
4374 0           return sig >> (F64_MIN_BIN_EXP - exp - 1);
4375             } else {
4376             /* underflow */
4377 0           return 0;
4378             }
4379             }
4380              
4381              
4382              
4383             /*==============================================================================
4384             * JSON Number Reader (IEEE-754)
4385             *============================================================================*/
4386              
4387             /** Maximum exact pow10 exponent for double value. */
4388             #define F64_POW10_EXP_MAX_EXACT 22
4389              
4390             /** Cached pow10 table. */
4391             static const f64 f64_pow10_table[] = {
4392             1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12,
4393             1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22
4394             };
4395              
4396             /**
4397             Read a JSON number.
4398            
4399             1. This function assume that the floating-point number is in IEEE-754 format.
4400             2. This function support uint64/int64/double number. If an integer number
4401             cannot fit in uint64/int64, it will returns as a double number. If a double
4402             number is infinite, the return value is based on flag.
4403             3. This function (with inline attribute) may generate a lot of instructions.
4404             */
4405             static_inline bool read_number(u8 **ptr,
4406             u8 **pre,
4407             yyjson_read_flag flg,
4408             yyjson_val *val,
4409             const char **msg) {
4410            
4411             #define return_err(_pos, _msg) do { \
4412             *msg = _msg; \
4413             *end = _pos; \
4414             return false; \
4415             } while (false)
4416            
4417             #define return_0() do { \
4418             val->tag = YYJSON_TYPE_NUM | (u8)((u8)sign << 3); \
4419             val->uni.u64 = 0; \
4420             *end = cur; return true; \
4421             } while (false)
4422              
4423             #define return_i64(_v) do { \
4424             val->tag = YYJSON_TYPE_NUM | (u8)((u8)sign << 3); \
4425             val->uni.u64 = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \
4426             *end = cur; return true; \
4427             } while (false)
4428            
4429             #define return_f64(_v) do { \
4430             val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
4431             val->uni.f64 = sign ? -(f64)(_v) : (f64)(_v); \
4432             *end = cur; return true; \
4433             } while (false)
4434            
4435             #define return_f64_bin(_v) do { \
4436             val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
4437             val->uni.u64 = ((u64)sign << 63) | (u64)(_v); \
4438             *end = cur; return true; \
4439             } while (false)
4440            
4441             #define return_inf() do { \
4442             if (has_read_flag(BIGNUM_AS_RAW)) return_raw(); \
4443             if (has_read_flag(ALLOW_INF_AND_NAN)) return_f64_bin(F64_RAW_INF); \
4444             else return_err(hdr, "number is infinity when parsed as double"); \
4445             } while (false)
4446            
4447             #define return_raw() do { \
4448             if (*pre) **pre = '\0'; /* add null-terminator for previous raw string */ \
4449             val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
4450             val->uni.str = (const char *)hdr; \
4451             *pre = cur; *end = cur; return true; \
4452             } while (false)
4453            
4454 13847           u8 *sig_cut = NULL; /* significant part cutting position for long number */
4455 13847           u8 *sig_end = NULL; /* significant part ending position */
4456 13847           u8 *dot_pos = NULL; /* decimal point position */
4457            
4458 13847           u64 sig = 0; /* significant part of the number */
4459 13847           i32 exp = 0; /* exponent part of the number */
4460            
4461             bool exp_sign; /* temporary exponent sign from literal part */
4462 13847           i64 exp_sig = 0; /* temporary exponent number from significant part */
4463 13847           i64 exp_lit = 0; /* temporary exponent number from exponent literal part */
4464             u64 num; /* temporary number for reading */
4465             u8 *tmp; /* temporary cursor for reading */
4466            
4467 13847           u8 *hdr = *ptr;
4468 13847           u8 *cur = *ptr;
4469 13847           u8 **end = ptr;
4470             bool sign;
4471            
4472             /* read number as raw string if has `YYJSON_READ_NUMBER_AS_RAW` flag */
4473 13855 0         if (has_read_flag(NUMBER_AS_RAW)) {
    50          
    50          
    50          
    50          
    50          
4474 0           return read_number_raw(ptr, pre, flg, val, msg);
4475             }
4476            
4477 13847           sign = (*hdr == '-');
4478 13847           cur += sign;
4479            
4480             /* begin with a leading zero or non-digit */
4481 27694 0         if (unlikely(!digi_is_nonzero(*cur))) { /* 0 or non-digit char */
    50          
    100          
    100          
    100          
    100          
4482 38 0         if (unlikely(*cur != '0')) { /* non-digit char */
    0          
    50          
    100          
    50          
    50          
4483 2 0         if (has_read_flag(ALLOW_INF_AND_NAN)) {
    0          
    0          
    50          
    0          
    0          
4484 2 0         if (read_inf_or_nan(sign, &cur, pre, val)) {
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
4485 1           *end = cur;
4486 1           return true;
4487             }
4488             }
4489 0           return_err(cur, "no digit after minus sign");
4490             }
4491             /* begin with 0 */
4492 74 0         if (likely(!digi_is_digit_or_fp(*++cur))) return_0();
    0          
    50          
    100          
    100          
    50          
4493 7 0         if (likely(*cur == '.')) {
    0          
    0          
    50          
    50          
    50          
4494 7           dot_pos = cur++;
4495 14 0         if (unlikely(!digi_is_digit(*cur))) {
    0          
    0          
    50          
    50          
    50          
4496 0           return_err(cur, "no digit after decimal point");
4497             }
4498 7 0         while (unlikely(*cur == '0')) cur++;
    0          
    0          
    50          
    50          
    50          
4499 14 0         if (likely(digi_is_digit(*cur))) {
    0          
    0          
    50          
    50          
    50          
4500             /* first non-zero digit after decimal point */
4501 7           sig = (u64)(*cur - '0'); /* read first digit */
4502 7           cur--;
4503 7           goto digi_frac_1; /* continue read fraction part */
4504             }
4505             }
4506 0 0         if (unlikely(digi_is_digit(*cur))) {
    0          
    0          
    0          
    0          
    0          
4507 0           return_err(cur - 1, "number with leading zero is not allowed");
4508             }
4509 0 0         if (unlikely(digi_is_exp(*cur))) { /* 0 with any exponent is still 0 */
    0          
    0          
    0          
    0          
    0          
4510 0           cur += (usize)1 + digi_is_sign(cur[1]);
4511 0 0         if (unlikely(!digi_is_digit(*cur))) {
    0          
    0          
    0          
    0          
    0          
4512 0           return_err(cur, "no digit after exponent sign");
4513             }
4514 0 0         while (digi_is_digit(*++cur));
    0          
    0          
    0          
    0          
    0          
4515             }
4516 0           return_f64_bin(0);
4517             }
4518            
4519             /* begin with non-zero digit */
4520 13809           sig = (u64)(*cur - '0');
4521            
4522             /*
4523             Read integral part, same as the following code.
4524            
4525             for (int i = 1; i <= 18; i++) {
4526             num = cur[i] - '0';
4527             if (num <= 9) sig = num + sig * 10;
4528             else goto digi_sepr_i;
4529             }
4530             */
4531             #define expr_intg(i) \
4532             if (likely((num = (u64)(cur[i] - (u8)'0')) <= 9)) sig = num + sig * 10; \
4533             else { goto digi_sepr_##i; }
4534 13809 0         repeat_in_1_18(expr_intg)
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4535             #undef expr_intg
4536            
4537            
4538 4           cur += 19; /* skip continuous 19 digits */
4539 8 0         if (!digi_is_digit_or_fp(*cur)) {
    0          
    0          
    100          
    0          
    0          
4540             /* this number is an integer consisting of 19 digits */
4541 3 0         if (sign && (sig > ((u64)1 << 63))) { /* overflow */
    0          
    0          
    0          
    0          
    0          
    100          
    50          
    0          
    0          
    0          
    0          
4542 0 0         if (has_read_flag(BIGNUM_AS_RAW)) return_raw();
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4543 0 0         return_f64(normalized_u64_to_f64(sig));
    0          
    0          
    0          
    0          
    0          
4544             }
4545 3 0         return_i64(sig);
    0          
    0          
    100          
    0          
    0          
4546             }
4547 1           goto digi_intg_more; /* read more digits in integral part */
4548            
4549            
4550             /* process first non-digit character */
4551             #define expr_sepr(i) \
4552             digi_sepr_##i: \
4553             if (likely(!digi_is_fp(cur[i]))) { cur += i; return_i64(sig); } \
4554             dot_pos = cur + i; \
4555             if (likely(cur[i] == '.')) goto digi_frac_##i; \
4556             cur += i; sig_end = cur; goto digi_exp_more;
4557 27610 0         repeat_in_1_18(expr_sepr)
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    50          
    50          
    0          
    50          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    50          
    100          
    50          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    50          
    50          
    100          
    50          
    50          
    100          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4558             #undef expr_sepr
4559            
4560            
4561             /* read fraction part */
4562             #define expr_frac(i) \
4563             digi_frac_##i: \
4564             if (likely((num = (u64)(cur[i + 1] - (u8)'0')) <= 9)) \
4565             sig = num + sig * 10; \
4566             else { goto digi_stop_##i; }
4567 6025 0         repeat_in_1_18(expr_frac)
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    0          
    100          
    100          
    100          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4568             #undef expr_frac
4569            
4570 0           cur += 20; /* skip 19 digits and 1 decimal point */
4571 0 0         if (!digi_is_digit(*cur)) goto digi_frac_end; /* fraction part end */
    0          
    0          
    0          
    0          
    0          
4572 0           goto digi_frac_more; /* read more digits in fraction part */
4573            
4574            
4575             /* significant part end */
4576             #define expr_stop(i) \
4577             digi_stop_##i: \
4578             cur += i + 1; \
4579             goto digi_frac_end;
4580 6025           repeat_in_1_18(expr_stop)
4581             #undef expr_stop
4582            
4583            
4584             /* read more digits in integral part */
4585 1           digi_intg_more:
4586 2 0         if (digi_is_digit(*cur)) {
    0          
    0          
    50          
    0          
    0          
4587 2 0         if (!digi_is_digit_or_fp(cur[1])) {
    0          
    0          
    50          
    0          
    0          
4588             /* this number is an integer consisting of 20 digits */
4589 1           num = (u64)(*cur - '0');
4590 1 0         if ((sig < (U64_MAX / 10)) ||
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
4591 1 0         (sig == (U64_MAX / 10) && num <= (U64_MAX % 10))) {
    0          
    0          
    50          
    0          
    0          
4592 1           sig = num + sig * 10;
4593 1           cur++;
4594             /* convert to double if overflow */
4595 1 0         if (sign) {
    0          
    0          
    50          
    0          
    0          
4596 0 0         if (has_read_flag(BIGNUM_AS_RAW)) return_raw();
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4597 0 0         return_f64(normalized_u64_to_f64(sig));
    0          
    0          
    0          
    0          
    0          
4598             }
4599 1 0         return_i64(sig);
    0          
    0          
    50          
    0          
    0          
4600             }
4601             }
4602             }
4603            
4604 0 0         if (digi_is_exp(*cur)) {
    0          
    0          
    0          
    0          
    0          
4605 0           dot_pos = cur;
4606 0           goto digi_exp_more;
4607             }
4608            
4609 0 0         if (*cur == '.') {
    0          
    0          
    0          
    0          
    0          
4610 0           dot_pos = cur++;
4611 0 0         if (!digi_is_digit(*cur)) {
    0          
    0          
    0          
    0          
    0          
4612 0           return_err(cur, "no digit after decimal point");
4613             }
4614             }
4615            
4616            
4617             /* read more digits in fraction part */
4618 0           digi_frac_more:
4619 0           sig_cut = cur; /* too large to fit in u64, excess digits need to be cut */
4620 0           sig += (*cur >= '5'); /* round */
4621 0 0         while (digi_is_digit(*++cur));
    0          
    0          
    0          
    0          
    0          
4622 0 0         if (!dot_pos) {
    0          
    0          
    0          
    0          
    0          
4623 0 0         if (!digi_is_fp(*cur) && has_read_flag(BIGNUM_AS_RAW)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4624 0 0         return_raw(); /* it's a large integer */
    0          
    0          
    0          
    0          
    0          
4625             }
4626 0           dot_pos = cur;
4627 0 0         if (*cur == '.') {
    0          
    0          
    0          
    0          
    0          
4628 0 0         if (!digi_is_digit(*++cur)) {
    0          
    0          
    0          
    0          
    0          
4629 0           return_err(cur, "no digit after decimal point");
4630             }
4631 0 0         while (digi_is_digit(*cur)) cur++;
    0          
    0          
    0          
    0          
    0          
4632             }
4633             }
4634 0           exp_sig = (i64)(dot_pos - sig_cut);
4635 0           exp_sig += (dot_pos < sig_cut);
4636            
4637             /* ignore trailing zeros */
4638 0           tmp = cur - 1;
4639 0 0         while (*tmp == '0' || *tmp == '.') tmp--;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4640 0 0         if (tmp < sig_cut) {
    0          
    0          
    0          
    0          
    0          
4641 0           sig_cut = NULL;
4642             } else {
4643 0           sig_end = cur;
4644             }
4645            
4646 0 0         if (digi_is_exp(*cur)) goto digi_exp_more;
    0          
    0          
    0          
    0          
    0          
4647 0           goto digi_exp_finish;
4648            
4649            
4650             /* fraction part end */
4651 6025           digi_frac_end:
4652 6025 0         if (unlikely(dot_pos + 1 == cur)) {
    0          
    0          
    50          
    50          
    50          
4653 0           return_err(cur, "no digit after decimal point");
4654             }
4655 6025           sig_end = cur;
4656 6025           exp_sig = -(i64)((u64)(cur - dot_pos) - 1);
4657 12050 0         if (likely(!digi_is_exp(*cur))) {
    0          
    0          
    100          
    50          
    50          
4658 6021 0         if (unlikely(exp_sig < F64_MIN_DEC_EXP - 19)) {
    0          
    0          
    50          
    50          
    50          
4659 0           return_f64_bin(0); /* underflow */
4660             }
4661 6021           exp = (i32)exp_sig;
4662 6021           goto digi_finish;
4663             } else {
4664 4           goto digi_exp_more;
4665             }
4666            
4667            
4668             /* read exponent part */
4669 6           digi_exp_more:
4670 6           exp_sign = (*++cur == '-');
4671 6           cur += digi_is_sign(*cur);
4672 12 0         if (unlikely(!digi_is_digit(*cur))) {
    0          
    0          
    50          
    0          
    0          
4673 0           return_err(cur, "no digit after exponent sign");
4674             }
4675 6 0         while (*cur == '0') cur++;
    0          
    0          
    50          
    0          
    0          
4676            
4677             /* read exponent literal */
4678 6           tmp = cur;
4679 48 0         while (digi_is_digit(*cur)) {
    0          
    0          
    100          
    0          
    0          
4680 18           exp_lit = (i64)((u8)(*cur++ - '0') + (u64)exp_lit * 10);
4681             }
4682 6 0         if (unlikely(cur - tmp >= U64_SAFE_DIG)) {
    0          
    0          
    50          
    0          
    0          
4683 0 0         if (exp_sign) {
    0          
    0          
    0          
    0          
    0          
4684 0           return_f64_bin(0); /* underflow */
4685             } else {
4686 0 0         return_inf(); /* overflow */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4687             }
4688             }
4689 6 0         exp_sig += exp_sign ? -exp_lit : exp_lit;
    0          
    0          
    100          
    0          
    0          
4690            
4691            
4692             /* validate exponent value */
4693 6           digi_exp_finish:
4694 6 0         if (unlikely(exp_sig < F64_MIN_DEC_EXP - 19)) {
    0          
    0          
    50          
    0          
    0          
4695 0           return_f64_bin(0); /* underflow */
4696             }
4697 6 0         if (unlikely(exp_sig > F64_MAX_DEC_EXP)) {
    0          
    0          
    50          
    0          
    0          
4698 0 0         return_inf(); /* overflow */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4699             }
4700 6           exp = (i32)exp_sig;
4701            
4702            
4703             /* all digit read finished */
4704 6027           digi_finish:
4705            
4706             /*
4707             Fast path 1:
4708            
4709             1. The floating-point number calculation should be accurate, see the
4710             comments of macro `YYJSON_DOUBLE_MATH_CORRECT`.
4711             2. Correct rounding should be performed (fegetround() == FE_TONEAREST).
4712             3. The input of floating point number calculation does not lose precision,
4713             which means: 64 - leading_zero(input) - trailing_zero(input) < 53.
4714            
4715             We don't check all available inputs here, because that would make the code
4716             more complicated, and not friendly to branch predictor.
4717             */
4718             #if YYJSON_DOUBLE_MATH_CORRECT
4719 6027 0         if (sig < ((u64)1 << 53) &&
    0          
    0          
    100          
    50          
    50          
4720 6023 0         exp >= -F64_POW10_EXP_MAX_EXACT &&
    0          
    0          
    100          
    50          
    50          
4721 6021 0         exp <= +F64_POW10_EXP_MAX_EXACT) {
    0          
    0          
    50          
    50          
    50          
4722 6021           f64 dbl = (f64)sig;
4723 6021 0         if (exp < 0) {
    0          
    0          
    50          
    50          
    50          
4724 6021           dbl /= f64_pow10_table[-exp];
4725             } else {
4726 0           dbl *= f64_pow10_table[+exp];
4727             }
4728 6021 0         return_f64(dbl);
    0          
    0          
    50          
    50          
    50          
4729             }
4730             #endif
4731            
4732             /*
4733             Fast path 2:
4734            
4735             To keep it simple, we only accept normal number here,
4736             let the slow path to handle subnormal and infinity number.
4737             */
4738 6 0         if (likely(!sig_cut &&
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    100          
    100          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4739             exp > -F64_MAX_DEC_EXP + 1 &&
4740             exp < +F64_MAX_DEC_EXP - 20)) {
4741             /*
4742             The result value is exactly equal to (sig * 10^exp),
4743             the exponent part (10^exp) can be converted to (sig2 * 2^exp2).
4744            
4745             The sig2 can be an infinite length number, only the highest 128 bits
4746             is cached in the pow10_sig_table.
4747            
4748             Now we have these bits:
4749             sig1 (normalized 64bit) : aaaaaaaa
4750             sig2 (higher 64bit) : bbbbbbbb
4751             sig2_ext (lower 64bit) : cccccccc
4752             sig2_cut (extra unknown bits) : dddddddddddd....
4753            
4754             And the calculation process is:
4755             ----------------------------------------
4756             aaaaaaaa *
4757             bbbbbbbbccccccccdddddddddddd....
4758             ----------------------------------------
4759             abababababababab +
4760             acacacacacacacac +
4761             adadadadadadadadadad....
4762             ----------------------------------------
4763             [hi____][lo____] +
4764             [hi2___][lo2___] +
4765             [unknown___________....]
4766             ----------------------------------------
4767            
4768             The addition with carry may affect higher bits, but if there is a 0
4769             in higher bits, the bits higher than 0 will not be affected.
4770            
4771             `lo2` + `unknown` may get a carry bit and may affect `hi2`, the max
4772             value of `hi2` is 0xFFFFFFFFFFFFFFFE, so `hi2` will not overflow.
4773            
4774             `lo` + `hi2` may also get a carry bit and may affect `hi`, but only
4775             the highest significant 53 bits of `hi` is needed. If there is a 0
4776             in the lower bits of `hi`, then all the following bits can be dropped.
4777            
4778             To convert the result to IEEE-754 double number, we need to perform
4779             correct rounding:
4780             1. if bit 54 is 0, round down,
4781             2. if bit 54 is 1 and any bit beyond bit 54 is 1, round up,
4782             3. if bit 54 is 1 and all bits beyond bit 54 are 0, round to even,
4783             as the extra bits is unknown, this case will not be handled here.
4784             */
4785            
4786             u64 raw;
4787             u64 sig1, sig2, sig2_ext, hi, lo, hi2, lo2, add, bits;
4788             i32 exp2;
4789             u32 lz;
4790 2           bool exact = false, carry, round_up;
4791            
4792             /* convert (10^exp) to (sig2 * 2^exp2) */
4793 2           pow10_table_get_sig(exp, &sig2, &sig2_ext);
4794 2           pow10_table_get_exp(exp, &exp2);
4795            
4796             /* normalize and multiply */
4797 2           lz = u64_lz_bits(sig);
4798 2           sig1 = sig << lz;
4799 2           exp2 -= (i32)lz;
4800 2           u128_mul(sig1, sig2, &hi, &lo);
4801            
4802             /*
4803             The `hi` is in range [0x4000000000000000, 0xFFFFFFFFFFFFFFFE],
4804             To get normalized value, `hi` should be shifted to the left by 0 or 1.
4805            
4806             The highest significant 53 bits is used by IEEE-754 double number,
4807             and the bit 54 is used to detect rounding direction.
4808            
4809             The lowest (64 - 54 - 1) bits is used to check whether it contains 0.
4810             */
4811 2           bits = hi & (((u64)1 << (64 - 54 - 1)) - 1);
4812 2 0         if (bits - 1 < (((u64)1 << (64 - 54 - 1)) - 2)) {
    0          
    0          
    50          
    0          
    0          
4813             /*
4814             (bits != 0 && bits != 0x1FF) => (bits - 1 < 0x1FF - 1)
4815             The `bits` is not zero, so we don't need to check `round to even`
4816             case. The `bits` contains bit `0`, so we can drop the extra bits
4817             after `0`.
4818             */
4819 2           exact = true;
4820            
4821             } else {
4822             /*
4823             (bits == 0 || bits == 0x1FF)
4824             The `bits` is filled with all `0` or all `1`, so we need to check
4825             lower bits with another 64-bit multiplication.
4826             */
4827 0           u128_mul(sig1, sig2_ext, &hi2, &lo2);
4828            
4829 0           add = lo + hi2;
4830 0 0         if (add + 1 > (u64)1) {
    0          
    0          
    0          
    0          
    0          
4831             /*
4832             (add != 0 && add != U64_MAX) => (add + 1 > 1)
4833             The `add` is not zero, so we don't need to check `round to
4834             even` case. The `add` contains bit `0`, so we can drop the
4835             extra bits after `0`. The `hi` cannot be U64_MAX, so it will
4836             not overflow.
4837             */
4838 0 0         carry = add < lo || add < hi2;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4839 0           hi += carry;
4840 0           exact = true;
4841             }
4842             }
4843            
4844 2 0         if (exact) {
    0          
    0          
    50          
    0          
    0          
4845             /* normalize */
4846 2           lz = hi < ((u64)1 << 63);
4847 2           hi <<= lz;
4848 2           exp2 -= (i32)lz;
4849 2           exp2 += 64;
4850            
4851             /* test the bit 54 and get rounding direction */
4852 2           round_up = (hi & ((u64)1 << (64 - 54))) > (u64)0;
4853 2 0         hi += (round_up ? ((u64)1 << (64 - 54)) : (u64)0);
    0          
    0          
    50          
    0          
    0          
4854            
4855             /* test overflow */
4856 2 0         if (hi < ((u64)1 << (64 - 54))) {
    0          
    0          
    50          
    0          
    0          
4857 0           hi = ((u64)1 << 63);
4858 0           exp2 += 1;
4859             }
4860            
4861             /* This is a normal number, convert it to IEEE-754 format. */
4862 2           hi >>= F64_BITS - F64_SIG_FULL_BITS;
4863 2           exp2 += F64_BITS - F64_SIG_FULL_BITS + F64_SIG_BITS;
4864 2           exp2 += F64_EXP_BIAS;
4865 2           raw = ((u64)exp2 << F64_SIG_BITS) | (hi & F64_SIG_MASK);
4866 2           return_f64_bin(raw);
4867             }
4868             }
4869            
4870             /*
4871             Slow path: read double number exactly with diyfp.
4872             1. Use cached diyfp to get an approximation value.
4873             2. Use bigcomp to check the approximation value if needed.
4874            
4875             This algorithm refers to google's double-conversion project:
4876             https://github.com/google/double-conversion
4877             */
4878             {
4879 4           const i32 ERR_ULP_LOG = 3;
4880 4           const i32 ERR_ULP = 1 << ERR_ULP_LOG;
4881 4           const i32 ERR_CACHED_POW = ERR_ULP / 2;
4882 4           const i32 ERR_MUL_FIXED = ERR_ULP / 2;
4883 4           const i32 DIY_SIG_BITS = 64;
4884 4           const i32 EXP_BIAS = F64_EXP_BIAS + F64_SIG_BITS;
4885 4           const i32 EXP_SUBNORMAL = -EXP_BIAS + 1;
4886            
4887             u64 fp_err;
4888             u32 bits;
4889             i32 order_of_magnitude;
4890             i32 effective_significand_size;
4891             i32 precision_digits_count;
4892             u64 precision_bits;
4893             u64 half_way;
4894            
4895             u64 raw;
4896             diy_fp fp, fp_upper;
4897             bigint big_full, big_comp;
4898             i32 cmp;
4899            
4900 4           fp.sig = sig;
4901 4           fp.exp = 0;
4902 4 0         fp_err = sig_cut ? (u64)(ERR_ULP / 2) : (u64)0;
    0          
    0          
    50          
    0          
    0          
4903            
4904             /* normalize */
4905 4           bits = u64_lz_bits(fp.sig);
4906 4           fp.sig <<= bits;
4907 4           fp.exp -= (i32)bits;
4908 4           fp_err <<= bits;
4909            
4910             /* multiply and add error */
4911 4           fp = diy_fp_mul(fp, diy_fp_get_cached_pow10(exp));
4912 4           fp_err += (u64)ERR_CACHED_POW + (fp_err != 0) + (u64)ERR_MUL_FIXED;
4913            
4914             /* normalize */
4915 4           bits = u64_lz_bits(fp.sig);
4916 4           fp.sig <<= bits;
4917 4           fp.exp -= (i32)bits;
4918 4           fp_err <<= bits;
4919            
4920             /* effective significand */
4921 4           order_of_magnitude = DIY_SIG_BITS + fp.exp;
4922 4 0         if (likely(order_of_magnitude >= EXP_SUBNORMAL + F64_SIG_FULL_BITS)) {
    0          
    0          
    50          
    0          
    0          
4923 4           effective_significand_size = F64_SIG_FULL_BITS;
4924 0 0         } else if (order_of_magnitude <= EXP_SUBNORMAL) {
    0          
    0          
    0          
    0          
    0          
4925 0           effective_significand_size = 0;
4926             } else {
4927 0           effective_significand_size = order_of_magnitude - EXP_SUBNORMAL;
4928             }
4929            
4930             /* precision digits count */
4931 4           precision_digits_count = DIY_SIG_BITS - effective_significand_size;
4932 4 0         if (unlikely(precision_digits_count + ERR_ULP_LOG >= DIY_SIG_BITS)) {
    0          
    0          
    50          
    0          
    0          
4933 0           i32 shr = (precision_digits_count + ERR_ULP_LOG) - DIY_SIG_BITS + 1;
4934 0           fp.sig >>= shr;
4935 0           fp.exp += shr;
4936 0           fp_err = (fp_err >> shr) + 1 + (u32)ERR_ULP;
4937 0           precision_digits_count -= shr;
4938             }
4939            
4940             /* half way */
4941 4           precision_bits = fp.sig & (((u64)1 << precision_digits_count) - 1);
4942 4           precision_bits *= (u32)ERR_ULP;
4943 4           half_way = (u64)1 << (precision_digits_count - 1);
4944 4           half_way *= (u32)ERR_ULP;
4945            
4946             /* rounding */
4947 4           fp.sig >>= precision_digits_count;
4948 4           fp.sig += (precision_bits >= half_way + fp_err);
4949 4 0         fp.exp += precision_digits_count;
    0          
    0          
    50          
    0          
    0          
4950            
4951             /* get IEEE double raw value */
4952 4           raw = diy_fp_to_ieee_raw(fp);
4953 4 0         if (unlikely(raw == F64_RAW_INF)) return_inf();
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4954 4 0         if (likely(precision_bits <= half_way - fp_err ||
    0          
    0          
    0          
    0          
    0          
    100          
    50          
    0          
    0          
    0          
    0          
4955             precision_bits >= half_way + fp_err)) {
4956 4           return_f64_bin(raw); /* number is accurate */
4957             }
4958             /* now the number is the correct value, or the next lower value */
4959            
4960             /* upper boundary */
4961 0 0         if (raw & F64_EXP_MASK) {
    0          
    0          
    0          
    0          
    0          
4962 0           fp_upper.sig = (raw & F64_SIG_MASK) + ((u64)1 << F64_SIG_BITS);
4963 0           fp_upper.exp = (i32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
4964             } else {
4965 0           fp_upper.sig = (raw & F64_SIG_MASK);
4966 0           fp_upper.exp = 1;
4967             }
4968 0           fp_upper.exp -= F64_EXP_BIAS + F64_SIG_BITS;
4969 0           fp_upper.sig <<= 1;
4970 0           fp_upper.exp -= 1;
4971 0           fp_upper.sig += 1; /* add half ulp */
4972            
4973             /* compare with bigint */
4974 0           bigint_set_buf(&big_full, sig, &exp, sig_cut, sig_end, dot_pos);
4975 0           bigint_set_u64(&big_comp, fp_upper.sig);
4976 0 0         if (exp >= 0) {
    0          
    0          
    0          
    0          
    0          
4977 0           bigint_mul_pow10(&big_full, +exp);
4978             } else {
4979 0           bigint_mul_pow10(&big_comp, -exp);
4980             }
4981 0 0         if (fp_upper.exp > 0) {
    0          
    0          
    0          
    0          
    0          
4982 0 0         bigint_mul_pow2(&big_comp, (u32)+fp_upper.exp);
    0          
    0          
    0          
    0          
    0          
4983             } else {
4984 0 0         bigint_mul_pow2(&big_full, (u32)-fp_upper.exp);
    0          
    0          
    0          
    0          
    0          
4985             }
4986 0           cmp = bigint_cmp(&big_full, &big_comp);
4987 0 0         if (likely(cmp != 0)) {
    0          
    0          
    0          
    0          
    0          
4988             /* round down or round up */
4989 0           raw += (cmp > 0);
4990             } else {
4991             /* falls midway, round to even */
4992 0           raw += (raw & 1);
4993             }
4994            
4995 0 0         if (unlikely(raw == F64_RAW_INF)) return_inf();
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4996 0           return_f64_bin(raw);
4997             }
4998            
4999             #undef return_err
5000             #undef return_inf
5001             #undef return_0
5002             #undef return_i64
5003             #undef return_f64
5004             #undef return_f64_bin
5005             #undef return_raw
5006             }
5007              
5008              
5009              
5010             #else /* FP_READER */
5011              
5012             /**
5013             Read a JSON number.
5014             This is a fallback function if the custom number reader is disabled.
5015             This function use libc's strtod() to read floating-point number.
5016             */
5017             static_inline bool read_number(u8 **ptr,
5018             u8 **pre,
5019             yyjson_read_flag flg,
5020             yyjson_val *val,
5021             const char **msg) {
5022            
5023             #define return_err(_pos, _msg) do { \
5024             *msg = _msg; \
5025             *end = _pos; \
5026             return false; \
5027             } while (false)
5028            
5029             #define return_0() do { \
5030             val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); \
5031             val->uni.u64 = 0; \
5032             *end = cur; return true; \
5033             } while (false)
5034              
5035             #define return_i64(_v) do { \
5036             val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); \
5037             val->uni.u64 = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \
5038             *end = cur; return true; \
5039             } while (false)
5040            
5041             #define return_f64(_v) do { \
5042             val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
5043             val->uni.f64 = sign ? -(f64)(_v) : (f64)(_v); \
5044             *end = cur; return true; \
5045             } while (false)
5046            
5047             #define return_f64_bin(_v) do { \
5048             val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
5049             val->uni.u64 = ((u64)sign << 63) | (u64)(_v); \
5050             *end = cur; return true; \
5051             } while (false)
5052            
5053             #define return_inf() do { \
5054             if (has_read_flag(BIGNUM_AS_RAW)) return_raw(); \
5055             if (has_read_flag(ALLOW_INF_AND_NAN)) return_f64_bin(F64_RAW_INF); \
5056             else return_err(hdr, "number is infinity when parsed as double"); \
5057             } while (false)
5058            
5059             #define return_raw() do { \
5060             if (*pre) **pre = '\0'; /* add null-terminator for previous raw string */ \
5061             val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
5062             val->uni.str = (const char *)hdr; \
5063             *pre = cur; *end = cur; return true; \
5064             } while (false)
5065            
5066             u64 sig, num;
5067             u8 *hdr = *ptr;
5068             u8 *cur = *ptr;
5069             u8 **end = ptr;
5070             u8 *dot = NULL;
5071             u8 *f64_end = NULL;
5072             bool sign;
5073            
5074             /* read number as raw string if has `YYJSON_READ_NUMBER_AS_RAW` flag */
5075             if (has_read_flag(NUMBER_AS_RAW)) {
5076             return read_number_raw(ptr, pre, flg, val, msg);
5077             }
5078            
5079             sign = (*hdr == '-');
5080             cur += sign;
5081             sig = (u8)(*cur - '0');
5082            
5083             /* read first digit, check leading zero */
5084             if (unlikely(!digi_is_digit(*cur))) {
5085             if (has_read_flag(ALLOW_INF_AND_NAN)) {
5086             if (read_inf_or_nan(sign, &cur, pre, val)) {
5087             *end = cur;
5088             return true;
5089             }
5090             }
5091             return_err(cur, "no digit after minus sign");
5092             }
5093             if (*cur == '0') {
5094             cur++;
5095             if (unlikely(digi_is_digit(*cur))) {
5096             return_err(cur - 1, "number with leading zero is not allowed");
5097             }
5098             if (!digi_is_fp(*cur)) return_0();
5099             goto read_double;
5100             }
5101            
5102             /* read continuous digits, up to 19 characters */
5103             #define expr_intg(i) \
5104             if (likely((num = (u64)(cur[i] - (u8)'0')) <= 9)) sig = num + sig * 10; \
5105             else { cur += i; goto intg_end; }
5106             repeat_in_1_18(expr_intg)
5107             #undef expr_intg
5108            
5109             /* here are 19 continuous digits, skip them */
5110             cur += 19;
5111             if (digi_is_digit(cur[0]) && !digi_is_digit_or_fp(cur[1])) {
5112             /* this number is an integer consisting of 20 digits */
5113             num = (u8)(*cur - '0');
5114             if ((sig < (U64_MAX / 10)) ||
5115             (sig == (U64_MAX / 10) && num <= (U64_MAX % 10))) {
5116             sig = num + sig * 10;
5117             cur++;
5118             if (sign) {
5119             if (has_read_flag(BIGNUM_AS_RAW)) return_raw();
5120             return_f64(normalized_u64_to_f64(sig));
5121             }
5122             return_i64(sig);
5123             }
5124             }
5125            
5126             intg_end:
5127             /* continuous digits ended */
5128             if (!digi_is_digit_or_fp(*cur)) {
5129             /* this number is an integer consisting of 1 to 19 digits */
5130             if (sign && (sig > ((u64)1 << 63))) {
5131             if (has_read_flag(BIGNUM_AS_RAW)) return_raw();
5132             return_f64(normalized_u64_to_f64(sig));
5133             }
5134             return_i64(sig);
5135             }
5136            
5137             read_double:
5138             /* this number should be read as double */
5139             while (digi_is_digit(*cur)) cur++;
5140             if (!digi_is_fp(*cur) && has_read_flag(BIGNUM_AS_RAW)) {
5141             return_raw(); /* it's a large integer */
5142             }
5143             if (*cur == '.') {
5144             /* skip fraction part */
5145             dot = cur;
5146             cur++;
5147             if (!digi_is_digit(*cur)) {
5148             return_err(cur, "no digit after decimal point");
5149             }
5150             cur++;
5151             while (digi_is_digit(*cur)) cur++;
5152             }
5153             if (digi_is_exp(*cur)) {
5154             /* skip exponent part */
5155             cur += 1 + digi_is_sign(cur[1]);
5156             if (!digi_is_digit(*cur)) {
5157             return_err(cur, "no digit after exponent sign");
5158             }
5159             cur++;
5160             while (digi_is_digit(*cur)) cur++;
5161             }
5162            
5163             /*
5164             libc's strtod() is used to parse the floating-point number.
5165            
5166             Note that the decimal point character used by strtod() is locale-dependent,
5167             and the rounding direction may affected by fesetround().
5168            
5169             For currently known locales, (en, zh, ja, ko, am, he, hi) use '.' as the
5170             decimal point, while other locales use ',' as the decimal point.
5171            
5172             Here strtod() is called twice for different locales, but if another thread
5173             happens calls setlocale() between two strtod(), parsing may still fail.
5174             */
5175             val->uni.f64 = strtod((const char *)hdr, (char **)&f64_end);
5176             if (unlikely(f64_end != cur)) {
5177             /* replace '.' with ',' for locale */
5178             bool cut = (*cur == ',');
5179             if (cut) *cur = ' ';
5180             if (dot) *dot = ',';
5181             val->uni.f64 = strtod((const char *)hdr, (char **)&f64_end);
5182             /* restore ',' to '.' */
5183             if (cut) *cur = ',';
5184             if (dot) *dot = '.';
5185             if (unlikely(f64_end != cur)) {
5186             return_err(hdr, "strtod() failed to parse the number");
5187             }
5188             }
5189             if (unlikely(val->uni.f64 >= HUGE_VAL || val->uni.f64 <= -HUGE_VAL)) {
5190             return_inf();
5191             }
5192             val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
5193             *end = cur;
5194             return true;
5195            
5196             #undef return_err
5197             #undef return_0
5198             #undef return_i64
5199             #undef return_f64
5200             #undef return_f64_bin
5201             #undef return_inf
5202             #undef return_raw
5203             }
5204              
5205             #endif /* FP_READER */
5206              
5207              
5208              
5209             /*==============================================================================
5210             * JSON String Reader
5211             *============================================================================*/
5212              
5213             /**
5214             Read a JSON string.
5215             @param ptr The head pointer of string before '"' prefix (inout).
5216             @param lst JSON last position.
5217             @param inv Allow invalid unicode.
5218             @param val The string value to be written.
5219             @param msg The error message pointer.
5220             @return Whether success.
5221             */
5222             static_inline bool read_string(u8 **ptr,
5223             u8 *lst,
5224             bool inv,
5225             yyjson_val *val,
5226             const char **msg) {
5227             /*
5228             Each unicode code point is encoded as 1 to 4 bytes in UTF-8 encoding,
5229             we use 4-byte mask and pattern value to validate UTF-8 byte sequence,
5230             this requires the input data to have 4-byte zero padding.
5231             ---------------------------------------------------
5232             1 byte
5233             unicode range [U+0000, U+007F]
5234             unicode min [.......0]
5235             unicode max [.1111111]
5236             bit pattern [0.......]
5237             ---------------------------------------------------
5238             2 byte
5239             unicode range [U+0080, U+07FF]
5240             unicode min [......10 ..000000]
5241             unicode max [...11111 ..111111]
5242             bit require [...xxxx. ........] (1E 00)
5243             bit mask [xxx..... xx......] (E0 C0)
5244             bit pattern [110..... 10......] (C0 80)
5245             ---------------------------------------------------
5246             3 byte
5247             unicode range [U+0800, U+FFFF]
5248             unicode min [........ ..100000 ..000000]
5249             unicode max [....1111 ..111111 ..111111]
5250             bit require [....xxxx ..x..... ........] (0F 20 00)
5251             bit mask [xxxx.... xx...... xx......] (F0 C0 C0)
5252             bit pattern [1110.... 10...... 10......] (E0 80 80)
5253             ---------------------------------------------------
5254             3 byte invalid (reserved for surrogate halves)
5255             unicode range [U+D800, U+DFFF]
5256             unicode min [....1101 ..100000 ..000000]
5257             unicode max [....1101 ..111111 ..111111]
5258             bit mask [....xxxx ..x..... ........] (0F 20 00)
5259             bit pattern [....1101 ..1..... ........] (0D 20 00)
5260             ---------------------------------------------------
5261             4 byte
5262             unicode range [U+10000, U+10FFFF]
5263             unicode min [........ ...10000 ..000000 ..000000]
5264             unicode max [.....100 ..001111 ..111111 ..111111]
5265             bit require [.....xxx ..xx.... ........ ........] (07 30 00 00)
5266             bit mask [xxxxx... xx...... xx...... xx......] (F8 C0 C0 C0)
5267             bit pattern [11110... 10...... 10...... 10......] (F0 80 80 80)
5268             ---------------------------------------------------
5269             */
5270             #if YYJSON_ENDIAN == YYJSON_BIG_ENDIAN
5271             const u32 b1_mask = 0x80000000UL;
5272             const u32 b1_patt = 0x00000000UL;
5273             const u32 b2_mask = 0xE0C00000UL;
5274             const u32 b2_patt = 0xC0800000UL;
5275             const u32 b2_requ = 0x1E000000UL;
5276             const u32 b3_mask = 0xF0C0C000UL;
5277             const u32 b3_patt = 0xE0808000UL;
5278             const u32 b3_requ = 0x0F200000UL;
5279             const u32 b3_erro = 0x0D200000UL;
5280             const u32 b4_mask = 0xF8C0C0C0UL;
5281             const u32 b4_patt = 0xF0808080UL;
5282             const u32 b4_requ = 0x07300000UL;
5283             const u32 b4_err0 = 0x04000000UL;
5284             const u32 b4_err1 = 0x03300000UL;
5285             #elif YYJSON_ENDIAN == YYJSON_LITTLE_ENDIAN
5286 50607           const u32 b1_mask = 0x00000080UL;
5287 50607           const u32 b1_patt = 0x00000000UL;
5288 50607           const u32 b2_mask = 0x0000C0E0UL;
5289 50607           const u32 b2_patt = 0x000080C0UL;
5290 50607           const u32 b2_requ = 0x0000001EUL;
5291 50607           const u32 b3_mask = 0x00C0C0F0UL;
5292 50607           const u32 b3_patt = 0x008080E0UL;
5293 50607           const u32 b3_requ = 0x0000200FUL;
5294 50607           const u32 b3_erro = 0x0000200DUL;
5295 50607           const u32 b4_mask = 0xC0C0C0F8UL;
5296 50607           const u32 b4_patt = 0x808080F0UL;
5297 50607           const u32 b4_requ = 0x00003007UL;
5298 50607           const u32 b4_err0 = 0x00000004UL;
5299 50607           const u32 b4_err1 = 0x00003003UL;
5300             #else
5301             /* this should be evaluated at compile-time */
5302             v32_uni b1_mask_uni = {{ 0x80, 0x00, 0x00, 0x00 }};
5303             v32_uni b1_patt_uni = {{ 0x00, 0x00, 0x00, 0x00 }};
5304             v32_uni b2_mask_uni = {{ 0xE0, 0xC0, 0x00, 0x00 }};
5305             v32_uni b2_patt_uni = {{ 0xC0, 0x80, 0x00, 0x00 }};
5306             v32_uni b2_requ_uni = {{ 0x1E, 0x00, 0x00, 0x00 }};
5307             v32_uni b3_mask_uni = {{ 0xF0, 0xC0, 0xC0, 0x00 }};
5308             v32_uni b3_patt_uni = {{ 0xE0, 0x80, 0x80, 0x00 }};
5309             v32_uni b3_requ_uni = {{ 0x0F, 0x20, 0x00, 0x00 }};
5310             v32_uni b3_erro_uni = {{ 0x0D, 0x20, 0x00, 0x00 }};
5311             v32_uni b4_mask_uni = {{ 0xF8, 0xC0, 0xC0, 0xC0 }};
5312             v32_uni b4_patt_uni = {{ 0xF0, 0x80, 0x80, 0x80 }};
5313             v32_uni b4_requ_uni = {{ 0x07, 0x30, 0x00, 0x00 }};
5314             v32_uni b4_err0_uni = {{ 0x04, 0x00, 0x00, 0x00 }};
5315             v32_uni b4_err1_uni = {{ 0x03, 0x30, 0x00, 0x00 }};
5316             u32 b1_mask = b1_mask_uni.u;
5317             u32 b1_patt = b1_patt_uni.u;
5318             u32 b2_mask = b2_mask_uni.u;
5319             u32 b2_patt = b2_patt_uni.u;
5320             u32 b2_requ = b2_requ_uni.u;
5321             u32 b3_mask = b3_mask_uni.u;
5322             u32 b3_patt = b3_patt_uni.u;
5323             u32 b3_requ = b3_requ_uni.u;
5324             u32 b3_erro = b3_erro_uni.u;
5325             u32 b4_mask = b4_mask_uni.u;
5326             u32 b4_patt = b4_patt_uni.u;
5327             u32 b4_requ = b4_requ_uni.u;
5328             u32 b4_err0 = b4_err0_uni.u;
5329             u32 b4_err1 = b4_err1_uni.u;
5330             #endif
5331            
5332             #define is_valid_seq_1(uni) ( \
5333             ((uni & b1_mask) == b1_patt) \
5334             )
5335              
5336             #define is_valid_seq_2(uni) ( \
5337             ((uni & b2_mask) == b2_patt) && \
5338             ((uni & b2_requ)) \
5339             )
5340            
5341             #define is_valid_seq_3(uni) ( \
5342             ((uni & b3_mask) == b3_patt) && \
5343             ((tmp = (uni & b3_requ))) && \
5344             ((tmp != b3_erro)) \
5345             )
5346            
5347             #define is_valid_seq_4(uni) ( \
5348             ((uni & b4_mask) == b4_patt) && \
5349             ((tmp = (uni & b4_requ))) && \
5350             ((tmp & b4_err0) == 0 || (tmp & b4_err1) == 0) \
5351             )
5352            
5353             #define return_err(_end, _msg) do { \
5354             *msg = _msg; \
5355             *end = _end; \
5356             return false; \
5357             } while (false)
5358            
5359 50607           u8 *cur = *ptr;
5360 50607           u8 **end = ptr;
5361 50607           u8 *src = ++cur, *dst, *pos;
5362             u16 hi, lo;
5363             u32 uni, tmp;
5364            
5365 10           skip_ascii:
5366             /* Most strings have no escaped characters, so we can jump them quickly. */
5367            
5368 58897           skip_ascii_begin:
5369             /*
5370             We want to make loop unrolling, as shown in the following code. Some
5371             compiler may not generate instructions as expected, so we rewrite it with
5372             explicit goto statements. We hope the compiler can generate instructions
5373             like this: https://godbolt.org/z/8vjsYq
5374            
5375             while (true) repeat16({
5376             if (likely(!(char_is_ascii_stop(*src)))) src++;
5377             else break;
5378             })
5379             */
5380             #define expr_jump(i) \
5381             if (likely(!char_is_ascii_stop(src[i]))) {} \
5382             else goto skip_ascii_stop##i;
5383            
5384             #define expr_stop(i) \
5385             skip_ascii_stop##i: \
5386             src += i; \
5387             goto skip_ascii_end;
5388            
5389 536850 50         repeat16_incr(expr_jump)
    100          
    50          
    100          
    100          
    100          
    50          
    100          
    50          
    100          
    50          
    100          
    50          
    100          
    50          
    50          
    50          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    50          
    50          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    100          
    50          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    100          
    100          
    100          
    50          
    50          
    100          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
5390 8280           src += 16;
5391 8280           goto skip_ascii_begin;
5392 50617           repeat16_incr(expr_stop)
5393            
5394             #undef expr_jump
5395             #undef expr_stop
5396            
5397 50617           skip_ascii_end:
5398            
5399             /*
5400             GCC may store src[i] in a register at each line of expr_jump(i) above.
5401             These instructions are useless and will degrade performance.
5402             This inline asm is a hint for gcc: "the memory has been modified,
5403             do not cache it".
5404            
5405             MSVC, Clang, ICC can generate expected instructions without this hint.
5406             */
5407             #if YYJSON_IS_REAL_GCC
5408 50617           __asm__ volatile("":"=m"(*src));
5409             #endif
5410 50617           if (likely(*src == '"')) {
5411 50595           val->tag = ((u64)(src - cur) << YYJSON_TAG_BIT) |
5412             (u64)(YYJSON_TYPE_STR | YYJSON_SUBTYPE_NOESC);
5413 50595           val->uni.str = (const char *)cur;
5414 50595           *src = '\0';
5415 50595           *end = src + 1;
5416 50595           return true;
5417             }
5418            
5419 22           skip_utf8:
5420 22 0         if (*src & 0x80) { /* non-ASCII character */
    0          
    0          
    0          
    100          
    100          
    100          
5421             /*
5422             Non-ASCII character appears here, which means that the text is likely
5423             to be written in non-English or emoticons. According to some common
5424             data set statistics, byte sequences of the same length may appear
5425             consecutively. We process the byte sequences of the same length in each
5426             loop, which is more friendly to branch prediction.
5427             */
5428 10           pos = src;
5429             #if YYJSON_DISABLE_UTF8_VALIDATION
5430             while (true) repeat8({
5431             if (likely((*src & 0xF0) == 0xE0)) src += 3;
5432             else break;
5433             })
5434             if (*src < 0x80) goto skip_ascii;
5435             while (true) repeat8({
5436             if (likely((*src & 0xE0) == 0xC0)) src += 2;
5437             else break;
5438             })
5439             while (true) repeat8({
5440             if (likely((*src & 0xF8) == 0xF0)) src += 4;
5441             else break;
5442             })
5443             #else
5444 10           uni = byte_load_4(src);
5445 15 0         while (is_valid_seq_3(uni)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    50          
    50          
    50          
    0          
    0          
    100          
    50          
    50          
5446 5           src += 3;
5447 5           uni = byte_load_4(src);
5448             }
5449 10 0         if (is_valid_seq_1(uni)) goto skip_ascii;
    0          
    0          
    0          
    100          
    50          
    100          
5450 12 0         while (is_valid_seq_2(uni)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    50          
    100          
    50          
    100          
    50          
5451 5           src += 2;
5452 5           uni = byte_load_4(src);
5453             }
5454 9 0         while (is_valid_seq_4(uni)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    100          
    50          
    50          
    0          
    100          
    50          
    50          
    0          
5455 2           src += 4;
5456 2           uni = byte_load_4(src);
5457             }
5458             #endif
5459 7 0         if (unlikely(pos == src)) {
    0          
    0          
    0          
    50          
    50          
    50          
5460 0 0         if (!inv) return_err(src, "invalid UTF-8 encoding in string");
    0          
    0          
    0          
    0          
    0          
    0          
5461 0           ++src;
5462             }
5463 7           goto skip_ascii;
5464             }
5465            
5466             /* The escape character appears, we need to copy it. */
5467 12           dst = src;
5468 39           copy_escape:
5469 39 0         if (likely(*src == '\\')) {
    0          
    0          
    0          
    100          
    100          
    100          
5470 27           switch (*++src) {
5471 4           case '"': *dst++ = '"'; src++; break;
5472 2           case '\\': *dst++ = '\\'; src++; break;
5473 1           case '/': *dst++ = '/'; src++; break;
5474 1           case 'b': *dst++ = '\b'; src++; break;
5475 1           case 'f': *dst++ = '\f'; src++; break;
5476 7           case 'n': *dst++ = '\n'; src++; break;
5477 1           case 'r': *dst++ = '\r'; src++; break;
5478 1           case 't': *dst++ = '\t'; src++; break;
5479 9           case 'u':
5480 18 0         if (unlikely(!read_hex_u16(++src, &hi))) {
    0          
    0          
    0          
    0          
    0          
    50          
5481 0           return_err(src - 2, "invalid escaped sequence in string");
5482             }
5483 9           src += 4;
5484 9 0         if (likely((hi & 0xF800) != 0xD800)) {
    0          
    0          
    0          
    0          
    0          
    100          
5485             /* a BMP character */
5486 7 0         if (hi >= 0x800) {
    0          
    0          
    0          
    0          
    0          
    50          
5487 0           *dst++ = (u8)(0xE0 | (hi >> 12));
5488 0           *dst++ = (u8)(0x80 | ((hi >> 6) & 0x3F));
5489 0           *dst++ = (u8)(0x80 | (hi & 0x3F));
5490 7 0         } else if (hi >= 0x80) {
    0          
    0          
    0          
    0          
    0          
    100          
5491 2           *dst++ = (u8)(0xC0 | (hi >> 6));
5492 2           *dst++ = (u8)(0x80 | (hi & 0x3F));
5493             } else {
5494 5           *dst++ = (u8)hi;
5495             }
5496             } else {
5497             /* a non-BMP character, represented as a surrogate pair */
5498 2 0         if (unlikely((hi & 0xFC00) != 0xD800)) {
    0          
    0          
    0          
    0          
    0          
    50          
5499 0           return_err(src - 6, "invalid high surrogate in string");
5500             }
5501 2 0         if (unlikely(!byte_match_2(src, "\\u"))) {
    0          
    0          
    0          
    0          
    0          
    50          
5502 0           return_err(src, "no low surrogate in string");
5503             }
5504 4 0         if (unlikely(!read_hex_u16(src + 2, &lo))) {
    0          
    0          
    0          
    0          
    0          
    50          
5505 0           return_err(src, "invalid escaped sequence in string");
5506             }
5507 2 0         if (unlikely((lo & 0xFC00) != 0xDC00)) {
    0          
    0          
    0          
    0          
    0          
    50          
5508 0           return_err(src, "invalid low surrogate in string");
5509             }
5510 2           uni = ((((u32)hi - 0xD800) << 10) |
5511 2           ((u32)lo - 0xDC00)) + 0x10000;
5512 2           *dst++ = (u8)(0xF0 | (uni >> 18));
5513 2           *dst++ = (u8)(0x80 | ((uni >> 12) & 0x3F));
5514 2           *dst++ = (u8)(0x80 | ((uni >> 6) & 0x3F));
5515 2           *dst++ = (u8)(0x80 | (uni & 0x3F));
5516 2           src += 6;
5517             }
5518 9           break;
5519 0           default: return_err(src, "invalid escaped character in string");
5520             }
5521 12 0         } else if (likely(*src == '"')) {
    0          
    0          
    0          
    50          
    50          
    50          
5522 12           val->tag = ((u64)(dst - cur) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR;
5523 12           val->uni.str = (const char *)cur;
5524 12           *dst = '\0';
5525 12           *end = src + 1;
5526 12           return true;
5527             } else {
5528 0 0         if (!inv) return_err(src, "unexpected control character in string");
    0          
    0          
    0          
    0          
    0          
    0          
5529 0 0         if (src >= lst) return_err(src, "unclosed string");
    0          
    0          
    0          
    0          
    0          
    0          
5530 0           *dst++ = *src++;
5531             }
5532            
5533 3           copy_ascii:
5534             /*
5535             Copy continuous ASCII, loop unrolling, same as the following code:
5536            
5537             while (true) repeat16({
5538             if (unlikely(char_is_ascii_stop(*src))) break;
5539             *dst++ = *src++;
5540             })
5541             */
5542             #if YYJSON_IS_REAL_GCC
5543             # define expr_jump(i) \
5544             if (likely(!(char_is_ascii_stop(src[i])))) {} \
5545             else { __asm__ volatile("":"=m"(src[i])); goto copy_ascii_stop_##i; }
5546             #else
5547             # define expr_jump(i) \
5548             if (likely(!(char_is_ascii_stop(src[i])))) {} \
5549             else { goto copy_ascii_stop_##i; }
5550             #endif
5551 141 0         repeat16_incr(expr_jump)
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    100          
    50          
    50          
    100          
    50          
    100          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    100          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
5552             #undef expr_jump
5553            
5554             byte_move_16(dst, src);
5555 3           src += 16;
5556 3           dst += 16;
5557 3           goto copy_ascii;
5558            
5559             /*
5560             The memory will be moved forward by at least 1 byte. So the `byte_move`
5561             can be one byte more than needed to reduce the number of instructions.
5562             */
5563 15           copy_ascii_stop_0:
5564 15           goto copy_utf8;
5565 6           copy_ascii_stop_1:
5566             byte_move_2(dst, src);
5567 6           src += 1;
5568 6           dst += 1;
5569 6           goto copy_utf8;
5570 2           copy_ascii_stop_2:
5571             byte_move_2(dst, src);
5572 2           src += 2;
5573 2           dst += 2;
5574 2           goto copy_utf8;
5575 0           copy_ascii_stop_3:
5576             byte_move_4(dst, src);
5577 0           src += 3;
5578 0           dst += 3;
5579 0           goto copy_utf8;
5580 0           copy_ascii_stop_4:
5581             byte_move_4(dst, src);
5582 0           src += 4;
5583 0           dst += 4;
5584 0           goto copy_utf8;
5585 2           copy_ascii_stop_5:
5586             byte_move_4(dst, src);
5587 2           byte_move_2(dst + 4, src + 4);
5588 2           src += 5;
5589 2           dst += 5;
5590 2           goto copy_utf8;
5591 0           copy_ascii_stop_6:
5592             byte_move_4(dst, src);
5593 0           byte_move_2(dst + 4, src + 4);
5594 0           src += 6;
5595 0           dst += 6;
5596 0           goto copy_utf8;
5597 1           copy_ascii_stop_7:
5598             byte_move_8(dst, src);
5599 1           src += 7;
5600 1           dst += 7;
5601 1           goto copy_utf8;
5602 0           copy_ascii_stop_8:
5603             byte_move_8(dst, src);
5604 0           src += 8;
5605 0           dst += 8;
5606 0           goto copy_utf8;
5607 1           copy_ascii_stop_9:
5608             byte_move_8(dst, src);
5609 1           byte_move_2(dst + 8, src + 8);
5610 1           src += 9;
5611 1           dst += 9;
5612 1           goto copy_utf8;
5613 0           copy_ascii_stop_10:
5614             byte_move_8(dst, src);
5615 0           byte_move_2(dst + 8, src + 8);
5616 0           src += 10;
5617 0           dst += 10;
5618 0           goto copy_utf8;
5619 0           copy_ascii_stop_11:
5620             byte_move_8(dst, src);
5621 0           byte_move_4(dst + 8, src + 8);
5622 0           src += 11;
5623 0           dst += 11;
5624 0           goto copy_utf8;
5625 0           copy_ascii_stop_12:
5626             byte_move_8(dst, src);
5627 0           byte_move_4(dst + 8, src + 8);
5628 0           src += 12;
5629 0           dst += 12;
5630 0           goto copy_utf8;
5631 0           copy_ascii_stop_13:
5632             byte_move_8(dst, src);
5633 0           byte_move_4(dst + 8, src + 8);
5634 0           byte_move_2(dst + 12, src + 12);
5635 0           src += 13;
5636 0           dst += 13;
5637 0           goto copy_utf8;
5638 0           copy_ascii_stop_14:
5639             byte_move_8(dst, src);
5640 0           byte_move_4(dst + 8, src + 8);
5641 0           byte_move_2(dst + 12, src + 12);
5642 0           src += 14;
5643 0           dst += 14;
5644 0           goto copy_utf8;
5645 0           copy_ascii_stop_15:
5646             byte_move_16(dst, src);
5647 0           src += 15;
5648 0           dst += 15;
5649 0           goto copy_utf8;
5650            
5651 27           copy_utf8:
5652 27 0         if (*src & 0x80) { /* non-ASCII character */
    0          
    0          
    0          
    50          
    50          
    50          
5653 0           pos = src;
5654 0           uni = byte_load_4(src);
5655             #if YYJSON_DISABLE_UTF8_VALIDATION
5656             while (true) repeat4({
5657             if ((uni & b3_mask) == b3_patt) {
5658             byte_copy_4(dst, &uni);
5659             dst += 3;
5660             src += 3;
5661             uni = byte_load_4(src);
5662             } else break;
5663             })
5664             if ((uni & b1_mask) == b1_patt) goto copy_ascii;
5665             while (true) repeat4({
5666             if ((uni & b2_mask) == b2_patt) {
5667             byte_copy_2(dst, &uni);
5668             dst += 2;
5669             src += 2;
5670             uni = byte_load_4(src);
5671             } else break;
5672             })
5673             while (true) repeat4({
5674             if ((uni & b4_mask) == b4_patt) {
5675             byte_copy_4(dst, &uni);
5676             dst += 4;
5677             src += 4;
5678             uni = byte_load_4(src);
5679             } else break;
5680             })
5681             #else
5682 0 0         while (is_valid_seq_3(uni)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
5683             byte_copy_4(dst, &uni);
5684 0           dst += 3;
5685 0           src += 3;
5686 0           uni = byte_load_4(src);
5687             }
5688 0 0         if (is_valid_seq_1(uni)) goto copy_ascii;
    0          
    0          
    0          
    0          
    0          
    0          
5689 0 0         while (is_valid_seq_2(uni)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
5690             byte_copy_2(dst, &uni);
5691 0           dst += 2;
5692 0           src += 2;
5693 0           uni = byte_load_4(src);
5694             }
5695 0 0         while (is_valid_seq_4(uni)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
5696             byte_copy_4(dst, &uni);
5697 0           dst += 4;
5698 0           src += 4;
5699 0           uni = byte_load_4(src);
5700             }
5701             #endif
5702 0 0         if (unlikely(pos == src)) {
    0          
    0          
    0          
    0          
    0          
    0          
5703 0 0         if (!inv) return_err(src, "invalid UTF-8 encoding in string");
    0          
    0          
    0          
    0          
    0          
    0          
5704 0           goto copy_ascii_stop_1;
5705             }
5706 0           goto copy_ascii;
5707             }
5708 27           goto copy_escape;
5709            
5710             #undef return_err
5711             #undef is_valid_seq_1
5712             #undef is_valid_seq_2
5713             #undef is_valid_seq_3
5714             #undef is_valid_seq_4
5715             }
5716              
5717              
5718              
5719             /*==============================================================================
5720             * JSON Reader Implementation
5721             *
5722             * We use goto statements to build the finite state machine (FSM).
5723             * The FSM's state was held by program counter (PC) and the 'goto' make the
5724             * state transitions.
5725             *============================================================================*/
5726              
5727             /** Read single value JSON document. */
5728 33           static_noinline yyjson_doc *read_root_single(u8 *hdr,
5729             u8 *cur,
5730             u8 *end,
5731             yyjson_alc alc,
5732             yyjson_read_flag flg,
5733             yyjson_read_err *err) {
5734            
5735             #define return_err(_pos, _code, _msg) do { \
5736             if (is_truncated_end(hdr, _pos, end, YYJSON_READ_ERROR_##_code, flg)) { \
5737             err->pos = (usize)(end - hdr); \
5738             err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
5739             err->msg = "unexpected end of data"; \
5740             } else { \
5741             err->pos = (usize)(_pos - hdr); \
5742             err->code = YYJSON_READ_ERROR_##_code; \
5743             err->msg = _msg; \
5744             } \
5745             if (val_hdr) alc.free(alc.ctx, (void *)val_hdr); \
5746             return NULL; \
5747             } while (false)
5748            
5749             usize hdr_len; /* value count used by doc */
5750             usize alc_num; /* value count capacity */
5751             yyjson_val *val_hdr; /* the head of allocated values */
5752             yyjson_val *val; /* current value */
5753             yyjson_doc *doc; /* the JSON document, equals to val_hdr */
5754             const char *msg; /* error message */
5755            
5756             bool raw; /* read number as raw */
5757             bool inv; /* allow invalid unicode */
5758             u8 *raw_end; /* raw end for null-terminator */
5759             u8 **pre; /* previous raw end pointer */
5760            
5761 33           hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
5762 33           hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
5763 33           alc_num = hdr_len + 1; /* single value */
5764            
5765 33           val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_num * sizeof(yyjson_val));
5766 33 50         if (unlikely(!val_hdr)) goto fail_alloc;
5767 33           val = val_hdr + hdr_len;
5768 99 50         raw = has_read_flag(NUMBER_AS_RAW) || has_read_flag(BIGNUM_AS_RAW);
    50          
5769 33           inv = has_read_flag(ALLOW_INVALID_UNICODE) != 0;
5770 33           raw_end = NULL;
5771 33 50         pre = raw ? &raw_end : NULL;
5772            
5773 66 100         if (char_is_number(*cur)) {
5774 8 50         if (likely(read_number(&cur, pre, flg, val, &msg))) goto doc_end;
5775 0           goto fail_number;
5776             }
5777 25 100         if (*cur == '"') {
5778 32 50         if (likely(read_string(&cur, end, inv, val, &msg))) goto doc_end;
5779 0           goto fail_string;
5780             }
5781 9 100         if (*cur == 't') {
5782 2 50         if (likely(read_true(&cur, val))) goto doc_end;
5783 0           goto fail_literal_true;
5784             }
5785 7 100         if (*cur == 'f') {
5786 2 50         if (likely(read_false(&cur, val))) goto doc_end;
5787 0           goto fail_literal_false;
5788             }
5789 5 100         if (*cur == 'n') {
5790 3 100         if (likely(read_null(&cur, val))) goto doc_end;
5791 2 50         if (has_read_flag(ALLOW_INF_AND_NAN)) {
5792 0 0         if (read_nan(false, &cur, pre, val)) goto doc_end;
5793             }
5794 1           goto fail_literal_null;
5795             }
5796 4 50         if (has_read_flag(ALLOW_INF_AND_NAN)) {
5797 0 0         if (read_inf_or_nan(false, &cur, pre, val)) goto doc_end;
5798             }
5799 2           goto fail_character;
5800            
5801 30           doc_end:
5802             /* check invalid contents after json document */
5803 30 50         if (unlikely(cur < end) && !has_read_flag(STOP_WHEN_DONE)) {
    0          
5804 0 0         if (has_read_flag(ALLOW_COMMENTS)) {
5805 0 0         if (!skip_spaces_and_comments(&cur)) {
5806 0 0         if (byte_match_2(cur, "/*")) goto fail_comment;
5807             }
5808             } else {
5809 0 0         while (char_is_space(*cur)) cur++;
5810             }
5811 0 0         if (unlikely(cur < end)) goto fail_garbage;
5812             }
5813            
5814 30 50         if (pre && *pre) **pre = '\0';
    0          
5815 30           doc = (yyjson_doc *)val_hdr;
5816 30           doc->root = val_hdr + hdr_len;
5817 30           doc->alc = alc;
5818 30           doc->dat_read = (usize)(cur - hdr);
5819 30           doc->val_read = 1;
5820 60 50         doc->str_pool = has_read_flag(INSITU) ? NULL : (char *)hdr;
5821 30           return doc;
5822            
5823 0           fail_string:
5824 0 0         return_err(cur, INVALID_STRING, msg);
    0          
5825 0           fail_number:
5826 0 0         return_err(cur, INVALID_NUMBER, msg);
    0          
5827 0           fail_alloc:
5828 0 0         return_err(cur, MEMORY_ALLOCATION,
    0          
5829             "memory allocation failed");
5830 0           fail_literal_true:
5831 0 0         return_err(cur, LITERAL,
    0          
5832             "invalid literal, expected a valid literal such as 'true'");
5833 0           fail_literal_false:
5834 0 0         return_err(cur, LITERAL,
    0          
5835             "invalid literal, expected a valid literal such as 'false'");
5836 1           fail_literal_null:
5837 1 50         return_err(cur, LITERAL,
    50          
5838             "invalid literal, expected a valid literal such as 'null'");
5839 2           fail_character:
5840 2 50         return_err(cur, UNEXPECTED_CHARACTER,
    50          
5841             "unexpected character, expected a valid root value");
5842 0           fail_comment:
5843 0 0         return_err(cur, INVALID_COMMENT,
    0          
5844             "unclosed multiline comment");
5845 0           fail_garbage:
5846 0 0         return_err(cur, UNEXPECTED_CONTENT,
    0          
5847             "unexpected content after document");
5848            
5849             #undef return_err
5850             }
5851              
5852             /** Read JSON document (accept all style, but optimized for minify). */
5853             static_inline yyjson_doc *read_root_minify(u8 *hdr,
5854             u8 *cur,
5855             u8 *end,
5856             yyjson_alc alc,
5857             yyjson_read_flag flg,
5858             yyjson_read_err *err) {
5859            
5860             #define return_err(_pos, _code, _msg) do { \
5861             if (is_truncated_end(hdr, _pos, end, YYJSON_READ_ERROR_##_code, flg)) { \
5862             err->pos = (usize)(end - hdr); \
5863             err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
5864             err->msg = "unexpected end of data"; \
5865             } else { \
5866             err->pos = (usize)(_pos - hdr); \
5867             err->code = YYJSON_READ_ERROR_##_code; \
5868             err->msg = _msg; \
5869             } \
5870             if (val_hdr) alc.free(alc.ctx, (void *)val_hdr); \
5871             return NULL; \
5872             } while (false)
5873            
5874             #define val_incr() do { \
5875             val++; \
5876             if (unlikely(val >= val_end)) { \
5877             usize alc_old = alc_len; \
5878             alc_len += alc_len / 2; \
5879             if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \
5880             val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
5881             alc_old * sizeof(yyjson_val), \
5882             alc_len * sizeof(yyjson_val)); \
5883             if ((!val_tmp)) goto fail_alloc; \
5884             val = val_tmp + (usize)(val - val_hdr); \
5885             ctn = val_tmp + (usize)(ctn - val_hdr); \
5886             val_hdr = val_tmp; \
5887             val_end = val_tmp + (alc_len - 2); \
5888             } \
5889             } while (false)
5890            
5891             usize dat_len; /* data length in bytes, hint for allocator */
5892             usize hdr_len; /* value count used by yyjson_doc */
5893             usize alc_len; /* value count allocated */
5894             usize alc_max; /* maximum value count for allocator */
5895             usize ctn_len; /* the number of elements in current container */
5896             yyjson_val *val_hdr; /* the head of allocated values */
5897             yyjson_val *val_end; /* the end of allocated values */
5898             yyjson_val *val_tmp; /* temporary pointer for realloc */
5899             yyjson_val *val; /* current JSON value */
5900             yyjson_val *ctn; /* current container */
5901             yyjson_val *ctn_parent; /* parent of current container */
5902             yyjson_doc *doc; /* the JSON document, equals to val_hdr */
5903             const char *msg; /* error message */
5904            
5905             bool raw; /* read number as raw */
5906             bool inv; /* allow invalid unicode */
5907             u8 *raw_end; /* raw end for null-terminator */
5908             u8 **pre; /* previous raw end pointer */
5909            
5910 6212 50         dat_len = has_read_flag(STOP_WHEN_DONE) ? 256 : (usize)(end - cur);
5911 6212           hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
5912 6212           hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
5913 6212           alc_max = USIZE_MAX / sizeof(yyjson_val);
5914 6212           alc_len = hdr_len + (dat_len / YYJSON_READER_ESTIMATED_MINIFY_RATIO) + 4;
5915 6212           alc_len = yyjson_min(alc_len, alc_max);
5916            
5917 6212           val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_len * sizeof(yyjson_val));
5918 6212 50         if (unlikely(!val_hdr)) goto fail_alloc;
5919 6212           val_end = val_hdr + (alc_len - 2); /* padding for key-value pair reading */
5920 6212           val = val_hdr + hdr_len;
5921 6212           ctn = val;
5922 6212           ctn_len = 0;
5923 18636 50         raw = has_read_flag(NUMBER_AS_RAW) || has_read_flag(BIGNUM_AS_RAW);
    50          
5924 6212           inv = has_read_flag(ALLOW_INVALID_UNICODE) != 0;
5925 6212           raw_end = NULL;
5926 6212 50         pre = raw ? &raw_end : NULL;
5927            
5928 6212 100         if (*cur++ == '{') {
5929 6167           ctn->tag = YYJSON_TYPE_OBJ;
5930 6167           ctn->uni.ofs = 0;
5931 6167           goto obj_key_begin;
5932             } else {
5933 45           ctn->tag = YYJSON_TYPE_ARR;
5934 45           ctn->uni.ofs = 0;
5935 45           goto arr_val_begin;
5936             }
5937            
5938 3494           arr_begin:
5939             /* save current container */
5940 3494           ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
5941 3494           (ctn->tag & YYJSON_TAG_MASK);
5942            
5943             /* create a new array value, save parent container offset */
5944 3494 100         val_incr();
    50          
5945 3494           val->tag = YYJSON_TYPE_ARR;
5946 3494           val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
5947            
5948             /* push the new array value as current container */
5949 3494           ctn = val;
5950 3494           ctn_len = 0;
5951            
5952 17           arr_val_begin:
5953 16699 100         if (*cur == '{') {
5954 1165           cur++;
5955 1165           goto obj_begin;
5956             }
5957 15534 100         if (*cur == '[') {
5958 1323           cur++;
5959 1323           goto arr_begin;
5960             }
5961 28422 100         if (char_is_number(*cur)) {
5962 118 100         val_incr();
    50          
5963 118           ctn_len++;
5964 118 50         if (likely(read_number(&cur, pre, flg, val, &msg))) goto arr_val_end;
5965 0           goto fail_number;
5966             }
5967 14093 100         if (*cur == '"') {
5968 14037 100         val_incr();
    50          
5969 14037           ctn_len++;
5970 28074 50         if (likely(read_string(&cur, end, inv, val, &msg))) goto arr_val_end;
5971 0           goto fail_string;
5972             }
5973 56 100         if (*cur == 't') {
5974 3 50         val_incr();
    0          
5975 3           ctn_len++;
5976 3 50         if (likely(read_true(&cur, val))) goto arr_val_end;
5977 0           goto fail_literal_true;
5978             }
5979 53 100         if (*cur == 'f') {
5980 2 50         val_incr();
    0          
5981 2           ctn_len++;
5982 2 50         if (likely(read_false(&cur, val))) goto arr_val_end;
5983 0           goto fail_literal_false;
5984             }
5985 51 100         if (*cur == 'n') {
5986 7 50         val_incr();
    0          
5987 7           ctn_len++;
5988 7 50         if (likely(read_null(&cur, val))) goto arr_val_end;
5989 0 0         if (has_read_flag(ALLOW_INF_AND_NAN)) {
5990 0 0         if (read_nan(false, &cur, pre, val)) goto arr_val_end;
5991             }
5992 0           goto fail_literal_null;
5993             }
5994 44 100         if (*cur == ']') {
5995 25           cur++;
5996 25 100         if (likely(ctn_len == 0)) goto arr_end;
5997 2 50         if (has_read_flag(ALLOW_TRAILING_COMMAS)) goto arr_end;
5998 0 0         while (*cur != ',') cur--;
5999 0           goto fail_trailing_comma;
6000             }
6001 38 100         if (char_is_space(*cur)) {
6002 34 50         while (char_is_space(*++cur));
6003 17           goto arr_val_begin;
6004             }
6005 4 50         if (has_read_flag(ALLOW_INF_AND_NAN) &&
6006 2 50         (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
    100          
    50          
6007 2 50         val_incr();
    0          
6008 2 100         ctn_len++;
6009 2 50         if (read_inf_or_nan(false, &cur, pre, val)) goto arr_val_end;
6010 0           goto fail_character_val;
6011             }
6012 0 0         if (has_read_flag(ALLOW_COMMENTS)) {
6013 0 0         if (skip_spaces_and_comments(&cur)) goto arr_val_begin;
6014 0 0         if (byte_match_2(cur, "/*")) goto fail_comment;
6015             }
6016 0           goto fail_character_val;
6017            
6018 1           arr_val_end:
6019 16658 100         if (*cur == ',') {
6020 13143           cur++;
6021 13143           goto arr_val_begin;
6022             }
6023 3515 100         if (*cur == ']') {
6024 3514           cur++;
6025 3514           goto arr_end;
6026             }
6027 2 50         if (char_is_space(*cur)) {
6028 2 50         while (char_is_space(*++cur));
6029 1           goto arr_val_end;
6030             }
6031 0 0         if (has_read_flag(ALLOW_COMMENTS)) {
6032 0 0         if (skip_spaces_and_comments(&cur)) goto arr_val_end;
6033 0 0         if (byte_match_2(cur, "/*")) goto fail_comment;
6034             }
6035 0           goto fail_character_arr_end;
6036            
6037 3539           arr_end:
6038             /* get parent container */
6039 3539           ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
6040            
6041             /* save the next sibling value offset */
6042 3539           ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
6043 3539           ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
6044 3539 100         if (unlikely(ctn == ctn_parent)) goto doc_end;
6045            
6046             /* pop parent as current container */
6047 3494           ctn = ctn_parent;
6048 3494           ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
6049 3494 100         if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
6050 2171           goto obj_val_end;
6051             } else {
6052 1323           goto arr_val_end;
6053             }
6054            
6055 3263           obj_begin:
6056             /* push container */
6057 3263           ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
6058 3263           (ctn->tag & YYJSON_TAG_MASK);
6059 3263 100         val_incr();
    50          
6060 3263           val->tag = YYJSON_TYPE_OBJ;
6061             /* offset to the parent */
6062 3263           val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
6063 3263           ctn = val;
6064 3263           ctn_len = 0;
6065            
6066 0           obj_key_begin:
6067 27110 100         if (likely(*cur == '"')) {
6068 27097 100         val_incr();
    50          
6069 27097           ctn_len++;
6070 54194 50         if (likely(read_string(&cur, end, inv, val, &msg))) goto obj_key_end;
6071 0           goto fail_string;
6072             }
6073 13 50         if (likely(*cur == '}')) {
6074 13           cur++;
6075 13 100         if (likely(ctn_len == 0)) goto obj_end;
6076 4 100         if (has_read_flag(ALLOW_TRAILING_COMMAS)) goto obj_end;
6077 3 100         while (*cur != ',') cur--;
6078 1           goto fail_trailing_comma;
6079             }
6080 0 0         if (char_is_space(*cur)) {
6081 0 0         while (char_is_space(*++cur));
6082 0           goto obj_key_begin;
6083             }
6084 0 0         if (has_read_flag(ALLOW_COMMENTS)) {
6085 0 0         if (skip_spaces_and_comments(&cur)) goto obj_key_begin;
6086 0 0         if (byte_match_2(cur, "/*")) goto fail_comment;
6087             }
6088 0           goto fail_character_obj_key;
6089            
6090 0           obj_key_end:
6091 27097 50         if (*cur == ':') {
6092 27097           cur++;
6093 27097           goto obj_val_begin;
6094             }
6095 0 0         if (char_is_space(*cur)) {
6096 0 0         while (char_is_space(*++cur));
6097 0           goto obj_key_end;
6098             }
6099 0 0         if (has_read_flag(ALLOW_COMMENTS)) {
6100 0 0         if (skip_spaces_and_comments(&cur)) goto obj_key_end;
6101 0 0         if (byte_match_2(cur, "/*")) goto fail_comment;
6102             }
6103 0           goto fail_character_obj_sep;
6104            
6105 0           obj_val_begin:
6106 27097 100         if (*cur == '"') {
6107 9178           val++;
6108 9178           ctn_len++;
6109 18356 50         if (likely(read_string(&cur, end, inv, val, &msg))) goto obj_val_end;
6110 0           goto fail_string;
6111             }
6112 35838 100         if (char_is_number(*cur)) {
6113 13629           val++;
6114 13629           ctn_len++;
6115 13629 50         if (likely(read_number(&cur, pre, flg, val, &msg))) goto obj_val_end;
6116 0           goto fail_number;
6117             }
6118 4290 100         if (*cur == '{') {
6119 2098           cur++;
6120 2098           goto obj_begin;
6121             }
6122 2192 100         if (*cur == '[') {
6123 2171           cur++;
6124 2171           goto arr_begin;
6125             }
6126 21 100         if (*cur == 't') {
6127 5           val++;
6128 5           ctn_len++;
6129 5 50         if (likely(read_true(&cur, val))) goto obj_val_end;
6130 0           goto fail_literal_true;
6131             }
6132 16 100         if (*cur == 'f') {
6133 5           val++;
6134 5           ctn_len++;
6135 5 50         if (likely(read_false(&cur, val))) goto obj_val_end;
6136 0           goto fail_literal_false;
6137             }
6138 11 100         if (*cur == 'n') {
6139 10           val++;
6140 10           ctn_len++;
6141 10 50         if (likely(read_null(&cur, val))) goto obj_val_end;
6142 0 0         if (has_read_flag(ALLOW_INF_AND_NAN)) {
6143 0 0         if (read_nan(false, &cur, pre, val)) goto obj_val_end;
6144             }
6145 0           goto fail_literal_null;
6146             }
6147 2 50         if (char_is_space(*cur)) {
6148 0 0         while (char_is_space(*++cur));
6149 0           goto obj_val_begin;
6150             }
6151 2 50         if (has_read_flag(ALLOW_INF_AND_NAN) &&
6152 0 0         (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
    0          
    0          
6153 0           val++;
6154 0 0         ctn_len++;
6155 0 0         if (read_inf_or_nan(false, &cur, pre, val)) goto obj_val_end;
6156 0           goto fail_character_val;
6157             }
6158 2 50         if (has_read_flag(ALLOW_COMMENTS)) {
6159 0 0         if (skip_spaces_and_comments(&cur)) goto obj_val_begin;
6160 0 0         if (byte_match_2(cur, "/*")) goto fail_comment;
6161             }
6162 1           goto fail_character_val;
6163            
6164 0           obj_val_end:
6165 27096 100         if (likely(*cur == ',')) {
6166 17680           cur++;
6167 17680           goto obj_key_begin;
6168             }
6169 9416 100         if (likely(*cur == '}')) {
6170 9415           cur++;
6171 9415           goto obj_end;
6172             }
6173 2 50         if (char_is_space(*cur)) {
6174 0 0         while (char_is_space(*++cur));
6175 0           goto obj_val_end;
6176             }
6177 2 50         if (has_read_flag(ALLOW_COMMENTS)) {
6178 0 0         if (skip_spaces_and_comments(&cur)) goto obj_val_end;
6179 0 0         if (byte_match_2(cur, "/*")) goto fail_comment;
6180             }
6181 1           goto fail_character_obj_end;
6182            
6183 9427           obj_end:
6184             /* pop container */
6185 9427           ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
6186             /* point to the next value */
6187 9427           ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
6188 9427           ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
6189 9427 100         if (unlikely(ctn == ctn_parent)) goto doc_end;
6190 3263           ctn = ctn_parent;
6191 3263           ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
6192 3263 100         if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
6193 2098           goto obj_val_end;
6194             } else {
6195 1165           goto arr_val_end;
6196             }
6197            
6198 6209           doc_end:
6199             /* check invalid contents after json document */
6200 6211 100         if (unlikely(cur < end) && !has_read_flag(STOP_WHEN_DONE)) {
    50          
6201 4 50         if (has_read_flag(ALLOW_COMMENTS)) {
6202 0           skip_spaces_and_comments(&cur);
6203 0 0         if (byte_match_2(cur, "/*")) goto fail_comment;
6204             } else {
6205 11 100         while (char_is_space(*cur)) cur++;
6206             }
6207 2 50         if (unlikely(cur < end)) goto fail_garbage;
6208             }
6209            
6210 6209 50         if (pre && *pre) **pre = '\0';
    0          
6211 6209           doc = (yyjson_doc *)val_hdr;
6212 6209           doc->root = val_hdr + hdr_len;
6213 6209           doc->alc = alc;
6214 6209           doc->dat_read = (usize)(cur - hdr);
6215 6209           doc->val_read = (usize)((val - doc->root) + 1);
6216 12418 50         doc->str_pool = has_read_flag(INSITU) ? NULL : (char *)hdr;
6217 6209           return doc;
6218            
6219 0           fail_string:
6220 0 0         return_err(cur, INVALID_STRING, msg);
    0          
6221 0           fail_number:
6222 0 0         return_err(cur, INVALID_NUMBER, msg);
    0          
6223 0           fail_alloc:
6224 0 0         return_err(cur, MEMORY_ALLOCATION,
    0          
6225             "memory allocation failed");
6226 1           fail_trailing_comma:
6227 1 50         return_err(cur, JSON_STRUCTURE,
    50          
6228             "trailing comma is not allowed");
6229 0           fail_literal_true:
6230 0 0         return_err(cur, LITERAL,
    0          
6231             "invalid literal, expected a valid literal such as 'true'");
6232 0           fail_literal_false:
6233 0 0         return_err(cur, LITERAL,
    0          
6234             "invalid literal, expected a valid literal such as 'false'");
6235 0           fail_literal_null:
6236 0 0         return_err(cur, LITERAL,
    0          
6237             "invalid literal, expected a valid literal such as 'null'");
6238 1           fail_character_val:
6239 1 50         return_err(cur, UNEXPECTED_CHARACTER,
    50          
6240             "unexpected character, expected a valid JSON value");
6241 0           fail_character_arr_end:
6242 0 0         return_err(cur, UNEXPECTED_CHARACTER,
    0          
6243             "unexpected character, expected a comma or a closing bracket");
6244 0           fail_character_obj_key:
6245 0 0         return_err(cur, UNEXPECTED_CHARACTER,
    0          
6246             "unexpected character, expected a string for object key");
6247 0           fail_character_obj_sep:
6248 0 0         return_err(cur, UNEXPECTED_CHARACTER,
    0          
6249             "unexpected character, expected a colon after object key");
6250 1           fail_character_obj_end:
6251 1 50         return_err(cur, UNEXPECTED_CHARACTER,
    50          
6252             "unexpected character, expected a comma or a closing brace");
6253 0           fail_comment:
6254 0 0         return_err(cur, INVALID_COMMENT,
    0          
6255             "unclosed multiline comment");
6256 0           fail_garbage:
6257 0 0         return_err(cur, UNEXPECTED_CONTENT,
    0          
6258             "unexpected content after document");
6259            
6260             #undef val_incr
6261             #undef return_err
6262             }
6263              
6264             /** Read JSON document (accept all style, but optimized for pretty). */
6265             static_inline yyjson_doc *read_root_pretty(u8 *hdr,
6266             u8 *cur,
6267             u8 *end,
6268             yyjson_alc alc,
6269             yyjson_read_flag flg,
6270             yyjson_read_err *err) {
6271            
6272             #define return_err(_pos, _code, _msg) do { \
6273             if (is_truncated_end(hdr, _pos, end, YYJSON_READ_ERROR_##_code, flg)) { \
6274             err->pos = (usize)(end - hdr); \
6275             err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
6276             err->msg = "unexpected end of data"; \
6277             } else { \
6278             err->pos = (usize)(_pos - hdr); \
6279             err->code = YYJSON_READ_ERROR_##_code; \
6280             err->msg = _msg; \
6281             } \
6282             if (val_hdr) alc.free(alc.ctx, (void *)val_hdr); \
6283             return NULL; \
6284             } while (false)
6285            
6286             #define val_incr() do { \
6287             val++; \
6288             if (unlikely(val >= val_end)) { \
6289             usize alc_old = alc_len; \
6290             alc_len += alc_len / 2; \
6291             if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \
6292             val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
6293             alc_old * sizeof(yyjson_val), \
6294             alc_len * sizeof(yyjson_val)); \
6295             if ((!val_tmp)) goto fail_alloc; \
6296             val = val_tmp + (usize)(val - val_hdr); \
6297             ctn = val_tmp + (usize)(ctn - val_hdr); \
6298             val_hdr = val_tmp; \
6299             val_end = val_tmp + (alc_len - 2); \
6300             } \
6301             } while (false)
6302            
6303             usize dat_len; /* data length in bytes, hint for allocator */
6304             usize hdr_len; /* value count used by yyjson_doc */
6305             usize alc_len; /* value count allocated */
6306             usize alc_max; /* maximum value count for allocator */
6307             usize ctn_len; /* the number of elements in current container */
6308             yyjson_val *val_hdr; /* the head of allocated values */
6309             yyjson_val *val_end; /* the end of allocated values */
6310             yyjson_val *val_tmp; /* temporary pointer for realloc */
6311             yyjson_val *val; /* current JSON value */
6312             yyjson_val *ctn; /* current container */
6313             yyjson_val *ctn_parent; /* parent of current container */
6314             yyjson_doc *doc; /* the JSON document, equals to val_hdr */
6315             const char *msg; /* error message */
6316            
6317             bool raw; /* read number as raw */
6318             bool inv; /* allow invalid unicode */
6319             u8 *raw_end; /* raw end for null-terminator */
6320             u8 **pre; /* previous raw end pointer */
6321            
6322 29 50         dat_len = has_read_flag(STOP_WHEN_DONE) ? 256 : (usize)(end - cur);
6323 29           hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
6324 29           hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
6325 29           alc_max = USIZE_MAX / sizeof(yyjson_val);
6326 29           alc_len = hdr_len + (dat_len / YYJSON_READER_ESTIMATED_PRETTY_RATIO) + 4;
6327 29           alc_len = yyjson_min(alc_len, alc_max);
6328            
6329 29           val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_len * sizeof(yyjson_val));
6330 29 50         if (unlikely(!val_hdr)) goto fail_alloc;
6331 29           val_end = val_hdr + (alc_len - 2); /* padding for key-value pair reading */
6332 29           val = val_hdr + hdr_len;
6333 29           ctn = val;
6334 29           ctn_len = 0;
6335 87 50         raw = has_read_flag(NUMBER_AS_RAW) || has_read_flag(BIGNUM_AS_RAW);
    50          
6336 29           inv = has_read_flag(ALLOW_INVALID_UNICODE) != 0;
6337 29           raw_end = NULL;
6338 29 50         pre = raw ? &raw_end : NULL;
6339            
6340 29 100         if (*cur++ == '{') {
6341 19           ctn->tag = YYJSON_TYPE_OBJ;
6342 19           ctn->uni.ofs = 0;
6343 19 50         if (*cur == '\n') cur++;
6344 19           goto obj_key_begin;
6345             } else {
6346 10           ctn->tag = YYJSON_TYPE_ARR;
6347 10           ctn->uni.ofs = 0;
6348 10 50         if (*cur == '\n') cur++;
6349 10           goto arr_val_begin;
6350             }
6351            
6352 20           arr_begin:
6353             /* save current container */
6354 20           ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
6355 20           (ctn->tag & YYJSON_TAG_MASK);
6356            
6357             /* create a new array value, save parent container offset */
6358 20 100         val_incr();
    50          
6359 20           val->tag = YYJSON_TYPE_ARR;
6360 20           val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
6361            
6362             /* push the new array value as current container */
6363 20           ctn = val;
6364 20           ctn_len = 0;
6365 20 100         if (*cur == '\n') cur++;
6366            
6367 5           arr_val_begin:
6368             #if YYJSON_IS_REAL_GCC
6369 326 100         while (true) repeat16({
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
6370             if (byte_match_2(cur, " ")) cur += 2;
6371             else break;
6372             })
6373             #else
6374             while (true) repeat16({
6375             if (likely(byte_match_2(cur, " "))) cur += 2;
6376             else break;
6377             })
6378             #endif
6379            
6380 72 100         if (*cur == '{') {
6381 24           cur++;
6382 24           goto obj_begin;
6383             }
6384 48 100         if (*cur == '[') {
6385 4           cur++;
6386 4           goto arr_begin;
6387             }
6388 88 100         if (char_is_number(*cur)) {
6389 18 100         val_incr();
    50          
6390 18           ctn_len++;
6391 18 50         if (likely(read_number(&cur, pre, flg, val, &msg))) goto arr_val_end;
6392 0           goto fail_number;
6393             }
6394 26 100         if (*cur == '"') {
6395 24 100         val_incr();
    50          
6396 24           ctn_len++;
6397 48 50         if (likely(read_string(&cur, end, inv, val, &msg))) goto arr_val_end;
6398 0           goto fail_string;
6399             }
6400 2 50         if (*cur == 't') {
6401 0 0         val_incr();
    0          
6402 0           ctn_len++;
6403 0 0         if (likely(read_true(&cur, val))) goto arr_val_end;
6404 0           goto fail_literal_true;
6405             }
6406 2 50         if (*cur == 'f') {
6407 0 0         val_incr();
    0          
6408 0           ctn_len++;
6409 0 0         if (likely(read_false(&cur, val))) goto arr_val_end;
6410 0           goto fail_literal_false;
6411             }
6412 2 50         if (*cur == 'n') {
6413 0 0         val_incr();
    0          
6414 0           ctn_len++;
6415 0 0         if (likely(read_null(&cur, val))) goto arr_val_end;
6416 0 0         if (has_read_flag(ALLOW_INF_AND_NAN)) {
6417 0 0         if (read_nan(false, &cur, pre, val)) goto arr_val_end;
6418             }
6419 0           goto fail_literal_null;
6420             }
6421 2 50         if (*cur == ']') {
6422 2           cur++;
6423 2 50         if (likely(ctn_len == 0)) goto arr_end;
6424 0 0         if (has_read_flag(ALLOW_TRAILING_COMMAS)) goto arr_end;
6425 0 0         while (*cur != ',') cur--;
6426 0           goto fail_trailing_comma;
6427             }
6428 0 0         if (char_is_space(*cur)) {
6429 0 0         while (char_is_space(*++cur));
6430 0           goto arr_val_begin;
6431             }
6432 0 0         if (has_read_flag(ALLOW_INF_AND_NAN) &&
6433 0 0         (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
    0          
    0          
6434 0 0         val_incr();
    0          
6435 0 0         ctn_len++;
6436 0 0         if (read_inf_or_nan(false, &cur, pre, val)) goto arr_val_end;
6437 0           goto fail_character_val;
6438             }
6439 0 0         if (has_read_flag(ALLOW_COMMENTS)) {
6440 0 0         if (skip_spaces_and_comments(&cur)) goto arr_val_begin;
6441 0 0         if (byte_match_2(cur, "/*")) goto fail_comment;
6442             }
6443 0           goto fail_character_val;
6444            
6445 20           arr_val_end:
6446 180 100         if (byte_match_2(cur, ",\n")) {
6447 37           cur += 2;
6448 37           goto arr_val_begin;
6449             }
6450 53 100         if (*cur == ',') {
6451 5           cur++;
6452 5           goto arr_val_begin;
6453             }
6454 48 100         if (*cur == ']') {
6455 28           cur++;
6456 28           goto arr_end;
6457             }
6458 40 50         if (char_is_space(*cur)) {
6459 115 100         while (char_is_space(*++cur));
6460 20           goto arr_val_end;
6461             }
6462 0 0         if (has_read_flag(ALLOW_COMMENTS)) {
6463 0 0         if (skip_spaces_and_comments(&cur)) goto arr_val_end;
6464 0 0         if (byte_match_2(cur, "/*")) goto fail_comment;
6465             }
6466 0           goto fail_character_arr_end;
6467            
6468 30           arr_end:
6469             /* get parent container */
6470 30           ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
6471            
6472             /* save the next sibling value offset */
6473 30           ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
6474 30           ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
6475 30 100         if (unlikely(ctn == ctn_parent)) goto doc_end;
6476            
6477             /* pop parent as current container */
6478 20           ctn = ctn_parent;
6479 20           ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
6480 20 100         if (*cur == '\n') cur++;
6481 20 100         if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
6482 16           goto obj_val_end;
6483             } else {
6484 4           goto arr_val_end;
6485             }
6486            
6487 64           obj_begin:
6488             /* push container */
6489 64           ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
6490 64           (ctn->tag & YYJSON_TAG_MASK);
6491 64 100         val_incr();
    50          
6492 64           val->tag = YYJSON_TYPE_OBJ;
6493             /* offset to the parent */
6494 64           val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
6495 64           ctn = val;
6496 64           ctn_len = 0;
6497 64 100         if (*cur == '\n') cur++;
6498            
6499 21           obj_key_begin:
6500             #if YYJSON_IS_REAL_GCC
6501 844 100         while (true) repeat16({
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
6502             if (byte_match_2(cur, " ")) cur += 2;
6503             else break;
6504             })
6505             #else
6506             while (true) repeat16({
6507             if (likely(byte_match_2(cur, " "))) cur += 2;
6508             else break;
6509             })
6510             #endif
6511 197 100         if (likely(*cur == '"')) {
6512 195 100         val_incr();
    50          
6513 195           ctn_len++;
6514 390 50         if (likely(read_string(&cur, end, inv, val, &msg))) goto obj_key_end;
6515 0           goto fail_string;
6516             }
6517 2 100         if (likely(*cur == '}')) {
6518 1           cur++;
6519 1 50         if (likely(ctn_len == 0)) goto obj_end;
6520 2 50         if (has_read_flag(ALLOW_TRAILING_COMMAS)) goto obj_end;
6521 0 0         while (*cur != ',') cur--;
6522 0           goto fail_trailing_comma;
6523             }
6524 2 50         if (char_is_space(*cur)) {
6525 0 0         while (char_is_space(*++cur));
6526 0           goto obj_key_begin;
6527             }
6528 2 50         if (has_read_flag(ALLOW_COMMENTS)) {
6529 1 50         if (skip_spaces_and_comments(&cur)) goto obj_key_begin;
6530 0 0         if (byte_match_2(cur, "/*")) goto fail_comment;
6531             }
6532 0           goto fail_character_obj_key;
6533            
6534 10           obj_key_end:
6535 410 100         if (byte_match_2(cur, ": ")) {
6536 133           cur += 2;
6537 133           goto obj_val_begin;
6538             }
6539 72 100         if (*cur == ':') {
6540 62           cur++;
6541 62           goto obj_val_begin;
6542             }
6543 20 50         if (char_is_space(*cur)) {
6544 21 100         while (char_is_space(*++cur));
6545 10           goto obj_key_end;
6546             }
6547 0 0         if (has_read_flag(ALLOW_COMMENTS)) {
6548 0 0         if (skip_spaces_and_comments(&cur)) goto obj_key_end;
6549 0 0         if (byte_match_2(cur, "/*")) goto fail_comment;
6550             }
6551 0           goto fail_character_obj_sep;
6552            
6553 1           obj_val_begin:
6554 196 100         if (*cur == '"') {
6555 60           val++;
6556 60           ctn_len++;
6557 120 50         if (likely(read_string(&cur, end, inv, val, &msg))) goto obj_val_end;
6558 0           goto fail_string;
6559             }
6560 272 100         if (char_is_number(*cur)) {
6561 74           val++;
6562 74           ctn_len++;
6563 74 50         if (likely(read_number(&cur, pre, flg, val, &msg))) goto obj_val_end;
6564 0           goto fail_number;
6565             }
6566 62 100         if (*cur == '{') {
6567 40           cur++;
6568 40           goto obj_begin;
6569             }
6570 22 100         if (*cur == '[') {
6571 16           cur++;
6572 16           goto arr_begin;
6573             }
6574 6 100         if (*cur == 't') {
6575 3           val++;
6576 3           ctn_len++;
6577 3 50         if (likely(read_true(&cur, val))) goto obj_val_end;
6578 0           goto fail_literal_true;
6579             }
6580 3 100         if (*cur == 'f') {
6581 1           val++;
6582 1           ctn_len++;
6583 1 50         if (likely(read_false(&cur, val))) goto obj_val_end;
6584 0           goto fail_literal_false;
6585             }
6586 2 100         if (*cur == 'n') {
6587 1           val++;
6588 1           ctn_len++;
6589 1 50         if (likely(read_null(&cur, val))) goto obj_val_end;
6590 0 0         if (has_read_flag(ALLOW_INF_AND_NAN)) {
6591 0 0         if (read_nan(false, &cur, pre, val)) goto obj_val_end;
6592             }
6593 0           goto fail_literal_null;
6594             }
6595 2 50         if (char_is_space(*cur)) {
6596 3 100         while (char_is_space(*++cur));
6597 1           goto obj_val_begin;
6598             }
6599 0 0         if (has_read_flag(ALLOW_INF_AND_NAN) &&
6600 0 0         (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
    0          
    0          
6601 0           val++;
6602 0 0         ctn_len++;
6603 0 0         if (read_inf_or_nan(false, &cur, pre, val)) goto obj_val_end;
6604 0           goto fail_character_val;
6605             }
6606 0 0         if (has_read_flag(ALLOW_COMMENTS)) {
6607 0 0         if (skip_spaces_and_comments(&cur)) goto obj_val_begin;
6608 0 0         if (byte_match_2(cur, "/*")) goto fail_comment;
6609             }
6610 0           goto fail_character_val;
6611            
6612 56           obj_val_end:
6613 502 100         if (byte_match_2(cur, ",\n")) {
6614 87           cur += 2;
6615 87           goto obj_key_begin;
6616             }
6617 164 100         if (likely(*cur == ',')) {
6618 26           cur++;
6619 26           goto obj_key_begin;
6620             }
6621 138 100         if (likely(*cur == '}')) {
6622 82           cur++;
6623 82           goto obj_end;
6624             }
6625 112 50         if (char_is_space(*cur)) {
6626 328 100         while (char_is_space(*++cur));
6627 56           goto obj_val_end;
6628             }
6629 0 0         if (has_read_flag(ALLOW_COMMENTS)) {
6630 0 0         if (skip_spaces_and_comments(&cur)) goto obj_val_end;
6631 0 0         if (byte_match_2(cur, "/*")) goto fail_comment;
6632             }
6633 0           goto fail_character_obj_end;
6634            
6635 83           obj_end:
6636             /* pop container */
6637 83           ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
6638             /* point to the next value */
6639 83           ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
6640 83           ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
6641 83 100         if (unlikely(ctn == ctn_parent)) goto doc_end;
6642 64           ctn = ctn_parent;
6643 64           ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
6644 64 100         if (*cur == '\n') cur++;
6645 64 100         if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
6646 40           goto obj_val_end;
6647             } else {
6648 24           goto arr_val_end;
6649             }
6650            
6651 29           doc_end:
6652             /* check invalid contents after json document */
6653 29 50         if (unlikely(cur < end) && !has_read_flag(STOP_WHEN_DONE)) {
    0          
6654 0 0         if (has_read_flag(ALLOW_COMMENTS)) {
6655 0           skip_spaces_and_comments(&cur);
6656 0 0         if (byte_match_2(cur, "/*")) goto fail_comment;
6657             } else {
6658 0 0         while (char_is_space(*cur)) cur++;
6659             }
6660 0 0         if (unlikely(cur < end)) goto fail_garbage;
6661             }
6662            
6663 29 50         if (pre && *pre) **pre = '\0';
    0          
6664 29           doc = (yyjson_doc *)val_hdr;
6665 29           doc->root = val_hdr + hdr_len;
6666 29           doc->alc = alc;
6667 29           doc->dat_read = (usize)(cur - hdr);
6668 29           doc->val_read = (usize)((val - val_hdr)) - hdr_len + 1;
6669 58 50         doc->str_pool = has_read_flag(INSITU) ? NULL : (char *)hdr;
6670 29           return doc;
6671            
6672 0           fail_string:
6673 0 0         return_err(cur, INVALID_STRING, msg);
    0          
6674 0           fail_number:
6675 0 0         return_err(cur, INVALID_NUMBER, msg);
    0          
6676 0           fail_alloc:
6677 0 0         return_err(cur, MEMORY_ALLOCATION,
    0          
6678             "memory allocation failed");
6679 0           fail_trailing_comma:
6680 0 0         return_err(cur, JSON_STRUCTURE,
    0          
6681             "trailing comma is not allowed");
6682 0           fail_literal_true:
6683 0 0         return_err(cur, LITERAL,
    0          
6684             "invalid literal, expected a valid literal such as 'true'");
6685 0           fail_literal_false:
6686 0 0         return_err(cur, LITERAL,
    0          
6687             "invalid literal, expected a valid literal such as 'false'");
6688 0           fail_literal_null:
6689 0 0         return_err(cur, LITERAL,
    0          
6690             "invalid literal, expected a valid literal such as 'null'");
6691 0           fail_character_val:
6692 0 0         return_err(cur, UNEXPECTED_CHARACTER,
    0          
6693             "unexpected character, expected a valid JSON value");
6694 0           fail_character_arr_end:
6695 0 0         return_err(cur, UNEXPECTED_CHARACTER,
    0          
6696             "unexpected character, expected a comma or a closing bracket");
6697 0           fail_character_obj_key:
6698 0 0         return_err(cur, UNEXPECTED_CHARACTER,
    0          
6699             "unexpected character, expected a string for object key");
6700 0           fail_character_obj_sep:
6701 0 0         return_err(cur, UNEXPECTED_CHARACTER,
    0          
6702             "unexpected character, expected a colon after object key");
6703 0           fail_character_obj_end:
6704 0 0         return_err(cur, UNEXPECTED_CHARACTER,
    0          
6705             "unexpected character, expected a comma or a closing brace");
6706 0           fail_comment:
6707 0 0         return_err(cur, INVALID_COMMENT,
    0          
6708             "unclosed multiline comment");
6709 0           fail_garbage:
6710 0 0         return_err(cur, UNEXPECTED_CONTENT,
    0          
6711             "unexpected content after document");
6712            
6713             #undef val_incr
6714             #undef return_err
6715             }
6716              
6717              
6718              
6719             /*==============================================================================
6720             * JSON Reader Entrance
6721             *============================================================================*/
6722              
6723 6274           yyjson_doc *yyjson_read_opts(char *dat,
6724             usize len,
6725             yyjson_read_flag flg,
6726             const yyjson_alc *alc_ptr,
6727             yyjson_read_err *err) {
6728            
6729             #define return_err(_pos, _code, _msg) do { \
6730             err->pos = (usize)(_pos); \
6731             err->msg = _msg; \
6732             err->code = YYJSON_READ_ERROR_##_code; \
6733             if (!has_read_flag(INSITU) && hdr) alc.free(alc.ctx, (void *)hdr); \
6734             return NULL; \
6735             } while (false)
6736            
6737             yyjson_read_err dummy_err;
6738             yyjson_alc alc;
6739             yyjson_doc *doc;
6740 6274           u8 *hdr = NULL, *end, *cur;
6741            
6742             /* validate input parameters */
6743 6274 50         if (!err) err = &dummy_err;
6744 6274 100         if (likely(!alc_ptr)) {
6745 6041           alc = YYJSON_DEFAULT_ALC;
6746             } else {
6747 233           alc = *alc_ptr;
6748             }
6749 6274 50         if (unlikely(!dat)) {
6750 0 0         return_err(0, INVALID_PARAMETER, "input data is NULL");
    0          
6751             }
6752 6274 50         if (unlikely(!len)) {
6753 0 0         return_err(0, INVALID_PARAMETER, "input length is 0");
    0          
6754             }
6755            
6756             /* add 4-byte zero padding for input data if necessary */
6757 12548 50         if (has_read_flag(INSITU)) {
6758 0           hdr = (u8 *)dat;
6759 0           end = (u8 *)dat + len;
6760 0           cur = (u8 *)dat;
6761             } else {
6762 6274 50         if (unlikely(len >= USIZE_MAX - YYJSON_PADDING_SIZE)) {
6763 0 0         return_err(0, MEMORY_ALLOCATION, "memory allocation failed");
    0          
6764             }
6765 6274           hdr = (u8 *)alc.malloc(alc.ctx, len + YYJSON_PADDING_SIZE);
6766 6274 50         if (unlikely(!hdr)) {
6767 0 0         return_err(0, MEMORY_ALLOCATION, "memory allocation failed");
    0          
6768             }
6769 6274           end = hdr + len;
6770 6274           cur = hdr;
6771 6274           memcpy(hdr, dat, len);
6772 6274           memset(end, 0, YYJSON_PADDING_SIZE);
6773             }
6774            
6775             /* skip empty contents before json document */
6776 12548 100         if (unlikely(char_is_space_or_comment(*cur))) {
6777 10 100         if (has_read_flag(ALLOW_COMMENTS)) {
6778 2 50         if (!skip_spaces_and_comments(&cur)) {
6779 0 0         return_err(cur - hdr, INVALID_COMMENT,
    0          
6780             "unclosed multiline comment");
6781             }
6782             } else {
6783 6 100         if (likely(char_is_space(*cur))) {
6784 13 100         while (char_is_space(*++cur));
6785             }
6786             }
6787 5 50         if (unlikely(cur >= end)) {
6788 0 0         return_err(0, EMPTY_CONTENT, "input data is empty");
    0          
6789             }
6790             }
6791            
6792             /* read json document */
6793 12548 100         if (likely(char_is_container(*cur))) {
6794 12512 100         if (char_is_space(cur[1]) && char_is_space(cur[2])) {
    100          
6795 58           doc = read_root_pretty(hdr, cur, end, alc, flg, err);
6796             } else {
6797 12424           doc = read_root_minify(hdr, cur, end, alc, flg, err);
6798             }
6799             } else {
6800 33           doc = read_root_single(hdr, cur, end, alc, flg, err);
6801             }
6802            
6803             /* check result */
6804 6274 100         if (likely(doc)) {
6805 6268           memset(err, 0, sizeof(yyjson_read_err));
6806             } else {
6807             /* RFC 8259: JSON text MUST be encoded using UTF-8 */
6808 6 100         if (err->pos == 0 && err->code != YYJSON_READ_ERROR_MEMORY_ALLOCATION) {
    50          
6809 3 50         if ((hdr[0] == 0xEF && hdr[1] == 0xBB && hdr[2] == 0xBF)) {
    0          
    0          
6810 0           err->msg = "byte order mark (BOM) is not supported";
6811 3 100         } else if (len >= 4 &&
6812 2 50         ((hdr[0] == 0x00 && hdr[1] == 0x00 &&
    0          
6813 0 0         hdr[2] == 0xFE && hdr[3] == 0xFF) ||
    0          
6814 2 50         (hdr[0] == 0xFF && hdr[1] == 0xFE &&
    0          
6815 0 0         hdr[2] == 0x00 && hdr[3] == 0x00))) {
    0          
6816 0           err->msg = "UTF-32 encoding is not supported";
6817 3 50         } else if (len >= 2 &&
6818 3 50         ((hdr[0] == 0xFE && hdr[1] == 0xFF) ||
    0          
6819 3 50         (hdr[0] == 0xFF && hdr[1] == 0xFE))) {
    0          
6820 0           err->msg = "UTF-16 encoding is not supported";
6821             }
6822             }
6823 12 50         if (!has_read_flag(INSITU)) alc.free(alc.ctx, (void *)hdr);
6824             }
6825 6274           return doc;
6826            
6827             #undef return_err
6828             }
6829              
6830 0           yyjson_doc *yyjson_read_file(const char *path,
6831             yyjson_read_flag flg,
6832             const yyjson_alc *alc_ptr,
6833             yyjson_read_err *err) {
6834             #define return_err(_code, _msg) do { \
6835             err->pos = 0; \
6836             err->msg = _msg; \
6837             err->code = YYJSON_READ_ERROR_##_code; \
6838             return NULL; \
6839             } while (false)
6840            
6841             yyjson_read_err dummy_err;
6842             yyjson_doc *doc;
6843             FILE *file;
6844            
6845 0 0         if (!err) err = &dummy_err;
6846 0 0         if (unlikely(!path)) return_err(INVALID_PARAMETER, "input path is NULL");
6847            
6848 0           file = fopen_readonly(path);
6849 0 0         if (unlikely(!file)) return_err(FILE_OPEN, "file opening failed");
6850            
6851 0           doc = yyjson_read_fp(file, flg, alc_ptr, err);
6852 0           fclose(file);
6853 0           return doc;
6854            
6855             #undef return_err
6856             }
6857              
6858 0           yyjson_doc *yyjson_read_fp(FILE *file,
6859             yyjson_read_flag flg,
6860             const yyjson_alc *alc_ptr,
6861             yyjson_read_err *err) {
6862             #define return_err(_code, _msg) do { \
6863             err->pos = 0; \
6864             err->msg = _msg; \
6865             err->code = YYJSON_READ_ERROR_##_code; \
6866             if (buf) alc.free(alc.ctx, buf); \
6867             return NULL; \
6868             } while (false)
6869            
6870             yyjson_read_err dummy_err;
6871 0 0         yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
6872             yyjson_doc *doc;
6873            
6874 0           long file_size = 0, file_pos;
6875 0           void *buf = NULL;
6876 0           usize buf_size = 0;
6877            
6878             /* validate input parameters */
6879 0 0         if (!err) err = &dummy_err;
6880 0 0         if (unlikely(!file)) return_err(INVALID_PARAMETER, "input file is NULL");
    0          
6881            
6882             /* get current position */
6883 0           file_pos = ftell(file);
6884 0 0         if (file_pos != -1) {
6885             /* get total file size, may fail */
6886 0 0         if (fseek(file, 0, SEEK_END) == 0) file_size = ftell(file);
6887             /* reset to original position, may fail */
6888 0 0         if (fseek(file, file_pos, SEEK_SET) != 0) file_size = 0;
6889             /* get file size from current postion to end */
6890 0 0         if (file_size > 0) file_size -= file_pos;
6891             }
6892            
6893             /* read file */
6894 0 0         if (file_size > 0) {
6895             /* read the entire file in one call */
6896 0           buf_size = (usize)file_size + YYJSON_PADDING_SIZE;
6897 0           buf = alc.malloc(alc.ctx, buf_size);
6898 0 0         if (buf == NULL) {
6899 0 0         return_err(MEMORY_ALLOCATION, "fail to alloc memory");
6900             }
6901 0 0         if (fread_safe(buf, (usize)file_size, file) != (usize)file_size) {
6902 0 0         return_err(FILE_READ, "file reading failed");
6903             }
6904             } else {
6905             /* failed to get file size, read it as a stream */
6906 0           usize chunk_min = (usize)64;
6907 0           usize chunk_max = (usize)512 * 1024 * 1024;
6908 0           usize chunk_now = chunk_min;
6909             usize read_size;
6910             void *tmp;
6911            
6912 0           buf_size = YYJSON_PADDING_SIZE;
6913             while (true) {
6914 0 0         if (buf_size + chunk_now < buf_size) { /* overflow */
6915 0 0         return_err(MEMORY_ALLOCATION, "fail to alloc memory");
6916             }
6917 0           buf_size += chunk_now;
6918 0 0         if (!buf) {
6919 0           buf = alc.malloc(alc.ctx, buf_size);
6920 0 0         if (!buf) return_err(MEMORY_ALLOCATION, "fail to alloc memory");
    0          
6921             } else {
6922 0           tmp = alc.realloc(alc.ctx, buf, buf_size - chunk_now, buf_size);
6923 0 0         if (!tmp) return_err(MEMORY_ALLOCATION, "fail to alloc memory");
    0          
6924 0           buf = tmp;
6925             }
6926 0           tmp = ((u8 *)buf) + buf_size - YYJSON_PADDING_SIZE - chunk_now;
6927 0           read_size = fread_safe(tmp, chunk_now, file);
6928 0           file_size += (long)read_size;
6929 0 0         if (read_size != chunk_now) break;
6930            
6931 0           chunk_now *= 2;
6932 0 0         if (chunk_now > chunk_max) chunk_now = chunk_max;
6933             }
6934             }
6935            
6936             /* read JSON */
6937 0           memset((u8 *)buf + file_size, 0, YYJSON_PADDING_SIZE);
6938 0           flg |= YYJSON_READ_INSITU;
6939 0           doc = yyjson_read_opts((char *)buf, (usize)file_size, flg, &alc, err);
6940 0 0         if (doc) {
6941 0           doc->str_pool = (char *)buf;
6942 0           return doc;
6943             } else {
6944 0           alc.free(alc.ctx, buf);
6945 0           return NULL;
6946             }
6947            
6948             #undef return_err
6949             }
6950              
6951 0           const char *yyjson_read_number(const char *dat,
6952             yyjson_val *val,
6953             yyjson_read_flag flg,
6954             const yyjson_alc *alc,
6955             yyjson_read_err *err) {
6956             #define return_err(_pos, _code, _msg) do { \
6957             err->pos = _pos > hdr ? (usize)(_pos - hdr) : 0; \
6958             err->msg = _msg; \
6959             err->code = YYJSON_READ_ERROR_##_code; \
6960             return NULL; \
6961             } while (false)
6962            
6963 0           u8 *hdr = constcast(u8 *)dat, *cur = hdr;
6964             bool raw; /* read number as raw */
6965             u8 *raw_end; /* raw end for null-terminator */
6966             u8 **pre; /* previous raw end pointer */
6967             const char *msg;
6968             yyjson_read_err dummy_err;
6969            
6970             #if !YYJSON_HAS_IEEE_754 || YYJSON_DISABLE_FAST_FP_CONV
6971             u8 buf[128];
6972             usize dat_len;
6973             #endif
6974            
6975 0 0         if (!err) err = &dummy_err;
6976 0 0         if (unlikely(!dat)) {
6977 0 0         return_err(cur, INVALID_PARAMETER, "input data is NULL");
6978             }
6979 0 0         if (unlikely(!val)) {
6980 0 0         return_err(cur, INVALID_PARAMETER, "output value is NULL");
6981             }
6982            
6983             #if !YYJSON_HAS_IEEE_754 || YYJSON_DISABLE_FAST_FP_CONV
6984             if (!alc) alc = &YYJSON_DEFAULT_ALC;
6985             dat_len = strlen(dat);
6986             if (dat_len < sizeof(buf)) {
6987             memcpy(buf, dat, dat_len + 1);
6988             hdr = buf;
6989             cur = hdr;
6990             } else {
6991             hdr = (u8 *)alc->malloc(alc->ctx, dat_len + 1);
6992             cur = hdr;
6993             if (unlikely(!hdr)) {
6994             return_err(cur, MEMORY_ALLOCATION, "memory allocation failed");
6995             }
6996             memcpy(hdr, dat, dat_len + 1);
6997             }
6998             hdr[dat_len] = 0;
6999             #endif
7000            
7001 0           raw = (flg & (YYJSON_READ_NUMBER_AS_RAW | YYJSON_READ_BIGNUM_AS_RAW)) != 0;
7002 0           raw_end = NULL;
7003 0 0         pre = raw ? &raw_end : NULL;
7004            
7005             #if !YYJSON_HAS_IEEE_754 || YYJSON_DISABLE_FAST_FP_CONV
7006             if (!read_number(&cur, pre, flg, val, &msg)) {
7007             if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr);
7008             return_err(cur, INVALID_NUMBER, msg);
7009             }
7010             if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr);
7011             if (yyjson_is_raw(val)) val->uni.str = dat;
7012             return dat + (cur - hdr);
7013             #else
7014 0 0         if (!read_number(&cur, pre, flg, val, &msg)) {
7015 0 0         return_err(cur, INVALID_NUMBER, msg);
7016             }
7017 0           return (const char *)cur;
7018             #endif
7019            
7020             #undef return_err
7021             }
7022              
7023             #endif /* YYJSON_DISABLE_READER */
7024              
7025              
7026              
7027             #if !YYJSON_DISABLE_WRITER
7028              
7029             /*==============================================================================
7030             * Integer Writer
7031             *
7032             * The maximum value of uint32_t is 4294967295 (10 digits),
7033             * these digits are named as 'aabbccddee' here.
7034             *
7035             * Although most compilers may convert the "division by constant value" into
7036             * "multiply and shift", manual conversion can still help some compilers
7037             * generate fewer and better instructions.
7038             *
7039             * Reference:
7040             * Division by Invariant Integers using Multiplication, 1994.
7041             * https://gmplib.org/~tege/divcnst-pldi94.pdf
7042             * Improved division by invariant integers, 2011.
7043             * https://gmplib.org/~tege/division-paper.pdf
7044             *============================================================================*/
7045              
7046             /** Digit table from 00 to 99. */
7047             yyjson_align(2)
7048             static const char digit_table[200] = {
7049             '0', '0', '0', '1', '0', '2', '0', '3', '0', '4',
7050             '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
7051             '1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
7052             '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
7053             '2', '0', '2', '1', '2', '2', '2', '3', '2', '4',
7054             '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
7055             '3', '0', '3', '1', '3', '2', '3', '3', '3', '4',
7056             '3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
7057             '4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
7058             '4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
7059             '5', '0', '5', '1', '5', '2', '5', '3', '5', '4',
7060             '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
7061             '6', '0', '6', '1', '6', '2', '6', '3', '6', '4',
7062             '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
7063             '7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
7064             '7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
7065             '8', '0', '8', '1', '8', '2', '8', '3', '8', '4',
7066             '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
7067             '9', '0', '9', '1', '9', '2', '9', '3', '9', '4',
7068             '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'
7069             };
7070              
7071             static_inline u8 *write_u32_len_8(u32 val, u8 *buf) {
7072             u32 aa, bb, cc, dd, aabb, ccdd; /* 8 digits: aabbccdd */
7073 7           aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
7074 7           ccdd = val - aabb * 10000; /* (val % 10000) */
7075 7           aa = (aabb * 5243) >> 19; /* (aabb / 100) */
7076 7           cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */
7077 7           bb = aabb - aa * 100; /* (aabb % 100) */
7078 7           dd = ccdd - cc * 100; /* (ccdd % 100) */
7079 7           byte_copy_2(buf + 0, digit_table + aa * 2);
7080 7           byte_copy_2(buf + 2, digit_table + bb * 2);
7081 7           byte_copy_2(buf + 4, digit_table + cc * 2);
7082 7           byte_copy_2(buf + 6, digit_table + dd * 2);
7083 7           return buf + 8;
7084             }
7085              
7086             static_inline u8 *write_u32_len_4(u32 val, u8 *buf) {
7087             u32 aa, bb; /* 4 digits: aabb */
7088 2           aa = (val * 5243) >> 19; /* (val / 100) */
7089 2           bb = val - aa * 100; /* (val % 100) */
7090 2           byte_copy_2(buf + 0, digit_table + aa * 2);
7091 2           byte_copy_2(buf + 2, digit_table + bb * 2);
7092 2           return buf + 4;
7093             }
7094              
7095             static_inline u8 *write_u32_len_1_8(u32 val, u8 *buf) {
7096             u32 aa, bb, cc, dd, aabb, bbcc, ccdd, lz;
7097            
7098 6686           if (val < 100) { /* 1-2 digits: aa */
7099 1034           lz = val < 10; /* leading zero: 0 or 1 */
7100 1034           byte_copy_2(buf + 0, digit_table + val * 2 + lz);
7101 1034           buf -= lz;
7102 1034           return buf + 2;
7103            
7104 5652 0         } else if (val < 10000) { /* 3-4 digits: aabb */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    50          
    0          
    0          
    0          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7105 5651           aa = (val * 5243) >> 19; /* (val / 100) */
7106 5651           bb = val - aa * 100; /* (val % 100) */
7107 5651           lz = aa < 10; /* leading zero: 0 or 1 */
7108 5651           byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7109 5651           buf -= lz;
7110 5651           byte_copy_2(buf + 2, digit_table + bb * 2);
7111 5651           return buf + 4;
7112            
7113 1 0         } else if (val < 1000000) { /* 5-6 digits: aabbcc */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7114 1           aa = (u32)(((u64)val * 429497) >> 32); /* (val / 10000) */
7115 1           bbcc = val - aa * 10000; /* (val % 10000) */
7116 1           bb = (bbcc * 5243) >> 19; /* (bbcc / 100) */
7117 1           cc = bbcc - bb * 100; /* (bbcc % 100) */
7118 1           lz = aa < 10; /* leading zero: 0 or 1 */
7119 1           byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7120 1           buf -= lz;
7121 1           byte_copy_2(buf + 2, digit_table + bb * 2);
7122 1           byte_copy_2(buf + 4, digit_table + cc * 2);
7123 1           return buf + 6;
7124            
7125             } else { /* 7-8 digits: aabbccdd */
7126 0           aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
7127 0           ccdd = val - aabb * 10000; /* (val % 10000) */
7128 0           aa = (aabb * 5243) >> 19; /* (aabb / 100) */
7129 0           cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */
7130 0           bb = aabb - aa * 100; /* (aabb % 100) */
7131 0           dd = ccdd - cc * 100; /* (ccdd % 100) */
7132 0           lz = aa < 10; /* leading zero: 0 or 1 */
7133 0           byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7134 0           buf -= lz;
7135 0           byte_copy_2(buf + 2, digit_table + bb * 2);
7136 0           byte_copy_2(buf + 4, digit_table + cc * 2);
7137 0           byte_copy_2(buf + 6, digit_table + dd * 2);
7138 0           return buf + 8;
7139             }
7140             }
7141              
7142             static_inline u8 *write_u64_len_5_8(u32 val, u8 *buf) {
7143             u32 aa, bb, cc, dd, aabb, bbcc, ccdd, lz;
7144            
7145 2           if (val < 1000000) { /* 5-6 digits: aabbcc */
7146 0           aa = (u32)(((u64)val * 429497) >> 32); /* (val / 10000) */
7147 0           bbcc = val - aa * 10000; /* (val % 10000) */
7148 0           bb = (bbcc * 5243) >> 19; /* (bbcc / 100) */
7149 0           cc = bbcc - bb * 100; /* (bbcc % 100) */
7150 0           lz = aa < 10; /* leading zero: 0 or 1 */
7151 0           byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7152 0           buf -= lz;
7153 0           byte_copy_2(buf + 2, digit_table + bb * 2);
7154 0           byte_copy_2(buf + 4, digit_table + cc * 2);
7155 0           return buf + 6;
7156            
7157             } else { /* 7-8 digits: aabbccdd */
7158 2           aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
7159 2           ccdd = val - aabb * 10000; /* (val % 10000) */
7160 2           aa = (aabb * 5243) >> 19; /* (aabb / 100) */
7161 2           cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */
7162 2           bb = aabb - aa * 100; /* (aabb % 100) */
7163 2           dd = ccdd - cc * 100; /* (ccdd % 100) */
7164 2           lz = aa < 10; /* leading zero: 0 or 1 */
7165 2           byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7166 2           buf -= lz;
7167 2           byte_copy_2(buf + 2, digit_table + bb * 2);
7168 2           byte_copy_2(buf + 4, digit_table + cc * 2);
7169 2           byte_copy_2(buf + 6, digit_table + dd * 2);
7170 2           return buf + 8;
7171             }
7172             }
7173              
7174             static_inline u8 *write_u64(u64 val, u8 *buf) {
7175             u64 tmp, hgh;
7176             u32 mid, low;
7177            
7178 1688 50         if (val < 100000000) { /* 1-8 digits */
    100          
    100          
    0          
    0          
    0          
7179 1681 50         buf = write_u32_len_1_8((u32)val, buf);
    100          
    100          
    0          
    0          
    0          
7180 1681           return buf;
7181            
7182 7 0         } else if (val < (u64)100000000 * 100000000) { /* 9-16 digits */
    50          
    100          
    0          
    0          
    0          
7183 5           hgh = val / 100000000; /* (val / 100000000) */
7184 5           low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
7185 10 0         buf = write_u32_len_1_8((u32)hgh, buf);
    50          
    50          
    0          
    0          
    0          
7186 5           buf = write_u32_len_8(low, buf);
7187 5           return buf;
7188            
7189             } else { /* 17-20 digits */
7190 2           tmp = val / 100000000; /* (val / 100000000) */
7191 2           low = (u32)(val - tmp * 100000000); /* (val % 100000000) */
7192 2           hgh = (u32)(tmp / 10000); /* (tmp / 10000) */
7193 2           mid = (u32)(tmp - hgh * 10000); /* (tmp % 10000) */
7194 4 0         buf = write_u64_len_5_8((u32)hgh, buf);
    0          
    50          
    0          
    0          
    0          
7195 2           buf = write_u32_len_4(mid, buf);
7196 2           buf = write_u32_len_8(low, buf);
7197 2           return buf;
7198             }
7199             }
7200              
7201              
7202              
7203             /*==============================================================================
7204             * Number Writer
7205             *============================================================================*/
7206              
7207             #if YYJSON_HAS_IEEE_754 && !YYJSON_DISABLE_FAST_FP_CONV /* FP_WRITER */
7208              
7209             /** Trailing zero count table for number 0 to 99.
7210             (generate with misc/make_tables.c) */
7211             static const u8 dec_trailing_zero_table[] = {
7212             2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7213             1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7214             1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7215             1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7216             1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7217             1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7218             1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7219             1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7220             1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7221             1, 0, 0, 0, 0, 0, 0, 0, 0, 0
7222             };
7223              
7224             /** Write an unsigned integer with a length of 1 to 16. */
7225             static_inline u8 *write_u64_len_1_to_16(u64 val, u8 *buf) {
7226             u64 hgh;
7227             u32 low;
7228 5000           if (val < 100000000) { /* 1-8 digits */
7229 5000 0         buf = write_u32_len_1_8((u32)val, buf);
    0          
    100          
    0          
    0          
    0          
7230 5000           return buf;
7231             } else { /* 9-16 digits */
7232 0           hgh = val / 100000000; /* (val / 100000000) */
7233 0           low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
7234 0 0         buf = write_u32_len_1_8((u32)hgh, buf);
    0          
    0          
    0          
    0          
    0          
7235 0           buf = write_u32_len_8(low, buf);
7236 0           return buf;
7237             }
7238             }
7239              
7240             /** Write an unsigned integer with a length of 1 to 17. */
7241             static_inline u8 *write_u64_len_1_to_17(u64 val, u8 *buf) {
7242             u64 hgh;
7243             u32 mid, low, one;
7244 0           if (val >= (u64)100000000 * 10000000) { /* len: 16 to 17 */
7245 0           hgh = val / 100000000; /* (val / 100000000) */
7246 0           low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
7247 0           one = (u32)(hgh / 100000000); /* (hgh / 100000000) */
7248 0           mid = (u32)(hgh - (u64)one * 100000000); /* (hgh % 100000000) */
7249 0           *buf = (u8)((u8)one + (u8)'0');
7250 0           buf += one > 0;
7251 0           buf = write_u32_len_8(mid, buf);
7252 0           buf = write_u32_len_8(low, buf);
7253 0           return buf;
7254 0 0         } else if (val >= (u64)100000000){ /* len: 9 to 15 */
    0          
    0          
    0          
    0          
    0          
7255 0           hgh = val / 100000000; /* (val / 100000000) */
7256 0           low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
7257 0 0         buf = write_u32_len_1_8((u32)hgh, buf);
    0          
    0          
    0          
    0          
    0          
7258 0           buf = write_u32_len_8(low, buf);
7259 0           return buf;
7260             } else { /* len: 1 to 8 */
7261 0 0         buf = write_u32_len_1_8((u32)val, buf);
    0          
    0          
    0          
    0          
    0          
7262 0           return buf;
7263             }
7264             }
7265              
7266             /**
7267             Write an unsigned integer with a length of 15 to 17 with trailing zero trimmed.
7268             These digits are named as "aabbccddeeffgghhii" here.
7269             For example, input 1234567890123000, output "1234567890123".
7270             */
7271             static_inline u8 *write_u64_len_15_to_17_trim(u8 *buf, u64 sig) {
7272             bool lz; /* leading zero */
7273             u32 tz1, tz2, tz; /* trailing zero */
7274            
7275 1016           u32 abbccddee = (u32)(sig / 100000000);
7276 1016           u32 ffgghhii = (u32)(sig - (u64)abbccddee * 100000000);
7277 1016           u32 abbcc = abbccddee / 10000; /* (abbccddee / 10000) */
7278 1016           u32 ddee = abbccddee - abbcc * 10000; /* (abbccddee % 10000) */
7279 1016           u32 abb = (u32)(((u64)abbcc * 167773) >> 24); /* (abbcc / 100) */
7280 1016           u32 a = (abb * 41) >> 12; /* (abb / 100) */
7281 1016           u32 bb = abb - a * 100; /* (abb % 100) */
7282 1016           u32 cc = abbcc - abb * 100; /* (abbcc % 100) */
7283            
7284             /* write abbcc */
7285 1016           buf[0] = (u8)(a + '0');
7286 1016           buf += a > 0;
7287 1016 0         lz = bb < 10 && a == 0;
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7288 1016           byte_copy_2(buf + 0, digit_table + bb * 2 + lz);
7289 1016           buf -= lz;
7290 1016           byte_copy_2(buf + 2, digit_table + cc * 2);
7291            
7292 1016 50         if (ffgghhii) {
    0          
    0          
    0          
    0          
    0          
    50          
    100          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7293 3           u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */
7294 3           u32 ee = ddee - dd * 100; /* (ddee % 100) */
7295 3           u32 ffgg = (u32)(((u64)ffgghhii * 109951163) >> 40); /* (val / 10000) */
7296 3           u32 hhii = ffgghhii - ffgg * 10000; /* (val % 10000) */
7297 3           u32 ff = (ffgg * 5243) >> 19; /* (aabb / 100) */
7298 3           u32 gg = ffgg - ff * 100; /* (aabb % 100) */
7299 3           byte_copy_2(buf + 4, digit_table + dd * 2);
7300 3           byte_copy_2(buf + 6, digit_table + ee * 2);
7301 3           byte_copy_2(buf + 8, digit_table + ff * 2);
7302 3           byte_copy_2(buf + 10, digit_table + gg * 2);
7303 3 0         if (hhii) {
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7304 3           u32 hh = (hhii * 5243) >> 19; /* (ccdd / 100) */
7305 3           u32 ii = hhii - hh * 100; /* (ccdd % 100) */
7306 3           byte_copy_2(buf + 12, digit_table + hh * 2);
7307 3           byte_copy_2(buf + 14, digit_table + ii * 2);
7308 3           tz1 = dec_trailing_zero_table[hh];
7309 3           tz2 = dec_trailing_zero_table[ii];
7310 3 0         tz = ii ? tz2 : (tz1 + 2);
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7311 3           buf += 16 - tz;
7312 3           return buf;
7313             } else {
7314 0           tz1 = dec_trailing_zero_table[ff];
7315 0           tz2 = dec_trailing_zero_table[gg];
7316 0 0         tz = gg ? tz2 : (tz1 + 2);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7317 0           buf += 12 - tz;
7318 0           return buf;
7319             }
7320             } else {
7321 1013 50         if (ddee) {
    0          
    0          
    0          
    0          
    0          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7322 658           u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */
7323 658           u32 ee = ddee - dd * 100; /* (ddee % 100) */
7324 658           byte_copy_2(buf + 4, digit_table + dd * 2);
7325 658           byte_copy_2(buf + 6, digit_table + ee * 2);
7326 658           tz1 = dec_trailing_zero_table[dd];
7327 658           tz2 = dec_trailing_zero_table[ee];
7328 658 0         tz = ee ? tz2 : (tz1 + 2);
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7329 658           buf += 8 - tz;
7330 658           return buf;
7331             } else {
7332 355           tz1 = dec_trailing_zero_table[bb];
7333 355           tz2 = dec_trailing_zero_table[cc];
7334 355 50         tz = cc ? tz2 : (tz1 + tz2);
    0          
    0          
    0          
    0          
    0          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7335 355           buf += 4 - tz;
7336 355           return buf;
7337             }
7338             }
7339             }
7340              
7341             /** Write a signed integer in the range -324 to 308. */
7342             static_inline u8 *write_f64_exp(i32 exp, u8 *buf) {
7343 3           buf[0] = '-';
7344 3           buf += exp < 0;
7345 3           exp = exp < 0 ? -exp : exp;
7346 3           if (exp < 100) {
7347 0           u32 lz = exp < 10;
7348 0           byte_copy_2(buf + 0, digit_table + (u32)exp * 2 + lz);
7349 0           return buf + 2 - lz;
7350             } else {
7351 3           u32 hi = ((u32)exp * 656) >> 16; /* exp / 100 */
7352 3           u32 lo = (u32)exp - hi * 100; /* exp % 100 */
7353 3           buf[0] = (u8)((u8)hi + (u8)'0');
7354 3           byte_copy_2(buf + 1, digit_table + lo * 2);
7355 3           return buf + 3;
7356             }
7357             }
7358              
7359             /** Multiplies 128-bit integer and returns highest 64-bit rounded value. */
7360             static_inline u64 round_to_odd(u64 hi, u64 lo, u64 cp) {
7361             u64 x_hi, x_lo, y_hi, y_lo;
7362             u128_mul(cp, lo, &x_hi, &x_lo);
7363 3048           u128_mul_add(cp, hi, x_hi, &y_hi, &y_lo);
7364 3048           return y_hi | (y_lo > 1);
7365             }
7366              
7367             /**
7368             Convert double number from binary to decimal.
7369             The output significand is shortest decimal but may have trailing zeros.
7370            
7371             This function use the Schubfach algorithm:
7372             Raffaello Giulietti, The Schubfach way to render doubles (5th version), 2022.
7373             https://drive.google.com/file/d/1gp5xv4CAa78SVgCeWfGqqI4FfYYYuNFb
7374             https://mail.openjdk.java.net/pipermail/core-libs-dev/2021-November/083536.html
7375             https://github.com/openjdk/jdk/pull/3402 (Java implementation)
7376             https://github.com/abolz/Drachennest (C++ implementation)
7377            
7378             See also:
7379             Dragonbox: A New Floating-Point Binary-to-Decimal Conversion Algorithm, 2022.
7380             https://github.com/jk-jeon/dragonbox/blob/master/other_files/Dragonbox.pdf
7381             https://github.com/jk-jeon/dragonbox
7382            
7383             @param sig_raw The raw value of significand in IEEE 754 format.
7384             @param exp_raw The raw value of exponent in IEEE 754 format.
7385             @param sig_bin The decoded value of significand in binary.
7386             @param exp_bin The decoded value of exponent in binary.
7387             @param sig_dec The output value of significand in decimal.
7388             @param exp_dec The output value of exponent in decimal.
7389             @warning The input double number should not be 0, inf, nan.
7390             */
7391             static_inline void f64_bin_to_dec(u64 sig_raw, u32 exp_raw,
7392             u64 sig_bin, i32 exp_bin,
7393             u64 *sig_dec, i32 *exp_dec) {
7394            
7395             bool is_even, regular_spacing, u_inside, w_inside, round_up;
7396             u64 s, sp, cb, cbl, cbr, vb, vbl, vbr, pow10hi, pow10lo, upper, lower, mid;
7397             i32 k, h, exp10;
7398            
7399 1016           is_even = !(sig_bin & 1);
7400 1016 50         regular_spacing = (sig_raw == 0 && exp_raw > 1);
    50          
    0          
    0          
    0          
    0          
    100          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7401            
7402 1016           cbl = 4 * sig_bin - 2 + regular_spacing;
7403 1016           cb = 4 * sig_bin;
7404 1016           cbr = 4 * sig_bin + 2;
7405            
7406             /* exp_bin: [-1074, 971] */
7407             /* k = regular_spacing ? floor(log10(pow(2, exp_bin))) */
7408             /* : floor(log10(pow(2, exp_bin) * 3.0 / 4.0)) */
7409             /* = regular_spacing ? floor(exp_bin * log10(2)) */
7410             /* : floor(exp_bin * log10(2) + log10(3.0 / 4.0)) */
7411 1016 50         k = (i32)(exp_bin * 315653 - (regular_spacing ? 131237 : 0)) >> 20;
    0          
    0          
    0          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7412            
7413             /* k: [-324, 292] */
7414             /* h = exp_bin + floor(log2(pow(10, e))) */
7415             /* = exp_bin + floor(log2(10) * e) */
7416 1016           exp10 = -k;
7417 1016           h = exp_bin + ((exp10 * 217707) >> 16) + 1;
7418            
7419             pow10_table_get_sig(exp10, &pow10hi, &pow10lo);
7420 1016 50         pow10lo += (exp10 < POW10_SIG_TABLE_MIN_EXACT_EXP ||
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7421             exp10 > POW10_SIG_TABLE_MAX_EXACT_EXP);
7422 1016           vbl = round_to_odd(pow10hi, pow10lo, cbl << h);
7423 1016           vb = round_to_odd(pow10hi, pow10lo, cb << h);
7424 1016           vbr = round_to_odd(pow10hi, pow10lo, cbr << h);
7425            
7426 1016           lower = vbl + !is_even;
7427 1016           upper = vbr - !is_even;
7428            
7429 1016           s = vb / 4;
7430 1016 50         if (s >= 10) {
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7431 1016           sp = s / 10;
7432 1016           u_inside = (lower <= 40 * sp);
7433 1016           w_inside = (upper >= 40 * sp + 40);
7434 1016 50         if (u_inside != w_inside) {
    0          
    0          
    0          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7435 1014           *sig_dec = sp + w_inside;
7436 1014           *exp_dec = k + 1;
7437 1014           return;
7438             }
7439             }
7440            
7441 2           u_inside = (lower <= 4 * s);
7442 2           w_inside = (upper >= 4 * s + 4);
7443            
7444 2           mid = 4 * s + 2;
7445 2 0         round_up = (vb > mid) || (vb == mid && (s & 1) != 0);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7446            
7447 2 0         *sig_dec = s + ((u_inside != w_inside) ? w_inside : round_up);
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7448 2           *exp_dec = k;
7449             }
7450              
7451             /**
7452             Write a double number (requires 32 bytes buffer).
7453            
7454             We follows the ECMAScript specification to print floating point numbers,
7455             but with the following changes:
7456             1. Keep the negative sign of 0.0 to preserve input information.
7457             2. Keep decimal point to indicate the number is floating point.
7458             3. Remove positive sign of exponent part.
7459             */
7460             static_inline u8 *write_f64_raw(u8 *buf, u64 raw, yyjson_write_flag flg) {
7461             u64 sig_bin, sig_dec, sig_raw;
7462             i32 exp_bin, exp_dec, sig_len, dot_pos, i, max;
7463             u32 exp_raw, hi, lo;
7464             u8 *hdr, *num_hdr, *num_end, *dot_end;
7465             bool sign;
7466            
7467             /* decode raw bytes from IEEE-754 double format. */
7468 6019           sign = (bool)(raw >> (F64_BITS - 1));
7469 6019           sig_raw = raw & F64_SIG_MASK;
7470 6019           exp_raw = (u32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
7471            
7472             /* return inf and nan */
7473 6019           if (unlikely(exp_raw == ((u32)1 << F64_EXP_BITS) - 1)) {
7474 6 0         if (has_write_flag(INF_AND_NAN_AS_NULL)) {
    0          
    50          
    0          
    0          
    0          
7475             byte_copy_4(buf, "null");
7476 0           return buf + 4;
7477             }
7478 6 0         else if (has_write_flag(ALLOW_INF_AND_NAN)) {
    0          
    50          
    0          
    0          
    0          
7479 3 0         if (sig_raw == 0) {
    0          
    100          
    0          
    0          
    0          
7480 2           buf[0] = '-';
7481 2           buf += sign;
7482             byte_copy_8(buf, "Infinity");
7483 2           buf += 8;
7484 2           return buf;
7485             } else {
7486             byte_copy_4(buf, "NaN");
7487 1           return buf + 3;
7488             }
7489             }
7490 0           return NULL;
7491             }
7492            
7493             /* add sign for all finite double value, including 0.0 and inf */
7494 6016           buf[0] = '-';
7495 6016           buf += sign;
7496 6016           hdr = buf;
7497            
7498             /* return zero */
7499 6016 50         if ((raw << 1) == 0) {
    0          
    50          
    0          
    0          
    0          
7500             byte_copy_4(buf, "0.0");
7501 0           buf += 3;
7502 0           return buf;
7503             }
7504            
7505 6016 50         if (likely(exp_raw != 0)) {
    0          
    50          
    0          
    0          
    0          
7506             /* normal number */
7507 6016           sig_bin = sig_raw | ((u64)1 << F64_SIG_BITS);
7508 6016           exp_bin = (i32)exp_raw - F64_EXP_BIAS - F64_SIG_BITS;
7509            
7510             /* fast path for small integer number without fraction */
7511 6016 50         if (-F64_SIG_BITS <= exp_bin && exp_bin <= 0) {
    0          
    0          
    0          
    100          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
7512 6010 0         if (u64_tz_bits(sig_bin) >= (u32)-exp_bin) {
    0          
    100          
    0          
    0          
    0          
7513             /* number is integer in range 1 to 0x1FFFFFFFFFFFFF */
7514 5000           sig_dec = sig_bin >> -exp_bin;
7515 10000 0         buf = write_u64_len_1_to_16(sig_dec, buf);
    0          
    50          
    0          
    0          
    0          
7516             byte_copy_2(buf, ".0");
7517 5000           buf += 2;
7518 5000           return buf;
7519             }
7520             }
7521            
7522             /* binary to decimal */
7523             f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
7524            
7525             /* the sig length is 15 to 17 */
7526 1016           sig_len = 17;
7527 1016           sig_len -= (sig_dec < (u64)100000000 * 100000000);
7528 1016           sig_len -= (sig_dec < (u64)100000000 * 10000000);
7529            
7530             /* the decimal point position relative to the first digit */
7531 1016           dot_pos = sig_len + exp_dec;
7532            
7533 1016 50         if (-6 < dot_pos && dot_pos <= 21) {
    50          
    0          
    0          
    100          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
7534             /* no need to write exponent part */
7535 1013 50         if (dot_pos <= 0) {
    0          
    100          
    0          
    0          
    0          
7536             /* dot before first digit */
7537             /* such as 0.1234, 0.000001234 */
7538 3           num_hdr = hdr + (2 - dot_pos);
7539 3 50         num_end = write_u64_len_15_to_17_trim(num_hdr, sig_dec);
    0          
    50          
    0          
    0          
    0          
7540 3           hdr[0] = '0';
7541 3           hdr[1] = '.';
7542 3           hdr += 2;
7543 3           max = -dot_pos;
7544 3 50         for (i = 0; i < max; i++) hdr[i] = '0';
    0          
    50          
    0          
    0          
    0          
7545 3           return num_end;
7546             } else {
7547             /* dot after first digit */
7548             /* such as 1.234, 1234.0, 123400000000000000000.0 */
7549 1010           memset(hdr + 0, '0', 8);
7550 1010           memset(hdr + 8, '0', 8);
7551 1010           memset(hdr + 16, '0', 8);
7552 1010           num_hdr = hdr + 1;
7553 1010 0         num_end = write_u64_len_15_to_17_trim(num_hdr, sig_dec);
    0          
    100          
    0          
    0          
    0          
7554 4288 0         for (i = 0; i < dot_pos; i++) hdr[i] = hdr[i + 1];
    0          
    100          
    0          
    0          
    0          
7555 1010           hdr[dot_pos] = '.';
7556 1010           dot_end = hdr + dot_pos + 2;
7557 1010           return dot_end < num_end ? num_end : dot_end;
7558             }
7559             } else {
7560             /* write with scientific notation */
7561             /* such as 1.234e56 */
7562 3 0         u8 *end = write_u64_len_15_to_17_trim(buf + 1, sig_dec);
    0          
    50          
    0          
    0          
    0          
7563 3           end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */
7564 3           exp_dec += sig_len - 1;
7565 3           hdr[0] = hdr[1];
7566 3           hdr[1] = '.';
7567 3           end[0] = 'e';
7568 3 0         buf = write_f64_exp(exp_dec, end + 1);
    0          
    50          
    0          
    0          
    0          
7569 3           return buf;
7570             }
7571            
7572             } else {
7573             /* subnormal number */
7574 0           sig_bin = sig_raw;
7575 0 0         exp_bin = 1 - F64_EXP_BIAS - F64_SIG_BITS;
    0          
    0          
    0          
    0          
    0          
7576            
7577             /* binary to decimal */
7578             f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
7579            
7580             /* write significand part */
7581 0 0         buf = write_u64_len_1_to_17(sig_dec, buf + 1);
    0          
    0          
    0          
    0          
    0          
7582 0           hdr[0] = hdr[1];
7583 0           hdr[1] = '.';
7584             do {
7585 0           buf--;
7586 0           exp_dec++;
7587 0 0         } while (*buf == '0');
    0          
    0          
    0          
    0          
    0          
7588 0           exp_dec += (i32)(buf - hdr - 2);
7589 0           buf += (*buf != '.');
7590 0           buf[0] = 'e';
7591 0           buf++;
7592            
7593             /* write exponent part */
7594 0           buf[0] = '-';
7595 0           buf++;
7596 0           exp_dec = -exp_dec;
7597 0           hi = ((u32)exp_dec * 656) >> 16; /* exp / 100 */
7598 0           lo = (u32)exp_dec - hi * 100; /* exp % 100 */
7599 0           buf[0] = (u8)((u8)hi + (u8)'0');
7600 0           byte_copy_2(buf + 1, digit_table + lo * 2);
7601 0           buf += 3;
7602 0           return buf;
7603             }
7604             }
7605              
7606             #else /* FP_WRITER */
7607              
7608             /** Write a double number (requires 32 bytes buffer). */
7609             static_inline u8 *write_f64_raw(u8 *buf, u64 raw, yyjson_write_flag flg) {
7610             /*
7611             For IEEE 754, `DBL_DECIMAL_DIG` is 17 for round-trip.
7612             For non-IEEE formats, 17 is used to avoid buffer overflow,
7613             round-trip is not guaranteed.
7614             */
7615             #if defined(DBL_DECIMAL_DIG) && DBL_DECIMAL_DIG != 17
7616             int dig = DBL_DECIMAL_DIG > 17 ? 17 : DBL_DECIMAL_DIG;
7617             #else
7618             int dig = 17;
7619             #endif
7620            
7621             /*
7622             The snprintf() function is locale-dependent. For currently known locales,
7623             (en, zh, ja, ko, am, he, hi) use '.' as the decimal point, while other
7624             locales use ',' as the decimal point. we need to replace ',' with '.'
7625             to avoid the locale setting.
7626             */
7627             f64 val = f64_from_raw(raw);
7628             #if YYJSON_MSC_VER >= 1400
7629             int len = sprintf_s((char *)buf, 32, "%.*g", dig, val);
7630             #elif defined(snprintf) || (YYJSON_STDC_VER >= 199901L)
7631             int len = snprintf((char *)buf, 32, "%.*g", dig, val);
7632             #else
7633             int len = sprintf((char *)buf, "%.*g", dig, val);
7634             #endif
7635            
7636             u8 *cur = buf;
7637             if (unlikely(len < 1)) return NULL;
7638             cur += (*cur == '-');
7639             if (unlikely(!digi_is_digit(*cur))) {
7640             /* nan, inf, or bad output */
7641             if (has_write_flag(INF_AND_NAN_AS_NULL)) {
7642             byte_copy_4(buf, "null");
7643             return buf + 4;
7644             }
7645             else if (has_write_flag(ALLOW_INF_AND_NAN)) {
7646             if (*cur == 'i') {
7647             byte_copy_8(cur, "Infinity");
7648             cur += 8;
7649             return cur;
7650             } else if (*cur == 'n') {
7651             byte_copy_4(buf, "NaN");
7652             return buf + 3;
7653             }
7654             }
7655             return NULL;
7656             } else {
7657             /* finite number */
7658             int i = 0;
7659             bool fp = false;
7660             for (; i < len; i++) {
7661             if (buf[i] == ',') buf[i] = '.';
7662             if (digi_is_fp((u8)buf[i])) fp = true;
7663             }
7664             if (!fp) {
7665             buf[len++] = '.';
7666             buf[len++] = '0';
7667             }
7668             }
7669             return buf + len;
7670             }
7671              
7672             #endif /* FP_WRITER */
7673              
7674             /** Write a JSON number (requires 32 bytes buffer). */
7675             static_inline u8 *write_number(u8 *cur, yyjson_val *val,
7676             yyjson_write_flag flg) {
7677 7629 100         if (val->tag & YYJSON_SUBTYPE_REAL) {
    0          
7678 6019 50         u64 raw = val->uni.u64;
    0          
    100          
    0          
    0          
    0          
7679 6019           return write_f64_raw(cur, raw, flg);
7680             } else {
7681 1688           u64 pos = val->uni.u64;
7682 1688           u64 neg = ~pos + 1;
7683 1688           usize sgn = ((val->tag & YYJSON_SUBTYPE_SINT) > 0) & ((i64)pos < 0);
7684 1688           *cur = '-';
7685 3376 100         return write_u64(sgn ? neg : pos, cur + sgn);
    50          
    50          
    0          
    0          
    0          
7686             }
7687             }
7688              
7689              
7690              
7691             /*==============================================================================
7692             * String Writer
7693             *============================================================================*/
7694              
7695             /** Character encode type, if (type > CHAR_ENC_ERR_1) bytes = type / 2; */
7696             typedef u8 char_enc_type;
7697             #define CHAR_ENC_CPY_1 0 /* 1-byte UTF-8, copy. */
7698             #define CHAR_ENC_ERR_1 1 /* 1-byte UTF-8, error. */
7699             #define CHAR_ENC_ESC_A 2 /* 1-byte ASCII, escaped as '\x'. */
7700             #define CHAR_ENC_ESC_1 3 /* 1-byte UTF-8, escaped as '\uXXXX'. */
7701             #define CHAR_ENC_CPY_2 4 /* 2-byte UTF-8, copy. */
7702             #define CHAR_ENC_ESC_2 5 /* 2-byte UTF-8, escaped as '\uXXXX'. */
7703             #define CHAR_ENC_CPY_3 6 /* 3-byte UTF-8, copy. */
7704             #define CHAR_ENC_ESC_3 7 /* 3-byte UTF-8, escaped as '\uXXXX'. */
7705             #define CHAR_ENC_CPY_4 8 /* 4-byte UTF-8, copy. */
7706             #define CHAR_ENC_ESC_4 9 /* 4-byte UTF-8, escaped as '\uXXXX\uXXXX'. */
7707              
7708             /** Character encode type table: don't escape unicode, don't escape '/'.
7709             (generate with misc/make_tables.c) */
7710             static const char_enc_type enc_table_cpy[256] = {
7711             3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
7712             3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7713             0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7714             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7715             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7716             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
7717             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7718             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7719             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7720             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7721             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7722             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7723             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7724             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7725             6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7726             8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1
7727             };
7728              
7729             /** Character encode type table: don't escape unicode, escape '/'.
7730             (generate with misc/make_tables.c) */
7731             static const char_enc_type enc_table_cpy_slash[256] = {
7732             3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
7733             3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7734             0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
7735             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7736             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7737             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
7738             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7739             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7740             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7741             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7742             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7743             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7744             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7745             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7746             6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7747             8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1
7748             };
7749              
7750             /** Character encode type table: escape unicode, don't escape '/'.
7751             (generate with misc/make_tables.c) */
7752             static const char_enc_type enc_table_esc[256] = {
7753             3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
7754             3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7755             0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7756             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7757             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7758             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
7759             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7760             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7761             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7762             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7763             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7764             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7765             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7766             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7767             7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7768             9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1
7769             };
7770              
7771             /** Character encode type table: escape unicode, escape '/'.
7772             (generate with misc/make_tables.c) */
7773             static const char_enc_type enc_table_esc_slash[256] = {
7774             3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
7775             3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7776             0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
7777             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7778             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7779             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
7780             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7781             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7782             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7783             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7784             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7785             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7786             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7787             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7788             7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7789             9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1
7790             };
7791              
7792             /** Escaped hex character table: ["00" "01" "02" ... "FD" "FE" "FF"].
7793             (generate with misc/make_tables.c) */
7794             yyjson_align(2)
7795             static const u8 esc_hex_char_table[512] = {
7796             '0', '0', '0', '1', '0', '2', '0', '3',
7797             '0', '4', '0', '5', '0', '6', '0', '7',
7798             '0', '8', '0', '9', '0', 'A', '0', 'B',
7799             '0', 'C', '0', 'D', '0', 'E', '0', 'F',
7800             '1', '0', '1', '1', '1', '2', '1', '3',
7801             '1', '4', '1', '5', '1', '6', '1', '7',
7802             '1', '8', '1', '9', '1', 'A', '1', 'B',
7803             '1', 'C', '1', 'D', '1', 'E', '1', 'F',
7804             '2', '0', '2', '1', '2', '2', '2', '3',
7805             '2', '4', '2', '5', '2', '6', '2', '7',
7806             '2', '8', '2', '9', '2', 'A', '2', 'B',
7807             '2', 'C', '2', 'D', '2', 'E', '2', 'F',
7808             '3', '0', '3', '1', '3', '2', '3', '3',
7809             '3', '4', '3', '5', '3', '6', '3', '7',
7810             '3', '8', '3', '9', '3', 'A', '3', 'B',
7811             '3', 'C', '3', 'D', '3', 'E', '3', 'F',
7812             '4', '0', '4', '1', '4', '2', '4', '3',
7813             '4', '4', '4', '5', '4', '6', '4', '7',
7814             '4', '8', '4', '9', '4', 'A', '4', 'B',
7815             '4', 'C', '4', 'D', '4', 'E', '4', 'F',
7816             '5', '0', '5', '1', '5', '2', '5', '3',
7817             '5', '4', '5', '5', '5', '6', '5', '7',
7818             '5', '8', '5', '9', '5', 'A', '5', 'B',
7819             '5', 'C', '5', 'D', '5', 'E', '5', 'F',
7820             '6', '0', '6', '1', '6', '2', '6', '3',
7821             '6', '4', '6', '5', '6', '6', '6', '7',
7822             '6', '8', '6', '9', '6', 'A', '6', 'B',
7823             '6', 'C', '6', 'D', '6', 'E', '6', 'F',
7824             '7', '0', '7', '1', '7', '2', '7', '3',
7825             '7', '4', '7', '5', '7', '6', '7', '7',
7826             '7', '8', '7', '9', '7', 'A', '7', 'B',
7827             '7', 'C', '7', 'D', '7', 'E', '7', 'F',
7828             '8', '0', '8', '1', '8', '2', '8', '3',
7829             '8', '4', '8', '5', '8', '6', '8', '7',
7830             '8', '8', '8', '9', '8', 'A', '8', 'B',
7831             '8', 'C', '8', 'D', '8', 'E', '8', 'F',
7832             '9', '0', '9', '1', '9', '2', '9', '3',
7833             '9', '4', '9', '5', '9', '6', '9', '7',
7834             '9', '8', '9', '9', '9', 'A', '9', 'B',
7835             '9', 'C', '9', 'D', '9', 'E', '9', 'F',
7836             'A', '0', 'A', '1', 'A', '2', 'A', '3',
7837             'A', '4', 'A', '5', 'A', '6', 'A', '7',
7838             'A', '8', 'A', '9', 'A', 'A', 'A', 'B',
7839             'A', 'C', 'A', 'D', 'A', 'E', 'A', 'F',
7840             'B', '0', 'B', '1', 'B', '2', 'B', '3',
7841             'B', '4', 'B', '5', 'B', '6', 'B', '7',
7842             'B', '8', 'B', '9', 'B', 'A', 'B', 'B',
7843             'B', 'C', 'B', 'D', 'B', 'E', 'B', 'F',
7844             'C', '0', 'C', '1', 'C', '2', 'C', '3',
7845             'C', '4', 'C', '5', 'C', '6', 'C', '7',
7846             'C', '8', 'C', '9', 'C', 'A', 'C', 'B',
7847             'C', 'C', 'C', 'D', 'C', 'E', 'C', 'F',
7848             'D', '0', 'D', '1', 'D', '2', 'D', '3',
7849             'D', '4', 'D', '5', 'D', '6', 'D', '7',
7850             'D', '8', 'D', '9', 'D', 'A', 'D', 'B',
7851             'D', 'C', 'D', 'D', 'D', 'E', 'D', 'F',
7852             'E', '0', 'E', '1', 'E', '2', 'E', '3',
7853             'E', '4', 'E', '5', 'E', '6', 'E', '7',
7854             'E', '8', 'E', '9', 'E', 'A', 'E', 'B',
7855             'E', 'C', 'E', 'D', 'E', 'E', 'E', 'F',
7856             'F', '0', 'F', '1', 'F', '2', 'F', '3',
7857             'F', '4', 'F', '5', 'F', '6', 'F', '7',
7858             'F', '8', 'F', '9', 'F', 'A', 'F', 'B',
7859             'F', 'C', 'F', 'D', 'F', 'E', 'F', 'F'
7860             };
7861              
7862             /** Escaped single character table. (generate with misc/make_tables.c) */
7863             yyjson_align(2)
7864             static const u8 esc_single_char_table[512] = {
7865             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7866             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7867             '\\', 'b', '\\', 't', '\\', 'n', ' ', ' ',
7868             '\\', 'f', '\\', 'r', ' ', ' ', ' ', ' ',
7869             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7870             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7871             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7872             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7873             ' ', ' ', ' ', ' ', '\\', '"', ' ', ' ',
7874             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7875             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7876             ' ', ' ', ' ', ' ', ' ', ' ', '\\', '/',
7877             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7878             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7879             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7880             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7881             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7882             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7883             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7884             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7885             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7886             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7887             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7888             '\\', '\\', ' ', ' ', ' ', ' ', ' ', ' ',
7889             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7890             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7891             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7892             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7893             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7894             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7895             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7896             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7897             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7898             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7899             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7900             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7901             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7902             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7903             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7904             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7905             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7906             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7907             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7908             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7909             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7910             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7911             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7912             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7913             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7914             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7915             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7916             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7917             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7918             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7919             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7920             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7921             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7922             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7923             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7924             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7925             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7926             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7927             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7928             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
7929             };
7930              
7931             /** Returns the encode table with options. */
7932             static_inline const char_enc_type *get_enc_table_with_flag(
7933             yyjson_write_flag flg) {
7934 2274 50         if (has_write_flag(ESCAPE_UNICODE)) {
    50          
    50          
    0          
    0          
    0          
7935 0 0         if (has_write_flag(ESCAPE_SLASHES)) {
    0          
    0          
    0          
    0          
    0          
7936 0           return enc_table_esc_slash;
7937             } else {
7938 0           return enc_table_esc;
7939             }
7940             } else {
7941 2300 50         if (has_write_flag(ESCAPE_SLASHES)) {
    50          
    50          
    0          
    0          
    0          
7942 0           return enc_table_cpy_slash;
7943             } else {
7944 1150           return enc_table_cpy;
7945             }
7946             }
7947             }
7948              
7949             /** Write raw string. */
7950             static_inline u8 *write_raw(u8 *cur, const u8 *raw, usize raw_len) {
7951 0           memcpy(cur, raw, raw_len);
7952 0           return cur + raw_len;
7953             }
7954              
7955             /**
7956             Write string no-escape.
7957             @param cur Buffer cursor.
7958             @param str A UTF-8 string, null-terminator is not required.
7959             @param str_len Length of string in bytes.
7960             @return The buffer cursor after string.
7961             */
7962             static_inline u8 *write_string_noesc(u8 *cur, const u8 *str, usize str_len) {
7963 0           *cur++ = '"';
7964 0 0         while (str_len >= 16) {
    0          
    0          
    0          
    0          
    0          
7965             byte_copy_16(cur, str);
7966 0           cur += 16;
7967 0           str += 16;
7968 0           str_len -= 16;
7969             }
7970 0 0         while (str_len >= 4) {
    0          
    0          
    0          
    0          
    0          
7971             byte_copy_4(cur, str);
7972 0           cur += 4;
7973 0           str += 4;
7974 0           str_len -= 4;
7975             }
7976 0 0         while (str_len) {
    0          
    0          
    0          
    0          
    0          
7977 0           *cur++ = *str++;
7978 0           str_len -= 1;
7979             }
7980 0           *cur++ = '"';
7981 0           return cur;
7982             }
7983              
7984             /**
7985             Write UTF-8 string (requires len * 6 + 2 bytes buffer).
7986             @param cur Buffer cursor.
7987             @param esc Escape unicode.
7988             @param inv Allow invalid unicode.
7989             @param str A UTF-8 string, null-terminator is not required.
7990             @param str_len Length of string in bytes.
7991             @param enc_table Encode type table for character.
7992             @return The buffer cursor after string, or NULL on invalid unicode.
7993             */
7994             static_inline u8 *write_string(u8 *cur, bool esc, bool inv,
7995             const u8 *str, usize str_len,
7996             const char_enc_type *enc_table) {
7997            
7998             /* UTF-8 character mask and pattern, see `read_string()` for details. */
7999             #if YYJSON_ENDIAN == YYJSON_BIG_ENDIAN
8000             const u16 b2_mask = 0xE0C0UL;
8001             const u16 b2_patt = 0xC080UL;
8002             const u16 b2_requ = 0x1E00UL;
8003             const u32 b3_mask = 0xF0C0C000UL;
8004             const u32 b3_patt = 0xE0808000UL;
8005             const u32 b3_requ = 0x0F200000UL;
8006             const u32 b3_erro = 0x0D200000UL;
8007             const u32 b4_mask = 0xF8C0C0C0UL;
8008             const u32 b4_patt = 0xF0808080UL;
8009             const u32 b4_requ = 0x07300000UL;
8010             const u32 b4_err0 = 0x04000000UL;
8011             const u32 b4_err1 = 0x03300000UL;
8012             #elif YYJSON_ENDIAN == YYJSON_LITTLE_ENDIAN
8013 34391           const u16 b2_mask = 0xC0E0UL;
8014 34391           const u16 b2_patt = 0x80C0UL;
8015 34391           const u16 b2_requ = 0x001EUL;
8016 34391           const u32 b3_mask = 0x00C0C0F0UL;
8017 34391           const u32 b3_patt = 0x008080E0UL;
8018 34391           const u32 b3_requ = 0x0000200FUL;
8019 34391           const u32 b3_erro = 0x0000200DUL;
8020 34391           const u32 b4_mask = 0xC0C0C0F8UL;
8021 34391           const u32 b4_patt = 0x808080F0UL;
8022 34391           const u32 b4_requ = 0x00003007UL;
8023 34391           const u32 b4_err0 = 0x00000004UL;
8024 34391           const u32 b4_err1 = 0x00003003UL;
8025             #else
8026             /* this should be evaluated at compile-time */
8027             v16_uni b2_mask_uni = {{ 0xE0, 0xC0 }};
8028             v16_uni b2_patt_uni = {{ 0xC0, 0x80 }};
8029             v16_uni b2_requ_uni = {{ 0x1E, 0x00 }};
8030             v32_uni b3_mask_uni = {{ 0xF0, 0xC0, 0xC0, 0x00 }};
8031             v32_uni b3_patt_uni = {{ 0xE0, 0x80, 0x80, 0x00 }};
8032             v32_uni b3_requ_uni = {{ 0x0F, 0x20, 0x00, 0x00 }};
8033             v32_uni b3_erro_uni = {{ 0x0D, 0x20, 0x00, 0x00 }};
8034             v32_uni b4_mask_uni = {{ 0xF8, 0xC0, 0xC0, 0xC0 }};
8035             v32_uni b4_patt_uni = {{ 0xF0, 0x80, 0x80, 0x80 }};
8036             v32_uni b4_requ_uni = {{ 0x07, 0x30, 0x00, 0x00 }};
8037             v32_uni b4_err0_uni = {{ 0x04, 0x00, 0x00, 0x00 }};
8038             v32_uni b4_err1_uni = {{ 0x03, 0x30, 0x00, 0x00 }};
8039             u16 b2_mask = b2_mask_uni.u;
8040             u16 b2_patt = b2_patt_uni.u;
8041             u16 b2_requ = b2_requ_uni.u;
8042             u32 b3_mask = b3_mask_uni.u;
8043             u32 b3_patt = b3_patt_uni.u;
8044             u32 b3_requ = b3_requ_uni.u;
8045             u32 b3_erro = b3_erro_uni.u;
8046             u32 b4_mask = b4_mask_uni.u;
8047             u32 b4_patt = b4_patt_uni.u;
8048             u32 b4_requ = b4_requ_uni.u;
8049             u32 b4_err0 = b4_err0_uni.u;
8050             u32 b4_err1 = b4_err1_uni.u;
8051             #endif
8052            
8053             #define is_valid_seq_2(uni) ( \
8054             ((uni & b2_mask) == b2_patt) && \
8055             ((uni & b2_requ)) \
8056             )
8057            
8058             #define is_valid_seq_3(uni) ( \
8059             ((uni & b3_mask) == b3_patt) && \
8060             ((tmp = (uni & b3_requ))) && \
8061             ((tmp != b3_erro)) \
8062             )
8063            
8064             #define is_valid_seq_4(uni) ( \
8065             ((uni & b4_mask) == b4_patt) && \
8066             ((tmp = (uni & b4_requ))) && \
8067             ((tmp & b4_err0) == 0 || (tmp & b4_err1) == 0) \
8068             )
8069            
8070             /* The replacement character U+FFFD, used to indicate invalid character. */
8071 34391           const v32 rep = {{ 'F', 'F', 'F', 'D' }};
8072 34391           const v32 pre = {{ '\\', 'u', '0', '0' }};
8073            
8074 34391           const u8 *src = str;
8075 34391           const u8 *end = str + str_len;
8076 34391           *cur++ = '"';
8077            
8078 34397           copy_ascii:
8079             /*
8080             Copy continuous ASCII, loop unrolling, same as the following code:
8081            
8082             while (end > src) (
8083             if (unlikely(enc_table[*src])) break;
8084             *cur++ = *src++;
8085             );
8086             */
8087             #define expr_jump(i) \
8088             if (unlikely(enc_table[src[i]])) goto stop_char_##i;
8089            
8090             #define expr_stop(i) \
8091             stop_char_##i: \
8092             memcpy(cur, src, i); \
8093             cur += i; src += i; goto copy_utf8;
8094            
8095 42672 100         while (end - src >= 16) {
    100          
    100          
    0          
    0          
    0          
8096 8275 50         repeat16_incr(expr_jump)
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
8097             byte_copy_16(cur, src);
8098 8275           cur += 16; src += 16;
8099             }
8100            
8101 78380 100         while (end - src >= 4) {
    100          
    100          
    0          
    0          
    0          
8102 43993 100         repeat4_incr(expr_jump)
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    100          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
8103             byte_copy_4(cur, src);
8104 43983           cur += 4; src += 4;
8105             }
8106            
8107 84703 100         while (end > src) {
    100          
    100          
    0          
    0          
    0          
8108 50317 100         expr_jump(0)
    50          
    50          
    0          
    0          
    0          
8109 50316           *cur++ = *src++;
8110             }
8111            
8112 34386           *cur++ = '"';
8113 34386           return cur;
8114            
8115 11           repeat16_incr(expr_stop)
8116            
8117             #undef expr_jump
8118             #undef expr_stop
8119            
8120 22           copy_utf8:
8121 33 100         if (unlikely(src + 4 > end)) {
    0          
    100          
    0          
    0          
    0          
8122 13 100         if (end == src) goto copy_end;
    0          
    100          
    0          
    0          
    0          
8123 8 50         if (end - src < enc_table[*src] / 2) goto err_one;
    0          
    50          
    0          
    0          
    0          
8124             }
8125 28           switch (enc_table[*src]) {
8126 6           case CHAR_ENC_CPY_1: {
8127 6           *cur++ = *src++;
8128 6           goto copy_ascii;
8129             }
8130 3           case CHAR_ENC_CPY_2: {
8131             u16 v;
8132             #if YYJSON_DISABLE_UTF8_VALIDATION
8133             byte_copy_2(cur, src);
8134             #else
8135 3           v = byte_load_2(src);
8136 3 50         if (unlikely(!is_valid_seq_2(v))) goto err_cpy;
    50          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
8137             byte_copy_2(cur, src);
8138             #endif
8139 3           cur += 2;
8140 3           src += 2;
8141 3           goto copy_utf8;
8142             }
8143 3           case CHAR_ENC_CPY_3: {
8144             u32 v, tmp;
8145             #if YYJSON_DISABLE_UTF8_VALIDATION
8146             if (likely(src + 4 <= end)) {
8147             byte_copy_4(cur, src);
8148             } else {
8149             byte_copy_2(cur, src);
8150             cur[2] = src[2];
8151             }
8152             #else
8153 3 100         if (likely(src + 4 <= end)) {
    0          
    0          
    0          
    0          
    0          
8154 2           v = byte_load_4(src);
8155 2 50         if (unlikely(!is_valid_seq_3(v))) goto err_cpy;
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
8156             byte_copy_4(cur, src);
8157             } else {
8158 1           v = byte_load_3(src);
8159 1 50         if (unlikely(!is_valid_seq_3(v))) goto err_cpy;
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
8160             byte_copy_4(cur, &v);
8161             }
8162             #endif
8163 3           cur += 3;
8164 3           src += 3;
8165 3           goto copy_utf8;
8166             }
8167 2           case CHAR_ENC_CPY_4: {
8168             u32 v, tmp;
8169             #if YYJSON_DISABLE_UTF8_VALIDATION
8170             byte_copy_4(cur, src);
8171             #else
8172 2           v = byte_load_4(src);
8173 2 50         if (unlikely(!is_valid_seq_4(v))) goto err_cpy;
    50          
    50          
    50          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
8174             byte_copy_4(cur, src);
8175             #endif
8176 2           cur += 4;
8177 2           src += 4;
8178 2           goto copy_utf8;
8179             }
8180 10           case CHAR_ENC_ESC_A: {
8181 10           byte_copy_2(cur, &esc_single_char_table[*src * 2]);
8182 10           cur += 2;
8183 10           src += 1;
8184 10           goto copy_utf8;
8185             }
8186 4           case CHAR_ENC_ESC_1: {
8187             byte_copy_4(cur + 0, &pre);
8188 4           byte_copy_2(cur + 4, &esc_hex_char_table[*src * 2]);
8189 4           cur += 6;
8190 4           src += 1;
8191 4           goto copy_utf8;
8192             }
8193 0           case CHAR_ENC_ESC_2: {
8194             u16 u, v;
8195             #if !YYJSON_DISABLE_UTF8_VALIDATION
8196 0           v = byte_load_2(src);
8197 0 0         if (unlikely(!is_valid_seq_2(v))) goto err_esc;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
8198             #endif
8199 0           u = (u16)(((u16)(src[0] & 0x1F) << 6) |
8200 0           ((u16)(src[1] & 0x3F) << 0));
8201             byte_copy_2(cur + 0, &pre);
8202 0           byte_copy_2(cur + 2, &esc_hex_char_table[(u >> 8) * 2]);
8203 0           byte_copy_2(cur + 4, &esc_hex_char_table[(u & 0xFF) * 2]);
8204 0           cur += 6;
8205 0           src += 2;
8206 0           goto copy_utf8;
8207             }
8208 0           case CHAR_ENC_ESC_3: {
8209             u16 u;
8210             u32 v, tmp;
8211             #if !YYJSON_DISABLE_UTF8_VALIDATION
8212 0           v = byte_load_3(src);
8213 0 0         if (unlikely(!is_valid_seq_3(v))) goto err_esc;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
8214             #endif
8215 0           u = (u16)(((u16)(src[0] & 0x0F) << 12) |
8216 0           ((u16)(src[1] & 0x3F) << 6) |
8217 0           ((u16)(src[2] & 0x3F) << 0));
8218             byte_copy_2(cur + 0, &pre);
8219 0           byte_copy_2(cur + 2, &esc_hex_char_table[(u >> 8) * 2]);
8220 0           byte_copy_2(cur + 4, &esc_hex_char_table[(u & 0xFF) * 2]);
8221 0           cur += 6;
8222 0           src += 3;
8223 0           goto copy_utf8;
8224             }
8225 0           case CHAR_ENC_ESC_4: {
8226             u32 hi, lo, u, v, tmp;
8227             #if !YYJSON_DISABLE_UTF8_VALIDATION
8228 0           v = byte_load_4(src);
8229 0 0         if (unlikely(!is_valid_seq_4(v))) goto err_esc;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
8230             #endif
8231 0           u = ((u32)(src[0] & 0x07) << 18) |
8232 0           ((u32)(src[1] & 0x3F) << 12) |
8233 0           ((u32)(src[2] & 0x3F) << 6) |
8234 0           ((u32)(src[3] & 0x3F) << 0);
8235 0           u -= 0x10000;
8236 0           hi = (u >> 10) + 0xD800;
8237 0           lo = (u & 0x3FF) + 0xDC00;
8238             byte_copy_2(cur + 0, &pre);
8239 0           byte_copy_2(cur + 2, &esc_hex_char_table[(hi >> 8) * 2]);
8240 0           byte_copy_2(cur + 4, &esc_hex_char_table[(hi & 0xFF) * 2]);
8241 0           byte_copy_2(cur + 6, &pre);
8242 0           byte_copy_2(cur + 8, &esc_hex_char_table[(lo >> 8) * 2]);
8243 0           byte_copy_2(cur + 10, &esc_hex_char_table[(lo & 0xFF) * 2]);
8244 0           cur += 12;
8245 0           src += 4;
8246 0           goto copy_utf8;
8247             }
8248 0           case CHAR_ENC_ERR_1: {
8249 0           goto err_one;
8250             }
8251 0           default: break;
8252             }
8253            
8254 5           copy_end:
8255 5           *cur++ = '"';
8256 5           return cur;
8257            
8258 0           err_one:
8259 0 0         if (esc) goto err_esc;
    0          
    0          
    0          
    0          
    0          
8260 0           else goto err_cpy;
8261            
8262 0           err_cpy:
8263 0 0         if (!inv) return NULL;
    0          
    0          
    0          
    0          
    0          
8264 0           *cur++ = *src++;
8265 0           goto copy_utf8;
8266            
8267 0           err_esc:
8268 0 0         if (!inv) return NULL;
    0          
    0          
    0          
    0          
    0          
8269             byte_copy_2(cur + 0, &pre);
8270 0           byte_copy_4(cur + 2, &rep);
8271 0           cur += 6;
8272 0           src += 1;
8273 0           goto copy_utf8;
8274            
8275             #undef is_valid_seq_2
8276             #undef is_valid_seq_3
8277             #undef is_valid_seq_4
8278             }
8279              
8280              
8281              
8282             /*==============================================================================
8283             * Writer Utilities
8284             *============================================================================*/
8285              
8286             /** Write null (requires 8 bytes buffer). */
8287             static_inline u8 *write_null(u8 *cur) {
8288 12           v64 v = {{ 'n', 'u', 'l', 'l', ',', '\n', 0, 0 }};
8289             byte_copy_8(cur, &v);
8290 14           return cur + 4;
8291             }
8292              
8293             /** Write bool (requires 8 bytes buffer). */
8294             static_inline u8 *write_bool(u8 *cur, bool val) {
8295 15           v64 v0 = {{ 'f', 'a', 'l', 's', 'e', ',', '\n', 0 }};
8296 15           v64 v1 = {{ 't', 'r', 'u', 'e', ',', '\n', 0, 0 }};
8297 15           if (val) {
8298             byte_copy_8(cur, &v1);
8299             } else {
8300             byte_copy_8(cur, &v0);
8301             }
8302 15           return cur + 5 - val;
8303             }
8304              
8305             /** Write indent (requires level x 4 bytes buffer).
8306             Param spaces should not larger than 4. */
8307             static_inline u8 *write_indent(u8 *cur, usize level, usize spaces) {
8308 945 100         while (level-- > 0) {
    100          
    50          
    100          
    0          
    50          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
8309             byte_copy_4(cur, " ");
8310 581           cur += spaces;
8311             }
8312 364           return cur;
8313             }
8314              
8315             /** Write data to file pointer. */
8316 0           static bool write_dat_to_fp(FILE *fp, u8 *dat, usize len,
8317             yyjson_write_err *err) {
8318 0 0         if (fwrite(dat, len, 1, fp) != 1) {
8319 0           err->msg = "file writing failed";
8320 0           err->code = YYJSON_WRITE_ERROR_FILE_WRITE;
8321 0           return false;
8322             }
8323 0           return true;
8324             }
8325              
8326             /** Write data to file. */
8327 0           static bool write_dat_to_file(const char *path, u8 *dat, usize len,
8328             yyjson_write_err *err) {
8329            
8330             #define return_err(_code, _msg) do { \
8331             err->msg = _msg; \
8332             err->code = YYJSON_WRITE_ERROR_##_code; \
8333             if (file) fclose(file); \
8334             return false; \
8335             } while (false)
8336            
8337 0           FILE *file = fopen_writeonly(path);
8338 0 0         if (file == NULL) {
8339 0 0         return_err(FILE_OPEN, "file opening failed");
8340             }
8341 0 0         if (fwrite(dat, len, 1, file) != 1) {
8342 0 0         return_err(FILE_WRITE, "file writing failed");
8343             }
8344 0 0         if (fclose(file) != 0) {
8345 0           file = NULL;
8346 0 0         return_err(FILE_WRITE, "file closing failed");
8347             }
8348 0           return true;
8349            
8350             #undef return_err
8351             }
8352              
8353              
8354              
8355             /*==============================================================================
8356             * JSON Writer Implementation
8357             *============================================================================*/
8358              
8359             typedef struct yyjson_write_ctx {
8360             usize tag;
8361             } yyjson_write_ctx;
8362              
8363             static_inline void yyjson_write_ctx_set(yyjson_write_ctx *ctx,
8364             usize size, bool is_obj) {
8365 0           ctx->tag = (size << 1) | (usize)is_obj;
8366 0           }
8367              
8368             static_inline void yyjson_write_ctx_get(yyjson_write_ctx *ctx,
8369             usize *size, bool *is_obj) {
8370 0           usize tag = ctx->tag;
8371 0           *size = tag >> 1;
8372 0           *is_obj = (bool)(tag & 1);
8373 0           }
8374              
8375             /** Write single JSON value. */
8376             static_inline u8 *yyjson_write_single(yyjson_val *val,
8377             yyjson_write_flag flg,
8378             yyjson_alc alc,
8379             usize *dat_len,
8380             yyjson_write_err *err) {
8381            
8382             #define return_err(_code, _msg) do { \
8383             if (hdr) alc.free(alc.ctx, (void *)hdr); \
8384             *dat_len = 0; \
8385             err->code = YYJSON_WRITE_ERROR_##_code; \
8386             err->msg = _msg; \
8387             return NULL; \
8388             } while (false)
8389            
8390             #define incr_len(_len) do { \
8391             hdr = (u8 *)alc.malloc(alc.ctx, _len); \
8392             if (!hdr) goto fail_alloc; \
8393             cur = hdr; \
8394             } while (false)
8395            
8396             #define check_str_len(_len) do { \
8397             if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
8398             goto fail_alloc; \
8399             } while (false)
8400            
8401 26           u8 *hdr = NULL, *cur;
8402             usize str_len;
8403             const u8 *str_ptr;
8404 26           const char_enc_type *enc_table = get_enc_table_with_flag(flg);
8405 26           bool cpy = (enc_table == enc_table_cpy);
8406 26           bool esc = has_write_flag(ESCAPE_UNICODE) != 0;
8407 26           bool inv = has_write_flag(ALLOW_INVALID_UNICODE) != 0;
8408 26           bool newline = has_write_flag(NEWLINE_AT_END) != 0;
8409 26           const usize end_len = 2; /* '\n' and '\0' */
8410            
8411 26           switch (unsafe_yyjson_get_type(val)) {
8412 0           case YYJSON_TYPE_RAW:
8413 0           str_len = unsafe_yyjson_get_len(val);
8414 0           str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
8415             check_str_len(str_len);
8416 0 0         incr_len(str_len + end_len);
    0          
8417 0           cur = write_raw(cur, str_ptr, str_len);
8418 0           break;
8419            
8420 13           case YYJSON_TYPE_STR:
8421 13           str_len = unsafe_yyjson_get_len(val);
8422 13           str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
8423             check_str_len(str_len);
8424 13 50         incr_len(str_len * 6 + 2 + end_len);
    0          
8425 26 50         if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
    50          
    0          
    0          
8426 0           cur = write_string_noesc(cur, str_ptr, str_len);
8427             } else {
8428 13           cur = write_string(cur, esc, inv, str_ptr, str_len, enc_table);
8429 13 50         if (unlikely(!cur)) goto fail_str;
    0          
8430             }
8431 13           break;
8432            
8433 4           case YYJSON_TYPE_NUM:
8434 4 50         incr_len(32 + end_len);
    100          
    0          
    0          
8435 4           cur = write_number(cur, val, flg);
8436 4 50         if (unlikely(!cur)) goto fail_num;
    0          
8437 4           break;
8438            
8439 2           case YYJSON_TYPE_BOOL:
8440 2 50         incr_len(8);
    0          
8441 2 100         cur = write_bool(cur, unsafe_yyjson_get_bool(val));
    0          
8442 2           break;
8443            
8444 1           case YYJSON_TYPE_NULL:
8445 1 50         incr_len(8);
    0          
8446 1           cur = write_null(cur);
8447 1           break;
8448            
8449 2           case YYJSON_TYPE_ARR:
8450 2 50         incr_len(2 + end_len);
    0          
8451             byte_copy_2(cur, "[]");
8452 2           cur += 2;
8453 2           break;
8454            
8455 4           case YYJSON_TYPE_OBJ:
8456 4 50         incr_len(2 + end_len);
    0          
8457             byte_copy_2(cur, "{}");
8458 4           cur += 2;
8459 4           break;
8460            
8461 0           default:
8462 0           goto fail_type;
8463             }
8464            
8465 26 50         if (newline) *cur++ = '\n';
    0          
8466 26           *cur = '\0';
8467 26           *dat_len = (usize)(cur - hdr);
8468 26           memset(err, 0, sizeof(yyjson_write_err));
8469 26           return hdr;
8470            
8471 0           fail_alloc:
8472 0 0         return_err(MEMORY_ALLOCATION, "memory allocation failed");
    0          
8473 0           fail_type:
8474 0 0         return_err(INVALID_VALUE_TYPE, "invalid JSON value type");
    0          
8475 0           fail_num:
8476 0 0         return_err(NAN_OR_INF, "nan or inf number is not allowed");
    0          
8477 0           fail_str:
8478 0 0         return_err(INVALID_STRING, "invalid utf-8 encoding in string");
    0          
8479            
8480             #undef return_err
8481             #undef check_str_len
8482             #undef incr_len
8483             }
8484              
8485             /** Write JSON document minify.
8486             The root of this document should be a non-empty container. */
8487             static_inline u8 *yyjson_write_minify(const yyjson_val *root,
8488             const yyjson_write_flag flg,
8489             const yyjson_alc alc,
8490             usize *dat_len,
8491             yyjson_write_err *err) {
8492            
8493             #define return_err(_code, _msg) do { \
8494             *dat_len = 0; \
8495             err->code = YYJSON_WRITE_ERROR_##_code; \
8496             err->msg = _msg; \
8497             if (hdr) alc.free(alc.ctx, hdr); \
8498             return NULL; \
8499             } while (false)
8500            
8501             #define incr_len(_len) do { \
8502             ext_len = (usize)(_len); \
8503             if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
8504             alc_inc = yyjson_max(alc_len / 2, ext_len); \
8505             alc_inc = size_align_up(alc_inc, sizeof(yyjson_write_ctx)); \
8506             if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
8507             goto fail_alloc; \
8508             alc_len += alc_inc; \
8509             tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
8510             if (unlikely(!tmp)) goto fail_alloc; \
8511             ctx_len = (usize)(end - (u8 *)ctx); \
8512             ctx_tmp = (yyjson_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
8513             memmove((void *)ctx_tmp, (void *)(tmp + ((u8 *)ctx - hdr)), ctx_len); \
8514             ctx = ctx_tmp; \
8515             cur = tmp + (cur - hdr); \
8516             end = tmp + alc_len; \
8517             hdr = tmp; \
8518             } \
8519             } while (false)
8520            
8521             #define check_str_len(_len) do { \
8522             if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
8523             goto fail_alloc; \
8524             } while (false)
8525            
8526             yyjson_val *val;
8527             yyjson_type val_type;
8528             usize ctn_len, ctn_len_tmp;
8529             bool ctn_obj, ctn_obj_tmp, is_key;
8530             u8 *hdr, *cur, *end, *tmp;
8531             yyjson_write_ctx *ctx, *ctx_tmp;
8532             usize alc_len, alc_inc, ctx_len, ext_len, str_len;
8533             const u8 *str_ptr;
8534 0           const char_enc_type *enc_table = get_enc_table_with_flag(flg);
8535 0           bool cpy = (enc_table == enc_table_cpy);
8536 0           bool esc = has_write_flag(ESCAPE_UNICODE) != 0;
8537 0           bool inv = has_write_flag(ALLOW_INVALID_UNICODE) != 0;
8538 0           bool newline = has_write_flag(NEWLINE_AT_END) != 0;
8539            
8540 0           alc_len = root->uni.ofs / sizeof(yyjson_val);
8541 0           alc_len = alc_len * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64;
8542 0           alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx));
8543 0           hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
8544 0 0         if (!hdr) goto fail_alloc;
8545 0           cur = hdr;
8546 0           end = hdr + alc_len;
8547 0           ctx = (yyjson_write_ctx *)(void *)end;
8548            
8549 0           doc_begin:
8550 0           val = constcast(yyjson_val *)root;
8551 0           val_type = unsafe_yyjson_get_type(val);
8552 0           ctn_obj = (val_type == YYJSON_TYPE_OBJ);
8553 0           ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
8554 0           *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
8555 0           val++;
8556            
8557 0           val_begin:
8558 0           val_type = unsafe_yyjson_get_type(val);
8559 0 0         if (val_type == YYJSON_TYPE_STR) {
8560 0           is_key = ((u8)ctn_obj & (u8)~ctn_len);
8561 0           str_len = unsafe_yyjson_get_len(val);
8562 0           str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
8563             check_str_len(str_len);
8564 0 0         incr_len(str_len * 6 + 16);
    0          
8565 0 0         if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
    0          
8566 0           cur = write_string_noesc(cur, str_ptr, str_len);
8567             } else {
8568 0           cur = write_string(cur, esc, inv, str_ptr, str_len, enc_table);
8569 0 0         if (unlikely(!cur)) goto fail_str;
8570             }
8571 0 0         *cur++ = is_key ? ':' : ',';
8572 0           goto val_end;
8573             }
8574 0 0         if (val_type == YYJSON_TYPE_NUM) {
8575 0 0         incr_len(32);
    0          
8576 0           cur = write_number(cur, val, flg);
8577 0 0         if (unlikely(!cur)) goto fail_num;
8578 0           *cur++ = ',';
8579 0           goto val_end;
8580             }
8581 0 0         if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
8582             (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
8583 0           ctn_len_tmp = unsafe_yyjson_get_len(val);
8584 0           ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
8585 0 0         incr_len(16);
    0          
8586 0 0         if (unlikely(ctn_len_tmp == 0)) {
8587             /* write empty container */
8588 0           *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
8589 0           *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
8590 0           *cur++ = ',';
8591 0           goto val_end;
8592             } else {
8593             /* push context, setup new container */
8594 0           yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj);
8595 0           ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
8596 0           ctn_obj = ctn_obj_tmp;
8597 0           *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
8598 0           val++;
8599 0           goto val_begin;
8600             }
8601             }
8602 0 0         if (val_type == YYJSON_TYPE_BOOL) {
8603 0 0         incr_len(16);
    0          
8604 0 0         cur = write_bool(cur, unsafe_yyjson_get_bool(val));
8605 0           cur++;
8606 0           goto val_end;
8607             }
8608 0 0         if (val_type == YYJSON_TYPE_NULL) {
8609 0 0         incr_len(16);
    0          
8610 0           cur = write_null(cur);
8611 0           cur++;
8612 0           goto val_end;
8613             }
8614 0 0         if (val_type == YYJSON_TYPE_RAW) {
8615 0           str_len = unsafe_yyjson_get_len(val);
8616 0           str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
8617             check_str_len(str_len);
8618 0 0         incr_len(str_len + 2);
    0          
8619 0           cur = write_raw(cur, str_ptr, str_len);
8620 0           *cur++ = ',';
8621 0           goto val_end;
8622             }
8623 0           goto fail_type;
8624            
8625 0           val_end:
8626 0           val++;
8627 0           ctn_len--;
8628 0 0         if (unlikely(ctn_len == 0)) goto ctn_end;
8629 0           goto val_begin;
8630            
8631 0           ctn_end:
8632 0           cur--;
8633 0           *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
8634 0           *cur++ = ',';
8635 0 0         if (unlikely((u8 *)ctx >= end)) goto doc_end;
8636 0           yyjson_write_ctx_get(ctx++, &ctn_len, &ctn_obj);
8637 0           ctn_len--;
8638 0 0         if (likely(ctn_len > 0)) {
8639 0           goto val_begin;
8640             } else {
8641 0           goto ctn_end;
8642             }
8643            
8644 0           doc_end:
8645 0 0         if (newline) {
8646 0 0         incr_len(2);
    0          
8647 0           *(cur - 1) = '\n';
8648 0           cur++;
8649             }
8650 0           *--cur = '\0';
8651 0           *dat_len = (usize)(cur - hdr);
8652 0           memset(err, 0, sizeof(yyjson_write_err));
8653 0           return hdr;
8654            
8655 0           fail_alloc:
8656 0 0         return_err(MEMORY_ALLOCATION, "memory allocation failed");
8657 0           fail_type:
8658 0 0         return_err(INVALID_VALUE_TYPE, "invalid JSON value type");
8659 0           fail_num:
8660 0 0         return_err(NAN_OR_INF, "nan or inf number is not allowed");
8661 0           fail_str:
8662 0 0         return_err(INVALID_STRING, "invalid utf-8 encoding in string");
8663            
8664             #undef return_err
8665             #undef incr_len
8666             #undef check_str_len
8667             }
8668              
8669             /** Write JSON document pretty.
8670             The root of this document should be a non-empty container. */
8671             static_inline u8 *yyjson_write_pretty(const yyjson_val *root,
8672             const yyjson_write_flag flg,
8673             const yyjson_alc alc,
8674             usize *dat_len,
8675             yyjson_write_err *err) {
8676            
8677             #define return_err(_code, _msg) do { \
8678             *dat_len = 0; \
8679             err->code = YYJSON_WRITE_ERROR_##_code; \
8680             err->msg = _msg; \
8681             if (hdr) alc.free(alc.ctx, hdr); \
8682             return NULL; \
8683             } while (false)
8684            
8685             #define incr_len(_len) do { \
8686             ext_len = (usize)(_len); \
8687             if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
8688             alc_inc = yyjson_max(alc_len / 2, ext_len); \
8689             alc_inc = size_align_up(alc_inc, sizeof(yyjson_write_ctx)); \
8690             if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
8691             goto fail_alloc; \
8692             alc_len += alc_inc; \
8693             tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
8694             if (unlikely(!tmp)) goto fail_alloc; \
8695             ctx_len = (usize)(end - (u8 *)ctx); \
8696             ctx_tmp = (yyjson_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
8697             memmove((void *)ctx_tmp, (void *)(tmp + ((u8 *)ctx - hdr)), ctx_len); \
8698             ctx = ctx_tmp; \
8699             cur = tmp + (cur - hdr); \
8700             end = tmp + alc_len; \
8701             hdr = tmp; \
8702             } \
8703             } while (false)
8704            
8705             #define check_str_len(_len) do { \
8706             if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
8707             goto fail_alloc; \
8708             } while (false)
8709            
8710             yyjson_val *val;
8711             yyjson_type val_type;
8712             usize ctn_len, ctn_len_tmp;
8713             bool ctn_obj, ctn_obj_tmp, is_key, no_indent;
8714             u8 *hdr, *cur, *end, *tmp;
8715             yyjson_write_ctx *ctx, *ctx_tmp;
8716             usize alc_len, alc_inc, ctx_len, ext_len, str_len, level;
8717             const u8 *str_ptr;
8718 0           const char_enc_type *enc_table = get_enc_table_with_flag(flg);
8719 0           bool cpy = (enc_table == enc_table_cpy);
8720 0           bool esc = has_write_flag(ESCAPE_UNICODE) != 0;
8721 0           bool inv = has_write_flag(ALLOW_INVALID_UNICODE) != 0;
8722 0 0         usize spaces = has_write_flag(PRETTY_TWO_SPACES) ? 2 : 4;
8723 0           bool newline = has_write_flag(NEWLINE_AT_END) != 0;
8724            
8725 0           alc_len = root->uni.ofs / sizeof(yyjson_val);
8726 0           alc_len = alc_len * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64;
8727 0           alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx));
8728 0           hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
8729 0 0         if (!hdr) goto fail_alloc;
8730 0           cur = hdr;
8731 0           end = hdr + alc_len;
8732 0           ctx = (yyjson_write_ctx *)(void *)end;
8733            
8734 0           doc_begin:
8735 0           val = constcast(yyjson_val *)root;
8736 0           val_type = unsafe_yyjson_get_type(val);
8737 0           ctn_obj = (val_type == YYJSON_TYPE_OBJ);
8738 0           ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
8739 0           *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
8740 0           *cur++ = '\n';
8741 0           val++;
8742 0           level = 1;
8743            
8744 0           val_begin:
8745 0           val_type = unsafe_yyjson_get_type(val);
8746 0 0         if (val_type == YYJSON_TYPE_STR) {
8747 0           is_key = (bool)((u8)ctn_obj & (u8)~ctn_len);
8748 0           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
8749 0           str_len = unsafe_yyjson_get_len(val);
8750 0           str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
8751             check_str_len(str_len);
8752 0 0         incr_len(str_len * 6 + 16 + (no_indent ? 0 : level * 4));
    0          
    0          
8753 0 0         cur = write_indent(cur, no_indent ? 0 : level, spaces);
8754 0 0         if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
    0          
8755 0           cur = write_string_noesc(cur, str_ptr, str_len);
8756             } else {
8757 0           cur = write_string(cur, esc, inv, str_ptr, str_len, enc_table);
8758 0 0         if (unlikely(!cur)) goto fail_str;
8759             }
8760 0 0         *cur++ = is_key ? ':' : ',';
8761 0 0         *cur++ = is_key ? ' ' : '\n';
8762 0           goto val_end;
8763             }
8764 0 0         if (val_type == YYJSON_TYPE_NUM) {
8765 0           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
8766 0 0         incr_len(32 + (no_indent ? 0 : level * 4));
    0          
    0          
8767 0 0         cur = write_indent(cur, no_indent ? 0 : level, spaces);
    0          
8768 0           cur = write_number(cur, val, flg);
8769 0 0         if (unlikely(!cur)) goto fail_num;
8770 0           *cur++ = ',';
8771 0           *cur++ = '\n';
8772 0           goto val_end;
8773             }
8774 0 0         if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
8775             (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
8776 0           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
8777 0           ctn_len_tmp = unsafe_yyjson_get_len(val);
8778 0           ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
8779 0 0         if (unlikely(ctn_len_tmp == 0)) {
8780             /* write empty container */
8781 0 0         incr_len(16 + (no_indent ? 0 : level * 4));
    0          
    0          
8782 0 0         cur = write_indent(cur, no_indent ? 0 : level, spaces);
8783 0           *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
8784 0           *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
8785 0           *cur++ = ',';
8786 0           *cur++ = '\n';
8787 0           goto val_end;
8788             } else {
8789             /* push context, setup new container */
8790 0 0         incr_len(32 + (no_indent ? 0 : level * 4));
    0          
    0          
8791 0           yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj);
8792 0           ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
8793 0           ctn_obj = ctn_obj_tmp;
8794 0 0         cur = write_indent(cur, no_indent ? 0 : level, spaces);
8795 0           level++;
8796 0           *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
8797 0           *cur++ = '\n';
8798 0           val++;
8799 0           goto val_begin;
8800             }
8801             }
8802 0 0         if (val_type == YYJSON_TYPE_BOOL) {
8803 0           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
8804 0 0         incr_len(16 + (no_indent ? 0 : level * 4));
    0          
    0          
8805 0 0         cur = write_indent(cur, no_indent ? 0 : level, spaces);
8806 0 0         cur = write_bool(cur, unsafe_yyjson_get_bool(val));
8807 0           cur += 2;
8808 0           goto val_end;
8809             }
8810 0 0         if (val_type == YYJSON_TYPE_NULL) {
8811 0           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
8812 0 0         incr_len(16 + (no_indent ? 0 : level * 4));
    0          
    0          
8813 0 0         cur = write_indent(cur, no_indent ? 0 : level, spaces);
8814 0           cur = write_null(cur);
8815 0           cur += 2;
8816 0           goto val_end;
8817             }
8818 0 0         if (val_type == YYJSON_TYPE_RAW) {
8819 0           str_len = unsafe_yyjson_get_len(val);
8820 0           str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
8821             check_str_len(str_len);
8822 0 0         incr_len(str_len + 3);
    0          
8823 0           cur = write_raw(cur, str_ptr, str_len);
8824 0           *cur++ = ',';
8825 0           *cur++ = '\n';
8826 0           goto val_end;
8827             }
8828 0           goto fail_type;
8829            
8830 0           val_end:
8831 0           val++;
8832 0           ctn_len--;
8833 0 0         if (unlikely(ctn_len == 0)) goto ctn_end;
8834 0           goto val_begin;
8835            
8836 0           ctn_end:
8837 0           cur -= 2;
8838 0           *cur++ = '\n';
8839 0 0         incr_len(level * 4);
    0          
8840 0           cur = write_indent(cur, --level, spaces);
8841 0           *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
8842 0 0         if (unlikely((u8 *)ctx >= end)) goto doc_end;
8843 0           yyjson_write_ctx_get(ctx++, &ctn_len, &ctn_obj);
8844 0           ctn_len--;
8845 0           *cur++ = ',';
8846 0           *cur++ = '\n';
8847 0 0         if (likely(ctn_len > 0)) {
8848 0           goto val_begin;
8849             } else {
8850 0           goto ctn_end;
8851             }
8852            
8853 0           doc_end:
8854 0 0         if (newline) {
8855 0 0         incr_len(2);
    0          
8856 0           *cur++ = '\n';
8857             }
8858 0           *cur = '\0';
8859 0           *dat_len = (usize)(cur - hdr);
8860 0           memset(err, 0, sizeof(yyjson_write_err));
8861 0           return hdr;
8862            
8863 0           fail_alloc:
8864 0 0         return_err(MEMORY_ALLOCATION, "memory allocation failed");
8865 0           fail_type:
8866 0 0         return_err(INVALID_VALUE_TYPE, "invalid JSON value type");
8867 0           fail_num:
8868 0 0         return_err(NAN_OR_INF, "nan or inf number is not allowed");
8869 0           fail_str:
8870 0 0         return_err(INVALID_STRING, "invalid utf-8 encoding in string");
8871            
8872             #undef return_err
8873             #undef incr_len
8874             #undef check_str_len
8875             }
8876              
8877 0           char *yyjson_val_write_opts(const yyjson_val *val,
8878             yyjson_write_flag flg,
8879             const yyjson_alc *alc_ptr,
8880             usize *dat_len,
8881             yyjson_write_err *err) {
8882             yyjson_write_err dummy_err;
8883             usize dummy_dat_len;
8884 0 0         yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
8885 0           yyjson_val *root = constcast(yyjson_val *)val;
8886            
8887 0 0         err = err ? err : &dummy_err;
8888 0 0         dat_len = dat_len ? dat_len : &dummy_dat_len;
8889            
8890 0 0         if (unlikely(!root)) {
8891 0           *dat_len = 0;
8892 0           err->msg = "input JSON is NULL";
8893 0           err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
8894 0           return NULL;
8895             }
8896            
8897 0 0         if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) {
    0          
8898 0           return (char *)yyjson_write_single(root, flg, alc, dat_len, err);
8899 0 0         } else if (flg & (YYJSON_WRITE_PRETTY | YYJSON_WRITE_PRETTY_TWO_SPACES)) {
8900 0           return (char *)yyjson_write_pretty(root, flg, alc, dat_len, err);
8901             } else {
8902 0           return (char *)yyjson_write_minify(root, flg, alc, dat_len, err);
8903             }
8904             }
8905              
8906 0           char *yyjson_write_opts(const yyjson_doc *doc,
8907             yyjson_write_flag flg,
8908             const yyjson_alc *alc_ptr,
8909             usize *dat_len,
8910             yyjson_write_err *err) {
8911 0 0         yyjson_val *root = doc ? doc->root : NULL;
8912 0           return yyjson_val_write_opts(root, flg, alc_ptr, dat_len, err);
8913             }
8914              
8915 0           bool yyjson_val_write_file(const char *path,
8916             const yyjson_val *val,
8917             yyjson_write_flag flg,
8918             const yyjson_alc *alc_ptr,
8919             yyjson_write_err *err) {
8920             yyjson_write_err dummy_err;
8921             u8 *dat;
8922 0           usize dat_len = 0;
8923 0           yyjson_val *root = constcast(yyjson_val *)val;
8924             bool suc;
8925            
8926 0 0         alc_ptr = alc_ptr ? alc_ptr : &YYJSON_DEFAULT_ALC;
8927 0 0         err = err ? err : &dummy_err;
8928 0 0         if (unlikely(!path || !*path)) {
    0          
8929 0           err->msg = "input path is invalid";
8930 0           err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
8931 0           return false;
8932             }
8933            
8934 0           dat = (u8 *)yyjson_val_write_opts(root, flg, alc_ptr, &dat_len, err);
8935 0 0         if (unlikely(!dat)) return false;
8936 0           suc = write_dat_to_file(path, dat, dat_len, err);
8937 0           alc_ptr->free(alc_ptr->ctx, dat);
8938 0           return suc;
8939             }
8940              
8941 0           bool yyjson_val_write_fp(FILE *fp,
8942             const yyjson_val *val,
8943             yyjson_write_flag flg,
8944             const yyjson_alc *alc_ptr,
8945             yyjson_write_err *err) {
8946             yyjson_write_err dummy_err;
8947             u8 *dat;
8948 0           usize dat_len = 0;
8949 0           yyjson_val *root = constcast(yyjson_val *)val;
8950             bool suc;
8951            
8952 0 0         alc_ptr = alc_ptr ? alc_ptr : &YYJSON_DEFAULT_ALC;
8953 0 0         err = err ? err : &dummy_err;
8954 0 0         if (unlikely(!fp)) {
8955 0           err->msg = "input fp is invalid";
8956 0           err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
8957 0           return false;
8958             }
8959            
8960 0           dat = (u8 *)yyjson_val_write_opts(root, flg, alc_ptr, &dat_len, err);
8961 0 0         if (unlikely(!dat)) return false;
8962 0           suc = write_dat_to_fp(fp, dat, dat_len, err);
8963 0           alc_ptr->free(alc_ptr->ctx, dat);
8964 0           return suc;
8965             }
8966              
8967 0           bool yyjson_write_file(const char *path,
8968             const yyjson_doc *doc,
8969             yyjson_write_flag flg,
8970             const yyjson_alc *alc_ptr,
8971             yyjson_write_err *err) {
8972 0 0         yyjson_val *root = doc ? doc->root : NULL;
8973 0           return yyjson_val_write_file(path, root, flg, alc_ptr, err);
8974             }
8975              
8976 0           bool yyjson_write_fp(FILE *fp,
8977             const yyjson_doc *doc,
8978             yyjson_write_flag flg,
8979             const yyjson_alc *alc_ptr,
8980             yyjson_write_err *err) {
8981 0 0         yyjson_val *root = doc ? doc->root : NULL;
8982 0           return yyjson_val_write_fp(fp, root, flg, alc_ptr, err);
8983             }
8984              
8985              
8986              
8987             /*==============================================================================
8988             * Mutable JSON Writer Implementation
8989             *============================================================================*/
8990              
8991             typedef struct yyjson_mut_write_ctx {
8992             usize tag;
8993             yyjson_mut_val *ctn;
8994             } yyjson_mut_write_ctx;
8995              
8996             static_inline void yyjson_mut_write_ctx_set(yyjson_mut_write_ctx *ctx,
8997             yyjson_mut_val *ctn,
8998             usize size, bool is_obj) {
8999 5470           ctx->tag = (size << 1) | (usize)is_obj;
9000 5470           ctx->ctn = ctn;
9001 5470           }
9002              
9003             static_inline void yyjson_mut_write_ctx_get(yyjson_mut_write_ctx *ctx,
9004             yyjson_mut_val **ctn,
9005             usize *size, bool *is_obj) {
9006 5470           usize tag = ctx->tag;
9007 5470           *size = tag >> 1;
9008 5470           *is_obj = (bool)(tag & 1);
9009 5470           *ctn = ctx->ctn;
9010 5470           }
9011              
9012             /** Get the estimated number of values for the mutable JSON document. */
9013             static_inline usize yyjson_mut_doc_estimated_val_num(
9014             const yyjson_mut_doc *doc) {
9015 1150           usize sum = 0;
9016 1150           yyjson_val_chunk *chunk = doc->val_pool.chunks;
9017 3360 100         while (chunk) {
9018 2210           sum += chunk->chunk_size / sizeof(yyjson_mut_val) - 1;
9019 2210 100         if (chunk == doc->val_pool.chunks) {
9020 1150           sum -= (usize)(doc->val_pool.end - doc->val_pool.cur);
9021             }
9022 2210           chunk = chunk->next;
9023             }
9024 1150           return sum;
9025             }
9026              
9027             /** Write single JSON value. */
9028             static_inline u8 *yyjson_mut_write_single(yyjson_mut_val *val,
9029             yyjson_write_flag flg,
9030             yyjson_alc alc,
9031             usize *dat_len,
9032             yyjson_write_err *err) {
9033 26           return yyjson_write_single((yyjson_val *)val, flg, alc, dat_len, err);
9034             }
9035              
9036             /** Write JSON document minify.
9037             The root of this document should be a non-empty container. */
9038             static_inline u8 *yyjson_mut_write_minify(const yyjson_mut_val *root,
9039             usize estimated_val_num,
9040             yyjson_write_flag flg,
9041             yyjson_alc alc,
9042             usize *dat_len,
9043             yyjson_write_err *err) {
9044            
9045             #define return_err(_code, _msg) do { \
9046             *dat_len = 0; \
9047             err->code = YYJSON_WRITE_ERROR_##_code; \
9048             err->msg = _msg; \
9049             if (hdr) alc.free(alc.ctx, hdr); \
9050             return NULL; \
9051             } while (false)
9052            
9053             #define incr_len(_len) do { \
9054             ext_len = (usize)(_len); \
9055             if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
9056             alc_inc = yyjson_max(alc_len / 2, ext_len); \
9057             alc_inc = size_align_up(alc_inc, sizeof(yyjson_mut_write_ctx)); \
9058             if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
9059             goto fail_alloc; \
9060             alc_len += alc_inc; \
9061             tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
9062             if (unlikely(!tmp)) goto fail_alloc; \
9063             ctx_len = (usize)(end - (u8 *)ctx); \
9064             ctx_tmp = (yyjson_mut_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
9065             memmove((void *)ctx_tmp, (void *)(tmp + ((u8 *)ctx - hdr)), ctx_len); \
9066             ctx = ctx_tmp; \
9067             cur = tmp + (cur - hdr); \
9068             end = tmp + alc_len; \
9069             hdr = tmp; \
9070             } \
9071             } while (false)
9072            
9073             #define check_str_len(_len) do { \
9074             if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
9075             goto fail_alloc; \
9076             } while (false)
9077            
9078             yyjson_mut_val *val, *ctn;
9079             yyjson_type val_type;
9080             usize ctn_len, ctn_len_tmp;
9081             bool ctn_obj, ctn_obj_tmp, is_key;
9082             u8 *hdr, *cur, *end, *tmp;
9083             yyjson_mut_write_ctx *ctx, *ctx_tmp;
9084             usize alc_len, alc_inc, ctx_len, ext_len, str_len;
9085             const u8 *str_ptr;
9086 1110           const char_enc_type *enc_table = get_enc_table_with_flag(flg);
9087 1110           bool cpy = (enc_table == enc_table_cpy);
9088 1110           bool esc = has_write_flag(ESCAPE_UNICODE) != 0;
9089 1110           bool inv = has_write_flag(ALLOW_INVALID_UNICODE) != 0;
9090 1110           bool newline = has_write_flag(NEWLINE_AT_END) != 0;
9091            
9092 1110           alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64;
9093 1110           alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx));
9094 1110           hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
9095 1110 50         if (!hdr) goto fail_alloc;
9096 1110           cur = hdr;
9097 1110           end = hdr + alc_len;
9098 1110           ctx = (yyjson_mut_write_ctx *)(void *)end;
9099            
9100 1110           doc_begin:
9101 1110           val = constcast(yyjson_mut_val *)root;
9102 1110           val_type = unsafe_yyjson_get_type(val);
9103 1110           ctn_obj = (val_type == YYJSON_TYPE_OBJ);
9104 1110           ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
9105 1110           *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9106 1110           ctn = val;
9107 1110           val = (yyjson_mut_val *)val->uni.ptr; /* tail */
9108 1110 100         val = ctn_obj ? val->next->next : val->next;
9109            
9110 46197           val_begin:
9111 47307           val_type = unsafe_yyjson_get_type(val);
9112 47307 100         if (val_type == YYJSON_TYPE_STR) {
9113 34203           is_key = ((u8)ctn_obj & (u8)~ctn_len);
9114 34203           str_len = unsafe_yyjson_get_len(val);
9115 34203           str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9116             check_str_len(str_len);
9117 34203 50         incr_len(str_len * 6 + 16);
    0          
9118 68406 50         if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
    50          
9119 0           cur = write_string_noesc(cur, str_ptr, str_len);
9120             } else {
9121 34203           cur = write_string(cur, esc, inv, str_ptr, str_len, enc_table);
9122 34203 50         if (unlikely(!cur)) goto fail_str;
9123             }
9124 34203 100         *cur++ = is_key ? ':' : ',';
9125 34203           goto val_end;
9126             }
9127 13104 100         if (val_type == YYJSON_TYPE_NUM) {
9128 7629 50         incr_len(32);
    0          
9129 7629           cur = write_number(cur, (yyjson_val *)val, flg);
9130 7629 50         if (unlikely(!cur)) goto fail_num;
9131 7629           *cur++ = ',';
9132 7629           goto val_end;
9133             }
9134 5475 100         if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
9135             (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
9136 5450           ctn_len_tmp = unsafe_yyjson_get_len(val);
9137 5450           ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
9138 5450 50         incr_len(16);
    0          
9139 5450 100         if (unlikely(ctn_len_tmp == 0)) {
9140             /* write empty container */
9141 29           *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
9142 29           *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
9143 29           *cur++ = ',';
9144 29           goto val_end;
9145             } else {
9146             /* push context, setup new container */
9147 5421           yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj);
9148 5421           ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
9149 5421           ctn_obj = ctn_obj_tmp;
9150 5421           *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9151 5421           ctn = val;
9152 5421           val = (yyjson_mut_val *)ctn->uni.ptr; /* tail */
9153 5421 100         val = ctn_obj ? val->next->next : val->next;
9154 5421           goto val_begin;
9155             }
9156             }
9157 25 100         if (val_type == YYJSON_TYPE_BOOL) {
9158 13 50         incr_len(16);
    0          
9159 13 100         cur = write_bool(cur, unsafe_yyjson_get_bool(val));
9160 13           cur++;
9161 13           goto val_end;
9162             }
9163 12 50         if (val_type == YYJSON_TYPE_NULL) {
9164 12 50         incr_len(16);
    0          
9165 12           cur = write_null(cur);
9166 12           cur++;
9167 12           goto val_end;
9168             }
9169 0 0         if (val_type == YYJSON_TYPE_RAW) {
9170 0           str_len = unsafe_yyjson_get_len(val);
9171 0           str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9172             check_str_len(str_len);
9173 0 0         incr_len(str_len + 2);
    0          
9174 0           cur = write_raw(cur, str_ptr, str_len);
9175 0           *cur++ = ',';
9176 0           goto val_end;
9177             }
9178 0           goto fail_type;
9179            
9180 41886           val_end:
9181 41886           ctn_len--;
9182 41886 100         if (unlikely(ctn_len == 0)) goto ctn_end;
9183 35506           val = val->next;
9184 35506           goto val_begin;
9185            
9186 6531           ctn_end:
9187 6531           cur--;
9188 6531           *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
9189 6531           *cur++ = ',';
9190 6531 100         if (unlikely((u8 *)ctx >= end)) goto doc_end;
9191 5421           val = ctn->next;
9192 5421           yyjson_mut_write_ctx_get(ctx++, &ctn, &ctn_len, &ctn_obj);
9193 5421           ctn_len--;
9194 5421 100         if (likely(ctn_len > 0)) {
9195 5270           goto val_begin;
9196             } else {
9197 151           goto ctn_end;
9198             }
9199            
9200 1110           doc_end:
9201 1110 50         if (newline) {
9202 0 0         incr_len(2);
    0          
9203 0           *(cur - 1) = '\n';
9204 0           cur++;
9205             }
9206 1110           *--cur = '\0';
9207 1110           *dat_len = (usize)(cur - hdr);
9208 1110           err->code = YYJSON_WRITE_SUCCESS;
9209 1110           err->msg = "success";
9210 1110           return hdr;
9211            
9212 0           fail_alloc:
9213 0 0         return_err(MEMORY_ALLOCATION, "memory allocation failed");
9214 0           fail_type:
9215 0 0         return_err(INVALID_VALUE_TYPE, "invalid JSON value type");
9216 0           fail_num:
9217 0 0         return_err(NAN_OR_INF, "nan or inf number is not allowed");
9218 0           fail_str:
9219 0 0         return_err(INVALID_STRING, "invalid utf-8 encoding in string");
9220            
9221             #undef return_err
9222             #undef incr_len
9223             #undef check_str_len
9224             }
9225              
9226             /** Write JSON document pretty.
9227             The root of this document should be a non-empty container. */
9228             static_inline u8 *yyjson_mut_write_pretty(const yyjson_mut_val *root,
9229             usize estimated_val_num,
9230             yyjson_write_flag flg,
9231             yyjson_alc alc,
9232             usize *dat_len,
9233             yyjson_write_err *err) {
9234            
9235             #define return_err(_code, _msg) do { \
9236             *dat_len = 0; \
9237             err->code = YYJSON_WRITE_ERROR_##_code; \
9238             err->msg = _msg; \
9239             if (hdr) alc.free(alc.ctx, hdr); \
9240             return NULL; \
9241             } while (false)
9242            
9243             #define incr_len(_len) do { \
9244             ext_len = (usize)(_len); \
9245             if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
9246             alc_inc = yyjson_max(alc_len / 2, ext_len); \
9247             alc_inc = size_align_up(alc_inc, sizeof(yyjson_mut_write_ctx)); \
9248             if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
9249             goto fail_alloc; \
9250             alc_len += alc_inc; \
9251             tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
9252             if (unlikely(!tmp)) goto fail_alloc; \
9253             ctx_len = (usize)(end - (u8 *)ctx); \
9254             ctx_tmp = (yyjson_mut_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
9255             memmove((void *)ctx_tmp, (void *)(tmp + ((u8 *)ctx - hdr)), ctx_len); \
9256             ctx = ctx_tmp; \
9257             cur = tmp + (cur - hdr); \
9258             end = tmp + alc_len; \
9259             hdr = tmp; \
9260             } \
9261             } while (false)
9262            
9263             #define check_str_len(_len) do { \
9264             if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
9265             goto fail_alloc; \
9266             } while (false)
9267            
9268             yyjson_mut_val *val, *ctn;
9269             yyjson_type val_type;
9270             usize ctn_len, ctn_len_tmp;
9271             bool ctn_obj, ctn_obj_tmp, is_key, no_indent;
9272             u8 *hdr, *cur, *end, *tmp;
9273             yyjson_mut_write_ctx *ctx, *ctx_tmp;
9274             usize alc_len, alc_inc, ctx_len, ext_len, str_len, level;
9275             const u8 *str_ptr;
9276 14           const char_enc_type *enc_table = get_enc_table_with_flag(flg);
9277 14           bool cpy = (enc_table == enc_table_cpy);
9278 14           bool esc = has_write_flag(ESCAPE_UNICODE) != 0;
9279 14           bool inv = has_write_flag(ALLOW_INVALID_UNICODE) != 0;
9280 28 100         usize spaces = has_write_flag(PRETTY_TWO_SPACES) ? 2 : 4;
9281 14           bool newline = has_write_flag(NEWLINE_AT_END) != 0;
9282            
9283 14           alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64;
9284 14           alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx));
9285 14           hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
9286 14 50         if (!hdr) goto fail_alloc;
9287 14           cur = hdr;
9288 14           end = hdr + alc_len;
9289 14           ctx = (yyjson_mut_write_ctx *)(void *)end;
9290            
9291 14           doc_begin:
9292 14           val = constcast(yyjson_mut_val *)root;
9293 14           val_type = unsafe_yyjson_get_type(val);
9294 14           ctn_obj = (val_type == YYJSON_TYPE_OBJ);
9295 14           ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
9296 14           *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9297 14           *cur++ = '\n';
9298 14           ctn = val;
9299 14           val = (yyjson_mut_val *)val->uni.ptr; /* tail */
9300 14 100         val = ctn_obj ? val->next->next : val->next;
9301 14           level = 1;
9302            
9303 287           val_begin:
9304 301           val_type = unsafe_yyjson_get_type(val);
9305 301 100         if (val_type == YYJSON_TYPE_STR) {
9306 175           is_key = (bool)((u8)ctn_obj & (u8)~ctn_len);
9307 175           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9308 175           str_len = unsafe_yyjson_get_len(val);
9309 175           str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9310             check_str_len(str_len);
9311 175 100         incr_len(str_len * 6 + 16 + (no_indent ? 0 : level * 4));
    50          
    0          
9312 175 100         cur = write_indent(cur, no_indent ? 0 : level, spaces);
9313 350 50         if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
    50          
9314 0           cur = write_string_noesc(cur, str_ptr, str_len);
9315             } else {
9316 175           cur = write_string(cur, esc, inv, str_ptr, str_len, enc_table);
9317 175 50         if (unlikely(!cur)) goto fail_str;
9318             }
9319 175 100         *cur++ = is_key ? ':' : ',';
9320 175 100         *cur++ = is_key ? ' ' : '\n';
9321 175           goto val_end;
9322             }
9323 126 100         if (val_type == YYJSON_TYPE_NUM) {
9324 74           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9325 74 100         incr_len(32 + (no_indent ? 0 : level * 4));
    50          
    0          
9326 148 100         cur = write_indent(cur, no_indent ? 0 : level, spaces);
    50          
9327 74           cur = write_number(cur, (yyjson_val *)val, flg);
9328 74 50         if (unlikely(!cur)) goto fail_num;
9329 74           *cur++ = ',';
9330 74           *cur++ = '\n';
9331 74           goto val_end;
9332             }
9333 52 100         if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
9334             (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
9335 51           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9336 51           ctn_len_tmp = unsafe_yyjson_get_len(val);
9337 51           ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
9338 51 100         if (unlikely(ctn_len_tmp == 0)) {
9339             /* write empty container */
9340 2 50         incr_len(16 + (no_indent ? 0 : level * 4));
    50          
    0          
9341 2 50         cur = write_indent(cur, no_indent ? 0 : level, spaces);
9342 2           *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
9343 2           *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
9344 2           *cur++ = ',';
9345 2           *cur++ = '\n';
9346 2           goto val_end;
9347             } else {
9348             /* push context, setup new container */
9349 49 100         incr_len(32 + (no_indent ? 0 : level * 4));
    50          
    0          
9350 49           yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj);
9351 49           ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
9352 49           ctn_obj = ctn_obj_tmp;
9353 49 100         cur = write_indent(cur, no_indent ? 0 : level, spaces);
9354 49           level++;
9355 49           *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9356 49           *cur++ = '\n';
9357 49           ctn = val;
9358 49           val = (yyjson_mut_val *)ctn->uni.ptr; /* tail */
9359 49 100         val = ctn_obj ? val->next->next : val->next;
9360 49           goto val_begin;
9361             }
9362             }
9363 1 50         if (val_type == YYJSON_TYPE_BOOL) {
9364 0           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9365 0 0         incr_len(16 + (no_indent ? 0 : level * 4));
    0          
    0          
9366 0 0         cur = write_indent(cur, no_indent ? 0 : level, spaces);
9367 0 0         cur = write_bool(cur, unsafe_yyjson_get_bool(val));
9368 0           cur += 2;
9369 0           goto val_end;
9370             }
9371 1 50         if (val_type == YYJSON_TYPE_NULL) {
9372 1           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9373 1 50         incr_len(16 + (no_indent ? 0 : level * 4));
    50          
    0          
9374 2 50         cur = write_indent(cur, no_indent ? 0 : level, spaces);
9375 1           cur = write_null(cur);
9376 1           cur += 2;
9377 1           goto val_end;
9378             }
9379 0 0         if (val_type == YYJSON_TYPE_RAW) {
9380 0           str_len = unsafe_yyjson_get_len(val);
9381 0           str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9382             check_str_len(str_len);
9383 0 0         incr_len(str_len + 3);
    0          
9384 0           cur = write_raw(cur, str_ptr, str_len);
9385 0           *cur++ = ',';
9386 0           *cur++ = '\n';
9387 0           goto val_end;
9388             }
9389 0           goto fail_type;
9390            
9391 252           val_end:
9392 252           ctn_len--;
9393 252 100         if (unlikely(ctn_len == 0)) goto ctn_end;
9394 211           val = val->next;
9395 211           goto val_begin;
9396            
9397 63           ctn_end:
9398 63           cur -= 2;
9399 63           *cur++ = '\n';
9400 63 50         incr_len(level * 4);
    0          
9401 63           cur = write_indent(cur, --level, spaces);
9402 63           *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
9403 63 100         if (unlikely((u8 *)ctx >= end)) goto doc_end;
9404 49           val = ctn->next;
9405 49           yyjson_mut_write_ctx_get(ctx++, &ctn, &ctn_len, &ctn_obj);
9406 49           ctn_len--;
9407 49           *cur++ = ',';
9408 49           *cur++ = '\n';
9409 49 100         if (likely(ctn_len > 0)) {
9410 27           goto val_begin;
9411             } else {
9412 22           goto ctn_end;
9413             }
9414            
9415 14           doc_end:
9416 14 50         if (newline) {
9417 0 0         incr_len(2);
    0          
9418 0           *cur++ = '\n';
9419             }
9420 14           *cur = '\0';
9421 14           *dat_len = (usize)(cur - hdr);
9422 14           err->code = YYJSON_WRITE_SUCCESS;
9423 14           err->msg = "success";
9424 14           return hdr;
9425            
9426 0           fail_alloc:
9427 0 0         return_err(MEMORY_ALLOCATION, "memory allocation failed");
9428 0           fail_type:
9429 0 0         return_err(INVALID_VALUE_TYPE, "invalid JSON value type");
9430 0           fail_num:
9431 0 0         return_err(NAN_OR_INF, "nan or inf number is not allowed");
9432 0           fail_str:
9433 0 0         return_err(INVALID_STRING, "invalid utf-8 encoding in string");
9434            
9435             #undef return_err
9436             #undef incr_len
9437             #undef check_str_len
9438             }
9439              
9440 1150           static char *yyjson_mut_write_opts_impl(const yyjson_mut_val *val,
9441             usize estimated_val_num,
9442             yyjson_write_flag flg,
9443             const yyjson_alc *alc_ptr,
9444             usize *dat_len,
9445             yyjson_write_err *err) {
9446             yyjson_write_err dummy_err;
9447             usize dummy_dat_len;
9448 1150 50         yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
9449 1150           yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
9450            
9451 1150 50         err = err ? err : &dummy_err;
9452 1150 50         dat_len = dat_len ? dat_len : &dummy_dat_len;
9453            
9454 1150 50         if (unlikely(!root)) {
9455 0           *dat_len = 0;
9456 0           err->msg = "input JSON is NULL";
9457 0           err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
9458 0           return NULL;
9459             }
9460            
9461 2280 100         if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) {
    100          
9462 26           return (char *)yyjson_mut_write_single(root, flg, alc, dat_len, err);
9463 1124 100         } else if (flg & (YYJSON_WRITE_PRETTY | YYJSON_WRITE_PRETTY_TWO_SPACES)) {
9464 14           return (char *)yyjson_mut_write_pretty(root, estimated_val_num,
9465             flg, alc, dat_len, err);
9466             } else {
9467 1110           return (char *)yyjson_mut_write_minify(root, estimated_val_num,
9468             flg, alc, dat_len, err);
9469             }
9470             }
9471              
9472 0           char *yyjson_mut_val_write_opts(const yyjson_mut_val *val,
9473             yyjson_write_flag flg,
9474             const yyjson_alc *alc_ptr,
9475             usize *dat_len,
9476             yyjson_write_err *err) {
9477 0           return yyjson_mut_write_opts_impl(val, 0, flg, alc_ptr, dat_len, err);
9478             }
9479              
9480 1150           char *yyjson_mut_write_opts(const yyjson_mut_doc *doc,
9481             yyjson_write_flag flg,
9482             const yyjson_alc *alc_ptr,
9483             usize *dat_len,
9484             yyjson_write_err *err) {
9485             yyjson_mut_val *root;
9486             usize estimated_val_num;
9487 1150 50         if (likely(doc)) {
9488 1150           root = doc->root;
9489 1150           estimated_val_num = yyjson_mut_doc_estimated_val_num(doc);
9490             } else {
9491 0           root = NULL;
9492 0           estimated_val_num = 0;
9493             }
9494 1150           return yyjson_mut_write_opts_impl(root, estimated_val_num,
9495             flg, alc_ptr, dat_len, err);
9496             }
9497              
9498 0           bool yyjson_mut_val_write_file(const char *path,
9499             const yyjson_mut_val *val,
9500             yyjson_write_flag flg,
9501             const yyjson_alc *alc_ptr,
9502             yyjson_write_err *err) {
9503             yyjson_write_err dummy_err;
9504             u8 *dat;
9505 0           usize dat_len = 0;
9506 0           yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
9507             bool suc;
9508            
9509 0 0         alc_ptr = alc_ptr ? alc_ptr : &YYJSON_DEFAULT_ALC;
9510 0 0         err = err ? err : &dummy_err;
9511 0 0         if (unlikely(!path || !*path)) {
    0          
9512 0           err->msg = "input path is invalid";
9513 0           err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
9514 0           return false;
9515             }
9516            
9517 0           dat = (u8 *)yyjson_mut_val_write_opts(root, flg, alc_ptr, &dat_len, err);
9518 0 0         if (unlikely(!dat)) return false;
9519 0           suc = write_dat_to_file(path, dat, dat_len, err);
9520 0           alc_ptr->free(alc_ptr->ctx, dat);
9521 0           return suc;
9522             }
9523              
9524 0           bool yyjson_mut_val_write_fp(FILE *fp,
9525             const yyjson_mut_val *val,
9526             yyjson_write_flag flg,
9527             const yyjson_alc *alc_ptr,
9528             yyjson_write_err *err) {
9529             yyjson_write_err dummy_err;
9530             u8 *dat;
9531 0           usize dat_len = 0;
9532 0           yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
9533             bool suc;
9534            
9535 0 0         alc_ptr = alc_ptr ? alc_ptr : &YYJSON_DEFAULT_ALC;
9536 0 0         err = err ? err : &dummy_err;
9537 0 0         if (unlikely(!fp)) {
9538 0           err->msg = "input fp is invalid";
9539 0           err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
9540 0           return false;
9541             }
9542            
9543 0           dat = (u8 *)yyjson_mut_val_write_opts(root, flg, alc_ptr, &dat_len, err);
9544 0 0         if (unlikely(!dat)) return false;
9545 0           suc = write_dat_to_fp(fp, dat, dat_len, err);
9546 0           alc_ptr->free(alc_ptr->ctx, dat);
9547 0           return suc;
9548             }
9549              
9550 0           bool yyjson_mut_write_file(const char *path,
9551             const yyjson_mut_doc *doc,
9552             yyjson_write_flag flg,
9553             const yyjson_alc *alc_ptr,
9554             yyjson_write_err *err) {
9555 0 0         yyjson_mut_val *root = doc ? doc->root : NULL;
9556 0           return yyjson_mut_val_write_file(path, root, flg, alc_ptr, err);
9557             }
9558              
9559 0           bool yyjson_mut_write_fp(FILE *fp,
9560             const yyjson_mut_doc *doc,
9561             yyjson_write_flag flg,
9562             const yyjson_alc *alc_ptr,
9563             yyjson_write_err *err) {
9564 0 0         yyjson_mut_val *root = doc ? doc->root : NULL;
9565 0           return yyjson_mut_val_write_fp(fp, root, flg, alc_ptr, err);
9566             }
9567              
9568             #endif /* YYJSON_DISABLE_WRITER */