File Coverage

yyjson.c
Criterion Covered Total %
statement 1462 4428 33.0
branch 1032 14878 6.9
condition n/a
subroutine n/a
pod n/a
total 2494 19306 12.9


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 /* for `HUGE_VAL/INFINIY/NAN` macros, no libm required */
25              
26              
27              
28             /*==============================================================================
29             * MARK: - Warning Suppress (Private)
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             * MARK: - Version (Public)
56             *============================================================================*/
57              
58 0           uint32_t yyjson_version(void) {
59 0           return YYJSON_VERSION_HEX;
60             }
61              
62              
63              
64             /*==============================================================================
65             * MARK: - Flags (Private)
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 && \
123             FLT_MANT_DIG == 24 && FLT_DIG == 6 && \
124             FLT_MIN_EXP == -125 && FLT_MAX_EXP == 128 && \
125             FLT_MIN_10_EXP == -37 && FLT_MAX_10_EXP == 38 && \
126             DBL_MANT_DIG == 53 && DBL_DIG == 15 && \
127             DBL_MIN_EXP == -1021 && DBL_MAX_EXP == 1024 && \
128             DBL_MIN_10_EXP == -307 && DBL_MAX_10_EXP == 308
129             # define YYJSON_HAS_IEEE_754 1
130             #else
131             # define YYJSON_HAS_IEEE_754 0
132             # undef YYJSON_DISABLE_FAST_FP_CONV
133             # define YYJSON_DISABLE_FAST_FP_CONV 1
134             #endif
135              
136             /*
137             Correct rounding in double number computations.
138              
139             On the x86 architecture, some compilers may use x87 FPU instructions for
140             floating-point arithmetic. The x87 FPU loads all floating point number as
141             80-bit double-extended precision internally, then rounds the result to original
142             precision, which may produce inaccurate results. For a more detailed
143             explanation, see the paper: https://arxiv.org/abs/cs/0701192
144              
145             Here are some examples of double precision calculation error:
146              
147             2877.0 / 1e6 == 0.002877, but x87 returns 0.0028770000000000002
148             43683.0 * 1e21 == 4.3683e25, but x87 returns 4.3683000000000004e25
149              
150             Here are some examples of compiler flags to generate x87 instructions on x86:
151              
152             clang -m32 -mno-sse
153             gcc/icc -m32 -mfpmath=387
154             msvc /arch:SSE or /arch:IA32
155              
156             If we are sure that there's no similar error described above, we can define the
157             YYJSON_DOUBLE_MATH_CORRECT as 1 to enable the fast path calculation. This is
158             not an accurate detection, it's just try to avoid the error at compile-time.
159             An accurate detection can be done at run-time:
160              
161             bool is_double_math_correct(void) {
162             volatile double r = 43683.0;
163             r *= 1e21;
164             return r == 4.3683e25;
165             }
166              
167             See also: utils.h in https://github.com/google/double-conversion/
168             */
169             #if !defined(FLT_EVAL_METHOD) && defined(__FLT_EVAL_METHOD__)
170             # define FLT_EVAL_METHOD __FLT_EVAL_METHOD__
171             #endif
172              
173             #if defined(FLT_EVAL_METHOD) && FLT_EVAL_METHOD != 0 && FLT_EVAL_METHOD != 1
174             # define YYJSON_DOUBLE_MATH_CORRECT 0
175             #elif defined(i386) || defined(__i386) || defined(__i386__) || \
176             defined(_X86_) || defined(__X86__) || defined(_M_IX86) || \
177             defined(__I86__) || defined(__IA32__) || defined(__THW_INTEL)
178             # if (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP == 2) || \
179             (defined(__SSE2_MATH__) && __SSE2_MATH__)
180             # define YYJSON_DOUBLE_MATH_CORRECT 1
181             # else
182             # define YYJSON_DOUBLE_MATH_CORRECT 0
183             # endif
184             #elif defined(__mc68000__) || defined(__pnacl__) || defined(__native_client__)
185             # define YYJSON_DOUBLE_MATH_CORRECT 0
186             #else
187             # define YYJSON_DOUBLE_MATH_CORRECT 1
188             #endif
189              
190             /*
191             Detect the endianness at compile-time.
192             YYJSON_ENDIAN == YYJSON_BIG_ENDIAN
193             YYJSON_ENDIAN == YYJSON_LITTLE_ENDIAN
194             */
195             #define YYJSON_BIG_ENDIAN 4321
196             #define YYJSON_LITTLE_ENDIAN 1234
197              
198             #if yyjson_has_include()
199             # include /* POSIX */
200             #endif
201             #if yyjson_has_include()
202             # include /* Linux */
203             #elif yyjson_has_include()
204             # include /* BSD, Android */
205             #elif yyjson_has_include()
206             # include /* BSD, Darwin */
207             #endif
208              
209             #if defined(BYTE_ORDER) && BYTE_ORDER
210             # if defined(BIG_ENDIAN) && (BYTE_ORDER == BIG_ENDIAN)
211             # define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
212             # elif defined(LITTLE_ENDIAN) && (BYTE_ORDER == LITTLE_ENDIAN)
213             # define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
214             # endif
215             #elif defined(__BYTE_ORDER) && __BYTE_ORDER
216             # if defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN)
217             # define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
218             # elif defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN)
219             # define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
220             # endif
221             #elif defined(__BYTE_ORDER__) && __BYTE_ORDER__
222             # if defined(__ORDER_BIG_ENDIAN__) && \
223             (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
224             # define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
225             # elif defined(__ORDER_LITTLE_ENDIAN__) && \
226             (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
227             # define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
228             # endif
229             #elif (defined(__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__ == 1) || \
230             defined(__i386) || defined(__i386__) || \
231             defined(_X86_) || defined(__X86__) || \
232             defined(_M_IX86) || defined(__THW_INTEL__) || \
233             defined(__x86_64) || defined(__x86_64__) || \
234             defined(__amd64) || defined(__amd64__) || \
235             defined(_M_AMD64) || defined(_M_X64) || \
236             defined(_M_ARM) || defined(_M_ARM64) || \
237             defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \
238             defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || \
239             defined(__EMSCRIPTEN__) || defined(__wasm__) || \
240             defined(__loongarch__)
241             # define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
242             #elif (defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ == 1) || \
243             defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \
244             defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) || \
245             defined(__or1k__) || defined(__OR1K__)
246             # define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
247             #else
248             # define YYJSON_ENDIAN 0 /* unknown endian, detect at run-time */
249             #endif
250              
251             /*
252             This macro controls how yyjson handles unaligned memory accesses.
253              
254             By default, yyjson uses `memcpy()` for memory copying. This allows the compiler
255             to optimize the code and emit unaligned memory access instructions when
256             supported by the target architecture.
257              
258             However, on some older compilers or architectures where `memcpy()` is not
259             well-optimized and may result in unnecessary function calls, defining this
260             macro as 1 may help. In such cases, yyjson switches to manual byte-by-byte
261             access, which can potentially improve performance.
262              
263             An example of the generated assembly code for ARM can be found here:
264             https://godbolt.org/z/334jjhxPT
265              
266             This flag is already enabled for common architectures in the following code,
267             so manual configuration is usually unnecessary. If unsure, you can check the
268             generated assembly or run benchmarks to make an informed decision.
269             */
270             #ifndef YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
271             # if defined(__ia64) || defined(_IA64) || defined(__IA64__) || \
272             defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
273             # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* Itanium */
274             # elif (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) && \
275             (defined(__GNUC__) || defined(__clang__)) && \
276             (!defined(__ARM_FEATURE_UNALIGNED) || !__ARM_FEATURE_UNALIGNED)
277             # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* ARM */
278             # elif defined(__sparc) || defined(__sparc__)
279             # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* SPARC */
280             # elif defined(__mips) || defined(__mips__) || defined(__MIPS__)
281             # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* MIPS */
282             # elif defined(__m68k__) || defined(M68000)
283             # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* M68K */
284             # else
285             # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 0
286             # endif
287             #endif
288              
289             /*
290             Estimated initial ratio of the JSON data (data_size / value_count).
291             For example:
292              
293             data: {"id":12345678,"name":"Harry"}
294             data_size: 30
295             value_count: 5
296             ratio: 6
297              
298             yyjson uses dynamic memory with a growth factor of 1.5 when reading and writing
299             JSON, the ratios below are used to determine the initial memory size.
300              
301             A too large ratio will waste memory, and a too small ratio will cause multiple
302             memory growths and degrade performance. Currently, these ratios are generated
303             with some commonly used JSON datasets.
304             */
305             #define YYJSON_READER_ESTIMATED_PRETTY_RATIO 16
306             #define YYJSON_READER_ESTIMATED_MINIFY_RATIO 6
307             #define YYJSON_WRITER_ESTIMATED_PRETTY_RATIO 32
308             #define YYJSON_WRITER_ESTIMATED_MINIFY_RATIO 18
309              
310             /* The initial and maximum size of the memory pool's chunk in yyjson_mut_doc. */
311             #define YYJSON_MUT_DOC_STR_POOL_INIT_SIZE 0x100
312             #define YYJSON_MUT_DOC_STR_POOL_MAX_SIZE 0x10000000
313             #define YYJSON_MUT_DOC_VAL_POOL_INIT_SIZE (0x10 * sizeof(yyjson_mut_val))
314             #define YYJSON_MUT_DOC_VAL_POOL_MAX_SIZE (0x1000000 * sizeof(yyjson_mut_val))
315              
316             /* The minimum size of the dynamic allocator's chunk. */
317             #define YYJSON_ALC_DYN_MIN_SIZE 0x1000
318              
319             /* Default value for compile-time options. */
320             #ifndef YYJSON_DISABLE_READER
321             #define YYJSON_DISABLE_READER 0
322             #endif
323             #ifndef YYJSON_DISABLE_WRITER
324             #define YYJSON_DISABLE_WRITER 0
325             #endif
326             #ifndef YYJSON_DISABLE_INCR_READER
327             #define YYJSON_DISABLE_INCR_READER 0
328             #endif
329             #ifndef YYJSON_DISABLE_UTILS
330             #define YYJSON_DISABLE_UTILS 0
331             #endif
332             #ifndef YYJSON_DISABLE_FAST_FP_CONV
333             #define YYJSON_DISABLE_FAST_FP_CONV 0
334             #endif
335             #ifndef YYJSON_DISABLE_NON_STANDARD
336             #define YYJSON_DISABLE_NON_STANDARD 0
337             #endif
338             #ifndef YYJSON_DISABLE_UTF8_VALIDATION
339             #define YYJSON_DISABLE_UTF8_VALIDATION 0
340             #endif
341              
342              
343              
344             /*==============================================================================
345             * MARK: - Macros (Private)
346             *============================================================================*/
347              
348             /* Macros used for loop unrolling and other purpose. */
349             #define repeat2(x) { x x }
350             #define repeat4(x) { x x x x }
351             #define repeat8(x) { x x x x x x x x }
352             #define repeat16(x) { x x x x x x x x x x x x x x x x }
353              
354             #define repeat2_incr(x) { x(0) x(1) }
355             #define repeat4_incr(x) { x(0) x(1) x(2) x(3) }
356             #define repeat8_incr(x) { x(0) x(1) x(2) x(3) x(4) x(5) x(6) x(7) }
357             #define repeat16_incr(x) { x(0) x(1) x(2) x(3) x(4) x(5) x(6) x(7) \
358             x(8) x(9) x(10) x(11) x(12) x(13) x(14) x(15) }
359             #define repeat_in_1_18(x) { x(1) x(2) x(3) x(4) x(5) x(6) x(7) x(8) \
360             x(9) x(10) x(11) x(12) x(13) x(14) x(15) x(16) \
361             x(17) x(18) }
362              
363             /* Macros used to provide branch prediction information for compiler. */
364             #undef likely
365             #define likely(x) yyjson_likely(x)
366             #undef unlikely
367             #define unlikely(x) yyjson_unlikely(x)
368              
369             /* Macros used to provide inline information for compiler. */
370             #undef static_inline
371             #define static_inline static yyjson_inline
372             #undef static_noinline
373             #define static_noinline static yyjson_noinline
374              
375             /* Macros for min and max. */
376             #undef yyjson_min
377             #define yyjson_min(x, y) ((x) < (y) ? (x) : (y))
378             #undef yyjson_max
379             #define yyjson_max(x, y) ((x) > (y) ? (x) : (y))
380              
381             /* Used to write u64 literal for C89 which doesn't support "ULL" suffix. */
382             #undef U64
383             #define U64(hi, lo) ((((u64)hi##UL) << 32U) + lo##UL)
384             #undef U32
385             #define U32(hi) ((u32)(hi##UL))
386              
387             /* Used to cast away (remove) const qualifier. */
388             #define constcast(type) (type)(void *)(size_t)(const void *)
389              
390             /*
391             Compiler barriers for single variables.
392              
393             These macros inform GCC that a read or write access to the given memory
394             location will occur, preventing certain compiler optimizations or reordering
395             around the access to 'val'. They do not emit any actual instructions.
396              
397             This is useful when GCC's default optimization strategies are suboptimal and
398             precise control over memory access patterns is required.
399             These barriers are not needed when using Clang or MSVC.
400             */
401             #if YYJSON_IS_REAL_GCC
402             # define gcc_load_barrier(val) __asm__ volatile(""::"m"(val))
403             # define gcc_store_barrier(val) __asm__ volatile("":"=m"(val))
404             # define gcc_full_barrier(val) __asm__ volatile("":"=m"(val):"m"(val))
405             #else
406             # define gcc_load_barrier(val)
407             # define gcc_store_barrier(val)
408             # define gcc_full_barrier(val)
409             #endif
410              
411              
412              
413             /*==============================================================================
414             * MARK: - Constants (Private)
415             *============================================================================*/
416              
417             /* Common error messages. */
418             #define MSG_FOPEN "failed to open file"
419             #define MSG_FREAD "failed to read file"
420             #define MSG_FWRITE "failed to write file"
421             #define MSG_FCLOSE "failed to close file"
422             #define MSG_MALLOC "failed to allocate memory"
423             #define MSG_CHAR_T "invalid literal, expected 'true'"
424             #define MSG_CHAR_F "invalid literal, expected 'false'"
425             #define MSG_CHAR_N "invalid literal, expected 'null'"
426             #define MSG_CHAR "unexpected character, expected a JSON value"
427             #define MSG_ARR_END "unexpected character, expected ',' or ']'"
428             #define MSG_OBJ_KEY "unexpected character, expected a string key"
429             #define MSG_OBJ_SEP "unexpected character, expected ':' after key"
430             #define MSG_OBJ_END "unexpected character, expected ',' or '}'"
431             #define MSG_GARBAGE "unexpected content after document"
432             #define MSG_NOT_END "unexpected end of data"
433             #define MSG_COMMENT "unclosed multiline comment"
434             #define MSG_COMMA "trailing comma is not allowed"
435             #define MSG_NAN_INF "nan or inf number is not allowed"
436             #define MSG_ERR_TYPE "invalid JSON value type"
437             #define MSG_ERR_BOM "UTF-8 byte order mark (BOM) is not supported"
438             #define MSG_ERR_UTF8 "invalid utf-8 encoding in string"
439             #define MSG_ERR_UTF16 "UTF-16 encoding is not supported"
440             #define MSG_ERR_UTF32 "UTF-32 encoding is not supported"
441              
442             /* U64 constant values */
443             #undef U64_MAX
444             #define U64_MAX U64(0xFFFFFFFF, 0xFFFFFFFF)
445             #undef I64_MAX
446             #define I64_MAX U64(0x7FFFFFFF, 0xFFFFFFFF)
447             #undef USIZE_MAX
448             #define USIZE_MAX ((usize)(~(usize)0))
449              
450             /* Maximum number of digits for reading u32/u64/usize safety (not overflow). */
451             #undef U32_SAFE_DIG
452             #define U32_SAFE_DIG 9 /* u32 max is 4294967295, 10 digits */
453             #undef U64_SAFE_DIG
454             #define U64_SAFE_DIG 19 /* u64 max is 18446744073709551615, 20 digits */
455             #undef USIZE_SAFE_DIG
456             #define USIZE_SAFE_DIG (sizeof(usize) == 8 ? U64_SAFE_DIG : U32_SAFE_DIG)
457              
458             /* Inf bits (positive) */
459             #define F64_BITS_INF U64(0x7FF00000, 0x00000000)
460              
461             /* NaN bits (quiet NaN, no payload, no sign) */
462             #if defined(__hppa__) || (defined(__mips__) && !defined(__mips_nan2008))
463             #define F64_BITS_NAN U64(0x7FF7FFFF, 0xFFFFFFFF)
464             #else
465             #define F64_BITS_NAN U64(0x7FF80000, 0x00000000)
466             #endif
467              
468             /* maximum significant digits count in decimal when reading double number */
469             #define F64_MAX_DEC_DIG 768
470              
471             /* maximum decimal power of double number (1.7976931348623157e308) */
472             #define F64_MAX_DEC_EXP 308
473              
474             /* minimum decimal power of double number (4.9406564584124654e-324) */
475             #define F64_MIN_DEC_EXP (-324)
476              
477             /* maximum binary power of double number */
478             #define F64_MAX_BIN_EXP 1024
479              
480             /* minimum binary power of double number */
481             #define F64_MIN_BIN_EXP (-1021)
482              
483             /* float/double number bits */
484             #define F32_BITS 32
485             #define F64_BITS 64
486              
487             /* float/double number exponent part bits */
488             #define F32_EXP_BITS 8
489             #define F64_EXP_BITS 11
490              
491             /* float/double number significand part bits */
492             #define F32_SIG_BITS 23
493             #define F64_SIG_BITS 52
494              
495             /* float/double number significand part bits (with 1 hidden bit) */
496             #define F32_SIG_FULL_BITS 24
497             #define F64_SIG_FULL_BITS 53
498              
499             /* float/double number significand bit mask */
500             #define F32_SIG_MASK U32(0x007FFFFF)
501             #define F64_SIG_MASK U64(0x000FFFFF, 0xFFFFFFFF)
502              
503             /* float/double number exponent bit mask */
504             #define F32_EXP_MASK U32(0x7F800000)
505             #define F64_EXP_MASK U64(0x7FF00000, 0x00000000)
506              
507             /* float/double number exponent bias */
508             #define F32_EXP_BIAS 127
509             #define F64_EXP_BIAS 1023
510              
511             /* float/double number significant digits count in decimal */
512             #define F32_DEC_DIG 9
513             #define F64_DEC_DIG 17
514              
515             /* buffer length required for float/double number writer */
516             #define FP_BUF_LEN 40
517              
518             /* maximum length of a number in incremental parsing */
519             #define INCR_NUM_MAX_LEN 1024
520              
521              
522              
523             /*==============================================================================
524             * MARK: - Types (Private)
525             *============================================================================*/
526              
527             /** Type define for primitive types. */
528             typedef float f32;
529             typedef double f64;
530             typedef int8_t i8;
531             typedef uint8_t u8;
532             typedef int16_t i16;
533             typedef uint16_t u16;
534             typedef int32_t i32;
535             typedef uint32_t u32;
536             typedef int64_t i64;
537             typedef uint64_t u64;
538             typedef size_t usize;
539              
540             /** 128-bit integer, used by floating-point number reader and writer. */
541             #if YYJSON_HAS_INT128
542             __extension__ typedef __int128 i128;
543             __extension__ typedef unsigned __int128 u128;
544             #endif
545              
546             /** 16/32/64-bit vector */
547             typedef struct v16 { char c[2]; } v16;
548             typedef struct v32 { char c[4]; } v32;
549             typedef struct v64 { char c[8]; } v64;
550              
551             /** 16/32/64-bit vector union */
552             typedef union v16_uni { v16 v; u16 u; } v16_uni;
553             typedef union v32_uni { v32 v; u32 u; } v32_uni;
554             typedef union v64_uni { v64 v; u64 u; } v64_uni;
555              
556              
557              
558             /*==============================================================================
559             * MARK: - Load/Store Utils (Private)
560             *============================================================================*/
561              
562             #define byte_move_idx(x) ((char *)dst)[x] = ((const char *)src)[x];
563             #define byte_move_src(x) ((char *)tmp)[x] = ((const char *)src)[x];
564             #define byte_move_dst(x) ((char *)dst)[x] = ((const char *)tmp)[x];
565              
566             /** Same as `memcpy(dst, src, 2)`, no overlap. */
567             static_inline void byte_copy_2(void *dst, const void *src) {
568             #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
569 35057           memcpy(dst, src, 2);
570             #else
571             repeat2_incr(byte_move_idx)
572             #endif
573 0           }
574              
575             /** Same as `memcpy(dst, src, 4)`, no overlap. */
576             static_inline void byte_copy_4(void *dst, const void *src) {
577             #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
578 24           memcpy(dst, src, 4);
579             #else
580             repeat4_incr(byte_move_idx)
581             #endif
582 24           }
583              
584             /** Same as `memcpy(dst, src, 8)`, no overlap. */
585             static_inline void byte_copy_8(void *dst, const void *src) {
586             #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
587 9           memcpy(dst, src, 8);
588             #else
589             repeat8_incr(byte_move_idx)
590             #endif
591 6           }
592              
593             /** Same as `memcpy(dst, src, 16)`, no overlap. */
594             static_inline void byte_copy_16(void *dst, const void *src) {
595             #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
596 0           memcpy(dst, src, 16);
597             #else
598             repeat16_incr(byte_move_idx)
599             #endif
600 0           }
601              
602             /** Same as `memmove(dst, src, 2)`, allows overlap. */
603             static_inline void byte_move_2(void *dst, const void *src) {
604             #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
605             u16 tmp;
606 3           memcpy(&tmp, src, 2);
607 3           memcpy(dst, &tmp, 2);
608             #else
609             char tmp[2];
610             repeat2_incr(byte_move_src)
611             repeat2_incr(byte_move_dst)
612             #endif
613 3           }
614              
615             /** Same as `memmove(dst, src, 4)`, allows overlap. */
616             static_inline void byte_move_4(void *dst, const void *src) {
617             #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
618             u32 tmp;
619 1           memcpy(&tmp, src, 4);
620 1           memcpy(dst, &tmp, 4);
621             #else
622             char tmp[4];
623             repeat4_incr(byte_move_src)
624             repeat4_incr(byte_move_dst)
625             #endif
626 1           }
627              
628             /** Same as `memmove(dst, src, 8)`, allows overlap. */
629             static_inline void byte_move_8(void *dst, const void *src) {
630             #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
631             u64 tmp;
632 0           memcpy(&tmp, src, 8);
633 0           memcpy(dst, &tmp, 8);
634             #else
635             char tmp[8];
636             repeat8_incr(byte_move_src)
637             repeat8_incr(byte_move_dst)
638             #endif
639 0           }
640              
641             /** Same as `memmove(dst, src, 16)`, allows overlap. */
642             static_inline void byte_move_16(void *dst, const void *src) {
643             #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
644 1           char *pdst = (char *)dst;
645 1           const char *psrc = (const char *)src;
646             u64 tmp1, tmp2;
647 1           memcpy(&tmp1, psrc, 8);
648 1           memcpy(&tmp2, psrc + 8, 8);
649 1           memcpy(pdst, &tmp1, 8);
650 1           memcpy(pdst + 8, &tmp2, 8);
651             #else
652             char tmp[16];
653             repeat16_incr(byte_move_src)
654             repeat16_incr(byte_move_dst)
655             #endif
656 0           }
657              
658             /** Same as `memmove(dst, src, n)`, but only `dst <= src` and `n <= 16`. */
659             static_inline void byte_move_forward(void *dst, void *src, usize n) {
660 9           char *d = (char *)dst, *s = (char *)src;
661 9           n += (n % 2); /* round up to even */
662 0           if (n == 16) { byte_move_16(d, s); return; }
663 9 0         if (n >= 8) { byte_move_8(d, s); n -= 8; d += 8; s += 8; }
    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          
    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          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    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          
    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          
664 10 0         if (n >= 4) { byte_move_4(d, s); n -= 4; d += 4; s += 4; }
    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          
    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          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    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          
    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          
665 9 0         if (n >= 2) { byte_move_2(d, s); }
    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          
    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          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    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          
    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          
666             }
667              
668             /** Same as `memcmp(buf, pat, 2) == 0`. */
669             static_inline bool byte_match_2(void *buf, const char *pat) {
670             #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
671             v16_uni u1, u2;
672 73           memcpy(&u1, buf, 2);
673 73           memcpy(&u2, pat, 2);
674 1           return u1.u == u2.u;
675             #else
676             return ((char *)buf)[0] == ((const char *)pat)[0] &&
677             ((char *)buf)[1] == ((const char *)pat)[1];
678             #endif
679             }
680              
681             /** Same as `memcmp(buf, pat, 4) == 0`. */
682             static_inline bool byte_match_4(void *buf, const char *pat) {
683             #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
684             v32_uni u1, u2;
685 28           memcpy(&u1, buf, 4);
686 28           memcpy(&u2, pat, 4);
687 28           return u1.u == u2.u;
688             #else
689             return ((char *)buf)[0] == ((const char *)pat)[0] &&
690             ((char *)buf)[1] == ((const char *)pat)[1] &&
691             ((char *)buf)[2] == ((const char *)pat)[2] &&
692             ((char *)buf)[3] == ((const char *)pat)[3];
693             #endif
694             }
695              
696             /** Loads 2 bytes from `src` as a u16 (native-endian). */
697             static_inline u16 byte_load_2(const void *src) {
698             v16_uni uni;
699             #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
700 12           memcpy(&uni, src, 2);
701             #else
702             uni.v.c[0] = ((const char *)src)[0];
703             uni.v.c[1] = ((const char *)src)[1];
704             #endif
705 6           return uni.u;
706             }
707              
708             /** Loads 3 bytes from `src` as a u32 (native-endian). */
709             static_inline u32 byte_load_3(const void *src) {
710             v32_uni uni;
711             #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
712 8           memcpy(&uni, src, 2);
713 8           uni.v.c[2] = ((const char *)src)[2];
714 8           uni.v.c[3] = 0;
715             #else
716             uni.v.c[0] = ((const char *)src)[0];
717             uni.v.c[1] = ((const char *)src)[1];
718             uni.v.c[2] = ((const char *)src)[2];
719             uni.v.c[3] = 0;
720             #endif
721 4           return uni.u;
722             }
723              
724             /** Loads 4 bytes from `src` as a u32 (native-endian). */
725             static_inline u32 byte_load_4(const void *src) {
726             v32_uni uni;
727             #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
728 18           memcpy(&uni, src, 4);
729             #else
730             uni.v.c[0] = ((const char *)src)[0];
731             uni.v.c[1] = ((const char *)src)[1];
732             uni.v.c[2] = ((const char *)src)[2];
733             uni.v.c[3] = ((const char *)src)[3];
734             #endif
735 6           return uni.u;
736             }
737              
738              
739              
740             /*==============================================================================
741             * MARK: - Character Utils (Private)
742             * These lookup tables were generated by `misc/make_tables.c`.
743             *============================================================================*/
744              
745             /* char_table1 */
746             #define CHAR_TYPE_ASCII (1 << 0) /* Except: ["\], [0x00-0x1F, 0x80-0xFF] */
747             #define CHAR_TYPE_ASCII_SQ (1 << 1) /* Except: ['\], [0x00-0x1F, 0x80-0xFF] */
748             #define CHAR_TYPE_SPACE (1 << 2) /* Whitespace: [ \t\n\r] */
749             #define CHAR_TYPE_SPACE_EXT (1 << 3) /* Whitespace: [ \t\n\r\v\f], JSON5 */
750             #define CHAR_TYPE_NUM (1 << 4) /* Number: [.-+0-9] */
751             #define CHAR_TYPE_COMMENT (1 << 5) /* Comment: [/] */
752              
753             /* char_table2 */
754             #define CHAR_TYPE_EOL (1 << 0) /* End of line: [\r\n] */
755             #define CHAR_TYPE_EOL_EXT (1 << 1) /* End of line: [\r\n], JSON5 */
756             #define CHAR_TYPE_ID_START (1 << 2) /* ID start: [_$A-Za-z\], U+0080+ */
757             #define CHAR_TYPE_ID_NEXT (1 << 3) /* ID next: [_$A-Za-z0-9\], U+0080+ */
758             #define CHAR_TYPE_ID_ASCII (1 << 4) /* ID next ASCII: [_$A-Za-z0-9] */
759              
760             /* char_table3 */
761             #define CHAR_TYPE_SIGN (1 << 0) /* [-+] */
762             #define CHAR_TYPE_DIGIT (1 << 1) /* [0-9] */
763             #define CHAR_TYPE_NONZERO (1 << 2) /* [1-9] */
764             #define CHAR_TYPE_EXP (1 << 3) /* [eE] */
765             #define CHAR_TYPE_DOT (1 << 4) /* [.] */
766              
767             static const u8 char_table1[256] = {
768             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
769             0x00, 0x0C, 0x0C, 0x08, 0x08, 0x0C, 0x00, 0x00,
770             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
771             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
772             0x0F, 0x03, 0x02, 0x03, 0x03, 0x03, 0x03, 0x01,
773             0x03, 0x03, 0x03, 0x13, 0x03, 0x13, 0x13, 0x23,
774             0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
775             0x13, 0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
776             0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
777             0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
778             0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
779             0x03, 0x03, 0x03, 0x03, 0x00, 0x03, 0x03, 0x03,
780             0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
781             0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
782             0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
783             0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
784             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
785             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
786             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
787             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
788             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
789             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
790             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
791             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
792             0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
793             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
794             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
795             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
796             0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
797             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
798             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
799             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
800             };
801              
802             static const u8 char_table2[256] = {
803             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
804             0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
805             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
806             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
807             0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
808             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
809             0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
810             0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
811             0x00, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
812             0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
813             0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
814             0x1C, 0x1C, 0x1C, 0x00, 0x0C, 0x00, 0x00, 0x1C,
815             0x00, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
816             0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
817             0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
818             0x1C, 0x1C, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00,
819             0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
820             0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
821             0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
822             0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
823             0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
824             0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
825             0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
826             0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
827             0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
828             0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
829             0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
830             0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
831             0x0C, 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
832             0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
833             0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
834             0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C
835             };
836              
837             static const u8 char_table3[256] = {
838             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
839             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
840             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
841             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
842             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
843             0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x10, 0x00,
844             0x02, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
845             0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
846             0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
847             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
848             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
849             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
850             0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
851             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
852             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
853             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
854             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
855             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
856             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
857             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
858             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
859             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
860             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
861             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
862             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
863             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
864             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
865             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
866             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
867             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
868             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
869             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
870             };
871              
872             /** Match a whitespace: [ \t\n\r]. */
873             static_inline bool char_is_space(u8 c) {
874 10134           return !!(char_table1[c] & CHAR_TYPE_SPACE);
875             }
876              
877             /** Match an extended whitespace: [ \t\n\r\\v\\f], JSON5 whitespace. */
878             static_inline bool char_is_space_ext(u8 c) {
879 0           return !!(char_table1[c] & CHAR_TYPE_SPACE_EXT);
880             }
881              
882             /** Match a JSON number: [.-+0-9]. */
883             static_inline bool char_is_num(u8 c) {
884 34235           return !!(char_table1[c] & CHAR_TYPE_NUM);
885             }
886              
887             /** Match an ASCII character in string: ["\], [0x00-0x1F, 0x80-0xFF]. */
888             static_inline bool char_is_ascii_skip(u8 c) {
889 241577           return !!(char_table1[c] & CHAR_TYPE_ASCII);
890             }
891              
892             /** Match an ASCII character single-quoted: ['\], [0x00-0x1F, 0x80-0xFF]. */
893             static_inline bool char_is_ascii_skip_sq(u8 c) {
894 0           return !!(char_table1[c] & CHAR_TYPE_ASCII_SQ);
895             }
896              
897             /** Match a trivia character: extended whitespace or comment. */
898             static_inline bool char_is_trivia(u8 c) {
899 0           return !!(char_table1[c] & (CHAR_TYPE_SPACE_EXT | CHAR_TYPE_COMMENT));
900             }
901              
902             /** Match a line end character: [\r\n]. */
903             static_inline bool char_is_eol(u8 c) {
904 0           return !!(char_table2[c] & CHAR_TYPE_EOL);
905             }
906              
907             /** Match an extended line end character: [\r\n], JSON5 line terminator. */
908             static_inline bool char_is_eol_ext(u8 c) {
909 0           return !!(char_table2[c] & CHAR_TYPE_EOL_EXT);
910             }
911              
912             /** Match an identifier name start: [_$A-Za-z\], U+0080+. */
913             static_inline bool char_is_id_start(u8 c) {
914 0           return !!(char_table2[c] & CHAR_TYPE_ID_START);
915             }
916              
917             /** Match an identifier name next: [_$A-Za-z0-9\], U+0080+. */
918             static_inline bool char_is_id_next(u8 c) {
919 0           return !!(char_table2[c] & CHAR_TYPE_ID_NEXT);
920             }
921              
922             /** Match an identifier name ASCII: [_$A-Za-z0-9]. */
923             static_inline bool char_is_id_ascii(u8 c) {
924 0           return !!(char_table2[c] & CHAR_TYPE_ID_ASCII);
925             }
926              
927             /** Match a sign: [+-] */
928             static_inline bool char_is_sign(u8 d) {
929 0           return !!(char_table3[d] & CHAR_TYPE_SIGN);
930             }
931              
932             /** Match a none-zero digit: [1-9] */
933             static_inline bool char_is_nonzero(u8 d) {
934 34148           return !!(char_table3[d] & CHAR_TYPE_NONZERO);
935             }
936              
937             /** Match a digit: [0-9] */
938             static_inline bool char_is_digit(u8 d) {
939 0           return !!(char_table3[d] & CHAR_TYPE_DIGIT);
940             }
941              
942             /** Match an exponent sign: [eE]. */
943             static_inline bool char_is_exp(u8 d) {
944 2           return !!(char_table3[d] & CHAR_TYPE_EXP);
945             }
946              
947             /** Match a floating point indicator: [.eE]. */
948             static_inline bool char_is_fp(u8 d) {
949 34148           return !!(char_table3[d] & (CHAR_TYPE_DOT | CHAR_TYPE_EXP));
950             }
951              
952             /** Match a digit or floating point indicator: [0-9.eE]. */
953             static_inline bool char_is_digit_or_fp(u8 d) {
954 0           return !!(char_table3[d] & (CHAR_TYPE_DIGIT | CHAR_TYPE_DOT |
955             CHAR_TYPE_EXP));
956             }
957              
958             /** Match a JSON container: `{` or `[`. */
959             static_inline bool char_is_ctn(u8 c) {
960 20250           return (c & 0xDF) == 0x5B; /* '[': 0x5B, '{': 0x7B */
961             }
962              
963             /** Convert ASCII letter to lowercase; valid only for [A-Za-z]. */
964             static_inline u8 char_to_lower(u8 c) {
965 0           return c | 0x20;
966             }
967              
968             /** Match UTF-8 byte order mask. */
969             static_inline bool is_utf8_bom(const u8 *cur) {
970 8           return byte_load_3(cur) == byte_load_3("\xEF\xBB\xBF");
971             }
972              
973             /** Match UTF-16 byte order mask. */
974             static_inline bool is_utf16_bom(const u8 *cur) {
975 9 0         return byte_load_2(cur) == byte_load_2("\xFE\xFF") ||
    50          
976 6 0         byte_load_2(cur) == byte_load_2("\xFF\xFE");
    50          
977             }
978              
979             /** Match UTF-32 byte order mask, need length check to avoid zero padding. */
980             static_inline bool is_utf32_bom(const u8 *cur) {
981 9 0         return byte_load_4(cur) == byte_load_4("\x00\x00\xFE\xFF") ||
    50          
982 6 0         byte_load_4(cur) == byte_load_4("\xFF\xFE\x00\x00");
    50          
983             }
984              
985             /** Get the extended line end length. Used with `char_is_eol_ext`. */
986             static_inline usize ext_eol_len(const u8 *cur) {
987 0 0         if (cur[0] < 0x80) return 1;
988 0 0         if (cur[1] == 0x80 && (cur[2] == 0xA8 || cur[2] == 0xA9)) return 3;
    0          
    0          
989 0           return 0;
990             }
991              
992             /** Get the extended whitespace length. Used with `char_is_space_ext`. */
993             static_inline usize ext_space_len(const u8 *cur) {
994 0 0         if (cur[0] < 0x80) {
995 0           return 1;
996 0 0         } else if (byte_load_2(cur) == byte_load_2("\xC2\xA0")) {
    0          
    0          
997 0           return 2;
998 0 0         } else if (byte_load_2(cur) == byte_load_2("\xE2\x80")) {
    0          
    0          
999 0 0         if (cur[2] >= 0x80 && cur[2] <= 0x8A) return 3;
    0          
    0          
    0          
    0          
    0          
1000 0 0         if (cur[2] == 0xA8 || cur[2] == 0xA9 || cur[2] == 0xAF) return 3;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1001             } else {
1002 0           u32 uni = byte_load_3(cur);
1003 0 0         if (uni == byte_load_3("\xE1\x9A\x80") ||
    0          
    0          
1004 0 0         uni == byte_load_3("\xE2\x81\x9F") ||
    0          
    0          
1005 0 0         uni == byte_load_3("\xE3\x80\x80") ||
    0          
    0          
1006 0 0         uni == byte_load_3("\xEF\xBB\xBF")) return 3;
    0          
    0          
1007             }
1008 0           return 0;
1009             }
1010              
1011              
1012              
1013             /*==============================================================================
1014             * MARK: - Hex Character Reader (Private)
1015             * This function is used by JSON reader to read escaped characters.
1016             *============================================================================*/
1017              
1018             /**
1019             This table is used to convert 4 hex character sequence to a number.
1020             A valid hex character [0-9A-Fa-f] will mapped to it's raw number [0x00, 0x0F],
1021             an invalid hex character will mapped to [0xF0].
1022             (generate with misc/make_tables.c)
1023             */
1024             static const u8 hex_conv_table[256] = {
1025             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1026             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1027             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1028             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1029             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1030             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1031             0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1032             0x08, 0x09, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1033             0xF0, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF0,
1034             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1035             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1036             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1037             0xF0, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF0,
1038             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1039             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1040             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1041             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1042             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1043             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1044             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1045             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1046             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1047             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1048             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1049             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1050             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1051             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1052             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1053             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1054             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1055             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1056             0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0
1057             };
1058              
1059             /** Load 4 hex characters to `u16`, return true on valid input. */
1060             static_inline bool hex_load_4(const u8 *src, u16 *dst) {
1061 10           u16 c0 = hex_conv_table[src[0]];
1062 10           u16 c1 = hex_conv_table[src[1]];
1063 10           u16 c2 = hex_conv_table[src[2]];
1064 10           u16 c3 = hex_conv_table[src[3]];
1065 10           u16 t0 = (u16)((c0 << 8) | c2);
1066 10           u16 t1 = (u16)((c1 << 8) | c3);
1067 10           *dst = (u16)((t0 << 4) | t1);
1068 10           return ((t0 | t1) & (u16)0xF0F0) == 0;
1069             }
1070              
1071             /** Load 2 hex characters to `u8`, return true on valid input. */
1072             static_inline bool hex_load_2(const u8 *src, u8 *dst) {
1073 0           u8 c0 = hex_conv_table[src[0]];
1074 0           u8 c1 = hex_conv_table[src[1]];
1075 0           *dst = (u8)((c0 << 4) | c1);
1076 0           return ((c0 | c1) & 0xF0) == 0;
1077             }
1078              
1079             /** Match a hexadecimal numeric character: [0-9a-fA-F]. */
1080             static_inline bool char_is_hex(u8 c) {
1081 0           return hex_conv_table[c] != 0xF0;
1082             }
1083              
1084              
1085              
1086             /*==============================================================================
1087             * MARK: - UTF8 Validation (Private)
1088             * Each Unicode code point is encoded using 1 to 4 bytes in UTF-8.
1089             * Validation is performed using a 4-byte mask and pattern-based approach,
1090             * which requires the input data to be padded with four zero bytes at the end.
1091             *============================================================================*/
1092              
1093             /* Macro for concatenating four u8 into a u32 and keeping the byte order. */
1094             #if YYJSON_ENDIAN == YYJSON_LITTLE_ENDIAN
1095             # define utf8_seq_def(name, a, b, c, d) \
1096             static const u32 utf8_seq_##name = 0x##d##c##b##a##UL;
1097             # define utf8_seq(name) utf8_seq_##name
1098             #elif YYJSON_ENDIAN == YYJSON_BIG_ENDIAN
1099             # define utf8_seq_def(name, a, b, c, d) \
1100             static const u32 utf8_seq_##name = 0x##a##b##c##d##UL;
1101             # define utf8_seq(name) utf8_seq_##name
1102             #else
1103             # define utf8_seq_def(name, a, b, c, d) \
1104             static const v32_uni utf8_uni_##name = {{ 0x##a, 0x##b, 0x##c, 0x##d }};
1105             # define utf8_seq(name) utf8_uni_##name.u
1106             #endif
1107              
1108             /*
1109             1-byte sequence (U+0000 to U+007F)
1110             bit min [.......0] (U+0000)
1111             bit max [.1111111] (U+007F)
1112             bit mask [x.......] (80)
1113             bit pattern [0.......] (00)
1114             */
1115             utf8_seq_def(b1_mask, 80, 00, 00, 00)
1116             utf8_seq_def(b1_patt, 00, 00, 00, 00)
1117             #define is_utf8_seq1(uni) ( \
1118             ((uni & utf8_seq(b1_mask)) == utf8_seq(b1_patt)) )
1119              
1120             /*
1121             2-byte sequence (U+0080 to U+07FF)
1122             bit min [......10 ..000000] (U+0080)
1123             bit max [...11111 ..111111] (U+07FF)
1124             bit mask [xxx..... xx......] (E0 C0)
1125             bit pattern [110..... 10......] (C0 80)
1126             bit require [...xxxx. ........] (1E 00)
1127             */
1128             utf8_seq_def(b2_mask, E0, C0, 00, 00)
1129             utf8_seq_def(b2_patt, C0, 80, 00, 00)
1130             utf8_seq_def(b2_requ, 1E, 00, 00, 00)
1131             #define is_utf8_seq2(uni) ( \
1132             ((uni & utf8_seq(b2_mask)) == utf8_seq(b2_patt)) && \
1133             ((uni & utf8_seq(b2_requ))) )
1134              
1135             /*
1136             3-byte sequence (U+0800 to U+FFFF)
1137             bit min [........ ..100000 ..000000] (U+0800)
1138             bit max [....1111 ..111111 ..111111] (U+FFFF)
1139             bit mask [xxxx.... xx...... xx......] (F0 C0 C0)
1140             bit pattern [1110.... 10...... 10......] (E0 80 80)
1141             bit require [....xxxx ..x..... ........] (0F 20 00)
1142              
1143             3-byte invalid sequence, reserved for surrogate halves (U+D800 to U+DFFF)
1144             bit min [....1101 ..100000 ..000000] (U+D800)
1145             bit max [....1101 ..111111 ..111111] (U+DFFF)
1146             bit mask [....xxxx ..x..... ........] (0F 20 00)
1147             bit pattern [....1101 ..1..... ........] (0D 20 00)
1148             */
1149             utf8_seq_def(b3_mask, F0, C0, C0, 00)
1150             utf8_seq_def(b3_patt, E0, 80, 80, 00)
1151             utf8_seq_def(b3_requ, 0F, 20, 00, 00)
1152             utf8_seq_def(b3_erro, 0D, 20, 00, 00)
1153             #define is_utf8_seq3(uni) ( \
1154             ((uni & utf8_seq(b3_mask)) == utf8_seq(b3_patt)) && \
1155             ((tmp = (uni & utf8_seq(b3_requ)))) && \
1156             ((tmp != utf8_seq(b3_erro))) )
1157              
1158             /*
1159             4-byte sequence (U+10000 to U+10FFFF)
1160             bit min [........ ...10000 ..000000 ..000000] (U+10000)
1161             bit max [.....100 ..001111 ..111111 ..111111] (U+10FFFF)
1162             bit mask [xxxxx... xx...... xx...... xx......] (F8 C0 C0 C0)
1163             bit pattern [11110... 10...... 10...... 10......] (F0 80 80 80)
1164             bit require [.....xxx ..xx.... ........ ........] (07 30 00 00)
1165             bit require 1 [.....x.. ........ ........ ........] (04 00 00 00)
1166             bit require 2 [......xx ..xx.... ........ ........] (03 30 00 00)
1167             */
1168             utf8_seq_def(b4_mask, F8, C0, C0, C0)
1169             utf8_seq_def(b4_patt, F0, 80, 80, 80)
1170             utf8_seq_def(b4_requ, 07, 30, 00, 00)
1171             utf8_seq_def(b4_req1, 04, 00, 00, 00)
1172             utf8_seq_def(b4_req2, 03, 30, 00, 00)
1173             #define is_utf8_seq4(uni) ( \
1174             ((uni & utf8_seq(b4_mask)) == utf8_seq(b4_patt)) && \
1175             ((tmp = (uni & utf8_seq(b4_requ)))) && \
1176             ((tmp & utf8_seq(b4_req1)) == 0 || (tmp & utf8_seq(b4_req2)) == 0) )
1177              
1178              
1179              
1180             /*==============================================================================
1181             * MARK: - Power10 Lookup Table (Private)
1182             * These data are used by the floating-point number reader and writer.
1183             *============================================================================*/
1184              
1185             #if !YYJSON_DISABLE_FAST_FP_CONV
1186              
1187             /** Maximum pow10 exponent that can be represented exactly as a float64. */
1188             #define F64_POW10_MAX_EXACT_EXP 22
1189              
1190             /** Cached pow10 table. */
1191             static const f64 f64_pow10_table[F64_POW10_MAX_EXACT_EXP + 1] = {
1192             1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12,
1193             1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22
1194             };
1195              
1196             /** Maximum pow10 exponent that can be represented exactly as a uint64. */
1197             #define U64_POW10_MAX_EXACT_EXP 19
1198              
1199             /** Table: [ 10^0, ..., 10^19 ] (generate with misc/make_tables.c) */
1200             static const u64 u64_pow10_table[U64_POW10_MAX_EXACT_EXP + 1] = {
1201             U64(0x00000000, 0x00000001), U64(0x00000000, 0x0000000A),
1202             U64(0x00000000, 0x00000064), U64(0x00000000, 0x000003E8),
1203             U64(0x00000000, 0x00002710), U64(0x00000000, 0x000186A0),
1204             U64(0x00000000, 0x000F4240), U64(0x00000000, 0x00989680),
1205             U64(0x00000000, 0x05F5E100), U64(0x00000000, 0x3B9ACA00),
1206             U64(0x00000002, 0x540BE400), U64(0x00000017, 0x4876E800),
1207             U64(0x000000E8, 0xD4A51000), U64(0x00000918, 0x4E72A000),
1208             U64(0x00005AF3, 0x107A4000), U64(0x00038D7E, 0xA4C68000),
1209             U64(0x002386F2, 0x6FC10000), U64(0x01634578, 0x5D8A0000),
1210             U64(0x0DE0B6B3, 0xA7640000), U64(0x8AC72304, 0x89E80000)
1211             };
1212              
1213             /** Minimum decimal exponent in pow10_sig_table. */
1214             #define POW10_SIG_TABLE_MIN_EXP -343
1215              
1216             /** Maximum decimal exponent in pow10_sig_table. */
1217             #define POW10_SIG_TABLE_MAX_EXP 324
1218              
1219             /** Minimum exact decimal exponent in pow10_sig_table */
1220             #define POW10_SIG_TABLE_MIN_EXACT_EXP 0
1221              
1222             /** Maximum exact decimal exponent in pow10_sig_table */
1223             #define POW10_SIG_TABLE_MAX_EXACT_EXP 55
1224              
1225             /** Normalized significant 128 bits of pow10, no rounded up (size: 10.4KB).
1226             This lookup table is used by both the double number reader and writer.
1227             (generate with misc/make_tables.c) */
1228             static const u64 pow10_sig_table[] = {
1229             U64(0xBF29DCAB, 0xA82FDEAE), U64(0x7432EE87, 0x3880FC33), /* ~= 10^-343 */
1230             U64(0xEEF453D6, 0x923BD65A), U64(0x113FAA29, 0x06A13B3F), /* ~= 10^-342 */
1231             U64(0x9558B466, 0x1B6565F8), U64(0x4AC7CA59, 0xA424C507), /* ~= 10^-341 */
1232             U64(0xBAAEE17F, 0xA23EBF76), U64(0x5D79BCF0, 0x0D2DF649), /* ~= 10^-340 */
1233             U64(0xE95A99DF, 0x8ACE6F53), U64(0xF4D82C2C, 0x107973DC), /* ~= 10^-339 */
1234             U64(0x91D8A02B, 0xB6C10594), U64(0x79071B9B, 0x8A4BE869), /* ~= 10^-338 */
1235             U64(0xB64EC836, 0xA47146F9), U64(0x9748E282, 0x6CDEE284), /* ~= 10^-337 */
1236             U64(0xE3E27A44, 0x4D8D98B7), U64(0xFD1B1B23, 0x08169B25), /* ~= 10^-336 */
1237             U64(0x8E6D8C6A, 0xB0787F72), U64(0xFE30F0F5, 0xE50E20F7), /* ~= 10^-335 */
1238             U64(0xB208EF85, 0x5C969F4F), U64(0xBDBD2D33, 0x5E51A935), /* ~= 10^-334 */
1239             U64(0xDE8B2B66, 0xB3BC4723), U64(0xAD2C7880, 0x35E61382), /* ~= 10^-333 */
1240             U64(0x8B16FB20, 0x3055AC76), U64(0x4C3BCB50, 0x21AFCC31), /* ~= 10^-332 */
1241             U64(0xADDCB9E8, 0x3C6B1793), U64(0xDF4ABE24, 0x2A1BBF3D), /* ~= 10^-331 */
1242             U64(0xD953E862, 0x4B85DD78), U64(0xD71D6DAD, 0x34A2AF0D), /* ~= 10^-330 */
1243             U64(0x87D4713D, 0x6F33AA6B), U64(0x8672648C, 0x40E5AD68), /* ~= 10^-329 */
1244             U64(0xA9C98D8C, 0xCB009506), U64(0x680EFDAF, 0x511F18C2), /* ~= 10^-328 */
1245             U64(0xD43BF0EF, 0xFDC0BA48), U64(0x0212BD1B, 0x2566DEF2), /* ~= 10^-327 */
1246             U64(0x84A57695, 0xFE98746D), U64(0x014BB630, 0xF7604B57), /* ~= 10^-326 */
1247             U64(0xA5CED43B, 0x7E3E9188), U64(0x419EA3BD, 0x35385E2D), /* ~= 10^-325 */
1248             U64(0xCF42894A, 0x5DCE35EA), U64(0x52064CAC, 0x828675B9), /* ~= 10^-324 */
1249             U64(0x818995CE, 0x7AA0E1B2), U64(0x7343EFEB, 0xD1940993), /* ~= 10^-323 */
1250             U64(0xA1EBFB42, 0x19491A1F), U64(0x1014EBE6, 0xC5F90BF8), /* ~= 10^-322 */
1251             U64(0xCA66FA12, 0x9F9B60A6), U64(0xD41A26E0, 0x77774EF6), /* ~= 10^-321 */
1252             U64(0xFD00B897, 0x478238D0), U64(0x8920B098, 0x955522B4), /* ~= 10^-320 */
1253             U64(0x9E20735E, 0x8CB16382), U64(0x55B46E5F, 0x5D5535B0), /* ~= 10^-319 */
1254             U64(0xC5A89036, 0x2FDDBC62), U64(0xEB2189F7, 0x34AA831D), /* ~= 10^-318 */
1255             U64(0xF712B443, 0xBBD52B7B), U64(0xA5E9EC75, 0x01D523E4), /* ~= 10^-317 */
1256             U64(0x9A6BB0AA, 0x55653B2D), U64(0x47B233C9, 0x2125366E), /* ~= 10^-316 */
1257             U64(0xC1069CD4, 0xEABE89F8), U64(0x999EC0BB, 0x696E840A), /* ~= 10^-315 */
1258             U64(0xF148440A, 0x256E2C76), U64(0xC00670EA, 0x43CA250D), /* ~= 10^-314 */
1259             U64(0x96CD2A86, 0x5764DBCA), U64(0x38040692, 0x6A5E5728), /* ~= 10^-313 */
1260             U64(0xBC807527, 0xED3E12BC), U64(0xC6050837, 0x04F5ECF2), /* ~= 10^-312 */
1261             U64(0xEBA09271, 0xE88D976B), U64(0xF7864A44, 0xC633682E), /* ~= 10^-311 */
1262             U64(0x93445B87, 0x31587EA3), U64(0x7AB3EE6A, 0xFBE0211D), /* ~= 10^-310 */
1263             U64(0xB8157268, 0xFDAE9E4C), U64(0x5960EA05, 0xBAD82964), /* ~= 10^-309 */
1264             U64(0xE61ACF03, 0x3D1A45DF), U64(0x6FB92487, 0x298E33BD), /* ~= 10^-308 */
1265             U64(0x8FD0C162, 0x06306BAB), U64(0xA5D3B6D4, 0x79F8E056), /* ~= 10^-307 */
1266             U64(0xB3C4F1BA, 0x87BC8696), U64(0x8F48A489, 0x9877186C), /* ~= 10^-306 */
1267             U64(0xE0B62E29, 0x29ABA83C), U64(0x331ACDAB, 0xFE94DE87), /* ~= 10^-305 */
1268             U64(0x8C71DCD9, 0xBA0B4925), U64(0x9FF0C08B, 0x7F1D0B14), /* ~= 10^-304 */
1269             U64(0xAF8E5410, 0x288E1B6F), U64(0x07ECF0AE, 0x5EE44DD9), /* ~= 10^-303 */
1270             U64(0xDB71E914, 0x32B1A24A), U64(0xC9E82CD9, 0xF69D6150), /* ~= 10^-302 */
1271             U64(0x892731AC, 0x9FAF056E), U64(0xBE311C08, 0x3A225CD2), /* ~= 10^-301 */
1272             U64(0xAB70FE17, 0xC79AC6CA), U64(0x6DBD630A, 0x48AAF406), /* ~= 10^-300 */
1273             U64(0xD64D3D9D, 0xB981787D), U64(0x092CBBCC, 0xDAD5B108), /* ~= 10^-299 */
1274             U64(0x85F04682, 0x93F0EB4E), U64(0x25BBF560, 0x08C58EA5), /* ~= 10^-298 */
1275             U64(0xA76C5823, 0x38ED2621), U64(0xAF2AF2B8, 0x0AF6F24E), /* ~= 10^-297 */
1276             U64(0xD1476E2C, 0x07286FAA), U64(0x1AF5AF66, 0x0DB4AEE1), /* ~= 10^-296 */
1277             U64(0x82CCA4DB, 0x847945CA), U64(0x50D98D9F, 0xC890ED4D), /* ~= 10^-295 */
1278             U64(0xA37FCE12, 0x6597973C), U64(0xE50FF107, 0xBAB528A0), /* ~= 10^-294 */
1279             U64(0xCC5FC196, 0xFEFD7D0C), U64(0x1E53ED49, 0xA96272C8), /* ~= 10^-293 */
1280             U64(0xFF77B1FC, 0xBEBCDC4F), U64(0x25E8E89C, 0x13BB0F7A), /* ~= 10^-292 */
1281             U64(0x9FAACF3D, 0xF73609B1), U64(0x77B19161, 0x8C54E9AC), /* ~= 10^-291 */
1282             U64(0xC795830D, 0x75038C1D), U64(0xD59DF5B9, 0xEF6A2417), /* ~= 10^-290 */
1283             U64(0xF97AE3D0, 0xD2446F25), U64(0x4B057328, 0x6B44AD1D), /* ~= 10^-289 */
1284             U64(0x9BECCE62, 0x836AC577), U64(0x4EE367F9, 0x430AEC32), /* ~= 10^-288 */
1285             U64(0xC2E801FB, 0x244576D5), U64(0x229C41F7, 0x93CDA73F), /* ~= 10^-287 */
1286             U64(0xF3A20279, 0xED56D48A), U64(0x6B435275, 0x78C1110F), /* ~= 10^-286 */
1287             U64(0x9845418C, 0x345644D6), U64(0x830A1389, 0x6B78AAA9), /* ~= 10^-285 */
1288             U64(0xBE5691EF, 0x416BD60C), U64(0x23CC986B, 0xC656D553), /* ~= 10^-284 */
1289             U64(0xEDEC366B, 0x11C6CB8F), U64(0x2CBFBE86, 0xB7EC8AA8), /* ~= 10^-283 */
1290             U64(0x94B3A202, 0xEB1C3F39), U64(0x7BF7D714, 0x32F3D6A9), /* ~= 10^-282 */
1291             U64(0xB9E08A83, 0xA5E34F07), U64(0xDAF5CCD9, 0x3FB0CC53), /* ~= 10^-281 */
1292             U64(0xE858AD24, 0x8F5C22C9), U64(0xD1B3400F, 0x8F9CFF68), /* ~= 10^-280 */
1293             U64(0x91376C36, 0xD99995BE), U64(0x23100809, 0xB9C21FA1), /* ~= 10^-279 */
1294             U64(0xB5854744, 0x8FFFFB2D), U64(0xABD40A0C, 0x2832A78A), /* ~= 10^-278 */
1295             U64(0xE2E69915, 0xB3FFF9F9), U64(0x16C90C8F, 0x323F516C), /* ~= 10^-277 */
1296             U64(0x8DD01FAD, 0x907FFC3B), U64(0xAE3DA7D9, 0x7F6792E3), /* ~= 10^-276 */
1297             U64(0xB1442798, 0xF49FFB4A), U64(0x99CD11CF, 0xDF41779C), /* ~= 10^-275 */
1298             U64(0xDD95317F, 0x31C7FA1D), U64(0x40405643, 0xD711D583), /* ~= 10^-274 */
1299             U64(0x8A7D3EEF, 0x7F1CFC52), U64(0x482835EA, 0x666B2572), /* ~= 10^-273 */
1300             U64(0xAD1C8EAB, 0x5EE43B66), U64(0xDA324365, 0x0005EECF), /* ~= 10^-272 */
1301             U64(0xD863B256, 0x369D4A40), U64(0x90BED43E, 0x40076A82), /* ~= 10^-271 */
1302             U64(0x873E4F75, 0xE2224E68), U64(0x5A7744A6, 0xE804A291), /* ~= 10^-270 */
1303             U64(0xA90DE353, 0x5AAAE202), U64(0x711515D0, 0xA205CB36), /* ~= 10^-269 */
1304             U64(0xD3515C28, 0x31559A83), U64(0x0D5A5B44, 0xCA873E03), /* ~= 10^-268 */
1305             U64(0x8412D999, 0x1ED58091), U64(0xE858790A, 0xFE9486C2), /* ~= 10^-267 */
1306             U64(0xA5178FFF, 0x668AE0B6), U64(0x626E974D, 0xBE39A872), /* ~= 10^-266 */
1307             U64(0xCE5D73FF, 0x402D98E3), U64(0xFB0A3D21, 0x2DC8128F), /* ~= 10^-265 */
1308             U64(0x80FA687F, 0x881C7F8E), U64(0x7CE66634, 0xBC9D0B99), /* ~= 10^-264 */
1309             U64(0xA139029F, 0x6A239F72), U64(0x1C1FFFC1, 0xEBC44E80), /* ~= 10^-263 */
1310             U64(0xC9874347, 0x44AC874E), U64(0xA327FFB2, 0x66B56220), /* ~= 10^-262 */
1311             U64(0xFBE91419, 0x15D7A922), U64(0x4BF1FF9F, 0x0062BAA8), /* ~= 10^-261 */
1312             U64(0x9D71AC8F, 0xADA6C9B5), U64(0x6F773FC3, 0x603DB4A9), /* ~= 10^-260 */
1313             U64(0xC4CE17B3, 0x99107C22), U64(0xCB550FB4, 0x384D21D3), /* ~= 10^-259 */
1314             U64(0xF6019DA0, 0x7F549B2B), U64(0x7E2A53A1, 0x46606A48), /* ~= 10^-258 */
1315             U64(0x99C10284, 0x4F94E0FB), U64(0x2EDA7444, 0xCBFC426D), /* ~= 10^-257 */
1316             U64(0xC0314325, 0x637A1939), U64(0xFA911155, 0xFEFB5308), /* ~= 10^-256 */
1317             U64(0xF03D93EE, 0xBC589F88), U64(0x793555AB, 0x7EBA27CA), /* ~= 10^-255 */
1318             U64(0x96267C75, 0x35B763B5), U64(0x4BC1558B, 0x2F3458DE), /* ~= 10^-254 */
1319             U64(0xBBB01B92, 0x83253CA2), U64(0x9EB1AAED, 0xFB016F16), /* ~= 10^-253 */
1320             U64(0xEA9C2277, 0x23EE8BCB), U64(0x465E15A9, 0x79C1CADC), /* ~= 10^-252 */
1321             U64(0x92A1958A, 0x7675175F), U64(0x0BFACD89, 0xEC191EC9), /* ~= 10^-251 */
1322             U64(0xB749FAED, 0x14125D36), U64(0xCEF980EC, 0x671F667B), /* ~= 10^-250 */
1323             U64(0xE51C79A8, 0x5916F484), U64(0x82B7E127, 0x80E7401A), /* ~= 10^-249 */
1324             U64(0x8F31CC09, 0x37AE58D2), U64(0xD1B2ECB8, 0xB0908810), /* ~= 10^-248 */
1325             U64(0xB2FE3F0B, 0x8599EF07), U64(0x861FA7E6, 0xDCB4AA15), /* ~= 10^-247 */
1326             U64(0xDFBDCECE, 0x67006AC9), U64(0x67A791E0, 0x93E1D49A), /* ~= 10^-246 */
1327             U64(0x8BD6A141, 0x006042BD), U64(0xE0C8BB2C, 0x5C6D24E0), /* ~= 10^-245 */
1328             U64(0xAECC4991, 0x4078536D), U64(0x58FAE9F7, 0x73886E18), /* ~= 10^-244 */
1329             U64(0xDA7F5BF5, 0x90966848), U64(0xAF39A475, 0x506A899E), /* ~= 10^-243 */
1330             U64(0x888F9979, 0x7A5E012D), U64(0x6D8406C9, 0x52429603), /* ~= 10^-242 */
1331             U64(0xAAB37FD7, 0xD8F58178), U64(0xC8E5087B, 0xA6D33B83), /* ~= 10^-241 */
1332             U64(0xD5605FCD, 0xCF32E1D6), U64(0xFB1E4A9A, 0x90880A64), /* ~= 10^-240 */
1333             U64(0x855C3BE0, 0xA17FCD26), U64(0x5CF2EEA0, 0x9A55067F), /* ~= 10^-239 */
1334             U64(0xA6B34AD8, 0xC9DFC06F), U64(0xF42FAA48, 0xC0EA481E), /* ~= 10^-238 */
1335             U64(0xD0601D8E, 0xFC57B08B), U64(0xF13B94DA, 0xF124DA26), /* ~= 10^-237 */
1336             U64(0x823C1279, 0x5DB6CE57), U64(0x76C53D08, 0xD6B70858), /* ~= 10^-236 */
1337             U64(0xA2CB1717, 0xB52481ED), U64(0x54768C4B, 0x0C64CA6E), /* ~= 10^-235 */
1338             U64(0xCB7DDCDD, 0xA26DA268), U64(0xA9942F5D, 0xCF7DFD09), /* ~= 10^-234 */
1339             U64(0xFE5D5415, 0x0B090B02), U64(0xD3F93B35, 0x435D7C4C), /* ~= 10^-233 */
1340             U64(0x9EFA548D, 0x26E5A6E1), U64(0xC47BC501, 0x4A1A6DAF), /* ~= 10^-232 */
1341             U64(0xC6B8E9B0, 0x709F109A), U64(0x359AB641, 0x9CA1091B), /* ~= 10^-231 */
1342             U64(0xF867241C, 0x8CC6D4C0), U64(0xC30163D2, 0x03C94B62), /* ~= 10^-230 */
1343             U64(0x9B407691, 0xD7FC44F8), U64(0x79E0DE63, 0x425DCF1D), /* ~= 10^-229 */
1344             U64(0xC2109436, 0x4DFB5636), U64(0x985915FC, 0x12F542E4), /* ~= 10^-228 */
1345             U64(0xF294B943, 0xE17A2BC4), U64(0x3E6F5B7B, 0x17B2939D), /* ~= 10^-227 */
1346             U64(0x979CF3CA, 0x6CEC5B5A), U64(0xA705992C, 0xEECF9C42), /* ~= 10^-226 */
1347             U64(0xBD8430BD, 0x08277231), U64(0x50C6FF78, 0x2A838353), /* ~= 10^-225 */
1348             U64(0xECE53CEC, 0x4A314EBD), U64(0xA4F8BF56, 0x35246428), /* ~= 10^-224 */
1349             U64(0x940F4613, 0xAE5ED136), U64(0x871B7795, 0xE136BE99), /* ~= 10^-223 */
1350             U64(0xB9131798, 0x99F68584), U64(0x28E2557B, 0x59846E3F), /* ~= 10^-222 */
1351             U64(0xE757DD7E, 0xC07426E5), U64(0x331AEADA, 0x2FE589CF), /* ~= 10^-221 */
1352             U64(0x9096EA6F, 0x3848984F), U64(0x3FF0D2C8, 0x5DEF7621), /* ~= 10^-220 */
1353             U64(0xB4BCA50B, 0x065ABE63), U64(0x0FED077A, 0x756B53A9), /* ~= 10^-219 */
1354             U64(0xE1EBCE4D, 0xC7F16DFB), U64(0xD3E84959, 0x12C62894), /* ~= 10^-218 */
1355             U64(0x8D3360F0, 0x9CF6E4BD), U64(0x64712DD7, 0xABBBD95C), /* ~= 10^-217 */
1356             U64(0xB080392C, 0xC4349DEC), U64(0xBD8D794D, 0x96AACFB3), /* ~= 10^-216 */
1357             U64(0xDCA04777, 0xF541C567), U64(0xECF0D7A0, 0xFC5583A0), /* ~= 10^-215 */
1358             U64(0x89E42CAA, 0xF9491B60), U64(0xF41686C4, 0x9DB57244), /* ~= 10^-214 */
1359             U64(0xAC5D37D5, 0xB79B6239), U64(0x311C2875, 0xC522CED5), /* ~= 10^-213 */
1360             U64(0xD77485CB, 0x25823AC7), U64(0x7D633293, 0x366B828B), /* ~= 10^-212 */
1361             U64(0x86A8D39E, 0xF77164BC), U64(0xAE5DFF9C, 0x02033197), /* ~= 10^-211 */
1362             U64(0xA8530886, 0xB54DBDEB), U64(0xD9F57F83, 0x0283FDFC), /* ~= 10^-210 */
1363             U64(0xD267CAA8, 0x62A12D66), U64(0xD072DF63, 0xC324FD7B), /* ~= 10^-209 */
1364             U64(0x8380DEA9, 0x3DA4BC60), U64(0x4247CB9E, 0x59F71E6D), /* ~= 10^-208 */
1365             U64(0xA4611653, 0x8D0DEB78), U64(0x52D9BE85, 0xF074E608), /* ~= 10^-207 */
1366             U64(0xCD795BE8, 0x70516656), U64(0x67902E27, 0x6C921F8B), /* ~= 10^-206 */
1367             U64(0x806BD971, 0x4632DFF6), U64(0x00BA1CD8, 0xA3DB53B6), /* ~= 10^-205 */
1368             U64(0xA086CFCD, 0x97BF97F3), U64(0x80E8A40E, 0xCCD228A4), /* ~= 10^-204 */
1369             U64(0xC8A883C0, 0xFDAF7DF0), U64(0x6122CD12, 0x8006B2CD), /* ~= 10^-203 */
1370             U64(0xFAD2A4B1, 0x3D1B5D6C), U64(0x796B8057, 0x20085F81), /* ~= 10^-202 */
1371             U64(0x9CC3A6EE, 0xC6311A63), U64(0xCBE33036, 0x74053BB0), /* ~= 10^-201 */
1372             U64(0xC3F490AA, 0x77BD60FC), U64(0xBEDBFC44, 0x11068A9C), /* ~= 10^-200 */
1373             U64(0xF4F1B4D5, 0x15ACB93B), U64(0xEE92FB55, 0x15482D44), /* ~= 10^-199 */
1374             U64(0x99171105, 0x2D8BF3C5), U64(0x751BDD15, 0x2D4D1C4A), /* ~= 10^-198 */
1375             U64(0xBF5CD546, 0x78EEF0B6), U64(0xD262D45A, 0x78A0635D), /* ~= 10^-197 */
1376             U64(0xEF340A98, 0x172AACE4), U64(0x86FB8971, 0x16C87C34), /* ~= 10^-196 */
1377             U64(0x9580869F, 0x0E7AAC0E), U64(0xD45D35E6, 0xAE3D4DA0), /* ~= 10^-195 */
1378             U64(0xBAE0A846, 0xD2195712), U64(0x89748360, 0x59CCA109), /* ~= 10^-194 */
1379             U64(0xE998D258, 0x869FACD7), U64(0x2BD1A438, 0x703FC94B), /* ~= 10^-193 */
1380             U64(0x91FF8377, 0x5423CC06), U64(0x7B6306A3, 0x4627DDCF), /* ~= 10^-192 */
1381             U64(0xB67F6455, 0x292CBF08), U64(0x1A3BC84C, 0x17B1D542), /* ~= 10^-191 */
1382             U64(0xE41F3D6A, 0x7377EECA), U64(0x20CABA5F, 0x1D9E4A93), /* ~= 10^-190 */
1383             U64(0x8E938662, 0x882AF53E), U64(0x547EB47B, 0x7282EE9C), /* ~= 10^-189 */
1384             U64(0xB23867FB, 0x2A35B28D), U64(0xE99E619A, 0x4F23AA43), /* ~= 10^-188 */
1385             U64(0xDEC681F9, 0xF4C31F31), U64(0x6405FA00, 0xE2EC94D4), /* ~= 10^-187 */
1386             U64(0x8B3C113C, 0x38F9F37E), U64(0xDE83BC40, 0x8DD3DD04), /* ~= 10^-186 */
1387             U64(0xAE0B158B, 0x4738705E), U64(0x9624AB50, 0xB148D445), /* ~= 10^-185 */
1388             U64(0xD98DDAEE, 0x19068C76), U64(0x3BADD624, 0xDD9B0957), /* ~= 10^-184 */
1389             U64(0x87F8A8D4, 0xCFA417C9), U64(0xE54CA5D7, 0x0A80E5D6), /* ~= 10^-183 */
1390             U64(0xA9F6D30A, 0x038D1DBC), U64(0x5E9FCF4C, 0xCD211F4C), /* ~= 10^-182 */
1391             U64(0xD47487CC, 0x8470652B), U64(0x7647C320, 0x0069671F), /* ~= 10^-181 */
1392             U64(0x84C8D4DF, 0xD2C63F3B), U64(0x29ECD9F4, 0x0041E073), /* ~= 10^-180 */
1393             U64(0xA5FB0A17, 0xC777CF09), U64(0xF4681071, 0x00525890), /* ~= 10^-179 */
1394             U64(0xCF79CC9D, 0xB955C2CC), U64(0x7182148D, 0x4066EEB4), /* ~= 10^-178 */
1395             U64(0x81AC1FE2, 0x93D599BF), U64(0xC6F14CD8, 0x48405530), /* ~= 10^-177 */
1396             U64(0xA21727DB, 0x38CB002F), U64(0xB8ADA00E, 0x5A506A7C), /* ~= 10^-176 */
1397             U64(0xCA9CF1D2, 0x06FDC03B), U64(0xA6D90811, 0xF0E4851C), /* ~= 10^-175 */
1398             U64(0xFD442E46, 0x88BD304A), U64(0x908F4A16, 0x6D1DA663), /* ~= 10^-174 */
1399             U64(0x9E4A9CEC, 0x15763E2E), U64(0x9A598E4E, 0x043287FE), /* ~= 10^-173 */
1400             U64(0xC5DD4427, 0x1AD3CDBA), U64(0x40EFF1E1, 0x853F29FD), /* ~= 10^-172 */
1401             U64(0xF7549530, 0xE188C128), U64(0xD12BEE59, 0xE68EF47C), /* ~= 10^-171 */
1402             U64(0x9A94DD3E, 0x8CF578B9), U64(0x82BB74F8, 0x301958CE), /* ~= 10^-170 */
1403             U64(0xC13A148E, 0x3032D6E7), U64(0xE36A5236, 0x3C1FAF01), /* ~= 10^-169 */
1404             U64(0xF18899B1, 0xBC3F8CA1), U64(0xDC44E6C3, 0xCB279AC1), /* ~= 10^-168 */
1405             U64(0x96F5600F, 0x15A7B7E5), U64(0x29AB103A, 0x5EF8C0B9), /* ~= 10^-167 */
1406             U64(0xBCB2B812, 0xDB11A5DE), U64(0x7415D448, 0xF6B6F0E7), /* ~= 10^-166 */
1407             U64(0xEBDF6617, 0x91D60F56), U64(0x111B495B, 0x3464AD21), /* ~= 10^-165 */
1408             U64(0x936B9FCE, 0xBB25C995), U64(0xCAB10DD9, 0x00BEEC34), /* ~= 10^-164 */
1409             U64(0xB84687C2, 0x69EF3BFB), U64(0x3D5D514F, 0x40EEA742), /* ~= 10^-163 */
1410             U64(0xE65829B3, 0x046B0AFA), U64(0x0CB4A5A3, 0x112A5112), /* ~= 10^-162 */
1411             U64(0x8FF71A0F, 0xE2C2E6DC), U64(0x47F0E785, 0xEABA72AB), /* ~= 10^-161 */
1412             U64(0xB3F4E093, 0xDB73A093), U64(0x59ED2167, 0x65690F56), /* ~= 10^-160 */
1413             U64(0xE0F218B8, 0xD25088B8), U64(0x306869C1, 0x3EC3532C), /* ~= 10^-159 */
1414             U64(0x8C974F73, 0x83725573), U64(0x1E414218, 0xC73A13FB), /* ~= 10^-158 */
1415             U64(0xAFBD2350, 0x644EEACF), U64(0xE5D1929E, 0xF90898FA), /* ~= 10^-157 */
1416             U64(0xDBAC6C24, 0x7D62A583), U64(0xDF45F746, 0xB74ABF39), /* ~= 10^-156 */
1417             U64(0x894BC396, 0xCE5DA772), U64(0x6B8BBA8C, 0x328EB783), /* ~= 10^-155 */
1418             U64(0xAB9EB47C, 0x81F5114F), U64(0x066EA92F, 0x3F326564), /* ~= 10^-154 */
1419             U64(0xD686619B, 0xA27255A2), U64(0xC80A537B, 0x0EFEFEBD), /* ~= 10^-153 */
1420             U64(0x8613FD01, 0x45877585), U64(0xBD06742C, 0xE95F5F36), /* ~= 10^-152 */
1421             U64(0xA798FC41, 0x96E952E7), U64(0x2C481138, 0x23B73704), /* ~= 10^-151 */
1422             U64(0xD17F3B51, 0xFCA3A7A0), U64(0xF75A1586, 0x2CA504C5), /* ~= 10^-150 */
1423             U64(0x82EF8513, 0x3DE648C4), U64(0x9A984D73, 0xDBE722FB), /* ~= 10^-149 */
1424             U64(0xA3AB6658, 0x0D5FDAF5), U64(0xC13E60D0, 0xD2E0EBBA), /* ~= 10^-148 */
1425             U64(0xCC963FEE, 0x10B7D1B3), U64(0x318DF905, 0x079926A8), /* ~= 10^-147 */
1426             U64(0xFFBBCFE9, 0x94E5C61F), U64(0xFDF17746, 0x497F7052), /* ~= 10^-146 */
1427             U64(0x9FD561F1, 0xFD0F9BD3), U64(0xFEB6EA8B, 0xEDEFA633), /* ~= 10^-145 */
1428             U64(0xC7CABA6E, 0x7C5382C8), U64(0xFE64A52E, 0xE96B8FC0), /* ~= 10^-144 */
1429             U64(0xF9BD690A, 0x1B68637B), U64(0x3DFDCE7A, 0xA3C673B0), /* ~= 10^-143 */
1430             U64(0x9C1661A6, 0x51213E2D), U64(0x06BEA10C, 0xA65C084E), /* ~= 10^-142 */
1431             U64(0xC31BFA0F, 0xE5698DB8), U64(0x486E494F, 0xCFF30A62), /* ~= 10^-141 */
1432             U64(0xF3E2F893, 0xDEC3F126), U64(0x5A89DBA3, 0xC3EFCCFA), /* ~= 10^-140 */
1433             U64(0x986DDB5C, 0x6B3A76B7), U64(0xF8962946, 0x5A75E01C), /* ~= 10^-139 */
1434             U64(0xBE895233, 0x86091465), U64(0xF6BBB397, 0xF1135823), /* ~= 10^-138 */
1435             U64(0xEE2BA6C0, 0x678B597F), U64(0x746AA07D, 0xED582E2C), /* ~= 10^-137 */
1436             U64(0x94DB4838, 0x40B717EF), U64(0xA8C2A44E, 0xB4571CDC), /* ~= 10^-136 */
1437             U64(0xBA121A46, 0x50E4DDEB), U64(0x92F34D62, 0x616CE413), /* ~= 10^-135 */
1438             U64(0xE896A0D7, 0xE51E1566), U64(0x77B020BA, 0xF9C81D17), /* ~= 10^-134 */
1439             U64(0x915E2486, 0xEF32CD60), U64(0x0ACE1474, 0xDC1D122E), /* ~= 10^-133 */
1440             U64(0xB5B5ADA8, 0xAAFF80B8), U64(0x0D819992, 0x132456BA), /* ~= 10^-132 */
1441             U64(0xE3231912, 0xD5BF60E6), U64(0x10E1FFF6, 0x97ED6C69), /* ~= 10^-131 */
1442             U64(0x8DF5EFAB, 0xC5979C8F), U64(0xCA8D3FFA, 0x1EF463C1), /* ~= 10^-130 */
1443             U64(0xB1736B96, 0xB6FD83B3), U64(0xBD308FF8, 0xA6B17CB2), /* ~= 10^-129 */
1444             U64(0xDDD0467C, 0x64BCE4A0), U64(0xAC7CB3F6, 0xD05DDBDE), /* ~= 10^-128 */
1445             U64(0x8AA22C0D, 0xBEF60EE4), U64(0x6BCDF07A, 0x423AA96B), /* ~= 10^-127 */
1446             U64(0xAD4AB711, 0x2EB3929D), U64(0x86C16C98, 0xD2C953C6), /* ~= 10^-126 */
1447             U64(0xD89D64D5, 0x7A607744), U64(0xE871C7BF, 0x077BA8B7), /* ~= 10^-125 */
1448             U64(0x87625F05, 0x6C7C4A8B), U64(0x11471CD7, 0x64AD4972), /* ~= 10^-124 */
1449             U64(0xA93AF6C6, 0xC79B5D2D), U64(0xD598E40D, 0x3DD89BCF), /* ~= 10^-123 */
1450             U64(0xD389B478, 0x79823479), U64(0x4AFF1D10, 0x8D4EC2C3), /* ~= 10^-122 */
1451             U64(0x843610CB, 0x4BF160CB), U64(0xCEDF722A, 0x585139BA), /* ~= 10^-121 */
1452             U64(0xA54394FE, 0x1EEDB8FE), U64(0xC2974EB4, 0xEE658828), /* ~= 10^-120 */
1453             U64(0xCE947A3D, 0xA6A9273E), U64(0x733D2262, 0x29FEEA32), /* ~= 10^-119 */
1454             U64(0x811CCC66, 0x8829B887), U64(0x0806357D, 0x5A3F525F), /* ~= 10^-118 */
1455             U64(0xA163FF80, 0x2A3426A8), U64(0xCA07C2DC, 0xB0CF26F7), /* ~= 10^-117 */
1456             U64(0xC9BCFF60, 0x34C13052), U64(0xFC89B393, 0xDD02F0B5), /* ~= 10^-116 */
1457             U64(0xFC2C3F38, 0x41F17C67), U64(0xBBAC2078, 0xD443ACE2), /* ~= 10^-115 */
1458             U64(0x9D9BA783, 0x2936EDC0), U64(0xD54B944B, 0x84AA4C0D), /* ~= 10^-114 */
1459             U64(0xC5029163, 0xF384A931), U64(0x0A9E795E, 0x65D4DF11), /* ~= 10^-113 */
1460             U64(0xF64335BC, 0xF065D37D), U64(0x4D4617B5, 0xFF4A16D5), /* ~= 10^-112 */
1461             U64(0x99EA0196, 0x163FA42E), U64(0x504BCED1, 0xBF8E4E45), /* ~= 10^-111 */
1462             U64(0xC06481FB, 0x9BCF8D39), U64(0xE45EC286, 0x2F71E1D6), /* ~= 10^-110 */
1463             U64(0xF07DA27A, 0x82C37088), U64(0x5D767327, 0xBB4E5A4C), /* ~= 10^-109 */
1464             U64(0x964E858C, 0x91BA2655), U64(0x3A6A07F8, 0xD510F86F), /* ~= 10^-108 */
1465             U64(0xBBE226EF, 0xB628AFEA), U64(0x890489F7, 0x0A55368B), /* ~= 10^-107 */
1466             U64(0xEADAB0AB, 0xA3B2DBE5), U64(0x2B45AC74, 0xCCEA842E), /* ~= 10^-106 */
1467             U64(0x92C8AE6B, 0x464FC96F), U64(0x3B0B8BC9, 0x0012929D), /* ~= 10^-105 */
1468             U64(0xB77ADA06, 0x17E3BBCB), U64(0x09CE6EBB, 0x40173744), /* ~= 10^-104 */
1469             U64(0xE5599087, 0x9DDCAABD), U64(0xCC420A6A, 0x101D0515), /* ~= 10^-103 */
1470             U64(0x8F57FA54, 0xC2A9EAB6), U64(0x9FA94682, 0x4A12232D), /* ~= 10^-102 */
1471             U64(0xB32DF8E9, 0xF3546564), U64(0x47939822, 0xDC96ABF9), /* ~= 10^-101 */
1472             U64(0xDFF97724, 0x70297EBD), U64(0x59787E2B, 0x93BC56F7), /* ~= 10^-100 */
1473             U64(0x8BFBEA76, 0xC619EF36), U64(0x57EB4EDB, 0x3C55B65A), /* ~= 10^-99 */
1474             U64(0xAEFAE514, 0x77A06B03), U64(0xEDE62292, 0x0B6B23F1), /* ~= 10^-98 */
1475             U64(0xDAB99E59, 0x958885C4), U64(0xE95FAB36, 0x8E45ECED), /* ~= 10^-97 */
1476             U64(0x88B402F7, 0xFD75539B), U64(0x11DBCB02, 0x18EBB414), /* ~= 10^-96 */
1477             U64(0xAAE103B5, 0xFCD2A881), U64(0xD652BDC2, 0x9F26A119), /* ~= 10^-95 */
1478             U64(0xD59944A3, 0x7C0752A2), U64(0x4BE76D33, 0x46F0495F), /* ~= 10^-94 */
1479             U64(0x857FCAE6, 0x2D8493A5), U64(0x6F70A440, 0x0C562DDB), /* ~= 10^-93 */
1480             U64(0xA6DFBD9F, 0xB8E5B88E), U64(0xCB4CCD50, 0x0F6BB952), /* ~= 10^-92 */
1481             U64(0xD097AD07, 0xA71F26B2), U64(0x7E2000A4, 0x1346A7A7), /* ~= 10^-91 */
1482             U64(0x825ECC24, 0xC873782F), U64(0x8ED40066, 0x8C0C28C8), /* ~= 10^-90 */
1483             U64(0xA2F67F2D, 0xFA90563B), U64(0x72890080, 0x2F0F32FA), /* ~= 10^-89 */
1484             U64(0xCBB41EF9, 0x79346BCA), U64(0x4F2B40A0, 0x3AD2FFB9), /* ~= 10^-88 */
1485             U64(0xFEA126B7, 0xD78186BC), U64(0xE2F610C8, 0x4987BFA8), /* ~= 10^-87 */
1486             U64(0x9F24B832, 0xE6B0F436), U64(0x0DD9CA7D, 0x2DF4D7C9), /* ~= 10^-86 */
1487             U64(0xC6EDE63F, 0xA05D3143), U64(0x91503D1C, 0x79720DBB), /* ~= 10^-85 */
1488             U64(0xF8A95FCF, 0x88747D94), U64(0x75A44C63, 0x97CE912A), /* ~= 10^-84 */
1489             U64(0x9B69DBE1, 0xB548CE7C), U64(0xC986AFBE, 0x3EE11ABA), /* ~= 10^-83 */
1490             U64(0xC24452DA, 0x229B021B), U64(0xFBE85BAD, 0xCE996168), /* ~= 10^-82 */
1491             U64(0xF2D56790, 0xAB41C2A2), U64(0xFAE27299, 0x423FB9C3), /* ~= 10^-81 */
1492             U64(0x97C560BA, 0x6B0919A5), U64(0xDCCD879F, 0xC967D41A), /* ~= 10^-80 */
1493             U64(0xBDB6B8E9, 0x05CB600F), U64(0x5400E987, 0xBBC1C920), /* ~= 10^-79 */
1494             U64(0xED246723, 0x473E3813), U64(0x290123E9, 0xAAB23B68), /* ~= 10^-78 */
1495             U64(0x9436C076, 0x0C86E30B), U64(0xF9A0B672, 0x0AAF6521), /* ~= 10^-77 */
1496             U64(0xB9447093, 0x8FA89BCE), U64(0xF808E40E, 0x8D5B3E69), /* ~= 10^-76 */
1497             U64(0xE7958CB8, 0x7392C2C2), U64(0xB60B1D12, 0x30B20E04), /* ~= 10^-75 */
1498             U64(0x90BD77F3, 0x483BB9B9), U64(0xB1C6F22B, 0x5E6F48C2), /* ~= 10^-74 */
1499             U64(0xB4ECD5F0, 0x1A4AA828), U64(0x1E38AEB6, 0x360B1AF3), /* ~= 10^-73 */
1500             U64(0xE2280B6C, 0x20DD5232), U64(0x25C6DA63, 0xC38DE1B0), /* ~= 10^-72 */
1501             U64(0x8D590723, 0x948A535F), U64(0x579C487E, 0x5A38AD0E), /* ~= 10^-71 */
1502             U64(0xB0AF48EC, 0x79ACE837), U64(0x2D835A9D, 0xF0C6D851), /* ~= 10^-70 */
1503             U64(0xDCDB1B27, 0x98182244), U64(0xF8E43145, 0x6CF88E65), /* ~= 10^-69 */
1504             U64(0x8A08F0F8, 0xBF0F156B), U64(0x1B8E9ECB, 0x641B58FF), /* ~= 10^-68 */
1505             U64(0xAC8B2D36, 0xEED2DAC5), U64(0xE272467E, 0x3D222F3F), /* ~= 10^-67 */
1506             U64(0xD7ADF884, 0xAA879177), U64(0x5B0ED81D, 0xCC6ABB0F), /* ~= 10^-66 */
1507             U64(0x86CCBB52, 0xEA94BAEA), U64(0x98E94712, 0x9FC2B4E9), /* ~= 10^-65 */
1508             U64(0xA87FEA27, 0xA539E9A5), U64(0x3F2398D7, 0x47B36224), /* ~= 10^-64 */
1509             U64(0xD29FE4B1, 0x8E88640E), U64(0x8EEC7F0D, 0x19A03AAD), /* ~= 10^-63 */
1510             U64(0x83A3EEEE, 0xF9153E89), U64(0x1953CF68, 0x300424AC), /* ~= 10^-62 */
1511             U64(0xA48CEAAA, 0xB75A8E2B), U64(0x5FA8C342, 0x3C052DD7), /* ~= 10^-61 */
1512             U64(0xCDB02555, 0x653131B6), U64(0x3792F412, 0xCB06794D), /* ~= 10^-60 */
1513             U64(0x808E1755, 0x5F3EBF11), U64(0xE2BBD88B, 0xBEE40BD0), /* ~= 10^-59 */
1514             U64(0xA0B19D2A, 0xB70E6ED6), U64(0x5B6ACEAE, 0xAE9D0EC4), /* ~= 10^-58 */
1515             U64(0xC8DE0475, 0x64D20A8B), U64(0xF245825A, 0x5A445275), /* ~= 10^-57 */
1516             U64(0xFB158592, 0xBE068D2E), U64(0xEED6E2F0, 0xF0D56712), /* ~= 10^-56 */
1517             U64(0x9CED737B, 0xB6C4183D), U64(0x55464DD6, 0x9685606B), /* ~= 10^-55 */
1518             U64(0xC428D05A, 0xA4751E4C), U64(0xAA97E14C, 0x3C26B886), /* ~= 10^-54 */
1519             U64(0xF5330471, 0x4D9265DF), U64(0xD53DD99F, 0x4B3066A8), /* ~= 10^-53 */
1520             U64(0x993FE2C6, 0xD07B7FAB), U64(0xE546A803, 0x8EFE4029), /* ~= 10^-52 */
1521             U64(0xBF8FDB78, 0x849A5F96), U64(0xDE985204, 0x72BDD033), /* ~= 10^-51 */
1522             U64(0xEF73D256, 0xA5C0F77C), U64(0x963E6685, 0x8F6D4440), /* ~= 10^-50 */
1523             U64(0x95A86376, 0x27989AAD), U64(0xDDE70013, 0x79A44AA8), /* ~= 10^-49 */
1524             U64(0xBB127C53, 0xB17EC159), U64(0x5560C018, 0x580D5D52), /* ~= 10^-48 */
1525             U64(0xE9D71B68, 0x9DDE71AF), U64(0xAAB8F01E, 0x6E10B4A6), /* ~= 10^-47 */
1526             U64(0x92267121, 0x62AB070D), U64(0xCAB39613, 0x04CA70E8), /* ~= 10^-46 */
1527             U64(0xB6B00D69, 0xBB55C8D1), U64(0x3D607B97, 0xC5FD0D22), /* ~= 10^-45 */
1528             U64(0xE45C10C4, 0x2A2B3B05), U64(0x8CB89A7D, 0xB77C506A), /* ~= 10^-44 */
1529             U64(0x8EB98A7A, 0x9A5B04E3), U64(0x77F3608E, 0x92ADB242), /* ~= 10^-43 */
1530             U64(0xB267ED19, 0x40F1C61C), U64(0x55F038B2, 0x37591ED3), /* ~= 10^-42 */
1531             U64(0xDF01E85F, 0x912E37A3), U64(0x6B6C46DE, 0xC52F6688), /* ~= 10^-41 */
1532             U64(0x8B61313B, 0xBABCE2C6), U64(0x2323AC4B, 0x3B3DA015), /* ~= 10^-40 */
1533             U64(0xAE397D8A, 0xA96C1B77), U64(0xABEC975E, 0x0A0D081A), /* ~= 10^-39 */
1534             U64(0xD9C7DCED, 0x53C72255), U64(0x96E7BD35, 0x8C904A21), /* ~= 10^-38 */
1535             U64(0x881CEA14, 0x545C7575), U64(0x7E50D641, 0x77DA2E54), /* ~= 10^-37 */
1536             U64(0xAA242499, 0x697392D2), U64(0xDDE50BD1, 0xD5D0B9E9), /* ~= 10^-36 */
1537             U64(0xD4AD2DBF, 0xC3D07787), U64(0x955E4EC6, 0x4B44E864), /* ~= 10^-35 */
1538             U64(0x84EC3C97, 0xDA624AB4), U64(0xBD5AF13B, 0xEF0B113E), /* ~= 10^-34 */
1539             U64(0xA6274BBD, 0xD0FADD61), U64(0xECB1AD8A, 0xEACDD58E), /* ~= 10^-33 */
1540             U64(0xCFB11EAD, 0x453994BA), U64(0x67DE18ED, 0xA5814AF2), /* ~= 10^-32 */
1541             U64(0x81CEB32C, 0x4B43FCF4), U64(0x80EACF94, 0x8770CED7), /* ~= 10^-31 */
1542             U64(0xA2425FF7, 0x5E14FC31), U64(0xA1258379, 0xA94D028D), /* ~= 10^-30 */
1543             U64(0xCAD2F7F5, 0x359A3B3E), U64(0x096EE458, 0x13A04330), /* ~= 10^-29 */
1544             U64(0xFD87B5F2, 0x8300CA0D), U64(0x8BCA9D6E, 0x188853FC), /* ~= 10^-28 */
1545             U64(0x9E74D1B7, 0x91E07E48), U64(0x775EA264, 0xCF55347D), /* ~= 10^-27 */
1546             U64(0xC6120625, 0x76589DDA), U64(0x95364AFE, 0x032A819D), /* ~= 10^-26 */
1547             U64(0xF79687AE, 0xD3EEC551), U64(0x3A83DDBD, 0x83F52204), /* ~= 10^-25 */
1548             U64(0x9ABE14CD, 0x44753B52), U64(0xC4926A96, 0x72793542), /* ~= 10^-24 */
1549             U64(0xC16D9A00, 0x95928A27), U64(0x75B7053C, 0x0F178293), /* ~= 10^-23 */
1550             U64(0xF1C90080, 0xBAF72CB1), U64(0x5324C68B, 0x12DD6338), /* ~= 10^-22 */
1551             U64(0x971DA050, 0x74DA7BEE), U64(0xD3F6FC16, 0xEBCA5E03), /* ~= 10^-21 */
1552             U64(0xBCE50864, 0x92111AEA), U64(0x88F4BB1C, 0xA6BCF584), /* ~= 10^-20 */
1553             U64(0xEC1E4A7D, 0xB69561A5), U64(0x2B31E9E3, 0xD06C32E5), /* ~= 10^-19 */
1554             U64(0x9392EE8E, 0x921D5D07), U64(0x3AFF322E, 0x62439FCF), /* ~= 10^-18 */
1555             U64(0xB877AA32, 0x36A4B449), U64(0x09BEFEB9, 0xFAD487C2), /* ~= 10^-17 */
1556             U64(0xE69594BE, 0xC44DE15B), U64(0x4C2EBE68, 0x7989A9B3), /* ~= 10^-16 */
1557             U64(0x901D7CF7, 0x3AB0ACD9), U64(0x0F9D3701, 0x4BF60A10), /* ~= 10^-15 */
1558             U64(0xB424DC35, 0x095CD80F), U64(0x538484C1, 0x9EF38C94), /* ~= 10^-14 */
1559             U64(0xE12E1342, 0x4BB40E13), U64(0x2865A5F2, 0x06B06FB9), /* ~= 10^-13 */
1560             U64(0x8CBCCC09, 0x6F5088CB), U64(0xF93F87B7, 0x442E45D3), /* ~= 10^-12 */
1561             U64(0xAFEBFF0B, 0xCB24AAFE), U64(0xF78F69A5, 0x1539D748), /* ~= 10^-11 */
1562             U64(0xDBE6FECE, 0xBDEDD5BE), U64(0xB573440E, 0x5A884D1B), /* ~= 10^-10 */
1563             U64(0x89705F41, 0x36B4A597), U64(0x31680A88, 0xF8953030), /* ~= 10^-9 */
1564             U64(0xABCC7711, 0x8461CEFC), U64(0xFDC20D2B, 0x36BA7C3D), /* ~= 10^-8 */
1565             U64(0xD6BF94D5, 0xE57A42BC), U64(0x3D329076, 0x04691B4C), /* ~= 10^-7 */
1566             U64(0x8637BD05, 0xAF6C69B5), U64(0xA63F9A49, 0xC2C1B10F), /* ~= 10^-6 */
1567             U64(0xA7C5AC47, 0x1B478423), U64(0x0FCF80DC, 0x33721D53), /* ~= 10^-5 */
1568             U64(0xD1B71758, 0xE219652B), U64(0xD3C36113, 0x404EA4A8), /* ~= 10^-4 */
1569             U64(0x83126E97, 0x8D4FDF3B), U64(0x645A1CAC, 0x083126E9), /* ~= 10^-3 */
1570             U64(0xA3D70A3D, 0x70A3D70A), U64(0x3D70A3D7, 0x0A3D70A3), /* ~= 10^-2 */
1571             U64(0xCCCCCCCC, 0xCCCCCCCC), U64(0xCCCCCCCC, 0xCCCCCCCC), /* ~= 10^-1 */
1572             U64(0x80000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^0 */
1573             U64(0xA0000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^1 */
1574             U64(0xC8000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^2 */
1575             U64(0xFA000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^3 */
1576             U64(0x9C400000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^4 */
1577             U64(0xC3500000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^5 */
1578             U64(0xF4240000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^6 */
1579             U64(0x98968000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^7 */
1580             U64(0xBEBC2000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^8 */
1581             U64(0xEE6B2800, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^9 */
1582             U64(0x9502F900, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^10 */
1583             U64(0xBA43B740, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^11 */
1584             U64(0xE8D4A510, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^12 */
1585             U64(0x9184E72A, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^13 */
1586             U64(0xB5E620F4, 0x80000000), U64(0x00000000, 0x00000000), /* == 10^14 */
1587             U64(0xE35FA931, 0xA0000000), U64(0x00000000, 0x00000000), /* == 10^15 */
1588             U64(0x8E1BC9BF, 0x04000000), U64(0x00000000, 0x00000000), /* == 10^16 */
1589             U64(0xB1A2BC2E, 0xC5000000), U64(0x00000000, 0x00000000), /* == 10^17 */
1590             U64(0xDE0B6B3A, 0x76400000), U64(0x00000000, 0x00000000), /* == 10^18 */
1591             U64(0x8AC72304, 0x89E80000), U64(0x00000000, 0x00000000), /* == 10^19 */
1592             U64(0xAD78EBC5, 0xAC620000), U64(0x00000000, 0x00000000), /* == 10^20 */
1593             U64(0xD8D726B7, 0x177A8000), U64(0x00000000, 0x00000000), /* == 10^21 */
1594             U64(0x87867832, 0x6EAC9000), U64(0x00000000, 0x00000000), /* == 10^22 */
1595             U64(0xA968163F, 0x0A57B400), U64(0x00000000, 0x00000000), /* == 10^23 */
1596             U64(0xD3C21BCE, 0xCCEDA100), U64(0x00000000, 0x00000000), /* == 10^24 */
1597             U64(0x84595161, 0x401484A0), U64(0x00000000, 0x00000000), /* == 10^25 */
1598             U64(0xA56FA5B9, 0x9019A5C8), U64(0x00000000, 0x00000000), /* == 10^26 */
1599             U64(0xCECB8F27, 0xF4200F3A), U64(0x00000000, 0x00000000), /* == 10^27 */
1600             U64(0x813F3978, 0xF8940984), U64(0x40000000, 0x00000000), /* == 10^28 */
1601             U64(0xA18F07D7, 0x36B90BE5), U64(0x50000000, 0x00000000), /* == 10^29 */
1602             U64(0xC9F2C9CD, 0x04674EDE), U64(0xA4000000, 0x00000000), /* == 10^30 */
1603             U64(0xFC6F7C40, 0x45812296), U64(0x4D000000, 0x00000000), /* == 10^31 */
1604             U64(0x9DC5ADA8, 0x2B70B59D), U64(0xF0200000, 0x00000000), /* == 10^32 */
1605             U64(0xC5371912, 0x364CE305), U64(0x6C280000, 0x00000000), /* == 10^33 */
1606             U64(0xF684DF56, 0xC3E01BC6), U64(0xC7320000, 0x00000000), /* == 10^34 */
1607             U64(0x9A130B96, 0x3A6C115C), U64(0x3C7F4000, 0x00000000), /* == 10^35 */
1608             U64(0xC097CE7B, 0xC90715B3), U64(0x4B9F1000, 0x00000000), /* == 10^36 */
1609             U64(0xF0BDC21A, 0xBB48DB20), U64(0x1E86D400, 0x00000000), /* == 10^37 */
1610             U64(0x96769950, 0xB50D88F4), U64(0x13144480, 0x00000000), /* == 10^38 */
1611             U64(0xBC143FA4, 0xE250EB31), U64(0x17D955A0, 0x00000000), /* == 10^39 */
1612             U64(0xEB194F8E, 0x1AE525FD), U64(0x5DCFAB08, 0x00000000), /* == 10^40 */
1613             U64(0x92EFD1B8, 0xD0CF37BE), U64(0x5AA1CAE5, 0x00000000), /* == 10^41 */
1614             U64(0xB7ABC627, 0x050305AD), U64(0xF14A3D9E, 0x40000000), /* == 10^42 */
1615             U64(0xE596B7B0, 0xC643C719), U64(0x6D9CCD05, 0xD0000000), /* == 10^43 */
1616             U64(0x8F7E32CE, 0x7BEA5C6F), U64(0xE4820023, 0xA2000000), /* == 10^44 */
1617             U64(0xB35DBF82, 0x1AE4F38B), U64(0xDDA2802C, 0x8A800000), /* == 10^45 */
1618             U64(0xE0352F62, 0xA19E306E), U64(0xD50B2037, 0xAD200000), /* == 10^46 */
1619             U64(0x8C213D9D, 0xA502DE45), U64(0x4526F422, 0xCC340000), /* == 10^47 */
1620             U64(0xAF298D05, 0x0E4395D6), U64(0x9670B12B, 0x7F410000), /* == 10^48 */
1621             U64(0xDAF3F046, 0x51D47B4C), U64(0x3C0CDD76, 0x5F114000), /* == 10^49 */
1622             U64(0x88D8762B, 0xF324CD0F), U64(0xA5880A69, 0xFB6AC800), /* == 10^50 */
1623             U64(0xAB0E93B6, 0xEFEE0053), U64(0x8EEA0D04, 0x7A457A00), /* == 10^51 */
1624             U64(0xD5D238A4, 0xABE98068), U64(0x72A49045, 0x98D6D880), /* == 10^52 */
1625             U64(0x85A36366, 0xEB71F041), U64(0x47A6DA2B, 0x7F864750), /* == 10^53 */
1626             U64(0xA70C3C40, 0xA64E6C51), U64(0x999090B6, 0x5F67D924), /* == 10^54 */
1627             U64(0xD0CF4B50, 0xCFE20765), U64(0xFFF4B4E3, 0xF741CF6D), /* == 10^55 */
1628             U64(0x82818F12, 0x81ED449F), U64(0xBFF8F10E, 0x7A8921A4), /* ~= 10^56 */
1629             U64(0xA321F2D7, 0x226895C7), U64(0xAFF72D52, 0x192B6A0D), /* ~= 10^57 */
1630             U64(0xCBEA6F8C, 0xEB02BB39), U64(0x9BF4F8A6, 0x9F764490), /* ~= 10^58 */
1631             U64(0xFEE50B70, 0x25C36A08), U64(0x02F236D0, 0x4753D5B4), /* ~= 10^59 */
1632             U64(0x9F4F2726, 0x179A2245), U64(0x01D76242, 0x2C946590), /* ~= 10^60 */
1633             U64(0xC722F0EF, 0x9D80AAD6), U64(0x424D3AD2, 0xB7B97EF5), /* ~= 10^61 */
1634             U64(0xF8EBAD2B, 0x84E0D58B), U64(0xD2E08987, 0x65A7DEB2), /* ~= 10^62 */
1635             U64(0x9B934C3B, 0x330C8577), U64(0x63CC55F4, 0x9F88EB2F), /* ~= 10^63 */
1636             U64(0xC2781F49, 0xFFCFA6D5), U64(0x3CBF6B71, 0xC76B25FB), /* ~= 10^64 */
1637             U64(0xF316271C, 0x7FC3908A), U64(0x8BEF464E, 0x3945EF7A), /* ~= 10^65 */
1638             U64(0x97EDD871, 0xCFDA3A56), U64(0x97758BF0, 0xE3CBB5AC), /* ~= 10^66 */
1639             U64(0xBDE94E8E, 0x43D0C8EC), U64(0x3D52EEED, 0x1CBEA317), /* ~= 10^67 */
1640             U64(0xED63A231, 0xD4C4FB27), U64(0x4CA7AAA8, 0x63EE4BDD), /* ~= 10^68 */
1641             U64(0x945E455F, 0x24FB1CF8), U64(0x8FE8CAA9, 0x3E74EF6A), /* ~= 10^69 */
1642             U64(0xB975D6B6, 0xEE39E436), U64(0xB3E2FD53, 0x8E122B44), /* ~= 10^70 */
1643             U64(0xE7D34C64, 0xA9C85D44), U64(0x60DBBCA8, 0x7196B616), /* ~= 10^71 */
1644             U64(0x90E40FBE, 0xEA1D3A4A), U64(0xBC8955E9, 0x46FE31CD), /* ~= 10^72 */
1645             U64(0xB51D13AE, 0xA4A488DD), U64(0x6BABAB63, 0x98BDBE41), /* ~= 10^73 */
1646             U64(0xE264589A, 0x4DCDAB14), U64(0xC696963C, 0x7EED2DD1), /* ~= 10^74 */
1647             U64(0x8D7EB760, 0x70A08AEC), U64(0xFC1E1DE5, 0xCF543CA2), /* ~= 10^75 */
1648             U64(0xB0DE6538, 0x8CC8ADA8), U64(0x3B25A55F, 0x43294BCB), /* ~= 10^76 */
1649             U64(0xDD15FE86, 0xAFFAD912), U64(0x49EF0EB7, 0x13F39EBE), /* ~= 10^77 */
1650             U64(0x8A2DBF14, 0x2DFCC7AB), U64(0x6E356932, 0x6C784337), /* ~= 10^78 */
1651             U64(0xACB92ED9, 0x397BF996), U64(0x49C2C37F, 0x07965404), /* ~= 10^79 */
1652             U64(0xD7E77A8F, 0x87DAF7FB), U64(0xDC33745E, 0xC97BE906), /* ~= 10^80 */
1653             U64(0x86F0AC99, 0xB4E8DAFD), U64(0x69A028BB, 0x3DED71A3), /* ~= 10^81 */
1654             U64(0xA8ACD7C0, 0x222311BC), U64(0xC40832EA, 0x0D68CE0C), /* ~= 10^82 */
1655             U64(0xD2D80DB0, 0x2AABD62B), U64(0xF50A3FA4, 0x90C30190), /* ~= 10^83 */
1656             U64(0x83C7088E, 0x1AAB65DB), U64(0x792667C6, 0xDA79E0FA), /* ~= 10^84 */
1657             U64(0xA4B8CAB1, 0xA1563F52), U64(0x577001B8, 0x91185938), /* ~= 10^85 */
1658             U64(0xCDE6FD5E, 0x09ABCF26), U64(0xED4C0226, 0xB55E6F86), /* ~= 10^86 */
1659             U64(0x80B05E5A, 0xC60B6178), U64(0x544F8158, 0x315B05B4), /* ~= 10^87 */
1660             U64(0xA0DC75F1, 0x778E39D6), U64(0x696361AE, 0x3DB1C721), /* ~= 10^88 */
1661             U64(0xC913936D, 0xD571C84C), U64(0x03BC3A19, 0xCD1E38E9), /* ~= 10^89 */
1662             U64(0xFB587849, 0x4ACE3A5F), U64(0x04AB48A0, 0x4065C723), /* ~= 10^90 */
1663             U64(0x9D174B2D, 0xCEC0E47B), U64(0x62EB0D64, 0x283F9C76), /* ~= 10^91 */
1664             U64(0xC45D1DF9, 0x42711D9A), U64(0x3BA5D0BD, 0x324F8394), /* ~= 10^92 */
1665             U64(0xF5746577, 0x930D6500), U64(0xCA8F44EC, 0x7EE36479), /* ~= 10^93 */
1666             U64(0x9968BF6A, 0xBBE85F20), U64(0x7E998B13, 0xCF4E1ECB), /* ~= 10^94 */
1667             U64(0xBFC2EF45, 0x6AE276E8), U64(0x9E3FEDD8, 0xC321A67E), /* ~= 10^95 */
1668             U64(0xEFB3AB16, 0xC59B14A2), U64(0xC5CFE94E, 0xF3EA101E), /* ~= 10^96 */
1669             U64(0x95D04AEE, 0x3B80ECE5), U64(0xBBA1F1D1, 0x58724A12), /* ~= 10^97 */
1670             U64(0xBB445DA9, 0xCA61281F), U64(0x2A8A6E45, 0xAE8EDC97), /* ~= 10^98 */
1671             U64(0xEA157514, 0x3CF97226), U64(0xF52D09D7, 0x1A3293BD), /* ~= 10^99 */
1672             U64(0x924D692C, 0xA61BE758), U64(0x593C2626, 0x705F9C56), /* ~= 10^100 */
1673             U64(0xB6E0C377, 0xCFA2E12E), U64(0x6F8B2FB0, 0x0C77836C), /* ~= 10^101 */
1674             U64(0xE498F455, 0xC38B997A), U64(0x0B6DFB9C, 0x0F956447), /* ~= 10^102 */
1675             U64(0x8EDF98B5, 0x9A373FEC), U64(0x4724BD41, 0x89BD5EAC), /* ~= 10^103 */
1676             U64(0xB2977EE3, 0x00C50FE7), U64(0x58EDEC91, 0xEC2CB657), /* ~= 10^104 */
1677             U64(0xDF3D5E9B, 0xC0F653E1), U64(0x2F2967B6, 0x6737E3ED), /* ~= 10^105 */
1678             U64(0x8B865B21, 0x5899F46C), U64(0xBD79E0D2, 0x0082EE74), /* ~= 10^106 */
1679             U64(0xAE67F1E9, 0xAEC07187), U64(0xECD85906, 0x80A3AA11), /* ~= 10^107 */
1680             U64(0xDA01EE64, 0x1A708DE9), U64(0xE80E6F48, 0x20CC9495), /* ~= 10^108 */
1681             U64(0x884134FE, 0x908658B2), U64(0x3109058D, 0x147FDCDD), /* ~= 10^109 */
1682             U64(0xAA51823E, 0x34A7EEDE), U64(0xBD4B46F0, 0x599FD415), /* ~= 10^110 */
1683             U64(0xD4E5E2CD, 0xC1D1EA96), U64(0x6C9E18AC, 0x7007C91A), /* ~= 10^111 */
1684             U64(0x850FADC0, 0x9923329E), U64(0x03E2CF6B, 0xC604DDB0), /* ~= 10^112 */
1685             U64(0xA6539930, 0xBF6BFF45), U64(0x84DB8346, 0xB786151C), /* ~= 10^113 */
1686             U64(0xCFE87F7C, 0xEF46FF16), U64(0xE6126418, 0x65679A63), /* ~= 10^114 */
1687             U64(0x81F14FAE, 0x158C5F6E), U64(0x4FCB7E8F, 0x3F60C07E), /* ~= 10^115 */
1688             U64(0xA26DA399, 0x9AEF7749), U64(0xE3BE5E33, 0x0F38F09D), /* ~= 10^116 */
1689             U64(0xCB090C80, 0x01AB551C), U64(0x5CADF5BF, 0xD3072CC5), /* ~= 10^117 */
1690             U64(0xFDCB4FA0, 0x02162A63), U64(0x73D9732F, 0xC7C8F7F6), /* ~= 10^118 */
1691             U64(0x9E9F11C4, 0x014DDA7E), U64(0x2867E7FD, 0xDCDD9AFA), /* ~= 10^119 */
1692             U64(0xC646D635, 0x01A1511D), U64(0xB281E1FD, 0x541501B8), /* ~= 10^120 */
1693             U64(0xF7D88BC2, 0x4209A565), U64(0x1F225A7C, 0xA91A4226), /* ~= 10^121 */
1694             U64(0x9AE75759, 0x6946075F), U64(0x3375788D, 0xE9B06958), /* ~= 10^122 */
1695             U64(0xC1A12D2F, 0xC3978937), U64(0x0052D6B1, 0x641C83AE), /* ~= 10^123 */
1696             U64(0xF209787B, 0xB47D6B84), U64(0xC0678C5D, 0xBD23A49A), /* ~= 10^124 */
1697             U64(0x9745EB4D, 0x50CE6332), U64(0xF840B7BA, 0x963646E0), /* ~= 10^125 */
1698             U64(0xBD176620, 0xA501FBFF), U64(0xB650E5A9, 0x3BC3D898), /* ~= 10^126 */
1699             U64(0xEC5D3FA8, 0xCE427AFF), U64(0xA3E51F13, 0x8AB4CEBE), /* ~= 10^127 */
1700             U64(0x93BA47C9, 0x80E98CDF), U64(0xC66F336C, 0x36B10137), /* ~= 10^128 */
1701             U64(0xB8A8D9BB, 0xE123F017), U64(0xB80B0047, 0x445D4184), /* ~= 10^129 */
1702             U64(0xE6D3102A, 0xD96CEC1D), U64(0xA60DC059, 0x157491E5), /* ~= 10^130 */
1703             U64(0x9043EA1A, 0xC7E41392), U64(0x87C89837, 0xAD68DB2F), /* ~= 10^131 */
1704             U64(0xB454E4A1, 0x79DD1877), U64(0x29BABE45, 0x98C311FB), /* ~= 10^132 */
1705             U64(0xE16A1DC9, 0xD8545E94), U64(0xF4296DD6, 0xFEF3D67A), /* ~= 10^133 */
1706             U64(0x8CE2529E, 0x2734BB1D), U64(0x1899E4A6, 0x5F58660C), /* ~= 10^134 */
1707             U64(0xB01AE745, 0xB101E9E4), U64(0x5EC05DCF, 0xF72E7F8F), /* ~= 10^135 */
1708             U64(0xDC21A117, 0x1D42645D), U64(0x76707543, 0xF4FA1F73), /* ~= 10^136 */
1709             U64(0x899504AE, 0x72497EBA), U64(0x6A06494A, 0x791C53A8), /* ~= 10^137 */
1710             U64(0xABFA45DA, 0x0EDBDE69), U64(0x0487DB9D, 0x17636892), /* ~= 10^138 */
1711             U64(0xD6F8D750, 0x9292D603), U64(0x45A9D284, 0x5D3C42B6), /* ~= 10^139 */
1712             U64(0x865B8692, 0x5B9BC5C2), U64(0x0B8A2392, 0xBA45A9B2), /* ~= 10^140 */
1713             U64(0xA7F26836, 0xF282B732), U64(0x8E6CAC77, 0x68D7141E), /* ~= 10^141 */
1714             U64(0xD1EF0244, 0xAF2364FF), U64(0x3207D795, 0x430CD926), /* ~= 10^142 */
1715             U64(0x8335616A, 0xED761F1F), U64(0x7F44E6BD, 0x49E807B8), /* ~= 10^143 */
1716             U64(0xA402B9C5, 0xA8D3A6E7), U64(0x5F16206C, 0x9C6209A6), /* ~= 10^144 */
1717             U64(0xCD036837, 0x130890A1), U64(0x36DBA887, 0xC37A8C0F), /* ~= 10^145 */
1718             U64(0x80222122, 0x6BE55A64), U64(0xC2494954, 0xDA2C9789), /* ~= 10^146 */
1719             U64(0xA02AA96B, 0x06DEB0FD), U64(0xF2DB9BAA, 0x10B7BD6C), /* ~= 10^147 */
1720             U64(0xC83553C5, 0xC8965D3D), U64(0x6F928294, 0x94E5ACC7), /* ~= 10^148 */
1721             U64(0xFA42A8B7, 0x3ABBF48C), U64(0xCB772339, 0xBA1F17F9), /* ~= 10^149 */
1722             U64(0x9C69A972, 0x84B578D7), U64(0xFF2A7604, 0x14536EFB), /* ~= 10^150 */
1723             U64(0xC38413CF, 0x25E2D70D), U64(0xFEF51385, 0x19684ABA), /* ~= 10^151 */
1724             U64(0xF46518C2, 0xEF5B8CD1), U64(0x7EB25866, 0x5FC25D69), /* ~= 10^152 */
1725             U64(0x98BF2F79, 0xD5993802), U64(0xEF2F773F, 0xFBD97A61), /* ~= 10^153 */
1726             U64(0xBEEEFB58, 0x4AFF8603), U64(0xAAFB550F, 0xFACFD8FA), /* ~= 10^154 */
1727             U64(0xEEAABA2E, 0x5DBF6784), U64(0x95BA2A53, 0xF983CF38), /* ~= 10^155 */
1728             U64(0x952AB45C, 0xFA97A0B2), U64(0xDD945A74, 0x7BF26183), /* ~= 10^156 */
1729             U64(0xBA756174, 0x393D88DF), U64(0x94F97111, 0x9AEEF9E4), /* ~= 10^157 */
1730             U64(0xE912B9D1, 0x478CEB17), U64(0x7A37CD56, 0x01AAB85D), /* ~= 10^158 */
1731             U64(0x91ABB422, 0xCCB812EE), U64(0xAC62E055, 0xC10AB33A), /* ~= 10^159 */
1732             U64(0xB616A12B, 0x7FE617AA), U64(0x577B986B, 0x314D6009), /* ~= 10^160 */
1733             U64(0xE39C4976, 0x5FDF9D94), U64(0xED5A7E85, 0xFDA0B80B), /* ~= 10^161 */
1734             U64(0x8E41ADE9, 0xFBEBC27D), U64(0x14588F13, 0xBE847307), /* ~= 10^162 */
1735             U64(0xB1D21964, 0x7AE6B31C), U64(0x596EB2D8, 0xAE258FC8), /* ~= 10^163 */
1736             U64(0xDE469FBD, 0x99A05FE3), U64(0x6FCA5F8E, 0xD9AEF3BB), /* ~= 10^164 */
1737             U64(0x8AEC23D6, 0x80043BEE), U64(0x25DE7BB9, 0x480D5854), /* ~= 10^165 */
1738             U64(0xADA72CCC, 0x20054AE9), U64(0xAF561AA7, 0x9A10AE6A), /* ~= 10^166 */
1739             U64(0xD910F7FF, 0x28069DA4), U64(0x1B2BA151, 0x8094DA04), /* ~= 10^167 */
1740             U64(0x87AA9AFF, 0x79042286), U64(0x90FB44D2, 0xF05D0842), /* ~= 10^168 */
1741             U64(0xA99541BF, 0x57452B28), U64(0x353A1607, 0xAC744A53), /* ~= 10^169 */
1742             U64(0xD3FA922F, 0x2D1675F2), U64(0x42889B89, 0x97915CE8), /* ~= 10^170 */
1743             U64(0x847C9B5D, 0x7C2E09B7), U64(0x69956135, 0xFEBADA11), /* ~= 10^171 */
1744             U64(0xA59BC234, 0xDB398C25), U64(0x43FAB983, 0x7E699095), /* ~= 10^172 */
1745             U64(0xCF02B2C2, 0x1207EF2E), U64(0x94F967E4, 0x5E03F4BB), /* ~= 10^173 */
1746             U64(0x8161AFB9, 0x4B44F57D), U64(0x1D1BE0EE, 0xBAC278F5), /* ~= 10^174 */
1747             U64(0xA1BA1BA7, 0x9E1632DC), U64(0x6462D92A, 0x69731732), /* ~= 10^175 */
1748             U64(0xCA28A291, 0x859BBF93), U64(0x7D7B8F75, 0x03CFDCFE), /* ~= 10^176 */
1749             U64(0xFCB2CB35, 0xE702AF78), U64(0x5CDA7352, 0x44C3D43E), /* ~= 10^177 */
1750             U64(0x9DEFBF01, 0xB061ADAB), U64(0x3A088813, 0x6AFA64A7), /* ~= 10^178 */
1751             U64(0xC56BAEC2, 0x1C7A1916), U64(0x088AAA18, 0x45B8FDD0), /* ~= 10^179 */
1752             U64(0xF6C69A72, 0xA3989F5B), U64(0x8AAD549E, 0x57273D45), /* ~= 10^180 */
1753             U64(0x9A3C2087, 0xA63F6399), U64(0x36AC54E2, 0xF678864B), /* ~= 10^181 */
1754             U64(0xC0CB28A9, 0x8FCF3C7F), U64(0x84576A1B, 0xB416A7DD), /* ~= 10^182 */
1755             U64(0xF0FDF2D3, 0xF3C30B9F), U64(0x656D44A2, 0xA11C51D5), /* ~= 10^183 */
1756             U64(0x969EB7C4, 0x7859E743), U64(0x9F644AE5, 0xA4B1B325), /* ~= 10^184 */
1757             U64(0xBC4665B5, 0x96706114), U64(0x873D5D9F, 0x0DDE1FEE), /* ~= 10^185 */
1758             U64(0xEB57FF22, 0xFC0C7959), U64(0xA90CB506, 0xD155A7EA), /* ~= 10^186 */
1759             U64(0x9316FF75, 0xDD87CBD8), U64(0x09A7F124, 0x42D588F2), /* ~= 10^187 */
1760             U64(0xB7DCBF53, 0x54E9BECE), U64(0x0C11ED6D, 0x538AEB2F), /* ~= 10^188 */
1761             U64(0xE5D3EF28, 0x2A242E81), U64(0x8F1668C8, 0xA86DA5FA), /* ~= 10^189 */
1762             U64(0x8FA47579, 0x1A569D10), U64(0xF96E017D, 0x694487BC), /* ~= 10^190 */
1763             U64(0xB38D92D7, 0x60EC4455), U64(0x37C981DC, 0xC395A9AC), /* ~= 10^191 */
1764             U64(0xE070F78D, 0x3927556A), U64(0x85BBE253, 0xF47B1417), /* ~= 10^192 */
1765             U64(0x8C469AB8, 0x43B89562), U64(0x93956D74, 0x78CCEC8E), /* ~= 10^193 */
1766             U64(0xAF584166, 0x54A6BABB), U64(0x387AC8D1, 0x970027B2), /* ~= 10^194 */
1767             U64(0xDB2E51BF, 0xE9D0696A), U64(0x06997B05, 0xFCC0319E), /* ~= 10^195 */
1768             U64(0x88FCF317, 0xF22241E2), U64(0x441FECE3, 0xBDF81F03), /* ~= 10^196 */
1769             U64(0xAB3C2FDD, 0xEEAAD25A), U64(0xD527E81C, 0xAD7626C3), /* ~= 10^197 */
1770             U64(0xD60B3BD5, 0x6A5586F1), U64(0x8A71E223, 0xD8D3B074), /* ~= 10^198 */
1771             U64(0x85C70565, 0x62757456), U64(0xF6872D56, 0x67844E49), /* ~= 10^199 */
1772             U64(0xA738C6BE, 0xBB12D16C), U64(0xB428F8AC, 0x016561DB), /* ~= 10^200 */
1773             U64(0xD106F86E, 0x69D785C7), U64(0xE13336D7, 0x01BEBA52), /* ~= 10^201 */
1774             U64(0x82A45B45, 0x0226B39C), U64(0xECC00246, 0x61173473), /* ~= 10^202 */
1775             U64(0xA34D7216, 0x42B06084), U64(0x27F002D7, 0xF95D0190), /* ~= 10^203 */
1776             U64(0xCC20CE9B, 0xD35C78A5), U64(0x31EC038D, 0xF7B441F4), /* ~= 10^204 */
1777             U64(0xFF290242, 0xC83396CE), U64(0x7E670471, 0x75A15271), /* ~= 10^205 */
1778             U64(0x9F79A169, 0xBD203E41), U64(0x0F0062C6, 0xE984D386), /* ~= 10^206 */
1779             U64(0xC75809C4, 0x2C684DD1), U64(0x52C07B78, 0xA3E60868), /* ~= 10^207 */
1780             U64(0xF92E0C35, 0x37826145), U64(0xA7709A56, 0xCCDF8A82), /* ~= 10^208 */
1781             U64(0x9BBCC7A1, 0x42B17CCB), U64(0x88A66076, 0x400BB691), /* ~= 10^209 */
1782             U64(0xC2ABF989, 0x935DDBFE), U64(0x6ACFF893, 0xD00EA435), /* ~= 10^210 */
1783             U64(0xF356F7EB, 0xF83552FE), U64(0x0583F6B8, 0xC4124D43), /* ~= 10^211 */
1784             U64(0x98165AF3, 0x7B2153DE), U64(0xC3727A33, 0x7A8B704A), /* ~= 10^212 */
1785             U64(0xBE1BF1B0, 0x59E9A8D6), U64(0x744F18C0, 0x592E4C5C), /* ~= 10^213 */
1786             U64(0xEDA2EE1C, 0x7064130C), U64(0x1162DEF0, 0x6F79DF73), /* ~= 10^214 */
1787             U64(0x9485D4D1, 0xC63E8BE7), U64(0x8ADDCB56, 0x45AC2BA8), /* ~= 10^215 */
1788             U64(0xB9A74A06, 0x37CE2EE1), U64(0x6D953E2B, 0xD7173692), /* ~= 10^216 */
1789             U64(0xE8111C87, 0xC5C1BA99), U64(0xC8FA8DB6, 0xCCDD0437), /* ~= 10^217 */
1790             U64(0x910AB1D4, 0xDB9914A0), U64(0x1D9C9892, 0x400A22A2), /* ~= 10^218 */
1791             U64(0xB54D5E4A, 0x127F59C8), U64(0x2503BEB6, 0xD00CAB4B), /* ~= 10^219 */
1792             U64(0xE2A0B5DC, 0x971F303A), U64(0x2E44AE64, 0x840FD61D), /* ~= 10^220 */
1793             U64(0x8DA471A9, 0xDE737E24), U64(0x5CEAECFE, 0xD289E5D2), /* ~= 10^221 */
1794             U64(0xB10D8E14, 0x56105DAD), U64(0x7425A83E, 0x872C5F47), /* ~= 10^222 */
1795             U64(0xDD50F199, 0x6B947518), U64(0xD12F124E, 0x28F77719), /* ~= 10^223 */
1796             U64(0x8A5296FF, 0xE33CC92F), U64(0x82BD6B70, 0xD99AAA6F), /* ~= 10^224 */
1797             U64(0xACE73CBF, 0xDC0BFB7B), U64(0x636CC64D, 0x1001550B), /* ~= 10^225 */
1798             U64(0xD8210BEF, 0xD30EFA5A), U64(0x3C47F7E0, 0x5401AA4E), /* ~= 10^226 */
1799             U64(0x8714A775, 0xE3E95C78), U64(0x65ACFAEC, 0x34810A71), /* ~= 10^227 */
1800             U64(0xA8D9D153, 0x5CE3B396), U64(0x7F1839A7, 0x41A14D0D), /* ~= 10^228 */
1801             U64(0xD31045A8, 0x341CA07C), U64(0x1EDE4811, 0x1209A050), /* ~= 10^229 */
1802             U64(0x83EA2B89, 0x2091E44D), U64(0x934AED0A, 0xAB460432), /* ~= 10^230 */
1803             U64(0xA4E4B66B, 0x68B65D60), U64(0xF81DA84D, 0x5617853F), /* ~= 10^231 */
1804             U64(0xCE1DE406, 0x42E3F4B9), U64(0x36251260, 0xAB9D668E), /* ~= 10^232 */
1805             U64(0x80D2AE83, 0xE9CE78F3), U64(0xC1D72B7C, 0x6B426019), /* ~= 10^233 */
1806             U64(0xA1075A24, 0xE4421730), U64(0xB24CF65B, 0x8612F81F), /* ~= 10^234 */
1807             U64(0xC94930AE, 0x1D529CFC), U64(0xDEE033F2, 0x6797B627), /* ~= 10^235 */
1808             U64(0xFB9B7CD9, 0xA4A7443C), U64(0x169840EF, 0x017DA3B1), /* ~= 10^236 */
1809             U64(0x9D412E08, 0x06E88AA5), U64(0x8E1F2895, 0x60EE864E), /* ~= 10^237 */
1810             U64(0xC491798A, 0x08A2AD4E), U64(0xF1A6F2BA, 0xB92A27E2), /* ~= 10^238 */
1811             U64(0xF5B5D7EC, 0x8ACB58A2), U64(0xAE10AF69, 0x6774B1DB), /* ~= 10^239 */
1812             U64(0x9991A6F3, 0xD6BF1765), U64(0xACCA6DA1, 0xE0A8EF29), /* ~= 10^240 */
1813             U64(0xBFF610B0, 0xCC6EDD3F), U64(0x17FD090A, 0x58D32AF3), /* ~= 10^241 */
1814             U64(0xEFF394DC, 0xFF8A948E), U64(0xDDFC4B4C, 0xEF07F5B0), /* ~= 10^242 */
1815             U64(0x95F83D0A, 0x1FB69CD9), U64(0x4ABDAF10, 0x1564F98E), /* ~= 10^243 */
1816             U64(0xBB764C4C, 0xA7A4440F), U64(0x9D6D1AD4, 0x1ABE37F1), /* ~= 10^244 */
1817             U64(0xEA53DF5F, 0xD18D5513), U64(0x84C86189, 0x216DC5ED), /* ~= 10^245 */
1818             U64(0x92746B9B, 0xE2F8552C), U64(0x32FD3CF5, 0xB4E49BB4), /* ~= 10^246 */
1819             U64(0xB7118682, 0xDBB66A77), U64(0x3FBC8C33, 0x221DC2A1), /* ~= 10^247 */
1820             U64(0xE4D5E823, 0x92A40515), U64(0x0FABAF3F, 0xEAA5334A), /* ~= 10^248 */
1821             U64(0x8F05B116, 0x3BA6832D), U64(0x29CB4D87, 0xF2A7400E), /* ~= 10^249 */
1822             U64(0xB2C71D5B, 0xCA9023F8), U64(0x743E20E9, 0xEF511012), /* ~= 10^250 */
1823             U64(0xDF78E4B2, 0xBD342CF6), U64(0x914DA924, 0x6B255416), /* ~= 10^251 */
1824             U64(0x8BAB8EEF, 0xB6409C1A), U64(0x1AD089B6, 0xC2F7548E), /* ~= 10^252 */
1825             U64(0xAE9672AB, 0xA3D0C320), U64(0xA184AC24, 0x73B529B1), /* ~= 10^253 */
1826             U64(0xDA3C0F56, 0x8CC4F3E8), U64(0xC9E5D72D, 0x90A2741E), /* ~= 10^254 */
1827             U64(0x88658996, 0x17FB1871), U64(0x7E2FA67C, 0x7A658892), /* ~= 10^255 */
1828             U64(0xAA7EEBFB, 0x9DF9DE8D), U64(0xDDBB901B, 0x98FEEAB7), /* ~= 10^256 */
1829             U64(0xD51EA6FA, 0x85785631), U64(0x552A7422, 0x7F3EA565), /* ~= 10^257 */
1830             U64(0x8533285C, 0x936B35DE), U64(0xD53A8895, 0x8F87275F), /* ~= 10^258 */
1831             U64(0xA67FF273, 0xB8460356), U64(0x8A892ABA, 0xF368F137), /* ~= 10^259 */
1832             U64(0xD01FEF10, 0xA657842C), U64(0x2D2B7569, 0xB0432D85), /* ~= 10^260 */
1833             U64(0x8213F56A, 0x67F6B29B), U64(0x9C3B2962, 0x0E29FC73), /* ~= 10^261 */
1834             U64(0xA298F2C5, 0x01F45F42), U64(0x8349F3BA, 0x91B47B8F), /* ~= 10^262 */
1835             U64(0xCB3F2F76, 0x42717713), U64(0x241C70A9, 0x36219A73), /* ~= 10^263 */
1836             U64(0xFE0EFB53, 0xD30DD4D7), U64(0xED238CD3, 0x83AA0110), /* ~= 10^264 */
1837             U64(0x9EC95D14, 0x63E8A506), U64(0xF4363804, 0x324A40AA), /* ~= 10^265 */
1838             U64(0xC67BB459, 0x7CE2CE48), U64(0xB143C605, 0x3EDCD0D5), /* ~= 10^266 */
1839             U64(0xF81AA16F, 0xDC1B81DA), U64(0xDD94B786, 0x8E94050A), /* ~= 10^267 */
1840             U64(0x9B10A4E5, 0xE9913128), U64(0xCA7CF2B4, 0x191C8326), /* ~= 10^268 */
1841             U64(0xC1D4CE1F, 0x63F57D72), U64(0xFD1C2F61, 0x1F63A3F0), /* ~= 10^269 */
1842             U64(0xF24A01A7, 0x3CF2DCCF), U64(0xBC633B39, 0x673C8CEC), /* ~= 10^270 */
1843             U64(0x976E4108, 0x8617CA01), U64(0xD5BE0503, 0xE085D813), /* ~= 10^271 */
1844             U64(0xBD49D14A, 0xA79DBC82), U64(0x4B2D8644, 0xD8A74E18), /* ~= 10^272 */
1845             U64(0xEC9C459D, 0x51852BA2), U64(0xDDF8E7D6, 0x0ED1219E), /* ~= 10^273 */
1846             U64(0x93E1AB82, 0x52F33B45), U64(0xCABB90E5, 0xC942B503), /* ~= 10^274 */
1847             U64(0xB8DA1662, 0xE7B00A17), U64(0x3D6A751F, 0x3B936243), /* ~= 10^275 */
1848             U64(0xE7109BFB, 0xA19C0C9D), U64(0x0CC51267, 0x0A783AD4), /* ~= 10^276 */
1849             U64(0x906A617D, 0x450187E2), U64(0x27FB2B80, 0x668B24C5), /* ~= 10^277 */
1850             U64(0xB484F9DC, 0x9641E9DA), U64(0xB1F9F660, 0x802DEDF6), /* ~= 10^278 */
1851             U64(0xE1A63853, 0xBBD26451), U64(0x5E7873F8, 0xA0396973), /* ~= 10^279 */
1852             U64(0x8D07E334, 0x55637EB2), U64(0xDB0B487B, 0x6423E1E8), /* ~= 10^280 */
1853             U64(0xB049DC01, 0x6ABC5E5F), U64(0x91CE1A9A, 0x3D2CDA62), /* ~= 10^281 */
1854             U64(0xDC5C5301, 0xC56B75F7), U64(0x7641A140, 0xCC7810FB), /* ~= 10^282 */
1855             U64(0x89B9B3E1, 0x1B6329BA), U64(0xA9E904C8, 0x7FCB0A9D), /* ~= 10^283 */
1856             U64(0xAC2820D9, 0x623BF429), U64(0x546345FA, 0x9FBDCD44), /* ~= 10^284 */
1857             U64(0xD732290F, 0xBACAF133), U64(0xA97C1779, 0x47AD4095), /* ~= 10^285 */
1858             U64(0x867F59A9, 0xD4BED6C0), U64(0x49ED8EAB, 0xCCCC485D), /* ~= 10^286 */
1859             U64(0xA81F3014, 0x49EE8C70), U64(0x5C68F256, 0xBFFF5A74), /* ~= 10^287 */
1860             U64(0xD226FC19, 0x5C6A2F8C), U64(0x73832EEC, 0x6FFF3111), /* ~= 10^288 */
1861             U64(0x83585D8F, 0xD9C25DB7), U64(0xC831FD53, 0xC5FF7EAB), /* ~= 10^289 */
1862             U64(0xA42E74F3, 0xD032F525), U64(0xBA3E7CA8, 0xB77F5E55), /* ~= 10^290 */
1863             U64(0xCD3A1230, 0xC43FB26F), U64(0x28CE1BD2, 0xE55F35EB), /* ~= 10^291 */
1864             U64(0x80444B5E, 0x7AA7CF85), U64(0x7980D163, 0xCF5B81B3), /* ~= 10^292 */
1865             U64(0xA0555E36, 0x1951C366), U64(0xD7E105BC, 0xC332621F), /* ~= 10^293 */
1866             U64(0xC86AB5C3, 0x9FA63440), U64(0x8DD9472B, 0xF3FEFAA7), /* ~= 10^294 */
1867             U64(0xFA856334, 0x878FC150), U64(0xB14F98F6, 0xF0FEB951), /* ~= 10^295 */
1868             U64(0x9C935E00, 0xD4B9D8D2), U64(0x6ED1BF9A, 0x569F33D3), /* ~= 10^296 */
1869             U64(0xC3B83581, 0x09E84F07), U64(0x0A862F80, 0xEC4700C8), /* ~= 10^297 */
1870             U64(0xF4A642E1, 0x4C6262C8), U64(0xCD27BB61, 0x2758C0FA), /* ~= 10^298 */
1871             U64(0x98E7E9CC, 0xCFBD7DBD), U64(0x8038D51C, 0xB897789C), /* ~= 10^299 */
1872             U64(0xBF21E440, 0x03ACDD2C), U64(0xE0470A63, 0xE6BD56C3), /* ~= 10^300 */
1873             U64(0xEEEA5D50, 0x04981478), U64(0x1858CCFC, 0xE06CAC74), /* ~= 10^301 */
1874             U64(0x95527A52, 0x02DF0CCB), U64(0x0F37801E, 0x0C43EBC8), /* ~= 10^302 */
1875             U64(0xBAA718E6, 0x8396CFFD), U64(0xD3056025, 0x8F54E6BA), /* ~= 10^303 */
1876             U64(0xE950DF20, 0x247C83FD), U64(0x47C6B82E, 0xF32A2069), /* ~= 10^304 */
1877             U64(0x91D28B74, 0x16CDD27E), U64(0x4CDC331D, 0x57FA5441), /* ~= 10^305 */
1878             U64(0xB6472E51, 0x1C81471D), U64(0xE0133FE4, 0xADF8E952), /* ~= 10^306 */
1879             U64(0xE3D8F9E5, 0x63A198E5), U64(0x58180FDD, 0xD97723A6), /* ~= 10^307 */
1880             U64(0x8E679C2F, 0x5E44FF8F), U64(0x570F09EA, 0xA7EA7648), /* ~= 10^308 */
1881             U64(0xB201833B, 0x35D63F73), U64(0x2CD2CC65, 0x51E513DA), /* ~= 10^309 */
1882             U64(0xDE81E40A, 0x034BCF4F), U64(0xF8077F7E, 0xA65E58D1), /* ~= 10^310 */
1883             U64(0x8B112E86, 0x420F6191), U64(0xFB04AFAF, 0x27FAF782), /* ~= 10^311 */
1884             U64(0xADD57A27, 0xD29339F6), U64(0x79C5DB9A, 0xF1F9B563), /* ~= 10^312 */
1885             U64(0xD94AD8B1, 0xC7380874), U64(0x18375281, 0xAE7822BC), /* ~= 10^313 */
1886             U64(0x87CEC76F, 0x1C830548), U64(0x8F229391, 0x0D0B15B5), /* ~= 10^314 */
1887             U64(0xA9C2794A, 0xE3A3C69A), U64(0xB2EB3875, 0x504DDB22), /* ~= 10^315 */
1888             U64(0xD433179D, 0x9C8CB841), U64(0x5FA60692, 0xA46151EB), /* ~= 10^316 */
1889             U64(0x849FEEC2, 0x81D7F328), U64(0xDBC7C41B, 0xA6BCD333), /* ~= 10^317 */
1890             U64(0xA5C7EA73, 0x224DEFF3), U64(0x12B9B522, 0x906C0800), /* ~= 10^318 */
1891             U64(0xCF39E50F, 0xEAE16BEF), U64(0xD768226B, 0x34870A00), /* ~= 10^319 */
1892             U64(0x81842F29, 0xF2CCE375), U64(0xE6A11583, 0x00D46640), /* ~= 10^320 */
1893             U64(0xA1E53AF4, 0x6F801C53), U64(0x60495AE3, 0xC1097FD0), /* ~= 10^321 */
1894             U64(0xCA5E89B1, 0x8B602368), U64(0x385BB19C, 0xB14BDFC4), /* ~= 10^322 */
1895             U64(0xFCF62C1D, 0xEE382C42), U64(0x46729E03, 0xDD9ED7B5), /* ~= 10^323 */
1896             U64(0x9E19DB92, 0xB4E31BA9), U64(0x6C07A2C2, 0x6A8346D1) /* ~= 10^324 */
1897             };
1898              
1899             /**
1900             Get the cached pow10 value from `pow10_sig_table`.
1901             @param exp10 The exponent of pow(10, e). This value must in range
1902             `POW10_SIG_TABLE_MIN_EXP` to `POW10_SIG_TABLE_MAX_EXP`.
1903             @param hi The highest 64 bits of pow(10, e).
1904             @param lo The lower 64 bits after `hi`.
1905             */
1906             static_inline void pow10_table_get_sig(i32 exp10, u64 *hi, u64 *lo) {
1907 1           i32 idx = exp10 - (POW10_SIG_TABLE_MIN_EXP);
1908 1           *hi = pow10_sig_table[idx * 2];
1909 1           *lo = pow10_sig_table[idx * 2 + 1];
1910 1           }
1911              
1912             /**
1913             Get the exponent (base 2) for highest 64 bits significand in `pow10_sig_table`.
1914             */
1915             static_inline void pow10_table_get_exp(i32 exp10, i32 *exp2) {
1916             /* e2 = floor(log2(pow(10, e))) - 64 + 1 */
1917             /* = floor(e * log2(10) - 63) */
1918 0           *exp2 = (exp10 * 217706 - 4128768) >> 16;
1919 0           }
1920              
1921             #endif
1922              
1923              
1924              
1925             /*==============================================================================
1926             * MARK: - Number and Bit Utils (Private)
1927             *============================================================================*/
1928              
1929             /** Convert bits to double. */
1930             static_inline f64 f64_from_bits(u64 u) {
1931             f64 f;
1932 0           memcpy(&f, &u, sizeof(u));
1933 0           return f;
1934             }
1935              
1936             /** Convert double to bits. */
1937             static_inline u64 f64_to_bits(f64 f) {
1938             u64 u;
1939             memcpy(&u, &f, sizeof(u));
1940             return u;
1941             }
1942              
1943             /** Convert double to bits. */
1944             static_inline u32 f32_to_bits(f32 f) {
1945             u32 u;
1946 0           memcpy(&u, &f, sizeof(u));
1947 0           return u;
1948             }
1949              
1950             /** Get 'infinity' bits with sign. */
1951             static_inline u64 f64_bits_inf(bool sign) {
1952             #if YYJSON_HAS_IEEE_754
1953 0           return F64_BITS_INF | ((u64)sign << 63);
1954             #elif defined(INFINITY)
1955             return f64_to_bits(sign ? -INFINITY : INFINITY);
1956             #else
1957             return f64_to_bits(sign ? -HUGE_VAL : HUGE_VAL);
1958             #endif
1959             }
1960              
1961             /** Get 'nan' bits with sign. */
1962             static_inline u64 f64_bits_nan(bool sign) {
1963             #if YYJSON_HAS_IEEE_754
1964 0           return F64_BITS_NAN | ((u64)sign << 63);
1965             #elif defined(NAN)
1966             return f64_to_bits(sign ? (f64)-NAN : (f64)NAN);
1967             #else
1968             return f64_to_bits((sign ? -0.0 : 0.0) / 0.0);
1969             #endif
1970             }
1971              
1972             /** Casting double to float, allow overflow. */
1973             #if yyjson_has_attribute(no_sanitize)
1974             __attribute__((no_sanitize("undefined")))
1975             #elif yyjson_gcc_available(4, 9, 0)
1976             __attribute__((__no_sanitize_undefined__))
1977             #endif
1978             static_inline f32 f64_to_f32(f64 val) {
1979 0           return (f32)val;
1980             }
1981              
1982             /** Returns the number of leading 0-bits in value (input should not be 0). */
1983             static_inline u32 u64_lz_bits(u64 v) {
1984             #if GCC_HAS_CLZLL
1985 0           return (u32)__builtin_clzll(v);
1986             #elif MSC_HAS_BIT_SCAN_64
1987             unsigned long r;
1988             _BitScanReverse64(&r, v);
1989             return (u32)63 - (u32)r;
1990             #elif MSC_HAS_BIT_SCAN
1991             unsigned long hi, lo;
1992             bool hi_set = _BitScanReverse(&hi, (u32)(v >> 32)) != 0;
1993             _BitScanReverse(&lo, (u32)v);
1994             hi |= 32;
1995             return (u32)63 - (u32)(hi_set ? hi : lo);
1996             #else
1997             /* branchless, use De Bruijn sequence */
1998             /* see: https://www.chessprogramming.org/BitScan */
1999             const u8 table[64] = {
2000             63, 16, 62, 7, 15, 36, 61, 3, 6, 14, 22, 26, 35, 47, 60, 2,
2001             9, 5, 28, 11, 13, 21, 42, 19, 25, 31, 34, 40, 46, 52, 59, 1,
2002             17, 8, 37, 4, 23, 27, 48, 10, 29, 12, 43, 20, 32, 41, 53, 18,
2003             38, 24, 49, 30, 44, 33, 54, 39, 50, 45, 55, 51, 56, 57, 58, 0
2004             };
2005             v |= v >> 1;
2006             v |= v >> 2;
2007             v |= v >> 4;
2008             v |= v >> 8;
2009             v |= v >> 16;
2010             v |= v >> 32;
2011             return table[(v * U64(0x03F79D71, 0xB4CB0A89)) >> 58];
2012             #endif
2013             }
2014              
2015             /** Returns the number of trailing 0-bits in value (input should not be 0). */
2016             static_inline u32 u64_tz_bits(u64 v) {
2017             #if GCC_HAS_CTZLL
2018 1           return (u32)__builtin_ctzll(v);
2019             #elif MSC_HAS_BIT_SCAN_64
2020             unsigned long r;
2021             _BitScanForward64(&r, v);
2022             return (u32)r;
2023             #elif MSC_HAS_BIT_SCAN
2024             unsigned long lo, hi;
2025             bool lo_set = _BitScanForward(&lo, (u32)(v)) != 0;
2026             _BitScanForward(&hi, (u32)(v >> 32));
2027             hi += 32;
2028             return lo_set ? lo : hi;
2029             #else
2030             /* branchless, use De Bruijn sequence */
2031             /* see: https://www.chessprogramming.org/BitScan */
2032             const u8 table[64] = {
2033             0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28,
2034             62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11,
2035             63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
2036             51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12
2037             };
2038             return table[((v & (~v + 1)) * U64(0x022FDD63, 0xCC95386D)) >> 58];
2039             #endif
2040             }
2041              
2042             /** Multiplies two 64-bit unsigned integers (a * b),
2043             returns the 128-bit result as 'hi' and 'lo'. */
2044             static_inline void u128_mul(u64 a, u64 b, u64 *hi, u64 *lo) {
2045             #if YYJSON_HAS_INT128
2046 1           u128 m = (u128)a * b;
2047 1           *hi = (u64)(m >> 64);
2048 1           *lo = (u64)(m);
2049             #elif MSC_HAS_UMUL128
2050             *lo = _umul128(a, b, hi);
2051             #else
2052             u32 a0 = (u32)(a), a1 = (u32)(a >> 32);
2053             u32 b0 = (u32)(b), b1 = (u32)(b >> 32);
2054             u64 p00 = (u64)a0 * b0, p01 = (u64)a0 * b1;
2055             u64 p10 = (u64)a1 * b0, p11 = (u64)a1 * b1;
2056             u64 m0 = p01 + (p00 >> 32);
2057             u32 m00 = (u32)(m0), m01 = (u32)(m0 >> 32);
2058             u64 m1 = p10 + m00;
2059             u32 m10 = (u32)(m1), m11 = (u32)(m1 >> 32);
2060             *hi = p11 + m01 + m11;
2061             *lo = ((u64)m10 << 32) | (u32)p00;
2062             #endif
2063 1           }
2064              
2065             /** Multiplies two 64-bit unsigned integers and add a value (a * b + c),
2066             returns the 128-bit result as 'hi' and 'lo'. */
2067             static_inline void u128_mul_add(u64 a, u64 b, u64 c, u64 *hi, u64 *lo) {
2068             #if YYJSON_HAS_INT128
2069 1           u128 m = (u128)a * b + c;
2070 1           *hi = (u64)(m >> 64);
2071 1           *lo = (u64)(m);
2072             #else
2073             u64 h, l, t;
2074             u128_mul(a, b, &h, &l);
2075             t = l + c;
2076             h += (u64)(((t < l) | (t < c)));
2077             *hi = h;
2078             *lo = t;
2079             #endif
2080 1           }
2081              
2082              
2083              
2084             /*==============================================================================
2085             * MARK: - File Utils (Private)
2086             * These functions are used to read and write JSON files.
2087             *============================================================================*/
2088              
2089             #define YYJSON_FOPEN_E
2090             #if !defined(_MSC_VER) && defined(__GLIBC__) && defined(__GLIBC_PREREQ)
2091             # if __GLIBC_PREREQ(2, 7)
2092             # undef YYJSON_FOPEN_E
2093             # define YYJSON_FOPEN_E "e" /* glibc extension to enable O_CLOEXEC */
2094             # endif
2095             #endif
2096              
2097             static_inline FILE *fopen_safe(const char *path, const char *mode) {
2098             #if YYJSON_MSC_VER >= 1400
2099             FILE *file = NULL;
2100             if (fopen_s(&file, path, mode) != 0) return NULL;
2101             return file;
2102             #else
2103 4           return fopen(path, mode);
2104             #endif
2105             }
2106              
2107             static_inline FILE *fopen_readonly(const char *path) {
2108 4           return fopen_safe(path, "rb" YYJSON_FOPEN_E);
2109             }
2110              
2111             static_inline FILE *fopen_writeonly(const char *path) {
2112 3           return fopen_safe(path, "wb" YYJSON_FOPEN_E);
2113             }
2114              
2115             static_inline usize fread_safe(void *buf, usize size, FILE *file) {
2116             #if YYJSON_MSC_VER >= 1400
2117             return fread_s(buf, size, 1, size, file);
2118             #else
2119 3           return fread(buf, 1, size, file);
2120             #endif
2121             }
2122              
2123              
2124              
2125             /*==============================================================================
2126             * MARK: - Size Utils (Private)
2127             * These functions are used for memory allocation.
2128             *============================================================================*/
2129              
2130             /** Returns whether the size is overflow after increment. */
2131             static_inline bool size_add_is_overflow(usize size, usize add) {
2132             return size > (size + add);
2133             }
2134              
2135             /** Returns whether the size is power of 2 (size should not be 0). */
2136             static_inline bool size_is_pow2(usize size) {
2137 0           return (size & (size - 1)) == 0;
2138             }
2139              
2140             /** Align size upwards (may overflow). */
2141             static_inline usize size_align_up(usize size, usize align) {
2142 15033 50         if (size_is_pow2(align)) {
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    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          
2143 15033           return (size + (align - 1)) & ~(align - 1);
2144             } else {
2145 0           return size + align - (size + align - 1) % align - 1;
2146             }
2147             }
2148              
2149             /** Align size downwards. */
2150             static_inline usize size_align_down(usize size, usize align) {
2151 0 0         if (size_is_pow2(align)) {
2152 0           return size & ~(align - 1);
2153             } else {
2154 0           return size - (size % align);
2155             }
2156             }
2157              
2158             /** Align address upwards (may overflow). */
2159             static_inline void *mem_align_up(void *mem, usize align) {
2160             usize size;
2161 0           memcpy(&size, &mem, sizeof(usize));
2162 0           size = size_align_up(size, align);
2163 0           memcpy(&mem, &size, sizeof(usize));
2164 0           return mem;
2165             }
2166              
2167              
2168              
2169             /*==============================================================================
2170             * MARK: - Default Memory Allocator (Private)
2171             * This is a simple libc memory allocator wrapper.
2172             *============================================================================*/
2173              
2174 90598           static void *default_malloc(void *ctx, usize size) {
2175 90598           return malloc(size);
2176             }
2177              
2178 53           static void *default_realloc(void *ctx, void *ptr, usize old_size, usize size) {
2179 53           return realloc(ptr, size);
2180             }
2181              
2182 75555           static void default_free(void *ctx, void *ptr) {
2183 75555           free(ptr);
2184 75555           }
2185              
2186             static const yyjson_alc YYJSON_DEFAULT_ALC = {
2187             default_malloc, default_realloc, default_free, NULL
2188             };
2189              
2190              
2191              
2192             /*==============================================================================
2193             * MARK: - Null Memory Allocator (Private)
2194             * This allocator is just a placeholder to ensure that the internal
2195             * malloc/realloc/free function pointers are not null.
2196             *============================================================================*/
2197              
2198 0           static void *null_malloc(void *ctx, usize size) {
2199 0           return NULL;
2200             }
2201              
2202 0           static void *null_realloc(void *ctx, void *ptr, usize old_size, usize size) {
2203 0           return NULL;
2204             }
2205              
2206 0           static void null_free(void *ctx, void *ptr) {
2207 0           return;
2208             }
2209              
2210             static const yyjson_alc YYJSON_NULL_ALC = {
2211             null_malloc, null_realloc, null_free, NULL
2212             };
2213              
2214              
2215              
2216             /*==============================================================================
2217             * MARK: - Pool Memory Allocator (Public)
2218             * This allocator is initialized with a fixed-size buffer.
2219             * The buffer is split into multiple memory chunks for memory allocation.
2220             *============================================================================*/
2221              
2222             /** memory chunk header */
2223             typedef struct pool_chunk {
2224             usize size; /* chunk memory size, include chunk header */
2225             struct pool_chunk *next; /* linked list, nullable */
2226             /* char mem[]; flexible array member */
2227             } pool_chunk;
2228              
2229             /** allocator ctx header */
2230             typedef struct pool_ctx {
2231             usize size; /* total memory size, include ctx header */
2232             pool_chunk *free_list; /* linked list, nullable */
2233             /* pool_chunk chunks[]; flexible array member */
2234             } pool_ctx;
2235              
2236             /** align up the input size to chunk size */
2237             static_inline void pool_size_align(usize *size) {
2238 0           *size = size_align_up(*size, sizeof(pool_chunk)) + sizeof(pool_chunk);
2239 0           }
2240              
2241 0           static void *pool_malloc(void *ctx_ptr, usize size) {
2242             /* assert(size != 0) */
2243 0           pool_ctx *ctx = (pool_ctx *)ctx_ptr;
2244 0           pool_chunk *next, *prev = NULL, *cur = ctx->free_list;
2245              
2246 0 0         if (unlikely(size >= ctx->size)) return NULL;
2247             pool_size_align(&size);
2248              
2249 0 0         while (cur) {
2250 0 0         if (cur->size < size) {
2251             /* not enough space, try next chunk */
2252 0           prev = cur;
2253 0           cur = cur->next;
2254 0           continue;
2255             }
2256 0 0         if (cur->size >= size + sizeof(pool_chunk) * 2) {
2257             /* too much space, split this chunk */
2258 0           next = (pool_chunk *)(void *)((u8 *)cur + size);
2259 0           next->size = cur->size - size;
2260 0           next->next = cur->next;
2261 0           cur->size = size;
2262             } else {
2263             /* just enough space, use whole chunk */
2264 0           next = cur->next;
2265             }
2266 0 0         if (prev) prev->next = next;
2267 0           else ctx->free_list = next;
2268 0           return (void *)(cur + 1);
2269             }
2270 0           return NULL;
2271             }
2272              
2273 0           static void pool_free(void *ctx_ptr, void *ptr) {
2274             /* assert(ptr != NULL) */
2275 0           pool_ctx *ctx = (pool_ctx *)ctx_ptr;
2276 0           pool_chunk *cur = ((pool_chunk *)ptr) - 1;
2277 0           pool_chunk *prev = NULL, *next = ctx->free_list;
2278              
2279 0 0         while (next && next < cur) {
    0          
2280 0           prev = next;
2281 0           next = next->next;
2282             }
2283 0 0         if (prev) prev->next = cur;
2284 0           else ctx->free_list = cur;
2285 0           cur->next = next;
2286              
2287 0 0         if (next && ((u8 *)cur + cur->size) == (u8 *)next) {
    0          
2288             /* merge cur to higher chunk */
2289 0           cur->size += next->size;
2290 0           cur->next = next->next;
2291             }
2292 0 0         if (prev && ((u8 *)prev + prev->size) == (u8 *)cur) {
    0          
2293             /* merge cur to lower chunk */
2294 0           prev->size += cur->size;
2295 0           prev->next = cur->next;
2296             }
2297 0           }
2298              
2299 0           static void *pool_realloc(void *ctx_ptr, void *ptr,
2300             usize old_size, usize size) {
2301             /* assert(ptr != NULL && size != 0 && old_size < size) */
2302 0           pool_ctx *ctx = (pool_ctx *)ctx_ptr;
2303 0           pool_chunk *cur = ((pool_chunk *)ptr) - 1, *prev, *next, *tmp;
2304              
2305             /* check size */
2306 0 0         if (unlikely(size >= ctx->size)) return NULL;
2307             pool_size_align(&old_size);
2308             pool_size_align(&size);
2309 0 0         if (unlikely(old_size == size)) return ptr;
2310              
2311             /* find next and prev chunk */
2312 0           prev = NULL;
2313 0           next = ctx->free_list;
2314 0 0         while (next && next < cur) {
    0          
2315 0           prev = next;
2316 0           next = next->next;
2317             }
2318              
2319 0 0         if ((u8 *)cur + cur->size == (u8 *)next && cur->size + next->size >= size) {
    0          
2320             /* merge to higher chunk if they are contiguous */
2321 0           usize free_size = cur->size + next->size - size;
2322 0 0         if (free_size > sizeof(pool_chunk) * 2) {
2323 0           tmp = (pool_chunk *)(void *)((u8 *)cur + size);
2324 0 0         if (prev) prev->next = tmp;
2325 0           else ctx->free_list = tmp;
2326 0           tmp->next = next->next;
2327 0           tmp->size = free_size;
2328 0           cur->size = size;
2329             } else {
2330 0 0         if (prev) prev->next = next->next;
2331 0           else ctx->free_list = next->next;
2332 0           cur->size += next->size;
2333             }
2334 0           return ptr;
2335             } else {
2336             /* fallback to malloc and memcpy */
2337 0           void *new_ptr = pool_malloc(ctx_ptr, size - sizeof(pool_chunk));
2338 0 0         if (new_ptr) {
2339 0           memcpy(new_ptr, ptr, cur->size - sizeof(pool_chunk));
2340 0           pool_free(ctx_ptr, ptr);
2341             }
2342 0           return new_ptr;
2343             }
2344             }
2345              
2346 0           bool yyjson_alc_pool_init(yyjson_alc *alc, void *buf, usize size) {
2347             pool_chunk *chunk;
2348             pool_ctx *ctx;
2349              
2350 0 0         if (unlikely(!alc)) return false;
2351 0           *alc = YYJSON_NULL_ALC;
2352 0 0         if (size < sizeof(pool_ctx) * 4) return false;
2353 0           ctx = (pool_ctx *)mem_align_up(buf, sizeof(pool_ctx));
2354 0 0         if (unlikely(!ctx)) return false;
2355 0           size -= (usize)((u8 *)ctx - (u8 *)buf);
2356 0           size = size_align_down(size, sizeof(pool_ctx));
2357              
2358 0           chunk = (pool_chunk *)(ctx + 1);
2359 0           chunk->size = size - sizeof(pool_ctx);
2360 0           chunk->next = NULL;
2361 0           ctx->size = size;
2362 0           ctx->free_list = chunk;
2363              
2364 0           alc->malloc = pool_malloc;
2365 0           alc->realloc = pool_realloc;
2366 0           alc->free = pool_free;
2367 0           alc->ctx = (void *)ctx;
2368 0           return true;
2369             }
2370              
2371              
2372              
2373             /*==============================================================================
2374             * MARK: - Dynamic Memory Allocator (Public)
2375             * This allocator allocates memory on demand and does not immediately release
2376             * unused memory. Instead, it places the unused memory into a freelist for
2377             * potential reuse in the future. It is only when the entire allocator is
2378             * destroyed that all previously allocated memory is released at once.
2379             *============================================================================*/
2380              
2381             /** memory chunk header */
2382             typedef struct dyn_chunk {
2383             usize size; /* chunk size, include header */
2384             struct dyn_chunk *next;
2385             /* char mem[]; flexible array member */
2386             } dyn_chunk;
2387              
2388             /** allocator ctx header */
2389             typedef struct {
2390             dyn_chunk free_list; /* dummy header, sorted from small to large */
2391             dyn_chunk used_list; /* dummy header */
2392             } dyn_ctx;
2393              
2394             /** align up the input size to chunk size */
2395             static_inline bool dyn_size_align(usize *size) {
2396 0           usize alc_size = *size + sizeof(dyn_chunk);
2397 0           alc_size = size_align_up(alc_size, YYJSON_ALC_DYN_MIN_SIZE);
2398 0 0         if (unlikely(alc_size < *size)) return false; /* overflow */
    0          
2399 0           *size = alc_size;
2400 0           return true;
2401             }
2402              
2403             /** remove a chunk from list (the chunk must already be in the list) */
2404             static_inline void dyn_chunk_list_remove(dyn_chunk *list, dyn_chunk *chunk) {
2405 0           dyn_chunk *prev = list, *cur;
2406 0 0         for (cur = prev->next; cur; cur = cur->next) {
    0          
2407 0 0         if (cur == chunk) {
    0          
2408 0           prev->next = cur->next;
2409 0           cur->next = NULL;
2410 0           return;
2411             }
2412 0           prev = cur;
2413             }
2414             }
2415              
2416             /** add a chunk to list header (the chunk must not be in the list) */
2417             static_inline void dyn_chunk_list_add(dyn_chunk *list, dyn_chunk *chunk) {
2418 0           chunk->next = list->next;
2419 0           list->next = chunk;
2420 0           }
2421              
2422 0           static void *dyn_malloc(void *ctx_ptr, usize size) {
2423             /* assert(size != 0) */
2424 0           const yyjson_alc def = YYJSON_DEFAULT_ALC;
2425 0           dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
2426             dyn_chunk *chunk, *prev;
2427 0 0         if (unlikely(!dyn_size_align(&size))) return NULL;
2428              
2429             /* freelist is empty, create new chunk */
2430 0 0         if (!ctx->free_list.next) {
2431 0           chunk = (dyn_chunk *)def.malloc(def.ctx, size);
2432 0 0         if (unlikely(!chunk)) return NULL;
2433 0           chunk->size = size;
2434 0           chunk->next = NULL;
2435 0           dyn_chunk_list_add(&ctx->used_list, chunk);
2436 0           return (void *)(chunk + 1);
2437             }
2438              
2439             /* find a large enough chunk, or resize the largest chunk */
2440 0           prev = &ctx->free_list;
2441             while (true) {
2442 0           chunk = prev->next;
2443 0 0         if (chunk->size >= size) { /* enough size, reuse this chunk */
2444 0           prev->next = chunk->next;
2445 0           dyn_chunk_list_add(&ctx->used_list, chunk);
2446 0           return (void *)(chunk + 1);
2447             }
2448 0 0         if (!chunk->next) { /* resize the largest chunk */
2449 0           chunk = (dyn_chunk *)def.realloc(def.ctx, chunk, chunk->size, size);
2450 0 0         if (unlikely(!chunk)) return NULL;
2451 0           prev->next = NULL;
2452 0           chunk->size = size;
2453 0           dyn_chunk_list_add(&ctx->used_list, chunk);
2454 0           return (void *)(chunk + 1);
2455             }
2456 0           prev = chunk;
2457             }
2458             }
2459              
2460 0           static void *dyn_realloc(void *ctx_ptr, void *ptr,
2461             usize old_size, usize size) {
2462             /* assert(ptr != NULL && size != 0 && old_size < size) */
2463 0           const yyjson_alc def = YYJSON_DEFAULT_ALC;
2464 0           dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
2465 0           dyn_chunk *new_chunk, *chunk = (dyn_chunk *)ptr - 1;
2466 0 0         if (unlikely(!dyn_size_align(&size))) return NULL;
2467 0 0         if (chunk->size >= size) return ptr;
2468              
2469 0           dyn_chunk_list_remove(&ctx->used_list, chunk);
2470 0           new_chunk = (dyn_chunk *)def.realloc(def.ctx, chunk, chunk->size, size);
2471 0 0         if (likely(new_chunk)) {
2472 0           new_chunk->size = size;
2473 0           chunk = new_chunk;
2474             }
2475 0           dyn_chunk_list_add(&ctx->used_list, chunk);
2476 0 0         return new_chunk ? (void *)(new_chunk + 1) : NULL;
2477             }
2478              
2479 0           static void dyn_free(void *ctx_ptr, void *ptr) {
2480             /* assert(ptr != NULL) */
2481 0           dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
2482 0           dyn_chunk *chunk = (dyn_chunk *)ptr - 1, *prev;
2483              
2484 0           dyn_chunk_list_remove(&ctx->used_list, chunk);
2485 0 0         for (prev = &ctx->free_list; prev; prev = prev->next) {
2486 0 0         if (!prev->next || prev->next->size >= chunk->size) {
    0          
2487 0           chunk->next = prev->next;
2488 0           prev->next = chunk;
2489 0           break;
2490             }
2491             }
2492 0           }
2493              
2494 0           yyjson_alc *yyjson_alc_dyn_new(void) {
2495 0           const yyjson_alc def = YYJSON_DEFAULT_ALC;
2496 0           usize hdr_len = sizeof(yyjson_alc) + sizeof(dyn_ctx);
2497 0           yyjson_alc *alc = (yyjson_alc *)def.malloc(def.ctx, hdr_len);
2498 0           dyn_ctx *ctx = (dyn_ctx *)(void *)(alc + 1);
2499 0 0         if (unlikely(!alc)) return NULL;
2500 0           alc->malloc = dyn_malloc;
2501 0           alc->realloc = dyn_realloc;
2502 0           alc->free = dyn_free;
2503 0           alc->ctx = alc + 1;
2504 0           memset(ctx, 0, sizeof(*ctx));
2505 0           return alc;
2506             }
2507              
2508 0           void yyjson_alc_dyn_free(yyjson_alc *alc) {
2509 0           const yyjson_alc def = YYJSON_DEFAULT_ALC;
2510 0           dyn_ctx *ctx = (dyn_ctx *)(void *)(alc + 1);
2511             dyn_chunk *chunk, *next;
2512 0 0         if (unlikely(!alc)) return;
2513 0 0         for (chunk = ctx->free_list.next; chunk; chunk = next) {
2514 0           next = chunk->next;
2515 0           def.free(def.ctx, chunk);
2516             }
2517 0 0         for (chunk = ctx->used_list.next; chunk; chunk = next) {
2518 0           next = chunk->next;
2519 0           def.free(def.ctx, chunk);
2520             }
2521 0           def.free(def.ctx, alc);
2522             }
2523              
2524              
2525              
2526             /*==============================================================================
2527             * MARK: - JSON Struct Utils (Public)
2528             * These functions are used for creating, copying, releasing, and comparing
2529             * JSON documents and values. They are widely used throughout this library.
2530             *============================================================================*/
2531              
2532             static_inline void unsafe_yyjson_str_pool_release(yyjson_str_pool *pool,
2533             yyjson_alc *alc) {
2534 20112           yyjson_str_chunk *chunk = pool->chunks, *next;
2535 35203 100         while (chunk) {
2536 15091           next = chunk->next;
2537 15091           alc->free(alc->ctx, chunk);
2538 15091           chunk = next;
2539             }
2540 20112           }
2541              
2542             static_inline void unsafe_yyjson_val_pool_release(yyjson_val_pool *pool,
2543             yyjson_alc *alc) {
2544 20112           yyjson_val_chunk *chunk = pool->chunks, *next;
2545 40225 100         while (chunk) {
2546 20113           next = chunk->next;
2547 20113           alc->free(alc->ctx, chunk);
2548 20113           chunk = next;
2549             }
2550 20112           }
2551              
2552 15091           bool unsafe_yyjson_str_pool_grow(yyjson_str_pool *pool,
2553             const yyjson_alc *alc, usize len) {
2554             yyjson_str_chunk *chunk;
2555             usize size, max_len;
2556              
2557             /* create a new chunk */
2558 15091           max_len = USIZE_MAX - sizeof(yyjson_str_chunk);
2559 15091 50         if (unlikely(len > max_len)) return false;
2560 15091           size = len + sizeof(yyjson_str_chunk);
2561 15091           size = yyjson_max(pool->chunk_size, size);
2562 15091           chunk = (yyjson_str_chunk *)alc->malloc(alc->ctx, size);
2563 15091 50         if (unlikely(!chunk)) return false;
2564              
2565             /* insert the new chunk as the head of the linked list */
2566 15091           chunk->next = pool->chunks;
2567 15091           chunk->chunk_size = size;
2568 15091           pool->chunks = chunk;
2569 15091           pool->cur = (char *)chunk + sizeof(yyjson_str_chunk);
2570 15091           pool->end = (char *)chunk + size;
2571              
2572             /* the next chunk is twice the size of the current one */
2573 15091           size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max);
2574 15091 50         if (size < pool->chunk_size) size = pool->chunk_size_max; /* overflow */
2575 15091           pool->chunk_size = size;
2576 15091           return true;
2577             }
2578              
2579 20113           bool unsafe_yyjson_val_pool_grow(yyjson_val_pool *pool,
2580             const yyjson_alc *alc, usize count) {
2581             yyjson_val_chunk *chunk;
2582             usize size, max_count;
2583              
2584             /* create a new chunk */
2585 20113           max_count = USIZE_MAX / sizeof(yyjson_mut_val) - 1;
2586 20113 50         if (unlikely(count > max_count)) return false;
2587 20113           size = (count + 1) * sizeof(yyjson_mut_val);
2588 20113           size = yyjson_max(pool->chunk_size, size);
2589 20113           chunk = (yyjson_val_chunk *)alc->malloc(alc->ctx, size);
2590 20113 50         if (unlikely(!chunk)) return false;
2591              
2592             /* insert the new chunk as the head of the linked list */
2593 20113           chunk->next = pool->chunks;
2594 20113           chunk->chunk_size = size;
2595 20113           pool->chunks = chunk;
2596 20113           pool->cur = (yyjson_mut_val *)(void *)((u8 *)chunk) + 1;
2597 20113           pool->end = (yyjson_mut_val *)(void *)((u8 *)chunk + size);
2598              
2599             /* the next chunk is twice the size of the current one */
2600 20113           size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max);
2601 20113 50         if (size < pool->chunk_size) size = pool->chunk_size_max; /* overflow */
2602 20113           pool->chunk_size = size;
2603 20113           return true;
2604             }
2605              
2606 0           bool yyjson_mut_doc_set_str_pool_size(yyjson_mut_doc *doc, size_t len) {
2607 0           usize max_size = USIZE_MAX - sizeof(yyjson_str_chunk);
2608 0 0         if (!doc || !len || len > max_size) return false;
    0          
    0          
2609 0           doc->str_pool.chunk_size = len + sizeof(yyjson_str_chunk);
2610 0           return true;
2611             }
2612              
2613 0           bool yyjson_mut_doc_set_val_pool_size(yyjson_mut_doc *doc, size_t count) {
2614 0           usize max_count = USIZE_MAX / sizeof(yyjson_mut_val) - 1;
2615 0 0         if (!doc || !count || count > max_count) return false;
    0          
    0          
2616 0           doc->val_pool.chunk_size = (count + 1) * sizeof(yyjson_mut_val);
2617 0           return true;
2618             }
2619              
2620 20112           void yyjson_mut_doc_free(yyjson_mut_doc *doc) {
2621 20112 50         if (doc) {
2622 20112           yyjson_alc alc = doc->alc;
2623 20112           memset(&doc->alc, 0, sizeof(alc));
2624 20112           unsafe_yyjson_str_pool_release(&doc->str_pool, &alc);
2625 20112           unsafe_yyjson_val_pool_release(&doc->val_pool, &alc);
2626 20112           alc.free(alc.ctx, doc);
2627             }
2628 20112           }
2629              
2630 20112           yyjson_mut_doc *yyjson_mut_doc_new(const yyjson_alc *alc) {
2631             yyjson_mut_doc *doc;
2632 20112 50         if (!alc) alc = &YYJSON_DEFAULT_ALC;
2633 20112           doc = (yyjson_mut_doc *)alc->malloc(alc->ctx, sizeof(yyjson_mut_doc));
2634 20112 50         if (!doc) return NULL;
2635 20112           memset(doc, 0, sizeof(yyjson_mut_doc));
2636              
2637 20112           doc->alc = *alc;
2638 20112           doc->str_pool.chunk_size = YYJSON_MUT_DOC_STR_POOL_INIT_SIZE;
2639 20112           doc->str_pool.chunk_size_max = YYJSON_MUT_DOC_STR_POOL_MAX_SIZE;
2640 20112           doc->val_pool.chunk_size = YYJSON_MUT_DOC_VAL_POOL_INIT_SIZE;
2641 20112           doc->val_pool.chunk_size_max = YYJSON_MUT_DOC_VAL_POOL_MAX_SIZE;
2642 20112           return doc;
2643             }
2644              
2645 10074           yyjson_mut_doc *yyjson_doc_mut_copy(yyjson_doc *doc, const yyjson_alc *alc) {
2646             yyjson_mut_doc *m_doc;
2647             yyjson_mut_val *m_val;
2648              
2649 10074 50         if (!doc || !doc->root) return NULL;
    50          
2650 10074           m_doc = yyjson_mut_doc_new(alc);
2651 10074 50         if (!m_doc) return NULL;
2652 10074           m_val = yyjson_val_mut_copy(m_doc, doc->root);
2653 10074 50         if (!m_val) {
2654 0           yyjson_mut_doc_free(m_doc);
2655 0           return NULL;
2656             }
2657             yyjson_mut_doc_set_root(m_doc, m_val);
2658 10074           return m_doc;
2659             }
2660              
2661 0           yyjson_mut_doc *yyjson_mut_doc_mut_copy(yyjson_mut_doc *doc,
2662             const yyjson_alc *alc) {
2663             yyjson_mut_doc *m_doc;
2664             yyjson_mut_val *m_val;
2665              
2666 0 0         if (!doc) return NULL;
2667 0 0         if (!doc->root) return yyjson_mut_doc_new(alc);
2668              
2669 0           m_doc = yyjson_mut_doc_new(alc);
2670 0 0         if (!m_doc) return NULL;
2671 0           m_val = yyjson_mut_val_mut_copy(m_doc, doc->root);
2672 0 0         if (!m_val) {
2673 0           yyjson_mut_doc_free(m_doc);
2674 0           return NULL;
2675             }
2676             yyjson_mut_doc_set_root(m_doc, m_val);
2677 0           return m_doc;
2678             }
2679              
2680 10078           yyjson_mut_val *yyjson_val_mut_copy(yyjson_mut_doc *m_doc,
2681             yyjson_val *i_vals) {
2682             /*
2683             The immutable object or array stores all sub-values in a contiguous memory,
2684             We copy them to another contiguous memory as mutable values,
2685             then reconnect the mutable values with the original relationship.
2686             */
2687             usize i_vals_len;
2688             yyjson_mut_val *m_vals, *m_val;
2689             yyjson_val *i_val, *i_end;
2690              
2691 10078 50         if (!m_doc || !i_vals) return NULL;
    50          
2692 10078           i_end = unsafe_yyjson_get_next(i_vals);
2693 10078 100         i_vals_len = (usize)(unsafe_yyjson_get_next(i_vals) - i_vals);
2694 10078           m_vals = unsafe_yyjson_mut_val(m_doc, i_vals_len);
2695 10078 50         if (!m_vals) return NULL;
2696 10078           i_val = i_vals;
2697 10078           m_val = m_vals;
2698              
2699 55624 100         for (; i_val < i_end; i_val++, m_val++) {
2700 45546           yyjson_type type = unsafe_yyjson_get_type(i_val);
2701 45546           m_val->tag = i_val->tag;
2702 45546           m_val->uni.u64 = i_val->uni.u64;
2703 57728 100         if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
    50          
2704 12182           const char *str = i_val->uni.str;
2705 12182 100         usize str_len = unsafe_yyjson_get_len(i_val);
2706 12182           m_val->uni.str = unsafe_yyjson_mut_strncpy(m_doc, str, str_len);
2707 12182 50         if (!m_val->uni.str) return NULL;
2708 33364 100         } else if (type == YYJSON_TYPE_ARR) {
2709 141           usize len = unsafe_yyjson_get_len(i_val);
2710 141 100         if (len > 0) {
2711 138           yyjson_val *ii_val = i_val + 1, *ii_next;
2712 138           yyjson_mut_val *mm_val = m_val + 1, *mm_ctn = m_val, *mm_next;
2713 11182 100         while (len-- > 1) {
2714 11044           ii_next = unsafe_yyjson_get_next(ii_val);
2715 11044           mm_next = mm_val + (ii_next - ii_val);
2716 11044           mm_val->next = mm_next;
2717 11044           ii_val = ii_next;
2718 11044           mm_val = mm_next;
2719             }
2720 138           mm_val->next = mm_ctn + 1;
2721 138           mm_ctn->uni.ptr = mm_val;
2722             }
2723 33223 100         } else if (type == YYJSON_TYPE_OBJ) {
2724 11090           usize len = unsafe_yyjson_get_len(i_val);
2725 11090 100         if (len > 0) {
2726 11084           yyjson_val *ii_key = i_val + 1, *ii_nextkey;
2727 11084           yyjson_mut_val *mm_key = m_val + 1, *mm_ctn = m_val;
2728             yyjson_mut_val *mm_nextkey;
2729 12143 100         while (len-- > 1) {
2730 1059           ii_nextkey = unsafe_yyjson_get_next(ii_key + 1);
2731 1059           mm_nextkey = mm_key + (ii_nextkey - ii_key);
2732 1059           mm_key->next = mm_key + 1;
2733 1059           mm_key->next->next = mm_nextkey;
2734 1059           ii_key = ii_nextkey;
2735 1059           mm_key = mm_nextkey;
2736             }
2737 11084           mm_key->next = mm_key + 1;
2738 11084           mm_key->next->next = mm_ctn + 1;
2739 11084           mm_ctn->uni.ptr = mm_key;
2740             }
2741             }
2742             }
2743 10078           return m_vals;
2744             }
2745              
2746 20083 100         static yyjson_mut_val *unsafe_yyjson_mut_val_mut_copy(yyjson_mut_doc *m_doc,
2747             yyjson_mut_val *m_vals) {
2748             /*
2749             The mutable object or array stores all sub-values in a circular linked
2750             list, so we can traverse them in the same loop. The traversal starts from
2751             the last item, continues with the first item in a list, and ends with the
2752             second to last item, which needs to be linked to the last item to close the
2753             circle.
2754             */
2755 20083           yyjson_mut_val *m_val = unsafe_yyjson_mut_val(m_doc, 1);
2756 20083 50         if (unlikely(!m_val)) return NULL;
2757 20083           m_val->tag = m_vals->tag;
2758              
2759 20083           switch (unsafe_yyjson_get_type(m_vals)) {
2760 5020           case YYJSON_TYPE_OBJ:
2761             case YYJSON_TYPE_ARR:
2762 5020 100         if (unsafe_yyjson_get_len(m_vals) > 0) {
2763 5017           yyjson_mut_val *last = (yyjson_mut_val *)m_vals->uni.ptr;
2764 5017           yyjson_mut_val *next = last->next, *prev;
2765 5017           prev = unsafe_yyjson_mut_val_mut_copy(m_doc, last);
2766 5017 50         if (!prev) return NULL;
2767 5017           m_val->uni.ptr = (void *)prev;
2768 15046 100         while (next != last) {
2769 10029           prev->next = unsafe_yyjson_mut_val_mut_copy(m_doc, next);
2770 10029 50         if (!prev->next) return NULL;
2771 10029           prev = prev->next;
2772 10029           next = next->next;
2773             }
2774 5017           prev->next = (yyjson_mut_val *)m_val->uni.ptr;
2775             }
2776 5020           break;
2777 27           case YYJSON_TYPE_RAW:
2778             case YYJSON_TYPE_STR: {
2779 27           const char *str = m_vals->uni.str;
2780 27 100         usize str_len = unsafe_yyjson_get_len(m_vals);
2781 27           m_val->uni.str = unsafe_yyjson_mut_strncpy(m_doc, str, str_len);
2782 27 50         if (!m_val->uni.str) return NULL;
2783 27           break;
2784             }
2785 15036           default:
2786 15036           m_val->uni = m_vals->uni;
2787 15036           break;
2788             }
2789 20083           return m_val;
2790             }
2791              
2792 5037           yyjson_mut_val *yyjson_mut_val_mut_copy(yyjson_mut_doc *doc,
2793             yyjson_mut_val *val) {
2794 5037 50         if (doc && val) return unsafe_yyjson_mut_val_mut_copy(doc, val);
    50          
2795 0           return NULL;
2796             }
2797              
2798             /* Count the number of values and the total length of the strings. */
2799 0           static void yyjson_mut_stat(yyjson_mut_val *val,
2800             usize *val_sum, usize *str_sum) {
2801 0           yyjson_type type = unsafe_yyjson_get_type(val);
2802 0           *val_sum += 1;
2803 0 0         if (type == YYJSON_TYPE_ARR || type == YYJSON_TYPE_OBJ) {
    0          
2804 0           yyjson_mut_val *child = (yyjson_mut_val *)val->uni.ptr;
2805 0           usize len = unsafe_yyjson_get_len(val), i;
2806 0           len <<= (u8)(type == YYJSON_TYPE_OBJ);
2807 0           *val_sum += len;
2808 0 0         for (i = 0; i < len; i++) {
2809 0           yyjson_type stype = unsafe_yyjson_get_type(child);
2810 0 0         if (stype == YYJSON_TYPE_STR || stype == YYJSON_TYPE_RAW) {
    0          
2811 0           *str_sum += unsafe_yyjson_get_len(child) + 1;
2812 0 0         } else if (stype == YYJSON_TYPE_ARR || stype == YYJSON_TYPE_OBJ) {
    0          
2813 0           yyjson_mut_stat(child, val_sum, str_sum);
2814 0           *val_sum -= 1;
2815             }
2816 0           child = child->next;
2817             }
2818 0 0         } else if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
    0          
2819 0           *str_sum += unsafe_yyjson_get_len(val) + 1;
2820             }
2821 0           }
2822              
2823             /* Copy mutable values to immutable value pool. */
2824 0           static usize yyjson_imut_copy(yyjson_val **val_ptr, char **buf_ptr,
2825             yyjson_mut_val *mval) {
2826 0           yyjson_val *val = *val_ptr;
2827 0           yyjson_type type = unsafe_yyjson_get_type(mval);
2828 0 0         if (type == YYJSON_TYPE_ARR || type == YYJSON_TYPE_OBJ) {
    0          
2829 0           yyjson_mut_val *child = (yyjson_mut_val *)mval->uni.ptr;
2830 0           usize len = unsafe_yyjson_get_len(mval), i;
2831 0           usize val_sum = 1;
2832 0 0         if (type == YYJSON_TYPE_OBJ) {
2833 0 0         if (len) child = child->next->next;
2834 0           len <<= 1;
2835             } else {
2836 0 0         if (len) child = child->next;
2837             }
2838 0           *val_ptr = val + 1;
2839 0 0         for (i = 0; i < len; i++) {
2840 0           val_sum += yyjson_imut_copy(val_ptr, buf_ptr, child);
2841 0           child = child->next;
2842             }
2843 0           val->tag = mval->tag;
2844 0           val->uni.ofs = val_sum * sizeof(yyjson_val);
2845 0           return val_sum;
2846 0 0         } else if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
    0          
2847 0           char *buf = *buf_ptr;
2848 0           usize len = unsafe_yyjson_get_len(mval);
2849 0           memcpy((void *)buf, (const void *)mval->uni.str, len);
2850 0           buf[len] = '\0';
2851 0           val->tag = mval->tag;
2852 0           val->uni.str = buf;
2853 0           *val_ptr = val + 1;
2854 0           *buf_ptr = buf + len + 1;
2855 0           return 1;
2856             } else {
2857 0           val->tag = mval->tag;
2858 0           val->uni = mval->uni;
2859 0           *val_ptr = val + 1;
2860 0           return 1;
2861             }
2862             }
2863              
2864 0           yyjson_doc *yyjson_mut_doc_imut_copy(yyjson_mut_doc *mdoc,
2865             const yyjson_alc *alc) {
2866 0 0         if (!mdoc) return NULL;
2867 0           return yyjson_mut_val_imut_copy(mdoc->root, alc);
2868             }
2869              
2870 0           yyjson_doc *yyjson_mut_val_imut_copy(yyjson_mut_val *mval,
2871             const yyjson_alc *alc) {
2872 0           usize val_num = 0, str_sum = 0, hdr_size, buf_size;
2873 0           yyjson_doc *doc = NULL;
2874 0           yyjson_val *val_hdr = NULL;
2875              
2876             /* This value should be NULL here. Setting a non-null value suppresses
2877             warning from the clang analyzer. */
2878 0           char *str_hdr = (char *)(void *)&str_sum;
2879 0 0         if (!mval) return NULL;
2880 0 0         if (!alc) alc = &YYJSON_DEFAULT_ALC;
2881              
2882             /* traverse the input value to get pool size */
2883 0           yyjson_mut_stat(mval, &val_num, &str_sum);
2884              
2885             /* create doc and val pool */
2886 0           hdr_size = size_align_up(sizeof(yyjson_doc), sizeof(yyjson_val));
2887 0           buf_size = hdr_size + val_num * sizeof(yyjson_val);
2888 0           doc = (yyjson_doc *)alc->malloc(alc->ctx, buf_size);
2889 0 0         if (!doc) return NULL;
2890 0           memset(doc, 0, sizeof(yyjson_doc));
2891 0           val_hdr = (yyjson_val *)(void *)((char *)(void *)doc + hdr_size);
2892 0           doc->root = val_hdr;
2893 0           doc->alc = *alc;
2894              
2895             /* create str pool */
2896 0 0         if (str_sum > 0) {
2897 0           str_hdr = (char *)alc->malloc(alc->ctx, str_sum);
2898 0           doc->str_pool = str_hdr;
2899 0 0         if (!str_hdr) {
2900 0           alc->free(alc->ctx, (void *)doc);
2901 0           return NULL;
2902             }
2903             }
2904              
2905             /* copy vals and strs */
2906 0           doc->val_read = yyjson_imut_copy(&val_hdr, &str_hdr, mval);
2907 0           doc->dat_read = str_sum + 1;
2908 0           return doc;
2909             }
2910              
2911             static_inline bool unsafe_yyjson_num_equals(void *lhs, void *rhs) {
2912 11           yyjson_val_uni *luni = &((yyjson_val *)lhs)->uni;
2913 11           yyjson_val_uni *runi = &((yyjson_val *)rhs)->uni;
2914 11           yyjson_subtype lt = unsafe_yyjson_get_subtype(lhs);
2915 11           yyjson_subtype rt = unsafe_yyjson_get_subtype(rhs);
2916 11 50         if (lt == rt) return luni->u64 == runi->u64;
    0          
2917 0 0         if (lt == YYJSON_SUBTYPE_SINT && rt == YYJSON_SUBTYPE_UINT) {
    0          
    0          
    0          
2918 0 0         return luni->i64 >= 0 && luni->u64 == runi->u64;
    0          
    0          
    0          
2919             }
2920 0 0         if (lt == YYJSON_SUBTYPE_UINT && rt == YYJSON_SUBTYPE_SINT) {
    0          
    0          
    0          
2921 0 0         return runi->i64 >= 0 && luni->u64 == runi->u64;
    0          
    0          
    0          
2922             }
2923 0           return false;
2924             }
2925              
2926             static_inline bool unsafe_yyjson_str_equals(void *lhs, void *rhs) {
2927 0           usize len = unsafe_yyjson_get_len(lhs);
2928 0 0         if (len != unsafe_yyjson_get_len(rhs)) return false;
    0          
2929 0           return !memcmp(unsafe_yyjson_get_str(lhs),
2930 0           unsafe_yyjson_get_str(rhs), len);
2931             }
2932              
2933 0           bool unsafe_yyjson_equals(yyjson_val *lhs, yyjson_val *rhs) {
2934 0           yyjson_type type = unsafe_yyjson_get_type(lhs);
2935 0 0         if (type != unsafe_yyjson_get_type(rhs)) return false;
2936              
2937 0           switch (type) {
2938 0           case YYJSON_TYPE_OBJ: {
2939 0           usize len = unsafe_yyjson_get_len(lhs);
2940 0 0         if (len != unsafe_yyjson_get_len(rhs)) return false;
2941 0 0         if (len > 0) {
2942             yyjson_obj_iter iter;
2943             yyjson_obj_iter_init(rhs, &iter);
2944 0           lhs = unsafe_yyjson_get_first(lhs);
2945 0 0         while (len-- > 0) {
2946 0 0         rhs = yyjson_obj_iter_getn(&iter, lhs->uni.str,
2947             unsafe_yyjson_get_len(lhs));
2948 0 0         if (!rhs) return false;
2949 0 0         if (!unsafe_yyjson_equals(lhs + 1, rhs)) return false;
2950 0           lhs = unsafe_yyjson_get_next(lhs + 1);
2951             }
2952             }
2953             /* yyjson allows duplicate keys, so the check may be inaccurate */
2954 0           return true;
2955             }
2956              
2957 0           case YYJSON_TYPE_ARR: {
2958 0           usize len = unsafe_yyjson_get_len(lhs);
2959 0 0         if (len != unsafe_yyjson_get_len(rhs)) return false;
2960 0 0         if (len > 0) {
2961 0           lhs = unsafe_yyjson_get_first(lhs);
2962 0           rhs = unsafe_yyjson_get_first(rhs);
2963 0 0         while (len-- > 0) {
2964 0 0         if (!unsafe_yyjson_equals(lhs, rhs)) return false;
2965 0           lhs = unsafe_yyjson_get_next(lhs);
2966 0           rhs = unsafe_yyjson_get_next(rhs);
2967             }
2968             }
2969 0           return true;
2970             }
2971              
2972 0           case YYJSON_TYPE_NUM:
2973 0           return unsafe_yyjson_num_equals(lhs, rhs);
2974              
2975 0           case YYJSON_TYPE_RAW:
2976             case YYJSON_TYPE_STR:
2977 0           return unsafe_yyjson_str_equals(lhs, rhs);
2978              
2979 0           case YYJSON_TYPE_NULL:
2980             case YYJSON_TYPE_BOOL:
2981 0           return lhs->tag == rhs->tag;
2982              
2983 0           default:
2984 0           return false;
2985             }
2986             }
2987              
2988 21           bool unsafe_yyjson_mut_equals(yyjson_mut_val *lhs, yyjson_mut_val *rhs) {
2989 21           yyjson_type type = unsafe_yyjson_get_type(lhs);
2990 21 50         if (type != unsafe_yyjson_get_type(rhs)) return false;
2991              
2992 21           switch (type) {
2993 3           case YYJSON_TYPE_OBJ: {
2994 3           usize len = unsafe_yyjson_get_len(lhs);
2995 3 50         if (len != unsafe_yyjson_get_len(rhs)) return false;
2996 3 50         if (len > 0) {
2997             yyjson_mut_obj_iter iter;
2998             yyjson_mut_obj_iter_init(rhs, &iter);
2999 3           lhs = (yyjson_mut_val *)lhs->uni.ptr;
3000 6 100         while (len-- > 0) {
3001 4 50         rhs = yyjson_mut_obj_iter_getn(&iter, lhs->uni.str,
3002             unsafe_yyjson_get_len(lhs));
3003 5 50         if (!rhs) return false;
3004 4 100         if (!unsafe_yyjson_mut_equals(lhs->next, rhs)) return false;
3005 3           lhs = lhs->next->next;
3006             }
3007             }
3008             /* yyjson allows duplicate keys, so the check may be inaccurate */
3009 2           return true;
3010             }
3011              
3012 5           case YYJSON_TYPE_ARR: {
3013 5           usize len = unsafe_yyjson_get_len(lhs);
3014 5 50         if (len != unsafe_yyjson_get_len(rhs)) return false;
3015 5 50         if (len > 0) {
3016 5           lhs = (yyjson_mut_val *)lhs->uni.ptr;
3017 5           rhs = (yyjson_mut_val *)rhs->uni.ptr;
3018 13 100         while (len-- > 0) {
3019 10 100         if (!unsafe_yyjson_mut_equals(lhs, rhs)) return false;
3020 8           lhs = lhs->next;
3021 8           rhs = rhs->next;
3022             }
3023             }
3024 3           return true;
3025             }
3026              
3027 11           case YYJSON_TYPE_NUM:
3028 11           return unsafe_yyjson_num_equals(lhs, rhs);
3029              
3030 0           case YYJSON_TYPE_RAW:
3031             case YYJSON_TYPE_STR:
3032 0           return unsafe_yyjson_str_equals(lhs, rhs);
3033              
3034 2           case YYJSON_TYPE_NULL:
3035             case YYJSON_TYPE_BOOL:
3036 2           return lhs->tag == rhs->tag;
3037              
3038 0           default:
3039 0           return false;
3040             }
3041             }
3042              
3043 0           bool yyjson_locate_pos(const char *str, size_t len, size_t pos,
3044             size_t *line, size_t *col, size_t *chr) {
3045 0           usize line_sum = 0, line_pos = 0, chr_sum = 0;
3046 0           const u8 *cur = (const u8 *)str;
3047 0           const u8 *end = cur + pos;
3048              
3049 0 0         if (!str || pos > len) {
    0          
3050 0 0         if (line) *line = 0;
3051 0 0         if (col) *col = 0;
3052 0 0         if (chr) *chr = 0;
3053 0           return false;
3054             }
3055              
3056 0 0         if (pos >= 3 && is_utf8_bom(cur)) cur += 3; /* don't count BOM */
    0          
3057 0 0         while (cur < end) {
3058 0           u8 c = *cur;
3059 0           chr_sum += 1;
3060 0 0         if (likely(c < 0x80)) { /* 0xxxxxxx (0x00-0x7F) ASCII */
3061 0 0         if (c == '\n') {
3062 0           line_sum += 1;
3063 0           line_pos = chr_sum;
3064             }
3065 0           cur += 1;
3066             }
3067 0 0         else if (c < 0xC0) cur += 1; /* 10xxxxxx (0x80-0xBF) Invalid */
3068 0 0         else if (c < 0xE0) cur += 2; /* 110xxxxx (0xC0-0xDF) 2-byte UTF-8 */
3069 0 0         else if (c < 0xF0) cur += 3; /* 1110xxxx (0xE0-0xEF) 3-byte UTF-8 */
3070 0 0         else if (c < 0xF8) cur += 4; /* 11110xxx (0xF0-0xF7) 4-byte UTF-8 */
3071 0           else cur += 1; /* 11111xxx (0xF8-0xFF) Invalid */
3072             }
3073 0 0         if (line) *line = line_sum + 1;
3074 0 0         if (col) *col = chr_sum - line_pos + 1;
3075 0 0         if (chr) *chr = chr_sum;
3076 0           return true;
3077             }
3078              
3079              
3080              
3081             #if !YYJSON_DISABLE_READER /* reader begin */
3082              
3083             /* Check read flag, avoids `always false` warning when disabled. */
3084             #define has_flg(_flg) unlikely(has_rflag(flg, YYJSON_READ_##_flg, 0))
3085             #define has_allow(_flg) unlikely(has_rflag(flg, YYJSON_READ_ALLOW_##_flg, 1))
3086             #define YYJSON_READ_ALLOW_TRIVIA (YYJSON_READ_ALLOW_COMMENTS | \
3087             YYJSON_READ_ALLOW_EXT_WHITESPACE)
3088             static_inline bool has_rflag(yyjson_read_flag flg, yyjson_read_flag chk,
3089             bool non_standard) {
3090             #if YYJSON_DISABLE_NON_STANDARD
3091             if (non_standard) return false;
3092             #endif
3093 74635           return (flg & chk) != 0;
3094             }
3095              
3096              
3097              
3098             /*==============================================================================
3099             * MARK: - JSON Reader Utils (Private)
3100             * These functions are used by JSON reader to read literals and comments.
3101             *============================================================================*/
3102              
3103             /** Read `true` literal, `*ptr[0]` should be `t`. */
3104             static_inline bool read_true(u8 **ptr, yyjson_val *val) {
3105 2           u8 *cur = *ptr;
3106 12 0         if (likely(byte_match_4(cur, "true"))) {
    0          
    0          
    50          
    0          
    50          
    50          
    50          
3107 12           val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_TRUE;
3108 12           *ptr = cur + 4;
3109 12           return true;
3110             }
3111 0           return false;
3112             }
3113              
3114             /** Read `false` literal, `*ptr[0]` should be `f`. */
3115             static_inline bool read_false(u8 **ptr, yyjson_val *val) {
3116 5           u8 *cur = *ptr;
3117 6 0         if (likely(byte_match_4(cur + 1, "alse"))) {
    0          
    0          
    0          
    0          
    50          
    50          
    50          
3118 5           val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_FALSE;
3119 5           *ptr = cur + 5;
3120 5           return true;
3121             }
3122 0           return false;
3123             }
3124              
3125             /** Read `null` literal, `*ptr[0]` should be `n`. */
3126             static_inline bool read_null(u8 **ptr, yyjson_val *val) {
3127 4           u8 *cur = *ptr;
3128 11 0         if (likely(byte_match_4(cur, "null"))) {
    0          
    0          
    50          
    0          
    50          
    50          
    100          
3129 8           val->tag = YYJSON_TYPE_NULL;
3130 8           *ptr = cur + 4;
3131 8           return true;
3132             }
3133 3           return false;
3134             }
3135              
3136             /** Read `Inf` or `Infinity` literal (ignoring case). */
3137             static_inline bool read_inf(u8 **ptr, u8 **pre,
3138             yyjson_read_flag flg, yyjson_val *val) {
3139 0           u8 *hdr = *ptr;
3140 0           u8 *cur = *ptr;
3141 0           u8 **end = ptr;
3142 0           bool sign = (*cur == '-');
3143 0 0         if (*cur == '+' && !has_allow(EXT_NUMBER)) return false;
    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          
3144 0           cur += char_is_sign(*cur);
3145 0 0         if (char_to_lower(cur[0]) == 'i' &&
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3146 0 0         char_to_lower(cur[1]) == 'n' &&
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3147 0 0         char_to_lower(cur[2]) == 'f') {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3148 0 0         if (char_to_lower(cur[3]) == 'i') {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3149 0 0         if (char_to_lower(cur[4]) == 'n' &&
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3150 0 0         char_to_lower(cur[5]) == 'i' &&
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3151 0 0         char_to_lower(cur[6]) == 't' &&
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3152 0 0         char_to_lower(cur[7]) == 'y') {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3153 0           cur += 8;
3154             } else {
3155 0           return false;
3156             }
3157             } else {
3158 0           cur += 3;
3159             }
3160 0           *end = cur;
3161 0 0         if (has_flg(NUMBER_AS_RAW)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3162 0           **pre = '\0'; /* add null-terminator for previous raw string */
3163 0           *pre = cur; /* save end position for current raw string */
3164 0           val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
3165 0           val->uni.str = (const char *)hdr;
3166             } else {
3167 0           val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
3168 0           val->uni.u64 = f64_bits_inf(sign);
3169             }
3170 0           return true;
3171             }
3172 0           return false;
3173             }
3174              
3175             /** Read `NaN` literal (ignoring case). */
3176             static_inline bool read_nan(u8 **ptr, u8 **pre,
3177             yyjson_read_flag flg, yyjson_val *val) {
3178 0           u8 *hdr = *ptr;
3179 0           u8 *cur = *ptr;
3180 0           u8 **end = ptr;
3181 0           bool sign = (*cur == '-');
3182 0 0         if (*cur == '+' && !has_allow(EXT_NUMBER)) return false;
    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          
3183 0           cur += char_is_sign(*cur);
3184 0 0         if (char_to_lower(cur[0]) == 'n' &&
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3185 0 0         char_to_lower(cur[1]) == 'a' &&
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3186 0 0         char_to_lower(cur[2]) == 'n') {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3187 0           cur += 3;
3188 0           *end = cur;
3189 0 0         if (has_flg(NUMBER_AS_RAW)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3190 0           **pre = '\0'; /* add null-terminator for previous raw string */
3191 0           *pre = cur; /* save end position for current raw string */
3192 0           val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
3193 0           val->uni.str = (const char *)hdr;
3194             } else {
3195 0           val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
3196 0           val->uni.u64 = f64_bits_nan(sign);
3197             }
3198 0           return true;
3199             }
3200 0           return false;
3201             }
3202              
3203             /** Read `Inf`, `Infinity` or `NaN` literal (ignoring case). */
3204             static_inline bool read_inf_or_nan(u8 **ptr, u8 **pre,
3205             yyjson_read_flag flg, yyjson_val *val) {
3206 0 0         if (read_inf(ptr, pre, flg, val)) return true;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3207 0 0         if (read_nan(ptr, pre, flg, val)) return true;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3208 0           return false;
3209             }
3210              
3211             /** Read a JSON number as raw string. */
3212 0           static_noinline bool read_num_raw(u8 **ptr, u8 **pre, yyjson_read_flag flg,
3213             yyjson_val *val, const char **msg) {
3214             #define return_err(_pos, _msg) do { \
3215             *msg = _msg; *end = _pos; return false; \
3216             } while (false)
3217              
3218             #define return_raw() do { \
3219             val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
3220             val->uni.str = (const char *)hdr; \
3221             **pre = '\0'; *pre = cur; *end = cur; return true; \
3222             } while (false)
3223              
3224 0           u8 *hdr = *ptr;
3225 0           u8 *cur = *ptr;
3226 0           u8 **end = ptr;
3227              
3228             /* skip sign */
3229 0           cur += (*cur == '-');
3230              
3231             /* read first digit, check leading zero */
3232 0 0         while (unlikely(!char_is_digit(*cur))) {
3233 0 0         if (has_allow(EXT_NUMBER)) {
3234 0 0         if (*cur == '+' && cur == hdr) { /* leading `+` sign */
    0          
3235 0           cur++;
3236 0           continue;
3237             }
3238 0 0         if (*cur == '.' && char_is_digit(cur[1])) { /* e.g. '.123' */
    0          
3239 0           goto read_double;
3240             }
3241             }
3242 0 0         if (has_allow(INF_AND_NAN)) {
3243 0 0         if (read_inf_or_nan(ptr, pre, flg, val)) return true;
3244             }
3245 0           return_err(cur, "no digit after sign");
3246             }
3247              
3248             /* read integral part */
3249 0 0         if (*cur == '0') {
3250 0           cur++;
3251 0 0         if (unlikely(char_is_digit(*cur))) {
3252 0           return_err(cur - 1, "number with leading zero is not allowed");
3253             }
3254 0 0         if (!char_is_fp(*cur)) {
3255 0 0         if (has_allow(EXT_NUMBER) && char_to_lower(*cur) == 'x') { /* hex */
    0          
3256 0 0         if (!char_is_hex(*++cur)) return_err(cur, "invalid hex number");
3257 0 0         while(char_is_hex(*cur)) cur++;
3258             }
3259 0           return_raw();
3260             }
3261             } else {
3262 0 0         while (char_is_digit(*cur)) cur++;
3263 0 0         if (!char_is_fp(*cur)) return_raw();
3264             }
3265              
3266 0           read_double:
3267             /* read fraction part */
3268 0 0         if (*cur == '.') {
3269 0           cur++;
3270 0 0         if (!char_is_digit(*cur)) {
3271 0 0         if (has_allow(EXT_NUMBER)) {
3272 0 0         if (!char_is_exp(*cur)) return_raw();
3273             } else {
3274 0           return_err(cur, "no digit after decimal point");
3275             }
3276             }
3277 0 0         while (char_is_digit(*cur)) cur++;
3278             }
3279              
3280             /* read exponent part */
3281 0 0         if (char_is_exp(*cur)) {
3282 0           cur += 1 + char_is_sign(cur[1]);
3283 0 0         if (!char_is_digit(*cur++)) {
3284 0           return_err(cur, "no digit after exponent sign");
3285             }
3286 0 0         while (char_is_digit(*cur)) cur++;
3287             }
3288              
3289 0           return_raw();
3290              
3291             #undef return_err
3292             #undef return_raw
3293             }
3294              
3295             /** Read a hex number. */
3296 0           static_noinline bool read_num_hex(u8 **ptr, u8 **pre, yyjson_read_flag flg,
3297             yyjson_val *val, const char **msg) {
3298 0           u8 *hdr = *ptr;
3299 0           u8 *cur = *ptr;
3300 0           u8 **end = ptr;
3301 0           u64 sig = 0, i = 0;
3302             bool sign;
3303              
3304             /* skip sign and '0x' */
3305 0           sign = (*cur == '-');
3306 0 0         cur += (*cur == '-' || *cur == '+') + 2;
    0          
3307              
3308             /* read hex */
3309 0 0         for(; i < 16; i++) {
3310 0           u8 c = hex_conv_table[cur[i]];
3311 0 0         if (c == 0xF0) break;
3312 0           sig <<= 4;
3313 0           sig |= c;
3314             }
3315              
3316             /* check error */
3317 0 0         if (unlikely(i == 0)) {
3318 0           *msg = "invalid hex number";
3319 0           return false;
3320             }
3321              
3322             /* check overflow */
3323 0 0         if (unlikely(i == 16)) {
3324 0 0         if (char_is_hex(cur[16]) || (sign && sig > ((u64)1 << 63))) {
    0          
    0          
3325 0 0         if (!has_flg(BIGNUM_AS_RAW)) {
3326 0           *msg = "hex number overflow";
3327 0           return false;
3328             }
3329 0           cur += 16;
3330 0 0         while (char_is_hex(*cur)) cur++;
3331 0           **pre = '\0';
3332 0           val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
3333 0           val->uni.str = (const char *)hdr;
3334 0           *pre = cur; *end = cur;
3335 0           return true;
3336             }
3337             }
3338              
3339 0           val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3);
3340 0 0         val->uni.u64 = (u64)(sign ? (u64)(~(sig) + 1) : (u64)(sig));
3341 0           *end = cur + i;
3342 0           return true;
3343             }
3344              
3345             /**
3346             Skip trivia (whitespace and comments).
3347             This function should be used only when `char_is_trivia()` returns true.
3348             @param ptr (inout) Input current position, output end position.
3349             @param eof JSON end position.
3350             @param flg JSON read flags.
3351             @return true if at least one character was skipped.
3352             false if no characters were skipped,
3353             or if a multi-line comment is unterminated;
3354             in the latter case, `ptr` will be set to `eof`.
3355             */
3356 0           static_noinline bool skip_trivia(u8 **ptr, u8 *eof, yyjson_read_flag flg) {
3357 0           u8 *hdr = *ptr, *cur = *ptr;
3358             usize len;
3359              
3360 0 0         while (cur < eof) {
3361 0           u8 *loop_begin = cur;
3362              
3363             /* skip standard whitespace */
3364 0 0         while(char_is_space(*cur)) cur++;
3365              
3366             /* skip extended whitespace */
3367 0 0         if (has_allow(EXT_WHITESPACE)) {
3368 0 0         while (char_is_space_ext(*cur)) {
3369 0           cur += (len = ext_space_len(cur));
3370 0 0         if (!len) break;
3371             }
3372             }
3373              
3374             /* skip comment, do not validate encoding */
3375 0 0         if (has_allow(COMMENTS) && cur[0] == '/') {
    0          
3376 0 0         if (cur[1] == '/') { /* single-line comment */
3377 0           cur += 2;
3378 0 0         if (has_allow(EXT_WHITESPACE)) {
3379 0 0         while (cur < eof) {
3380 0 0         if (char_is_eol_ext(*cur)) {
3381 0           cur += (len = ext_eol_len(cur));
3382 0 0         if (len) break;
3383             }
3384 0           cur++;
3385             }
3386             } else {
3387 0 0         while (cur < eof && !char_is_eol(*cur)) cur++;
    0          
3388             }
3389 0 0         } else if (cur[1] == '*') { /* multi-line comment */
3390 0           cur += 2;
3391 0 0         while (!byte_match_2(cur, "*/") && cur < eof) cur++;
    0          
3392 0 0         if (cur == eof) {
3393 0           *ptr = eof;
3394 0           return false; /* unclosed comment */
3395             }
3396 0           cur += 2;
3397             }
3398             }
3399 0 0         if (cur == loop_begin) break;
3400             }
3401 0           *ptr = cur;
3402 0           return cur > hdr;
3403             }
3404              
3405             /**
3406             Check truncated UTF-8 character.
3407             Return true if `cur` starts a valid UTF-8 sequence that is truncated.
3408             */
3409 0           static bool is_truncated_utf8(u8 *cur, u8 *eof) {
3410             u8 c0, c1, c2;
3411 0           usize len = (usize)(eof - cur);
3412 0 0         if (cur >= eof || len >= 4) return false;
    0          
3413 0           c0 = cur[0]; c1 = cur[1]; c2 = cur[2];
3414             /* 1-byte UTF-8, not truncated */
3415 0 0         if (c0 < 0x80) return false;
3416 0 0         if (len == 1) {
3417             /* 2-byte UTF-8, truncated */
3418 0 0         if ((c0 & 0xE0) == 0xC0 && (c0 & 0x1E) != 0x00) return true;
    0          
3419             /* 3-byte UTF-8, truncated */
3420 0 0         if ((c0 & 0xF0) == 0xE0) return true;
3421             /* 4-byte UTF-8, truncated */
3422 0 0         if ((c0 & 0xF8) == 0xF0 && (c0 & 0x07) <= 0x04) return true;
    0          
3423 0 0         } else if (len == 2) {
3424             /* 3-byte UTF-8, truncated */
3425 0 0         if ((c0 & 0xF0) == 0xE0 && (c1 & 0xC0) == 0x80) {
    0          
3426 0           u8 t = (u8)(((c0 & 0x0F) << 1) | ((c1 & 0x20) >> 5));
3427 0 0         return 0x01 <= t && t != 0x1B;
    0          
3428             }
3429             /* 4-byte UTF-8, truncated */
3430 0 0         if ((c0 & 0xF8) == 0xF0 && (c1 & 0xC0) == 0x80) {
    0          
3431 0           u8 t = (u8)(((c0 & 0x07) << 2) | ((c1 & 0x30) >> 4));
3432 0 0         return 0x01 <= t && t <= 0x10;
    0          
3433             }
3434 0 0         } else if (len == 3) {
3435             /* 4 bytes UTF-8, truncated */
3436 0 0         if ((c0 & 0xF8) == 0xF0 && (c1 & 0xC0) == 0x80 && (c2 & 0xC0) == 0x80) {
    0          
    0          
3437 0           u8 t = (u8)(((c0 & 0x07) << 2) | ((c1 & 0x30) >> 4));
3438 0 0         return 0x01 <= t && t <= 0x10;
    0          
3439             }
3440             }
3441 0           return false;
3442             }
3443              
3444             /**
3445             Check truncated string.
3446             Returns true if `cur` match `str` but is truncated.
3447             The `str` should be lowercase ASCII letters.
3448             */
3449 9           static bool is_truncated_str(u8 *cur, u8 *eof, const char *str,
3450             bool case_sensitive) {
3451 9           usize len = strlen(str);
3452 9 50         if (cur + len <= eof || eof <= cur) return false;
    0          
3453 0 0         if (case_sensitive) {
3454 0           return memcmp(cur, str, (usize)(eof - cur)) == 0;
3455             }
3456 0 0         for (; cur < eof; cur++, str++) {
3457 0 0         if (char_to_lower(*cur) != *(const u8 *)str) return false;
3458             }
3459 0           return true;
3460             }
3461              
3462             /**
3463             Check truncated JSON on parsing errors.
3464             Returns true if the input is valid but truncated.
3465             */
3466 4           static_noinline bool is_truncated_end(u8 *hdr, u8 *cur, u8 *eof,
3467             yyjson_read_code code,
3468             yyjson_read_flag flg) {
3469 4 50         if (cur >= eof) return true;
3470 4 100         if (code == YYJSON_READ_ERROR_LITERAL) {
3471 6           if (is_truncated_str(cur, eof, "true", true) ||
3472 6 50         is_truncated_str(cur, eof, "false", true) ||
3473 3           is_truncated_str(cur, eof, "null", true)) {
3474 0           return true;
3475             }
3476             }
3477 4 100         if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER ||
3478 3 50         code == YYJSON_READ_ERROR_INVALID_NUMBER ||
3479 3 50         code == YYJSON_READ_ERROR_LITERAL) {
3480 8 50         if (has_allow(INF_AND_NAN)) {
3481 0 0         if (*cur == '-') cur++;
3482 0           if (is_truncated_str(cur, eof, "infinity", false) ||
3483 0           is_truncated_str(cur, eof, "nan", false)) {
3484 0           return true;
3485             }
3486             }
3487             }
3488 4 50         if (code == YYJSON_READ_ERROR_UNEXPECTED_CONTENT) {
3489 0 0         if (has_allow(INF_AND_NAN)) {
3490 0           if (hdr + 3 <= cur &&
3491 0           is_truncated_str(cur - 3, eof, "infinity", false)) {
3492 0           return true; /* e.g. infin would be read as inf + in */
3493             }
3494             }
3495             }
3496 4 50         if (code == YYJSON_READ_ERROR_INVALID_STRING) {
3497 0           usize len = (usize)(eof - cur);
3498              
3499             /* unicode escape sequence */
3500 0 0         if (*cur == '\\') {
3501 0 0         if (len == 1) return true;
3502 0 0         if (len <= 5) {
3503 0 0         if (*++cur != 'u') return false;
3504 0 0         for (++cur; cur < eof; cur++) {
3505 0 0         if (!char_is_hex(*cur)) return false;
3506             }
3507 0           return true;
3508 0 0         } else if (len <= 11) {
3509             /* incomplete surrogate pair? */
3510             u16 hi;
3511 0 0         if (*++cur != 'u') return false;
3512 0 0         if (!hex_load_4(++cur, &hi)) return false;
3513 0 0         if ((hi & 0xF800) != 0xD800) return false;
3514 0           cur += 4;
3515 0 0         if (cur >= eof) return true;
3516             /* valid low surrogate is DC00...DFFF */
3517 0 0         if (*cur != '\\') return false;
3518 0 0         if (++cur >= eof) return true;
3519 0 0         if (*cur != 'u') return false;
3520 0 0         if (++cur >= eof) return true;
3521 0 0         if (*cur != 'd' && *cur != 'D') return false;
    0          
3522 0 0         if (++cur >= eof) return true;
3523 0 0         if ((*cur < 'c' || *cur > 'f') && (*cur < 'C' || *cur > 'F'))
    0          
    0          
    0          
3524 0           return false;
3525 0 0         if (++cur >= eof) return true;
3526 0 0         if (!char_is_hex(*cur)) return false;
3527 0           return true;
3528             }
3529 0           return false;
3530             }
3531              
3532             /* 2 to 4 bytes UTF-8 */
3533 0 0         if (is_truncated_utf8(cur, eof)) {
3534 0           return true;
3535             }
3536             }
3537 8 50         if (has_allow(COMMENTS)) {
3538 0 0         if (code == YYJSON_READ_ERROR_INVALID_COMMENT) {
3539             /* unclosed multiline comment */
3540 0           return true;
3541             }
3542 0 0         if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER &&
3543 0 0         *cur == '/' && cur + 1 == eof) {
    0          
3544             /* truncated beginning of comment */
3545 0           return true;
3546             }
3547             }
3548 4 100         if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER &&
3549 2 50         has_allow(BOM)) {
3550             /* truncated UTF-8 BOM */
3551 0           usize len = (usize)(eof - cur);
3552 0 0         if (cur == hdr && len < 3 && !memcmp(hdr, "\xEF\xBB\xBF", len)) {
    0          
    0          
3553 0           return true;
3554             }
3555             }
3556 4           return false;
3557             }
3558              
3559              
3560              
3561             #if !YYJSON_DISABLE_FAST_FP_CONV /* FP_READER */
3562              
3563             /*==============================================================================
3564             * MARK: - BigInt For Floating Point Number Reader (Private)
3565             *
3566             * The bigint algorithm is used by floating-point number reader to get correctly
3567             * rounded result for numbers with lots of digits. This part of code is rarely
3568             * used for common numbers.
3569             *============================================================================*/
3570              
3571             /** Unsigned arbitrarily large integer */
3572             typedef struct bigint {
3573             u32 used; /* used chunks count, should not be 0 */
3574             u64 bits[64]; /* chunks (58 is enough here) */
3575             } bigint;
3576              
3577             /**
3578             Evaluate 'big += val'.
3579             @param big A big number (can be 0).
3580             @param val An unsigned integer (can be 0).
3581             */
3582             static_inline void bigint_add_u64(bigint *big, u64 val) {
3583             u32 idx, max;
3584 0           u64 num = big->bits[0];
3585 0           u64 add = num + val;
3586 0           big->bits[0] = add;
3587 0 0         if (likely((add >= num) || (add >= val))) return;
    0          
3588 0 0         for ((void)(idx = 1), max = big->used; idx < max; idx++) {
3589 0 0         if (likely(big->bits[idx] != U64_MAX)) {
3590 0           big->bits[idx] += 1;
3591 0           return;
3592             }
3593 0           big->bits[idx] = 0;
3594             }
3595 0           big->bits[big->used++] = 1;
3596             }
3597              
3598             /**
3599             Evaluate 'big *= val'.
3600             @param big A big number (can be 0).
3601             @param val An unsigned integer (cannot be 0).
3602             */
3603             static_inline void bigint_mul_u64(bigint *big, u64 val) {
3604 0           u32 idx = 0, max = big->used;
3605 0           u64 hi, lo, carry = 0;
3606 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          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3607 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          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3608             }
3609 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          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3610 0           u128_mul_add(big->bits[idx], val, carry, &hi, &lo);
3611 0           big->bits[idx] = lo;
3612 0           carry = hi;
3613             }
3614 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          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3615 0           }
3616              
3617             /**
3618             Evaluate 'big *= 2^exp'.
3619             @param big A big number (can be 0).
3620             @param exp An exponent integer (can be 0).
3621             */
3622             static_inline void bigint_mul_pow2(bigint *big, u32 exp) {
3623 0           u32 shft = exp % 64;
3624 0           u32 move = exp / 64;
3625 0           u32 idx = big->used;
3626 0           if (unlikely(shft == 0)) {
3627 0 0         for (; idx > 0; idx--) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3628 0           big->bits[idx + move - 1] = big->bits[idx - 1];
3629             }
3630 0           big->used += move;
3631 0 0         while (move) big->bits[--move] = 0;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3632             } else {
3633 0           big->bits[idx] = 0;
3634 0 0         for (; idx > 0; idx--) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3635 0           u64 num = big->bits[idx] << shft;
3636 0           num |= big->bits[idx - 1] >> (64 - shft);
3637 0           big->bits[idx + move] = num;
3638             }
3639 0           big->bits[move] = big->bits[0] << shft;
3640 0           big->used += move + (big->bits[big->used + move] > 0);
3641 0 0         while (move) big->bits[--move] = 0;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3642             }
3643 0           }
3644              
3645             /**
3646             Evaluate 'big *= 10^exp'.
3647             @param big A big number (can be 0).
3648             @param exp An exponent integer (cannot be 0).
3649             */
3650             static_inline void bigint_mul_pow10(bigint *big, i32 exp) {
3651 0 0         for (; exp >= U64_POW10_MAX_EXACT_EXP; exp -= U64_POW10_MAX_EXACT_EXP) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3652 0           bigint_mul_u64(big, u64_pow10_table[U64_POW10_MAX_EXACT_EXP]);
3653             }
3654 0 0         if (exp) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3655 0           bigint_mul_u64(big, u64_pow10_table[exp]);
3656             }
3657 0           }
3658              
3659             /**
3660             Compare two bigint.
3661             @return -1 if 'a < b', +1 if 'a > b', 0 if 'a == b'.
3662             */
3663             static_inline i32 bigint_cmp(bigint *a, bigint *b) {
3664 0           u32 idx = a->used;
3665 0 0         if (a->used < b->used) return -1;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3666 0 0         if (a->used > b->used) return +1;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3667 0 0         while (idx-- > 0) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3668 0           u64 av = a->bits[idx];
3669 0           u64 bv = b->bits[idx];
3670 0 0         if (av < bv) return -1;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3671 0 0         if (av > bv) return +1;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3672             }
3673 0           return 0;
3674             }
3675              
3676             /**
3677             Evaluate 'big = val'.
3678             @param big A big number (can be 0).
3679             @param val An unsigned integer (can be 0).
3680             */
3681             static_inline void bigint_set_u64(bigint *big, u64 val) {
3682 0           big->used = 1;
3683 0           big->bits[0] = val;
3684 0           }
3685              
3686             /** Set a bigint with floating point number string. */
3687 0           static_noinline void bigint_set_buf(bigint *big, u64 sig, i32 *exp,
3688             u8 *sig_cut, u8 *sig_end, u8 *dot_pos) {
3689              
3690 0 0         if (unlikely(!sig_cut)) {
3691             /* no digit cut, set significant part only */
3692             bigint_set_u64(big, sig);
3693 0           return;
3694              
3695             } else {
3696             /* some digits were cut, read them from 'sig_cut' to 'sig_end' */
3697 0           u8 *hdr = sig_cut;
3698 0           u8 *cur = hdr;
3699 0           u32 len = 0;
3700 0           u64 val = 0;
3701 0           bool dig_big_cut = false;
3702 0           bool has_dot = (hdr < dot_pos) & (dot_pos < sig_end);
3703 0           u32 dig_len_total = U64_SAFE_DIG + (u32)(sig_end - hdr) - has_dot;
3704              
3705 0           sig -= (*sig_cut >= '5'); /* sig was rounded before */
3706 0 0         if (dig_len_total > F64_MAX_DEC_DIG) {
3707 0           dig_big_cut = true;
3708 0           sig_end -= dig_len_total - (F64_MAX_DEC_DIG + 1);
3709 0           sig_end -= (dot_pos + 1 == sig_end);
3710 0           dig_len_total = (F64_MAX_DEC_DIG + 1);
3711             }
3712 0           *exp -= (i32)dig_len_total - U64_SAFE_DIG;
3713              
3714 0           big->used = 1;
3715 0           big->bits[0] = sig;
3716 0 0         while (cur < sig_end) {
3717 0 0         if (likely(cur != dot_pos)) {
3718 0           val = val * 10 + (u8)(*cur++ - '0');
3719 0           len++;
3720 0 0         if (unlikely(cur == sig_end && dig_big_cut)) {
    0          
3721             /* The last digit must be non-zero, */
3722             /* set it to '1' for correct rounding. */
3723 0           val = val - (val % 10) + 1;
3724             }
3725 0 0         if (len == U64_SAFE_DIG || cur == sig_end) {
    0          
3726 0           bigint_mul_pow10(big, (i32)len);
3727             bigint_add_u64(big, val);
3728 0           val = 0;
3729 0           len = 0;
3730             }
3731             } else {
3732 0           cur++;
3733             }
3734             }
3735             }
3736             }
3737              
3738              
3739              
3740             /*==============================================================================
3741             * MARK: - Diy Floating Point (Private)
3742             *============================================================================*/
3743              
3744             /** "Do It Yourself Floating Point" struct. */
3745             typedef struct diy_fp {
3746             u64 sig; /* significand */
3747             i32 exp; /* exponent, base 2 */
3748             i32 pad; /* padding, useless */
3749             } diy_fp;
3750              
3751             /** Get cached rounded diy_fp with pow(10, e) The input value must in range
3752             [POW10_SIG_TABLE_MIN_EXP, POW10_SIG_TABLE_MAX_EXP]. */
3753             static_inline diy_fp diy_fp_get_cached_pow10(i32 exp10) {
3754             diy_fp fp;
3755             u64 sig_ext;
3756             pow10_table_get_sig(exp10, &fp.sig, &sig_ext);
3757             pow10_table_get_exp(exp10, &fp.exp);
3758 0           fp.sig += (sig_ext >> 63);
3759 0           return fp;
3760             }
3761              
3762             /** Returns fp * fp2. */
3763             static_inline diy_fp diy_fp_mul(diy_fp fp, diy_fp fp2) {
3764             u64 hi, lo;
3765 0           u128_mul(fp.sig, fp2.sig, &hi, &lo);
3766 0           fp.sig = hi + (lo >> 63);
3767 0           fp.exp += fp2.exp + 64;
3768 0           return fp;
3769             }
3770              
3771             /** Convert diy_fp to IEEE-754 raw value. */
3772             static_inline u64 diy_fp_to_ieee_raw(diy_fp fp) {
3773 0           u64 sig = fp.sig;
3774 0           i32 exp = fp.exp;
3775             u32 lz_bits;
3776 0           if (unlikely(fp.sig == 0)) return 0;
3777              
3778 0           lz_bits = u64_lz_bits(sig);
3779 0           sig <<= lz_bits;
3780 0           sig >>= F64_BITS - F64_SIG_FULL_BITS;
3781 0           exp -= (i32)lz_bits;
3782 0           exp += F64_BITS - F64_SIG_FULL_BITS;
3783 0           exp += F64_SIG_BITS;
3784              
3785 0 0         if (unlikely(exp >= F64_MAX_BIN_EXP)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3786             /* overflow */
3787 0           return F64_BITS_INF;
3788 0 0         } else if (likely(exp >= F64_MIN_BIN_EXP - 1)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3789             /* normal */
3790 0           exp += F64_EXP_BIAS;
3791 0           return ((u64)exp << F64_SIG_BITS) | (sig & F64_SIG_MASK);
3792 0 0         } else if (likely(exp >= F64_MIN_BIN_EXP - F64_SIG_FULL_BITS)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3793             /* subnormal */
3794 0           return sig >> (F64_MIN_BIN_EXP - exp - 1);
3795             } else {
3796             /* underflow */
3797 0           return 0;
3798             }
3799             }
3800              
3801              
3802              
3803             /*==============================================================================
3804             * MARK: - Number Reader (Private)
3805             *============================================================================*/
3806              
3807             /**
3808             Read a JSON number.
3809              
3810             1. This function assume that the floating-point number is in IEEE-754 format.
3811             2. This function support uint64/int64/double number. If an integer number
3812             cannot fit in uint64/int64, it will returns as a double number. If a double
3813             number is infinite, the return value is based on flag.
3814             3. This function (with inline attribute) may generate a lot of instructions.
3815             */
3816             static_inline bool read_num(u8 **ptr, u8 **pre, yyjson_read_flag flg,
3817             yyjson_val *val, const char **msg) {
3818             #define return_err(_pos, _msg) do { \
3819             *msg = _msg; \
3820             *end = _pos; \
3821             return false; \
3822             } while (false)
3823              
3824             #define return_0() do { \
3825             val->tag = YYJSON_TYPE_NUM | (u8)((u8)sign << 3); \
3826             val->uni.u64 = 0; \
3827             *end = cur; return true; \
3828             } while (false)
3829              
3830             #define return_i64(_v) do { \
3831             val->tag = YYJSON_TYPE_NUM | (u8)((u8)sign << 3); \
3832             val->uni.u64 = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \
3833             *end = cur; return true; \
3834             } while (false)
3835              
3836             #define return_f64(_v) do { \
3837             val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
3838             val->uni.f64 = sign ? -(f64)(_v) : (f64)(_v); \
3839             *end = cur; return true; \
3840             } while (false)
3841              
3842             #define return_f64_bin(_v) do { \
3843             val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
3844             val->uni.u64 = ((u64)sign << 63) | (u64)(_v); \
3845             *end = cur; return true; \
3846             } while (false)
3847              
3848             #define return_inf() do { \
3849             if (has_flg(BIGNUM_AS_RAW)) return_raw(); \
3850             if (has_allow(INF_AND_NAN)) return_f64_bin(F64_BITS_INF); \
3851             else return_err(hdr, "number is infinity when parsed as double"); \
3852             } while (false)
3853              
3854             #define return_raw() do { \
3855             **pre = '\0'; /* add null-terminator for previous raw string */ \
3856             val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
3857             val->uni.str = (const char *)hdr; \
3858             *pre = cur; *end = cur; return true; \
3859             } while (false)
3860              
3861 34148           u8 *sig_cut = NULL; /* significant part cutting position for long number */
3862 34148           u8 *sig_end = NULL; /* significant part ending position */
3863 34148           u8 *dot_pos = NULL; /* decimal point position */
3864              
3865 34148           u64 sig = 0; /* significant part of the number */
3866 34148           i32 exp = 0; /* exponent part of the number */
3867              
3868             bool exp_sign; /* temporary exponent sign from literal part */
3869 34148           i64 exp_sig = 0; /* temporary exponent number from significant part */
3870 34148           i64 exp_lit = 0; /* temporary exponent number from exponent literal part */
3871             u64 num; /* temporary number for reading */
3872             u8 *tmp; /* temporary cursor for reading */
3873              
3874 34148           u8 *hdr = *ptr;
3875 34148           u8 *cur = *ptr;
3876 34148           u8 **end = ptr;
3877             bool sign;
3878              
3879             /* read number as raw string if has `YYJSON_READ_NUMBER_AS_RAW` flag */
3880 34152 0         if (has_flg(NUMBER_AS_RAW)) {
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
3881 0           return read_num_raw(ptr, pre, flg, val, msg);
3882             }
3883              
3884 34148           sign = (*hdr == '-');
3885 34148           cur += sign;
3886              
3887             /* begin with a leading zero or non-digit */
3888 68296 0         while (unlikely(!char_is_nonzero(*cur))) { /* 0 or non-digit char */
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
3889 0 0         if (unlikely(*cur != '0')) { /* non-digit char */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3890 0 0         if (has_allow(EXT_NUMBER)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3891 0 0         if (*cur == '+' && cur == hdr) { /* leading `+` sign */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3892 0           cur++;
3893 0           continue;
3894             }
3895 0 0         if (*cur == '.' && char_is_digit(cur[1])) { /* e.g. '.123' */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3896 0           goto leading_dot;
3897             }
3898             }
3899 0 0         if (has_allow(INF_AND_NAN)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3900 0 0         if (read_inf_or_nan(ptr, pre, flg, val)) return true;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3901             }
3902 0           return_err(cur, "no digit after sign");
3903             }
3904             /* begin with 0 */
3905 0 0         if (likely(!char_is_digit_or_fp(*++cur))) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3906 0 0         if (has_allow(EXT_NUMBER) && char_to_lower(*cur) == 'x') { /* hex */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3907 0           return read_num_hex(ptr, pre, flg, val, msg);
3908             }
3909 0           return_0();
3910             }
3911 0 0         if (likely(*cur == '.')) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3912 0           leading_dot:
3913 0           dot_pos = cur++;
3914 0 0         if (unlikely(!char_is_digit(*cur))) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3915 0 0         if (has_allow(EXT_NUMBER)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3916 0 0         if (char_is_exp(*cur)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3917 0           goto digi_exp_more;
3918             } else {
3919 0           return_f64_bin(0);
3920             }
3921             }
3922 0           return_err(cur, "no digit after decimal point");
3923             }
3924 0 0         while (unlikely(*cur == '0')) cur++;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3925 0 0         if (likely(char_is_digit(*cur))) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3926             /* first non-zero digit after decimal point */
3927 0           sig = (u64)(*cur - '0'); /* read first digit */
3928 0           cur--;
3929 0           goto digi_frac_1; /* continue read fraction part */
3930             }
3931             }
3932 0 0         if (unlikely(char_is_digit(*cur))) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3933 0           return_err(cur - 1, "number with leading zero is not allowed");
3934             }
3935 0 0         if (unlikely(char_is_exp(*cur))) { /* 0 with any exponent is still 0 */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3936 0           cur += (usize)1 + char_is_sign(cur[1]);
3937 0 0         if (unlikely(!char_is_digit(*cur))) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3938 0           return_err(cur, "no digit after exponent sign");
3939             }
3940 0 0         while (char_is_digit(*++cur));
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3941             }
3942 0           return_f64_bin(0);
3943             }
3944              
3945             /* begin with non-zero digit */
3946 34148           sig = (u64)(*cur - '0');
3947              
3948             /*
3949             Read integral part, same as the following code.
3950              
3951             for (int i = 1; i <= 18; i++) {
3952             num = cur[i] - '0';
3953             if (num <= 9) sig = num + sig * 10;
3954             else goto digi_sepr_i;
3955             }
3956             */
3957             #define expr_intg(i) \
3958             if (likely((num = (u64)(cur[i] - (u8)'0')) <= 9)) sig = num + sig * 10; \
3959             else { goto digi_sepr_##i; }
3960 34148 0         repeat_in_1_18(expr_intg)
    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          
    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          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    100          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    100          
    50          
    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          
3961             #undef expr_intg
3962              
3963              
3964 0           cur += 19; /* skip continuous 19 digits */
3965 0 0         if (!char_is_digit_or_fp(*cur)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3966             /* this number is an integer consisting of 19 digits */
3967 0 0         if (sign && (sig > ((u64)1 << 63))) { /* overflow */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3968 0 0         if (has_flg(BIGNUM_AS_RAW)) return_raw();
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3969 0 0         return_f64(unsafe_yyjson_u64_to_f64(sig));
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3970             }
3971 0 0         return_i64(sig);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3972             }
3973 0           goto digi_intg_more; /* read more digits in integral part */
3974              
3975              
3976             /* process first non-digit character */
3977             #define expr_sepr(i) \
3978             digi_sepr_##i: \
3979             if (likely(!char_is_fp(cur[i]))) { cur += i; return_i64(sig); } \
3980             dot_pos = cur + i; \
3981             if (likely(cur[i] == '.')) goto digi_frac_##i; \
3982             cur += i; sig_end = cur; goto digi_exp_more;
3983 68296 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          
    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          
    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          
    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          
    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          
    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          
    50          
    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          
    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          
    50          
    50          
    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          
    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          
3984             #undef expr_sepr
3985              
3986              
3987             /* read fraction part */
3988             #define expr_frac(i) \
3989             digi_frac_##i: \
3990             if (likely((num = (u64)(cur[i + 1] - (u8)'0')) <= 9)) \
3991             sig = num + sig * 10; \
3992             else { goto digi_stop_##i; }
3993 2 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          
    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          
    0          
    0          
    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          
3994             #undef expr_frac
3995              
3996 0           cur += 20; /* skip 19 digits and 1 decimal point */
3997 0 0         if (!char_is_digit(*cur)) goto digi_frac_end; /* fraction part end */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3998 0           goto digi_frac_more; /* read more digits in fraction part */
3999              
4000              
4001             /* significant part end */
4002             #define expr_stop(i) \
4003             digi_stop_##i: \
4004             cur += i + 1; \
4005             goto digi_frac_end;
4006 2           repeat_in_1_18(expr_stop)
4007             #undef expr_stop
4008              
4009              
4010             /* read more digits in integral part */
4011 0           digi_intg_more:
4012 0 0         if (char_is_digit(*cur)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4013 0 0         if (!char_is_digit_or_fp(cur[1])) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4014             /* this number is an integer consisting of 20 digits */
4015 0           num = (u64)(*cur - '0');
4016 0 0         if ((sig < (U64_MAX / 10)) ||
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4017 0 0         (sig == (U64_MAX / 10) && num <= (U64_MAX % 10))) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4018 0           sig = num + sig * 10;
4019 0           cur++;
4020             /* convert to double if overflow */
4021 0 0         if (sign) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4022 0 0         if (has_flg(BIGNUM_AS_RAW)) return_raw();
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4023 0 0         return_f64(unsafe_yyjson_u64_to_f64(sig));
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4024             }
4025 0 0         return_i64(sig);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4026             }
4027             }
4028             }
4029              
4030 0 0         if (char_is_exp(*cur)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4031 0           dot_pos = cur;
4032 0           goto digi_exp_more;
4033             }
4034              
4035 0 0         if (*cur == '.') {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4036 0           dot_pos = cur++;
4037 0 0         if (unlikely(!char_is_digit(*cur))) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4038 0 0         if (has_allow(EXT_NUMBER)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4039 0           goto digi_frac_end;
4040             }
4041 0           return_err(cur, "no digit after decimal point");
4042             }
4043             }
4044              
4045              
4046             /* read more digits in fraction part */
4047 0           digi_frac_more:
4048 0           sig_cut = cur; /* too large to fit in u64, excess digits need to be cut */
4049 0           sig += (*cur >= '5'); /* round */
4050 0 0         while (char_is_digit(*++cur));
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4051 0 0         if (!dot_pos) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4052 0 0         if (!char_is_fp(*cur) && has_flg(BIGNUM_AS_RAW)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4053 0           return_raw(); /* it's a large integer */
4054             }
4055 0           dot_pos = cur;
4056 0 0         if (*cur == '.') {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4057 0 0         if (unlikely(!char_is_digit(*++cur))) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4058 0 0         if (!has_allow(EXT_NUMBER)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4059 0           return_err(cur, "no digit after decimal point");
4060             }
4061             }
4062 0 0         while (char_is_digit(*cur)) cur++;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4063             }
4064             }
4065 0           exp_sig = (i64)(dot_pos - sig_cut);
4066 0           exp_sig += (dot_pos < sig_cut);
4067              
4068             /* ignore trailing zeros */
4069 0           tmp = cur - 1;
4070 0 0         while ((*tmp == '0' || *tmp == '.') && tmp > hdr) tmp--;
    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          
4071 0 0         if (tmp < sig_cut) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4072 0           sig_cut = NULL;
4073             } else {
4074 0           sig_end = cur;
4075             }
4076              
4077 0 0         if (char_is_exp(*cur)) goto digi_exp_more;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4078 0           goto digi_exp_finish;
4079              
4080              
4081             /* fraction part end */
4082 2           digi_frac_end:
4083 2 0         if (unlikely(dot_pos + 1 == cur)) {
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
4084 0 0         if (!has_allow(EXT_NUMBER)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4085 0           return_err(cur, "no digit after decimal point");
4086             }
4087             }
4088 2           sig_end = cur;
4089 2           exp_sig = -(i64)((u64)(cur - dot_pos) - 1);
4090 4 0         if (likely(!char_is_exp(*cur))) {
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
4091 2 0         if (unlikely(exp_sig < F64_MIN_DEC_EXP - 19)) {
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
4092 0           return_f64_bin(0); /* underflow */
4093             }
4094 2           exp = (i32)exp_sig;
4095 2           goto digi_finish;
4096             } else {
4097 0           goto digi_exp_more;
4098             }
4099              
4100              
4101             /* read exponent part */
4102 0           digi_exp_more:
4103 0           exp_sign = (*++cur == '-');
4104 0           cur += char_is_sign(*cur);
4105 0 0         if (unlikely(!char_is_digit(*cur))) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4106 0           return_err(cur, "no digit after exponent sign");
4107             }
4108 0 0         while (*cur == '0') cur++;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4109              
4110             /* read exponent literal */
4111 0           tmp = cur;
4112 0 0         while (char_is_digit(*cur)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4113 0           exp_lit = (i64)((u8)(*cur++ - '0') + (u64)exp_lit * 10);
4114             }
4115 0 0         if (unlikely(cur - tmp >= U64_SAFE_DIG)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4116 0 0         if (exp_sign) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4117 0           return_f64_bin(0); /* underflow */
4118             } else {
4119 0 0         return_inf(); /* overflow */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4120             }
4121             }
4122 0 0         exp_sig += exp_sign ? -exp_lit : exp_lit;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4123              
4124              
4125             /* validate exponent value */
4126 0           digi_exp_finish:
4127 0 0         if (unlikely(exp_sig < F64_MIN_DEC_EXP - 19)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4128 0           return_f64_bin(0); /* underflow */
4129             }
4130 0 0         if (unlikely(exp_sig > F64_MAX_DEC_EXP)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4131 0 0         return_inf(); /* overflow */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4132             }
4133 0           exp = (i32)exp_sig;
4134              
4135              
4136             /* all digit read finished */
4137 2           digi_finish:
4138              
4139             /*
4140             Fast path 1:
4141              
4142             1. The floating-point number calculation should be accurate, see the
4143             comments of macro `YYJSON_DOUBLE_MATH_CORRECT`.
4144             2. Correct rounding should be performed (fegetround() == FE_TONEAREST).
4145             3. The input of floating point number calculation does not lose precision,
4146             which means: 64 - leading_zero(input) - trailing_zero(input) < 53.
4147              
4148             We don't check all available inputs here, because that would make the code
4149             more complicated, and not friendly to branch predictor.
4150             */
4151             #if YYJSON_DOUBLE_MATH_CORRECT
4152 2 0         if (sig < ((u64)1 << 53) &&
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
4153 2 0         exp >= -F64_POW10_MAX_EXACT_EXP &&
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
4154 2 0         exp <= +F64_POW10_MAX_EXACT_EXP) {
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
4155 2           f64 dbl = (f64)sig;
4156 2 0         if (exp < 0) {
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
4157 2           dbl /= f64_pow10_table[-exp];
4158             } else {
4159 0           dbl *= f64_pow10_table[+exp];
4160             }
4161 2 0         return_f64(dbl);
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
4162             }
4163             #endif
4164              
4165             /*
4166             Fast path 2:
4167              
4168             To keep it simple, we only accept normal number here,
4169             let the slow path to handle subnormal and infinity number.
4170             */
4171 0 0         if (likely(!sig_cut &&
    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          
4172             exp > -F64_MAX_DEC_EXP + 1 &&
4173             exp < +F64_MAX_DEC_EXP - 20)) {
4174             /*
4175             The result value is exactly equal to (sig * 10^exp),
4176             the exponent part (10^exp) can be converted to (sig2 * 2^exp2).
4177              
4178             The sig2 can be an infinite length number, only the highest 128 bits
4179             is cached in the pow10_sig_table.
4180              
4181             Now we have these bits:
4182             sig1 (normalized 64bit) : aaaaaaaa
4183             sig2 (higher 64bit) : bbbbbbbb
4184             sig2_ext (lower 64bit) : cccccccc
4185             sig2_cut (extra unknown bits) : dddddddddddd....
4186              
4187             And the calculation process is:
4188             ----------------------------------------
4189             aaaaaaaa *
4190             bbbbbbbbccccccccdddddddddddd....
4191             ----------------------------------------
4192             abababababababab +
4193             acacacacacacacac +
4194             adadadadadadadadadad....
4195             ----------------------------------------
4196             [hi____][lo____] +
4197             [hi2___][lo2___] +
4198             [unknown___________....]
4199             ----------------------------------------
4200              
4201             The addition with carry may affect higher bits, but if there is a 0
4202             in higher bits, the bits higher than 0 will not be affected.
4203              
4204             `lo2` + `unknown` may get a carry bit and may affect `hi2`, the max
4205             value of `hi2` is 0xFFFFFFFFFFFFFFFE, so `hi2` will not overflow.
4206              
4207             `lo` + `hi2` may also get a carry bit and may affect `hi`, but only
4208             the highest significant 53 bits of `hi` is needed. If there is a 0
4209             in the lower bits of `hi`, then all the following bits can be dropped.
4210              
4211             To convert the result to IEEE-754 double number, we need to perform
4212             correct rounding:
4213             1. if bit 54 is 0, round down,
4214             2. if bit 54 is 1 and any bit beyond bit 54 is 1, round up,
4215             3. if bit 54 is 1 and all bits beyond bit 54 are 0, round to even,
4216             as the extra bits is unknown, this case will not be handled here.
4217             */
4218              
4219             u64 raw;
4220             u64 sig1, sig2, sig2_ext, hi, lo, hi2, lo2, add, bits;
4221             i32 exp2;
4222             u32 lz;
4223 0           bool exact = false, carry, round_up;
4224              
4225             /* convert (10^exp) to (sig2 * 2^exp2) */
4226 0           pow10_table_get_sig(exp, &sig2, &sig2_ext);
4227 0           pow10_table_get_exp(exp, &exp2);
4228              
4229             /* normalize and multiply */
4230 0           lz = u64_lz_bits(sig);
4231 0           sig1 = sig << lz;
4232 0           exp2 -= (i32)lz;
4233 0           u128_mul(sig1, sig2, &hi, &lo);
4234              
4235             /*
4236             The `hi` is in range [0x4000000000000000, 0xFFFFFFFFFFFFFFFE],
4237             To get normalized value, `hi` should be shifted to the left by 0 or 1.
4238              
4239             The highest significant 53 bits is used by IEEE-754 double number,
4240             and the bit 54 is used to detect rounding direction.
4241              
4242             The lowest (64 - 54 - 1) bits is used to check whether it contains 0.
4243             */
4244 0           bits = hi & (((u64)1 << (64 - 54 - 1)) - 1);
4245 0 0         if (bits - 1 < (((u64)1 << (64 - 54 - 1)) - 2)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4246             /*
4247             (bits != 0 && bits != 0x1FF) => (bits - 1 < 0x1FF - 1)
4248             The `bits` is not zero, so we don't need to check `round to even`
4249             case. The `bits` contains bit `0`, so we can drop the extra bits
4250             after `0`.
4251             */
4252 0           exact = true;
4253              
4254             } else {
4255             /*
4256             (bits == 0 || bits == 0x1FF)
4257             The `bits` is filled with all `0` or all `1`, so we need to check
4258             lower bits with another 64-bit multiplication.
4259             */
4260 0           u128_mul(sig1, sig2_ext, &hi2, &lo2);
4261              
4262 0           add = lo + hi2;
4263 0 0         if (add + 1 > (u64)1) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4264             /*
4265             (add != 0 && add != U64_MAX) => (add + 1 > 1)
4266             The `add` is not zero, so we don't need to check `round to
4267             even` case. The `add` contains bit `0`, so we can drop the
4268             extra bits after `0`. The `hi` cannot be U64_MAX, so it will
4269             not overflow.
4270             */
4271 0 0         carry = add < lo || add < hi2;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4272 0           hi += carry;
4273 0           exact = true;
4274             }
4275             }
4276              
4277 0 0         if (exact) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4278             /* normalize */
4279 0           lz = hi < ((u64)1 << 63);
4280 0           hi <<= lz;
4281 0           exp2 -= (i32)lz;
4282 0           exp2 += 64;
4283              
4284             /* test the bit 54 and get rounding direction */
4285 0           round_up = (hi & ((u64)1 << (64 - 54))) > (u64)0;
4286 0 0         hi += (round_up ? ((u64)1 << (64 - 54)) : (u64)0);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4287              
4288             /* test overflow */
4289 0 0         if (hi < ((u64)1 << (64 - 54))) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4290 0           hi = ((u64)1 << 63);
4291 0           exp2 += 1;
4292             }
4293              
4294             /* This is a normal number, convert it to IEEE-754 format. */
4295 0           hi >>= F64_BITS - F64_SIG_FULL_BITS;
4296 0           exp2 += F64_BITS - F64_SIG_FULL_BITS + F64_SIG_BITS;
4297 0           exp2 += F64_EXP_BIAS;
4298 0           raw = ((u64)exp2 << F64_SIG_BITS) | (hi & F64_SIG_MASK);
4299 0           return_f64_bin(raw);
4300             }
4301             }
4302              
4303             /*
4304             Slow path: read double number exactly with diyfp.
4305             1. Use cached diyfp to get an approximation value.
4306             2. Use bigcomp to check the approximation value if needed.
4307              
4308             This algorithm refers to google's double-conversion project:
4309             https://github.com/google/double-conversion
4310             */
4311             {
4312 0           const i32 ERR_ULP_LOG = 3;
4313 0           const i32 ERR_ULP = 1 << ERR_ULP_LOG;
4314 0           const i32 ERR_CACHED_POW = ERR_ULP / 2;
4315 0           const i32 ERR_MUL_FIXED = ERR_ULP / 2;
4316 0           const i32 DIY_SIG_BITS = 64;
4317 0           const i32 EXP_BIAS = F64_EXP_BIAS + F64_SIG_BITS;
4318 0           const i32 EXP_SUBNORMAL = -EXP_BIAS + 1;
4319              
4320             u64 fp_err;
4321             u32 bits;
4322             i32 order_of_magnitude;
4323             i32 effective_significand_size;
4324             i32 precision_digits_count;
4325             u64 precision_bits;
4326             u64 half_way;
4327              
4328             u64 raw;
4329             diy_fp fp, fp_upper;
4330             bigint big_full, big_comp;
4331             i32 cmp;
4332              
4333 0           fp.sig = sig;
4334 0           fp.exp = 0;
4335 0 0         fp_err = sig_cut ? (u64)(ERR_ULP / 2) : (u64)0;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4336              
4337             /* normalize */
4338 0           bits = u64_lz_bits(fp.sig);
4339 0           fp.sig <<= bits;
4340 0           fp.exp -= (i32)bits;
4341 0           fp_err <<= bits;
4342              
4343             /* multiply and add error */
4344 0           fp = diy_fp_mul(fp, diy_fp_get_cached_pow10(exp));
4345 0           fp_err += (u64)ERR_CACHED_POW + (fp_err != 0) + (u64)ERR_MUL_FIXED;
4346              
4347             /* normalize */
4348 0           bits = u64_lz_bits(fp.sig);
4349 0           fp.sig <<= bits;
4350 0           fp.exp -= (i32)bits;
4351 0           fp_err <<= bits;
4352              
4353             /* effective significand */
4354 0           order_of_magnitude = DIY_SIG_BITS + fp.exp;
4355 0 0         if (likely(order_of_magnitude >= EXP_SUBNORMAL + F64_SIG_FULL_BITS)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4356 0           effective_significand_size = F64_SIG_FULL_BITS;
4357 0 0         } else if (order_of_magnitude <= EXP_SUBNORMAL) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4358 0           effective_significand_size = 0;
4359             } else {
4360 0           effective_significand_size = order_of_magnitude - EXP_SUBNORMAL;
4361             }
4362              
4363             /* precision digits count */
4364 0           precision_digits_count = DIY_SIG_BITS - effective_significand_size;
4365 0 0         if (unlikely(precision_digits_count + ERR_ULP_LOG >= DIY_SIG_BITS)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4366 0           i32 shr = (precision_digits_count + ERR_ULP_LOG) - DIY_SIG_BITS + 1;
4367 0           fp.sig >>= shr;
4368 0           fp.exp += shr;
4369 0           fp_err = (fp_err >> shr) + 1 + (u32)ERR_ULP;
4370 0           precision_digits_count -= shr;
4371             }
4372              
4373             /* half way */
4374 0           precision_bits = fp.sig & (((u64)1 << precision_digits_count) - 1);
4375 0           precision_bits *= (u32)ERR_ULP;
4376 0           half_way = (u64)1 << (precision_digits_count - 1);
4377 0           half_way *= (u32)ERR_ULP;
4378              
4379             /* rounding */
4380 0           fp.sig >>= precision_digits_count;
4381 0           fp.sig += (precision_bits >= half_way + fp_err);
4382 0 0         fp.exp += precision_digits_count;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4383              
4384             /* get IEEE double raw value */
4385 0           raw = diy_fp_to_ieee_raw(fp);
4386 0 0         if (unlikely(raw == F64_BITS_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          
    0          
    0          
    0          
4387 0 0         if (likely(precision_bits <= half_way - fp_err ||
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4388             precision_bits >= half_way + fp_err)) {
4389 0           return_f64_bin(raw); /* number is accurate */
4390             }
4391             /* now the number is the correct value, or the next lower value */
4392              
4393             /* upper boundary */
4394 0 0         if (raw & F64_EXP_MASK) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4395 0           fp_upper.sig = (raw & F64_SIG_MASK) + ((u64)1 << F64_SIG_BITS);
4396 0           fp_upper.exp = (i32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
4397             } else {
4398 0           fp_upper.sig = (raw & F64_SIG_MASK);
4399 0           fp_upper.exp = 1;
4400             }
4401 0           fp_upper.exp -= F64_EXP_BIAS + F64_SIG_BITS;
4402 0           fp_upper.sig <<= 1;
4403 0           fp_upper.exp -= 1;
4404 0           fp_upper.sig += 1; /* add half ulp */
4405              
4406             /* compare with bigint */
4407 0           bigint_set_buf(&big_full, sig, &exp, sig_cut, sig_end, dot_pos);
4408 0           bigint_set_u64(&big_comp, fp_upper.sig);
4409 0 0         if (exp >= 0) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4410 0           bigint_mul_pow10(&big_full, +exp);
4411             } else {
4412 0           bigint_mul_pow10(&big_comp, -exp);
4413             }
4414 0 0         if (fp_upper.exp > 0) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4415 0 0         bigint_mul_pow2(&big_comp, (u32)+fp_upper.exp);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4416             } else {
4417 0 0         bigint_mul_pow2(&big_full, (u32)-fp_upper.exp);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4418             }
4419 0           cmp = bigint_cmp(&big_full, &big_comp);
4420 0 0         if (likely(cmp != 0)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4421             /* round down or round up */
4422 0           raw += (cmp > 0);
4423             } else {
4424             /* falls midway, round to even */
4425 0           raw += (raw & 1);
4426             }
4427              
4428 0 0         if (unlikely(raw == F64_BITS_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          
    0          
    0          
    0          
4429 0           return_f64_bin(raw);
4430             }
4431              
4432             #undef return_err
4433             #undef return_inf
4434             #undef return_0
4435             #undef return_i64
4436             #undef return_f64
4437             #undef return_f64_bin
4438             #undef return_raw
4439             }
4440              
4441              
4442              
4443             #else /* FP_READER */
4444              
4445             /**
4446             Read a JSON number.
4447             This is a fallback function if the custom number reader is disabled.
4448             This function use libc's strtod() to read floating-point number.
4449             */
4450             static_inline bool read_num(u8 **ptr, u8 **pre, yyjson_read_flag flg,
4451             yyjson_val *val, const char **msg) {
4452             #define return_err(_pos, _msg) do { \
4453             *msg = _msg; \
4454             *end = _pos; \
4455             return false; \
4456             } while (false)
4457              
4458             #define return_0() do { \
4459             val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); \
4460             val->uni.u64 = 0; \
4461             *end = cur; return true; \
4462             } while (false)
4463              
4464             #define return_i64(_v) do { \
4465             val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); \
4466             val->uni.u64 = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \
4467             *end = cur; return true; \
4468             } while (false)
4469              
4470             #define return_f64(_v) do { \
4471             val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
4472             val->uni.f64 = sign ? -(f64)(_v) : (f64)(_v); \
4473             *end = cur; return true; \
4474             } while (false)
4475              
4476             #define return_f64_bin(_v) do { \
4477             val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
4478             val->uni.u64 = ((u64)sign << 63) | (u64)(_v); \
4479             *end = cur; return true; \
4480             } while (false)
4481              
4482             #define return_inf() do { \
4483             if (has_flg(BIGNUM_AS_RAW)) return_raw(); \
4484             if (has_allow(INF_AND_NAN)) return_f64_bin(F64_BITS_INF); \
4485             else return_err(hdr, "number is infinity when parsed as double"); \
4486             } while (false)
4487              
4488             #define return_raw() do { \
4489             val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
4490             val->uni.str = (const char *)hdr; \
4491             **pre = '\0'; *pre = cur; *end = cur; return true; \
4492             } while (false)
4493              
4494             u64 sig, num;
4495             u8 *hdr = *ptr;
4496             u8 *cur = *ptr;
4497             u8 **end = ptr;
4498             u8 *dot = NULL;
4499             u8 *f64_end = NULL;
4500             bool sign;
4501              
4502             /* read number as raw string if has `YYJSON_READ_NUMBER_AS_RAW` flag */
4503             if (has_flg(NUMBER_AS_RAW)) {
4504             return read_num_raw(ptr, pre, flg, val, msg);
4505             }
4506              
4507             sign = (*hdr == '-');
4508             cur += sign;
4509             sig = (u8)(*cur - '0');
4510              
4511             /* read first digit, check leading zero */
4512             while (unlikely(!char_is_digit(*cur))) {
4513             if (has_allow(EXT_NUMBER)) {
4514             if (*cur == '+' && cur == hdr) { /* leading `+` sign */
4515             cur++;
4516             sig = (u8)(*cur - '0');
4517             continue;
4518             }
4519             if (*cur == '.' && char_is_num(cur[1])) { /* no integer part */
4520             goto read_double; /* e.g. '.123' */
4521             }
4522             }
4523             if (has_allow(INF_AND_NAN)) {
4524             if (read_inf_or_nan(ptr, pre, flg, val)) return true;
4525             }
4526             return_err(cur, "no digit after sign");
4527             }
4528             if (*cur == '0') {
4529             cur++;
4530             if (unlikely(char_is_digit(*cur))) {
4531             return_err(cur - 1, "number with leading zero is not allowed");
4532             }
4533             if (!char_is_fp(*cur)) {
4534             if (has_allow(EXT_NUMBER) &&
4535             (*cur == 'x' || *cur == 'X')) { /* hex integer */
4536             return read_num_hex(ptr, pre, flg, val, msg);
4537             }
4538             return_0();
4539             }
4540             goto read_double;
4541             }
4542              
4543             /* read continuous digits, up to 19 characters */
4544             #define expr_intg(i) \
4545             if (likely((num = (u64)(cur[i] - (u8)'0')) <= 9)) sig = num + sig * 10; \
4546             else { cur += i; goto intg_end; }
4547             repeat_in_1_18(expr_intg)
4548             #undef expr_intg
4549              
4550             /* here are 19 continuous digits, skip them */
4551             cur += 19;
4552             if (char_is_digit(cur[0]) && !char_is_digit_or_fp(cur[1])) {
4553             /* this number is an integer consisting of 20 digits */
4554             num = (u8)(*cur - '0');
4555             if ((sig < (U64_MAX / 10)) ||
4556             (sig == (U64_MAX / 10) && num <= (U64_MAX % 10))) {
4557             sig = num + sig * 10;
4558             cur++;
4559             if (sign) {
4560             if (has_flg(BIGNUM_AS_RAW)) return_raw();
4561             return_f64(unsafe_yyjson_u64_to_f64(sig));
4562             }
4563             return_i64(sig);
4564             }
4565             }
4566              
4567             intg_end:
4568             /* continuous digits ended */
4569             if (!char_is_digit_or_fp(*cur)) {
4570             /* this number is an integer consisting of 1 to 19 digits */
4571             if (sign && (sig > ((u64)1 << 63))) {
4572             if (has_flg(BIGNUM_AS_RAW)) return_raw();
4573             return_f64(unsafe_yyjson_u64_to_f64(sig));
4574             }
4575             return_i64(sig);
4576             }
4577              
4578             read_double:
4579             /* this number should be read as double */
4580             while (char_is_digit(*cur)) cur++;
4581             if (!char_is_fp(*cur) && has_flg(BIGNUM_AS_RAW)) {
4582             return_raw(); /* it's a large integer */
4583             }
4584             while (*cur == '.') {
4585             /* skip fraction part */
4586             dot = cur;
4587             cur++;
4588             if (!char_is_digit(*cur)) {
4589             if (has_allow(EXT_NUMBER)) {
4590             break;
4591             } else {
4592             return_err(cur, "no digit after decimal point");
4593             }
4594             }
4595             cur++;
4596             while (char_is_digit(*cur)) cur++;
4597             break;
4598             }
4599             if (char_is_exp(*cur)) {
4600             /* skip exponent part */
4601             cur += 1 + char_is_sign(cur[1]);
4602             if (!char_is_digit(*cur)) {
4603             return_err(cur, "no digit after exponent sign");
4604             }
4605             cur++;
4606             while (char_is_digit(*cur)) cur++;
4607             }
4608              
4609             /*
4610             libc's strtod() is used to parse the floating-point number.
4611              
4612             Note that the decimal point character used by strtod() is locale-dependent,
4613             and the rounding direction may affected by fesetround().
4614              
4615             For currently known locales, (en, zh, ja, ko, am, he, hi) use '.' as the
4616             decimal point, while other locales use ',' as the decimal point.
4617              
4618             Here strtod() is called twice for different locales, but if another thread
4619             happens calls setlocale() between two strtod(), parsing may still fail.
4620             */
4621             val->uni.f64 = strtod((const char *)hdr, (char **)&f64_end);
4622             if (unlikely(f64_end != cur)) {
4623             /* replace '.' with ',' for locale */
4624             bool cut = (*cur == ',');
4625             if (cut) *cur = ' ';
4626             if (dot) *dot = ',';
4627             val->uni.f64 = strtod((const char *)hdr, (char **)&f64_end);
4628             /* restore ',' to '.' */
4629             if (cut) *cur = ',';
4630             if (dot) *dot = '.';
4631             if (unlikely(f64_end != cur)) {
4632             return_err(hdr, "strtod() failed to parse the number");
4633             }
4634             }
4635             if (unlikely(val->uni.f64 >= HUGE_VAL || val->uni.f64 <= -HUGE_VAL)) {
4636             return_inf();
4637             }
4638             val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
4639             *end = cur;
4640             return true;
4641              
4642             #undef return_err
4643             #undef return_0
4644             #undef return_i64
4645             #undef return_f64
4646             #undef return_f64_bin
4647             #undef return_inf
4648             #undef return_raw
4649             }
4650              
4651             #endif /* FP_READER */
4652              
4653              
4654              
4655             /*==============================================================================
4656             * MARK: - String Reader (Private)
4657             *============================================================================*/
4658              
4659             /** Read unicode escape sequence. */
4660             static_inline bool read_uni_esc(u8 **src_ptr, u8 **dst_ptr, const char **msg) {
4661             #define return_err(_end, _msg) *msg = _msg; *src_ptr = _end; return false
4662              
4663 9           u8 *src = *src_ptr;
4664 9           u8 *dst = *dst_ptr;
4665             u16 hi, lo;
4666             u32 uni;
4667              
4668 0           src += 2; /* skip `\u` */
4669 9 0         if (unlikely(!hex_load_4(src, &hi))) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
4670 0           return_err(src - 2, "invalid escaped sequence in string");
4671             }
4672 9           src += 4; /* skip hex */
4673 9 0         if (likely((hi & 0xF800) != 0xD800)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    0          
    0          
    0          
4674             /* a BMP character */
4675 8 0         if (hi >= 0x800) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    0          
    0          
    0          
4676 3           *dst++ = (u8)(0xE0 | (hi >> 12));
4677 3           *dst++ = (u8)(0x80 | ((hi >> 6) & 0x3F));
4678 3           *dst++ = (u8)(0x80 | (hi & 0x3F));
4679 5 0         } else if (hi >= 0x80) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    0          
    0          
    0          
4680 3           *dst++ = (u8)(0xC0 | (hi >> 6));
4681 3           *dst++ = (u8)(0x80 | (hi & 0x3F));
4682             } else {
4683 2           *dst++ = (u8)hi;
4684             }
4685             } else {
4686             /* a non-BMP character, represented as a surrogate pair */
4687 1 0         if (unlikely((hi & 0xFC00) != 0xD800)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
4688 0           return_err(src - 6, "invalid high surrogate in string");
4689             }
4690 1 0         if (unlikely(!byte_match_2(src, "\\u"))) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
4691 0           return_err(src - 6, "no low surrogate in string");
4692             }
4693 2 0         if (unlikely(!hex_load_4(src + 2, &lo))) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
4694 0           return_err(src - 6, "invalid escape in string");
4695             }
4696 1 0         if (unlikely((lo & 0xFC00) != 0xDC00)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
4697 0           return_err(src - 6, "invalid low surrogate in string");
4698             }
4699 1           uni = ((((u32)hi - 0xD800) << 10) |
4700 1           ((u32)lo - 0xDC00)) + 0x10000;
4701 1           *dst++ = (u8)(0xF0 | (uni >> 18));
4702 1           *dst++ = (u8)(0x80 | ((uni >> 12) & 0x3F));
4703 1           *dst++ = (u8)(0x80 | ((uni >> 6) & 0x3F));
4704 1           *dst++ = (u8)(0x80 | (uni & 0x3F));
4705 1           src += 6;
4706             }
4707 9           *src_ptr = src;
4708 9           *dst_ptr = dst;
4709 9           return true;
4710             #undef return_err
4711             }
4712              
4713             /**
4714             Read a JSON string.
4715             @param quo The quote character (single quote or double quote).
4716             @param ptr The head pointer of string before quote (inout).
4717             @param eof JSON end position.
4718             @param flg JSON read flag.
4719             @param val The string value to be written.
4720             @param msg The error message pointer.
4721             @param con Continuation for incremental parsing.
4722             @return Whether success.
4723             */
4724             static_inline bool read_str_opt(u8 quo, u8 **ptr, u8 *eof, yyjson_read_flag flg,
4725             yyjson_val *val, const char **msg, u8 *con[2]) {
4726             /*
4727             GCC may sometimes load variables into registers too early, causing
4728             unnecessary instructions and performance degradation. This inline assembly
4729             serves as a hint to GCC: 'This variable will be modified, so avoid loading
4730             it too early.' Other compilers like MSVC, Clang, and ICC can generate the
4731             expected instructions without needing this hint.
4732              
4733             Check out this example: https://godbolt.org/z/YG6a5W5Ec
4734             */
4735             #define return_err(_end, _msg) do { \
4736             *msg = _msg; \
4737             *end = _end; \
4738             if (con) { con[0] = _end; con[1] = dst; } \
4739             return false; \
4740             } while (false)
4741              
4742 16234           u8 *hdr = *ptr + 1;
4743 16234           u8 **end = ptr;
4744 16234           u8 *src = hdr, *dst = NULL, *pos;
4745             u16 hi, lo;
4746             u32 uni, tmp;
4747              
4748             /* Resume incremental parsing. */
4749 2 0         if (con && unlikely(con[0])) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
4750 0           src = con[0];
4751 0           dst = con[1];
4752 0 0         if (dst) goto copy_ascii;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4753             }
4754              
4755 28487           skip_ascii:
4756             /*
4757             Most strings have no escaped characters, so we can jump them quickly.
4758              
4759             We want to make loop unrolling, as shown in the following code. Some
4760             compiler may not generate instructions as expected, so we rewrite it with
4761             explicit goto statements. We hope the compiler can generate instructions
4762             like this: https://godbolt.org/z/8vjsYq
4763              
4764             while (true) repeat16({
4765             if (likely((char_is_ascii_skip(*src)))) src++;
4766             else break;
4767             })
4768             */
4769 28487 0         if (quo == '"') {
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
4770             #define expr_jump(i) \
4771             if (likely(char_is_ascii_skip(src[i]))) {} \
4772             else goto skip_ascii_stop##i;
4773              
4774             #define expr_stop(i) \
4775             skip_ascii_stop##i: \
4776             src += i; \
4777             goto skip_ascii_end;
4778              
4779 270047 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          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    100          
    100          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    100          
    100          
    100          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    100          
    50          
    100          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    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          
4780 12250           src += 16;
4781 12250           goto skip_ascii;
4782 16237           repeat16_incr(expr_stop)
4783              
4784             #undef expr_jump
4785             #undef expr_stop
4786             } else {
4787             #define expr_jump(i) \
4788             if (likely(char_is_ascii_skip_sq(src[i]))) {} \
4789             else goto skip_ascii_stop_sq##i;
4790              
4791             #define expr_stop(i) \
4792             skip_ascii_stop_sq##i: \
4793             src += i; \
4794             goto skip_ascii_end;
4795              
4796 0 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          
    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          
    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          
    0          
    0          
4797 0           src += 16;
4798 0           goto skip_ascii;
4799 0           repeat16_incr(expr_stop)
4800              
4801             #undef expr_jump
4802             #undef expr_stop
4803             }
4804              
4805 16237           skip_ascii_end:
4806 16237           gcc_store_barrier(*src);
4807 16237           if (likely(*src == quo)) {
4808 32454           val->tag = ((u64)(src - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR |
4809 16227 0         (quo == '"' ? YYJSON_SUBTYPE_NOESC : 0);
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
4810 16227           val->uni.str = (const char *)hdr;
4811 16227           *src = '\0';
4812 16227           *end = src + 1;
4813 16227 0         if (con) con[0] = con[1] = NULL;
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
4814 16227           return true;
4815             }
4816              
4817 10           skip_utf8:
4818 10 0         if (*src & 0x80) { /* non-ASCII character */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    0          
    0          
4819             /*
4820             Non-ASCII character appears here, which means that the text is likely
4821             to be written in non-English or emoticons. According to some common
4822             data set statistics, byte sequences of the same length may appear
4823             consecutively. We process the byte sequences of the same length in each
4824             loop, which is more friendly to branch prediction.
4825             */
4826 3           pos = src;
4827             #if YYJSON_DISABLE_UTF8_VALIDATION
4828             while (true) repeat8({
4829             if (likely((*src & 0xF0) == 0xE0)) src += 3;
4830             else break;
4831             })
4832             if (*src < 0x80) goto skip_ascii;
4833             while (true) repeat8({
4834             if (likely((*src & 0xE0) == 0xC0)) src += 2;
4835             else break;
4836             })
4837             while (true) repeat8({
4838             if (likely((*src & 0xF8) == 0xF0)) src += 4;
4839             else break;
4840             })
4841             #else
4842 3           uni = byte_load_4(src);
4843 4 0         while (is_utf8_seq3(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          
    100          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
4844 1           src += 3;
4845 2           uni = byte_load_4(src);
4846             }
4847 3 0         if (is_utf8_seq1(uni)) goto skip_ascii;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    0          
    0          
4848 2 0         while (is_utf8_seq2(uni)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
4849 0           src += 2;
4850 0           uni = byte_load_4(src);
4851             }
4852 4 0         while (is_utf8_seq4(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          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4853 2           src += 4;
4854 4           uni = byte_load_4(src);
4855             }
4856             #endif
4857 2 0         if (unlikely(pos == src)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
4858 0 0         if (has_allow(INVALID_UNICODE)) ++src;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4859 0 0         else return_err(src, "invalid UTF-8 encoding in string");
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4860             }
4861 2           goto skip_ascii;
4862             }
4863              
4864             /* The escape character appears, we need to copy it. */
4865 7           dst = src;
4866 16           copy_escape:
4867 16 0         if (likely(*src == '\\')) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    0          
    0          
4868 9           switch (*++src) {
4869 0           case '"': *dst++ = '"'; src++; break;
4870 0           case '\\': *dst++ = '\\'; src++; break;
4871 0           case '/': *dst++ = '/'; src++; break;
4872 0           case 'b': *dst++ = '\b'; src++; break;
4873 0           case 'f': *dst++ = '\f'; src++; break;
4874 0           case 'n': *dst++ = '\n'; src++; break;
4875 0           case 'r': *dst++ = '\r'; src++; break;
4876 0           case 't': *dst++ = '\t'; src++; break;
4877 9           case 'u':
4878 9           src--;
4879 9 0         if (!read_uni_esc(&src, &dst, msg)) return_err(src, *msg);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
4880 9           break;
4881 0           default: {
4882 0 0         if (has_allow(EXT_ESCAPE)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4883             /* read extended escape (non-standard) */
4884 0           switch (*src) {
4885 0           case '\'': *dst++ = '\''; src++; break;
4886 0           case 'a': *dst++ = '\a'; src++; break;
4887 0           case 'v': *dst++ = '\v'; src++; break;
4888 0           case '?': *dst++ = '\?'; src++; break;
4889 0           case 'e': *dst++ = 0x1B; src++; break;
4890 0           case '0':
4891 0 0         if (!char_is_digit(src[1])) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4892 0           *dst++ = '\0'; src++; break;
4893             }
4894 0 0         return_err(src - 1, "octal escape is not allowed");
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4895 0           case '1': case '2': case '3': case '4':
4896             case '5': case '6': case '7': case '8': case '9':
4897 0 0         return_err(src - 1, "invalid number escape");
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4898 0           case 'x': {
4899             u8 c;
4900 0 0         if (hex_load_2(src + 1, &c)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4901 0           src += 3;
4902 0 0         if (c <= 0x7F) { /* 1-byte ASCII */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4903 0           *dst++ = c;
4904             } else { /* 2-byte UTF-8 */
4905 0           *dst++ = (u8)(0xC0 | (c >> 6));
4906 0           *dst++ = (u8)(0x80 | (c & 0x3F));
4907             }
4908 0           break;
4909             }
4910 0 0         return_err(src - 1, "invalid hex escape");
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4911             }
4912 0           case '\n': src++; break;
4913 0           case '\r': src++; src += (*src == '\n'); break;
4914 0           case 0xE2: /* Line terminator: U+2028, U+2029 */
4915 0 0         if ((src[1] == 0x80 && src[2] == 0xA8) ||
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4916 0 0         (src[1] == 0x80 && src[2] == 0xA9)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4917 0           src += 3;
4918             }
4919 0           break;
4920 0           default:
4921 0           break; /* skip */
4922             }
4923 0 0         } else if (quo == '\'' && *src == '\'') {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4924 0           *dst++ = '\''; src++; break;
4925             } else {
4926 0 0         return_err(src - 1, "invalid escaped sequence in string");
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4927             }
4928             }
4929             }
4930 7 0         } else if (likely(*src == quo)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
4931 7           val->tag = ((u64)(dst - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR;
4932 7           val->uni.str = (const char *)hdr;
4933 7           *dst = '\0';
4934 7           *end = src + 1;
4935 7 0         if (con) con[0] = con[1] = NULL;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
4936 7           return true;
4937             } else {
4938 0 0         if (!has_allow(INVALID_UNICODE)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4939 0 0         return_err(src, "unexpected control character in string");
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4940             }
4941 0 0         if (src >= eof) return_err(src, "unclosed string");
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4942 0           *dst++ = *src++;
4943             }
4944              
4945 0           copy_ascii:
4946             /*
4947             Copy continuous ASCII, loop unrolling, same as the following code:
4948              
4949             while (true) repeat16({
4950             if (char_is_ascii_skip(*src)) *dst++ = *src++;
4951             else break;
4952             })
4953             */
4954 9 0         if (quo == '"') {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
4955             #define expr_jump(i) \
4956             if (likely((char_is_ascii_skip(src[i])))) {} \
4957             else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; }
4958 26 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          
    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          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    100          
    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          
4959             #undef expr_jump
4960             } else {
4961             #define expr_jump(i) \
4962             if (likely((char_is_ascii_skip_sq(src[i])))) {} \
4963             else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; }
4964 0 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          
    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          
    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          
    0          
    0          
4965             #undef expr_jump
4966             }
4967              
4968 0           byte_move_16(dst, src);
4969 0           dst += 16; src += 16;
4970 0           goto copy_ascii;
4971              
4972             /*
4973             The memory is copied forward since `dst < src`.
4974             So it's safe to move one extra byte to reduce instruction count.
4975             */
4976             #define expr_jump(i) \
4977             copy_ascii_stop_##i: \
4978             byte_move_forward(dst, src, i); \
4979             dst += i; src += i; \
4980             goto copy_utf8;
4981 18 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          
    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          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    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          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4982             #undef expr_jump
4983              
4984 9           copy_utf8:
4985 9 0         if (*src & 0x80) { /* non-ASCII character */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
4986 0           pos = src;
4987 0           uni = byte_load_4(src);
4988             #if YYJSON_DISABLE_UTF8_VALIDATION
4989             while (true) repeat4({
4990             if ((uni & utf8_seq(b3_mask)) == utf8_seq(b3_patt)) {
4991             byte_copy_4(dst, &uni);
4992             dst += 3; src += 3;
4993             uni = byte_load_4(src);
4994             } else break;
4995             })
4996             if ((uni & utf8_seq(b1_mask)) == utf8_seq(b1_patt)) goto copy_ascii;
4997             while (true) repeat4({
4998             if ((uni & utf8_seq(b2_mask)) == utf8_seq(b2_patt)) {
4999             byte_copy_2(dst, &uni);
5000             dst += 2; src += 2;
5001             uni = byte_load_4(src);
5002             } else break;
5003             })
5004             while (true) repeat4({
5005             if ((uni & utf8_seq(b4_mask)) == utf8_seq(b4_patt)) {
5006             byte_copy_4(dst, &uni);
5007             dst += 4; src += 4;
5008             uni = byte_load_4(src);
5009             } else break;
5010             })
5011             #else
5012 0 0         while (is_utf8_seq3(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          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
5013 0           byte_copy_4(dst, &uni);
5014 0           dst += 3; src += 3;
5015 0           uni = byte_load_4(src);
5016             }
5017 0 0         if (is_utf8_seq1(uni)) goto copy_ascii;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
5018 0 0         while (is_utf8_seq2(uni)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
5019 0           byte_copy_2(dst, &uni);
5020 0           dst += 2; src += 2;
5021 0           uni = byte_load_4(src);
5022             }
5023 0 0         while (is_utf8_seq4(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          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
5024 0           byte_copy_4(dst, &uni);
5025 0           dst += 4; src += 4;
5026 0           uni = byte_load_4(src);
5027             }
5028             #endif
5029 0 0         if (unlikely(pos == src)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
5030 0 0         if (!has_allow(INVALID_UNICODE)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
5031 0 0         return_err(src, MSG_ERR_UTF8);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
5032             }
5033 0           goto copy_ascii_stop_1;
5034             }
5035 0           goto copy_ascii;
5036             }
5037 9           goto copy_escape;
5038              
5039             #undef return_err
5040             }
5041              
5042             static_inline bool read_str(u8 **ptr, u8 *eof, yyjson_read_flag flg,
5043             yyjson_val *val, const char **msg) {
5044 16234           return read_str_opt('\"', ptr, eof, flg, val, msg, NULL);
5045             }
5046              
5047             static_inline bool read_str_con(u8 **ptr, u8 *eof, yyjson_read_flag flg,
5048             yyjson_val *val, const char **msg, u8 **con) {
5049 0           return read_str_opt('\"', ptr, eof, flg, val, msg, con);
5050             }
5051              
5052 0 0         static_noinline bool read_str_sq(u8 **ptr, u8 *eof, yyjson_read_flag flg,
5053             yyjson_val *val, const char **msg) {
5054 0           return read_str_opt('\'', ptr, eof, flg, val, msg, NULL);
5055             }
5056              
5057             /** Read unquoted key (identifier name). */
5058 0           static_noinline bool read_str_id(u8 **ptr, u8 *eof, yyjson_read_flag flg,
5059             u8 **pre, yyjson_val *val, const char **msg) {
5060             #define return_err(_end, _msg) do { \
5061             *msg = _msg; \
5062             *end = _end; \
5063             return false; \
5064             } while (false)
5065              
5066             #define return_suc(_str_end, _cur_end) do { \
5067             val->tag = ((u64)(_str_end - hdr) << YYJSON_TAG_BIT) | \
5068             (u64)(YYJSON_TYPE_STR); \
5069             val->uni.str = (const char *)hdr; \
5070             *pre = _str_end; *end = _cur_end; \
5071             return true; \
5072             } while (false)
5073              
5074 0           u8 *hdr = *ptr;
5075 0           u8 **end = ptr;
5076 0           u8 *src = hdr, *dst = NULL;
5077             u16 hi, lo;
5078             u32 uni, tmp;
5079              
5080             /* add null-terminator for previous raw string */
5081 0           **pre = '\0';
5082              
5083 0           skip_ascii:
5084             #define expr_jump(i) \
5085             if (likely(char_is_id_ascii(src[i]))) {} \
5086             else goto skip_ascii_stop##i;
5087              
5088             #define expr_stop(i) \
5089             skip_ascii_stop##i: \
5090             src += i; \
5091             goto skip_ascii_end;
5092              
5093 0 0         repeat16_incr(expr_jump)
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
5094 0           src += 16;
5095 0           goto skip_ascii;
5096 0           repeat16_incr(expr_stop)
5097              
5098             #undef expr_jump
5099             #undef expr_stop
5100              
5101 0           skip_ascii_end:
5102 0           gcc_store_barrier(*src);
5103 0 0         if (likely(!char_is_id_next(*src))) {
5104 0           return_suc(src, src);
5105             }
5106              
5107 0           skip_utf8:
5108 0 0         while (*src >= 0x80) {
5109 0 0         if (has_allow(EXT_WHITESPACE)) {
5110 0 0         if (char_is_space_ext(*src) && ext_space_len(src)) {
    0          
    0          
5111 0           return_suc(src, src);
5112             }
5113             }
5114 0           uni = byte_load_4(src);
5115 0 0         if (is_utf8_seq2(uni)) {
    0          
5116 0           src += 2;
5117 0 0         } else if (is_utf8_seq3(uni)) {
    0          
    0          
5118 0           src += 3;
5119 0 0         } else if (is_utf8_seq4(uni)) {
    0          
    0          
    0          
5120 0           src += 4;
5121             } else {
5122             #if !YYJSON_DISABLE_UTF8_VALIDATION
5123 0 0         if (!has_allow(INVALID_UNICODE)) return_err(src, MSG_ERR_UTF8);
5124             #endif
5125 0           src += 1;
5126             }
5127             }
5128 0 0         if (char_is_id_ascii(*src)) goto skip_ascii;
5129              
5130             /* The escape character appears, we need to copy it. */
5131 0           dst = src;
5132 0           copy_escape:
5133 0 0         if (byte_match_2(src, "\\u")) {
5134 0 0         if (!read_uni_esc(&src, &dst, msg)) return_err(src, *msg);
5135             } else {
5136 0 0         if (!char_is_id_next(*src)) return_suc(dst, src);
5137 0           return_err(src, "unexpected character in key");
5138             }
5139              
5140 0           copy_ascii:
5141             /*
5142             Copy continuous ASCII, loop unrolling, same as the following code:
5143              
5144             while (true) repeat16({
5145             if (char_is_ascii_skip(*src)) *dst++ = *src++;
5146             else break;
5147             })
5148             */
5149             #define expr_jump(i) \
5150             if (likely((char_is_id_ascii(src[i])))) {} \
5151             else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; }
5152 0 0         repeat16_incr(expr_jump)
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
5153             #undef expr_jump
5154              
5155 0           byte_move_16(dst, src);
5156 0           dst += 16; src += 16;
5157 0           goto copy_ascii;
5158              
5159             #define expr_jump(i) \
5160             copy_ascii_stop_##i: \
5161             byte_move_forward(dst, src, i); \
5162             dst += i; src += i; \
5163             goto copy_utf8;
5164 0 0         repeat16_incr(expr_jump)
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
5165             #undef expr_jump
5166              
5167 0           copy_utf8:
5168 0 0         while (*src >= 0x80) { /* non-ASCII character */
5169 0 0         if (has_allow(EXT_WHITESPACE)) {
5170 0 0         if (char_is_space_ext(*src) && ext_space_len(src)) {
    0          
    0          
5171 0           return_suc(dst, src);
5172             }
5173             }
5174 0           uni = byte_load_4(src);
5175 0 0         if (is_utf8_seq2(uni)) {
    0          
5176 0           byte_copy_2(dst, &uni);
5177 0           dst += 2; src += 2;
5178 0 0         } else if (is_utf8_seq3(uni)) {
    0          
    0          
5179 0           byte_copy_4(dst, &uni);
5180 0           dst += 3; src += 3;
5181 0 0         } else if (is_utf8_seq4(uni)) {
    0          
    0          
    0          
5182 0           byte_copy_4(dst, &uni);
5183 0           dst += 4; src += 4;
5184             } else {
5185             #if !YYJSON_DISABLE_UTF8_VALIDATION
5186 0 0         if (!has_allow(INVALID_UNICODE)) return_err(src, MSG_ERR_UTF8);
5187             #endif
5188 0           *dst = *src;
5189 0           dst += 1; src += 1;
5190             }
5191             }
5192 0 0         if (char_is_id_ascii(*src)) goto copy_ascii;
5193 0           goto copy_escape;
5194              
5195             #undef return_err
5196             #undef return_suc
5197             }
5198              
5199              
5200              
5201             /*==============================================================================
5202             * MARK: - JSON Reader Implementation (Private)
5203             *
5204             * We use goto statements to build the finite state machine (FSM).
5205             * The FSM's state was held by program counter (PC) and the 'goto' make the
5206             * state transitions.
5207             *============================================================================*/
5208              
5209             /** Read single value JSON document. */
5210 14           static_noinline yyjson_doc *read_root_single(u8 *hdr, u8 *cur, u8 *eof,
5211             yyjson_alc alc,
5212             yyjson_read_flag flg,
5213             yyjson_read_err *err) {
5214             #define return_err(_pos, _code, _msg) do { \
5215             if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \
5216             err->pos = (usize)(eof - hdr); \
5217             err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
5218             err->msg = MSG_NOT_END; \
5219             } else { \
5220             err->pos = (usize)(_pos - hdr); \
5221             err->code = YYJSON_READ_ERROR_##_code; \
5222             err->msg = _msg; \
5223             } \
5224             if (val_hdr) alc.free(alc.ctx, val_hdr); \
5225             return NULL; \
5226             } while (false)
5227              
5228             usize hdr_len; /* value count used by doc */
5229             usize alc_num; /* value count capacity */
5230             yyjson_val *val_hdr; /* the head of allocated values */
5231             yyjson_val *val; /* current value */
5232             yyjson_doc *doc; /* the JSON document, equals to val_hdr */
5233             const char *msg; /* error message */
5234              
5235             u8 raw_end[1]; /* raw end for null-terminator */
5236 14           u8 *raw_ptr = raw_end;
5237 14           u8 **pre = &raw_ptr; /* previous raw end pointer */
5238              
5239 14           hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
5240 14           hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
5241 14           alc_num = hdr_len + 1; /* single value */
5242              
5243 14           val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_num * sizeof(yyjson_val));
5244 14 50         if (unlikely(!val_hdr)) goto fail_alloc;
5245 14           val = val_hdr + hdr_len;
5246              
5247 28 100         if (char_is_num(*cur)) {
5248 4 50         if (likely(read_num(&cur, pre, flg, val, &msg))) goto doc_end;
5249 0           goto fail_number;
5250             }
5251 10 100         if (*cur == '"') {
5252 2 50         if (likely(read_str(&cur, eof, flg, val, &msg))) goto doc_end;
5253 0           goto fail_string;
5254             }
5255 8 100         if (*cur == 't') {
5256 2 50         if (likely(read_true(&cur, val))) goto doc_end;
5257 0           goto fail_literal_true;
5258             }
5259 6 100         if (*cur == 'f') {
5260 1 50         if (likely(read_false(&cur, val))) goto doc_end;
5261 0           goto fail_literal_false;
5262             }
5263 5 100         if (*cur == 'n') {
5264 4 100         if (likely(read_null(&cur, val))) goto doc_end;
5265 6 50         if (has_allow(INF_AND_NAN)) {
5266 0 0         if (read_nan(&cur, pre, flg, val)) goto doc_end;
5267             }
5268 3           goto fail_literal_null;
5269             }
5270 2 50         if (has_allow(INF_AND_NAN)) {
5271 0 0         if (read_inf_or_nan(&cur, pre, flg, val)) goto doc_end;
5272             }
5273 2 50         if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
    0          
5274 0 0         if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto doc_end;
5275 0           goto fail_string;
5276             }
5277 1           goto fail_character;
5278              
5279 10           doc_end:
5280             /* check invalid contents after json document */
5281 10 50         if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) {
    0          
5282 0 0         while (char_is_space(*cur)) cur++;
5283 0 0         if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
    0          
5284 0 0         if (!skip_trivia(&cur, eof, flg) && cur == eof) {
    0          
5285 0           goto fail_comment;
5286             }
5287             }
5288 0 0         if (unlikely(cur < eof)) goto fail_garbage;
5289             }
5290              
5291 10           **pre = '\0';
5292 10           doc = (yyjson_doc *)val_hdr;
5293 10           doc->root = val_hdr + hdr_len;
5294 10           doc->alc = alc;
5295 10           doc->dat_read = (usize)(cur - hdr);
5296 10           doc->val_read = 1;
5297 20 50         doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
5298 10           return doc;
5299              
5300 0 0         fail_string: return_err(cur, INVALID_STRING, msg);
    0          
5301 0 0         fail_number: return_err(cur, INVALID_NUMBER, msg);
    0          
5302 0 0         fail_alloc: return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
    0          
5303 0 0         fail_literal_true: return_err(cur, LITERAL, MSG_CHAR_T);
    0          
5304 0 0         fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F);
    0          
5305 3 50         fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N);
    50          
5306 1 50         fail_character: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
    50          
5307 0 0         fail_comment: return_err(cur, INVALID_COMMENT, MSG_COMMENT);
    0          
5308 0 0         fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
    0          
5309              
5310             #undef return_err
5311             }
5312              
5313             /** Read JSON document (accept all style, but optimized for minify). */
5314             static_inline yyjson_doc *read_root_minify(u8 *hdr, u8 *cur, u8 *eof,
5315             yyjson_alc alc,
5316             yyjson_read_flag flg,
5317             yyjson_read_err *err) {
5318             #define return_err(_pos, _code, _msg) do { \
5319             if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \
5320             err->pos = (usize)(eof - hdr); \
5321             err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
5322             err->msg = MSG_NOT_END; \
5323             } else { \
5324             err->pos = (usize)(_pos - hdr); \
5325             err->code = YYJSON_READ_ERROR_##_code; \
5326             err->msg = _msg; \
5327             } \
5328             if (val_hdr) alc.free(alc.ctx, val_hdr); \
5329             return NULL; \
5330             } while (false)
5331              
5332             #define val_incr() do { \
5333             val++; \
5334             if (unlikely(val >= val_end)) { \
5335             usize alc_old = alc_len; \
5336             usize val_ofs = (usize)(val - val_hdr); \
5337             usize ctn_ofs = (usize)(ctn - val_hdr); \
5338             alc_len += alc_len / 2; \
5339             if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \
5340             val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
5341             alc_old * sizeof(yyjson_val), \
5342             alc_len * sizeof(yyjson_val)); \
5343             if ((!val_tmp)) goto fail_alloc; \
5344             val = val_tmp + val_ofs; \
5345             ctn = val_tmp + ctn_ofs; \
5346             val_hdr = val_tmp; \
5347             val_end = val_tmp + (alc_len - 2); \
5348             } \
5349             } while (false)
5350              
5351             usize dat_len; /* data length in bytes, hint for allocator */
5352             usize hdr_len; /* value count used by yyjson_doc */
5353             usize alc_len; /* value count allocated */
5354             usize alc_max; /* maximum value count for allocator */
5355             usize ctn_len; /* the number of elements in current container */
5356             yyjson_val *val_hdr; /* the head of allocated values */
5357             yyjson_val *val_end; /* the end of allocated values */
5358             yyjson_val *val_tmp; /* temporary pointer for realloc */
5359             yyjson_val *val; /* current JSON value */
5360             yyjson_val *ctn; /* current container */
5361             yyjson_val *ctn_parent; /* parent of current container */
5362             yyjson_doc *doc; /* the JSON document, equals to val_hdr */
5363             const char *msg; /* error message */
5364              
5365             u8 raw_end[1]; /* raw end for null-terminator */
5366 10101           u8 *raw_ptr = raw_end;
5367 10101           u8 **pre = &raw_ptr; /* previous raw end pointer */
5368              
5369 10101 50         dat_len = has_flg(STOP_WHEN_DONE) ? 256 : (usize)(eof - cur);
5370 10101           hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
5371 10101           hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
5372 10101           alc_max = USIZE_MAX / sizeof(yyjson_val);
5373 10101           alc_len = hdr_len + (dat_len / YYJSON_READER_ESTIMATED_MINIFY_RATIO) + 4;
5374 10101           alc_len = yyjson_min(alc_len, alc_max);
5375              
5376 10101           val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_len * sizeof(yyjson_val));
5377 10101 50         if (unlikely(!val_hdr)) goto fail_alloc;
5378 10101           val_end = val_hdr + (alc_len - 2); /* padding for key-value pair reading */
5379 10101           val = val_hdr + hdr_len;
5380 10101           ctn = val;
5381 10101           ctn_len = 0;
5382              
5383 10101 100         if (*cur++ == '{') {
5384 10077           ctn->tag = YYJSON_TYPE_OBJ;
5385 10077           ctn->uni.ofs = 0;
5386 10077           goto obj_key_begin;
5387             } else {
5388 24           ctn->tag = YYJSON_TYPE_ARR;
5389 24           ctn->uni.ofs = 0;
5390 24           goto arr_val_begin;
5391             }
5392              
5393 226           arr_begin:
5394             /* save current container */
5395 226           ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
5396 226           (ctn->tag & YYJSON_TAG_MASK);
5397              
5398             /* create a new array value, save parent container offset */
5399 226 100         val_incr();
    50          
5400 226           val->tag = YYJSON_TYPE_ARR;
5401 226           val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
5402              
5403             /* push the new array value as current container */
5404 226           ctn = val;
5405 226           ctn_len = 0;
5406              
5407 0           arr_val_begin:
5408 22300 100         if (*cur == '{') {
5409 2015           cur++;
5410 2015           goto obj_begin;
5411             }
5412 20285 100         if (*cur == '[') {
5413 201           cur++;
5414 201           goto arr_begin;
5415             }
5416 40168 100         if (char_is_num(*cur)) {
5417 20067 100         val_incr();
    50          
5418 20067           ctn_len++;
5419 20067 50         if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_end;
5420 0           goto fail_number;
5421             }
5422 17 100         if (*cur == '"') {
5423 7 50         val_incr();
    0          
5424 7 50         ctn_len++;
5425 7 50         if (likely(read_str(&cur, eof, flg, val, &msg))) goto arr_val_end;
5426 0           goto fail_string;
5427             }
5428 10 100         if (*cur == 't') {
5429 2 100         val_incr();
    50          
5430 2           ctn_len++;
5431 2 50         if (likely(read_true(&cur, val))) goto arr_val_end;
5432 0           goto fail_literal_true;
5433             }
5434 8 100         if (*cur == 'f') {
5435 1 50         val_incr();
    0          
5436 1           ctn_len++;
5437 1 50         if (likely(read_false(&cur, val))) goto arr_val_end;
5438 0           goto fail_literal_false;
5439             }
5440 7 100         if (*cur == 'n') {
5441 3 50         val_incr();
    0          
5442 3           ctn_len++;
5443 3 50         if (likely(read_null(&cur, val))) goto arr_val_end;
5444 0 0         if (has_allow(INF_AND_NAN)) {
5445 0 0         if (read_nan(&cur, pre, flg, val)) goto arr_val_end;
5446             }
5447 0           goto fail_literal_null;
5448             }
5449 4 50         if (*cur == ']') {
5450 4           cur++;
5451 4 50         if (likely(ctn_len == 0)) goto arr_end;
5452 0 0         if (has_allow(TRAILING_COMMAS)) goto arr_end;
5453 0 0         while (*cur != ',') cur--;
5454 0           goto fail_trailing_comma;
5455             }
5456 0 0         if (char_is_space(*cur)) {
5457 0 0         while (char_is_space(*++cur));
5458 0           goto arr_val_begin;
5459             }
5460 0 0         if (has_allow(INF_AND_NAN) &&
5461 0 0         (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
    0          
    0          
5462 0 0         val_incr();
    0          
5463 0 0         ctn_len++;
5464 0 0         if (read_inf_or_nan(&cur, pre, flg, val)) goto arr_val_end;
5465 0           goto fail_character_val;
5466             }
5467 0 0         if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
    0          
5468 0 0         val_incr();
    0          
5469 0           ctn_len++;
5470 0 0         if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto arr_val_end;
5471 0           goto fail_string;
5472             }
5473 0 0         if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
    0          
5474 0 0         if (skip_trivia(&cur, eof, flg)) goto arr_val_begin;
5475 0 0         if (cur == eof) goto fail_comment;
5476             }
5477 0           goto fail_character_val;
5478              
5479 0           arr_val_end:
5480 22296 100         if (*cur == ',') {
5481 22050           cur++;
5482 22050           goto arr_val_begin;
5483             }
5484 246 50         if (*cur == ']') {
5485 246           cur++;
5486 246           goto arr_end;
5487             }
5488 0 0         if (char_is_space(*cur)) {
5489 0 0         while (char_is_space(*++cur));
5490 0           goto arr_val_end;
5491             }
5492 0 0         if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
    0          
5493 0 0         if (skip_trivia(&cur, eof, flg)) goto arr_val_end;
5494 0 0         if (cur == eof) goto fail_comment;
5495             }
5496 0           goto fail_character_arr_end;
5497              
5498 250           arr_end:
5499             /* get parent container */
5500 250           ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
5501              
5502             /* save the next sibling value offset */
5503 250           ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
5504 250           ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
5505 250 100         if (unlikely(ctn == ctn_parent)) goto doc_end;
5506              
5507             /* pop parent as current container */
5508 226           ctn = ctn_parent;
5509 226           ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
5510 226 100         if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
5511 25           goto obj_val_end;
5512             } else {
5513 201           goto arr_val_end;
5514             }
5515              
5516 2034           obj_begin:
5517             /* push container */
5518 2034           ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
5519 2034           (ctn->tag & YYJSON_TAG_MASK);
5520 2034 100         val_incr();
    50          
5521 2034           val->tag = YYJSON_TYPE_OBJ;
5522             /* offset to the parent */
5523 2034           val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
5524 2034           ctn = val;
5525 2034           ctn_len = 0;
5526              
5527 0           obj_key_begin:
5528 15175 100         if (likely(*cur == '"')) {
5529 15169 100         val_incr();
    50          
5530 15169 50         ctn_len++;
5531 15169 50         if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_key_end;
5532 0           goto fail_string;
5533             }
5534 6 50         if (likely(*cur == '}')) {
5535 6           cur++;
5536 6 50         if (likely(ctn_len == 0)) goto obj_end;
5537 0 0         if (has_allow(TRAILING_COMMAS)) goto obj_end;
5538 0 0         while (*cur != ',') cur--;
5539 0           goto fail_trailing_comma;
5540             }
5541 0 0         if (char_is_space(*cur)) {
5542 0 0         while (char_is_space(*++cur));
5543 0           goto obj_key_begin;
5544             }
5545 0 0         if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
    0          
5546 0 0         val_incr();
    0          
5547 0           ctn_len++;
5548 0 0         if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_key_end;
5549 0           goto fail_string;
5550             }
5551 0 0         if (has_allow(UNQUOTED_KEY) && char_is_id_start(*cur)) {
    0          
5552 0 0         val_incr();
    0          
5553 0           ctn_len++;
5554 0 0         if (read_str_id(&cur, eof, flg, pre, val, &msg)) goto obj_key_end;
5555 0           goto fail_string;
5556             }
5557 0 0         if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
    0          
5558 0 0         if (skip_trivia(&cur, eof, flg)) goto obj_key_begin;
5559 0 0         if (cur == eof) goto fail_comment;
5560             }
5561 0           goto fail_character_obj_key;
5562              
5563 0           obj_key_end:
5564 15169 50         if (*cur == ':') {
5565 15169           cur++;
5566 15169           goto obj_val_begin;
5567             }
5568 0 0         if (char_is_space(*cur)) {
5569 0 0         while (char_is_space(*++cur));
5570 0           goto obj_key_end;
5571             }
5572 0 0         if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
    0          
5573 0 0         if (skip_trivia(&cur, eof, flg)) goto obj_key_end;
5574 0 0         if (cur == eof) goto fail_comment;
5575             }
5576 0           goto fail_character_obj_sep;
5577              
5578 0           obj_val_begin:
5579 15169 100         if (*cur == '"') {
5580 1039           val++;
5581 1039 50         ctn_len++;
5582 1039 50         if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_val_end;
5583 0           goto fail_string;
5584             }
5585 28260 100         if (char_is_num(*cur)) {
5586 14073           val++;
5587 14073           ctn_len++;
5588 14073 50         if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_end;
5589 0           goto fail_number;
5590             }
5591 57 100         if (*cur == '{') {
5592 19           cur++;
5593 19           goto obj_begin;
5594             }
5595 38 100         if (*cur == '[') {
5596 25           cur++;
5597 25           goto arr_begin;
5598             }
5599 13 100         if (*cur == 't') {
5600 7           val++;
5601 7           ctn_len++;
5602 7 50         if (likely(read_true(&cur, val))) goto obj_val_end;
5603 0           goto fail_literal_true;
5604             }
5605 6 100         if (*cur == 'f') {
5606 3           val++;
5607 3           ctn_len++;
5608 3 50         if (likely(read_false(&cur, val))) goto obj_val_end;
5609 0           goto fail_literal_false;
5610             }
5611 3 50         if (*cur == 'n') {
5612 3           val++;
5613 3           ctn_len++;
5614 3 50         if (likely(read_null(&cur, val))) goto obj_val_end;
5615 0 0         if (has_allow(INF_AND_NAN)) {
5616 0 0         if (read_nan(&cur, pre, flg, val)) goto obj_val_end;
5617             }
5618 0           goto fail_literal_null;
5619             }
5620 0 0         if (char_is_space(*cur)) {
5621 0 0         while (char_is_space(*++cur));
5622 0           goto obj_val_begin;
5623             }
5624 0 0         if (has_allow(INF_AND_NAN) &&
5625 0 0         (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
    0          
    0          
5626 0           val++;
5627 0 0         ctn_len++;
5628 0 0         if (read_inf_or_nan(&cur, pre, flg, val)) goto obj_val_end;
5629 0           goto fail_character_val;
5630             }
5631 0 0         if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
    0          
5632 0           val++;
5633 0           ctn_len++;
5634 0 0         if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_val_end;
5635 0           goto fail_string;
5636             }
5637 0 0         if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
    0          
5638 0 0         if (skip_trivia(&cur, eof, flg)) goto obj_val_begin;
5639 0 0         if (cur == eof) goto fail_comment;
5640             }
5641 0           goto fail_character_val;
5642              
5643 0           obj_val_end:
5644 15169 100         if (likely(*cur == ',')) {
5645 3064           cur++;
5646 3064           goto obj_key_begin;
5647             }
5648 12105 50         if (likely(*cur == '}')) {
5649 12105           cur++;
5650 12105           goto obj_end;
5651             }
5652 0 0         if (char_is_space(*cur)) {
5653 0 0         while (char_is_space(*++cur));
5654 0           goto obj_val_end;
5655             }
5656 0 0         if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
    0          
5657 0 0         if (skip_trivia(&cur, eof, flg)) goto obj_val_end;
5658 0 0         if (cur == eof) goto fail_comment;
5659             }
5660 0           goto fail_character_obj_end;
5661              
5662 12111           obj_end:
5663             /* pop container */
5664 12111           ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
5665             /* point to the next value */
5666 12111           ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
5667 12111           ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
5668 12111 100         if (unlikely(ctn == ctn_parent)) goto doc_end;
5669 2034           ctn = ctn_parent;
5670 2034           ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
5671 2034 100         if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
5672 19           goto obj_val_end;
5673             } else {
5674 2015           goto arr_val_end;
5675             }
5676              
5677 10101           doc_end:
5678             /* check invalid contents after json document */
5679 10101 50         if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) {
    0          
5680 0 0         while (char_is_space(*cur)) cur++;
5681 0 0         if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
    0          
5682 0 0         if (!skip_trivia(&cur, eof, flg) && cur == eof) {
    0          
5683 0           goto fail_comment;
5684             }
5685             }
5686 0 0         if (unlikely(cur < eof)) goto fail_garbage;
5687             }
5688              
5689 10101           **pre = '\0';
5690 10101           doc = (yyjson_doc *)val_hdr;
5691 10101           doc->root = val_hdr + hdr_len;
5692 10101           doc->alc = alc;
5693 10101           doc->dat_read = (usize)(cur - hdr);
5694 10101           doc->val_read = (usize)((val - doc->root) + 1);
5695 20202 100         doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
5696 10101           return doc;
5697              
5698 0 0         fail_string: return_err(cur, INVALID_STRING, msg);
    0          
5699 0 0         fail_number: return_err(cur, INVALID_NUMBER, msg);
    0          
5700 0 0         fail_alloc: return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
    0          
5701 0 0         fail_trailing_comma: return_err(cur, JSON_STRUCTURE, MSG_COMMA);
    0          
5702 0 0         fail_literal_true: return_err(cur, LITERAL, MSG_CHAR_T);
    0          
5703 0 0         fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F);
    0          
5704 0 0         fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N);
    0          
5705 0 0         fail_character_val: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
    0          
5706 0 0         fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END);
    0          
5707 0 0         fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY);
    0          
5708 0 0         fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
    0          
5709 0 0         fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
    0          
5710 0 0         fail_comment: return_err(cur, INVALID_COMMENT, MSG_COMMENT);
    0          
5711 0 0         fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
    0          
5712              
5713             #undef val_incr
5714             #undef return_err
5715             }
5716              
5717             /** Read JSON document (accept all style, but optimized for pretty). */
5718             static_inline yyjson_doc *read_root_pretty(u8 *hdr, u8 *cur, u8 *eof,
5719             yyjson_alc alc,
5720             yyjson_read_flag flg,
5721             yyjson_read_err *err) {
5722             #define return_err(_pos, _code, _msg) do { \
5723             if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \
5724             err->pos = (usize)(eof - hdr); \
5725             err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
5726             err->msg = MSG_NOT_END; \
5727             } else { \
5728             err->pos = (usize)(_pos - hdr); \
5729             err->code = YYJSON_READ_ERROR_##_code; \
5730             err->msg = _msg; \
5731             } \
5732             if (val_hdr) alc.free(alc.ctx, val_hdr); \
5733             return NULL; \
5734             } while (false)
5735              
5736             #define val_incr() do { \
5737             val++; \
5738             if (unlikely(val >= val_end)) { \
5739             usize alc_old = alc_len; \
5740             usize val_ofs = (usize)(val - val_hdr); \
5741             usize ctn_ofs = (usize)(ctn - val_hdr); \
5742             alc_len += alc_len / 2; \
5743             if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \
5744             val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
5745             alc_old * sizeof(yyjson_val), \
5746             alc_len * sizeof(yyjson_val)); \
5747             if ((!val_tmp)) goto fail_alloc; \
5748             val = val_tmp + val_ofs; \
5749             ctn = val_tmp + ctn_ofs; \
5750             val_hdr = val_tmp; \
5751             val_end = val_tmp + (alc_len - 2); \
5752             } \
5753             } while (false)
5754              
5755             usize dat_len; /* data length in bytes, hint for allocator */
5756             usize hdr_len; /* value count used by yyjson_doc */
5757             usize alc_len; /* value count allocated */
5758             usize alc_max; /* maximum value count for allocator */
5759             usize ctn_len; /* the number of elements in current container */
5760             yyjson_val *val_hdr; /* the head of allocated values */
5761             yyjson_val *val_end; /* the end of allocated values */
5762             yyjson_val *val_tmp; /* temporary pointer for realloc */
5763             yyjson_val *val; /* current JSON value */
5764             yyjson_val *ctn; /* current container */
5765             yyjson_val *ctn_parent; /* parent of current container */
5766             yyjson_doc *doc; /* the JSON document, equals to val_hdr */
5767             const char *msg; /* error message */
5768              
5769             u8 raw_end[1]; /* raw end for null-terminator */
5770 3           u8 *raw_ptr = raw_end;
5771 3           u8 **pre = &raw_ptr; /* previous raw end pointer */
5772              
5773 3 50         dat_len = has_flg(STOP_WHEN_DONE) ? 256 : (usize)(eof - cur);
5774 3           hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
5775 3           hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
5776 3           alc_max = USIZE_MAX / sizeof(yyjson_val);
5777 3           alc_len = hdr_len + (dat_len / YYJSON_READER_ESTIMATED_PRETTY_RATIO) + 4;
5778 3           alc_len = yyjson_min(alc_len, alc_max);
5779              
5780 3           val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_len * sizeof(yyjson_val));
5781 3 50         if (unlikely(!val_hdr)) goto fail_alloc;
5782 3           val_end = val_hdr + (alc_len - 2); /* padding for key-value pair reading */
5783 3           val = val_hdr + hdr_len;
5784 3           ctn = val;
5785 3           ctn_len = 0;
5786              
5787 3 100         if (*cur++ == '{') {
5788 2           ctn->tag = YYJSON_TYPE_OBJ;
5789 2           ctn->uni.ofs = 0;
5790 2 50         if (*cur == '\n') cur++;
5791 2           goto obj_key_begin;
5792             } else {
5793 1           ctn->tag = YYJSON_TYPE_ARR;
5794 1           ctn->uni.ofs = 0;
5795 1 50         if (*cur == '\n') cur++;
5796 1           goto arr_val_begin;
5797             }
5798              
5799 1           arr_begin:
5800             /* save current container */
5801 1           ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
5802 1           (ctn->tag & YYJSON_TAG_MASK);
5803              
5804             /* create a new array value, save parent container offset */
5805 1 50         val_incr();
    0          
5806 1           val->tag = YYJSON_TYPE_ARR;
5807 1           val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
5808              
5809             /* push the new array value as current container */
5810 1           ctn = val;
5811 1           ctn_len = 0;
5812 1 50         if (*cur == '\n') cur++;
5813              
5814 0           arr_val_begin:
5815             #if YYJSON_IS_REAL_GCC
5816 30 50         while (true) repeat16({
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
5817             if (byte_match_2(cur, " ")) cur += 2;
5818             else break;
5819             })
5820             #else
5821             while (true) repeat16({
5822             if (likely(byte_match_2(cur, " "))) cur += 2;
5823             else break;
5824             })
5825             #endif
5826              
5827 5 100         if (*cur == '{') {
5828 3           cur++;
5829 3           goto obj_begin;
5830             }
5831 2 50         if (*cur == '[') {
5832 0           cur++;
5833 0           goto arr_begin;
5834             }
5835 4 50         if (char_is_num(*cur)) {
5836 0 0         val_incr();
    0          
5837 0           ctn_len++;
5838 0 0         if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_end;
5839 0           goto fail_number;
5840             }
5841 2 50         if (*cur == '"') {
5842 0 0         val_incr();
    0          
5843 0 0         ctn_len++;
5844 0 0         if (likely(read_str(&cur, eof, flg, val, &msg))) goto arr_val_end;
5845 0           goto fail_string;
5846             }
5847 2 100         if (*cur == 't') {
5848 1 50         val_incr();
    50          
5849 1           ctn_len++;
5850 1 50         if (likely(read_true(&cur, val))) goto arr_val_end;
5851 0           goto fail_literal_true;
5852             }
5853 1 50         if (*cur == 'f') {
5854 0 0         val_incr();
    0          
5855 0           ctn_len++;
5856 0 0         if (likely(read_false(&cur, val))) goto arr_val_end;
5857 0           goto fail_literal_false;
5858             }
5859 1 50         if (*cur == 'n') {
5860 1 50         val_incr();
    0          
5861 1           ctn_len++;
5862 1 50         if (likely(read_null(&cur, val))) goto arr_val_end;
5863 0 0         if (has_allow(INF_AND_NAN)) {
5864 0 0         if (read_nan(&cur, pre, flg, val)) goto arr_val_end;
5865             }
5866 0           goto fail_literal_null;
5867             }
5868 0 0         if (*cur == ']') {
5869 0           cur++;
5870 0 0         if (likely(ctn_len == 0)) goto arr_end;
5871 0 0         if (has_allow(TRAILING_COMMAS)) goto arr_end;
5872 0 0         while (*cur != ',') cur--;
5873 0           goto fail_trailing_comma;
5874             }
5875 0 0         if (char_is_space(*cur)) {
5876 0 0         while (char_is_space(*++cur));
5877 0           goto arr_val_begin;
5878             }
5879 0 0         if (has_allow(INF_AND_NAN) &&
5880 0 0         (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
    0          
    0          
5881 0 0         val_incr();
    0          
5882 0 0         ctn_len++;
5883 0 0         if (read_inf_or_nan(&cur, pre, flg, val)) goto arr_val_end;
5884 0           goto fail_character_val;
5885             }
5886 0 0         if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
    0          
5887 0 0         val_incr();
    0          
5888 0           ctn_len++;
5889 0 0         if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto arr_val_end;
5890 0           goto fail_string;
5891             }
5892 0 0         if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
    0          
5893 0 0         if (skip_trivia(&cur, eof, flg)) goto arr_val_begin;
5894 0 0         if (cur == eof) goto fail_comment;
5895             }
5896 0           goto fail_character_val;
5897              
5898 2           arr_val_end:
5899 14 100         if (byte_match_2(cur, ",\n")) {
5900 3           cur += 2;
5901 3           goto arr_val_begin;
5902             }
5903 4 50         if (*cur == ',') {
5904 0           cur++;
5905 0           goto arr_val_begin;
5906             }
5907 4 100         if (*cur == ']') {
5908 2           cur++;
5909 2           goto arr_end;
5910             }
5911 4 50         if (char_is_space(*cur)) {
5912 11 100         while (char_is_space(*++cur));
5913 2           goto arr_val_end;
5914             }
5915 0 0         if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
    0          
5916 0 0         if (skip_trivia(&cur, eof, flg)) goto arr_val_end;
5917 0 0         if (cur == eof) goto fail_comment;
5918             }
5919 0           goto fail_character_arr_end;
5920              
5921 2           arr_end:
5922             /* get parent container */
5923 2           ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
5924              
5925             /* save the next sibling value offset */
5926 2           ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
5927 2           ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
5928 2 100         if (unlikely(ctn == ctn_parent)) goto doc_end;
5929              
5930             /* pop parent as current container */
5931 1           ctn = ctn_parent;
5932 1           ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
5933 1 50         if (*cur == '\n') cur++;
5934 1 50         if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
5935 1           goto obj_val_end;
5936             } else {
5937 0           goto arr_val_end;
5938             }
5939              
5940 3           obj_begin:
5941             /* push container */
5942 3           ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
5943 3           (ctn->tag & YYJSON_TAG_MASK);
5944 3 50         val_incr();
    0          
5945 3           val->tag = YYJSON_TYPE_OBJ;
5946             /* offset to the parent */
5947 3           val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
5948 3           ctn = val;
5949 3           ctn_len = 0;
5950 3 50         if (*cur == '\n') cur++;
5951              
5952 3           obj_key_begin:
5953             #if YYJSON_IS_REAL_GCC
5954 28 100         while (true) repeat16({
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
5955             if (byte_match_2(cur, " ")) cur += 2;
5956             else break;
5957             })
5958             #else
5959             while (true) repeat16({
5960             if (likely(byte_match_2(cur, " "))) cur += 2;
5961             else break;
5962             })
5963             #endif
5964 11 50         if (likely(*cur == '"')) {
5965 11 100         val_incr();
    50          
5966 11 50         ctn_len++;
5967 11 50         if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_key_end;
5968 0           goto fail_string;
5969             }
5970 0 0         if (likely(*cur == '}')) {
5971 0           cur++;
5972 0 0         if (likely(ctn_len == 0)) goto obj_end;
5973 0 0         if (has_allow(TRAILING_COMMAS)) goto obj_end;
5974 0 0         while (*cur != ',') cur--;
5975 0           goto fail_trailing_comma;
5976             }
5977 0 0         if (char_is_space(*cur)) {
5978 0 0         while (char_is_space(*++cur));
5979 0           goto obj_key_begin;
5980             }
5981 0 0         if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
    0          
5982 0 0         val_incr();
    0          
5983 0           ctn_len++;
5984 0 0         if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_key_end;
5985 0           goto fail_string;
5986             }
5987 0 0         if (has_allow(UNQUOTED_KEY) && char_is_id_start(*cur)) {
    0          
5988 0 0         val_incr();
    0          
5989 0           ctn_len++;
5990 0 0         if (read_str_id(&cur, eof, flg, pre, val, &msg)) goto obj_key_end;
5991 0           goto fail_string;
5992             }
5993 0 0         if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
    0          
5994 0 0         if (skip_trivia(&cur, eof, flg)) goto obj_key_begin;
5995 0 0         if (cur == eof) goto fail_comment;
5996             }
5997 0           goto fail_character_obj_key;
5998              
5999 0           obj_key_end:
6000 22 100         if (byte_match_2(cur, ": ")) {
6001 3           cur += 2;
6002 3           goto obj_val_begin;
6003             }
6004 8 50         if (*cur == ':') {
6005 8           cur++;
6006 8           goto obj_val_begin;
6007             }
6008 0 0         if (char_is_space(*cur)) {
6009 0 0         while (char_is_space(*++cur));
6010 0           goto obj_key_end;
6011             }
6012 0 0         if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
    0          
6013 0 0         if (skip_trivia(&cur, eof, flg)) goto obj_key_end;
6014 0 0         if (cur == eof) goto fail_comment;
6015             }
6016 0           goto fail_character_obj_sep;
6017              
6018 0           obj_val_begin:
6019 11 100         if (*cur == '"') {
6020 6           val++;
6021 6 50         ctn_len++;
6022 6 50         if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_val_end;
6023 0           goto fail_string;
6024             }
6025 10 100         if (char_is_num(*cur)) {
6026 4           val++;
6027 4           ctn_len++;
6028 4 50         if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_end;
6029 0           goto fail_number;
6030             }
6031 1 50         if (*cur == '{') {
6032 0           cur++;
6033 0           goto obj_begin;
6034             }
6035 1 50         if (*cur == '[') {
6036 1           cur++;
6037 1           goto arr_begin;
6038             }
6039 0 0         if (*cur == 't') {
6040 0           val++;
6041 0           ctn_len++;
6042 0 0         if (likely(read_true(&cur, val))) goto obj_val_end;
6043 0           goto fail_literal_true;
6044             }
6045 0 0         if (*cur == 'f') {
6046 0           val++;
6047 0           ctn_len++;
6048 0 0         if (likely(read_false(&cur, val))) goto obj_val_end;
6049 0           goto fail_literal_false;
6050             }
6051 0 0         if (*cur == 'n') {
6052 0           val++;
6053 0           ctn_len++;
6054 0 0         if (likely(read_null(&cur, val))) goto obj_val_end;
6055 0 0         if (has_allow(INF_AND_NAN)) {
6056 0 0         if (read_nan(&cur, pre, flg, val)) goto obj_val_end;
6057             }
6058 0           goto fail_literal_null;
6059             }
6060 0 0         if (char_is_space(*cur)) {
6061 0 0         while (char_is_space(*++cur));
6062 0           goto obj_val_begin;
6063             }
6064 0 0         if (has_allow(INF_AND_NAN) &&
6065 0 0         (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
    0          
    0          
6066 0           val++;
6067 0 0         ctn_len++;
6068 0 0         if (read_inf_or_nan(&cur, pre, flg, val)) goto obj_val_end;
6069 0           goto fail_character_val;
6070             }
6071 0 0         if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
    0          
6072 0           val++;
6073 0           ctn_len++;
6074 0 0         if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_val_end;
6075 0           goto fail_string;
6076             }
6077 0 0         if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
    0          
6078 0 0         if (skip_trivia(&cur, eof, flg)) goto obj_val_begin;
6079 0 0         if (cur == eof) goto fail_comment;
6080             }
6081 0           goto fail_character_val;
6082              
6083 1           obj_val_end:
6084 24 100         if (byte_match_2(cur, ",\n")) {
6085 1           cur += 2;
6086 1           goto obj_key_begin;
6087             }
6088 11 100         if (likely(*cur == ',')) {
6089 5           cur++;
6090 5           goto obj_key_begin;
6091             }
6092 6 100         if (likely(*cur == '}')) {
6093 5           cur++;
6094 5           goto obj_end;
6095             }
6096 2 50         if (char_is_space(*cur)) {
6097 2 50         while (char_is_space(*++cur));
6098 1           goto obj_val_end;
6099             }
6100 0 0         if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
    0          
6101 0 0         if (skip_trivia(&cur, eof, flg)) goto obj_val_end;
6102 0 0         if (cur == eof) goto fail_comment;
6103             }
6104 0           goto fail_character_obj_end;
6105              
6106 5           obj_end:
6107             /* pop container */
6108 5           ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
6109             /* point to the next value */
6110 5           ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
6111 5           ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
6112 5 100         if (unlikely(ctn == ctn_parent)) goto doc_end;
6113 3           ctn = ctn_parent;
6114 3           ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
6115 3 100         if (*cur == '\n') cur++;
6116 3 50         if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
6117 0           goto obj_val_end;
6118             } else {
6119 3           goto arr_val_end;
6120             }
6121              
6122 3           doc_end:
6123             /* check invalid contents after json document */
6124 3 50         if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) {
    0          
6125 0 0         while (char_is_space(*cur)) cur++;
6126 0 0         if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
    0          
6127 0 0         if (!skip_trivia(&cur, eof, flg) && cur == eof) {
    0          
6128 0           goto fail_comment;
6129             }
6130             }
6131 0 0         if (unlikely(cur < eof)) goto fail_garbage;
6132             }
6133              
6134 3           **pre = '\0';
6135 3           doc = (yyjson_doc *)val_hdr;
6136 3           doc->root = val_hdr + hdr_len;
6137 3           doc->alc = alc;
6138 3           doc->dat_read = (usize)(cur - hdr);
6139 3           doc->val_read = (usize)((val - doc->root) + 1);
6140 6 100         doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
6141 3           return doc;
6142              
6143 0 0         fail_string: return_err(cur, INVALID_STRING, msg);
    0          
6144 0 0         fail_number: return_err(cur, INVALID_NUMBER, msg);
    0          
6145 0 0         fail_alloc: return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
    0          
6146 0 0         fail_trailing_comma: return_err(cur, JSON_STRUCTURE, MSG_COMMA);
    0          
6147 0 0         fail_literal_true: return_err(cur, LITERAL, MSG_CHAR_T);
    0          
6148 0 0         fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F);
    0          
6149 0 0         fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N);
    0          
6150 0 0         fail_character_val: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
    0          
6151 0 0         fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END);
    0          
6152 0 0         fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY);
    0          
6153 0 0         fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
    0          
6154 0 0         fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
    0          
6155 0 0         fail_comment: return_err(cur, INVALID_COMMENT, MSG_COMMENT);
    0          
6156 0 0         fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
    0          
6157              
6158             #undef val_incr
6159             #undef return_err
6160             }
6161              
6162              
6163              
6164             /*==============================================================================
6165             * MARK: - JSON Reader (Public)
6166             *============================================================================*/
6167              
6168 10119           yyjson_doc *yyjson_read_opts(char *dat, usize len,
6169             yyjson_read_flag flg,
6170             const yyjson_alc *alc_ptr,
6171             yyjson_read_err *err) {
6172             #define return_err(_pos, _code, _msg) do { \
6173             err->pos = (usize)(_pos); \
6174             err->msg = _msg; \
6175             err->code = YYJSON_READ_ERROR_##_code; \
6176             if (!has_flg(INSITU) && hdr) alc.free(alc.ctx, (void *)hdr); \
6177             return NULL; \
6178             } while (false)
6179              
6180             yyjson_read_err tmp_err;
6181 10119 100         yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
6182             yyjson_doc *doc;
6183 10119           u8 *hdr = NULL, *eof, *cur;
6184              
6185             /* validate input parameters */
6186 10119 100         if (!err) err = &tmp_err;
6187 10119 50         if (unlikely(!dat)) return_err(0, INVALID_PARAMETER, "input data is NULL");
    0          
    0          
6188 10120 100         if (unlikely(!len)) return_err(0, INVALID_PARAMETER, "input length is 0");
    50          
    50          
6189              
6190             /* add 4-byte zero padding for input data if necessary */
6191 20236 100         if (has_flg(INSITU)) {
6192 3           hdr = (u8 *)dat;
6193 3           eof = (u8 *)dat + len;
6194 3           cur = (u8 *)dat;
6195             } else {
6196 10115 50         if (unlikely(len >= USIZE_MAX - YYJSON_PADDING_SIZE)) {
6197 0 0         return_err(0, MEMORY_ALLOCATION, MSG_MALLOC);
    0          
6198             }
6199 10115           hdr = (u8 *)alc.malloc(alc.ctx, len + YYJSON_PADDING_SIZE);
6200 10115 50         if (unlikely(!hdr)) {
6201 0 0         return_err(0, MEMORY_ALLOCATION, MSG_MALLOC);
    0          
6202             }
6203 10115           eof = hdr + len;
6204 10115           cur = hdr;
6205 10115           memcpy(hdr, dat, len);
6206             }
6207 10118           memset(eof, 0, YYJSON_PADDING_SIZE);
6208              
6209 20236 50         if (has_allow(BOM)) {
6210 0 0         if (len >= 3 && is_utf8_bom(cur)) cur += 3;
    0          
6211             }
6212              
6213             /* skip empty contents before json document */
6214 20236 100         if (unlikely(!char_is_ctn(*cur))) {
6215 28 50         while (char_is_space(*cur)) cur++;
6216 28 50         if (unlikely(!char_is_ctn(*cur))) {
6217 28 50         if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
    0          
6218 0 0         if (!skip_trivia(&cur, eof, flg) && cur == eof) {
    0          
6219 0 0         return_err(cur - hdr, INVALID_COMMENT, MSG_COMMENT);
    0          
6220             }
6221             }
6222             }
6223 14 50         if (unlikely(cur >= eof)) {
6224 0 0         return_err(0, EMPTY_CONTENT, "input data is empty");
    0          
6225             }
6226             }
6227              
6228             /* read json document */
6229 20236 100         if (likely(char_is_ctn(*cur))) {
6230 20211 100         if (char_is_space(cur[1]) && char_is_space(cur[2])) {
    50          
6231 6           doc = read_root_pretty(hdr, cur, eof, alc, flg, err);
6232             } else {
6233 20202           doc = read_root_minify(hdr, cur, eof, alc, flg, err);
6234             }
6235             } else {
6236 14           doc = read_root_single(hdr, cur, eof, alc, flg, err);
6237             }
6238              
6239             /* check result */
6240 10118 100         if (likely(doc)) {
6241 10114           memset(err, 0, sizeof(yyjson_read_err));
6242             } else {
6243             /* RFC 8259: JSON text MUST be encoded using UTF-8 */
6244 4 50         if (err->pos == 0 && err->code != YYJSON_READ_ERROR_MEMORY_ALLOCATION) {
    50          
6245 4 100         if (is_utf8_bom(hdr)) err->msg = MSG_ERR_BOM;
6246 6 50         else if (len >= 4 && is_utf32_bom(hdr)) err->msg = MSG_ERR_UTF32;
    50          
6247 6 50         else if (len >= 2 && is_utf16_bom(hdr)) err->msg = MSG_ERR_UTF16;
    50          
6248             }
6249 8 50         if (!has_flg(INSITU)) alc.free(alc.ctx, hdr);
6250             }
6251 10118           return doc;
6252              
6253             #undef return_err
6254             }
6255              
6256 4           yyjson_doc *yyjson_read_file(const char *path,
6257             yyjson_read_flag flg,
6258             const yyjson_alc *alc_ptr,
6259             yyjson_read_err *err) {
6260             #define return_err(_code, _msg) do { \
6261             err->pos = 0; \
6262             err->msg = _msg; \
6263             err->code = YYJSON_READ_ERROR_##_code; \
6264             return NULL; \
6265             } while (false)
6266              
6267             yyjson_read_err tmp_err;
6268             yyjson_doc *doc;
6269             FILE *file;
6270              
6271 4 50         if (!err) err = &tmp_err;
6272 4 50         if (unlikely(!path)) return_err(INVALID_PARAMETER, "input path is NULL");
6273              
6274 4           file = fopen_readonly(path);
6275 4 100         if (unlikely(!file)) return_err(FILE_OPEN, MSG_FREAD);
6276              
6277 3           doc = yyjson_read_fp(file, flg, alc_ptr, err);
6278 3           fclose(file);
6279 3           return doc;
6280              
6281             #undef return_err
6282             }
6283              
6284 3           yyjson_doc *yyjson_read_fp(FILE *file,
6285             yyjson_read_flag flg,
6286             const yyjson_alc *alc_ptr,
6287             yyjson_read_err *err) {
6288             #define return_err(_code, _msg) do { \
6289             err->pos = 0; \
6290             err->msg = _msg; \
6291             err->code = YYJSON_READ_ERROR_##_code; \
6292             if (buf) alc.free(alc.ctx, buf); \
6293             return NULL; \
6294             } while (false)
6295              
6296             yyjson_read_err tmp_err;
6297 3 50         yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
6298             yyjson_doc *doc;
6299              
6300 3           long file_size = 0, file_pos;
6301 3           void *buf = NULL;
6302 3           usize buf_size = 0;
6303              
6304             /* validate input parameters */
6305 3 50         if (!err) err = &tmp_err;
6306 3 50         if (unlikely(!file)) return_err(INVALID_PARAMETER, "input file is NULL");
    0          
6307              
6308             /* get current position */
6309 3           file_pos = ftell(file);
6310 3 50         if (file_pos != -1) {
6311             /* get total file size, may fail */
6312 3 50         if (fseek(file, 0, SEEK_END) == 0) file_size = ftell(file);
6313             /* reset to original position, may fail */
6314 3 50         if (fseek(file, file_pos, SEEK_SET) != 0) file_size = 0;
6315             /* get file size from current postion to end */
6316 3 50         if (file_size > 0) file_size -= file_pos;
6317             }
6318              
6319             /* read file */
6320 3 50         if (file_size > 0) {
6321             /* read the entire file in one call */
6322 3           buf_size = (usize)file_size + YYJSON_PADDING_SIZE;
6323 3           buf = alc.malloc(alc.ctx, buf_size);
6324 3 50         if (buf == NULL) {
6325 0 0         return_err(MEMORY_ALLOCATION, MSG_MALLOC);
6326             }
6327 6 50         if (fread_safe(buf, (usize)file_size, file) != (usize)file_size) {
6328 0 0         return_err(FILE_READ, MSG_FREAD);
6329             }
6330             } else {
6331             /* failed to get file size, read it as a stream */
6332 0           usize chunk_min = (usize)64;
6333 0           usize chunk_max = (usize)512 * 1024 * 1024;
6334 0           usize chunk_now = chunk_min;
6335             usize read_size;
6336             void *tmp;
6337              
6338 0           buf_size = YYJSON_PADDING_SIZE;
6339             while (true) {
6340 0 0         if (buf_size + chunk_now < buf_size) { /* overflow */
6341 0 0         return_err(MEMORY_ALLOCATION, MSG_MALLOC);
6342             }
6343 0           buf_size += chunk_now;
6344 0 0         if (!buf) {
6345 0           buf = alc.malloc(alc.ctx, buf_size);
6346 0 0         if (!buf) return_err(MEMORY_ALLOCATION, MSG_MALLOC);
    0          
6347             } else {
6348 0           tmp = alc.realloc(alc.ctx, buf, buf_size - chunk_now, buf_size);
6349 0 0         if (!tmp) return_err(MEMORY_ALLOCATION, MSG_MALLOC);
    0          
6350 0           buf = tmp;
6351             }
6352 0           tmp = ((u8 *)buf) + buf_size - YYJSON_PADDING_SIZE - chunk_now;
6353 0           read_size = fread_safe(tmp, chunk_now, file);
6354 0           file_size += (long)read_size;
6355 0 0         if (read_size != chunk_now) break;
6356              
6357 0           chunk_now *= 2;
6358 0 0         if (chunk_now > chunk_max) chunk_now = chunk_max;
6359             }
6360             }
6361              
6362             /* read JSON */
6363 3           memset((u8 *)buf + file_size, 0, YYJSON_PADDING_SIZE);
6364 3           flg |= YYJSON_READ_INSITU;
6365 3           doc = yyjson_read_opts((char *)buf, (usize)file_size, flg, &alc, err);
6366 3 50         if (doc) {
6367 3           doc->str_pool = (char *)buf;
6368 3           return doc;
6369             } else {
6370 0           alc.free(alc.ctx, buf);
6371 0           return NULL;
6372             }
6373              
6374             #undef return_err
6375             }
6376              
6377 0           const char *yyjson_read_number(const char *dat,
6378             yyjson_val *val,
6379             yyjson_read_flag flg,
6380             const yyjson_alc *alc,
6381             yyjson_read_err *err) {
6382             #define return_err(_pos, _code, _msg) do { \
6383             err->pos = _pos > hdr ? (usize)(_pos - hdr) : 0; \
6384             err->msg = _msg; \
6385             err->code = YYJSON_READ_ERROR_##_code; \
6386             return NULL; \
6387             } while (false)
6388              
6389 0           u8 *hdr = constcast(u8 *)dat, *cur = hdr;
6390             u8 raw_end[1]; /* raw end for null-terminator */
6391 0           u8 *raw_ptr = raw_end;
6392 0           u8 **pre = &raw_ptr; /* previous raw end pointer */
6393             const char *msg;
6394             yyjson_read_err tmp_err;
6395              
6396             #if YYJSON_DISABLE_FAST_FP_CONV
6397             u8 buf[128];
6398             usize dat_len;
6399             #endif
6400              
6401 0 0         if (!err) err = &tmp_err;
6402 0 0         if (unlikely(!dat)) {
6403 0 0         return_err(cur, INVALID_PARAMETER, "input data is NULL");
6404             }
6405 0 0         if (unlikely(!val)) {
6406 0 0         return_err(cur, INVALID_PARAMETER, "output value is NULL");
6407             }
6408              
6409             #if YYJSON_DISABLE_FAST_FP_CONV
6410             if (!alc) alc = &YYJSON_DEFAULT_ALC;
6411             dat_len = strlen(dat);
6412             if (dat_len < sizeof(buf)) {
6413             memcpy(buf, dat, dat_len + 1);
6414             hdr = buf;
6415             cur = hdr;
6416             } else {
6417             hdr = (u8 *)alc->malloc(alc->ctx, dat_len + 1);
6418             cur = hdr;
6419             if (unlikely(!hdr)) {
6420             return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
6421             }
6422             memcpy(hdr, dat, dat_len + 1);
6423             }
6424             hdr[dat_len] = 0;
6425             #endif
6426              
6427             #if YYJSON_DISABLE_FAST_FP_CONV
6428             if (!read_num(&cur, pre, flg, val, &msg)) {
6429             if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr);
6430             return_err(cur, INVALID_NUMBER, msg);
6431             }
6432             if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr);
6433             if (yyjson_is_raw(val)) val->uni.str = dat;
6434             return dat + (cur - hdr);
6435             #else
6436 0 0         if (!read_num(&cur, pre, flg, val, &msg)) {
6437 0 0         return_err(cur, INVALID_NUMBER, msg);
6438             }
6439 0           return (const char *)cur;
6440             #endif
6441              
6442             #undef return_err
6443             }
6444              
6445              
6446              
6447             /*==============================================================================
6448             * MARK: - Incremental JSON Reader (Public)
6449             *============================================================================*/
6450              
6451             #if !YYJSON_DISABLE_INCR_READER
6452              
6453             /* labels within yyjson_incr_read() to resume incremental parsing */
6454             #define LABEL_doc_begin 0
6455             #define LABEL_arr_val_begin 1
6456             #define LABEL_arr_val_end 2
6457             #define LABEL_obj_key_begin 3
6458             #define LABEL_obj_key_end 4
6459             #define LABEL_obj_val_begin 5
6460             #define LABEL_obj_val_end 6
6461             #define LABEL_doc_end 7
6462              
6463             /** State for incremental JSON reader, opaque in the API. */
6464             struct yyjson_incr_state {
6465             u32 label; /* current parser goto label */
6466             yyjson_alc alc; /* allocator */
6467             yyjson_read_flag flg; /* read flags */
6468             u8 *hdr; /* JSON data header */
6469             u8 *cur; /* current position in JSON data */
6470             usize buf_len; /* total buffer length (without padding) */
6471             usize hdr_len; /* value count used by yyjson_doc */
6472             usize alc_len; /* value count allocated */
6473             usize ctn_len; /* the number of elements in current container */
6474             yyjson_val *val_hdr; /* the head of allocated values */
6475             yyjson_val *val_end; /* the end of allocated values */
6476             yyjson_val *val; /* current JSON value */
6477             yyjson_val *ctn; /* current container */
6478             u8 *str_con[2]; /* string parser incremental state */
6479             };
6480              
6481 0           yyjson_incr_state *yyjson_incr_new(char *buf, size_t buf_len,
6482             yyjson_read_flag flg,
6483             const yyjson_alc *alc_ptr) {
6484 0           yyjson_incr_state *state = NULL;
6485 0 0         yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
6486              
6487             /* remove non-standard flags */
6488 0           flg &= ~YYJSON_READ_JSON5;
6489 0           flg &= ~YYJSON_READ_ALLOW_BOM;
6490 0           flg &= ~YYJSON_READ_ALLOW_INVALID_UNICODE;
6491              
6492 0 0         if (unlikely(!buf)) return NULL;
6493 0 0         if (unlikely(buf_len >= USIZE_MAX - YYJSON_PADDING_SIZE)) return NULL;
6494 0           state = (yyjson_incr_state *)alc.malloc(alc.ctx, sizeof(*state));
6495 0 0         if (!state) return NULL;
6496 0           memset(state, 0, sizeof(yyjson_incr_state));
6497 0           state->alc = alc;
6498 0           state->flg = flg;
6499 0           state->buf_len = buf_len;
6500              
6501             /* add 4-byte zero padding for input data if necessary */
6502 0 0         if (has_flg(INSITU)) {
6503 0           state->hdr = (u8 *)buf;
6504             } else {
6505 0           state->hdr = (u8 *)alc.malloc(alc.ctx, buf_len + YYJSON_PADDING_SIZE);
6506 0 0         if (unlikely(!state->hdr)) {
6507 0           alc.free(alc.ctx, state);
6508 0           return NULL;
6509             }
6510 0           memcpy(state->hdr, buf, buf_len);
6511             }
6512 0           memset(state->hdr + buf_len, 0, YYJSON_PADDING_SIZE);
6513 0           state->cur = state->hdr;
6514 0           state->label = LABEL_doc_begin;
6515 0           return state;
6516             }
6517              
6518 0           void yyjson_incr_free(yyjson_incr_state *state) {
6519 0 0         if (state) {
6520 0           yyjson_alc alc = state->alc;
6521 0           memset(&state->alc, 0, sizeof(alc));
6522 0 0         if (state->val_hdr) {
6523 0           alc.free(alc.ctx, (void *)state->val_hdr);
6524             }
6525 0 0         if (state->hdr && !(state->flg & YYJSON_READ_INSITU)) {
    0          
6526 0           alc.free(alc.ctx, state->hdr);
6527             }
6528 0           alc.free(alc.ctx, state);
6529             }
6530 0           }
6531              
6532 0           yyjson_doc *yyjson_incr_read(yyjson_incr_state *state, size_t len,
6533             yyjson_read_err *err) {
6534             #define return_err_inv_param(_msg) do { \
6535             err->pos = 0; \
6536             err->msg = _msg; \
6537             err->code = YYJSON_READ_ERROR_INVALID_PARAMETER; \
6538             return NULL; \
6539             } while (false)
6540              
6541             #define return_err(_pos, _code, _msg) do { \
6542             if (is_truncated_end(hdr, _pos, end, YYJSON_READ_ERROR_##_code, flg)) { \
6543             goto unexpected_end; \
6544             } else { \
6545             err->pos = (usize)(_pos - hdr); \
6546             err->code = YYJSON_READ_ERROR_##_code; \
6547             err->msg = _msg; \
6548             } \
6549             return NULL; \
6550             } while (false)
6551              
6552             #define val_incr() do { \
6553             val++; \
6554             if (unlikely(val >= val_end)) { \
6555             usize alc_old = alc_len; \
6556             alc_len += alc_len / 2; \
6557             if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \
6558             val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
6559             alc_old * sizeof(yyjson_val), \
6560             alc_len * sizeof(yyjson_val)); \
6561             if ((!val_tmp)) goto fail_alloc; \
6562             val = val_tmp + (usize)(val - val_hdr); \
6563             ctn = val_tmp + (usize)(ctn - val_hdr); \
6564             state->val = val_tmp + (usize)(state->val - val_hdr); \
6565             state->val_hdr = val_hdr = val_tmp; \
6566             val_end = val_tmp + (alc_len - 2); \
6567             state->val_end = val_end; \
6568             } \
6569             } while (false)
6570              
6571             /* save position where it's possible to resume incremental parsing */
6572             #define save_incr_state(_label) do { \
6573             state->label = LABEL_##_label; \
6574             state->cur = cur; \
6575             state->val = val; \
6576             state->ctn_len = ctn_len; \
6577             state->hdr_len = hdr_len; \
6578             if (unlikely(cur >= end)) goto unexpected_end; \
6579             } while (false)
6580              
6581             #define check_maybe_truncated_number() do { \
6582             if (unlikely(cur >= end)) { \
6583             if (unlikely(cur > state->cur + INCR_NUM_MAX_LEN)) { \
6584             msg = "number too long"; \
6585             goto fail_number; \
6586             } \
6587             goto unexpected_end; \
6588             } \
6589             } while (false)
6590              
6591 0           u8 *hdr = NULL, *end = NULL, *cur = NULL;
6592             yyjson_read_flag flg;
6593             yyjson_alc alc;
6594             usize dat_len; /* data length in bytes, hint for allocator */
6595             usize hdr_len; /* value count used by yyjson_doc */
6596             usize alc_len; /* value count allocated */
6597             usize alc_max; /* maximum value count for allocator */
6598             usize ctn_len; /* the number of elements in current container */
6599             yyjson_val *val_hdr; /* the head of allocated values */
6600             yyjson_val *val_end; /* the end of allocated values */
6601             yyjson_val *val_tmp; /* temporary pointer for realloc */
6602             yyjson_val *val; /* current JSON value */
6603             yyjson_val *ctn; /* current container */
6604             yyjson_val *ctn_parent; /* parent of current container */
6605             yyjson_doc *doc; /* the JSON document, equals to val_hdr */
6606             const char *msg; /* error message */
6607              
6608             yyjson_read_err tmp_err;
6609             u8 raw_end[1]; /* raw end for null-terminator */
6610 0           u8 *raw_ptr = raw_end;
6611 0           u8 **pre = &raw_ptr; /* previous raw end pointer */
6612 0           u8 **con = NULL; /* for incremental string parsing */
6613 0           u8 saved_end = '\0'; /* saved end char */
6614              
6615             /* validate input parameters */
6616 0 0         if (!err) err = &tmp_err;
6617 0 0         if (unlikely(!state)) {
6618 0           return_err_inv_param("input state is NULL");
6619             }
6620 0 0         if (unlikely(!len)) {
6621 0           return_err_inv_param("input length is 0");
6622             }
6623 0 0         if (unlikely(len > state->buf_len)) {
6624 0           return_err_inv_param("length is greater than total input length");
6625             }
6626              
6627             /* restore state saved from the previous call */
6628 0           hdr = state->hdr;
6629 0           end = state->hdr + len;
6630 0           cur = state->cur;
6631 0           flg = state->flg;
6632 0           alc = state->alc;
6633 0           ctn_len = state->ctn_len;
6634 0           hdr_len = state->hdr_len;
6635 0           alc_len = state->alc_len;
6636 0           val = state->val;
6637 0           val_hdr = state->val_hdr;
6638 0           val_end = state->val_end;
6639 0           ctn = state->ctn;
6640 0           con = state->str_con;
6641 0           alc_max = USIZE_MAX / sizeof(yyjson_val);
6642              
6643             /* insert null terminator to make us stop at the specified end, even if
6644             the data contains more valid JSON */
6645 0           saved_end = *end;
6646 0           *end = '\0';
6647              
6648             /* resume parsing from the last save point */
6649 0           switch (state->label) {
6650 0           case LABEL_doc_begin: goto doc_begin;
6651 0           case LABEL_arr_val_begin: goto arr_val_begin;
6652 0           case LABEL_arr_val_end: goto arr_val_end;
6653 0           case LABEL_obj_key_begin: goto obj_key_begin;
6654 0           case LABEL_obj_key_end: goto obj_key_end;
6655 0           case LABEL_obj_val_begin: goto obj_val_begin;
6656 0           case LABEL_obj_val_end: goto obj_val_end;
6657 0           case LABEL_doc_end: goto doc_end;
6658 0           default: return_err_inv_param("invalid incremental state");
6659             }
6660              
6661 0           doc_begin:
6662             /* skip empty contents before json document */
6663 0 0         if (unlikely(!char_is_ctn(*cur))) {
6664 0 0         while (char_is_space(*cur)) cur++;
6665 0 0         if (unlikely(cur >= end)) goto unexpected_end; /* input data is empty */
6666             }
6667              
6668             /* allocate memory for document */
6669 0 0         if (!val_hdr) {
6670 0           hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
6671 0           hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
6672 0 0         if (likely(char_is_ctn(*cur))) {
6673 0 0         dat_len = has_flg(STOP_WHEN_DONE) ? 256 : state->buf_len;
6674 0           alc_len = hdr_len +
6675 0           (dat_len / YYJSON_READER_ESTIMATED_MINIFY_RATIO) + 4;
6676 0           alc_len = yyjson_min(alc_len, alc_max);
6677             } else {
6678 0           alc_len = hdr_len + 1; /* single value */
6679             }
6680 0           val_hdr = (yyjson_val *)alc.malloc(alc.ctx,
6681             alc_len * sizeof(yyjson_val));
6682 0 0         if (unlikely(!val_hdr)) goto fail_alloc;
6683 0           val_end = val_hdr + (alc_len - 2); /* padding for kv pair reading */
6684 0           val = val_hdr + hdr_len;
6685 0           ctn = val;
6686 0           ctn_len = 0;
6687 0           state->val_hdr = val_hdr;
6688 0           state->val_end = val_end;
6689 0 0         save_incr_state(doc_begin);
6690             }
6691              
6692             /* read json document */
6693 0 0         if (*cur == '{') {
6694 0           cur++;
6695 0           ctn->tag = YYJSON_TYPE_OBJ;
6696 0           ctn->uni.ofs = 0;
6697 0           goto obj_key_begin;
6698             }
6699 0 0         if (*cur == '[') {
6700 0           cur++;
6701 0           ctn->tag = YYJSON_TYPE_ARR;
6702 0           ctn->uni.ofs = 0;
6703 0           goto arr_val_begin;
6704             }
6705 0 0         if (char_is_num(*cur)) {
6706 0 0         if (likely(read_num(&cur, pre, flg, val, &msg))) goto doc_end;
6707 0           goto fail_number;
6708             }
6709 0 0         if (*cur == '"') {
6710 0 0         if (likely(read_str_con(&cur, end, flg, val, &msg, con))) goto doc_end;
6711 0           goto fail_string;
6712             }
6713 0 0         if (*cur == 't') {
6714 0 0         if (likely(read_true(&cur, val))) goto doc_end;
6715 0           goto fail_literal_true;
6716             }
6717 0 0         if (*cur == 'f') {
6718 0 0         if (likely(read_false(&cur, val))) goto doc_end;
6719 0           goto fail_literal_false;
6720             }
6721 0 0         if (*cur == 'n') {
6722 0 0         if (likely(read_null(&cur, val))) goto doc_end;
6723 0           goto fail_literal_null;
6724             }
6725              
6726 0           msg = "unexpected character, expected a valid root value";
6727 0 0         if (cur == hdr) {
6728             /* RFC 8259: JSON text MUST be encoded using UTF-8 */
6729 0 0         if (is_utf8_bom(hdr)) msg = MSG_ERR_BOM;
6730 0 0         else if (len >= 4 && is_utf32_bom(hdr)) msg = MSG_ERR_UTF32;
    0          
6731 0 0         else if (len >= 2 && is_utf16_bom(hdr)) msg = MSG_ERR_UTF16;
    0          
6732             }
6733 0 0         return_err(cur, UNEXPECTED_CHARACTER, msg);
6734              
6735 0           arr_begin:
6736             /* save current container */
6737 0           ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
6738 0           (ctn->tag & YYJSON_TAG_MASK);
6739              
6740             /* create a new array value, save parent container offset */
6741 0 0         val_incr();
    0          
6742 0           val->tag = YYJSON_TYPE_ARR;
6743 0           val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
6744              
6745             /* push the new array value as current container */
6746 0           ctn = val;
6747 0           ctn_len = 0;
6748              
6749 0           arr_val_begin:
6750 0 0         save_incr_state(arr_val_begin);
6751 0           arr_val_continue:
6752 0 0         if (*cur == '{') {
6753 0           cur++;
6754 0           goto obj_begin;
6755             }
6756 0 0         if (*cur == '[') {
6757 0           cur++;
6758 0           goto arr_begin;
6759             }
6760 0 0         if (char_is_num(*cur)) {
6761 0 0         val_incr();
    0          
6762 0           ctn_len++;
6763 0 0         if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_maybe_end;
6764 0           goto fail_number;
6765             }
6766 0 0         if (*cur == '"') {
6767 0 0         val_incr();
    0          
6768 0 0         ctn_len++;
6769 0 0         if (likely(read_str_con(&cur, end, flg, val, &msg, con)))
6770 0           goto arr_val_end;
6771 0           goto fail_string;
6772             }
6773 0 0         if (*cur == 't') {
6774 0 0         val_incr();
    0          
6775 0           ctn_len++;
6776 0 0         if (likely(read_true(&cur, val))) goto arr_val_end;
6777 0           goto fail_literal_true;
6778             }
6779 0 0         if (*cur == 'f') {
6780 0 0         val_incr();
    0          
6781 0           ctn_len++;
6782 0 0         if (likely(read_false(&cur, val))) goto arr_val_end;
6783 0           goto fail_literal_false;
6784             }
6785 0 0         if (*cur == 'n') {
6786 0 0         val_incr();
    0          
6787 0           ctn_len++;
6788 0 0         if (likely(read_null(&cur, val))) goto arr_val_end;
6789 0           goto fail_literal_null;
6790             }
6791 0 0         if (*cur == ']') {
6792 0           cur++;
6793 0 0         if (likely(ctn_len == 0)) goto arr_end;
6794 0 0         while (*cur != ',') cur--;
6795 0           goto fail_trailing_comma;
6796             }
6797 0 0         if (char_is_space(*cur)) {
6798 0 0         while (char_is_space(*++cur));
6799 0           goto arr_val_continue;
6800             }
6801 0           goto fail_character_val;
6802              
6803 0           arr_val_maybe_end:
6804             /* if incremental parsing stops in the middle of a number, it may continue
6805             with more digits, so arr val maybe didn't end yet */
6806 0 0         check_maybe_truncated_number();
    0          
6807              
6808 0           arr_val_end:
6809 0 0         save_incr_state(arr_val_end);
6810 0 0         if (*cur == ',') {
6811 0           cur++;
6812 0           goto arr_val_begin;
6813             }
6814 0 0         if (*cur == ']') {
6815 0           cur++;
6816 0           goto arr_end;
6817             }
6818 0 0         if (char_is_space(*cur)) {
6819 0 0         while (char_is_space(*++cur));
6820 0           goto arr_val_end;
6821             }
6822 0           goto fail_character_arr_end;
6823              
6824 0           arr_end:
6825             /* get parent container */
6826 0           ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
6827              
6828             /* save the next sibling value offset */
6829 0           ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
6830 0           ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
6831 0 0         if (unlikely(ctn == ctn_parent)) goto doc_end;
6832              
6833             /* pop parent as current container */
6834 0           ctn = ctn_parent;
6835 0           ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
6836 0 0         if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
6837 0           goto obj_val_end;
6838             } else {
6839 0           goto arr_val_end;
6840             }
6841              
6842 0           obj_begin:
6843             /* push container */
6844 0           ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
6845 0           (ctn->tag & YYJSON_TAG_MASK);
6846 0 0         val_incr();
    0          
6847 0           val->tag = YYJSON_TYPE_OBJ;
6848             /* offset to the parent */
6849 0           val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
6850 0           ctn = val;
6851 0           ctn_len = 0;
6852              
6853 0           obj_key_begin:
6854 0 0         save_incr_state(obj_key_begin);
6855 0           obj_key_continue:
6856 0 0         if (likely(*cur == '"')) {
6857 0 0         val_incr();
    0          
6858 0 0         ctn_len++;
6859 0 0         if (likely(read_str_con(&cur, end, flg, val, &msg, con)))
6860 0           goto obj_key_end;
6861 0           goto fail_string;
6862             }
6863 0 0         if (likely(*cur == '}')) {
6864 0           cur++;
6865 0 0         if (likely(ctn_len == 0)) goto obj_end;
6866 0 0         while (*cur != ',') cur--;
6867 0           goto fail_trailing_comma;
6868             }
6869 0 0         if (char_is_space(*cur)) {
6870 0 0         while (char_is_space(*++cur));
6871 0           goto obj_key_continue;
6872             }
6873 0           goto fail_character_obj_key;
6874              
6875 0           obj_key_end:
6876 0 0         save_incr_state(obj_key_end);
6877 0 0         if (*cur == ':') {
6878 0           cur++;
6879 0           goto obj_val_begin;
6880             }
6881 0 0         if (char_is_space(*cur)) {
6882 0 0         while (char_is_space(*++cur));
6883 0           goto obj_key_end;
6884             }
6885 0           goto fail_character_obj_sep;
6886              
6887 0           obj_val_begin:
6888 0 0         save_incr_state(obj_val_begin);
6889 0           obj_val_continue:
6890 0 0         if (*cur == '"') {
6891 0           val++;
6892 0 0         ctn_len++;
6893 0 0         if (likely(read_str_con(&cur, end, flg, val, &msg, con)))
6894 0           goto obj_val_end;
6895 0           goto fail_string;
6896             }
6897 0 0         if (char_is_num(*cur)) {
6898 0           val++;
6899 0           ctn_len++;
6900 0 0         if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_maybe_end;
6901 0           goto fail_number;
6902             }
6903 0 0         if (*cur == '{') {
6904 0           cur++;
6905 0           goto obj_begin;
6906             }
6907 0 0         if (*cur == '[') {
6908 0           cur++;
6909 0           goto arr_begin;
6910             }
6911 0 0         if (*cur == 't') {
6912 0           val++;
6913 0           ctn_len++;
6914 0 0         if (likely(read_true(&cur, val))) goto obj_val_end;
6915 0           goto fail_literal_true;
6916             }
6917 0 0         if (*cur == 'f') {
6918 0           val++;
6919 0           ctn_len++;
6920 0 0         if (likely(read_false(&cur, val))) goto obj_val_end;
6921 0           goto fail_literal_false;
6922             }
6923 0 0         if (*cur == 'n') {
6924 0           val++;
6925 0           ctn_len++;
6926 0 0         if (likely(read_null(&cur, val))) goto obj_val_end;
6927 0           goto fail_literal_null;
6928             }
6929 0 0         if (char_is_space(*cur)) {
6930 0 0         while (char_is_space(*++cur));
6931 0           goto obj_val_continue;
6932             }
6933 0           goto fail_character_val;
6934              
6935 0           obj_val_maybe_end:
6936             /* if incremental parsing stops in the middle of a number, it may continue
6937             with more digits, so obj val maybe didn't end yet */
6938 0 0         check_maybe_truncated_number();
    0          
6939              
6940 0           obj_val_end:
6941 0 0         save_incr_state(obj_val_end);
6942 0 0         if (likely(*cur == ',')) {
6943 0           cur++;
6944 0           goto obj_key_begin;
6945             }
6946 0 0         if (likely(*cur == '}')) {
6947 0           cur++;
6948 0           goto obj_end;
6949             }
6950 0 0         if (char_is_space(*cur)) {
6951 0 0         while (char_is_space(*++cur));
6952 0           goto obj_val_end;
6953             }
6954 0           goto fail_character_obj_end;
6955              
6956 0           obj_end:
6957             /* pop container */
6958 0           ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
6959             /* point to the next value */
6960 0           ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
6961 0           ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
6962 0 0         if (unlikely(ctn == ctn_parent)) goto doc_end;
6963 0           ctn = ctn_parent;
6964 0           ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
6965 0 0         if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
6966 0           goto obj_val_end;
6967             } else {
6968 0           goto arr_val_end;
6969             }
6970              
6971 0           doc_end:
6972             /* check invalid contents after json document */
6973 0 0         if (unlikely(cur < end) && !has_flg(STOP_WHEN_DONE)) {
    0          
6974 0 0         save_incr_state(doc_end);
6975 0 0         while (char_is_space(*cur)) cur++;
6976 0 0         if (unlikely(cur < end)) goto fail_garbage;
6977             }
6978              
6979 0           **pre = '\0';
6980 0           doc = (yyjson_doc *)val_hdr;
6981 0           doc->root = val_hdr + hdr_len;
6982 0           doc->alc = alc;
6983 0           doc->dat_read = (usize)(cur - hdr);
6984 0           doc->val_read = (usize)((val - doc->root) + 1);
6985 0 0         doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
6986 0           state->hdr = NULL;
6987 0           state->val_hdr = NULL;
6988 0           memset(err, 0, sizeof(yyjson_read_err));
6989 0           return doc;
6990              
6991 0           unexpected_end:
6992 0           err->pos = len;
6993             /* if no nore data, stop the incr read */
6994 0 0         if (unlikely(len >= state->buf_len)) {
6995 0           err->code = YYJSON_READ_ERROR_UNEXPECTED_END;
6996 0           err->msg = MSG_NOT_END;
6997 0           return NULL;
6998             }
6999             /* save parser state in extended error struct, in addition to what was
7000             * stored in the last save_incr_state */
7001 0           err->code = YYJSON_READ_ERROR_MORE;
7002 0           err->msg = "need more data";
7003 0           state->val_end = val_end;
7004 0           state->ctn = ctn;
7005 0           state->alc_len = alc_len;
7006             /* restore the end where we've inserted a null terminator */
7007 0           *end = saved_end;
7008 0           return NULL;
7009              
7010 0 0         fail_string: return_err(cur, INVALID_STRING, msg);
7011 0 0         fail_number: return_err(cur, INVALID_NUMBER, msg);
7012 0 0         fail_alloc: return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
7013 0 0         fail_trailing_comma: return_err(cur, JSON_STRUCTURE, MSG_COMMA);
7014 0 0         fail_literal_true: return_err(cur, LITERAL, MSG_CHAR_T);
7015 0 0         fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F);
7016 0 0         fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N);
7017 0 0         fail_character_val: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
7018 0 0         fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END);
7019 0 0         fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY);
7020 0 0         fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
7021 0 0         fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
7022 0 0         fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
7023              
7024             #undef val_incr
7025             #undef return_err
7026             #undef return_err_inv_param
7027             #undef save_incr_state
7028             #undef check_maybe_truncated_number
7029             }
7030              
7031             #endif /* YYJSON_DISABLE_INCR_READER */
7032              
7033             #undef has_flg
7034             #undef has_allow
7035             #endif /* YYJSON_DISABLE_READER */
7036              
7037              
7038              
7039             #if !YYJSON_DISABLE_WRITER /* writer begin */
7040              
7041             /* Check write flag, avoids `always false` warning when disabled. */
7042             #define has_flg(_flg) unlikely(has_wflag(flg, YYJSON_WRITE_##_flg, 0))
7043             #define has_allow(_flg) unlikely(has_wflag(flg, YYJSON_WRITE_ALLOW_##_flg, 1))
7044             static_inline bool has_wflag(yyjson_write_flag flg, yyjson_write_flag chk,
7045             bool non_standard) {
7046             #if YYJSON_DISABLE_NON_STANDARD
7047             if (non_standard) return false;
7048             #endif
7049 75239           return (flg & chk) != 0;
7050             }
7051              
7052             /*==============================================================================
7053             * MARK: - Integer Writer (Private)
7054             *
7055             * The maximum value of uint32_t is 4294967295 (10 digits),
7056             * these digits are named as 'aabbccddee' here.
7057             *
7058             * Although most compilers may convert the "division by constant value" into
7059             * "multiply and shift", manual conversion can still help some compilers
7060             * generate fewer and better instructions.
7061             *
7062             * Reference:
7063             * Division by Invariant Integers using Multiplication, 1994.
7064             * https://gmplib.org/~tege/divcnst-pldi94.pdf
7065             * Improved division by invariant integers, 2011.
7066             * https://gmplib.org/~tege/division-paper.pdf
7067             *============================================================================*/
7068              
7069             /** Digit table from 00 to 99. */
7070             yyjson_align(2)
7071             static const char digit_table[200] = {
7072             '0', '0', '0', '1', '0', '2', '0', '3', '0', '4',
7073             '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
7074             '1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
7075             '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
7076             '2', '0', '2', '1', '2', '2', '2', '3', '2', '4',
7077             '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
7078             '3', '0', '3', '1', '3', '2', '3', '3', '3', '4',
7079             '3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
7080             '4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
7081             '4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
7082             '5', '0', '5', '1', '5', '2', '5', '3', '5', '4',
7083             '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
7084             '6', '0', '6', '1', '6', '2', '6', '3', '6', '4',
7085             '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
7086             '7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
7087             '7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
7088             '8', '0', '8', '1', '8', '2', '8', '3', '8', '4',
7089             '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
7090             '9', '0', '9', '1', '9', '2', '9', '3', '9', '4',
7091             '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'
7092             };
7093              
7094             static_inline u8 *write_u32_len_8(u32 val, u8 *buf) {
7095             u32 aa, bb, cc, dd, aabb, ccdd; /* 8 digits: aabbccdd */
7096 0           aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
7097 0           ccdd = val - aabb * 10000; /* (val % 10000) */
7098 0           aa = (aabb * 5243) >> 19; /* (aabb / 100) */
7099 0           cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */
7100 0           bb = aabb - aa * 100; /* (aabb % 100) */
7101 0           dd = ccdd - cc * 100; /* (ccdd % 100) */
7102 0           byte_copy_2(buf + 0, digit_table + aa * 2);
7103 0           byte_copy_2(buf + 2, digit_table + bb * 2);
7104 0           byte_copy_2(buf + 4, digit_table + cc * 2);
7105 0           byte_copy_2(buf + 6, digit_table + dd * 2);
7106 0           return buf + 8;
7107             }
7108              
7109             static_inline u8 *write_u32_len_4(u32 val, u8 *buf) {
7110             u32 aa, bb; /* 4 digits: aabb */
7111 0           aa = (val * 5243) >> 19; /* (val / 100) */
7112 0           bb = val - aa * 100; /* (val % 100) */
7113 0           byte_copy_2(buf + 0, digit_table + aa * 2);
7114 0           byte_copy_2(buf + 2, digit_table + bb * 2);
7115 0           return buf + 4;
7116             }
7117              
7118             static_inline u8 *write_u32_len_1_to_8(u32 val, u8 *buf) {
7119             u32 aa, bb, cc, dd, aabb, bbcc, ccdd, lz;
7120              
7121 35053           if (val < 100) { /* 1-2 digits: aa */
7122 35053           lz = val < 10; /* leading zero: 0 or 1 */
7123 35053           byte_copy_2(buf + 0, digit_table + val * 2 + lz);
7124 35053           buf -= lz;
7125 35053           return buf + 2;
7126              
7127 0 0         } else if (val < 10000) { /* 3-4 digits: aabb */
    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          
7128 0           aa = (val * 5243) >> 19; /* (val / 100) */
7129 0           bb = val - aa * 100; /* (val % 100) */
7130 0           lz = aa < 10; /* leading zero: 0 or 1 */
7131 0           byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7132 0           buf -= lz;
7133 0           byte_copy_2(buf + 2, digit_table + bb * 2);
7134 0           return buf + 4;
7135              
7136 0 0         } else if (val < 1000000) { /* 5-6 digits: aabbcc */
    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          
7137 0           aa = (u32)(((u64)val * 429497) >> 32); /* (val / 10000) */
7138 0           bbcc = val - aa * 10000; /* (val % 10000) */
7139 0           bb = (bbcc * 5243) >> 19; /* (bbcc / 100) */
7140 0           cc = bbcc - bb * 100; /* (bbcc % 100) */
7141 0           lz = aa < 10; /* leading zero: 0 or 1 */
7142 0           byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7143 0           buf -= lz;
7144 0           byte_copy_2(buf + 2, digit_table + bb * 2);
7145 0           byte_copy_2(buf + 4, digit_table + cc * 2);
7146 0           return buf + 6;
7147              
7148             } else { /* 7-8 digits: aabbccdd */
7149 0           aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
7150 0           ccdd = val - aabb * 10000; /* (val % 10000) */
7151 0           aa = (aabb * 5243) >> 19; /* (aabb / 100) */
7152 0           cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */
7153 0           bb = aabb - aa * 100; /* (aabb % 100) */
7154 0           dd = ccdd - cc * 100; /* (ccdd % 100) */
7155 0           lz = aa < 10; /* leading zero: 0 or 1 */
7156 0           byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7157 0           buf -= lz;
7158 0           byte_copy_2(buf + 2, digit_table + bb * 2);
7159 0           byte_copy_2(buf + 4, digit_table + cc * 2);
7160 0           byte_copy_2(buf + 6, digit_table + dd * 2);
7161 0           return buf + 8;
7162             }
7163             }
7164              
7165             static_inline u8 *write_u32_len_5_to_8(u32 val, u8 *buf) {
7166             u32 aa, bb, cc, dd, aabb, bbcc, ccdd, lz;
7167              
7168 0           if (val < 1000000) { /* 5-6 digits: aabbcc */
7169 0           aa = (u32)(((u64)val * 429497) >> 32); /* (val / 10000) */
7170 0           bbcc = val - aa * 10000; /* (val % 10000) */
7171 0           bb = (bbcc * 5243) >> 19; /* (bbcc / 100) */
7172 0           cc = bbcc - bb * 100; /* (bbcc % 100) */
7173 0           lz = aa < 10; /* leading zero: 0 or 1 */
7174 0           byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7175 0           buf -= lz;
7176 0           byte_copy_2(buf + 2, digit_table + bb * 2);
7177 0           byte_copy_2(buf + 4, digit_table + cc * 2);
7178 0           return buf + 6;
7179              
7180             } else { /* 7-8 digits: aabbccdd */
7181 0           aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
7182 0           ccdd = val - aabb * 10000; /* (val % 10000) */
7183 0           aa = (aabb * 5243) >> 19; /* (aabb / 100) */
7184 0           cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */
7185 0           bb = aabb - aa * 100; /* (aabb % 100) */
7186 0           dd = ccdd - cc * 100; /* (ccdd % 100) */
7187 0           lz = aa < 10; /* leading zero: 0 or 1 */
7188 0           byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7189 0           buf -= lz;
7190 0           byte_copy_2(buf + 2, digit_table + bb * 2);
7191 0           byte_copy_2(buf + 4, digit_table + cc * 2);
7192 0           byte_copy_2(buf + 6, digit_table + dd * 2);
7193 0           return buf + 8;
7194             }
7195             }
7196              
7197             static_inline u8 *write_u64(u64 val, u8 *buf) {
7198             u64 tmp, hgh;
7199             u32 mid, low;
7200              
7201 35053 50         if (val < 100000000) { /* 1-8 digits */
    50          
    50          
    0          
    0          
    0          
    0          
7202 35053 50         buf = write_u32_len_1_to_8((u32)val, buf);
    50          
    50          
    0          
    0          
    0          
    0          
    0          
7203 35053           return buf;
7204              
7205 0 0         } else if (val < (u64)100000000 * 100000000) { /* 9-16 digits */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7206 0           hgh = val / 100000000; /* (val / 100000000) */
7207 0           low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
7208 0 0         buf = write_u32_len_1_to_8((u32)hgh, buf);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7209 0           buf = write_u32_len_8(low, buf);
7210 0           return buf;
7211              
7212             } else { /* 17-20 digits */
7213 0           tmp = val / 100000000; /* (val / 100000000) */
7214 0           low = (u32)(val - tmp * 100000000); /* (val % 100000000) */
7215 0           hgh = (u32)(tmp / 10000); /* (tmp / 10000) */
7216 0           mid = (u32)(tmp - hgh * 10000); /* (tmp % 10000) */
7217 0 0         buf = write_u32_len_5_to_8((u32)hgh, buf);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7218 0           buf = write_u32_len_4(mid, buf);
7219 0           buf = write_u32_len_8(low, buf);
7220 0           return buf;
7221             }
7222             }
7223              
7224              
7225              
7226             /*==============================================================================
7227             * MARK: - Number Writer (Private)
7228             *============================================================================*/
7229              
7230             #if !YYJSON_DISABLE_FAST_FP_CONV /* FP_WRITER */
7231              
7232             /** Trailing zero count table for number 0 to 99.
7233             (generate with misc/make_tables.c) */
7234             static const u8 dec_trailing_zero_table[] = {
7235             2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7236             1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7237             1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7238             1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7239             1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7240             1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7241             1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7242             1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7243             1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7244             1, 0, 0, 0, 0, 0, 0, 0, 0, 0
7245             };
7246              
7247             static_inline u8 *write_u64_len_1_to_16(u64 val, u8 *buf) {
7248             u64 hgh;
7249             u32 low;
7250 0           if (val < 100000000) { /* 1-8 digits */
7251 0 0         buf = write_u32_len_1_to_8((u32)val, buf);
    0          
7252 0           return buf;
7253             } else { /* 9-16 digits */
7254 0           hgh = val / 100000000; /* (val / 100000000) */
7255 0           low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
7256 0 0         buf = write_u32_len_1_to_8((u32)hgh, buf);
    0          
7257 0           buf = write_u32_len_8(low, buf);
7258 0           return buf;
7259             }
7260             }
7261              
7262             static_inline u8 *write_u64_len_1_to_17(u64 val, u8 *buf) {
7263             u64 hgh;
7264             u32 mid, low, one;
7265 0           if (val >= (u64)100000000 * 10000000) { /* len: 16 to 17 */
7266 0           hgh = val / 100000000; /* (val / 100000000) */
7267 0           low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
7268 0           one = (u32)(hgh / 100000000); /* (hgh / 100000000) */
7269 0           mid = (u32)(hgh - (u64)one * 100000000); /* (hgh % 100000000) */
7270 0           *buf = (u8)((u8)one + (u8)'0');
7271 0           buf += one > 0;
7272 0           buf = write_u32_len_8(mid, buf);
7273 0           buf = write_u32_len_8(low, buf);
7274 0           return buf;
7275 0 0         } else if (val >= (u64)100000000){ /* len: 9 to 15 */
    0          
7276 0           hgh = val / 100000000; /* (val / 100000000) */
7277 0           low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
7278 0 0         buf = write_u32_len_1_to_8((u32)hgh, buf);
    0          
7279 0           buf = write_u32_len_8(low, buf);
7280 0           return buf;
7281             } else { /* len: 1 to 8 */
7282 0 0         buf = write_u32_len_1_to_8((u32)val, buf);
    0          
7283 0           return buf;
7284             }
7285             }
7286              
7287             /**
7288             Write an unsigned integer with a length of 7 to 9 with trailing zero trimmed.
7289             These digits are named as "abbccddee" here.
7290             For example, input 123456000, output "123456".
7291             */
7292             static_inline u8 *write_u32_len_7_to_9_trim(u32 val, u8 *buf) {
7293             bool lz;
7294             u32 tz, tz1, tz2;
7295              
7296 0           u32 abbcc = val / 10000; /* (abbccddee / 10000) */
7297 0           u32 ddee = val - abbcc * 10000; /* (abbccddee % 10000) */
7298 0           u32 abb = (u32)(((u64)abbcc * 167773) >> 24); /* (abbcc / 100) */
7299 0           u32 a = (abb * 41) >> 12; /* (abb / 100) */
7300 0           u32 bb = abb - a * 100; /* (abb % 100) */
7301 0           u32 cc = abbcc - abb * 100; /* (abbcc % 100) */
7302              
7303             /* write abbcc */
7304 0           buf[0] = (u8)(a + '0');
7305 0           buf += a > 0;
7306 0 0         lz = bb < 10 && a == 0;
    0          
7307 0           byte_copy_2(buf + 0, digit_table + bb * 2 + lz);
7308 0           buf -= lz;
7309 0           byte_copy_2(buf + 2, digit_table + cc * 2);
7310              
7311 0 0         if (ddee) {
    0          
7312 0           u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */
7313 0           u32 ee = ddee - dd * 100; /* (ddee % 100) */
7314 0           byte_copy_2(buf + 4, digit_table + dd * 2);
7315 0           byte_copy_2(buf + 6, digit_table + ee * 2);
7316 0           tz1 = dec_trailing_zero_table[dd];
7317 0           tz2 = dec_trailing_zero_table[ee];
7318 0 0         tz = ee ? tz2 : (tz1 + 2);
    0          
7319 0           buf += 8 - tz;
7320 0           return buf;
7321             } else {
7322 0           tz1 = dec_trailing_zero_table[bb];
7323 0           tz2 = dec_trailing_zero_table[cc];
7324 0 0         tz = cc ? tz2 : (tz1 + tz2);
    0          
7325 0           buf += 4 - tz;
7326 0           return buf;
7327             }
7328             }
7329              
7330             /**
7331             Write an unsigned integer with a length of 16 or 17 with trailing zero trimmed.
7332             These digits are named as "abbccddeeffgghhii" here.
7333             For example, input 1234567890123000, output "1234567890123".
7334             */
7335             static_inline u8 *write_u64_len_16_to_17_trim(u64 val, u8 *buf) {
7336             u32 tz, tz1, tz2;
7337              
7338 1           u32 abbccddee = (u32)(val / 100000000);
7339 1           u32 ffgghhii = (u32)(val - (u64)abbccddee * 100000000);
7340 1           u32 abbcc = abbccddee / 10000;
7341 1           u32 ddee = abbccddee - abbcc * 10000;
7342 1           u32 abb = (u32)(((u64)abbcc * 167773) >> 24); /* (abbcc / 100) */
7343 1           u32 a = (abb * 41) >> 12; /* (abb / 100) */
7344 1           u32 bb = abb - a * 100; /* (abb % 100) */
7345 1           u32 cc = abbcc - abb * 100; /* (abbcc % 100) */
7346 1           buf[0] = (u8)(a + '0');
7347 1           buf += a > 0;
7348 1           byte_copy_2(buf + 0, digit_table + bb * 2);
7349 1           byte_copy_2(buf + 2, digit_table + cc * 2);
7350              
7351 1 0         if (ffgghhii) {
    50          
    0          
7352 0           u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */
7353 0           u32 ee = ddee - dd * 100; /* (ddee % 100) */
7354 0           u32 ffgg = (u32)(((u64)ffgghhii * 109951163) >> 40); /* (val / 10000) */
7355 0           u32 hhii = ffgghhii - ffgg * 10000; /* (val % 10000) */
7356 0           u32 ff = (ffgg * 5243) >> 19; /* (aabb / 100) */
7357 0           u32 gg = ffgg - ff * 100; /* (aabb % 100) */
7358 0           byte_copy_2(buf + 4, digit_table + dd * 2);
7359 0           byte_copy_2(buf + 6, digit_table + ee * 2);
7360 0           byte_copy_2(buf + 8, digit_table + ff * 2);
7361 0           byte_copy_2(buf + 10, digit_table + gg * 2);
7362 0 0         if (hhii) {
    0          
    0          
7363 0           u32 hh = (hhii * 5243) >> 19; /* (ccdd / 100) */
7364 0           u32 ii = hhii - hh * 100; /* (ccdd % 100) */
7365 0           byte_copy_2(buf + 12, digit_table + hh * 2);
7366 0           byte_copy_2(buf + 14, digit_table + ii * 2);
7367 0           tz1 = dec_trailing_zero_table[hh];
7368 0           tz2 = dec_trailing_zero_table[ii];
7369 0 0         tz = ii ? tz2 : (tz1 + 2);
    0          
    0          
7370 0           return buf + 16 - tz;
7371             } else {
7372 0           tz1 = dec_trailing_zero_table[ff];
7373 0           tz2 = dec_trailing_zero_table[gg];
7374 0 0         tz = gg ? tz2 : (tz1 + 2);
    0          
    0          
7375 0           return buf + 12 - tz;
7376             }
7377             } else {
7378 1 0         if (ddee) {
    50          
    0          
7379 0           u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */
7380 0           u32 ee = ddee - dd * 100; /* (ddee % 100) */
7381 0           byte_copy_2(buf + 4, digit_table + dd * 2);
7382 0           byte_copy_2(buf + 6, digit_table + ee * 2);
7383 0           tz1 = dec_trailing_zero_table[dd];
7384 0           tz2 = dec_trailing_zero_table[ee];
7385 0 0         tz = ee ? tz2 : (tz1 + 2);
    0          
    0          
7386 0           return buf + 8 - tz;
7387             } else {
7388 1           tz1 = dec_trailing_zero_table[bb];
7389 1           tz2 = dec_trailing_zero_table[cc];
7390 1 0         tz = cc ? tz2 : (tz1 + tz2);
    50          
    0          
7391 1           return buf + 4 - tz;
7392             }
7393             }
7394             }
7395              
7396             /** Write exponent part in range `e-45` to `e38`. */
7397             static_inline u8 *write_f32_exp(i32 exp, u8 *buf) {
7398             bool lz;
7399             byte_copy_2(buf, "e-");
7400 0 0         buf += 2 - (exp >= 0);
    0          
7401 0           exp = exp < 0 ? -exp : exp;
7402 0           lz = exp < 10;
7403 0           byte_copy_2(buf + 0, digit_table + (u32)exp * 2 + lz);
7404 0           return buf + 2 - lz;
7405             }
7406              
7407             /** Write exponent part in range `e-324` to `e308`. */
7408             static_inline u8 *write_f64_exp(i32 exp, u8 *buf) {
7409             byte_copy_2(buf, "e-");
7410 0 0         buf += 2 - (exp >= 0);
    0          
    0          
7411 0           exp = exp < 0 ? -exp : exp;
7412 0 0         if (exp < 100) {
    0          
    0          
7413 0           bool lz = exp < 10;
7414 0           byte_copy_2(buf + 0, digit_table + (u32)exp * 2 + lz);
7415 0           return buf + 2 - lz;
7416             } else {
7417 0           u32 hi = ((u32)exp * 656) >> 16; /* exp / 100 */
7418 0           u32 lo = (u32)exp - hi * 100; /* exp % 100 */
7419 0           buf[0] = (u8)((u8)hi + (u8)'0');
7420 0           byte_copy_2(buf + 1, digit_table + lo * 2);
7421 0           return buf + 3;
7422             }
7423             }
7424              
7425             /** Magic number for fast `divide by power of 10`. */
7426             typedef struct {
7427             u64 p10, mul;
7428             u32 shr1, shr2;
7429             } div_pow10_magic;
7430              
7431             /** Generated with llvm, see https://github.com/llvm/llvm-project/
7432             blob/main/llvm/lib/Support/DivisionByConstantInfo.cpp */
7433             static const div_pow10_magic div_pow10_table[] = {
7434             { U64(0x00000000, 0x00000001), U64(0x00000000, 0x00000000), 0, 0 },
7435             { U64(0x00000000, 0x0000000A), U64(0xCCCCCCCC, 0xCCCCCCCD), 0, 3 },
7436             { U64(0x00000000, 0x00000064), U64(0x28F5C28F, 0x5C28F5C3), 2, 2 },
7437             { U64(0x00000000, 0x000003E8), U64(0x20C49BA5, 0xE353F7CF), 3, 4 },
7438             { U64(0x00000000, 0x00002710), U64(0x346DC5D6, 0x3886594B), 0, 11 },
7439             { U64(0x00000000, 0x000186A0), U64(0x0A7C5AC4, 0x71B47843), 5, 7 },
7440             { U64(0x00000000, 0x000F4240), U64(0x431BDE82, 0xD7B634DB), 0, 18 },
7441             { U64(0x00000000, 0x00989680), U64(0xD6BF94D5, 0xE57A42BD), 0, 23 },
7442             { U64(0x00000000, 0x05F5E100), U64(0xABCC7711, 0x8461CEFD), 0, 26 },
7443             { U64(0x00000000, 0x3B9ACA00), U64(0x0044B82F, 0xA09B5A53), 9, 11 },
7444             { U64(0x00000002, 0x540BE400), U64(0xDBE6FECE, 0xBDEDD5BF), 0, 33 },
7445             { U64(0x00000017, 0x4876E800), U64(0xAFEBFF0B, 0xCB24AAFF), 0, 36 },
7446             { U64(0x000000E8, 0xD4A51000), U64(0x232F3302, 0x5BD42233), 0, 37 },
7447             { U64(0x00000918, 0x4E72A000), U64(0x384B84D0, 0x92ED0385), 0, 41 },
7448             { U64(0x00005AF3, 0x107A4000), U64(0x0B424DC3, 0x5095CD81), 0, 42 },
7449             { U64(0x00038D7E, 0xA4C68000), U64(0x00024075, 0xF3DCEAC3), 15, 20 },
7450             { U64(0x002386F2, 0x6FC10000), U64(0x39A5652F, 0xB1137857), 0, 51 },
7451             { U64(0x01634578, 0x5D8A0000), U64(0x00005C3B, 0xD5191B53), 17, 22 },
7452             { U64(0x0DE0B6B3, 0xA7640000), U64(0x000049C9, 0x7747490F), 18, 24 },
7453             { U64(0x8AC72304, 0x89E80000), U64(0x760F253E, 0xDB4AB0d3), 0, 62 },
7454             };
7455              
7456             /** Divide a number by power of 10. */
7457             static_inline void div_pow10(u64 num, u32 exp, u64 *div, u64 *mod, u64 *p10) {
7458             u64 hi, lo;
7459 0           div_pow10_magic m = div_pow10_table[exp];
7460 0           u128_mul(num >> m.shr1, m.mul, &hi, &lo);
7461 0           *div = hi >> m.shr2;
7462 0           *mod = num - (*div * m.p10);
7463 0           *p10 = m.p10;
7464 0           }
7465              
7466             /** Multiplies 64-bit integer and returns highest 64-bit rounded value. */
7467             static_inline u32 u64_round_to_odd(u64 u, u32 cp) {
7468             u64 hi, lo;
7469             u32 y_hi, y_lo;
7470 0           u128_mul(cp, u, &hi, &lo);
7471 0           y_hi = (u32)hi;
7472 0           y_lo = (u32)(lo >> 32);
7473 0           return y_hi | (y_lo > 1);
7474             }
7475              
7476             /** Multiplies 128-bit integer and returns highest 64-bit rounded value. */
7477             static_inline u64 u128_round_to_odd(u64 hi, u64 lo, u64 cp) {
7478             u64 x_hi, x_lo, y_hi, y_lo;
7479             u128_mul(cp, lo, &x_hi, &x_lo);
7480 0           u128_mul_add(cp, hi, x_hi, &y_hi, &y_lo);
7481 0           return y_hi | (y_lo > 1);
7482             }
7483              
7484             /** Convert f32 from binary to decimal (shortest but may have trailing zeros).
7485             The input should not be 0, inf or nan. */
7486             static_inline void f32_bin_to_dec(u32 sig_raw, u32 exp_raw,
7487             u32 sig_bin, i32 exp_bin,
7488             u32 *sig_dec, i32 *exp_dec) {
7489              
7490             bool is_even, irregular, round_up, trim;
7491             bool u0_inside, u1_inside, w0_inside, w1_inside;
7492             u64 p10_hi, p10_lo, hi, lo;
7493             u32 s, sp, cb, cbl, cbr, vb, vbl, vbr, upper, lower, mid;
7494             i32 k, h;
7495              
7496             /* Fast path, see f64_bin_to_dec(). */
7497 0 0         while (likely(sig_raw)) {
    0          
7498             u32 mod, dec, add_1, add_10, s_hi, s_lo;
7499             u32 c, half_ulp, t0, t1;
7500              
7501             /* k = floor(exp_bin * log10(2)); */
7502             /* h = exp_bin + floor(log2(10) * -k); (h = 0/1/2/3) */
7503 0           k = (i32)(exp_bin * 315653) >> 20;
7504 0           h = exp_bin + ((-k * 217707) >> 16);
7505 0           pow10_table_get_sig(-k, &p10_hi, &p10_lo);
7506              
7507             /* sig_bin << (1/2/3/4) */
7508 0           cb = sig_bin << (h + 1);
7509 0           u128_mul(cb, p10_hi, &hi, &lo);
7510 0           s_hi = (u32)(hi);
7511 0           s_lo = (u32)(lo >> 32);
7512 0           mod = s_hi % 10;
7513 0           dec = s_hi - mod;
7514              
7515             /* right shift 4 to fit in u32 */
7516 0           c = (mod << (32 - 4)) | (s_lo >> 4);
7517 0           half_ulp = (u32)(p10_hi >> (32 + 4 - h));
7518              
7519             /* check w1, u0, w0 range */
7520 0           w1_inside = (s_lo >= ((u32)1 << 31));
7521 0 0         if (unlikely(s_lo == ((u32)1 << 31))) break;
    0          
7522 0           u0_inside = (half_ulp >= c);
7523 0 0         if (unlikely(half_ulp == c)) break;
    0          
7524 0           t0 = (u32)10 << (32 - 4);
7525 0           t1 = c + half_ulp;
7526 0           w0_inside = (t1 >= t0);
7527 0 0         if (unlikely(t0 - t1 <= (u32)1)) break;
    0          
7528              
7529 0           trim = (u0_inside | w0_inside);
7530 0 0         add_10 = (w0_inside ? 10 : 0);
    0          
7531 0           add_1 = mod + w1_inside;
7532 0 0         *sig_dec = dec + (trim ? add_10 : add_1);
    0          
7533 0           *exp_dec = k;
7534 0           return;
7535             }
7536              
7537             /* Schubfach algorithm, see f64_bin_to_dec(). */
7538 0 0         irregular = (sig_raw == 0 && exp_raw > 1);
    0          
    0          
    0          
7539 0           is_even = !(sig_bin & 1);
7540 0           cbl = 4 * sig_bin - 2 + irregular;
7541 0           cb = 4 * sig_bin;
7542 0           cbr = 4 * sig_bin + 2;
7543              
7544             /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */
7545             /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */
7546 0 0         k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20;
    0          
7547 0           h = exp_bin + ((-k * 217707) >> 16) + 1;
7548 0           pow10_table_get_sig(-k, &p10_hi, &p10_lo);
7549 0           p10_hi += 1;
7550              
7551 0           vbl = u64_round_to_odd(p10_hi, cbl << h);
7552 0           vb = u64_round_to_odd(p10_hi, cb << h);
7553 0           vbr = u64_round_to_odd(p10_hi, cbr << h);
7554 0           lower = vbl + !is_even;
7555 0           upper = vbr - !is_even;
7556              
7557 0           s = vb / 4;
7558 0 0         if (s >= 10) {
    0          
7559 0           sp = s / 10;
7560 0           u0_inside = (lower <= 40 * sp);
7561 0           w0_inside = (upper >= 40 * sp + 40);
7562 0 0         if (u0_inside != w0_inside) {
    0          
7563 0 0         *sig_dec = sp * 10 + (w0_inside ? 10 : 0);
    0          
7564 0           *exp_dec = k;
7565 0           return;
7566             }
7567             }
7568 0           u1_inside = (lower <= 4 * s);
7569 0           w1_inside = (upper >= 4 * s + 4);
7570 0           mid = 4 * s + 2;
7571 0 0         round_up = (vb > mid) || (vb == mid && (s & 1) != 0);
    0          
    0          
    0          
    0          
    0          
7572 0 0         *sig_dec = s + ((u1_inside != w1_inside) ? w1_inside : round_up);
    0          
7573 0           *exp_dec = k;
7574             }
7575              
7576             /** Convert f64 from binary to decimal (shortest but may have trailing zeros).
7577             The input should not be 0, inf or nan. */
7578             static_inline void f64_bin_to_dec(u64 sig_raw, u32 exp_raw,
7579             u64 sig_bin, i32 exp_bin,
7580             u64 *sig_dec, i32 *exp_dec) {
7581              
7582             bool is_even, irregular, round_up, trim;
7583             bool u0_inside, u1_inside, w0_inside, w1_inside;
7584             u64 s, sp, cb, cbl, cbr, vb, vbl, vbr, p10_hi, p10_lo, upper, lower, mid;
7585             i32 k, h;
7586              
7587             /*
7588             Fast path:
7589             For regular spacing significand 'c', there are 4 candidates:
7590              
7591             u0 u1 c w1 w0
7592             ----|----|----|----|----|-*--|----|----|----|----|----|----|----|----
7593             9 0 1 2 3 4 5 6 7 8 9 0 1
7594             |___________________|___________________|
7595             1ulp
7596              
7597             The `1ulp` is in the range [1.0, 10.0).
7598             If (c - 0.5ulp < u0), trim the last digit and round down.
7599             If (c + 0.5ulp > w0), trim the last digit and round up.
7600             If (c - 0.5ulp < u1), round down.
7601             If (c + 0.5ulp > w1), round up.
7602             */
7603 1 0         while (likely(sig_raw)) {
    50          
    0          
7604             u64 mod, dec, add_1, add_10, s_hi, s_lo;
7605             u64 c, half_ulp, t0, t1;
7606              
7607             /* k = floor(exp_bin * log10(2)); */
7608             /* h = exp_bin + floor(log2(10) * -k); (h = 0/1/2/3) */
7609 1           k = (i32)(exp_bin * 315653) >> 20;
7610 1           h = exp_bin + ((-k * 217707) >> 16);
7611 1           pow10_table_get_sig(-k, &p10_hi, &p10_lo);
7612              
7613             /* sig_bin << (1/2/3/4) */
7614 1           cb = sig_bin << (h + 1);
7615 1           u128_mul(cb, p10_lo, &s_hi, &s_lo);
7616 1           u128_mul_add(cb, p10_hi, s_hi, &s_hi, &s_lo);
7617 1           mod = s_hi % 10;
7618 1           dec = s_hi - mod;
7619              
7620             /* right shift 4 to fit in u64 */
7621 1           c = (mod << (64 - 4)) | (s_lo >> 4);
7622 1           half_ulp = p10_hi >> (4 - h);
7623              
7624             /* check w1, u0, w0 range */
7625 1           w1_inside = (s_lo >= ((u64)1 << 63));
7626 1 0         if (unlikely(s_lo == ((u64)1 << 63))) break;
    50          
    0          
7627 1           u0_inside = (half_ulp >= c);
7628 1 0         if (unlikely(half_ulp == c)) break;
    50          
    0          
7629 1           t0 = ((u64)10 << (64 - 4));
7630 1           t1 = c + half_ulp;
7631 1           w0_inside = (t1 >= t0);
7632 1 0         if (unlikely(t0 - t1 <= (u64)1)) break;
    50          
    0          
7633              
7634 1           trim = (u0_inside | w0_inside);
7635 1 0         add_10 = (w0_inside ? 10 : 0);
    50          
    0          
7636 1           add_1 = mod + w1_inside;
7637 1 0         *sig_dec = dec + (trim ? add_10 : add_1);
    50          
    0          
7638 1           *exp_dec = k;
7639 1           return;
7640             }
7641              
7642             /*
7643             Schubfach algorithm:
7644             Raffaello Giulietti, The Schubfach way to render doubles, 2022.
7645             https://drive.google.com/file/d/1gp5xv4CAa78SVgCeWfGqqI4FfYYYuNFb (Paper)
7646             https://github.com/openjdk/jdk/pull/3402 (Java implementation)
7647             https://github.com/abolz/Drachennest (C++ implementation)
7648             */
7649 0 0         irregular = (sig_raw == 0 && exp_raw > 1);
    0          
    0          
    0          
    0          
    0          
7650 0           is_even = !(sig_bin & 1);
7651 0           cbl = 4 * sig_bin - 2 + irregular;
7652 0           cb = 4 * sig_bin;
7653 0           cbr = 4 * sig_bin + 2;
7654              
7655             /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */
7656             /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */
7657 0 0         k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20;
    0          
    0          
7658 0           h = exp_bin + ((-k * 217707) >> 16) + 1;
7659 0           pow10_table_get_sig(-k, &p10_hi, &p10_lo);
7660 0           p10_lo += 1;
7661              
7662 0           vbl = u128_round_to_odd(p10_hi, p10_lo, cbl << h);
7663 0           vb = u128_round_to_odd(p10_hi, p10_lo, cb << h);
7664 0           vbr = u128_round_to_odd(p10_hi, p10_lo, cbr << h);
7665 0           lower = vbl + !is_even;
7666 0           upper = vbr - !is_even;
7667              
7668 0           s = vb / 4;
7669 0 0         if (s >= 10) {
    0          
    0          
7670 0           sp = s / 10;
7671 0           u0_inside = (lower <= 40 * sp);
7672 0           w0_inside = (upper >= 40 * sp + 40);
7673 0 0         if (u0_inside != w0_inside) {
    0          
    0          
7674 0 0         *sig_dec = sp * 10 + (w0_inside ? 10 : 0);
    0          
    0          
7675 0           *exp_dec = k;
7676 0           return;
7677             }
7678             }
7679 0           u1_inside = (lower <= 4 * s);
7680 0           w1_inside = (upper >= 4 * s + 4);
7681 0           mid = 4 * s + 2;
7682 0 0         round_up = (vb > mid) || (vb == mid && (s & 1) != 0);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7683 0 0         *sig_dec = s + ((u1_inside != w1_inside) ? w1_inside : round_up);
    0          
    0          
7684 0           *exp_dec = k;
7685             }
7686              
7687             /** Convert f64 from binary to decimal (fast but not the shortest).
7688             The input should not be 0, inf, nan. */
7689             static_inline void f64_bin_to_dec_fast(u64 sig_raw, u32 exp_raw,
7690             u64 sig_bin, i32 exp_bin,
7691             u64 *sig_dec, i32 *exp_dec,
7692             bool *round_up) {
7693             u64 cb, p10_hi, p10_lo, s_hi, s_lo;
7694             i32 k, h;
7695             bool irregular, u;
7696              
7697 0 0         irregular = (sig_raw == 0 && exp_raw > 1);
    0          
7698              
7699             /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */
7700             /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */
7701 0 0         k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20;
7702 0           h = exp_bin + ((-k * 217707) >> 16);
7703 0           pow10_table_get_sig(-k, &p10_hi, &p10_lo);
7704              
7705             /* sig_bin << (1/2/3/4) */
7706 0           cb = sig_bin << (h + 1);
7707 0           u128_mul(cb, p10_lo, &s_hi, &s_lo);
7708 0           u128_mul_add(cb, p10_hi, s_hi, &s_hi, &s_lo);
7709              
7710             /* round up */
7711 0 0         u = s_lo >= (irregular ? U64(0x55555555, 0x55555555) : ((u64)1 << 63));
7712              
7713 0           *sig_dec = s_hi + u;
7714 0           *exp_dec = k;
7715 0           *round_up = u;
7716 0           return;
7717             }
7718              
7719             /** Write inf/nan if allowed. */
7720             static_inline u8 *write_inf_or_nan(u8 *buf, yyjson_write_flag flg,
7721             u64 sig_raw, bool sign) {
7722 0 0         if (has_flg(INF_AND_NAN_AS_NULL)) {
    0          
    0          
7723             byte_copy_4(buf, "null");
7724 0           return buf + 4;
7725             }
7726 0 0         if (has_allow(INF_AND_NAN)) {
    0          
    0          
7727 0 0         if (sig_raw == 0) {
    0          
    0          
7728 0           buf[0] = '-';
7729 0           buf += sign;
7730             byte_copy_8(buf, "Infinity");
7731 0           return buf + 8;
7732             } else {
7733             byte_copy_4(buf, "NaN");
7734 0           return buf + 3;
7735             }
7736             }
7737 0           return NULL;
7738             }
7739              
7740             /**
7741             Write a float number (requires 40 bytes buffer).
7742             We follow the ECMAScript specification for printing floating-point numbers,
7743             similar to `Number.prototype.toString()`, but with the following changes:
7744             1. Keep the negative sign of `-0.0` to preserve input information.
7745             2. Keep decimal point to indicate the number is floating point.
7746             3. Remove positive sign in the exponent part.
7747             */
7748 0           static_noinline u8 *write_f32_raw(u8 *buf, u64 raw_f64,
7749             yyjson_write_flag flg) {
7750             u32 sig_bin, sig_dec, sig_raw;
7751             i32 exp_bin, exp_dec, sig_len, dot_ofs;
7752             u32 exp_raw, raw;
7753             u8 *end;
7754             bool sign;
7755              
7756             /* cast double to float */
7757 0           raw = f32_to_bits(f64_to_f32(f64_from_bits(raw_f64)));
7758              
7759             /* decode raw bytes from IEEE-754 double format. */
7760 0           sign = (bool)(raw >> (F32_BITS - 1));
7761 0           sig_raw = raw & F32_SIG_MASK;
7762 0           exp_raw = (raw & F32_EXP_MASK) >> F32_SIG_BITS;
7763              
7764             /* return inf or nan */
7765 0 0         if (unlikely(exp_raw == ((u32)1 << F32_EXP_BITS) - 1)) {
7766 0           return write_inf_or_nan(buf, flg, sig_raw, sign);
7767             }
7768              
7769             /* add sign for all finite number */
7770 0           buf[0] = '-';
7771 0           buf += sign;
7772              
7773             /* return zero */
7774 0 0         if ((raw << 1) == 0) {
7775             byte_copy_4(buf, "0.0");
7776 0           return buf + 3;
7777             }
7778              
7779 0 0         if (likely(exp_raw != 0)) {
7780             /* normal number */
7781 0           sig_bin = sig_raw | ((u32)1 << F32_SIG_BITS);
7782 0           exp_bin = (i32)exp_raw - F32_EXP_BIAS - F32_SIG_BITS;
7783              
7784             /* fast path for small integer number without fraction */
7785 0 0         if ((-F32_SIG_BITS <= exp_bin && exp_bin <= 0) &&
    0          
7786 0 0         (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) {
7787 0           sig_dec = sig_bin >> -exp_bin; /* range: [1, 0xFFFFFF] */
7788 0 0         buf = write_u32_len_1_to_8(sig_dec, buf);
7789             byte_copy_2(buf, ".0");
7790 0           return buf + 2;
7791             }
7792              
7793             /* binary to decimal */
7794             f32_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
7795              
7796             /* the sig length is 7 or 9 */
7797 0 0         sig_len = 7 + (sig_dec >= (u32)10000000) + (sig_dec >= (u32)100000000);
7798              
7799             /* the decimal point offset relative to the first digit */
7800 0           dot_ofs = sig_len + exp_dec;
7801              
7802 0 0         if (-6 < dot_ofs && dot_ofs <= 21) {
    0          
7803             i32 num_sep_pos, dot_set_pos, pre_ofs;
7804             u8 *num_hdr, *num_end, *num_sep, *dot_end;
7805             bool no_pre_zero;
7806              
7807             /* fill zeros */
7808 0           memset(buf, '0', 32);
7809              
7810             /* not prefixed with zero, e.g. 1.234, 1234.0 */
7811 0           no_pre_zero = (dot_ofs > 0);
7812              
7813             /* write the number as digits */
7814 0 0         pre_ofs = no_pre_zero ? 0 : (2 - dot_ofs);
7815 0           num_hdr = buf + pre_ofs;
7816 0 0         num_end = write_u32_len_7_to_9_trim(sig_dec, num_hdr);
7817              
7818             /* seperate these digits to leave a space for dot */
7819 0 0         num_sep_pos = no_pre_zero ? dot_ofs : 0;
7820 0           num_sep = num_hdr + num_sep_pos;
7821 0           byte_move_8(num_sep + no_pre_zero, num_sep);
7822 0           num_end += no_pre_zero;
7823              
7824             /* write the dot */
7825 0           dot_set_pos = yyjson_max(dot_ofs, 1);
7826 0           buf[dot_set_pos] = '.';
7827              
7828             /* return the ending */
7829 0           dot_end = buf + dot_ofs + 2;
7830 0           return yyjson_max(dot_end, num_end);
7831              
7832             } else {
7833             /* write with scientific notation, e.g. 1.234e56 */
7834 0 0         end = write_u32_len_7_to_9_trim(sig_dec, buf + 1);
7835 0           end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */
7836 0           exp_dec += sig_len - 1;
7837 0           buf[0] = buf[1];
7838 0           buf[1] = '.';
7839 0           return write_f32_exp(exp_dec, end);
7840             }
7841              
7842             } else {
7843             /* subnormal number */
7844 0           sig_bin = sig_raw;
7845 0           exp_bin = 1 - F32_EXP_BIAS - F32_SIG_BITS;
7846              
7847             /* binary to decimal */
7848             f32_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
7849              
7850             /* write significand part */
7851 0 0         end = write_u32_len_1_to_8(sig_dec, buf + 1);
7852 0           buf[0] = buf[1];
7853 0           buf[1] = '.';
7854 0           exp_dec += (i32)(end - buf) - 2;
7855              
7856             /* trim trailing zeros */
7857 0           end -= *(end - 1) == '0'; /* branchless for last zero */
7858 0           end -= *(end - 1) == '0'; /* branchless for second last zero */
7859 0 0         while (*(end - 1) == '0') end--; /* for unlikely more zeros */
7860 0           end -= *(end - 1) == '.'; /* remove dot, e.g. 2.e-321 -> 2e-321 */
7861              
7862             /* write exponent part */
7863 0           return write_f32_exp(exp_dec, end);
7864             }
7865             }
7866              
7867             /**
7868             Write a double number (requires 40 bytes buffer).
7869             We follow the ECMAScript specification for printing floating-point numbers,
7870             similar to `Number.prototype.toString()`, but with the following changes:
7871             1. Keep the negative sign of `-0.0` to preserve input information.
7872             2. Keep decimal point to indicate the number is floating point.
7873             3. Remove positive sign in the exponent part.
7874             */
7875 1           static_noinline u8 *write_f64_raw(u8 *buf, u64 raw, yyjson_write_flag flg) {
7876             u64 sig_bin, sig_dec, sig_raw;
7877             i32 exp_bin, exp_dec, sig_len, dot_ofs;
7878             u32 exp_raw;
7879             u8 *end;
7880             bool sign;
7881              
7882             /* decode raw bytes from IEEE-754 double format. */
7883 1           sign = (bool)(raw >> (F64_BITS - 1));
7884 1           sig_raw = raw & F64_SIG_MASK;
7885 1           exp_raw = (u32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
7886              
7887             /* return inf or nan */
7888 1 50         if (unlikely(exp_raw == ((u32)1 << F64_EXP_BITS) - 1)) {
7889 0           return write_inf_or_nan(buf, flg, sig_raw, sign);
7890             }
7891              
7892             /* add sign for all finite number */
7893 1           buf[0] = '-';
7894 1           buf += sign;
7895              
7896             /* return zero */
7897 1 50         if ((raw << 1) == 0) {
7898             byte_copy_4(buf, "0.0");
7899 0           return buf + 3;
7900             }
7901              
7902 1 50         if (likely(exp_raw != 0)) {
7903             /* normal number */
7904 1           sig_bin = sig_raw | ((u64)1 << F64_SIG_BITS);
7905 1           exp_bin = (i32)exp_raw - F64_EXP_BIAS - F64_SIG_BITS;
7906              
7907             /* fast path for small integer number without fraction */
7908 1 50         if ((-F64_SIG_BITS <= exp_bin && exp_bin <= 0) &&
    50          
7909 1 50         (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) {
7910 0           sig_dec = sig_bin >> -exp_bin; /* range: [1, 0x1FFFFFFFFFFFFF] */
7911 0 0         buf = write_u64_len_1_to_16(sig_dec, buf);
7912             byte_copy_2(buf, ".0");
7913 0           return buf + 2;
7914             }
7915              
7916             /* binary to decimal */
7917             f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
7918              
7919             /* the sig length is 16 or 17 */
7920 1 50         sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
7921              
7922             /* the decimal point offset relative to the first digit */
7923 1           dot_ofs = sig_len + exp_dec;
7924              
7925 1 50         if (-6 < dot_ofs && dot_ofs <= 21) {
    50          
7926             i32 num_sep_pos, dot_set_pos, pre_ofs;
7927             u8 *num_hdr, *num_end, *num_sep, *dot_end;
7928             bool no_pre_zero;
7929              
7930             /* fill zeros */
7931 1           memset(buf, '0', 32);
7932              
7933             /* not prefixed with zero, e.g. 1.234, 1234.0 */
7934 1           no_pre_zero = (dot_ofs > 0);
7935              
7936             /* write the number as digits */
7937 1 50         pre_ofs = no_pre_zero ? 0 : (2 - dot_ofs);
7938 1           num_hdr = buf + pre_ofs;
7939 1           num_end = write_u64_len_16_to_17_trim(sig_dec, num_hdr);
7940              
7941             /* seperate these digits to leave a space for dot */
7942 1 50         num_sep_pos = no_pre_zero ? dot_ofs : 0;
7943 1           num_sep = num_hdr + num_sep_pos;
7944 1           byte_move_16(num_sep + no_pre_zero, num_sep);
7945 1           num_end += no_pre_zero;
7946              
7947             /* write the dot */
7948 1           dot_set_pos = yyjson_max(dot_ofs, 1);
7949 1           buf[dot_set_pos] = '.';
7950              
7951             /* return the ending */
7952 1           dot_end = buf + dot_ofs + 2;
7953 1           return yyjson_max(dot_end, num_end);
7954              
7955             } else {
7956             /* write with scientific notation, e.g. 1.234e56 */
7957 0           end = write_u64_len_16_to_17_trim(sig_dec, buf + 1);
7958 0           end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */
7959 0           exp_dec += sig_len - 1;
7960 0           buf[0] = buf[1];
7961 0           buf[1] = '.';
7962 0           return write_f64_exp(exp_dec, end);
7963             }
7964              
7965             } else {
7966             /* subnormal number */
7967 0           sig_bin = sig_raw;
7968 0           exp_bin = 1 - F64_EXP_BIAS - F64_SIG_BITS;
7969              
7970             /* binary to decimal */
7971             f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
7972              
7973             /* write significand part */
7974 0 0         end = write_u64_len_1_to_17(sig_dec, buf + 1);
7975 0           buf[0] = buf[1];
7976 0           buf[1] = '.';
7977 0           exp_dec += (i32)(end - buf) - 2;
7978              
7979             /* trim trailing zeros */
7980 0           end -= *(end - 1) == '0'; /* branchless for last zero */
7981 0           end -= *(end - 1) == '0'; /* branchless for second last zero */
7982 0 0         while (*(end - 1) == '0') end--; /* for unlikely more zeros */
7983 0           end -= *(end - 1) == '.'; /* remove dot, e.g. 2.e-321 -> 2e-321 */
7984              
7985             /* write exponent part */
7986 0           return write_f64_exp(exp_dec, end);
7987             }
7988             }
7989              
7990             /**
7991             Write a double number using fixed-point notation (requires 40 bytes buffer).
7992              
7993             We follow the ECMAScript specification for printing floating-point numbers,
7994             similar to `Number.prototype.toFixed(prec)`, but with the following changes:
7995             1. Keep the negative sign of `-0.0` to preserve input information.
7996             2. Keep decimal point to indicate the number is floating point.
7997             3. Remove positive sign in the exponent part.
7998             4. Remove trailing zeros and reduce unnecessary precision.
7999             */
8000 0           static_noinline u8 *write_f64_raw_fixed(u8 *buf, u64 raw, yyjson_write_flag flg,
8001             u32 prec) {
8002             u64 sig_bin, sig_dec, sig_raw;
8003             i32 exp_bin, exp_dec, sig_len, dot_ofs;
8004             u32 exp_raw;
8005             u8 *end;
8006             bool sign;
8007              
8008             /* decode raw bytes from IEEE-754 double format. */
8009 0           sign = (bool)(raw >> (F64_BITS - 1));
8010 0           sig_raw = raw & F64_SIG_MASK;
8011 0           exp_raw = (u32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
8012              
8013             /* return inf or nan */
8014 0 0         if (unlikely(exp_raw == ((u32)1 << F64_EXP_BITS) - 1)) {
8015 0           return write_inf_or_nan(buf, flg, sig_raw, sign);
8016             }
8017              
8018             /* add sign for all finite number */
8019 0           buf[0] = '-';
8020 0           buf += sign;
8021              
8022             /* return zero */
8023 0 0         if ((raw << 1) == 0) {
8024             byte_copy_4(buf, "0.0");
8025 0           return buf + 3;
8026             }
8027              
8028 0 0         if (likely(exp_raw != 0)) {
8029             /* normal number */
8030 0           sig_bin = sig_raw | ((u64)1 << F64_SIG_BITS);
8031 0           exp_bin = (i32)exp_raw - F64_EXP_BIAS - F64_SIG_BITS;
8032              
8033             /* fast path for small integer number without fraction */
8034 0 0         if ((-F64_SIG_BITS <= exp_bin && exp_bin <= 0) &&
    0          
8035 0 0         (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) {
8036 0           sig_dec = sig_bin >> -exp_bin; /* range: [1, 0x1FFFFFFFFFFFFF] */
8037 0 0         buf = write_u64_len_1_to_16(sig_dec, buf);
8038             byte_copy_2(buf, ".0");
8039 0           return buf + 2;
8040             }
8041              
8042             /* only `fabs(num) < 1e21` are processed here. */
8043 0 0         if ((raw << 1) < (U64(0x444B1AE4, 0xD6E2EF50) << 1)) {
8044             i32 num_sep_pos, dot_set_pos, pre_ofs;
8045             u8 *num_hdr, *num_end, *num_sep;
8046             bool round_up, no_pre_zero;
8047              
8048             /* binary to decimal */
8049             f64_bin_to_dec_fast(sig_raw, exp_raw, sig_bin, exp_bin,
8050             &sig_dec, &exp_dec, &round_up);
8051              
8052             /* the sig length is 16 or 17 */
8053 0 0         sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
8054              
8055             /* limit the length of digits after the decimal point */
8056 0 0         if (exp_dec < -1) {
8057 0           i32 sig_len_cut = -exp_dec - (i32)prec;
8058 0 0         if (sig_len_cut > sig_len) {
8059             byte_copy_4(buf, "0.0");
8060 0           return buf + 3;
8061             }
8062 0 0         if (sig_len_cut > 0) {
8063             u64 div, mod, p10;
8064              
8065             /* remove round up */
8066 0           sig_dec -= round_up;
8067 0 0         sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
8068              
8069             /* cut off some digits */
8070 0           div_pow10(sig_dec, (u32)sig_len_cut, &div, &mod, &p10);
8071              
8072             /* add round up */
8073 0           sig_dec = div + (mod >= p10 / 2);
8074              
8075             /* update exp and sig length */
8076 0           exp_dec += sig_len_cut;
8077 0           sig_len -= sig_len_cut;
8078 0 0         sig_len += (sig_len >= 0) &&
8079 0 0         (sig_dec >= div_pow10_table[sig_len].p10);
8080             }
8081 0 0         if (sig_len <= 0) {
8082             byte_copy_4(buf, "0.0");
8083 0           return buf + 3;
8084             }
8085             }
8086              
8087             /* fill zeros */
8088 0           memset(buf, '0', 32);
8089              
8090             /* the decimal point offset relative to the first digit */
8091 0           dot_ofs = sig_len + exp_dec;
8092              
8093             /* not prefixed with zero, e.g. 1.234, 1234.0 */
8094 0           no_pre_zero = (dot_ofs > 0);
8095              
8096             /* write the number as digits */
8097 0 0         pre_ofs = no_pre_zero ? 0 : (1 - dot_ofs);
8098 0           num_hdr = buf + pre_ofs;
8099 0 0         num_end = write_u64_len_1_to_17(sig_dec, num_hdr);
8100              
8101             /* seperate these digits to leave a space for dot */
8102 0 0         num_sep_pos = no_pre_zero ? dot_ofs : -dot_ofs;
8103 0           num_sep = buf + num_sep_pos;
8104 0           byte_move_16(num_sep + 1, num_sep);
8105 0           num_end += (exp_dec < 0);
8106              
8107             /* write the dot */
8108 0           dot_set_pos = yyjson_max(dot_ofs, 1);
8109 0           buf[dot_set_pos] = '.';
8110              
8111             /* remove trailing zeros */
8112 0           buf += dot_set_pos + 2;
8113 0           buf = yyjson_max(buf, num_end);
8114 0           buf -= *(buf - 1) == '0'; /* branchless for last zero */
8115 0           buf -= *(buf - 1) == '0'; /* branchless for second last zero */
8116 0 0         while (*(buf - 1) == '0') buf--; /* for unlikely more zeros */
8117 0           buf += *(buf - 1) == '.'; /* keep a zero after dot */
8118 0           return buf;
8119              
8120             } else {
8121             /* binary to decimal */
8122             f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin,
8123             &sig_dec, &exp_dec);
8124              
8125             /* the sig length is 16 or 17 */
8126 0 0         sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
8127              
8128             /* write with scientific notation, e.g. 1.234e56 */
8129 0           end = write_u64_len_16_to_17_trim(sig_dec, buf + 1);
8130 0           end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */
8131 0           exp_dec += sig_len - 1;
8132 0           buf[0] = buf[1];
8133 0           buf[1] = '.';
8134 0           return write_f64_exp(exp_dec, end);
8135             }
8136             } else {
8137             /* subnormal number */
8138             byte_copy_4(buf, "0.0");
8139 0           return buf + 3;
8140             }
8141             }
8142              
8143             #else /* FP_WRITER */
8144              
8145             #if YYJSON_MSC_VER >= 1400
8146             #define snprintf_num(buf, len, fmt, dig, val) \
8147             sprintf_s((char *)buf, len, fmt, dig, val)
8148             #elif defined(snprintf) || (YYJSON_STDC_VER >= 199901L)
8149             #define snprintf_num(buf, len, fmt, dig, val) \
8150             snprintf((char *)buf, len, fmt, dig, val)
8151             #else
8152             #define snprintf_num(buf, len, fmt, dig, val) \
8153             sprintf((char *)buf, fmt, dig, val)
8154             #endif
8155              
8156             static_noinline u8 *write_fp_reformat(u8 *buf, int len,
8157             yyjson_write_flag flg, bool fixed) {
8158             u8 *cur = buf;
8159             if (unlikely(len < 1)) return NULL;
8160             cur += (*cur == '-');
8161             if (unlikely(!char_is_digit(*cur))) {
8162             /* nan, inf, or bad output */
8163             if (has_flg(INF_AND_NAN_AS_NULL)) {
8164             byte_copy_4(buf, "null");
8165             return buf + 4;
8166             } else if (has_allow(INF_AND_NAN)) {
8167             if (*cur == 'i') {
8168             byte_copy_8(cur, "Infinity");
8169             return cur + 8;
8170             } else if (*cur == 'n') {
8171             byte_copy_4(buf, "NaN");
8172             return buf + 3;
8173             }
8174             }
8175             return NULL;
8176             } else {
8177             /* finite number */
8178             u8 *end = buf + len, *dot = NULL, *exp = NULL;
8179              
8180             /*
8181             The snprintf() function is locale-dependent. For currently known
8182             locales, (en, zh, ja, ko, am, he, hi) use '.' as the decimal point,
8183             while other locales use ',' as the decimal point. we need to replace
8184             ',' with '.' to avoid the locale setting.
8185             */
8186             for (; cur < end; cur++) {
8187             switch (*cur) {
8188             case ',': *cur = '.'; /* fallthrough */
8189             case '.': dot = cur; break;
8190             case 'e': exp = cur; break;
8191             default: break;
8192             }
8193             }
8194             if (fixed) {
8195             /* remove trailing zeros */
8196             while (*(end - 1) == '0') end--;
8197             end += *(end - 1) == '.';
8198             } else {
8199             if (!dot && !exp) {
8200             /* add decimal point, e.g. 123 -> 123.0 */
8201             byte_copy_2(end, ".0");
8202             end += 2;
8203             } else if (exp) {
8204             cur = exp + 1;
8205             /* remove positive sign in the exponent part */
8206             if (*cur == '+') {
8207             memmove(cur, cur + 1, (usize)(end - cur - 1));
8208             end--;
8209             }
8210             cur += (*cur == '-');
8211             /* remove leading zeros in the exponent part */
8212             if (*cur == '0') {
8213             u8 *hdr = cur++;
8214             while (*cur == '0') cur++;
8215             memmove(hdr, cur, (usize)(end - cur));
8216             end -= (usize)(cur - hdr);
8217             }
8218             }
8219             }
8220             return end;
8221             }
8222             }
8223              
8224             /** Write a double number (requires 40 bytes buffer). */
8225             static_noinline u8 *write_f64_raw(u8 *buf, u64 raw, yyjson_write_flag flg) {
8226             #if defined(DBL_DECIMAL_DIG) && DBL_DECIMAL_DIG < F64_DEC_DIG
8227             int dig = DBL_DECIMAL_DIG;
8228             #else
8229             int dig = F64_DEC_DIG;
8230             #endif
8231             f64 val = f64_from_bits(raw);
8232             int len = snprintf_num(buf, FP_BUF_LEN, "%.*g", dig, val);
8233             return write_fp_reformat(buf, len, flg, false);
8234             }
8235              
8236             /** Write a double number (requires 40 bytes buffer). */
8237             static_noinline u8 *write_f32_raw(u8 *buf, u64 raw, yyjson_write_flag flg) {
8238             #if defined(FLT_DECIMAL_DIG) && FLT_DECIMAL_DIG < F32_DEC_DIG
8239             int dig = FLT_DECIMAL_DIG;
8240             #else
8241             int dig = F32_DEC_DIG;
8242             #endif
8243             f64 val = (f64)f64_to_f32(f64_from_bits(raw));
8244             int len = snprintf_num(buf, FP_BUF_LEN, "%.*g", dig, val);
8245             return write_fp_reformat(buf, len, flg, false);
8246             }
8247              
8248             /** Write a double number (requires 40 bytes buffer). */
8249             static_noinline u8 *write_f64_raw_fixed(u8 *buf, u64 raw,
8250             yyjson_write_flag flg, u32 prec) {
8251             f64 val = (f64)f64_from_bits(raw);
8252             if (-1e21 < val && val < 1e21) {
8253             int len = snprintf_num(buf, FP_BUF_LEN, "%.*f", (int)prec, val);
8254             return write_fp_reformat(buf, len, flg, true);
8255             } else {
8256             return write_f64_raw(buf, raw, flg);
8257             }
8258             }
8259              
8260             #endif /* FP_WRITER */
8261              
8262             /** Write a JSON number (requires 40 bytes buffer). */
8263             static_inline u8 *write_num(u8 *cur, yyjson_val *val, yyjson_write_flag flg) {
8264 35040 50         if (!(val->tag & YYJSON_SUBTYPE_REAL)) {
    0          
8265 35053           u64 pos = val->uni.u64;
8266 35053           u64 neg = ~pos + 1;
8267 35053           usize sign = ((val->tag & YYJSON_SUBTYPE_SINT) > 0) & ((i64)pos < 0);
8268 35053           *cur = '-';
8269 70106 50         return write_u64(sign ? neg : pos, cur + sign);
    50          
    50          
    0          
    0          
    0          
8270             } else {
8271 1           u64 raw = val->uni.u64;
8272 1           u32 val_fmt = (u32)(val->tag >> 32);
8273 1           u32 all_fmt = flg;
8274 1           u32 fmt = val_fmt | all_fmt;
8275 1 50         if (likely(!(fmt >> (32 - YYJSON_WRITE_FP_FLAG_BITS)))) {
    0          
    0          
    0          
    0          
    0          
8276             /* double to shortest */
8277 1           return write_f64_raw(cur, raw, flg);
8278 0 0         } else if (fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS)) {
    0          
    0          
    0          
    0          
    0          
8279             /* double to fixed */
8280 0           u32 val_prec = val_fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS);
8281 0           u32 all_prec = all_fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS);
8282 0 0         u32 prec = val_prec ? val_prec : all_prec;
    0          
    0          
    0          
    0          
    0          
8283 0           return write_f64_raw_fixed(cur, raw, flg, prec);
8284             } else {
8285 0 0         if (fmt & YYJSON_WRITE_FP_TO_FLOAT) {
    0          
    0          
    0          
    0          
    0          
8286             /* float to shortest */
8287 0           return write_f32_raw(cur, raw, flg);
8288             } else {
8289             /* double to shortest */
8290 0           return write_f64_raw(cur, raw, flg);
8291             }
8292             }
8293             }
8294             }
8295              
8296 0           char *yyjson_write_number(const yyjson_val *val, char *buf) {
8297 0 0         if (unlikely(!val || !buf)) return NULL;
    0          
8298 0           switch (val->tag & YYJSON_TAG_MASK) {
8299 0           case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_UINT: {
8300 0 0         buf = (char *)write_u64(val->uni.u64, (u8 *)buf);
8301 0           *buf = '\0';
8302 0           return buf;
8303             }
8304 0           case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_SINT: {
8305 0           u64 pos = val->uni.u64;
8306 0           u64 neg = ~pos + 1;
8307 0           usize sign = ((i64)pos < 0);
8308 0           *buf = '-';
8309 0 0         buf = (char *)write_u64(sign ? neg : pos, (u8 *)buf + sign);
8310 0           *buf = '\0';
8311 0           return buf;
8312             }
8313 0           case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL: {
8314 0           u64 raw = val->uni.u64;
8315 0           u32 fmt = (u32)(val->tag >> 32);
8316 0           u32 flg = YYJSON_WRITE_ALLOW_INF_AND_NAN;
8317 0 0         if (likely(!(fmt >> (32 - YYJSON_WRITE_FP_FLAG_BITS)))) {
8318 0           buf = (char *)write_f64_raw((u8 *)buf, raw, flg);
8319 0 0         } else if (fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS)) {
8320 0           u32 prec = fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS);
8321 0           buf = (char *)write_f64_raw_fixed((u8 *)buf, raw, flg, prec);
8322             } else {
8323 0 0         if (fmt & YYJSON_WRITE_FP_TO_FLOAT) {
8324 0           buf = (char *)write_f32_raw((u8 *)buf, raw, flg);
8325             } else {
8326 0           buf = (char *)write_f64_raw((u8 *)buf, raw, flg);
8327             }
8328             }
8329 0 0         if (buf) *buf = '\0';
8330 0           return buf;
8331             }
8332 0           default: return NULL;
8333             }
8334             }
8335              
8336              
8337              
8338             /*==============================================================================
8339             * MARK: - String Writer (Private)
8340             *============================================================================*/
8341              
8342             /** Character encode type, if (type > CHAR_ENC_ERR_1) bytes = type / 2; */
8343             typedef u8 char_enc_type;
8344             #define CHAR_ENC_CPY_1 0 /* 1-byte UTF-8, copy. */
8345             #define CHAR_ENC_ERR_1 1 /* 1-byte UTF-8, error. */
8346             #define CHAR_ENC_ESC_A 2 /* 1-byte ASCII, escaped as '\x'. */
8347             #define CHAR_ENC_ESC_1 3 /* 1-byte UTF-8, escaped as '\uXXXX'. */
8348             #define CHAR_ENC_CPY_2 4 /* 2-byte UTF-8, copy. */
8349             #define CHAR_ENC_ESC_2 5 /* 2-byte UTF-8, escaped as '\uXXXX'. */
8350             #define CHAR_ENC_CPY_3 6 /* 3-byte UTF-8, copy. */
8351             #define CHAR_ENC_ESC_3 7 /* 3-byte UTF-8, escaped as '\uXXXX'. */
8352             #define CHAR_ENC_CPY_4 8 /* 4-byte UTF-8, copy. */
8353             #define CHAR_ENC_ESC_4 9 /* 4-byte UTF-8, escaped as '\uXXXX\uXXXX'. */
8354              
8355             /** Character encode type table: don't escape unicode, don't escape '/'.
8356             (generate with misc/make_tables.c) */
8357             static const char_enc_type enc_table_cpy[256] = {
8358             3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
8359             3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
8360             0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8361             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8362             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8363             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
8364             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8365             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8366             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8367             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8368             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8369             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8370             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
8371             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
8372             6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
8373             8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1
8374             };
8375              
8376             /** Character encode type table: don't escape unicode, escape '/'.
8377             (generate with misc/make_tables.c) */
8378             static const char_enc_type enc_table_cpy_slash[256] = {
8379             3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
8380             3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
8381             0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
8382             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8383             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8384             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
8385             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8386             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8387             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8388             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8389             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8390             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8391             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
8392             4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
8393             6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
8394             8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1
8395             };
8396              
8397             /** Character encode type table: escape unicode, don't escape '/'.
8398             (generate with misc/make_tables.c) */
8399             static const char_enc_type enc_table_esc[256] = {
8400             3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
8401             3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
8402             0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8403             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8404             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8405             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
8406             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8407             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8408             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8409             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8410             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8411             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8412             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
8413             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
8414             7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
8415             9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1
8416             };
8417              
8418             /** Character encode type table: escape unicode, escape '/'.
8419             (generate with misc/make_tables.c) */
8420             static const char_enc_type enc_table_esc_slash[256] = {
8421             3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
8422             3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
8423             0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
8424             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8425             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8426             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
8427             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8428             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8429             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8430             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8431             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8432             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8433             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
8434             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
8435             7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
8436             9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1
8437             };
8438              
8439             /** Escaped hex character table: ["00" "01" "02" ... "FD" "FE" "FF"].
8440             (generate with misc/make_tables.c) */
8441             yyjson_align(2)
8442             static const u8 esc_hex_char_table[512] = {
8443             '0', '0', '0', '1', '0', '2', '0', '3',
8444             '0', '4', '0', '5', '0', '6', '0', '7',
8445             '0', '8', '0', '9', '0', 'A', '0', 'B',
8446             '0', 'C', '0', 'D', '0', 'E', '0', 'F',
8447             '1', '0', '1', '1', '1', '2', '1', '3',
8448             '1', '4', '1', '5', '1', '6', '1', '7',
8449             '1', '8', '1', '9', '1', 'A', '1', 'B',
8450             '1', 'C', '1', 'D', '1', 'E', '1', 'F',
8451             '2', '0', '2', '1', '2', '2', '2', '3',
8452             '2', '4', '2', '5', '2', '6', '2', '7',
8453             '2', '8', '2', '9', '2', 'A', '2', 'B',
8454             '2', 'C', '2', 'D', '2', 'E', '2', 'F',
8455             '3', '0', '3', '1', '3', '2', '3', '3',
8456             '3', '4', '3', '5', '3', '6', '3', '7',
8457             '3', '8', '3', '9', '3', 'A', '3', 'B',
8458             '3', 'C', '3', 'D', '3', 'E', '3', 'F',
8459             '4', '0', '4', '1', '4', '2', '4', '3',
8460             '4', '4', '4', '5', '4', '6', '4', '7',
8461             '4', '8', '4', '9', '4', 'A', '4', 'B',
8462             '4', 'C', '4', 'D', '4', 'E', '4', 'F',
8463             '5', '0', '5', '1', '5', '2', '5', '3',
8464             '5', '4', '5', '5', '5', '6', '5', '7',
8465             '5', '8', '5', '9', '5', 'A', '5', 'B',
8466             '5', 'C', '5', 'D', '5', 'E', '5', 'F',
8467             '6', '0', '6', '1', '6', '2', '6', '3',
8468             '6', '4', '6', '5', '6', '6', '6', '7',
8469             '6', '8', '6', '9', '6', 'A', '6', 'B',
8470             '6', 'C', '6', 'D', '6', 'E', '6', 'F',
8471             '7', '0', '7', '1', '7', '2', '7', '3',
8472             '7', '4', '7', '5', '7', '6', '7', '7',
8473             '7', '8', '7', '9', '7', 'A', '7', 'B',
8474             '7', 'C', '7', 'D', '7', 'E', '7', 'F',
8475             '8', '0', '8', '1', '8', '2', '8', '3',
8476             '8', '4', '8', '5', '8', '6', '8', '7',
8477             '8', '8', '8', '9', '8', 'A', '8', 'B',
8478             '8', 'C', '8', 'D', '8', 'E', '8', 'F',
8479             '9', '0', '9', '1', '9', '2', '9', '3',
8480             '9', '4', '9', '5', '9', '6', '9', '7',
8481             '9', '8', '9', '9', '9', 'A', '9', 'B',
8482             '9', 'C', '9', 'D', '9', 'E', '9', 'F',
8483             'A', '0', 'A', '1', 'A', '2', 'A', '3',
8484             'A', '4', 'A', '5', 'A', '6', 'A', '7',
8485             'A', '8', 'A', '9', 'A', 'A', 'A', 'B',
8486             'A', 'C', 'A', 'D', 'A', 'E', 'A', 'F',
8487             'B', '0', 'B', '1', 'B', '2', 'B', '3',
8488             'B', '4', 'B', '5', 'B', '6', 'B', '7',
8489             'B', '8', 'B', '9', 'B', 'A', 'B', 'B',
8490             'B', 'C', 'B', 'D', 'B', 'E', 'B', 'F',
8491             'C', '0', 'C', '1', 'C', '2', 'C', '3',
8492             'C', '4', 'C', '5', 'C', '6', 'C', '7',
8493             'C', '8', 'C', '9', 'C', 'A', 'C', 'B',
8494             'C', 'C', 'C', 'D', 'C', 'E', 'C', 'F',
8495             'D', '0', 'D', '1', 'D', '2', 'D', '3',
8496             'D', '4', 'D', '5', 'D', '6', 'D', '7',
8497             'D', '8', 'D', '9', 'D', 'A', 'D', 'B',
8498             'D', 'C', 'D', 'D', 'D', 'E', 'D', 'F',
8499             'E', '0', 'E', '1', 'E', '2', 'E', '3',
8500             'E', '4', 'E', '5', 'E', '6', 'E', '7',
8501             'E', '8', 'E', '9', 'E', 'A', 'E', 'B',
8502             'E', 'C', 'E', 'D', 'E', 'E', 'E', 'F',
8503             'F', '0', 'F', '1', 'F', '2', 'F', '3',
8504             'F', '4', 'F', '5', 'F', '6', 'F', '7',
8505             'F', '8', 'F', '9', 'F', 'A', 'F', 'B',
8506             'F', 'C', 'F', 'D', 'F', 'E', 'F', 'F'
8507             };
8508              
8509             /** Escaped single character table. (generate with misc/make_tables.c) */
8510             yyjson_align(2)
8511             static const u8 esc_single_char_table[512] = {
8512             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8513             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8514             '\\', 'b', '\\', 't', '\\', 'n', ' ', ' ',
8515             '\\', 'f', '\\', 'r', ' ', ' ', ' ', ' ',
8516             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8517             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8518             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8519             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8520             ' ', ' ', ' ', ' ', '\\', '"', ' ', ' ',
8521             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8522             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8523             ' ', ' ', ' ', ' ', ' ', ' ', '\\', '/',
8524             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8525             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8526             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8527             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8528             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8529             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8530             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8531             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8532             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8533             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8534             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8535             '\\', '\\', ' ', ' ', ' ', ' ', ' ', ' ',
8536             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8537             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8538             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8539             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8540             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8541             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8542             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8543             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8544             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8545             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8546             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8547             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8548             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8549             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8550             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8551             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8552             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8553             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8554             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8555             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8556             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8557             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8558             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8559             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8560             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8561             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8562             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8563             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8564             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8565             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8566             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8567             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8568             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8569             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8570             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8571             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8572             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8573             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8574             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8575             ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
8576             };
8577              
8578             /** Returns the encode table with options. */
8579             static_inline const char_enc_type *get_enc_table_with_flag(
8580             yyjson_write_flag flg) {
8581 30076 50         if (has_flg(ESCAPE_UNICODE)) {
    50          
    50          
    0          
    0          
    0          
8582 0 0         if (has_flg(ESCAPE_SLASHES)) {
    0          
    0          
    0          
    0          
    0          
8583 0           return enc_table_esc_slash;
8584             } else {
8585 0           return enc_table_esc;
8586             }
8587             } else {
8588 30092 50         if (has_flg(ESCAPE_SLASHES)) {
    50          
    50          
    0          
    0          
    0          
8589 0           return enc_table_cpy_slash;
8590             } else {
8591 15046           return enc_table_cpy;
8592             }
8593             }
8594             }
8595              
8596             /** Write raw string. */
8597             static_inline u8 *write_raw(u8 *cur, const u8 *raw, usize raw_len) {
8598 0           memcpy(cur, raw, raw_len);
8599 0           return cur + raw_len;
8600             }
8601              
8602             /**
8603             Write string no-escape.
8604             @param cur Buffer cursor.
8605             @param str A UTF-8 string, null-terminator is not required.
8606             @param str_len Length of string in bytes.
8607             @return The buffer cursor after string.
8608             */
8609             static_inline u8 *write_str_noesc(u8 *cur, const u8 *str, usize str_len) {
8610 10032           *cur++ = '"';
8611 10032 50         while (str_len >= 16) {
    50          
    50          
    0          
    0          
    0          
8612             byte_copy_16(cur, str);
8613 0           cur += 16;
8614 0           str += 16;
8615 0           str_len -= 16;
8616             }
8617 10037 50         while (str_len >= 4) {
    50          
    100          
    0          
    0          
    0          
8618             byte_copy_4(cur, str);
8619 5           cur += 4;
8620 5           str += 4;
8621 5           str_len -= 4;
8622             }
8623 20066 100         while (str_len) {
    100          
    100          
    0          
    0          
    0          
8624 10034           *cur++ = *str++;
8625 10034           str_len -= 1;
8626             }
8627 10032           *cur++ = '"';
8628 10032           return cur;
8629             }
8630              
8631             /**
8632             Write UTF-8 string (requires len * 6 + 2 bytes buffer).
8633             @param cur Buffer cursor.
8634             @param esc Escape unicode.
8635             @param inv Allow invalid unicode.
8636             @param str A UTF-8 string, null-terminator is not required.
8637             @param str_len Length of string in bytes.
8638             @param enc_table Encode type table for character.
8639             @return The buffer cursor after string, or NULL on invalid unicode.
8640             */
8641             static_inline u8 *write_str(u8 *cur, bool esc, bool inv,
8642             const u8 *str, usize str_len,
8643             const char_enc_type *enc_table) {
8644             /* The replacement character U+FFFD, used to indicate invalid character. */
8645 10018           const v32 rep = {{ 'F', 'F', 'F', 'D' }};
8646 10018           const v32 pre = {{ '\\', 'u', '0', '0' }};
8647              
8648 10018           const u8 *src = str;
8649 10018           const u8 *end = str + str_len;
8650 10018           *cur++ = '"';
8651              
8652 10018           copy_ascii:
8653             /*
8654             Copy continuous ASCII, loop unrolling, same as the following code:
8655              
8656             while (end > src) (
8657             if (unlikely(enc_table[*src])) break;
8658             *cur++ = *src++;
8659             );
8660             */
8661             #define expr_jump(i) \
8662             if (unlikely(enc_table[src[i]])) goto stop_char_##i;
8663              
8664             #define expr_stop(i) \
8665             stop_char_##i: \
8666             memcpy(cur, src, i); \
8667             cur += i; src += i; goto copy_utf8;
8668              
8669 10018 50         while (end - src >= 16) {
    50          
    50          
    0          
    0          
    0          
8670 0 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          
    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          
8671             byte_copy_16(cur, src);
8672 0           cur += 16; src += 16;
8673             }
8674              
8675 10022 100         while (end - src >= 4) {
    50          
    100          
    0          
    0          
    0          
8676 4 50         repeat4_incr(expr_jump)
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
8677             byte_copy_4(cur, src);
8678 4           cur += 4; src += 4;
8679             }
8680              
8681 20040 100         while (end > src) {
    100          
    100          
    0          
    0          
    0          
8682 10022 50         expr_jump(0)
    50          
    50          
    0          
    0          
    0          
8683 10022           *cur++ = *src++;
8684             }
8685              
8686 10018           *cur++ = '"';
8687 10018           return cur;
8688              
8689 0           repeat16_incr(expr_stop)
8690              
8691             #undef expr_jump
8692             #undef expr_stop
8693              
8694 0           copy_utf8:
8695 0 0         if (unlikely(src + 4 > end)) {
    0          
    0          
    0          
    0          
    0          
8696 0 0         if (end == src) goto copy_end;
    0          
    0          
    0          
    0          
    0          
8697 0 0         if (end - src < enc_table[*src] / 2) goto err_one;
    0          
    0          
    0          
    0          
    0          
8698             }
8699 0           switch (enc_table[*src]) {
8700 0           case CHAR_ENC_CPY_1: {
8701 0           *cur++ = *src++;
8702 0           goto copy_ascii;
8703             }
8704 0           case CHAR_ENC_CPY_2: {
8705             #if YYJSON_DISABLE_UTF8_VALIDATION
8706             byte_copy_2(cur, src);
8707             #else
8708 0           u32 uni = 0;
8709             byte_copy_2(&uni, src);
8710 0 0         if (unlikely(!is_utf8_seq2(uni))) goto err_cpy;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
8711             byte_copy_2(cur, &uni);
8712             #endif
8713 0           cur += 2;
8714 0           src += 2;
8715 0           goto copy_utf8;
8716             }
8717 0           case CHAR_ENC_CPY_3: {
8718             #if YYJSON_DISABLE_UTF8_VALIDATION
8719             if (likely(src + 4 <= end)) {
8720             byte_copy_4(cur, src);
8721             } else {
8722             byte_copy_2(cur, src);
8723             cur[2] = src[2];
8724             }
8725             #else
8726             u32 uni, tmp;
8727 0 0         if (likely(src + 4 <= end)) {
    0          
    0          
    0          
    0          
    0          
8728 0           uni = byte_load_4(src);
8729 0 0         if (unlikely(!is_utf8_seq3(uni))) goto err_cpy;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
8730             byte_copy_4(cur, src);
8731             } else {
8732 0           uni = byte_load_3(src);
8733 0 0         if (unlikely(!is_utf8_seq3(uni))) goto err_cpy;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
8734             byte_copy_4(cur, &uni);
8735             }
8736             #endif
8737 0           cur += 3;
8738 0           src += 3;
8739 0           goto copy_utf8;
8740             }
8741 0           case CHAR_ENC_CPY_4: {
8742             #if YYJSON_DISABLE_UTF8_VALIDATION
8743             byte_copy_4(cur, src);
8744             #else
8745             u32 uni, tmp;
8746 0           uni = byte_load_4(src);
8747 0 0         if (unlikely(!is_utf8_seq4(uni))) goto err_cpy;
    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          
8748             byte_copy_4(cur, src);
8749             #endif
8750 0           cur += 4;
8751 0           src += 4;
8752 0           goto copy_utf8;
8753             }
8754 0           case CHAR_ENC_ESC_A: {
8755 0           byte_copy_2(cur, &esc_single_char_table[*src * 2]);
8756 0           cur += 2;
8757 0           src += 1;
8758 0           goto copy_utf8;
8759             }
8760 0           case CHAR_ENC_ESC_1: {
8761             byte_copy_4(cur + 0, &pre);
8762 0           byte_copy_2(cur + 4, &esc_hex_char_table[*src * 2]);
8763 0           cur += 6;
8764 0           src += 1;
8765 0           goto copy_utf8;
8766             }
8767 0           case CHAR_ENC_ESC_2: {
8768             u16 u;
8769             #if !YYJSON_DISABLE_UTF8_VALIDATION
8770 0           u32 v4 = 0;
8771 0           u16 v2 = byte_load_2(src);
8772             byte_copy_2(&v4, &v2);
8773 0 0         if (unlikely(!is_utf8_seq2(v4))) goto err_esc;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
8774             #endif
8775 0           u = (u16)(((u16)(src[0] & 0x1F) << 6) |
8776 0           ((u16)(src[1] & 0x3F) << 0));
8777             byte_copy_2(cur + 0, &pre);
8778 0           byte_copy_2(cur + 2, &esc_hex_char_table[(u >> 8) * 2]);
8779 0           byte_copy_2(cur + 4, &esc_hex_char_table[(u & 0xFF) * 2]);
8780 0           cur += 6;
8781 0           src += 2;
8782 0           goto copy_utf8;
8783             }
8784 0           case CHAR_ENC_ESC_3: {
8785             u16 u;
8786             u32 v, tmp;
8787             #if !YYJSON_DISABLE_UTF8_VALIDATION
8788 0           v = byte_load_3(src);
8789 0 0         if (unlikely(!is_utf8_seq3(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          
8790             #endif
8791 0           u = (u16)(((u16)(src[0] & 0x0F) << 12) |
8792 0           ((u16)(src[1] & 0x3F) << 6) |
8793 0           ((u16)(src[2] & 0x3F) << 0));
8794             byte_copy_2(cur + 0, &pre);
8795 0           byte_copy_2(cur + 2, &esc_hex_char_table[(u >> 8) * 2]);
8796 0           byte_copy_2(cur + 4, &esc_hex_char_table[(u & 0xFF) * 2]);
8797 0           cur += 6;
8798 0           src += 3;
8799 0           goto copy_utf8;
8800             }
8801 0           case CHAR_ENC_ESC_4: {
8802             u32 hi, lo, u, v, tmp;
8803             #if !YYJSON_DISABLE_UTF8_VALIDATION
8804 0           v = byte_load_4(src);
8805 0 0         if (unlikely(!is_utf8_seq4(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          
8806             #endif
8807 0           u = ((u32)(src[0] & 0x07) << 18) |
8808 0           ((u32)(src[1] & 0x3F) << 12) |
8809 0           ((u32)(src[2] & 0x3F) << 6) |
8810 0           ((u32)(src[3] & 0x3F) << 0);
8811 0           u -= 0x10000;
8812 0           hi = (u >> 10) + 0xD800;
8813 0           lo = (u & 0x3FF) + 0xDC00;
8814             byte_copy_2(cur + 0, &pre);
8815 0           byte_copy_2(cur + 2, &esc_hex_char_table[(hi >> 8) * 2]);
8816 0           byte_copy_2(cur + 4, &esc_hex_char_table[(hi & 0xFF) * 2]);
8817 0           byte_copy_2(cur + 6, &pre);
8818 0           byte_copy_2(cur + 8, &esc_hex_char_table[(lo >> 8) * 2]);
8819 0           byte_copy_2(cur + 10, &esc_hex_char_table[(lo & 0xFF) * 2]);
8820 0           cur += 12;
8821 0           src += 4;
8822 0           goto copy_utf8;
8823             }
8824 0           case CHAR_ENC_ERR_1: {
8825 0           goto err_one;
8826             }
8827 0           default: break; /* unreachable */
8828             }
8829              
8830 0           copy_end:
8831 0           *cur++ = '"';
8832 0           return cur;
8833              
8834 0           err_one:
8835 0 0         if (esc) goto err_esc;
    0          
    0          
    0          
    0          
    0          
8836 0           else goto err_cpy;
8837              
8838 0           err_cpy:
8839 0 0         if (!inv) return NULL;
    0          
    0          
    0          
    0          
    0          
8840 0           *cur++ = *src++;
8841 0           goto copy_utf8;
8842              
8843 0           err_esc:
8844 0 0         if (!inv) return NULL;
    0          
    0          
    0          
    0          
    0          
8845             byte_copy_2(cur + 0, &pre);
8846 0           byte_copy_4(cur + 2, &rep);
8847 0           cur += 6;
8848 0           src += 1;
8849 0           goto copy_utf8;
8850             }
8851              
8852              
8853              
8854             /*==============================================================================
8855             * MARK: - JSON Writer Utilities (Private)
8856             *============================================================================*/
8857              
8858             /** Write null (requires 8 bytes buffer). */
8859             static_inline u8 *write_null(u8 *cur) {
8860 1           v64 v = {{ 'n', 'u', 'l', 'l', ',', '\n', 0, 0 }};
8861             byte_copy_8(cur, &v);
8862 3           return cur + 4;
8863             }
8864              
8865             /** Write bool (requires 8 bytes buffer). */
8866             static_inline u8 *write_bool(u8 *cur, bool val) {
8867 6           v64 v0 = {{ 'f', 'a', 'l', 's', 'e', ',', '\n', 0 }};
8868 6           v64 v1 = {{ 't', 'r', 'u', 'e', ',', '\n', 0, 0 }};
8869 6           if (val) {
8870             byte_copy_8(cur, &v1);
8871             } else {
8872             byte_copy_8(cur, &v0);
8873             }
8874 6           return cur + 5 - val;
8875             }
8876              
8877             /** Write indent (requires level x 4 bytes buffer).
8878             Param spaces should not larger than 4. */
8879             static_inline u8 *write_indent(u8 *cur, usize level, usize spaces) {
8880 47 100         while (level-- > 0) {
    50          
    0          
    50          
    100          
    100          
    0          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
8881             byte_copy_4(cur, " ");
8882 15           cur += spaces;
8883             }
8884 32           return cur;
8885             }
8886              
8887             /** Write data to file pointer. */
8888 0           static bool write_dat_to_fp(FILE *fp, u8 *dat, usize len,
8889             yyjson_write_err *err) {
8890 0 0         if (fwrite(dat, len, 1, fp) != 1) {
8891 0           err->msg = "file writing failed";
8892 0           err->code = YYJSON_WRITE_ERROR_FILE_WRITE;
8893 0           return false;
8894             }
8895 0           return true;
8896             }
8897              
8898             /** Write data to file. */
8899 3           static bool write_dat_to_file(const char *path, u8 *dat, usize len,
8900             yyjson_write_err *err) {
8901             #define return_err(_code, _msg) do { \
8902             err->msg = _msg; \
8903             err->code = YYJSON_WRITE_ERROR_##_code; \
8904             if (file) fclose(file); \
8905             return false; \
8906             } while (false)
8907              
8908 3           FILE *file = fopen_writeonly(path);
8909 3 50         if (file == NULL) {
8910 0 0         return_err(FILE_OPEN, MSG_FOPEN);
8911             }
8912 3 50         if (fwrite(dat, len, 1, file) != 1) {
8913 0 0         return_err(FILE_WRITE, MSG_FWRITE);
8914             }
8915 3 50         if (fclose(file) != 0) {
8916 0           file = NULL;
8917 0 0         return_err(FILE_WRITE, MSG_FCLOSE);
8918             }
8919 3           return true;
8920              
8921             #undef return_err
8922             }
8923              
8924              
8925              
8926             /*==============================================================================
8927             * MARK: - JSON Writer Implementation (Private)
8928             *============================================================================*/
8929              
8930             typedef struct yyjson_write_ctx {
8931             usize tag;
8932             } yyjson_write_ctx;
8933              
8934             static_inline void yyjson_write_ctx_set(yyjson_write_ctx *ctx,
8935             usize size, bool is_obj) {
8936 0           ctx->tag = (size << 1) | (usize)is_obj;
8937 0           }
8938              
8939             static_inline void yyjson_write_ctx_get(yyjson_write_ctx *ctx,
8940             usize *size, bool *is_obj) {
8941 0           usize tag = ctx->tag;
8942 0           *size = tag >> 1;
8943 0           *is_obj = (bool)(tag & 1);
8944 0           }
8945              
8946             /** Write single JSON value. */
8947             static_inline u8 *yyjson_write_single(yyjson_val *val,
8948             yyjson_write_flag flg,
8949             yyjson_alc alc,
8950             usize *dat_len,
8951             yyjson_write_err *err) {
8952             #define return_err(_code, _msg) do { \
8953             if (hdr) alc.free(alc.ctx, (void *)hdr); \
8954             *dat_len = 0; \
8955             err->code = YYJSON_WRITE_ERROR_##_code; \
8956             err->msg = _msg; \
8957             return NULL; \
8958             } while (false)
8959              
8960             #define incr_len(_len) do { \
8961             hdr = (u8 *)alc.malloc(alc.ctx, _len); \
8962             if (!hdr) goto fail_alloc; \
8963             cur = hdr; \
8964             } while (false)
8965              
8966             #define check_str_len(_len) do { \
8967             if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
8968             goto fail_alloc; \
8969             } while (false)
8970              
8971 16           u8 *hdr = NULL, *cur;
8972             usize str_len;
8973             const u8 *str_ptr;
8974 16           const char_enc_type *enc_table = get_enc_table_with_flag(flg);
8975 16           bool cpy = (enc_table == enc_table_cpy);
8976 16           bool esc = has_flg(ESCAPE_UNICODE) != 0;
8977 16           bool inv = has_allow(INVALID_UNICODE) != 0;
8978 16           bool newline = has_flg(NEWLINE_AT_END) != 0;
8979 16           const usize end_len = 2; /* '\n' and '\0' */
8980              
8981 16           switch (unsafe_yyjson_get_type(val)) {
8982 0           case YYJSON_TYPE_RAW:
8983 0           str_len = unsafe_yyjson_get_len(val);
8984 0           str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
8985             check_str_len(str_len);
8986 0 0         incr_len(str_len + end_len);
    0          
8987 0           cur = write_raw(cur, str_ptr, str_len);
8988 0           break;
8989              
8990 4           case YYJSON_TYPE_STR:
8991 4           str_len = unsafe_yyjson_get_len(val);
8992 4           str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
8993             check_str_len(str_len);
8994 4 50         incr_len(str_len * 6 + 2 + end_len);
    0          
8995 8 50         if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
    100          
    0          
    0          
8996 2           cur = write_str_noesc(cur, str_ptr, str_len);
8997             } else {
8998 2           cur = write_str(cur, esc, inv, str_ptr, str_len, enc_table);
8999 2 50         if (unlikely(!cur)) goto fail_str;
    0          
9000             }
9001 4           break;
9002              
9003 6           case YYJSON_TYPE_NUM:
9004 6 50         incr_len(FP_BUF_LEN + end_len);
    100          
    0          
    0          
9005 6           cur = write_num(cur, val, flg);
9006 6 50         if (unlikely(!cur)) goto fail_num;
    0          
9007 6           break;
9008              
9009 3           case YYJSON_TYPE_BOOL:
9010 3 50         incr_len(8);
    0          
9011 3 100         cur = write_bool(cur, unsafe_yyjson_get_bool(val));
    0          
9012 3           break;
9013              
9014 1           case YYJSON_TYPE_NULL:
9015 1 50         incr_len(8);
    0          
9016 1           cur = write_null(cur);
9017 1           break;
9018              
9019 1           case YYJSON_TYPE_ARR:
9020 1 50         incr_len(2 + end_len);
    0          
9021             byte_copy_2(cur, "[]");
9022 1           cur += 2;
9023 1           break;
9024              
9025 1           case YYJSON_TYPE_OBJ:
9026 1 50         incr_len(2 + end_len);
    0          
9027             byte_copy_2(cur, "{}");
9028 1           cur += 2;
9029 1           break;
9030              
9031 0           default:
9032 0           goto fail_type;
9033             }
9034              
9035 16 50         if (newline) *cur++ = '\n';
    0          
9036 16           *cur = '\0';
9037 16           *dat_len = (usize)(cur - hdr);
9038 16           memset(err, 0, sizeof(yyjson_write_err));
9039 16           return hdr;
9040              
9041 0 0         fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
    0          
9042 0 0         fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
    0          
9043 0 0         fail_num: return_err(NAN_OR_INF, MSG_NAN_INF);
    0          
9044 0 0         fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8);
    0          
9045              
9046             #undef return_err
9047             #undef check_str_len
9048             #undef incr_len
9049             }
9050              
9051             /** Write JSON document minify.
9052             The root of this document should be a non-empty container. */
9053             static_inline u8 *yyjson_write_minify(const yyjson_val *root,
9054             const yyjson_write_flag flg,
9055             const yyjson_alc alc,
9056             usize *dat_len,
9057             yyjson_write_err *err) {
9058             #define return_err(_code, _msg) do { \
9059             *dat_len = 0; \
9060             err->code = YYJSON_WRITE_ERROR_##_code; \
9061             err->msg = _msg; \
9062             if (hdr) alc.free(alc.ctx, hdr); \
9063             return NULL; \
9064             } while (false)
9065              
9066             #define incr_len(_len) do { \
9067             ext_len = (usize)(_len); \
9068             if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
9069             usize ctx_pos = (usize)((u8 *)ctx - hdr); \
9070             usize cur_pos = (usize)(cur - hdr); \
9071             ctx_len = (usize)(end - (u8 *)ctx); \
9072             alc_inc = yyjson_max(alc_len / 2, ext_len); \
9073             alc_inc = size_align_up(alc_inc, sizeof(yyjson_write_ctx)); \
9074             if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
9075             goto fail_alloc; \
9076             alc_len += alc_inc; \
9077             tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
9078             if (unlikely(!tmp)) goto fail_alloc; \
9079             ctx_tmp = (yyjson_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
9080             memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
9081             ctx = ctx_tmp; \
9082             cur = tmp + cur_pos; \
9083             end = tmp + alc_len; \
9084             hdr = tmp; \
9085             } \
9086             } while (false)
9087              
9088             #define check_str_len(_len) do { \
9089             if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
9090             goto fail_alloc; \
9091             } while (false)
9092              
9093             yyjson_val *val;
9094             yyjson_type val_type;
9095             usize ctn_len, ctn_len_tmp;
9096             bool ctn_obj, ctn_obj_tmp, is_key;
9097             u8 *hdr, *cur, *end, *tmp;
9098             yyjson_write_ctx *ctx, *ctx_tmp;
9099             usize alc_len, alc_inc, ctx_len, ext_len, str_len;
9100             const u8 *str_ptr;
9101 0           const char_enc_type *enc_table = get_enc_table_with_flag(flg);
9102 0           bool cpy = (enc_table == enc_table_cpy);
9103 0           bool esc = has_flg(ESCAPE_UNICODE) != 0;
9104 0           bool inv = has_allow(INVALID_UNICODE) != 0;
9105 0           bool newline = has_flg(NEWLINE_AT_END) != 0;
9106              
9107 0           alc_len = root->uni.ofs / sizeof(yyjson_val);
9108 0           alc_len = alc_len * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64;
9109 0           alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx));
9110 0           hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
9111 0 0         if (!hdr) goto fail_alloc;
9112 0           cur = hdr;
9113 0           end = hdr + alc_len;
9114 0           ctx = (yyjson_write_ctx *)(void *)end;
9115              
9116 0           doc_begin:
9117 0           val = constcast(yyjson_val *)root;
9118 0           val_type = unsafe_yyjson_get_type(val);
9119 0           ctn_obj = (val_type == YYJSON_TYPE_OBJ);
9120 0           ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
9121 0           *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9122 0           val++;
9123              
9124 0           val_begin:
9125 0           val_type = unsafe_yyjson_get_type(val);
9126 0 0         if (val_type == YYJSON_TYPE_STR) {
9127 0           is_key = ((u8)ctn_obj & (u8)~ctn_len);
9128 0           str_len = unsafe_yyjson_get_len(val);
9129 0           str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9130             check_str_len(str_len);
9131 0 0         incr_len(str_len * 6 + 16);
    0          
9132 0 0         if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
    0          
9133 0           cur = write_str_noesc(cur, str_ptr, str_len);
9134             } else {
9135 0           cur = write_str(cur, esc, inv, str_ptr, str_len, enc_table);
9136 0 0         if (unlikely(!cur)) goto fail_str;
9137             }
9138 0 0         *cur++ = is_key ? ':' : ',';
9139 0           goto val_end;
9140             }
9141 0 0         if (val_type == YYJSON_TYPE_NUM) {
9142 0 0         incr_len(FP_BUF_LEN);
    0          
9143 0           cur = write_num(cur, val, flg);
9144 0 0         if (unlikely(!cur)) goto fail_num;
9145 0           *cur++ = ',';
9146 0           goto val_end;
9147             }
9148 0 0         if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
9149             (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
9150 0           ctn_len_tmp = unsafe_yyjson_get_len(val);
9151 0           ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
9152 0 0         incr_len(16);
    0          
9153 0 0         if (unlikely(ctn_len_tmp == 0)) {
9154             /* write empty container */
9155 0           *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
9156 0           *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
9157 0           *cur++ = ',';
9158 0           goto val_end;
9159             } else {
9160             /* push context, setup new container */
9161 0           yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj);
9162 0           ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
9163 0           ctn_obj = ctn_obj_tmp;
9164 0           *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9165 0           val++;
9166 0           goto val_begin;
9167             }
9168             }
9169 0 0         if (val_type == YYJSON_TYPE_BOOL) {
9170 0 0         incr_len(16);
    0          
9171 0 0         cur = write_bool(cur, unsafe_yyjson_get_bool(val));
9172 0           cur++;
9173 0           goto val_end;
9174             }
9175 0 0         if (val_type == YYJSON_TYPE_NULL) {
9176 0 0         incr_len(16);
    0          
9177 0           cur = write_null(cur);
9178 0           cur++;
9179 0           goto val_end;
9180             }
9181 0 0         if (val_type == YYJSON_TYPE_RAW) {
9182 0           str_len = unsafe_yyjson_get_len(val);
9183 0           str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9184             check_str_len(str_len);
9185 0 0         incr_len(str_len + 2);
    0          
9186 0           cur = write_raw(cur, str_ptr, str_len);
9187 0           *cur++ = ',';
9188 0           goto val_end;
9189             }
9190 0           goto fail_type;
9191              
9192 0           val_end:
9193 0           val++;
9194 0           ctn_len--;
9195 0 0         if (unlikely(ctn_len == 0)) goto ctn_end;
9196 0           goto val_begin;
9197              
9198 0           ctn_end:
9199 0           cur--;
9200 0           *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
9201 0           *cur++ = ',';
9202 0 0         if (unlikely((u8 *)ctx >= end)) goto doc_end;
9203 0           yyjson_write_ctx_get(ctx++, &ctn_len, &ctn_obj);
9204 0           ctn_len--;
9205 0 0         if (likely(ctn_len > 0)) {
9206 0           goto val_begin;
9207             } else {
9208 0           goto ctn_end;
9209             }
9210              
9211 0           doc_end:
9212 0 0         if (newline) {
9213 0 0         incr_len(2);
    0          
9214 0           *(cur - 1) = '\n';
9215 0           cur++;
9216             }
9217 0           *--cur = '\0';
9218 0           *dat_len = (usize)(cur - hdr);
9219 0           memset(err, 0, sizeof(yyjson_write_err));
9220 0           return hdr;
9221              
9222 0 0         fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
9223 0 0         fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
9224 0 0         fail_num: return_err(NAN_OR_INF, MSG_NAN_INF);
9225 0 0         fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8);
9226              
9227             #undef return_err
9228             #undef incr_len
9229             #undef check_str_len
9230             }
9231              
9232             /** Write JSON document pretty.
9233             The root of this document should be a non-empty container. */
9234             static_inline u8 *yyjson_write_pretty(const yyjson_val *root,
9235             const yyjson_write_flag flg,
9236             const yyjson_alc alc,
9237             usize *dat_len,
9238             yyjson_write_err *err) {
9239             #define return_err(_code, _msg) do { \
9240             *dat_len = 0; \
9241             err->code = YYJSON_WRITE_ERROR_##_code; \
9242             err->msg = _msg; \
9243             if (hdr) alc.free(alc.ctx, hdr); \
9244             return NULL; \
9245             } while (false)
9246              
9247             #define incr_len(_len) do { \
9248             ext_len = (usize)(_len); \
9249             if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
9250             usize ctx_pos = (usize)((u8 *)ctx - hdr); \
9251             usize cur_pos = (usize)(cur - hdr); \
9252             ctx_len = (usize)(end - (u8 *)ctx); \
9253             alc_inc = yyjson_max(alc_len / 2, ext_len); \
9254             alc_inc = size_align_up(alc_inc, sizeof(yyjson_write_ctx)); \
9255             if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
9256             goto fail_alloc; \
9257             alc_len += alc_inc; \
9258             tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
9259             if (unlikely(!tmp)) goto fail_alloc; \
9260             ctx_tmp = (yyjson_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
9261             memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
9262             ctx = ctx_tmp; \
9263             cur = tmp + cur_pos; \
9264             end = tmp + alc_len; \
9265             hdr = tmp; \
9266             } \
9267             } while (false)
9268              
9269             #define check_str_len(_len) do { \
9270             if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
9271             goto fail_alloc; \
9272             } while (false)
9273              
9274             yyjson_val *val;
9275             yyjson_type val_type;
9276             usize ctn_len, ctn_len_tmp;
9277             bool ctn_obj, ctn_obj_tmp, is_key, no_indent;
9278             u8 *hdr, *cur, *end, *tmp;
9279             yyjson_write_ctx *ctx, *ctx_tmp;
9280             usize alc_len, alc_inc, ctx_len, ext_len, str_len, level;
9281             const u8 *str_ptr;
9282 0           const char_enc_type *enc_table = get_enc_table_with_flag(flg);
9283 0           bool cpy = (enc_table == enc_table_cpy);
9284 0           bool esc = has_flg(ESCAPE_UNICODE) != 0;
9285 0           bool inv = has_allow(INVALID_UNICODE) != 0;
9286 0 0         usize spaces = has_flg(PRETTY_TWO_SPACES) ? 2 : 4;
9287 0           bool newline = has_flg(NEWLINE_AT_END) != 0;
9288              
9289 0           alc_len = root->uni.ofs / sizeof(yyjson_val);
9290 0           alc_len = alc_len * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64;
9291 0           alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx));
9292 0           hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
9293 0 0         if (!hdr) goto fail_alloc;
9294 0           cur = hdr;
9295 0           end = hdr + alc_len;
9296 0           ctx = (yyjson_write_ctx *)(void *)end;
9297              
9298 0           doc_begin:
9299 0           val = constcast(yyjson_val *)root;
9300 0           val_type = unsafe_yyjson_get_type(val);
9301 0           ctn_obj = (val_type == YYJSON_TYPE_OBJ);
9302 0           ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
9303 0           *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9304 0           *cur++ = '\n';
9305 0           val++;
9306 0           level = 1;
9307              
9308 0           val_begin:
9309 0           val_type = unsafe_yyjson_get_type(val);
9310 0 0         if (val_type == YYJSON_TYPE_STR) {
9311 0           is_key = (bool)((u8)ctn_obj & (u8)~ctn_len);
9312 0           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9313 0           str_len = unsafe_yyjson_get_len(val);
9314 0           str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9315             check_str_len(str_len);
9316 0 0         incr_len(str_len * 6 + 16 + (no_indent ? 0 : level * 4));
    0          
    0          
9317 0 0         cur = write_indent(cur, no_indent ? 0 : level, spaces);
9318 0 0         if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
    0          
9319 0           cur = write_str_noesc(cur, str_ptr, str_len);
9320             } else {
9321 0           cur = write_str(cur, esc, inv, str_ptr, str_len, enc_table);
9322 0 0         if (unlikely(!cur)) goto fail_str;
9323             }
9324 0 0         *cur++ = is_key ? ':' : ',';
9325 0 0         *cur++ = is_key ? ' ' : '\n';
9326 0           goto val_end;
9327             }
9328 0 0         if (val_type == YYJSON_TYPE_NUM) {
9329 0           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9330 0 0         incr_len(FP_BUF_LEN + (no_indent ? 0 : level * 4));
    0          
    0          
9331 0 0         cur = write_indent(cur, no_indent ? 0 : level, spaces);
    0          
9332 0           cur = write_num(cur, val, flg);
9333 0 0         if (unlikely(!cur)) goto fail_num;
9334 0           *cur++ = ',';
9335 0           *cur++ = '\n';
9336 0           goto val_end;
9337             }
9338 0 0         if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
9339             (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
9340 0           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9341 0           ctn_len_tmp = unsafe_yyjson_get_len(val);
9342 0           ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
9343 0 0         if (unlikely(ctn_len_tmp == 0)) {
9344             /* write empty container */
9345 0 0         incr_len(16 + (no_indent ? 0 : level * 4));
    0          
    0          
9346 0 0         cur = write_indent(cur, no_indent ? 0 : level, spaces);
9347 0           *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
9348 0           *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
9349 0           *cur++ = ',';
9350 0           *cur++ = '\n';
9351 0           goto val_end;
9352             } else {
9353             /* push context, setup new container */
9354 0 0         incr_len(32 + (no_indent ? 0 : level * 4));
    0          
    0          
9355 0           yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj);
9356 0           ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
9357 0           ctn_obj = ctn_obj_tmp;
9358 0 0         cur = write_indent(cur, no_indent ? 0 : level, spaces);
9359 0           level++;
9360 0           *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9361 0           *cur++ = '\n';
9362 0           val++;
9363 0           goto val_begin;
9364             }
9365             }
9366 0 0         if (val_type == YYJSON_TYPE_BOOL) {
9367 0           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9368 0 0         incr_len(16 + (no_indent ? 0 : level * 4));
    0          
    0          
9369 0 0         cur = write_indent(cur, no_indent ? 0 : level, spaces);
9370 0 0         cur = write_bool(cur, unsafe_yyjson_get_bool(val));
9371 0           cur += 2;
9372 0           goto val_end;
9373             }
9374 0 0         if (val_type == YYJSON_TYPE_NULL) {
9375 0           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9376 0 0         incr_len(16 + (no_indent ? 0 : level * 4));
    0          
    0          
9377 0 0         cur = write_indent(cur, no_indent ? 0 : level, spaces);
9378 0           cur = write_null(cur);
9379 0           cur += 2;
9380 0           goto val_end;
9381             }
9382 0 0         if (val_type == YYJSON_TYPE_RAW) {
9383 0           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9384 0           str_len = unsafe_yyjson_get_len(val);
9385 0           str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9386             check_str_len(str_len);
9387 0 0         incr_len(str_len + 3 + (no_indent ? 0 : level * 4));
    0          
    0          
9388 0 0         cur = write_indent(cur, no_indent ? 0 : level, spaces);
9389 0           cur = write_raw(cur, str_ptr, str_len);
9390 0           *cur++ = ',';
9391 0           *cur++ = '\n';
9392 0           goto val_end;
9393             }
9394 0           goto fail_type;
9395              
9396 0           val_end:
9397 0           val++;
9398 0           ctn_len--;
9399 0 0         if (unlikely(ctn_len == 0)) goto ctn_end;
9400 0           goto val_begin;
9401              
9402 0           ctn_end:
9403 0           cur -= 2;
9404 0           *cur++ = '\n';
9405 0 0         incr_len(level * 4);
    0          
9406 0           cur = write_indent(cur, --level, spaces);
9407 0           *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
9408 0 0         if (unlikely((u8 *)ctx >= end)) goto doc_end;
9409 0           yyjson_write_ctx_get(ctx++, &ctn_len, &ctn_obj);
9410 0           ctn_len--;
9411 0           *cur++ = ',';
9412 0           *cur++ = '\n';
9413 0 0         if (likely(ctn_len > 0)) {
9414 0           goto val_begin;
9415             } else {
9416 0           goto ctn_end;
9417             }
9418              
9419 0           doc_end:
9420 0 0         if (newline) {
9421 0 0         incr_len(2);
    0          
9422 0           *cur++ = '\n';
9423             }
9424 0           *cur = '\0';
9425 0           *dat_len = (usize)(cur - hdr);
9426 0           memset(err, 0, sizeof(yyjson_write_err));
9427 0           return hdr;
9428              
9429 0 0         fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
9430 0 0         fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
9431 0 0         fail_num: return_err(NAN_OR_INF, MSG_NAN_INF);
9432 0 0         fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8);
9433              
9434             #undef return_err
9435             #undef incr_len
9436             #undef check_str_len
9437             }
9438              
9439              
9440              
9441             /*==============================================================================
9442             * MARK: - JSON Writer (Public)
9443             *============================================================================*/
9444              
9445 0           char *yyjson_val_write_opts(const yyjson_val *val,
9446             yyjson_write_flag flg,
9447             const yyjson_alc *alc_ptr,
9448             usize *dat_len,
9449             yyjson_write_err *err) {
9450             yyjson_write_err tmp_err;
9451             usize tmp_dat_len;
9452 0 0         yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
9453 0           yyjson_val *root = constcast(yyjson_val *)val;
9454              
9455 0 0         if (!err) err = &tmp_err;
9456 0 0         if (!dat_len) dat_len = &tmp_dat_len;
9457              
9458 0 0         if (unlikely(!root)) {
9459 0           *dat_len = 0;
9460 0           err->msg = "input JSON is NULL";
9461 0           err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
9462 0           return NULL;
9463             }
9464              
9465 0 0         if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) {
    0          
9466 0           return (char *)yyjson_write_single(root, flg, alc, dat_len, err);
9467 0 0         } else if (flg & (YYJSON_WRITE_PRETTY | YYJSON_WRITE_PRETTY_TWO_SPACES)) {
9468 0           return (char *)yyjson_write_pretty(root, flg, alc, dat_len, err);
9469             } else {
9470 0           return (char *)yyjson_write_minify(root, flg, alc, dat_len, err);
9471             }
9472             }
9473              
9474 0           char *yyjson_write_opts(const yyjson_doc *doc,
9475             yyjson_write_flag flg,
9476             const yyjson_alc *alc_ptr,
9477             usize *dat_len,
9478             yyjson_write_err *err) {
9479 0 0         yyjson_val *root = doc ? doc->root : NULL;
9480 0           return yyjson_val_write_opts(root, flg, alc_ptr, dat_len, err);
9481             }
9482              
9483 0           bool yyjson_val_write_file(const char *path,
9484             const yyjson_val *val,
9485             yyjson_write_flag flg,
9486             const yyjson_alc *alc_ptr,
9487             yyjson_write_err *err) {
9488             yyjson_write_err tmp_err;
9489 0 0         yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
9490             u8 *dat;
9491 0           usize dat_len = 0;
9492 0           yyjson_val *root = constcast(yyjson_val *)val;
9493             bool suc;
9494              
9495 0 0         if (!err) err = &tmp_err;
9496 0 0         if (unlikely(!path || !*path)) {
    0          
9497 0           err->msg = "input path is invalid";
9498 0           err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
9499 0           return false;
9500             }
9501              
9502 0           dat = (u8 *)yyjson_val_write_opts(root, flg, &alc, &dat_len, err);
9503 0 0         if (unlikely(!dat)) return false;
9504 0           suc = write_dat_to_file(path, dat, dat_len, err);
9505 0           alc.free(alc.ctx, dat);
9506 0           return suc;
9507             }
9508              
9509 0           bool yyjson_val_write_fp(FILE *fp,
9510             const yyjson_val *val,
9511             yyjson_write_flag flg,
9512             const yyjson_alc *alc_ptr,
9513             yyjson_write_err *err) {
9514             yyjson_write_err tmp_err;
9515 0 0         yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
9516             u8 *dat;
9517 0           usize dat_len = 0;
9518 0           yyjson_val *root = constcast(yyjson_val *)val;
9519             bool suc;
9520              
9521 0 0         if (!err) err = &tmp_err;
9522 0 0         if (unlikely(!fp)) {
9523 0           err->msg = "input fp is invalid";
9524 0           err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
9525 0           return false;
9526             }
9527              
9528 0           dat = (u8 *)yyjson_val_write_opts(root, flg, &alc, &dat_len, err);
9529 0 0         if (unlikely(!dat)) return false;
9530 0           suc = write_dat_to_fp(fp, dat, dat_len, err);
9531 0           alc.free(alc.ctx, dat);
9532 0           return suc;
9533             }
9534              
9535 0           bool yyjson_write_file(const char *path,
9536             const yyjson_doc *doc,
9537             yyjson_write_flag flg,
9538             const yyjson_alc *alc_ptr,
9539             yyjson_write_err *err) {
9540 0 0         yyjson_val *root = doc ? doc->root : NULL;
9541 0           return yyjson_val_write_file(path, root, flg, alc_ptr, err);
9542             }
9543              
9544 0           bool yyjson_write_fp(FILE *fp,
9545             const yyjson_doc *doc,
9546             yyjson_write_flag flg,
9547             const yyjson_alc *alc_ptr,
9548             yyjson_write_err *err) {
9549 0 0         yyjson_val *root = doc ? doc->root : NULL;
9550 0           return yyjson_val_write_fp(fp, root, flg, alc_ptr, err);
9551             }
9552              
9553              
9554              
9555             /*==============================================================================
9556             * MARK: - Mutable JSON Writer Implementation (Private)
9557             *============================================================================*/
9558              
9559             typedef struct yyjson_mut_write_ctx {
9560             usize tag;
9561             yyjson_mut_val *ctn;
9562             } yyjson_mut_write_ctx;
9563              
9564             static_inline void yyjson_mut_write_ctx_set(yyjson_mut_write_ctx *ctx,
9565             yyjson_mut_val *ctn,
9566             usize size, bool is_obj) {
9567 8           ctx->tag = (size << 1) | (usize)is_obj;
9568 8           ctx->ctn = ctn;
9569 8           }
9570              
9571             static_inline void yyjson_mut_write_ctx_get(yyjson_mut_write_ctx *ctx,
9572             yyjson_mut_val **ctn,
9573             usize *size, bool *is_obj) {
9574 8           usize tag = ctx->tag;
9575 8           *size = tag >> 1;
9576 8           *is_obj = (bool)(tag & 1);
9577 8           *ctn = ctx->ctn;
9578 8           }
9579              
9580             /** Get the estimated number of values for the mutable JSON document. */
9581             static_inline usize yyjson_mut_doc_estimated_val_num(
9582             const yyjson_mut_doc *doc) {
9583 15026           usize sum = 0;
9584 15026           yyjson_val_chunk *chunk = doc->val_pool.chunks;
9585 30053 100         while (chunk) {
9586 15027           sum += chunk->chunk_size / sizeof(yyjson_mut_val) - 1;
9587 15027 100         if (chunk == doc->val_pool.chunks) {
9588 15026           sum -= (usize)(doc->val_pool.end - doc->val_pool.cur);
9589             }
9590 15027           chunk = chunk->next;
9591             }
9592 15026           return sum;
9593             }
9594              
9595             /** Write single JSON value. */
9596             static_inline u8 *yyjson_mut_write_single(yyjson_mut_val *val,
9597             yyjson_write_flag flg,
9598             yyjson_alc alc,
9599             usize *dat_len,
9600             yyjson_write_err *err) {
9601 16           return yyjson_write_single((yyjson_val *)val, flg, alc, dat_len, err);
9602             }
9603              
9604             /** Write JSON document minify.
9605             The root of this document should be a non-empty container. */
9606             static_inline u8 *yyjson_mut_write_minify(const yyjson_mut_val *root,
9607             usize estimated_val_num,
9608             yyjson_write_flag flg,
9609             yyjson_alc alc,
9610             usize *dat_len,
9611             yyjson_write_err *err) {
9612             #define return_err(_code, _msg) do { \
9613             *dat_len = 0; \
9614             err->code = YYJSON_WRITE_ERROR_##_code; \
9615             err->msg = _msg; \
9616             if (hdr) alc.free(alc.ctx, hdr); \
9617             return NULL; \
9618             } while (false)
9619              
9620             #define incr_len(_len) do { \
9621             ext_len = (usize)(_len); \
9622             if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
9623             usize ctx_pos = (usize)((u8 *)ctx - hdr); \
9624             usize cur_pos = (usize)(cur - hdr); \
9625             ctx_len = (usize)(end - (u8 *)ctx); \
9626             alc_inc = yyjson_max(alc_len / 2, ext_len); \
9627             alc_inc = size_align_up(alc_inc, sizeof(yyjson_mut_write_ctx)); \
9628             if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
9629             goto fail_alloc; \
9630             alc_len += alc_inc; \
9631             tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
9632             if (unlikely(!tmp)) goto fail_alloc; \
9633             ctx_tmp = (yyjson_mut_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
9634             memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
9635             ctx = ctx_tmp; \
9636             cur = tmp + cur_pos; \
9637             end = tmp + alc_len; \
9638             hdr = tmp; \
9639             } \
9640             } while (false)
9641              
9642             #define check_str_len(_len) do { \
9643             if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
9644             goto fail_alloc; \
9645             } while (false)
9646              
9647             yyjson_mut_val *val, *ctn;
9648             yyjson_type val_type;
9649             usize ctn_len, ctn_len_tmp;
9650             bool ctn_obj, ctn_obj_tmp, is_key;
9651             u8 *hdr, *cur, *end, *tmp;
9652             yyjson_mut_write_ctx *ctx, *ctx_tmp;
9653             usize alc_len, alc_inc, ctx_len, ext_len, str_len;
9654             const u8 *str_ptr;
9655 15021           const char_enc_type *enc_table = get_enc_table_with_flag(flg);
9656 15021           bool cpy = (enc_table == enc_table_cpy);
9657 15021           bool esc = has_flg(ESCAPE_UNICODE) != 0;
9658 15021           bool inv = has_allow(INVALID_UNICODE) != 0;
9659 15021           bool newline = has_flg(NEWLINE_AT_END) != 0;
9660              
9661 15021           alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64;
9662 15021           alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx));
9663 15021           hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
9664 15021 50         if (!hdr) goto fail_alloc;
9665 15021           cur = hdr;
9666 15021           end = hdr + alc_len;
9667 15021           ctx = (yyjson_mut_write_ctx *)(void *)end;
9668              
9669 15021           doc_begin:
9670 15021           val = constcast(yyjson_mut_val *)root;
9671 15021           val_type = unsafe_yyjson_get_type(val);
9672 15021           ctn_obj = (val_type == YYJSON_TYPE_OBJ);
9673 15021           ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
9674 15021           *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9675 15021           ctn = val;
9676 15021           val = (yyjson_mut_val *)val->uni.ptr; /* tail */
9677 15021 100         val = ctn_obj ? val->next->next : val->next;
9678              
9679 40066           val_begin:
9680 55087           val_type = unsafe_yyjson_get_type(val);
9681 55087 100         if (val_type == YYJSON_TYPE_STR) {
9682 20035           is_key = ((u8)ctn_obj & (u8)~ctn_len);
9683 20035           str_len = unsafe_yyjson_get_len(val);
9684 20035           str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9685             check_str_len(str_len);
9686 20035 50         incr_len(str_len * 6 + 16);
    0          
9687 40070 50         if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
    100          
9688 10024           cur = write_str_noesc(cur, str_ptr, str_len);
9689             } else {
9690 10011           cur = write_str(cur, esc, inv, str_ptr, str_len, enc_table);
9691 10011 50         if (unlikely(!cur)) goto fail_str;
9692             }
9693 20035 100         *cur++ = is_key ? ':' : ',';
9694 20035           goto val_end;
9695             }
9696 35052 100         if (val_type == YYJSON_TYPE_NUM) {
9697 35042 100         incr_len(FP_BUF_LEN);
    50          
9698 35040           cur = write_num(cur, (yyjson_val *)val, flg);
9699 35040 50         if (unlikely(!cur)) goto fail_num;
9700 35040           *cur++ = ',';
9701 35040           goto val_end;
9702             }
9703 12 100         if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
9704             (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
9705 9           ctn_len_tmp = unsafe_yyjson_get_len(val);
9706 9           ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
9707 9 50         incr_len(16);
    0          
9708 9 100         if (unlikely(ctn_len_tmp == 0)) {
9709             /* write empty container */
9710 2           *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
9711 2           *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
9712 2           *cur++ = ',';
9713 2           goto val_end;
9714             } else {
9715             /* push context, setup new container */
9716 7           yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj);
9717 7           ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
9718 7           ctn_obj = ctn_obj_tmp;
9719 7           *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9720 7           ctn = val;
9721 7           val = (yyjson_mut_val *)ctn->uni.ptr; /* tail */
9722 7 100         val = ctn_obj ? val->next->next : val->next;
9723 7           goto val_begin;
9724             }
9725             }
9726 3 100         if (val_type == YYJSON_TYPE_BOOL) {
9727 2 50         incr_len(16);
    0          
9728 2 100         cur = write_bool(cur, unsafe_yyjson_get_bool(val));
9729 2           cur++;
9730 2           goto val_end;
9731             }
9732 1 50         if (val_type == YYJSON_TYPE_NULL) {
9733 1 50         incr_len(16);
    0          
9734 1           cur = write_null(cur);
9735 1           cur++;
9736 1           goto val_end;
9737             }
9738 0 0         if (val_type == YYJSON_TYPE_RAW) {
9739 0           str_len = unsafe_yyjson_get_len(val);
9740 0           str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9741             check_str_len(str_len);
9742 0 0         incr_len(str_len + 2);
    0          
9743 0           cur = write_raw(cur, str_ptr, str_len);
9744 0           *cur++ = ',';
9745 0           goto val_end;
9746             }
9747 0           goto fail_type;
9748              
9749 55080           val_end:
9750 55080           ctn_len--;
9751 55080 100         if (unlikely(ctn_len == 0)) goto ctn_end;
9752 40059           val = val->next;
9753 40059           goto val_begin;
9754              
9755 15028           ctn_end:
9756 15028           cur--;
9757 15028           *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
9758 15028           *cur++ = ',';
9759 15028 100         if (unlikely((u8 *)ctx >= end)) goto doc_end;
9760 7           val = ctn->next;
9761 7           yyjson_mut_write_ctx_get(ctx++, &ctn, &ctn_len, &ctn_obj);
9762 7           ctn_len--;
9763 7 50         if (likely(ctn_len > 0)) {
9764 0           goto val_begin;
9765             } else {
9766 7           goto ctn_end;
9767             }
9768              
9769 15021           doc_end:
9770 15021 50         if (newline) {
9771 0 0         incr_len(2);
    0          
9772 0           *(cur - 1) = '\n';
9773 0           cur++;
9774             }
9775 15021           *--cur = '\0';
9776 15021           *dat_len = (usize)(cur - hdr);
9777 15021           err->code = YYJSON_WRITE_SUCCESS;
9778 15021           err->msg = NULL;
9779 15021           return hdr;
9780              
9781 0 0         fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
9782 0 0         fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
9783 0 0         fail_num: return_err(NAN_OR_INF, MSG_NAN_INF);
9784 0 0         fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8);
9785              
9786             #undef return_err
9787             #undef incr_len
9788             #undef check_str_len
9789             }
9790              
9791             /** Write JSON document pretty.
9792             The root of this document should be a non-empty container. */
9793             static_inline u8 *yyjson_mut_write_pretty(const yyjson_mut_val *root,
9794             usize estimated_val_num,
9795             yyjson_write_flag flg,
9796             yyjson_alc alc,
9797             usize *dat_len,
9798             yyjson_write_err *err) {
9799             #define return_err(_code, _msg) do { \
9800             *dat_len = 0; \
9801             err->code = YYJSON_WRITE_ERROR_##_code; \
9802             err->msg = _msg; \
9803             if (hdr) alc.free(alc.ctx, hdr); \
9804             return NULL; \
9805             } while (false)
9806              
9807             #define incr_len(_len) do { \
9808             ext_len = (usize)(_len); \
9809             if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
9810             usize ctx_pos = (usize)((u8 *)ctx - hdr); \
9811             usize cur_pos = (usize)(cur - hdr); \
9812             ctx_len = (usize)(end - (u8 *)ctx); \
9813             alc_inc = yyjson_max(alc_len / 2, ext_len); \
9814             alc_inc = size_align_up(alc_inc, sizeof(yyjson_mut_write_ctx)); \
9815             if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
9816             goto fail_alloc; \
9817             alc_len += alc_inc; \
9818             tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
9819             if (unlikely(!tmp)) goto fail_alloc; \
9820             ctx_tmp = (yyjson_mut_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
9821             memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
9822             ctx = ctx_tmp; \
9823             cur = tmp + cur_pos; \
9824             end = tmp + alc_len; \
9825             hdr = tmp; \
9826             } \
9827             } while (false)
9828              
9829             #define check_str_len(_len) do { \
9830             if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
9831             goto fail_alloc; \
9832             } while (false)
9833              
9834             yyjson_mut_val *val, *ctn;
9835             yyjson_type val_type;
9836             usize ctn_len, ctn_len_tmp;
9837             bool ctn_obj, ctn_obj_tmp, is_key, no_indent;
9838             u8 *hdr, *cur, *end, *tmp;
9839             yyjson_mut_write_ctx *ctx, *ctx_tmp;
9840             usize alc_len, alc_inc, ctx_len, ext_len, str_len, level;
9841             const u8 *str_ptr;
9842 9           const char_enc_type *enc_table = get_enc_table_with_flag(flg);
9843 9           bool cpy = (enc_table == enc_table_cpy);
9844 9           bool esc = has_flg(ESCAPE_UNICODE) != 0;
9845 9           bool inv = has_allow(INVALID_UNICODE) != 0;
9846 18 50         usize spaces = has_flg(PRETTY_TWO_SPACES) ? 2 : 4;
9847 9           bool newline = has_flg(NEWLINE_AT_END) != 0;
9848              
9849 9           alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64;
9850 9           alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx));
9851 9           hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
9852 9 50         if (!hdr) goto fail_alloc;
9853 9           cur = hdr;
9854 9           end = hdr + alc_len;
9855 9           ctx = (yyjson_mut_write_ctx *)(void *)end;
9856              
9857 9           doc_begin:
9858 9           val = constcast(yyjson_mut_val *)root;
9859 9           val_type = unsafe_yyjson_get_type(val);
9860 9           ctn_obj = (val_type == YYJSON_TYPE_OBJ);
9861 9           ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
9862 9           *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9863 9           *cur++ = '\n';
9864 9           ctn = val;
9865 9           val = (yyjson_mut_val *)val->uni.ptr; /* tail */
9866 9 50         val = ctn_obj ? val->next->next : val->next;
9867 9           level = 1;
9868              
9869 13           val_begin:
9870 22           val_type = unsafe_yyjson_get_type(val);
9871 22 100         if (val_type == YYJSON_TYPE_STR) {
9872 11           is_key = (bool)((u8)ctn_obj & (u8)~ctn_len);
9873 11           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9874 11           str_len = unsafe_yyjson_get_len(val);
9875 11           str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9876             check_str_len(str_len);
9877 11 100         incr_len(str_len * 6 + 16 + (no_indent ? 0 : level * 4));
    50          
    0          
9878 11 100         cur = write_indent(cur, no_indent ? 0 : level, spaces);
9879 22 50         if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
    100          
9880 6           cur = write_str_noesc(cur, str_ptr, str_len);
9881             } else {
9882 5           cur = write_str(cur, esc, inv, str_ptr, str_len, enc_table);
9883 5 50         if (unlikely(!cur)) goto fail_str;
9884             }
9885 11 100         *cur++ = is_key ? ':' : ',';
9886 11 100         *cur++ = is_key ? ' ' : '\n';
9887 11           goto val_end;
9888             }
9889 11 100         if (val_type == YYJSON_TYPE_NUM) {
9890 8           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9891 8 50         incr_len(FP_BUF_LEN + (no_indent ? 0 : level * 4));
    50          
    0          
9892 16 50         cur = write_indent(cur, no_indent ? 0 : level, spaces);
    50          
9893 8           cur = write_num(cur, (yyjson_val *)val, flg);
9894 8 50         if (unlikely(!cur)) goto fail_num;
9895 8           *cur++ = ',';
9896 8           *cur++ = '\n';
9897 8           goto val_end;
9898             }
9899 3 100         if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
9900             (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
9901 1           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9902 1           ctn_len_tmp = unsafe_yyjson_get_len(val);
9903 1           ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
9904 1 50         if (unlikely(ctn_len_tmp == 0)) {
9905             /* write empty container */
9906 0 0         incr_len(16 + (no_indent ? 0 : level * 4));
    0          
    0          
9907 0 0         cur = write_indent(cur, no_indent ? 0 : level, spaces);
9908 0           *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
9909 0           *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
9910 0           *cur++ = ',';
9911 0           *cur++ = '\n';
9912 0           goto val_end;
9913             } else {
9914             /* push context, setup new container */
9915 1 50         incr_len(32 + (no_indent ? 0 : level * 4));
    50          
    0          
9916 1           yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj);
9917 1           ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
9918 1           ctn_obj = ctn_obj_tmp;
9919 1 50         cur = write_indent(cur, no_indent ? 0 : level, spaces);
9920 1           level++;
9921 1           *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9922 1           *cur++ = '\n';
9923 1           ctn = val;
9924 1           val = (yyjson_mut_val *)ctn->uni.ptr; /* tail */
9925 1 50         val = ctn_obj ? val->next->next : val->next;
9926 1           goto val_begin;
9927             }
9928             }
9929 2 100         if (val_type == YYJSON_TYPE_BOOL) {
9930 1           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9931 2 50         incr_len(16 + (no_indent ? 0 : level * 4));
    50          
    50          
9932 2 50         cur = write_indent(cur, no_indent ? 0 : level, spaces);
9933 1 50         cur = write_bool(cur, unsafe_yyjson_get_bool(val));
9934 1           cur += 2;
9935 1           goto val_end;
9936             }
9937 1 50         if (val_type == YYJSON_TYPE_NULL) {
9938 1           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9939 1 50         incr_len(16 + (no_indent ? 0 : level * 4));
    50          
    0          
9940 2 50         cur = write_indent(cur, no_indent ? 0 : level, spaces);
9941 1           cur = write_null(cur);
9942 1           cur += 2;
9943 1           goto val_end;
9944             }
9945 0 0         if (val_type == YYJSON_TYPE_RAW) {
9946 0           no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9947 0           str_len = unsafe_yyjson_get_len(val);
9948 0           str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9949             check_str_len(str_len);
9950 0 0         incr_len(str_len + 3 + (no_indent ? 0 : level * 4));
    0          
    0          
9951 0 0         cur = write_indent(cur, no_indent ? 0 : level, spaces);
9952 0           cur = write_raw(cur, str_ptr, str_len);
9953 0           *cur++ = ',';
9954 0           *cur++ = '\n';
9955 0           goto val_end;
9956             }
9957 0           goto fail_type;
9958              
9959 21           val_end:
9960 21           ctn_len--;
9961 21 100         if (unlikely(ctn_len == 0)) goto ctn_end;
9962 12           val = val->next;
9963 12           goto val_begin;
9964              
9965 10           ctn_end:
9966 10           cur -= 2;
9967 10           *cur++ = '\n';
9968 10 50         incr_len(level * 4);
    0          
9969 10           cur = write_indent(cur, --level, spaces);
9970 10           *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
9971 10 100         if (unlikely((u8 *)ctx >= end)) goto doc_end;
9972 1           val = ctn->next;
9973 1           yyjson_mut_write_ctx_get(ctx++, &ctn, &ctn_len, &ctn_obj);
9974 1           ctn_len--;
9975 1           *cur++ = ',';
9976 1           *cur++ = '\n';
9977 1 50         if (likely(ctn_len > 0)) {
9978 0           goto val_begin;
9979             } else {
9980 1           goto ctn_end;
9981             }
9982              
9983 9           doc_end:
9984 9 50         if (newline) {
9985 0 0         incr_len(2);
    0          
9986 0           *cur++ = '\n';
9987             }
9988 9           *cur = '\0';
9989 9           *dat_len = (usize)(cur - hdr);
9990 9           err->code = YYJSON_WRITE_SUCCESS;
9991 9           err->msg = NULL;
9992 9           return hdr;
9993              
9994 0 0         fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
9995 0 0         fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
9996 0 0         fail_num: return_err(NAN_OR_INF, MSG_NAN_INF);
9997 0 0         fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8);
9998              
9999             #undef return_err
10000             #undef incr_len
10001             #undef check_str_len
10002             }
10003              
10004 15046           static char *yyjson_mut_write_opts_impl(const yyjson_mut_val *val,
10005             usize estimated_val_num,
10006             yyjson_write_flag flg,
10007             const yyjson_alc *alc_ptr,
10008             usize *dat_len,
10009             yyjson_write_err *err) {
10010             yyjson_write_err tmp_err;
10011             usize tmp_dat_len;
10012 15046 100         yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
10013 15046           yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
10014              
10015 15046 50         if (!err) err = &tmp_err;
10016 15046 50         if (!dat_len) dat_len = &tmp_dat_len;
10017              
10018 15046 50         if (unlikely(!root)) {
10019 0           *dat_len = 0;
10020 0           err->msg = "input JSON is NULL";
10021 0           err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
10022 0           return NULL;
10023             }
10024              
10025 30078 100         if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) {
    100          
10026 16           return (char *)yyjson_mut_write_single(root, flg, alc, dat_len, err);
10027 15030 100         } else if (flg & (YYJSON_WRITE_PRETTY | YYJSON_WRITE_PRETTY_TWO_SPACES)) {
10028 9           return (char *)yyjson_mut_write_pretty(root, estimated_val_num,
10029             flg, alc, dat_len, err);
10030             } else {
10031 15021           return (char *)yyjson_mut_write_minify(root, estimated_val_num,
10032             flg, alc, dat_len, err);
10033             }
10034             }
10035              
10036              
10037              
10038             /*==============================================================================
10039             * MARK: - Mutable JSON Writer (Public)
10040             *============================================================================*/
10041              
10042 20           char *yyjson_mut_val_write_opts(const yyjson_mut_val *val,
10043             yyjson_write_flag flg,
10044             const yyjson_alc *alc_ptr,
10045             usize *dat_len,
10046             yyjson_write_err *err) {
10047 20           return yyjson_mut_write_opts_impl(val, 0, flg, alc_ptr, dat_len, err);
10048             }
10049              
10050 15026           char *yyjson_mut_write_opts(const yyjson_mut_doc *doc,
10051             yyjson_write_flag flg,
10052             const yyjson_alc *alc_ptr,
10053             usize *dat_len,
10054             yyjson_write_err *err) {
10055             yyjson_mut_val *root;
10056             usize estimated_val_num;
10057 15026 50         if (likely(doc)) {
10058 15026           root = doc->root;
10059 15026           estimated_val_num = yyjson_mut_doc_estimated_val_num(doc);
10060             } else {
10061 0           root = NULL;
10062 0           estimated_val_num = 0;
10063             }
10064 15026           return yyjson_mut_write_opts_impl(root, estimated_val_num,
10065             flg, alc_ptr, dat_len, err);
10066             }
10067              
10068 3           bool yyjson_mut_val_write_file(const char *path,
10069             const yyjson_mut_val *val,
10070             yyjson_write_flag flg,
10071             const yyjson_alc *alc_ptr,
10072             yyjson_write_err *err) {
10073             yyjson_write_err tmp_err;
10074 3 50         yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
10075             u8 *dat;
10076 3           usize dat_len = 0;
10077 3           yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
10078             bool suc;
10079              
10080 3 50         if (!err) err = &tmp_err;
10081 3 50         if (unlikely(!path || !*path)) {
    50          
10082 0           err->msg = "input path is invalid";
10083 0           err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
10084 0           return false;
10085             }
10086              
10087 3           dat = (u8 *)yyjson_mut_val_write_opts(root, flg, &alc, &dat_len, err);
10088 3 50         if (unlikely(!dat)) return false;
10089 3           suc = write_dat_to_file(path, dat, dat_len, err);
10090 3           alc.free(alc.ctx, dat);
10091 3           return suc;
10092             }
10093              
10094 0           bool yyjson_mut_val_write_fp(FILE *fp,
10095             const yyjson_mut_val *val,
10096             yyjson_write_flag flg,
10097             const yyjson_alc *alc_ptr,
10098             yyjson_write_err *err) {
10099             yyjson_write_err tmp_err;
10100 0 0         yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
10101             u8 *dat;
10102 0           usize dat_len = 0;
10103 0           yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
10104             bool suc;
10105              
10106 0 0         if (!err) err = &tmp_err;
10107 0 0         if (unlikely(!fp)) {
10108 0           err->msg = "input fp is invalid";
10109 0           err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
10110 0           return false;
10111             }
10112              
10113 0           dat = (u8 *)yyjson_mut_val_write_opts(root, flg, &alc, &dat_len, err);
10114 0 0         if (unlikely(!dat)) return false;
10115 0           suc = write_dat_to_fp(fp, dat, dat_len, err);
10116 0           alc.free(alc.ctx, dat);
10117 0           return suc;
10118             }
10119              
10120 3           bool yyjson_mut_write_file(const char *path,
10121             const yyjson_mut_doc *doc,
10122             yyjson_write_flag flg,
10123             const yyjson_alc *alc_ptr,
10124             yyjson_write_err *err) {
10125 3 50         yyjson_mut_val *root = doc ? doc->root : NULL;
10126 3           return yyjson_mut_val_write_file(path, root, flg, alc_ptr, err);
10127             }
10128              
10129 0           bool yyjson_mut_write_fp(FILE *fp,
10130             const yyjson_mut_doc *doc,
10131             yyjson_write_flag flg,
10132             const yyjson_alc *alc_ptr,
10133             yyjson_write_err *err) {
10134 0 0         yyjson_mut_val *root = doc ? doc->root : NULL;
10135 0           return yyjson_mut_val_write_fp(fp, root, flg, alc_ptr, err);
10136             }
10137              
10138             #undef has_flg
10139             #undef has_allow
10140             #endif /* YYJSON_DISABLE_WRITER */
10141              
10142              
10143              
10144             #if !YYJSON_DISABLE_UTILS
10145              
10146             /*==============================================================================
10147             * MARK: - JSON Pointer API (RFC 6901) (Public)
10148             *============================================================================*/
10149              
10150             /**
10151             Get a token from JSON pointer string.
10152             @param ptr [in] string that points to current token prefix `/`
10153             [out] string that points to next token prefix `/`, or string end
10154             @param end [in] end of the entire JSON Pointer string
10155             @param len [out] unescaped token length
10156             @param esc [out] number of escaped characters in this token
10157             @return head of the token, or NULL if syntax error
10158             */
10159             static_inline const char *ptr_next_token(const char **ptr, const char *end,
10160             usize *len, usize *esc) {
10161 15294           const char *hdr = *ptr + 1;
10162 15294           const char *cur = hdr;
10163             /* skip unescaped characters */
10164 30821 100         while (cur < end && *cur != '/' && *cur != '~') cur++;
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    50          
    0          
    0          
    0          
10165 15294 100         if (likely(cur == end || *cur != '~')) {
    50          
    0          
    0          
    0          
    0          
    100          
    50          
    0          
    0          
10166             /* no escaped characters, return */
10167 15294           *ptr = cur;
10168 15294           *len = (usize)(cur - hdr);
10169 15294           *esc = 0;
10170 15294           return hdr;
10171             } else {
10172             /* handle escaped characters */
10173 0           usize esc_num = 0;
10174 0 0         while (cur < end && *cur != '/') {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
10175 0 0         if (*cur++ == '~') {
    0          
    0          
    0          
    0          
10176 0 0         if (cur == end || (*cur != '0' && *cur != '1')) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
10177 0           *ptr = cur - 1;
10178 0           return NULL;
10179             }
10180 0           esc_num++;
10181             }
10182             }
10183 0           *ptr = cur;
10184 0           *len = (usize)(cur - hdr) - esc_num;
10185 0           *esc = esc_num;
10186 0           return hdr;
10187             }
10188             }
10189              
10190             /**
10191             Convert token string to index.
10192             @param cur [in] token head
10193             @param len [in] token length
10194             @param idx [out] the index number, or USIZE_MAX if token is '-'
10195             @return true if token is a valid array index
10196             */
10197             static_inline bool ptr_token_to_idx(const char *cur, usize len, usize *idx) {
10198 118           const char *end = cur + len;
10199 118           usize num = 0, add;
10200 118 50         if (unlikely(len == 0 || len > USIZE_SAFE_DIG)) return false;
    50          
    50          
    50          
    0          
    0          
10201 118 100         if (*cur == '0') {
    100          
    0          
10202 104 50         if (unlikely(len > 1)) return false;
    50          
    0          
10203 104           *idx = 0;
10204 104           return true;
10205             }
10206 14 100         if (*cur == '-') {
    50          
    0          
10207 8 50         if (unlikely(len > 1)) return false;
    0          
    0          
10208 8           *idx = USIZE_MAX;
10209 8           return true;
10210             }
10211 15 100         for (; cur < end && (add = (usize)((u8)*cur - (u8)'0')) <= 9; cur++) {
    50          
    100          
    50          
    0          
    0          
10212 9           num = num * 10 + add;
10213             }
10214 6 50         if (unlikely(num == 0 || cur < end)) return false;
    50          
    50          
    50          
    0          
    0          
10215 6           *idx = num;
10216 6           return true;
10217             }
10218              
10219             /**
10220             Compare JSON key with token.
10221             @param key a string key (yyjson_val or yyjson_mut_val)
10222             @param token a JSON pointer token
10223             @param len unescaped token length
10224             @param esc number of escaped characters in this token
10225             @return true if `str` is equals to `token`
10226             */
10227             static_inline bool ptr_token_eq(void *key,
10228             const char *token, usize len, usize esc) {
10229 0           yyjson_val *val = (yyjson_val *)key;
10230 18301 100         if (unsafe_yyjson_get_len(val) != len) return false;
    100          
    0          
10231 18130 50         if (likely(!esc)) {
    50          
    0          
10232 18130           return memcmp(val->uni.str, token, len) == 0;
10233             } else {
10234 0           const char *str = val->uni.str;
10235 0 0         for (; len-- > 0; token++, str++) {
    0          
    0          
10236 0 0         if (*token == '~') {
    0          
    0          
10237 0 0         if (*str != (*++token == '0' ? '~' : '/')) return false;
    0          
    0          
    0          
    0          
    0          
10238             } else {
10239 0 0         if (*str != *token) return false;
    0          
    0          
10240             }
10241             }
10242 0           return true;
10243             }
10244             }
10245              
10246             /**
10247             Get a value from array by token.
10248             @param arr an array, should not be NULL or non-array type
10249             @param token a JSON pointer token
10250             @param len unescaped token length
10251             @param esc number of escaped characters in this token
10252             @return value at index, or NULL if token is not index or index is out of range
10253             */
10254             static_inline yyjson_val *ptr_arr_get(yyjson_val *arr, const char *token,
10255             usize len, usize esc) {
10256 0           yyjson_val *val = unsafe_yyjson_get_first(arr);
10257 0           usize num = unsafe_yyjson_get_len(arr), idx = 0;
10258 0 0         if (unlikely(num == 0)) return NULL;
10259 0 0         if (unlikely(!ptr_token_to_idx(token, len, &idx))) return NULL;
10260 0 0         if (unlikely(idx >= num)) return NULL;
10261 0 0         if (unsafe_yyjson_arr_is_flat(arr)) {
10262 0           return val + idx;
10263             } else {
10264 0 0         while (idx-- > 0) val = unsafe_yyjson_get_next(val);
10265 0           return val;
10266             }
10267             }
10268              
10269             /**
10270             Get a value from object by token.
10271             @param obj [in] an object, should not be NULL or non-object type
10272             @param token [in] a JSON pointer token
10273             @param len [in] unescaped token length
10274             @param esc [in] number of escaped characters in this token
10275             @return value associated with the token, or NULL if no value
10276             */
10277             static_inline yyjson_val *ptr_obj_get(yyjson_val *obj, const char *token,
10278             usize len, usize esc) {
10279 0           yyjson_val *key = unsafe_yyjson_get_first(obj);
10280 0           usize num = unsafe_yyjson_get_len(obj);
10281 0 0         if (unlikely(num == 0)) return NULL;
10282 0 0         for (; num > 0; num--, key = unsafe_yyjson_get_next(key + 1)) {
10283 0 0         if (ptr_token_eq(key, token, len, esc)) return key + 1;
10284             }
10285 0           return NULL;
10286             }
10287              
10288             /**
10289             Get a value from array by token.
10290             @param arr [in] an array, should not be NULL or non-array type
10291             @param token [in] a JSON pointer token
10292             @param len [in] unescaped token length
10293             @param esc [in] number of escaped characters in this token
10294             @param pre [out] previous (sibling) value of the returned value
10295             @param last [out] whether index is last
10296             @return value at index, or NULL if token is not index or index is out of range
10297             */
10298             static_inline yyjson_mut_val *ptr_mut_arr_get(yyjson_mut_val *arr,
10299             const char *token,
10300             usize len, usize esc,
10301             yyjson_mut_val **pre,
10302             bool *last) {
10303 120           yyjson_mut_val *val = (yyjson_mut_val *)arr->uni.ptr; /* last (tail) */
10304 120           usize num = unsafe_yyjson_get_len(arr), idx;
10305 120 50         if (last) *last = false;
    50          
10306 120 50         if (pre) *pre = NULL;
    50          
10307 120 100         if (unlikely(num == 0)) {
    50          
10308 2 50         if (last && len == 1 && (*token == '0' || *token == '-')) *last = true;
    50          
    50          
    50          
    0          
    0          
    0          
    0          
10309 2           return NULL;
10310             }
10311 118 50         if (unlikely(!ptr_token_to_idx(token, len, &idx))) return NULL;
    50          
10312 118 50         if (last) *last = (idx == num || idx == USIZE_MAX);
    50          
    100          
    50          
    50          
    50          
10313 118 100         if (unlikely(idx >= num)) return NULL;
    50          
10314 10115 100         while (idx-- > 0) val = val->next;
    100          
10315 110 50         if (pre) *pre = val;
    50          
10316 110           return val->next;
10317             }
10318              
10319             /**
10320             Get a value from object by token.
10321             @param obj [in] an object, should not be NULL or non-object type
10322             @param token [in] a JSON pointer token
10323             @param len [in] unescaped token length
10324             @param esc [in] number of escaped characters in this token
10325             @param pre [out] previous (sibling) key of the returned value's key
10326             @return value associated with the token, or NULL if no value
10327             */
10328             static_inline yyjson_mut_val *ptr_mut_obj_get(yyjson_mut_val *obj,
10329             const char *token,
10330             usize len, usize esc,
10331             yyjson_mut_val **pre) {
10332 15174           yyjson_mut_val *pre_key = (yyjson_mut_val *)obj->uni.ptr, *key;
10333 15174           usize num = unsafe_yyjson_get_len(obj);
10334 15174 50         if (pre) *pre = NULL;
    50          
10335 15174 100         if (unlikely(num == 0)) return NULL;
    100          
10336 28328 100         for (; num > 0; num--, pre_key = key) {
    100          
10337 18301           key = pre_key->next->next;
10338 18301 100         if (ptr_token_eq(key, token, len, esc)) {
    100          
10339 5143 50         if (pre) *pre = pre_key;
    50          
10340 5143           return key->next;
10341             }
10342             }
10343 10027           return NULL;
10344             }
10345              
10346             /**
10347             Create a string value with JSON pointer token.
10348             @param token [in] a JSON pointer token
10349             @param len [in] unescaped token length
10350             @param esc [in] number of escaped characters in this token
10351             @param doc [in] used for memory allocation when creating value
10352             @return new string value, or NULL if memory allocation failed
10353             */
10354             static_inline yyjson_mut_val *ptr_new_key(const char *token,
10355             usize len, usize esc,
10356             yyjson_mut_doc *doc) {
10357 10018           const char *src = token;
10358 10018           if (likely(!esc)) {
10359 10018           return yyjson_mut_strncpy(doc, src, len);
10360             } else {
10361 0           const char *end = src + len + esc;
10362 0 0         char *dst = unsafe_yyjson_mut_str_alc(doc, len + esc);
    0          
10363 0           char *str = dst;
10364 0 0         if (unlikely(!dst)) return NULL;
    0          
10365 0 0         for (; src < end; src++, dst++) {
    0          
10366 0 0         if (*src != '~') *dst = *src;
    0          
10367 0 0         else *dst = (*++src == '0' ? '~' : '/');
    0          
10368             }
10369 0 0         *dst = '\0';
    0          
10370 0           return yyjson_mut_strn(doc, str, len);
10371             }
10372             }
10373              
10374             /* macros for yyjson_ptr */
10375             #define return_err(_ret, _code, _pos, _msg) do { \
10376             if (err) { \
10377             err->code = YYJSON_PTR_ERR_##_code; \
10378             err->msg = _msg; \
10379             err->pos = (usize)(_pos); \
10380             } \
10381             return _ret; \
10382             } while (false)
10383              
10384             #define return_err_resolve(_ret, _pos) \
10385             return_err(_ret, RESOLVE, _pos, "JSON pointer cannot be resolved")
10386             #define return_err_syntax(_ret, _pos) \
10387             return_err(_ret, SYNTAX, _pos, "invalid escaped character")
10388             #define return_err_alloc(_ret) \
10389             return_err(_ret, MEMORY_ALLOCATION, 0, "failed to create value")
10390              
10391 0           yyjson_val *unsafe_yyjson_ptr_getx(yyjson_val *val,
10392             const char *ptr, size_t ptr_len,
10393             yyjson_ptr_err *err) {
10394              
10395 0           const char *hdr = ptr, *end = ptr + ptr_len, *token;
10396             usize len, esc;
10397             yyjson_type type;
10398              
10399             while (true) {
10400 0           token = ptr_next_token(&ptr, end, &len, &esc);
10401 0 0         if (unlikely(!token)) return_err_syntax(NULL, ptr - hdr);
    0          
10402 0           type = unsafe_yyjson_get_type(val);
10403 0 0         if (type == YYJSON_TYPE_OBJ) {
10404 0           val = ptr_obj_get(val, token, len, esc);
10405 0 0         } else if (type == YYJSON_TYPE_ARR) {
10406 0           val = ptr_arr_get(val, token, len, esc);
10407             } else {
10408 0           val = NULL;
10409             }
10410 0 0         if (!val) return_err_resolve(NULL, token - hdr);
    0          
10411 0 0         if (ptr == end) return val;
10412             }
10413             }
10414              
10415 5127           yyjson_mut_val *unsafe_yyjson_mut_ptr_getx(
10416             yyjson_mut_val *val, const char *ptr, size_t ptr_len,
10417             yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
10418              
10419 5127           const char *hdr = ptr, *end = ptr + ptr_len, *token;
10420             usize len, esc;
10421 5127           yyjson_mut_val *ctn, *pre = NULL;
10422             yyjson_type type;
10423 5127           bool idx_is_last = false;
10424              
10425             while (true) {
10426 123           token = ptr_next_token(&ptr, end, &len, &esc);
10427 5250 50         if (unlikely(!token)) return_err_syntax(NULL, ptr - hdr);
    0          
10428 5250           ctn = val;
10429 5250           type = unsafe_yyjson_get_type(val);
10430 5250 100         if (type == YYJSON_TYPE_OBJ) {
10431 10284           val = ptr_mut_obj_get(val, token, len, esc, &pre);
10432 108 50         } else if (type == YYJSON_TYPE_ARR) {
10433 216           val = ptr_mut_arr_get(val, token, len, esc, &pre, &idx_is_last);
10434             } else {
10435 0           val = NULL;
10436             }
10437 5250 100         if (ctx && (ptr == end)) {
    100          
10438 7 50         if (type == YYJSON_TYPE_OBJ ||
    0          
10439 0 0         (type == YYJSON_TYPE_ARR && (val || idx_is_last))) {
    0          
10440 7           ctx->ctn = ctn;
10441 7           ctx->pre = pre;
10442             }
10443             }
10444 5250 100         if (!val) return_err_resolve(NULL, token - hdr);
    100          
10445 5237 100         if (ptr == end) return val;
10446             }
10447             }
10448              
10449 10031           bool unsafe_yyjson_mut_ptr_putx(
10450             yyjson_mut_val *val, const char *ptr, size_t ptr_len,
10451             yyjson_mut_val *new_val, yyjson_mut_doc *doc, bool create_parent,
10452             bool insert_new, yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
10453              
10454 10031           const char *hdr = ptr, *end = ptr + ptr_len, *token;
10455             usize token_len, esc, ctn_len;
10456 10031           yyjson_mut_val *ctn, *key, *pre = NULL;
10457 10031           yyjson_mut_val *sep_ctn = NULL, *sep_key = NULL, *sep_val = NULL;
10458             yyjson_type ctn_type;
10459 10031           bool idx_is_last = false;
10460              
10461             /* skip exist parent nodes */
10462             while (true) {
10463 13           token = ptr_next_token(&ptr, end, &token_len, &esc);
10464 10044 50         if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
    0          
10465 10044           ctn = val;
10466 10044           ctn_type = unsafe_yyjson_get_type(ctn);
10467 10044 100         if (ctn_type == YYJSON_TYPE_OBJ) {
10468 20064           val = ptr_mut_obj_get(ctn, token, token_len, esc, &pre);
10469 12 50         } else if (ctn_type == YYJSON_TYPE_ARR) {
10470 24           val = ptr_mut_arr_get(ctn, token, token_len, esc, &pre,
10471             &idx_is_last);
10472 0 0         } else return_err_resolve(false, token - hdr);
10473 10044 100         if (!val) break;
10474 16 100         if (ptr == end) break; /* is last token */
10475             }
10476              
10477             /* create parent nodes if not exist */
10478 10031 50         if (unlikely(ptr != end)) { /* not last token */
10479 0 0         if (!create_parent) return_err_resolve(false, token - hdr);
    0          
10480              
10481             /* add value at last index if container is array */
10482 0 0         if (ctn_type == YYJSON_TYPE_ARR) {
10483 0 0         if (!idx_is_last || !insert_new) {
    0          
10484 0 0         return_err_resolve(false, token - hdr);
10485             }
10486 0           val = yyjson_mut_obj(doc);
10487 0 0         if (!val) return_err_alloc(false);
    0          
10488              
10489             /* delay attaching until all operations are completed */
10490 0           sep_ctn = ctn;
10491 0           sep_key = NULL;
10492 0           sep_val = val;
10493              
10494             /* move to next token */
10495 0           ctn = val;
10496 0           val = NULL;
10497 0           ctn_type = YYJSON_TYPE_OBJ;
10498 0           token = ptr_next_token(&ptr, end, &token_len, &esc);
10499 0 0         if (unlikely(!token)) return_err_resolve(false, token - hdr);
    0          
10500             }
10501              
10502             /* container is object, create parent nodes */
10503 0 0         while (ptr != end) { /* not last token */
10504 0 0         key = ptr_new_key(token, token_len, esc, doc);
10505 0 0         if (!key) return_err_alloc(false);
    0          
10506 0           val = yyjson_mut_obj(doc);
10507 0 0         if (!val) return_err_alloc(false);
    0          
10508              
10509             /* delay attaching until all operations are completed */
10510 0 0         if (!sep_ctn) {
10511 0           sep_ctn = ctn;
10512 0           sep_key = key;
10513 0           sep_val = val;
10514             } else {
10515             yyjson_mut_obj_add(ctn, key, val);
10516             }
10517              
10518             /* move to next token */
10519 0           ctn = val;
10520 0           val = NULL;
10521 0           token = ptr_next_token(&ptr, end, &token_len, &esc);
10522 0 0         if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
    0          
10523             }
10524             }
10525              
10526             /* JSON pointer is resolved, insert or replace target value */
10527 10031           ctn_len = unsafe_yyjson_get_len(ctn);
10528 10031 100         if (ctn_type == YYJSON_TYPE_OBJ) {
10529 10019 50         if (ctx) ctx->ctn = ctn;
10530 10019 100         if (!val || insert_new) {
    50          
10531             /* insert new key-value pair */
10532 10018 50         key = ptr_new_key(token, token_len, esc, doc);
10533 10018 50         if (unlikely(!key)) return_err_alloc(false);
    0          
10534 10018 50         if (ctx) ctx->pre = ctn_len ? (yyjson_mut_val *)ctn->uni.ptr : key;
    0          
10535 10018           unsafe_yyjson_mut_obj_add(ctn, key, new_val, ctn_len);
10536             } else {
10537             /* replace exist value */
10538 1           key = pre->next->next;
10539 1 50         if (ctx) ctx->pre = pre;
10540 1 50         if (ctx) ctx->old = val;
10541             yyjson_mut_obj_put(ctn, key, new_val);
10542             }
10543             } else {
10544             /* array */
10545 12 50         if (ctx && (val || idx_is_last)) ctx->ctn = ctn;
    0          
    0          
10546 12 100         if (insert_new) {
10547             /* append new value */
10548 5 50         if (val) {
10549 0           pre->next = new_val;
10550 0           new_val->next = val;
10551 0 0         if (ctx) ctx->pre = pre;
10552 0           unsafe_yyjson_set_len(ctn, ctn_len + 1);
10553 5 50         } else if (idx_is_last) {
10554 5 50         if (ctx) ctx->pre = ctn_len ?
10555 0 0         (yyjson_mut_val *)ctn->uni.ptr : new_val;
10556             yyjson_mut_arr_append(ctn, new_val);
10557             } else {
10558 0 0         return_err_resolve(false, token - hdr);
10559             }
10560             } else {
10561             /* replace exist value */
10562 7 100         if (!val) return_err_resolve(false, token - hdr);
    50          
10563 2 50         if (ctn_len > 1) {
10564 2           new_val->next = val->next;
10565 2           pre->next = new_val;
10566 2 50         if (ctn->uni.ptr == val) ctn->uni.ptr = new_val;
10567             } else {
10568 0           new_val->next = new_val;
10569 0           ctn->uni.ptr = new_val;
10570 0           pre = new_val;
10571             }
10572 2 50         if (ctx) ctx->pre = pre;
10573 2 50         if (ctx) ctx->old = val;
10574             }
10575             }
10576              
10577             /* all operations are completed, attach the new components to the target */
10578 10026 50         if (unlikely(sep_ctn)) {
10579 0 0         if (sep_key) yyjson_mut_obj_add(sep_ctn, sep_key, sep_val);
10580             else yyjson_mut_arr_append(sep_ctn, sep_val);
10581             }
10582 10026           return true;
10583             }
10584              
10585 1           yyjson_mut_val *unsafe_yyjson_mut_ptr_replacex(
10586             yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val,
10587             yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
10588              
10589             yyjson_mut_val *cur_val;
10590             yyjson_ptr_ctx cur_ctx;
10591 1           memset(&cur_ctx, 0, sizeof(cur_ctx));
10592 1 50         if (!ctx) ctx = &cur_ctx;
10593 1           cur_val = unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err);
10594 1 50         if (!cur_val) return NULL;
10595              
10596 2 50         if (yyjson_mut_is_obj(ctx->ctn)) {
    50          
10597 1           yyjson_mut_val *key = ctx->pre->next->next;
10598 1 50         yyjson_mut_obj_put(ctx->ctn, key, new_val);
10599             } else {
10600             yyjson_ptr_ctx_replace(ctx, new_val);
10601             }
10602 1           ctx->old = cur_val;
10603 1           return cur_val;
10604             }
10605              
10606 6           yyjson_mut_val *unsafe_yyjson_mut_ptr_removex(
10607             yyjson_mut_val *val, const char *ptr, size_t len,
10608             yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
10609              
10610             yyjson_mut_val *cur_val;
10611             yyjson_ptr_ctx cur_ctx;
10612 6           memset(&cur_ctx, 0, sizeof(cur_ctx));
10613 6 100         if (!ctx) ctx = &cur_ctx;
10614 6           cur_val = unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err);
10615 6 100         if (cur_val) {
10616 8 50         if (yyjson_mut_is_obj(ctx->ctn)) {
    50          
10617 4           yyjson_mut_val *key = ctx->pre->next->next;
10618 4 50         yyjson_mut_obj_put(ctx->ctn, key, NULL);
10619             } else {
10620             yyjson_ptr_ctx_remove(ctx);
10621             }
10622 4           ctx->pre = NULL;
10623 4           ctx->old = cur_val;
10624             }
10625 6           return cur_val;
10626             }
10627              
10628             /* macros for yyjson_ptr */
10629             #undef return_err
10630             #undef return_err_resolve
10631             #undef return_err_syntax
10632             #undef return_err_alloc
10633              
10634              
10635              
10636             /*==============================================================================
10637             * MARK: - JSON Patch API (RFC 6902) (Public)
10638             *============================================================================*/
10639              
10640             /* JSON Patch operation */
10641             typedef enum patch_op {
10642             PATCH_OP_ADD, /* path, value */
10643             PATCH_OP_REMOVE, /* path */
10644             PATCH_OP_REPLACE, /* path, value */
10645             PATCH_OP_MOVE, /* from, path */
10646             PATCH_OP_COPY, /* from, path */
10647             PATCH_OP_TEST, /* path, value */
10648             PATCH_OP_NONE /* invalid */
10649             } patch_op;
10650              
10651 7           static patch_op patch_op_get(yyjson_val *op) {
10652 7           const char *str = op->uni.str;
10653 7           switch (unsafe_yyjson_get_len(op)) {
10654 1           case 3:
10655 1 50         if (!memcmp(str, "add", 3)) return PATCH_OP_ADD;
10656 0           return PATCH_OP_NONE;
10657 4           case 4:
10658 4 100         if (!memcmp(str, "move", 4)) return PATCH_OP_MOVE;
10659 3 100         if (!memcmp(str, "copy", 4)) return PATCH_OP_COPY;
10660 2 50         if (!memcmp(str, "test", 4)) return PATCH_OP_TEST;
10661 0           return PATCH_OP_NONE;
10662 1           case 6:
10663 1 50         if (!memcmp(str, "remove", 6)) return PATCH_OP_REMOVE;
10664 0           return PATCH_OP_NONE;
10665 1           case 7:
10666 1 50         if (!memcmp(str, "replace", 7)) return PATCH_OP_REPLACE;
10667 0           return PATCH_OP_NONE;
10668 0           default:
10669 0           return PATCH_OP_NONE;
10670             }
10671             }
10672              
10673             /* macros for yyjson_patch */
10674             #define return_err(_code, _msg) do { \
10675             if (err->ptr.code == YYJSON_PTR_ERR_MEMORY_ALLOCATION) { \
10676             err->code = YYJSON_PATCH_ERROR_MEMORY_ALLOCATION; \
10677             err->msg = _msg; \
10678             memset(&err->ptr, 0, sizeof(yyjson_ptr_err)); \
10679             } else { \
10680             err->code = YYJSON_PATCH_ERROR_##_code; \
10681             err->msg = _msg; \
10682             err->idx = iter.idx ? iter.idx - 1 : 0; \
10683             } \
10684             return NULL; \
10685             } while (false)
10686              
10687             #define return_err_copy() \
10688             return_err(MEMORY_ALLOCATION, "failed to copy value")
10689             #define return_err_key(_key) \
10690             return_err(MISSING_KEY, "missing key " _key)
10691             #define return_err_val(_key) \
10692             return_err(INVALID_MEMBER, "invalid member " _key)
10693              
10694             #define ptr_get(_ptr) yyjson_mut_ptr_getx( \
10695             root, _ptr->uni.str, _ptr##_len, NULL, &err->ptr)
10696             #define ptr_add(_ptr, _val) yyjson_mut_ptr_addx( \
10697             root, _ptr->uni.str, _ptr##_len, _val, doc, false, NULL, &err->ptr)
10698             #define ptr_remove(_ptr) yyjson_mut_ptr_removex( \
10699             root, _ptr->uni.str, _ptr##_len, NULL, &err->ptr)
10700             #define ptr_replace(_ptr, _val)yyjson_mut_ptr_replacex( \
10701             root, _ptr->uni.str, _ptr##_len, _val, NULL, &err->ptr)
10702              
10703 0           yyjson_mut_val *yyjson_patch(yyjson_mut_doc *doc,
10704             yyjson_val *orig,
10705             yyjson_val *patch,
10706             yyjson_patch_err *err) {
10707              
10708             yyjson_mut_val *root;
10709             yyjson_val *obj;
10710             yyjson_arr_iter iter;
10711             yyjson_patch_err err_tmp;
10712 0 0         if (!err) err = &err_tmp;
10713 0           memset(err, 0, sizeof(*err));
10714 0           memset(&iter, 0, sizeof(iter));
10715              
10716 0 0         if (unlikely(!doc || !orig || !patch)) {
    0          
    0          
    0          
10717 0 0         return_err(INVALID_PARAMETER, "input parameter is NULL");
    0          
10718             }
10719 0 0         if (unlikely(!yyjson_is_arr(patch))) {
10720 0 0         return_err(INVALID_PARAMETER, "input patch is not array");
    0          
10721             }
10722 0           root = yyjson_val_mut_copy(doc, orig);
10723 0 0         if (unlikely(!root)) return_err_copy();
    0          
    0          
10724              
10725             /* iterate through the patch array */
10726             yyjson_arr_iter_init(patch, &iter);
10727 0 0         while ((obj = yyjson_arr_iter_next(&iter))) {
10728             patch_op op_enum;
10729 0           yyjson_val *op, *path, *from = NULL, *value;
10730 0           yyjson_mut_val *val = NULL, *test;
10731 0           usize path_len, from_len = 0;
10732 0 0         if (unlikely(!unsafe_yyjson_is_obj(obj))) {
10733 0 0         return_err(INVALID_OPERATION, "JSON patch operation is not object");
    0          
10734             }
10735              
10736             /* get required member: op */
10737 0           op = yyjson_obj_get(obj, "op");
10738 0 0         if (unlikely(!op)) return_err_key("`op`");
    0          
    0          
10739 0 0         if (unlikely(!yyjson_is_str(op))) return_err_val("`op`");
    0          
    0          
10740 0           op_enum = patch_op_get(op);
10741              
10742             /* get required member: path */
10743 0           path = yyjson_obj_get(obj, "path");
10744 0 0         if (unlikely(!path)) return_err_key("`path`");
    0          
    0          
10745 0 0         if (unlikely(!yyjson_is_str(path))) return_err_val("`path`");
    0          
    0          
10746 0           path_len = unsafe_yyjson_get_len(path);
10747              
10748             /* get required member: value, from */
10749 0           switch ((int)op_enum) {
10750 0 0         case PATCH_OP_ADD: case PATCH_OP_REPLACE: case PATCH_OP_TEST:
10751 0           value = yyjson_obj_get(obj, "value");
10752 0 0         if (unlikely(!value)) return_err_key("`value`");
    0          
    0          
10753 0           val = yyjson_val_mut_copy(doc, value);
10754 0 0         if (unlikely(!val)) return_err_copy();
    0          
    0          
10755 0           break;
10756 0 0         case PATCH_OP_MOVE: case PATCH_OP_COPY:
10757 0           from = yyjson_obj_get(obj, "from");
10758 0 0         if (unlikely(!from)) return_err_key("`from`");
    0          
    0          
10759 0 0         if (unlikely(!yyjson_is_str(from))) return_err_val("`from`");
    0          
    0          
10760 0           from_len = unsafe_yyjson_get_len(from);
10761 0           break;
10762 0           default:
10763 0           break;
10764             }
10765              
10766             /* perform an operation */
10767 0           switch ((int)op_enum) {
10768 0           case PATCH_OP_ADD: /* add(path, val) */
10769 0 0         if (unlikely(path_len == 0)) { root = val; break; }
10770 0 0         if (unlikely(!ptr_add(path, val))) {
    0          
10771 0 0         return_err(POINTER, "failed to add `path`");
    0          
10772             }
10773 0           break;
10774 0           case PATCH_OP_REMOVE: /* remove(path) */
10775 0 0         if (unlikely(!ptr_remove(path))) {
    0          
10776 0 0         return_err(POINTER, "failed to remove `path`");
    0          
10777             }
10778 0           break;
10779 0           case PATCH_OP_REPLACE: /* replace(path, val) */
10780 0 0         if (unlikely(path_len == 0)) { root = val; break; }
10781 0 0         if (unlikely(!ptr_replace(path, val))) {
    0          
10782 0 0         return_err(POINTER, "failed to replace `path`");
    0          
10783             }
10784 0           break;
10785 0           case PATCH_OP_MOVE: /* val = remove(from), add(path, val) */
10786 0 0         if (unlikely(from_len == 0 && path_len == 0)) break;
    0          
10787 0 0         val = ptr_remove(from);
10788 0 0         if (unlikely(!val)) {
10789 0 0         return_err(POINTER, "failed to remove `from`");
    0          
10790             }
10791 0 0         if (unlikely(path_len == 0)) { root = val; break; }
10792 0 0         if (unlikely(!ptr_add(path, val))) {
    0          
10793 0 0         return_err(POINTER, "failed to add `path`");
    0          
10794             }
10795 0           break;
10796 0           case PATCH_OP_COPY: /* val = get(from).copy, add(path, val) */
10797 0 0         val = ptr_get(from);
10798 0 0         if (unlikely(!val)) {
10799 0 0         return_err(POINTER, "failed to get `from`");
    0          
10800             }
10801 0 0         if (unlikely(path_len == 0)) { root = val; break; }
10802 0           val = yyjson_mut_val_mut_copy(doc, val);
10803 0 0         if (unlikely(!val)) return_err_copy();
    0          
    0          
10804 0 0         if (unlikely(!ptr_add(path, val))) {
    0          
10805 0 0         return_err(POINTER, "failed to add `path`");
    0          
10806             }
10807 0           break;
10808 0           case PATCH_OP_TEST: /* test = get(path), test.eq(val) */
10809 0 0         test = ptr_get(path);
10810 0 0         if (unlikely(!test)) {
10811 0 0         return_err(POINTER, "failed to get `path`");
    0          
10812             }
10813 0 0         if (unlikely(!yyjson_mut_equals(val, test))) {
10814 0 0         return_err(EQUAL, "failed to test equal");
    0          
10815             }
10816 0           break;
10817 0           default:
10818 0 0         return_err(INVALID_MEMBER, "unsupported `op`");
    0          
10819             }
10820             }
10821 0           return root;
10822             }
10823              
10824 5           yyjson_mut_val *yyjson_mut_patch(yyjson_mut_doc *doc,
10825             yyjson_mut_val *orig,
10826             yyjson_mut_val *patch,
10827             yyjson_patch_err *err) {
10828             yyjson_mut_val *root, *obj;
10829             yyjson_mut_arr_iter iter;
10830             yyjson_patch_err err_tmp;
10831 5 50         if (!err) err = &err_tmp;
10832 5           memset(err, 0, sizeof(*err));
10833 5           memset(&iter, 0, sizeof(iter));
10834              
10835 5 50         if (unlikely(!doc || !orig || !patch)) {
    50          
    50          
    50          
10836 0 0         return_err(INVALID_PARAMETER, "input parameter is NULL");
    0          
10837             }
10838 5 50         if (unlikely(!yyjson_mut_is_arr(patch))) {
10839 0 0         return_err(INVALID_PARAMETER, "input patch is not array");
    0          
10840             }
10841 5           root = yyjson_mut_val_mut_copy(doc, orig);
10842 5 50         if (unlikely(!root)) return_err_copy();
    0          
    0          
10843              
10844             /* iterate through the patch array */
10845             yyjson_mut_arr_iter_init(patch, &iter);
10846 16 100         while ((obj = yyjson_mut_arr_iter_next(&iter))) {
10847             patch_op op_enum;
10848 7           yyjson_mut_val *op, *path, *from = NULL, *value;
10849 7           yyjson_mut_val *val = NULL, *test;
10850 7           usize path_len, from_len = 0;
10851 7 50         if (!unsafe_yyjson_is_obj(obj)) {
10852 0 0         return_err(INVALID_OPERATION, "JSON patch operation is not object");
    0          
10853             }
10854              
10855             /* get required member: op */
10856 7           op = yyjson_mut_obj_get(obj, "op");
10857 7 50         if (unlikely(!op)) return_err_key("`op`");
    0          
    0          
10858 7 50         if (unlikely(!yyjson_mut_is_str(op))) return_err_val("`op`");
    0          
    0          
10859 7           op_enum = patch_op_get((yyjson_val *)(void *)op);
10860              
10861             /* get required member: path */
10862 7           path = yyjson_mut_obj_get(obj, "path");
10863 7 50         if (unlikely(!path)) return_err_key("`path`");
    0          
    0          
10864 7 50         if (unlikely(!yyjson_mut_is_str(path))) return_err_val("`path`");
    0          
    0          
10865 7           path_len = unsafe_yyjson_get_len(path);
10866              
10867             /* get required member: value, from */
10868 7           switch ((int)op_enum) {
10869 4 50         case PATCH_OP_ADD: case PATCH_OP_REPLACE: case PATCH_OP_TEST:
10870 4           value = yyjson_mut_obj_get(obj, "value");
10871 4 50         if (unlikely(!value)) return_err_key("`value`");
    0          
    0          
10872 4           val = yyjson_mut_val_mut_copy(doc, value);
10873 4 50         if (unlikely(!val)) return_err_copy();
    0          
    0          
10874 4           break;
10875 2 50         case PATCH_OP_MOVE: case PATCH_OP_COPY:
10876 2           from = yyjson_mut_obj_get(obj, "from");
10877 2 50         if (unlikely(!from)) return_err_key("`from`");
    0          
    0          
10878 2 50         if (unlikely(!yyjson_mut_is_str(from))) {
10879 0 0         return_err_val("`from`");
    0          
10880             }
10881 2           from_len = unsafe_yyjson_get_len(from);
10882 2           break;
10883 1           default:
10884 1           break;
10885             }
10886              
10887             /* perform an operation */
10888 7           switch ((int)op_enum) {
10889 1           case PATCH_OP_ADD: /* add(path, val) */
10890 1 50         if (unlikely(path_len == 0)) { root = val; break; }
10891 2 50         if (unlikely(!ptr_add(path, val))) {
    50          
10892 0 0         return_err(POINTER, "failed to add `path`");
    0          
10893             }
10894 1           break;
10895 1           case PATCH_OP_REMOVE: /* remove(path) */
10896 2 50         if (unlikely(!ptr_remove(path))) {
    50          
10897 0 0         return_err(POINTER, "failed to remove `path`");
    0          
10898             }
10899 1           break;
10900 1           case PATCH_OP_REPLACE: /* replace(path, val) */
10901 1 50         if (unlikely(path_len == 0)) { root = val; break; }
10902 2 50         if (unlikely(!ptr_replace(path, val))) {
    50          
10903 0 0         return_err(POINTER, "failed to replace `path`");
    0          
10904             }
10905 1           break;
10906 1           case PATCH_OP_MOVE: /* val = remove(from), add(path, val) */
10907 1 50         if (unlikely(from_len == 0 && path_len == 0)) break;
    0          
10908 1 50         val = ptr_remove(from);
10909 1 50         if (unlikely(!val)) {
10910 0 0         return_err(POINTER, "failed to remove `from`");
    0          
10911             }
10912 1 50         if (unlikely(path_len == 0)) { root = val; break; }
10913 2 50         if (unlikely(!ptr_add(path, val))) {
    50          
10914 0 0         return_err(POINTER, "failed to add `path`");
    0          
10915             }
10916 1           break;
10917 1           case PATCH_OP_COPY: /* val = get(from).copy, add(path, val) */
10918 1 50         val = ptr_get(from);
10919 1 50         if (unlikely(!val)) {
10920 0 0         return_err(POINTER, "failed to get `from`");
    0          
10921             }
10922 1 50         if (unlikely(path_len == 0)) { root = val; break; }
10923 1           val = yyjson_mut_val_mut_copy(doc, val);
10924 1 50         if (unlikely(!val)) return_err_copy();
    0          
    0          
10925 2 50         if (unlikely(!ptr_add(path, val))) {
    50          
10926 0 0         return_err(POINTER, "failed to add `path`");
    0          
10927             }
10928 1           break;
10929 2           case PATCH_OP_TEST: /* test = get(path), test.eq(val) */
10930 2 50         test = ptr_get(path);
10931 2 50         if (unlikely(!test)) {
10932 0 0         return_err(POINTER, "failed to get `path`");
    0          
10933             }
10934 2 100         if (unlikely(!yyjson_mut_equals(val, test))) {
10935 1 50         return_err(EQUAL, "failed to test equal");
    50          
10936             }
10937 1           break;
10938 0           default:
10939 0 0         return_err(INVALID_MEMBER, "unsupported `op`");
    0          
10940             }
10941             }
10942 4           return root;
10943             }
10944              
10945             /* macros for yyjson_patch */
10946             #undef return_err
10947             #undef return_err_copy
10948             #undef return_err_key
10949             #undef return_err_val
10950             #undef ptr_get
10951             #undef ptr_add
10952             #undef ptr_remove
10953             #undef ptr_replace
10954              
10955              
10956              
10957             /*==============================================================================
10958             * MARK: - JSON Merge-Patch API (RFC 7386) (Public)
10959             *============================================================================*/
10960              
10961 0 0         yyjson_mut_val *yyjson_merge_patch(yyjson_mut_doc *doc,
10962             yyjson_val *orig,
10963             yyjson_val *patch) {
10964             usize idx, max;
10965             yyjson_val *key, *orig_val, *patch_val, local_orig;
10966             yyjson_mut_val *builder, *mut_key, *mut_val, *merged_val;
10967              
10968 0 0         if (unlikely(!yyjson_is_obj(patch))) {
10969 0           return yyjson_val_mut_copy(doc, patch);
10970             }
10971              
10972 0           builder = yyjson_mut_obj(doc);
10973 0 0         if (unlikely(!builder)) return NULL;
10974              
10975 0 0         memset(&local_orig, 0, sizeof(local_orig));
10976 0 0         if (!yyjson_is_obj(orig)) {
10977 0           orig = &local_orig;
10978 0           orig->tag = builder->tag;
10979 0           orig->uni = builder->uni;
10980             }
10981              
10982             /* If orig is contributing, copy any items not modified by the patch */
10983 0 0         if (orig != &local_orig) {
10984 0 0         yyjson_obj_foreach(orig, idx, max, key, orig_val) {
    0          
    0          
10985 0 0         patch_val = yyjson_obj_getn(patch,
10986             unsafe_yyjson_get_str(key),
10987             unsafe_yyjson_get_len(key));
10988 0 0         if (!patch_val) {
10989 0           mut_key = yyjson_val_mut_copy(doc, key);
10990 0           mut_val = yyjson_val_mut_copy(doc, orig_val);
10991 0 0         if (!yyjson_mut_obj_add(builder, mut_key, mut_val)) return NULL;
10992             }
10993             }
10994             }
10995              
10996             /* Merge items modified by the patch. */
10997 0 0         yyjson_obj_foreach(patch, idx, max, key, patch_val) {
    0          
    0          
10998             /* null indicates the field is removed. */
10999 0 0         if (unsafe_yyjson_is_null(patch_val)) {
11000 0           continue;
11001             }
11002 0           mut_key = yyjson_val_mut_copy(doc, key);
11003 0 0         orig_val = yyjson_obj_getn(orig,
11004             unsafe_yyjson_get_str(key),
11005             unsafe_yyjson_get_len(key));
11006 0           merged_val = yyjson_merge_patch(doc, orig_val, patch_val);
11007 0 0         if (!yyjson_mut_obj_add(builder, mut_key, merged_val)) return NULL;
11008             }
11009              
11010 0           return builder;
11011             }
11012              
11013 5 50         yyjson_mut_val *yyjson_mut_merge_patch(yyjson_mut_doc *doc,
11014             yyjson_mut_val *orig,
11015             yyjson_mut_val *patch) {
11016             usize idx, max;
11017             yyjson_mut_val *key, *orig_val, *patch_val, local_orig;
11018             yyjson_mut_val *builder, *mut_key, *mut_val, *merged_val;
11019              
11020 5 100         if (unlikely(!yyjson_mut_is_obj(patch))) {
11021 3           return yyjson_mut_val_mut_copy(doc, patch);
11022             }
11023              
11024 2           builder = yyjson_mut_obj(doc);
11025 2 50         if (unlikely(!builder)) return NULL;
11026              
11027 2 50         memset(&local_orig, 0, sizeof(local_orig));
11028 2 50         if (!yyjson_mut_is_obj(orig)) {
11029 0           orig = &local_orig;
11030 0           orig->tag = builder->tag;
11031 0           orig->uni = builder->uni;
11032             }
11033              
11034             /* If orig is contributing, copy any items not modified by the patch */
11035 2 50         if (orig != &local_orig) {
11036 8 50         yyjson_mut_obj_foreach(orig, idx, max, key, orig_val) {
    50          
    50          
    100          
11037 8 50         patch_val = yyjson_mut_obj_getn(patch,
11038             unsafe_yyjson_get_str(key),
11039             unsafe_yyjson_get_len(key));
11040 4 100         if (!patch_val) {
11041 1           mut_key = yyjson_mut_val_mut_copy(doc, key);
11042 1           mut_val = yyjson_mut_val_mut_copy(doc, orig_val);
11043 1 50         if (!yyjson_mut_obj_add(builder, mut_key, mut_val)) return NULL;
11044             }
11045             }
11046             }
11047              
11048             /* Merge items modified by the patch. */
11049 9 50         yyjson_mut_obj_foreach(patch, idx, max, key, patch_val) {
    50          
    50          
    100          
11050             /* null indicates the field is removed. */
11051 5 100         if (unsafe_yyjson_is_null(patch_val)) {
11052 1           continue;
11053             }
11054 4           mut_key = yyjson_mut_val_mut_copy(doc, key);
11055 8 50         orig_val = yyjson_mut_obj_getn(orig,
11056             unsafe_yyjson_get_str(key),
11057             unsafe_yyjson_get_len(key));
11058 4           merged_val = yyjson_mut_merge_patch(doc, orig_val, patch_val);
11059 4 50         if (!yyjson_mut_obj_add(builder, mut_key, merged_val)) return NULL;
11060             }
11061              
11062 2           return builder;
11063             }
11064              
11065             #endif /* YYJSON_DISABLE_UTILS */