ohmu
·
2026-10-15
1/*==============================================================================
2 Copyright (c) 2020 YaoYuan <ibireme@gmail.com>
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21 *============================================================================*/
22
23#include "yyjson.h"
24
25
26
27/*==============================================================================
28 * MARK: - Warning Suppress (Private)
29 *============================================================================*/
30
31#if defined(__clang__)
32# pragma clang diagnostic ignored "-Wunused-function"
33# pragma clang diagnostic ignored "-Wunused-parameter"
34# pragma clang diagnostic ignored "-Wunused-label"
35# pragma clang diagnostic ignored "-Wunused-macros"
36# pragma clang diagnostic ignored "-Wunused-variable"
37#elif YYJSON_IS_REAL_GCC && yyjson_gcc_available(4, 2, 0)
38# pragma GCC diagnostic ignored "-Wunused-function"
39# pragma GCC diagnostic ignored "-Wunused-parameter"
40# pragma GCC diagnostic ignored "-Wunused-label"
41# pragma GCC diagnostic ignored "-Wunused-macros"
42# pragma GCC diagnostic ignored "-Wunused-variable"
43#elif defined(_MSC_VER)
44# pragma warning(disable:4100) /* unreferenced formal parameter */
45# pragma warning(disable:4101) /* unreferenced variable */
46# pragma warning(disable:4102) /* unreferenced label */
47# pragma warning(disable:4127) /* conditional expression is constant */
48# pragma warning(disable:4702) /* unreachable code */
49# pragma warning(disable:4706) /* assignment within conditional expression */
50#endif
51
52
53
54/*==============================================================================
55 * MARK: - Version (Public)
56 *============================================================================*/
57
58uint32_t yyjson_version(void) {
59 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 <intrin.h>
71# if defined(_M_AMD64) || defined(_M_ARM64)
72# define MSC_HAS_BIT_SCAN_64 1
73# pragma intrinsic(_BitScanForward64)
74# pragma intrinsic(_BitScanReverse64)
75# else
76# define MSC_HAS_BIT_SCAN_64 0
77# endif
78# if defined(_M_AMD64) || defined(_M_ARM64) || \
79 defined(_M_IX86) || defined(_M_ARM)
80# define MSC_HAS_BIT_SCAN 1
81# pragma intrinsic(_BitScanForward)
82# pragma intrinsic(_BitScanReverse)
83# else
84# define MSC_HAS_BIT_SCAN 0
85# endif
86# if defined(_M_AMD64)
87# define MSC_HAS_UMUL128 1
88# pragma intrinsic(_umul128)
89# else
90# define MSC_HAS_UMUL128 0
91# endif
92#else
93# define MSC_HAS_BIT_SCAN_64 0
94# define MSC_HAS_BIT_SCAN 0
95# define MSC_HAS_UMUL128 0
96#endif
97
98/* gcc builtin */
99#if yyjson_has_builtin(__builtin_clzll) || yyjson_gcc_available(3, 4, 0)
100# define GCC_HAS_CLZLL 1
101#else
102# define GCC_HAS_CLZLL 0
103#endif
104
105#if yyjson_has_builtin(__builtin_ctzll) || yyjson_gcc_available(3, 4, 0)
106# define GCC_HAS_CTZLL 1
107#else
108# define GCC_HAS_CTZLL 0
109#endif
110
111/* int128 type */
112#ifndef YYJSON_HAS_INT128
113# if defined(__SIZEOF_INT128__) && (__SIZEOF_INT128__ == 16) && \
114 (defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER)) && \
115 (!defined(__EMSCRIPTEN__) && !defined(__wasm__))
116# define YYJSON_HAS_INT128 1
117# else
118# define YYJSON_HAS_INT128 0
119# endif
120#endif
121
122/* IEEE 754 floating-point binary representation */
123#ifndef YYJSON_HAS_IEEE_754
124# if defined(__STDC_IEC_559__) || defined(__STDC_IEC_60559_BFP__)
125# define YYJSON_HAS_IEEE_754 1
126# elif FLT_RADIX == 2 && \
127 FLT_MANT_DIG == 24 && FLT_DIG == 6 && \
128 FLT_MIN_EXP == -125 && FLT_MAX_EXP == 128 && \
129 FLT_MIN_10_EXP == -37 && FLT_MAX_10_EXP == 38 && \
130 DBL_MANT_DIG == 53 && DBL_DIG == 15 && \
131 DBL_MIN_EXP == -1021 && DBL_MAX_EXP == 1024 && \
132 DBL_MIN_10_EXP == -307 && DBL_MAX_10_EXP == 308
133# define YYJSON_HAS_IEEE_754 1
134# else
135# define YYJSON_HAS_IEEE_754 0
136# undef YYJSON_DISABLE_FAST_FP_CONV
137# define YYJSON_DISABLE_FAST_FP_CONV 1
138# endif
139#endif
140
141#if YYJSON_DISABLE_FAST_FP_CONV && YYJSON_FREESTANDING
142# error DISABLE_FAST_FP_CONV and FREESTANDING cannot be used together
143#endif
144
145/* Inf and NaN */
146#ifndef INFINITY
147# ifndef HUGE_VAL
148# define INFINITY ((double)(1.0 / 0.0))
149# else
150# define INFINITY HUGE_VAL
151# endif
152#endif
153#ifndef NAN
154# define NAN ((double)(0.0 / 0.0))
155#endif
156
157/*
158 Correct rounding in double number computations.
159
160 On the x86 architecture, some compilers may use x87 FPU instructions for
161 floating-point arithmetic. The x87 FPU loads all floating-point numbers as
162 80-bit double-extended precision internally, then rounds the result to the
163 original precision, which may produce inaccurate results. For a more detailed
164 explanation, see the paper: https://arxiv.org/abs/cs/0701192
165
166 Here are some examples of double precision calculation error:
167
168 2877.0 / 1e6 == 0.002877, but x87 returns 0.0028770000000000002
169 43683.0 * 1e21 == 4.3683e25, but x87 returns 4.3683000000000004e25
170
171 Here are some examples of compiler flags to generate x87 instructions on x86:
172
173 clang -m32 -mno-sse
174 gcc/icc -m32 -mfpmath=387
175 msvc /arch:SSE or /arch:IA32
176
177 If we are sure that there's no similar error described above, we can define the
178 YYJSON_DOUBLE_MATH_CORRECT as 1 to enable the fast path calculation. This is
179 not an accurate detection; it just tries to avoid the error at compile-time.
180 An accurate detection can be done at run-time:
181
182 bool is_double_math_correct(void) {
183 volatile double r = 43683.0;
184 r *= 1e21;
185 return r == 4.3683e25;
186 }
187
188 See also: utils.h in https://github.com/google/double-conversion/
189 */
190#if !defined(FLT_EVAL_METHOD) && defined(__FLT_EVAL_METHOD__)
191# define FLT_EVAL_METHOD __FLT_EVAL_METHOD__
192#endif
193
194#if defined(FLT_EVAL_METHOD) && FLT_EVAL_METHOD != 0 && FLT_EVAL_METHOD != 1
195# define YYJSON_DOUBLE_MATH_CORRECT 0
196#elif defined(i386) || defined(__i386) || defined(__i386__) || \
197 defined(_X86_) || defined(__X86__) || defined(_M_IX86) || \
198 defined(__I86__) || defined(__IA32__) || defined(__THW_INTEL)
199# if (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP == 2) || \
200 (defined(__SSE2_MATH__) && __SSE2_MATH__)
201# define YYJSON_DOUBLE_MATH_CORRECT 1
202# else
203# define YYJSON_DOUBLE_MATH_CORRECT 0
204# endif
205#elif defined(__mc68000__) || defined(__pnacl__) || defined(__native_client__)
206# define YYJSON_DOUBLE_MATH_CORRECT 0
207#else
208# define YYJSON_DOUBLE_MATH_CORRECT 1
209#endif
210
211/*
212 Detect the endianness at compile-time.
213 YYJSON_ENDIAN == YYJSON_BIG_ENDIAN
214 YYJSON_ENDIAN == YYJSON_LITTLE_ENDIAN
215 */
216#define YYJSON_BIG_ENDIAN 4321
217#define YYJSON_LITTLE_ENDIAN 1234
218
219#if yyjson_has_include(<sys/types.h>)
220# include <sys/types.h> /* POSIX */
221#endif
222#if yyjson_has_include(<endian.h>)
223# include <endian.h> /* Linux */
224#elif yyjson_has_include(<sys/endian.h>)
225# include <sys/endian.h> /* BSD, Android */
226#elif yyjson_has_include(<machine/endian.h>)
227# include <machine/endian.h> /* BSD, Darwin */
228#endif
229
230#if defined(BYTE_ORDER) && BYTE_ORDER
231# if defined(BIG_ENDIAN) && (BYTE_ORDER == BIG_ENDIAN)
232# define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
233# elif defined(LITTLE_ENDIAN) && (BYTE_ORDER == LITTLE_ENDIAN)
234# define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
235# endif
236#elif defined(__BYTE_ORDER) && __BYTE_ORDER
237# if defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN)
238# define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
239# elif defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN)
240# define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
241# endif
242#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__
243# if defined(__ORDER_BIG_ENDIAN__) && \
244 (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
245# define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
246# elif defined(__ORDER_LITTLE_ENDIAN__) && \
247 (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
248# define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
249# endif
250#elif (defined(__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__ == 1) || \
251 defined(__i386) || defined(__i386__) || \
252 defined(_X86_) || defined(__X86__) || \
253 defined(_M_IX86) || defined(__THW_INTEL__) || \
254 defined(__x86_64) || defined(__x86_64__) || \
255 defined(__amd64) || defined(__amd64__) || \
256 defined(_M_AMD64) || defined(_M_X64) || \
257 defined(_M_ARM) || defined(_M_ARM64) || \
258 defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \
259 defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || \
260 defined(__EMSCRIPTEN__) || defined(__wasm__) || \
261 defined(__loongarch__)
262# define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
263#elif (defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ == 1) || \
264 defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \
265 defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) || \
266 defined(__or1k__) || defined(__OR1K__)
267# define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
268#else
269# define YYJSON_ENDIAN 0 /* unknown endian, detect at run-time */
270#endif
271
272/*
273 This macro controls how yyjson handles unaligned memory accesses.
274
275 By default, yyjson uses `memcpy()` for memory copying. This allows the compiler
276 to optimize the code and emit unaligned memory access instructions when
277 supported by the target architecture.
278
279 However, on some older compilers or architectures where `memcpy()` is not
280 well-optimized and may result in unnecessary function calls, defining this
281 macro as 1 may help. In such cases, yyjson switches to manual byte-by-byte
282 access, which can potentially improve performance.
283
284 An example of the generated assembly code for ARM can be found here:
285 https://godbolt.org/z/334jjhxPT
286
287 This flag is already enabled for common architectures in the following code,
288 so manual configuration is usually unnecessary. If unsure, you can check the
289 generated assembly or run benchmarks to make an informed decision.
290 */
291#ifndef YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
292# if defined(__ia64) || defined(_IA64) || defined(__IA64__) || \
293 defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
294# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* Itanium */
295# elif (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) && \
296 (defined(__GNUC__) || defined(__clang__)) && \
297 (!defined(__ARM_FEATURE_UNALIGNED) || !__ARM_FEATURE_UNALIGNED)
298# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* ARM */
299# elif defined(__sparc) || defined(__sparc__)
300# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* SPARC */
301# elif defined(__mips) || defined(__mips__) || defined(__MIPS__)
302# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* MIPS */
303# elif defined(__m68k__) || defined(M68000)
304# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* M68K */
305# else
306# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 0
307# endif
308#endif
309
310/*
311 Estimated initial ratio of the JSON data (data_size / value_count).
312 For example:
313
314 data: {"id":12345678,"name":"Harry"}
315 data_size: 30
316 value_count: 5
317 ratio: 6
318
319 yyjson uses dynamic memory with a growth factor of 1.5 when reading and writing
320 JSON, the ratios below are used to determine the initial memory size.
321
322 A too large ratio will waste memory, and a too small ratio will cause multiple
323 memory growths and degrade performance. Currently, these ratios are generated
324 with some commonly used JSON datasets.
325 */
326#define YYJSON_READER_ESTIMATED_PRETTY_RATIO 16
327#define YYJSON_READER_ESTIMATED_MINIFY_RATIO 6
328#define YYJSON_WRITER_ESTIMATED_PRETTY_RATIO 32
329#define YYJSON_WRITER_ESTIMATED_MINIFY_RATIO 18
330
331/* The initial and maximum size of the memory pool's chunk in yyjson_mut_doc. */
332#define YYJSON_MUT_DOC_STR_POOL_INIT_SIZE 0x100
333#define YYJSON_MUT_DOC_STR_POOL_MAX_SIZE 0x10000000
334#define YYJSON_MUT_DOC_VAL_POOL_INIT_SIZE (0x10 * sizeof(yyjson_mut_val))
335#define YYJSON_MUT_DOC_VAL_POOL_MAX_SIZE (0x1000000 * sizeof(yyjson_mut_val))
336
337/* The minimum size of the dynamic allocator's chunk. */
338#define YYJSON_ALC_DYN_MIN_SIZE 0x1000
339
340/* Default value for compile-time options. */
341
342#ifndef YYJSON_READER_DEPTH_LIMIT
343#define YYJSON_READER_DEPTH_LIMIT 0
344#endif
345
346#ifndef YYJSON_WRITER_DEPTH_LIMIT
347#define YYJSON_WRITER_DEPTH_LIMIT 0
348#endif
349
350/*==============================================================================
351 * MARK: - Macros (Private)
352 *============================================================================*/
353
354/* Macros used for loop unrolling and other purposes. */
355#define repeat2(x) { x x }
356#define repeat4(x) { x x x x }
357#define repeat8(x) { x x x x x x x x }
358#define repeat16(x) { x x x x x x x x x x x x x x x x }
359
360#define repeat2_incr(x) { x(0) x(1) }
361#define repeat4_incr(x) { x(0) x(1) x(2) x(3) }
362#define repeat8_incr(x) { x(0) x(1) x(2) x(3) x(4) x(5) x(6) x(7) }
363#define repeat16_incr(x) { x(0) x(1) x(2) x(3) x(4) x(5) x(6) x(7) \
364 x(8) x(9) x(10) x(11) x(12) x(13) x(14) x(15) }
365#define repeat_in_1_18(x) { x(1) x(2) x(3) x(4) x(5) x(6) x(7) x(8) \
366 x(9) x(10) x(11) x(12) x(13) x(14) x(15) x(16) \
367 x(17) x(18) }
368
369/* Macros used to provide branch prediction information for compiler. */
370#undef likely
371#define likely(x) yyjson_likely(x)
372#undef unlikely
373#define unlikely(x) yyjson_unlikely(x)
374
375/* Macros used to provide inline information for compiler. */
376#undef static_inline
377#define static_inline static yyjson_inline
378#undef static_noinline
379#define static_noinline static yyjson_noinline
380
381/* Macros for min and max. */
382#undef yyjson_min
383#define yyjson_min(x, y) ((x) < (y) ? (x) : (y))
384#undef yyjson_max
385#define yyjson_max(x, y) ((x) > (y) ? (x) : (y))
386
387/* Used to write u64 literal for C89 which doesn't support "ULL" suffix. */
388#undef U64
389#define U64(hi, lo) ((((u64)hi##UL) << 32U) + lo##UL)
390#undef U32
391#define U32(hi) ((u32)(hi##UL))
392
393/* Used to cast away (remove) const qualifier. */
394#define constcast yyjson_constcast
395
396/*
397 Compiler barriers for single variables.
398
399 These macros inform GCC that a read or write access to the given memory
400 location will occur, preventing certain compiler optimizations or reordering
401 around the access to 'val'. They do not emit any actual instructions.
402
403 This is useful when GCC's default optimization strategies are suboptimal and
404 precise control over memory access patterns is required.
405 These barriers are not needed when using Clang or MSVC.
406 */
407#if YYJSON_IS_REAL_GCC
408# define gcc_load_barrier(val) __asm__ volatile(""::"m"(val))
409# define gcc_store_barrier(val) __asm__ volatile("":"=m"(val))
410# define gcc_full_barrier(val) __asm__ volatile("":"=m"(val):"m"(val))
411#else
412# define gcc_load_barrier(val)
413# define gcc_store_barrier(val)
414# define gcc_full_barrier(val)
415#endif
416
417
418
419/*==============================================================================
420 * MARK: - Constants (Private)
421 *============================================================================*/
422
423/* Common error messages. */
424#define MSG_FOPEN "failed to open file"
425#define MSG_FREAD "failed to read file"
426#define MSG_FWRITE "failed to write file"
427#define MSG_FCLOSE "failed to close file"
428#define MSG_MALLOC "failed to allocate memory"
429#define MSG_CHAR_T "invalid literal, expected 'true'"
430#define MSG_CHAR_F "invalid literal, expected 'false'"
431#define MSG_CHAR_N "invalid literal, expected 'null'"
432#define MSG_CHAR "unexpected character, expected a JSON value"
433#define MSG_ARR_END "unexpected character, expected ',' or ']'"
434#define MSG_OBJ_KEY "unexpected character, expected a string key"
435#define MSG_OBJ_SEP "unexpected character, expected ':' after key"
436#define MSG_OBJ_END "unexpected character, expected ',' or '}'"
437#define MSG_GARBAGE "unexpected content after document"
438#define MSG_NOT_END "unexpected end of data"
439#define MSG_COMMENT "unclosed multiline comment"
440#define MSG_COMMA "trailing comma is not allowed"
441#define MSG_NAN_INF "nan or inf number is not allowed"
442#define MSG_ERR_TYPE "invalid JSON value type"
443#define MSG_ERR_BOM "UTF-8 byte order mark (BOM) is not supported"
444#define MSG_ERR_UTF8 "invalid utf-8 encoding in string"
445#define MSG_ERR_UTF16 "UTF-16 encoding is not supported"
446#define MSG_ERR_UTF32 "UTF-32 encoding is not supported"
447#define MSG_DEPTH "depth limit exceeded"
448
449/* U64 constant values */
450#undef U64_MAX
451#define U64_MAX U64(0xFFFFFFFF, 0xFFFFFFFF)
452#undef I64_MAX
453#define I64_MAX U64(0x7FFFFFFF, 0xFFFFFFFF)
454#undef USIZE_MAX
455#define USIZE_MAX ((usize)(~(usize)0))
456
457/* Maximum number of digits for reading u32/u64/usize safety (not overflow). */
458#undef U32_SAFE_DIG
459#define U32_SAFE_DIG 9 /* u32 max is 4294967295, 10 digits */
460#undef U64_SAFE_DIG
461#define U64_SAFE_DIG 19 /* u64 max is 18446744073709551615, 20 digits */
462#undef USIZE_SAFE_DIG
463#define USIZE_SAFE_DIG (sizeof(usize) == 8 ? U64_SAFE_DIG : U32_SAFE_DIG)
464
465/* Inf bits (positive) */
466#define F64_BITS_INF U64(0x7FF00000, 0x00000000)
467
468/* NaN bits (quiet NaN, no payload, no sign) */
469#if defined(__hppa__) || (defined(__mips__) && !defined(__mips_nan2008))
470#define F64_BITS_NAN U64(0x7FF7FFFF, 0xFFFFFFFF)
471#else
472#define F64_BITS_NAN U64(0x7FF80000, 0x00000000)
473#endif
474
475/* maximum significant digits count in decimal when reading double number */
476#define F64_MAX_DEC_DIG 768
477
478/* maximum decimal power of double number (1.7976931348623157e308) */
479#define F64_MAX_DEC_EXP 308
480
481/* minimum decimal power of double number (4.9406564584124654e-324) */
482#define F64_MIN_DEC_EXP (-324)
483
484/* maximum binary power of double number */
485#define F64_MAX_BIN_EXP 1024
486
487/* minimum binary power of double number */
488#define F64_MIN_BIN_EXP (-1021)
489
490/* float/double number bits */
491#define F32_BITS 32
492#define F64_BITS 64
493
494/* float/double number exponent part bits */
495#define F32_EXP_BITS 8
496#define F64_EXP_BITS 11
497
498/* float/double number significand part bits */
499#define F32_SIG_BITS 23
500#define F64_SIG_BITS 52
501
502/* float/double number significand part bits (with 1 hidden bit) */
503#define F32_SIG_FULL_BITS 24
504#define F64_SIG_FULL_BITS 53
505
506/* float/double number significand bit mask */
507#define F32_SIG_MASK U32(0x007FFFFF)
508#define F64_SIG_MASK U64(0x000FFFFF, 0xFFFFFFFF)
509
510/* float/double number exponent bit mask */
511#define F32_EXP_MASK U32(0x7F800000)
512#define F64_EXP_MASK U64(0x7FF00000, 0x00000000)
513
514/* float/double number exponent bias */
515#define F32_EXP_BIAS 127
516#define F64_EXP_BIAS 1023
517
518/* float/double number significant digits count in decimal */
519#define F32_DEC_DIG 9
520#define F64_DEC_DIG 17
521
522/* buffer length required for float/double number writer */
523#define FP_BUF_LEN 40
524
525/* maximum length of a number in incremental parsing */
526#define INCR_NUM_MAX_LEN 1024
527
528
529
530/*==============================================================================
531 * MARK: - Types (Private)
532 *============================================================================*/
533
534/** Type aliases for primitive types. */
535typedef float f32;
536typedef double f64;
537typedef int8_t i8;
538typedef uint8_t u8;
539typedef int16_t i16;
540typedef uint16_t u16;
541typedef int32_t i32;
542typedef uint32_t u32;
543typedef int64_t i64;
544typedef uint64_t u64;
545typedef size_t usize;
546
547/** 128-bit integer, used by floating-point number reader and writer. */
548#if YYJSON_HAS_INT128
549__extension__ typedef __int128 i128;
550__extension__ typedef unsigned __int128 u128;
551#endif
552
553/** 16/32/64-bit vector */
554typedef struct v16 { char c[2]; } v16;
555typedef struct v32 { char c[4]; } v32;
556typedef struct v64 { char c[8]; } v64;
557
558/** 16/32/64-bit vector union */
559typedef union v16_uni { v16 v; u16 u; } v16_uni;
560typedef union v32_uni { v32 v; u32 u; } v32_uni;
561typedef union v64_uni { v64 v; u64 u; } v64_uni;
562
563
564
565/*==============================================================================
566 * MARK: - Load/Store Utils (Private)
567 *============================================================================*/
568
569#define byte_move_idx(x) ((char *)dst)[x] = ((const char *)src)[x];
570#define byte_move_src(x) ((char *)tmp)[x] = ((const char *)src)[x];
571#define byte_move_dst(x) ((char *)dst)[x] = ((const char *)tmp)[x];
572
573/** Same as `memcpy(dst, src, 2)`, no overlap. */
574static_inline void byte_copy_2(void *dst, const void *src) {
575#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
576 memcpy(dst, src, 2);
577#else
578 repeat2_incr(byte_move_idx)
579#endif
580}
581
582/** Same as `memcpy(dst, src, 4)`, no overlap. */
583static_inline void byte_copy_4(void *dst, const void *src) {
584#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
585 memcpy(dst, src, 4);
586#else
587 repeat4_incr(byte_move_idx)
588#endif
589}
590
591/** Same as `memcpy(dst, src, 8)`, no overlap. */
592static_inline void byte_copy_8(void *dst, const void *src) {
593#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
594 memcpy(dst, src, 8);
595#else
596 repeat8_incr(byte_move_idx)
597#endif
598}
599
600/** Same as `memcpy(dst, src, 16)`, no overlap. */
601static_inline void byte_copy_16(void *dst, const void *src) {
602#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
603 memcpy(dst, src, 16);
604#else
605 repeat16_incr(byte_move_idx)
606#endif
607}
608
609/** Same as `memmove(dst, src, 2)`, allows overlap. */
610static_inline void byte_move_2(void *dst, const void *src) {
611#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
612 u16 tmp;
613 memcpy(&tmp, src, 2);
614 memcpy(dst, &tmp, 2);
615#else
616 char tmp[2];
617 repeat2_incr(byte_move_src)
618 repeat2_incr(byte_move_dst)
619#endif
620}
621
622/** Same as `memmove(dst, src, 4)`, allows overlap. */
623static_inline void byte_move_4(void *dst, const void *src) {
624#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
625 u32 tmp;
626 memcpy(&tmp, src, 4);
627 memcpy(dst, &tmp, 4);
628#else
629 char tmp[4];
630 repeat4_incr(byte_move_src)
631 repeat4_incr(byte_move_dst)
632#endif
633}
634
635/** Same as `memmove(dst, src, 8)`, allows overlap. */
636static_inline void byte_move_8(void *dst, const void *src) {
637#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
638 u64 tmp;
639 memcpy(&tmp, src, 8);
640 memcpy(dst, &tmp, 8);
641#else
642 char tmp[8];
643 repeat8_incr(byte_move_src)
644 repeat8_incr(byte_move_dst)
645#endif
646}
647
648/** Same as `memmove(dst, src, 16)`, allows overlap. */
649static_inline void byte_move_16(void *dst, const void *src) {
650#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
651 char *pdst = (char *)dst;
652 const char *psrc = (const char *)src;
653 u64 tmp1, tmp2;
654 memcpy(&tmp1, psrc, 8);
655 memcpy(&tmp2, psrc + 8, 8);
656 memcpy(pdst, &tmp1, 8);
657 memcpy(pdst + 8, &tmp2, 8);
658#else
659 char tmp[16];
660 repeat16_incr(byte_move_src)
661 repeat16_incr(byte_move_dst)
662#endif
663}
664
665/** Same as `memmove(dst, src, n)`, but only `dst <= src` and `n <= 16`. */
666static_inline void byte_move_forward(void *dst, void *src, usize n) {
667 char *d = (char *)dst, *s = (char *)src;
668 n += (n % 2); /* round up to even */
669 if (n == 16) { byte_move_16(d, s); return; }
670 if (n >= 8) { byte_move_8(d, s); n -= 8; d += 8; s += 8; }
671 if (n >= 4) { byte_move_4(d, s); n -= 4; d += 4; s += 4; }
672 if (n >= 2) { byte_move_2(d, s); }
673}
674
675/** Same as `memcmp(buf, pat, 2) == 0`. */
676static_inline bool byte_match_2(void *buf, const char *pat) {
677#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
678 v16_uni u1, u2;
679 memcpy(&u1, buf, 2);
680 memcpy(&u2, pat, 2);
681 return u1.u == u2.u;
682#else
683 return ((char *)buf)[0] == ((const char *)pat)[0] &&
684 ((char *)buf)[1] == ((const char *)pat)[1];
685#endif
686}
687
688/** Same as `memcmp(buf, pat, 4) == 0`. */
689static_inline bool byte_match_4(void *buf, const char *pat) {
690#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
691 v32_uni u1, u2;
692 memcpy(&u1, buf, 4);
693 memcpy(&u2, pat, 4);
694 return u1.u == u2.u;
695#else
696 return ((char *)buf)[0] == ((const char *)pat)[0] &&
697 ((char *)buf)[1] == ((const char *)pat)[1] &&
698 ((char *)buf)[2] == ((const char *)pat)[2] &&
699 ((char *)buf)[3] == ((const char *)pat)[3];
700#endif
701}
702
703/** Loads 2 bytes from `src` as a u16 (native-endian). */
704static_inline u16 byte_load_2(const void *src) {
705 v16_uni uni;
706#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
707 memcpy(&uni, src, 2);
708#else
709 uni.v.c[0] = ((const char *)src)[0];
710 uni.v.c[1] = ((const char *)src)[1];
711#endif
712 return uni.u;
713}
714
715/** Loads 3 bytes from `src` as a u32 (native-endian). */
716static_inline u32 byte_load_3(const void *src) {
717 v32_uni uni;
718#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
719 memcpy(&uni, src, 2);
720 uni.v.c[2] = ((const char *)src)[2];
721 uni.v.c[3] = 0;
722#else
723 uni.v.c[0] = ((const char *)src)[0];
724 uni.v.c[1] = ((const char *)src)[1];
725 uni.v.c[2] = ((const char *)src)[2];
726 uni.v.c[3] = 0;
727#endif
728 return uni.u;
729}
730
731/** Loads 4 bytes from `src` as a u32 (native-endian). */
732static_inline u32 byte_load_4(const void *src) {
733 v32_uni uni;
734#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
735 memcpy(&uni, src, 4);
736#else
737 uni.v.c[0] = ((const char *)src)[0];
738 uni.v.c[1] = ((const char *)src)[1];
739 uni.v.c[2] = ((const char *)src)[2];
740 uni.v.c[3] = ((const char *)src)[3];
741#endif
742 return uni.u;
743}
744
745
746
747/*==============================================================================
748 * MARK: - Character Utils (Private)
749 * These lookup tables were generated by `misc/make_tables.c`.
750 *============================================================================*/
751
752/* char_table1 */
753#define CHAR_TYPE_ASCII (1 << 0) /* Except: ["\], [0x00-0x1F, 0x80-0xFF] */
754#define CHAR_TYPE_ASCII_SQ (1 << 1) /* Except: ['\], [0x00-0x1F, 0x80-0xFF] */
755#define CHAR_TYPE_SPACE (1 << 2) /* Whitespace: [ \t\n\r] */
756#define CHAR_TYPE_SPACE_EXT (1 << 3) /* Whitespace: [ \t\n\r\v\f], JSON5 */
757#define CHAR_TYPE_NUM (1 << 4) /* Number: [.-+0-9] */
758#define CHAR_TYPE_COMMENT (1 << 5) /* Comment: [/] */
759
760/* char_table2 */
761#define CHAR_TYPE_EOL (1 << 0) /* End of line: [\r\n] */
762#define CHAR_TYPE_EOL_EXT (1 << 1) /* End of line: [\r\n], JSON5 */
763#define CHAR_TYPE_ID_START (1 << 2) /* ID start: [_$A-Za-z\], U+0080+ */
764#define CHAR_TYPE_ID_NEXT (1 << 3) /* ID next: [_$A-Za-z0-9\], U+0080+ */
765#define CHAR_TYPE_ID_ASCII (1 << 4) /* ID next ASCII: [_$A-Za-z0-9] */
766
767/* char_table3 */
768#define CHAR_TYPE_SIGN (1 << 0) /* [-+] */
769#define CHAR_TYPE_DIGIT (1 << 1) /* [0-9] */
770#define CHAR_TYPE_NONZERO (1 << 2) /* [1-9] */
771#define CHAR_TYPE_EXP (1 << 3) /* [eE] */
772#define CHAR_TYPE_DOT (1 << 4) /* [.] */
773
774static const u8 char_table1[256] = {
775 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
776 0x00, 0x0C, 0x0C, 0x08, 0x08, 0x0C, 0x00, 0x00,
777 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
778 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
779 0x0F, 0x03, 0x02, 0x03, 0x03, 0x03, 0x03, 0x01,
780 0x03, 0x03, 0x03, 0x13, 0x03, 0x13, 0x13, 0x23,
781 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
782 0x13, 0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
783 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
784 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
785 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
786 0x03, 0x03, 0x03, 0x03, 0x00, 0x03, 0x03, 0x03,
787 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
788 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
789 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
790 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
791 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
792 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
793 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
794 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
795 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
796 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
797 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
798 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
799 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
800 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
801 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
802 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
803 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
804 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
805 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
806 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
807};
808
809static const u8 char_table2[256] = {
810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
811 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
812 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
813 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
814 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
815 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
816 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
817 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
818 0x00, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
819 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
820 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
821 0x1C, 0x1C, 0x1C, 0x00, 0x0C, 0x00, 0x00, 0x1C,
822 0x00, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
823 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
824 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
825 0x1C, 0x1C, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00,
826 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
827 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
828 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
829 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
830 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
831 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
832 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
833 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
834 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
835 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
836 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
837 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
838 0x0C, 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
839 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
840 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
841 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C
842};
843
844static const u8 char_table3[256] = {
845 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
846 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x01, 0x00, 0x01, 0x10, 0x00,
851 0x02, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
852 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
853 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
854 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
855 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
856 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
857 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
858 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
859 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
860 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
861 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
862 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
863 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
864 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
865 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
866 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
867 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
868 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
869 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
870 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
871 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
872 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
873 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
874 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
875 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
876 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
877};
878
879/** Match a whitespace: [ \t\n\r]. */
880static_inline bool char_is_space(u8 c) {
881 return !!(char_table1[c] & CHAR_TYPE_SPACE);
882}
883
884/** Match an extended whitespace: [ \t\n\r\\v\\f], JSON5 whitespace. */
885static_inline bool char_is_space_ext(u8 c) {
886 return !!(char_table1[c] & CHAR_TYPE_SPACE_EXT);
887}
888
889/** Match a JSON number: [.-+0-9]. */
890static_inline bool char_is_num(u8 c) {
891 return !!(char_table1[c] & CHAR_TYPE_NUM);
892}
893
894/** Match an ASCII character in string: ["\], [0x00-0x1F, 0x80-0xFF]. */
895static_inline bool char_is_ascii_skip(u8 c) {
896 return !!(char_table1[c] & CHAR_TYPE_ASCII);
897}
898
899/** Match an ASCII character single-quoted: ['\], [0x00-0x1F, 0x80-0xFF]. */
900static_inline bool char_is_ascii_skip_sq(u8 c) {
901 return !!(char_table1[c] & CHAR_TYPE_ASCII_SQ);
902}
903
904/** Match a trivia character: extended whitespace or comment. */
905static_inline bool char_is_trivia(u8 c) {
906 return !!(char_table1[c] & (CHAR_TYPE_SPACE_EXT | CHAR_TYPE_COMMENT));
907}
908
909/** Match a line end character: [\r\n]. */
910static_inline bool char_is_eol(u8 c) {
911 return !!(char_table2[c] & CHAR_TYPE_EOL);
912}
913
914/** Match an extended line end character: [\r\n], JSON5 line terminator. */
915static_inline bool char_is_eol_ext(u8 c) {
916 return !!(char_table2[c] & CHAR_TYPE_EOL_EXT);
917}
918
919/** Match an identifier name start: [_$A-Za-z\], U+0080+. */
920static_inline bool char_is_id_start(u8 c) {
921 return !!(char_table2[c] & CHAR_TYPE_ID_START);
922}
923
924/** Match an identifier name next: [_$A-Za-z0-9\], U+0080+. */
925static_inline bool char_is_id_next(u8 c) {
926 return !!(char_table2[c] & CHAR_TYPE_ID_NEXT);
927}
928
929/** Match an identifier name ASCII: [_$A-Za-z0-9]. */
930static_inline bool char_is_id_ascii(u8 c) {
931 return !!(char_table2[c] & CHAR_TYPE_ID_ASCII);
932}
933
934/** Match a sign: [+-] */
935static_inline bool char_is_sign(u8 d) {
936 return !!(char_table3[d] & CHAR_TYPE_SIGN);
937}
938
939/** Match a non-zero digit: [1-9] */
940static_inline bool char_is_nonzero(u8 d) {
941 return !!(char_table3[d] & CHAR_TYPE_NONZERO);
942}
943
944/** Match a digit: [0-9] */
945static_inline bool char_is_digit(u8 d) {
946 return !!(char_table3[d] & CHAR_TYPE_DIGIT);
947}
948
949/** Match an exponent character: [eE]. */
950static_inline bool char_is_exp(u8 d) {
951 return !!(char_table3[d] & CHAR_TYPE_EXP);
952}
953
954/** Match a floating point indicator: [.eE]. */
955static_inline bool char_is_fp(u8 d) {
956 return !!(char_table3[d] & (CHAR_TYPE_DOT | CHAR_TYPE_EXP));
957}
958
959/** Match a digit or floating point indicator: [0-9.eE]. */
960static_inline bool char_is_digit_or_fp(u8 d) {
961 return !!(char_table3[d] & (CHAR_TYPE_DIGIT | CHAR_TYPE_DOT |
962 CHAR_TYPE_EXP));
963}
964
965/** Match a JSON container: `{` or `[`. */
966static_inline bool char_is_ctn(u8 c) {
967 return (c & 0xDF) == 0x5B; /* '[': 0x5B, '{': 0x7B */
968}
969
970/** Convert ASCII letter to lowercase; valid only for [A-Za-z]. */
971static_inline u8 char_to_lower(u8 c) {
972 return c | 0x20;
973}
974
975/** Match UTF-8 byte order mask. */
976static_inline bool is_utf8_bom(const u8 *cur) {
977 return byte_load_3(cur) == byte_load_3("\xEF\xBB\xBF");
978}
979
980/** Match UTF-16 byte order mask. */
981static_inline bool is_utf16_bom(const u8 *cur) {
982 return byte_load_2(cur) == byte_load_2("\xFE\xFF") ||
983 byte_load_2(cur) == byte_load_2("\xFF\xFE");
984}
985
986/** Match UTF-32 byte order mask, need length check to avoid zero padding. */
987static_inline bool is_utf32_bom(const u8 *cur) {
988 return byte_load_4(cur) == byte_load_4("\x00\x00\xFE\xFF") ||
989 byte_load_4(cur) == byte_load_4("\xFF\xFE\x00\x00");
990}
991
992/** Get the extended line end length. Used with `char_is_eol_ext`. */
993static_inline usize ext_eol_len(const u8 *cur) {
994 if (cur[0] < 0x80) return 1;
995 if (cur[1] == 0x80 && (cur[2] == 0xA8 || cur[2] == 0xA9)) return 3;
996 return 0;
997}
998
999/** Get the extended whitespace length. Used with `char_is_space_ext`. */
1000static_inline usize ext_space_len(const u8 *cur) {
1001 if (cur[0] < 0x80) {
1002 return 1;
1003 } else if (byte_load_2(cur) == byte_load_2("\xC2\xA0")) {
1004 return 2;
1005 } else if (byte_load_2(cur) == byte_load_2("\xE2\x80")) {
1006 if (cur[2] >= 0x80 && cur[2] <= 0x8A) return 3;
1007 if (cur[2] == 0xA8 || cur[2] == 0xA9 || cur[2] == 0xAF) return 3;
1008 } else {
1009 u32 uni = byte_load_3(cur);
1010 if (uni == byte_load_3("\xE1\x9A\x80") ||
1011 uni == byte_load_3("\xE2\x81\x9F") ||
1012 uni == byte_load_3("\xE3\x80\x80") ||
1013 uni == byte_load_3("\xEF\xBB\xBF")) return 3;
1014 }
1015 return 0;
1016}
1017
1018
1019
1020/*==============================================================================
1021 * MARK: - Hex Character Reader (Private)
1022 * This function is used by JSON reader to read escaped characters.
1023 *============================================================================*/
1024
1025/**
1026 This table is used to convert a 4-hex-character sequence to a number.
1027 A valid hex character [0-9A-Fa-f] is mapped to its raw value [0x00, 0x0F];
1028 an invalid hex character is mapped to [0xF0].
1029 (generated with misc/make_tables.c)
1030 */
1031static const u8 hex_conv_table[256] = {
1032 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1033 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 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, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1038 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1039 0x08, 0x09, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1040 0xF0, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF0,
1041 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1042 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1043 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1044 0xF0, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF0,
1045 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1046 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1047 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1048 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1049 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1050 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1051 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1052 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1053 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1054 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1055 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1056 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1057 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1058 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1059 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1060 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1061 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1062 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1063 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0
1064};
1065
1066/** Load 4 hex characters to `u16`, return true on valid input. */
1067static_inline bool hex_load_4(const u8 *src, u16 *dst) {
1068 u16 c0 = hex_conv_table[src[0]];
1069 u16 c1 = hex_conv_table[src[1]];
1070 u16 c2 = hex_conv_table[src[2]];
1071 u16 c3 = hex_conv_table[src[3]];
1072 u16 t0 = (u16)((c0 << 8) | c2);
1073 u16 t1 = (u16)((c1 << 8) | c3);
1074 *dst = (u16)((t0 << 4) | t1);
1075 return ((t0 | t1) & (u16)0xF0F0) == 0;
1076}
1077
1078/** Load 2 hex characters to `u8`, return true on valid input. */
1079static_inline bool hex_load_2(const u8 *src, u8 *dst) {
1080 u8 c0 = hex_conv_table[src[0]];
1081 u8 c1 = hex_conv_table[src[1]];
1082 *dst = (u8)((c0 << 4) | c1);
1083 return ((c0 | c1) & 0xF0) == 0;
1084}
1085
1086/** Match a hexadecimal numeric character: [0-9a-fA-F]. */
1087static_inline bool char_is_hex(u8 c) {
1088 return hex_conv_table[c] != 0xF0;
1089}
1090
1091
1092
1093/*==============================================================================
1094 * MARK: - UTF8 Validation (Private)
1095 * Each Unicode code point is encoded using 1 to 4 bytes in UTF-8.
1096 * Validation is performed using a 4-byte mask and pattern-based approach,
1097 * which requires the input data to be padded with four zero bytes at the end.
1098 *============================================================================*/
1099
1100/* Macro for concatenating four u8 into a u32 and keeping the byte order. */
1101#if YYJSON_ENDIAN == YYJSON_LITTLE_ENDIAN
1102# define utf8_seq_def(name, a, b, c, d) \
1103 static const u32 utf8_seq_##name = 0x##d##c##b##a##UL;
1104# define utf8_seq(name) utf8_seq_##name
1105#elif YYJSON_ENDIAN == YYJSON_BIG_ENDIAN
1106# define utf8_seq_def(name, a, b, c, d) \
1107 static const u32 utf8_seq_##name = 0x##a##b##c##d##UL;
1108# define utf8_seq(name) utf8_seq_##name
1109#else
1110# define utf8_seq_def(name, a, b, c, d) \
1111 static const v32_uni utf8_uni_##name = {{ 0x##a, 0x##b, 0x##c, 0x##d }};
1112# define utf8_seq(name) utf8_uni_##name.u
1113#endif
1114
1115/*
1116 1-byte sequence (U+0000 to U+007F)
1117 bit min [.......0] (U+0000)
1118 bit max [.1111111] (U+007F)
1119 bit mask [x.......] (80)
1120 bit pattern [0.......] (00)
1121 */
1122utf8_seq_def(b1_mask, 80, 00, 00, 00)
1123utf8_seq_def(b1_patt, 00, 00, 00, 00)
1124#define is_utf8_seq1(uni) ( \
1125 ((uni & utf8_seq(b1_mask)) == utf8_seq(b1_patt)) )
1126
1127/*
1128 2-byte sequence (U+0080 to U+07FF)
1129 bit min [......10 ..000000] (U+0080)
1130 bit max [...11111 ..111111] (U+07FF)
1131 bit mask [xxx..... xx......] (E0 C0)
1132 bit pattern [110..... 10......] (C0 80)
1133 bit require [...xxxx. ........] (1E 00)
1134 */
1135utf8_seq_def(b2_mask, E0, C0, 00, 00)
1136utf8_seq_def(b2_patt, C0, 80, 00, 00)
1137utf8_seq_def(b2_requ, 1E, 00, 00, 00)
1138#define is_utf8_seq2(uni) ( \
1139 ((uni & utf8_seq(b2_mask)) == utf8_seq(b2_patt)) && \
1140 ((uni & utf8_seq(b2_requ))) )
1141
1142/*
1143 3-byte sequence (U+0800 to U+FFFF)
1144 bit min [........ ..100000 ..000000] (U+0800)
1145 bit max [....1111 ..111111 ..111111] (U+FFFF)
1146 bit mask [xxxx.... xx...... xx......] (F0 C0 C0)
1147 bit pattern [1110.... 10...... 10......] (E0 80 80)
1148 bit require [....xxxx ..x..... ........] (0F 20 00)
1149
1150 3-byte invalid sequence, reserved for surrogate halves (U+D800 to U+DFFF)
1151 bit min [....1101 ..100000 ..000000] (U+D800)
1152 bit max [....1101 ..111111 ..111111] (U+DFFF)
1153 bit mask [....xxxx ..x..... ........] (0F 20 00)
1154 bit pattern [....1101 ..1..... ........] (0D 20 00)
1155 */
1156utf8_seq_def(b3_mask, F0, C0, C0, 00)
1157utf8_seq_def(b3_patt, E0, 80, 80, 00)
1158utf8_seq_def(b3_requ, 0F, 20, 00, 00)
1159utf8_seq_def(b3_erro, 0D, 20, 00, 00)
1160#define is_utf8_seq3(uni) ( \
1161 ((uni & utf8_seq(b3_mask)) == utf8_seq(b3_patt)) && \
1162 ((tmp = (uni & utf8_seq(b3_requ)))) && \
1163 ((tmp != utf8_seq(b3_erro))) )
1164
1165/*
1166 4-byte sequence (U+10000 to U+10FFFF)
1167 bit min [........ ...10000 ..000000 ..000000] (U+10000)
1168 bit max [.....100 ..001111 ..111111 ..111111] (U+10FFFF)
1169 bit mask [xxxxx... xx...... xx...... xx......] (F8 C0 C0 C0)
1170 bit pattern [11110... 10...... 10...... 10......] (F0 80 80 80)
1171 bit require [.....xxx ..xx.... ........ ........] (07 30 00 00)
1172 bit require 1 [.....x.. ........ ........ ........] (04 00 00 00)
1173 bit require 2 [......xx ..xx.... ........ ........] (03 30 00 00)
1174 */
1175utf8_seq_def(b4_mask, F8, C0, C0, C0)
1176utf8_seq_def(b4_patt, F0, 80, 80, 80)
1177utf8_seq_def(b4_requ, 07, 30, 00, 00)
1178utf8_seq_def(b4_req1, 04, 00, 00, 00)
1179utf8_seq_def(b4_req2, 03, 30, 00, 00)
1180#define is_utf8_seq4(uni) ( \
1181 ((uni & utf8_seq(b4_mask)) == utf8_seq(b4_patt)) && \
1182 ((tmp = (uni & utf8_seq(b4_requ)))) && \
1183 ((tmp & utf8_seq(b4_req1)) == 0 || (tmp & utf8_seq(b4_req2)) == 0) )
1184
1185
1186
1187/*==============================================================================
1188 * MARK: - Power10 Lookup Table (Private)
1189 * These data are used by the floating-point number reader and writer.
1190 *============================================================================*/
1191
1192#if !YYJSON_DISABLE_FAST_FP_CONV
1193
1194/** Maximum pow10 exponent that can be represented exactly as a float64. */
1195#define F64_POW10_MAX_EXACT_EXP 22
1196
1197#if YYJSON_DOUBLE_MATH_CORRECT
1198/** Cached pow10 table. */
1199static const f64 f64_pow10_table[F64_POW10_MAX_EXACT_EXP + 1] = {
1200 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12,
1201 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22
1202};
1203#endif
1204
1205/** Maximum pow10 exponent that can be represented exactly as a uint64. */
1206#define U64_POW10_MAX_EXACT_EXP 19
1207
1208/** Table: [ 10^0, ..., 10^19 ] (generated with misc/make_tables.c) */
1209static const u64 u64_pow10_table[U64_POW10_MAX_EXACT_EXP + 1] = {
1210 U64(0x00000000, 0x00000001), U64(0x00000000, 0x0000000A),
1211 U64(0x00000000, 0x00000064), U64(0x00000000, 0x000003E8),
1212 U64(0x00000000, 0x00002710), U64(0x00000000, 0x000186A0),
1213 U64(0x00000000, 0x000F4240), U64(0x00000000, 0x00989680),
1214 U64(0x00000000, 0x05F5E100), U64(0x00000000, 0x3B9ACA00),
1215 U64(0x00000002, 0x540BE400), U64(0x00000017, 0x4876E800),
1216 U64(0x000000E8, 0xD4A51000), U64(0x00000918, 0x4E72A000),
1217 U64(0x00005AF3, 0x107A4000), U64(0x00038D7E, 0xA4C68000),
1218 U64(0x002386F2, 0x6FC10000), U64(0x01634578, 0x5D8A0000),
1219 U64(0x0DE0B6B3, 0xA7640000), U64(0x8AC72304, 0x89E80000)
1220};
1221
1222/** Minimum decimal exponent in pow10_sig_table. */
1223#define POW10_SIG_TABLE_MIN_EXP -343
1224
1225/** Maximum decimal exponent in pow10_sig_table. */
1226#define POW10_SIG_TABLE_MAX_EXP 324
1227
1228/** Minimum exact decimal exponent in pow10_sig_table */
1229#define POW10_SIG_TABLE_MIN_EXACT_EXP 0
1230
1231/** Maximum exact decimal exponent in pow10_sig_table */
1232#define POW10_SIG_TABLE_MAX_EXACT_EXP 55
1233
1234/** Normalized significant 128 bits of pow10, not rounded up (size: 10.4KB).
1235 This lookup table is used by both the double number reader and writer.
1236 (generated with misc/make_tables.c) */
1237static const u64 pow10_sig_table[] = {
1238 U64(0xBF29DCAB, 0xA82FDEAE), U64(0x7432EE87, 0x3880FC33), /* ~= 10^-343 */
1239 U64(0xEEF453D6, 0x923BD65A), U64(0x113FAA29, 0x06A13B3F), /* ~= 10^-342 */
1240 U64(0x9558B466, 0x1B6565F8), U64(0x4AC7CA59, 0xA424C507), /* ~= 10^-341 */
1241 U64(0xBAAEE17F, 0xA23EBF76), U64(0x5D79BCF0, 0x0D2DF649), /* ~= 10^-340 */
1242 U64(0xE95A99DF, 0x8ACE6F53), U64(0xF4D82C2C, 0x107973DC), /* ~= 10^-339 */
1243 U64(0x91D8A02B, 0xB6C10594), U64(0x79071B9B, 0x8A4BE869), /* ~= 10^-338 */
1244 U64(0xB64EC836, 0xA47146F9), U64(0x9748E282, 0x6CDEE284), /* ~= 10^-337 */
1245 U64(0xE3E27A44, 0x4D8D98B7), U64(0xFD1B1B23, 0x08169B25), /* ~= 10^-336 */
1246 U64(0x8E6D8C6A, 0xB0787F72), U64(0xFE30F0F5, 0xE50E20F7), /* ~= 10^-335 */
1247 U64(0xB208EF85, 0x5C969F4F), U64(0xBDBD2D33, 0x5E51A935), /* ~= 10^-334 */
1248 U64(0xDE8B2B66, 0xB3BC4723), U64(0xAD2C7880, 0x35E61382), /* ~= 10^-333 */
1249 U64(0x8B16FB20, 0x3055AC76), U64(0x4C3BCB50, 0x21AFCC31), /* ~= 10^-332 */
1250 U64(0xADDCB9E8, 0x3C6B1793), U64(0xDF4ABE24, 0x2A1BBF3D), /* ~= 10^-331 */
1251 U64(0xD953E862, 0x4B85DD78), U64(0xD71D6DAD, 0x34A2AF0D), /* ~= 10^-330 */
1252 U64(0x87D4713D, 0x6F33AA6B), U64(0x8672648C, 0x40E5AD68), /* ~= 10^-329 */
1253 U64(0xA9C98D8C, 0xCB009506), U64(0x680EFDAF, 0x511F18C2), /* ~= 10^-328 */
1254 U64(0xD43BF0EF, 0xFDC0BA48), U64(0x0212BD1B, 0x2566DEF2), /* ~= 10^-327 */
1255 U64(0x84A57695, 0xFE98746D), U64(0x014BB630, 0xF7604B57), /* ~= 10^-326 */
1256 U64(0xA5CED43B, 0x7E3E9188), U64(0x419EA3BD, 0x35385E2D), /* ~= 10^-325 */
1257 U64(0xCF42894A, 0x5DCE35EA), U64(0x52064CAC, 0x828675B9), /* ~= 10^-324 */
1258 U64(0x818995CE, 0x7AA0E1B2), U64(0x7343EFEB, 0xD1940993), /* ~= 10^-323 */
1259 U64(0xA1EBFB42, 0x19491A1F), U64(0x1014EBE6, 0xC5F90BF8), /* ~= 10^-322 */
1260 U64(0xCA66FA12, 0x9F9B60A6), U64(0xD41A26E0, 0x77774EF6), /* ~= 10^-321 */
1261 U64(0xFD00B897, 0x478238D0), U64(0x8920B098, 0x955522B4), /* ~= 10^-320 */
1262 U64(0x9E20735E, 0x8CB16382), U64(0x55B46E5F, 0x5D5535B0), /* ~= 10^-319 */
1263 U64(0xC5A89036, 0x2FDDBC62), U64(0xEB2189F7, 0x34AA831D), /* ~= 10^-318 */
1264 U64(0xF712B443, 0xBBD52B7B), U64(0xA5E9EC75, 0x01D523E4), /* ~= 10^-317 */
1265 U64(0x9A6BB0AA, 0x55653B2D), U64(0x47B233C9, 0x2125366E), /* ~= 10^-316 */
1266 U64(0xC1069CD4, 0xEABE89F8), U64(0x999EC0BB, 0x696E840A), /* ~= 10^-315 */
1267 U64(0xF148440A, 0x256E2C76), U64(0xC00670EA, 0x43CA250D), /* ~= 10^-314 */
1268 U64(0x96CD2A86, 0x5764DBCA), U64(0x38040692, 0x6A5E5728), /* ~= 10^-313 */
1269 U64(0xBC807527, 0xED3E12BC), U64(0xC6050837, 0x04F5ECF2), /* ~= 10^-312 */
1270 U64(0xEBA09271, 0xE88D976B), U64(0xF7864A44, 0xC633682E), /* ~= 10^-311 */
1271 U64(0x93445B87, 0x31587EA3), U64(0x7AB3EE6A, 0xFBE0211D), /* ~= 10^-310 */
1272 U64(0xB8157268, 0xFDAE9E4C), U64(0x5960EA05, 0xBAD82964), /* ~= 10^-309 */
1273 U64(0xE61ACF03, 0x3D1A45DF), U64(0x6FB92487, 0x298E33BD), /* ~= 10^-308 */
1274 U64(0x8FD0C162, 0x06306BAB), U64(0xA5D3B6D4, 0x79F8E056), /* ~= 10^-307 */
1275 U64(0xB3C4F1BA, 0x87BC8696), U64(0x8F48A489, 0x9877186C), /* ~= 10^-306 */
1276 U64(0xE0B62E29, 0x29ABA83C), U64(0x331ACDAB, 0xFE94DE87), /* ~= 10^-305 */
1277 U64(0x8C71DCD9, 0xBA0B4925), U64(0x9FF0C08B, 0x7F1D0B14), /* ~= 10^-304 */
1278 U64(0xAF8E5410, 0x288E1B6F), U64(0x07ECF0AE, 0x5EE44DD9), /* ~= 10^-303 */
1279 U64(0xDB71E914, 0x32B1A24A), U64(0xC9E82CD9, 0xF69D6150), /* ~= 10^-302 */
1280 U64(0x892731AC, 0x9FAF056E), U64(0xBE311C08, 0x3A225CD2), /* ~= 10^-301 */
1281 U64(0xAB70FE17, 0xC79AC6CA), U64(0x6DBD630A, 0x48AAF406), /* ~= 10^-300 */
1282 U64(0xD64D3D9D, 0xB981787D), U64(0x092CBBCC, 0xDAD5B108), /* ~= 10^-299 */
1283 U64(0x85F04682, 0x93F0EB4E), U64(0x25BBF560, 0x08C58EA5), /* ~= 10^-298 */
1284 U64(0xA76C5823, 0x38ED2621), U64(0xAF2AF2B8, 0x0AF6F24E), /* ~= 10^-297 */
1285 U64(0xD1476E2C, 0x07286FAA), U64(0x1AF5AF66, 0x0DB4AEE1), /* ~= 10^-296 */
1286 U64(0x82CCA4DB, 0x847945CA), U64(0x50D98D9F, 0xC890ED4D), /* ~= 10^-295 */
1287 U64(0xA37FCE12, 0x6597973C), U64(0xE50FF107, 0xBAB528A0), /* ~= 10^-294 */
1288 U64(0xCC5FC196, 0xFEFD7D0C), U64(0x1E53ED49, 0xA96272C8), /* ~= 10^-293 */
1289 U64(0xFF77B1FC, 0xBEBCDC4F), U64(0x25E8E89C, 0x13BB0F7A), /* ~= 10^-292 */
1290 U64(0x9FAACF3D, 0xF73609B1), U64(0x77B19161, 0x8C54E9AC), /* ~= 10^-291 */
1291 U64(0xC795830D, 0x75038C1D), U64(0xD59DF5B9, 0xEF6A2417), /* ~= 10^-290 */
1292 U64(0xF97AE3D0, 0xD2446F25), U64(0x4B057328, 0x6B44AD1D), /* ~= 10^-289 */
1293 U64(0x9BECCE62, 0x836AC577), U64(0x4EE367F9, 0x430AEC32), /* ~= 10^-288 */
1294 U64(0xC2E801FB, 0x244576D5), U64(0x229C41F7, 0x93CDA73F), /* ~= 10^-287 */
1295 U64(0xF3A20279, 0xED56D48A), U64(0x6B435275, 0x78C1110F), /* ~= 10^-286 */
1296 U64(0x9845418C, 0x345644D6), U64(0x830A1389, 0x6B78AAA9), /* ~= 10^-285 */
1297 U64(0xBE5691EF, 0x416BD60C), U64(0x23CC986B, 0xC656D553), /* ~= 10^-284 */
1298 U64(0xEDEC366B, 0x11C6CB8F), U64(0x2CBFBE86, 0xB7EC8AA8), /* ~= 10^-283 */
1299 U64(0x94B3A202, 0xEB1C3F39), U64(0x7BF7D714, 0x32F3D6A9), /* ~= 10^-282 */
1300 U64(0xB9E08A83, 0xA5E34F07), U64(0xDAF5CCD9, 0x3FB0CC53), /* ~= 10^-281 */
1301 U64(0xE858AD24, 0x8F5C22C9), U64(0xD1B3400F, 0x8F9CFF68), /* ~= 10^-280 */
1302 U64(0x91376C36, 0xD99995BE), U64(0x23100809, 0xB9C21FA1), /* ~= 10^-279 */
1303 U64(0xB5854744, 0x8FFFFB2D), U64(0xABD40A0C, 0x2832A78A), /* ~= 10^-278 */
1304 U64(0xE2E69915, 0xB3FFF9F9), U64(0x16C90C8F, 0x323F516C), /* ~= 10^-277 */
1305 U64(0x8DD01FAD, 0x907FFC3B), U64(0xAE3DA7D9, 0x7F6792E3), /* ~= 10^-276 */
1306 U64(0xB1442798, 0xF49FFB4A), U64(0x99CD11CF, 0xDF41779C), /* ~= 10^-275 */
1307 U64(0xDD95317F, 0x31C7FA1D), U64(0x40405643, 0xD711D583), /* ~= 10^-274 */
1308 U64(0x8A7D3EEF, 0x7F1CFC52), U64(0x482835EA, 0x666B2572), /* ~= 10^-273 */
1309 U64(0xAD1C8EAB, 0x5EE43B66), U64(0xDA324365, 0x0005EECF), /* ~= 10^-272 */
1310 U64(0xD863B256, 0x369D4A40), U64(0x90BED43E, 0x40076A82), /* ~= 10^-271 */
1311 U64(0x873E4F75, 0xE2224E68), U64(0x5A7744A6, 0xE804A291), /* ~= 10^-270 */
1312 U64(0xA90DE353, 0x5AAAE202), U64(0x711515D0, 0xA205CB36), /* ~= 10^-269 */
1313 U64(0xD3515C28, 0x31559A83), U64(0x0D5A5B44, 0xCA873E03), /* ~= 10^-268 */
1314 U64(0x8412D999, 0x1ED58091), U64(0xE858790A, 0xFE9486C2), /* ~= 10^-267 */
1315 U64(0xA5178FFF, 0x668AE0B6), U64(0x626E974D, 0xBE39A872), /* ~= 10^-266 */
1316 U64(0xCE5D73FF, 0x402D98E3), U64(0xFB0A3D21, 0x2DC8128F), /* ~= 10^-265 */
1317 U64(0x80FA687F, 0x881C7F8E), U64(0x7CE66634, 0xBC9D0B99), /* ~= 10^-264 */
1318 U64(0xA139029F, 0x6A239F72), U64(0x1C1FFFC1, 0xEBC44E80), /* ~= 10^-263 */
1319 U64(0xC9874347, 0x44AC874E), U64(0xA327FFB2, 0x66B56220), /* ~= 10^-262 */
1320 U64(0xFBE91419, 0x15D7A922), U64(0x4BF1FF9F, 0x0062BAA8), /* ~= 10^-261 */
1321 U64(0x9D71AC8F, 0xADA6C9B5), U64(0x6F773FC3, 0x603DB4A9), /* ~= 10^-260 */
1322 U64(0xC4CE17B3, 0x99107C22), U64(0xCB550FB4, 0x384D21D3), /* ~= 10^-259 */
1323 U64(0xF6019DA0, 0x7F549B2B), U64(0x7E2A53A1, 0x46606A48), /* ~= 10^-258 */
1324 U64(0x99C10284, 0x4F94E0FB), U64(0x2EDA7444, 0xCBFC426D), /* ~= 10^-257 */
1325 U64(0xC0314325, 0x637A1939), U64(0xFA911155, 0xFEFB5308), /* ~= 10^-256 */
1326 U64(0xF03D93EE, 0xBC589F88), U64(0x793555AB, 0x7EBA27CA), /* ~= 10^-255 */
1327 U64(0x96267C75, 0x35B763B5), U64(0x4BC1558B, 0x2F3458DE), /* ~= 10^-254 */
1328 U64(0xBBB01B92, 0x83253CA2), U64(0x9EB1AAED, 0xFB016F16), /* ~= 10^-253 */
1329 U64(0xEA9C2277, 0x23EE8BCB), U64(0x465E15A9, 0x79C1CADC), /* ~= 10^-252 */
1330 U64(0x92A1958A, 0x7675175F), U64(0x0BFACD89, 0xEC191EC9), /* ~= 10^-251 */
1331 U64(0xB749FAED, 0x14125D36), U64(0xCEF980EC, 0x671F667B), /* ~= 10^-250 */
1332 U64(0xE51C79A8, 0x5916F484), U64(0x82B7E127, 0x80E7401A), /* ~= 10^-249 */
1333 U64(0x8F31CC09, 0x37AE58D2), U64(0xD1B2ECB8, 0xB0908810), /* ~= 10^-248 */
1334 U64(0xB2FE3F0B, 0x8599EF07), U64(0x861FA7E6, 0xDCB4AA15), /* ~= 10^-247 */
1335 U64(0xDFBDCECE, 0x67006AC9), U64(0x67A791E0, 0x93E1D49A), /* ~= 10^-246 */
1336 U64(0x8BD6A141, 0x006042BD), U64(0xE0C8BB2C, 0x5C6D24E0), /* ~= 10^-245 */
1337 U64(0xAECC4991, 0x4078536D), U64(0x58FAE9F7, 0x73886E18), /* ~= 10^-244 */
1338 U64(0xDA7F5BF5, 0x90966848), U64(0xAF39A475, 0x506A899E), /* ~= 10^-243 */
1339 U64(0x888F9979, 0x7A5E012D), U64(0x6D8406C9, 0x52429603), /* ~= 10^-242 */
1340 U64(0xAAB37FD7, 0xD8F58178), U64(0xC8E5087B, 0xA6D33B83), /* ~= 10^-241 */
1341 U64(0xD5605FCD, 0xCF32E1D6), U64(0xFB1E4A9A, 0x90880A64), /* ~= 10^-240 */
1342 U64(0x855C3BE0, 0xA17FCD26), U64(0x5CF2EEA0, 0x9A55067F), /* ~= 10^-239 */
1343 U64(0xA6B34AD8, 0xC9DFC06F), U64(0xF42FAA48, 0xC0EA481E), /* ~= 10^-238 */
1344 U64(0xD0601D8E, 0xFC57B08B), U64(0xF13B94DA, 0xF124DA26), /* ~= 10^-237 */
1345 U64(0x823C1279, 0x5DB6CE57), U64(0x76C53D08, 0xD6B70858), /* ~= 10^-236 */
1346 U64(0xA2CB1717, 0xB52481ED), U64(0x54768C4B, 0x0C64CA6E), /* ~= 10^-235 */
1347 U64(0xCB7DDCDD, 0xA26DA268), U64(0xA9942F5D, 0xCF7DFD09), /* ~= 10^-234 */
1348 U64(0xFE5D5415, 0x0B090B02), U64(0xD3F93B35, 0x435D7C4C), /* ~= 10^-233 */
1349 U64(0x9EFA548D, 0x26E5A6E1), U64(0xC47BC501, 0x4A1A6DAF), /* ~= 10^-232 */
1350 U64(0xC6B8E9B0, 0x709F109A), U64(0x359AB641, 0x9CA1091B), /* ~= 10^-231 */
1351 U64(0xF867241C, 0x8CC6D4C0), U64(0xC30163D2, 0x03C94B62), /* ~= 10^-230 */
1352 U64(0x9B407691, 0xD7FC44F8), U64(0x79E0DE63, 0x425DCF1D), /* ~= 10^-229 */
1353 U64(0xC2109436, 0x4DFB5636), U64(0x985915FC, 0x12F542E4), /* ~= 10^-228 */
1354 U64(0xF294B943, 0xE17A2BC4), U64(0x3E6F5B7B, 0x17B2939D), /* ~= 10^-227 */
1355 U64(0x979CF3CA, 0x6CEC5B5A), U64(0xA705992C, 0xEECF9C42), /* ~= 10^-226 */
1356 U64(0xBD8430BD, 0x08277231), U64(0x50C6FF78, 0x2A838353), /* ~= 10^-225 */
1357 U64(0xECE53CEC, 0x4A314EBD), U64(0xA4F8BF56, 0x35246428), /* ~= 10^-224 */
1358 U64(0x940F4613, 0xAE5ED136), U64(0x871B7795, 0xE136BE99), /* ~= 10^-223 */
1359 U64(0xB9131798, 0x99F68584), U64(0x28E2557B, 0x59846E3F), /* ~= 10^-222 */
1360 U64(0xE757DD7E, 0xC07426E5), U64(0x331AEADA, 0x2FE589CF), /* ~= 10^-221 */
1361 U64(0x9096EA6F, 0x3848984F), U64(0x3FF0D2C8, 0x5DEF7621), /* ~= 10^-220 */
1362 U64(0xB4BCA50B, 0x065ABE63), U64(0x0FED077A, 0x756B53A9), /* ~= 10^-219 */
1363 U64(0xE1EBCE4D, 0xC7F16DFB), U64(0xD3E84959, 0x12C62894), /* ~= 10^-218 */
1364 U64(0x8D3360F0, 0x9CF6E4BD), U64(0x64712DD7, 0xABBBD95C), /* ~= 10^-217 */
1365 U64(0xB080392C, 0xC4349DEC), U64(0xBD8D794D, 0x96AACFB3), /* ~= 10^-216 */
1366 U64(0xDCA04777, 0xF541C567), U64(0xECF0D7A0, 0xFC5583A0), /* ~= 10^-215 */
1367 U64(0x89E42CAA, 0xF9491B60), U64(0xF41686C4, 0x9DB57244), /* ~= 10^-214 */
1368 U64(0xAC5D37D5, 0xB79B6239), U64(0x311C2875, 0xC522CED5), /* ~= 10^-213 */
1369 U64(0xD77485CB, 0x25823AC7), U64(0x7D633293, 0x366B828B), /* ~= 10^-212 */
1370 U64(0x86A8D39E, 0xF77164BC), U64(0xAE5DFF9C, 0x02033197), /* ~= 10^-211 */
1371 U64(0xA8530886, 0xB54DBDEB), U64(0xD9F57F83, 0x0283FDFC), /* ~= 10^-210 */
1372 U64(0xD267CAA8, 0x62A12D66), U64(0xD072DF63, 0xC324FD7B), /* ~= 10^-209 */
1373 U64(0x8380DEA9, 0x3DA4BC60), U64(0x4247CB9E, 0x59F71E6D), /* ~= 10^-208 */
1374 U64(0xA4611653, 0x8D0DEB78), U64(0x52D9BE85, 0xF074E608), /* ~= 10^-207 */
1375 U64(0xCD795BE8, 0x70516656), U64(0x67902E27, 0x6C921F8B), /* ~= 10^-206 */
1376 U64(0x806BD971, 0x4632DFF6), U64(0x00BA1CD8, 0xA3DB53B6), /* ~= 10^-205 */
1377 U64(0xA086CFCD, 0x97BF97F3), U64(0x80E8A40E, 0xCCD228A4), /* ~= 10^-204 */
1378 U64(0xC8A883C0, 0xFDAF7DF0), U64(0x6122CD12, 0x8006B2CD), /* ~= 10^-203 */
1379 U64(0xFAD2A4B1, 0x3D1B5D6C), U64(0x796B8057, 0x20085F81), /* ~= 10^-202 */
1380 U64(0x9CC3A6EE, 0xC6311A63), U64(0xCBE33036, 0x74053BB0), /* ~= 10^-201 */
1381 U64(0xC3F490AA, 0x77BD60FC), U64(0xBEDBFC44, 0x11068A9C), /* ~= 10^-200 */
1382 U64(0xF4F1B4D5, 0x15ACB93B), U64(0xEE92FB55, 0x15482D44), /* ~= 10^-199 */
1383 U64(0x99171105, 0x2D8BF3C5), U64(0x751BDD15, 0x2D4D1C4A), /* ~= 10^-198 */
1384 U64(0xBF5CD546, 0x78EEF0B6), U64(0xD262D45A, 0x78A0635D), /* ~= 10^-197 */
1385 U64(0xEF340A98, 0x172AACE4), U64(0x86FB8971, 0x16C87C34), /* ~= 10^-196 */
1386 U64(0x9580869F, 0x0E7AAC0E), U64(0xD45D35E6, 0xAE3D4DA0), /* ~= 10^-195 */
1387 U64(0xBAE0A846, 0xD2195712), U64(0x89748360, 0x59CCA109), /* ~= 10^-194 */
1388 U64(0xE998D258, 0x869FACD7), U64(0x2BD1A438, 0x703FC94B), /* ~= 10^-193 */
1389 U64(0x91FF8377, 0x5423CC06), U64(0x7B6306A3, 0x4627DDCF), /* ~= 10^-192 */
1390 U64(0xB67F6455, 0x292CBF08), U64(0x1A3BC84C, 0x17B1D542), /* ~= 10^-191 */
1391 U64(0xE41F3D6A, 0x7377EECA), U64(0x20CABA5F, 0x1D9E4A93), /* ~= 10^-190 */
1392 U64(0x8E938662, 0x882AF53E), U64(0x547EB47B, 0x7282EE9C), /* ~= 10^-189 */
1393 U64(0xB23867FB, 0x2A35B28D), U64(0xE99E619A, 0x4F23AA43), /* ~= 10^-188 */
1394 U64(0xDEC681F9, 0xF4C31F31), U64(0x6405FA00, 0xE2EC94D4), /* ~= 10^-187 */
1395 U64(0x8B3C113C, 0x38F9F37E), U64(0xDE83BC40, 0x8DD3DD04), /* ~= 10^-186 */
1396 U64(0xAE0B158B, 0x4738705E), U64(0x9624AB50, 0xB148D445), /* ~= 10^-185 */
1397 U64(0xD98DDAEE, 0x19068C76), U64(0x3BADD624, 0xDD9B0957), /* ~= 10^-184 */
1398 U64(0x87F8A8D4, 0xCFA417C9), U64(0xE54CA5D7, 0x0A80E5D6), /* ~= 10^-183 */
1399 U64(0xA9F6D30A, 0x038D1DBC), U64(0x5E9FCF4C, 0xCD211F4C), /* ~= 10^-182 */
1400 U64(0xD47487CC, 0x8470652B), U64(0x7647C320, 0x0069671F), /* ~= 10^-181 */
1401 U64(0x84C8D4DF, 0xD2C63F3B), U64(0x29ECD9F4, 0x0041E073), /* ~= 10^-180 */
1402 U64(0xA5FB0A17, 0xC777CF09), U64(0xF4681071, 0x00525890), /* ~= 10^-179 */
1403 U64(0xCF79CC9D, 0xB955C2CC), U64(0x7182148D, 0x4066EEB4), /* ~= 10^-178 */
1404 U64(0x81AC1FE2, 0x93D599BF), U64(0xC6F14CD8, 0x48405530), /* ~= 10^-177 */
1405 U64(0xA21727DB, 0x38CB002F), U64(0xB8ADA00E, 0x5A506A7C), /* ~= 10^-176 */
1406 U64(0xCA9CF1D2, 0x06FDC03B), U64(0xA6D90811, 0xF0E4851C), /* ~= 10^-175 */
1407 U64(0xFD442E46, 0x88BD304A), U64(0x908F4A16, 0x6D1DA663), /* ~= 10^-174 */
1408 U64(0x9E4A9CEC, 0x15763E2E), U64(0x9A598E4E, 0x043287FE), /* ~= 10^-173 */
1409 U64(0xC5DD4427, 0x1AD3CDBA), U64(0x40EFF1E1, 0x853F29FD), /* ~= 10^-172 */
1410 U64(0xF7549530, 0xE188C128), U64(0xD12BEE59, 0xE68EF47C), /* ~= 10^-171 */
1411 U64(0x9A94DD3E, 0x8CF578B9), U64(0x82BB74F8, 0x301958CE), /* ~= 10^-170 */
1412 U64(0xC13A148E, 0x3032D6E7), U64(0xE36A5236, 0x3C1FAF01), /* ~= 10^-169 */
1413 U64(0xF18899B1, 0xBC3F8CA1), U64(0xDC44E6C3, 0xCB279AC1), /* ~= 10^-168 */
1414 U64(0x96F5600F, 0x15A7B7E5), U64(0x29AB103A, 0x5EF8C0B9), /* ~= 10^-167 */
1415 U64(0xBCB2B812, 0xDB11A5DE), U64(0x7415D448, 0xF6B6F0E7), /* ~= 10^-166 */
1416 U64(0xEBDF6617, 0x91D60F56), U64(0x111B495B, 0x3464AD21), /* ~= 10^-165 */
1417 U64(0x936B9FCE, 0xBB25C995), U64(0xCAB10DD9, 0x00BEEC34), /* ~= 10^-164 */
1418 U64(0xB84687C2, 0x69EF3BFB), U64(0x3D5D514F, 0x40EEA742), /* ~= 10^-163 */
1419 U64(0xE65829B3, 0x046B0AFA), U64(0x0CB4A5A3, 0x112A5112), /* ~= 10^-162 */
1420 U64(0x8FF71A0F, 0xE2C2E6DC), U64(0x47F0E785, 0xEABA72AB), /* ~= 10^-161 */
1421 U64(0xB3F4E093, 0xDB73A093), U64(0x59ED2167, 0x65690F56), /* ~= 10^-160 */
1422 U64(0xE0F218B8, 0xD25088B8), U64(0x306869C1, 0x3EC3532C), /* ~= 10^-159 */
1423 U64(0x8C974F73, 0x83725573), U64(0x1E414218, 0xC73A13FB), /* ~= 10^-158 */
1424 U64(0xAFBD2350, 0x644EEACF), U64(0xE5D1929E, 0xF90898FA), /* ~= 10^-157 */
1425 U64(0xDBAC6C24, 0x7D62A583), U64(0xDF45F746, 0xB74ABF39), /* ~= 10^-156 */
1426 U64(0x894BC396, 0xCE5DA772), U64(0x6B8BBA8C, 0x328EB783), /* ~= 10^-155 */
1427 U64(0xAB9EB47C, 0x81F5114F), U64(0x066EA92F, 0x3F326564), /* ~= 10^-154 */
1428 U64(0xD686619B, 0xA27255A2), U64(0xC80A537B, 0x0EFEFEBD), /* ~= 10^-153 */
1429 U64(0x8613FD01, 0x45877585), U64(0xBD06742C, 0xE95F5F36), /* ~= 10^-152 */
1430 U64(0xA798FC41, 0x96E952E7), U64(0x2C481138, 0x23B73704), /* ~= 10^-151 */
1431 U64(0xD17F3B51, 0xFCA3A7A0), U64(0xF75A1586, 0x2CA504C5), /* ~= 10^-150 */
1432 U64(0x82EF8513, 0x3DE648C4), U64(0x9A984D73, 0xDBE722FB), /* ~= 10^-149 */
1433 U64(0xA3AB6658, 0x0D5FDAF5), U64(0xC13E60D0, 0xD2E0EBBA), /* ~= 10^-148 */
1434 U64(0xCC963FEE, 0x10B7D1B3), U64(0x318DF905, 0x079926A8), /* ~= 10^-147 */
1435 U64(0xFFBBCFE9, 0x94E5C61F), U64(0xFDF17746, 0x497F7052), /* ~= 10^-146 */
1436 U64(0x9FD561F1, 0xFD0F9BD3), U64(0xFEB6EA8B, 0xEDEFA633), /* ~= 10^-145 */
1437 U64(0xC7CABA6E, 0x7C5382C8), U64(0xFE64A52E, 0xE96B8FC0), /* ~= 10^-144 */
1438 U64(0xF9BD690A, 0x1B68637B), U64(0x3DFDCE7A, 0xA3C673B0), /* ~= 10^-143 */
1439 U64(0x9C1661A6, 0x51213E2D), U64(0x06BEA10C, 0xA65C084E), /* ~= 10^-142 */
1440 U64(0xC31BFA0F, 0xE5698DB8), U64(0x486E494F, 0xCFF30A62), /* ~= 10^-141 */
1441 U64(0xF3E2F893, 0xDEC3F126), U64(0x5A89DBA3, 0xC3EFCCFA), /* ~= 10^-140 */
1442 U64(0x986DDB5C, 0x6B3A76B7), U64(0xF8962946, 0x5A75E01C), /* ~= 10^-139 */
1443 U64(0xBE895233, 0x86091465), U64(0xF6BBB397, 0xF1135823), /* ~= 10^-138 */
1444 U64(0xEE2BA6C0, 0x678B597F), U64(0x746AA07D, 0xED582E2C), /* ~= 10^-137 */
1445 U64(0x94DB4838, 0x40B717EF), U64(0xA8C2A44E, 0xB4571CDC), /* ~= 10^-136 */
1446 U64(0xBA121A46, 0x50E4DDEB), U64(0x92F34D62, 0x616CE413), /* ~= 10^-135 */
1447 U64(0xE896A0D7, 0xE51E1566), U64(0x77B020BA, 0xF9C81D17), /* ~= 10^-134 */
1448 U64(0x915E2486, 0xEF32CD60), U64(0x0ACE1474, 0xDC1D122E), /* ~= 10^-133 */
1449 U64(0xB5B5ADA8, 0xAAFF80B8), U64(0x0D819992, 0x132456BA), /* ~= 10^-132 */
1450 U64(0xE3231912, 0xD5BF60E6), U64(0x10E1FFF6, 0x97ED6C69), /* ~= 10^-131 */
1451 U64(0x8DF5EFAB, 0xC5979C8F), U64(0xCA8D3FFA, 0x1EF463C1), /* ~= 10^-130 */
1452 U64(0xB1736B96, 0xB6FD83B3), U64(0xBD308FF8, 0xA6B17CB2), /* ~= 10^-129 */
1453 U64(0xDDD0467C, 0x64BCE4A0), U64(0xAC7CB3F6, 0xD05DDBDE), /* ~= 10^-128 */
1454 U64(0x8AA22C0D, 0xBEF60EE4), U64(0x6BCDF07A, 0x423AA96B), /* ~= 10^-127 */
1455 U64(0xAD4AB711, 0x2EB3929D), U64(0x86C16C98, 0xD2C953C6), /* ~= 10^-126 */
1456 U64(0xD89D64D5, 0x7A607744), U64(0xE871C7BF, 0x077BA8B7), /* ~= 10^-125 */
1457 U64(0x87625F05, 0x6C7C4A8B), U64(0x11471CD7, 0x64AD4972), /* ~= 10^-124 */
1458 U64(0xA93AF6C6, 0xC79B5D2D), U64(0xD598E40D, 0x3DD89BCF), /* ~= 10^-123 */
1459 U64(0xD389B478, 0x79823479), U64(0x4AFF1D10, 0x8D4EC2C3), /* ~= 10^-122 */
1460 U64(0x843610CB, 0x4BF160CB), U64(0xCEDF722A, 0x585139BA), /* ~= 10^-121 */
1461 U64(0xA54394FE, 0x1EEDB8FE), U64(0xC2974EB4, 0xEE658828), /* ~= 10^-120 */
1462 U64(0xCE947A3D, 0xA6A9273E), U64(0x733D2262, 0x29FEEA32), /* ~= 10^-119 */
1463 U64(0x811CCC66, 0x8829B887), U64(0x0806357D, 0x5A3F525F), /* ~= 10^-118 */
1464 U64(0xA163FF80, 0x2A3426A8), U64(0xCA07C2DC, 0xB0CF26F7), /* ~= 10^-117 */
1465 U64(0xC9BCFF60, 0x34C13052), U64(0xFC89B393, 0xDD02F0B5), /* ~= 10^-116 */
1466 U64(0xFC2C3F38, 0x41F17C67), U64(0xBBAC2078, 0xD443ACE2), /* ~= 10^-115 */
1467 U64(0x9D9BA783, 0x2936EDC0), U64(0xD54B944B, 0x84AA4C0D), /* ~= 10^-114 */
1468 U64(0xC5029163, 0xF384A931), U64(0x0A9E795E, 0x65D4DF11), /* ~= 10^-113 */
1469 U64(0xF64335BC, 0xF065D37D), U64(0x4D4617B5, 0xFF4A16D5), /* ~= 10^-112 */
1470 U64(0x99EA0196, 0x163FA42E), U64(0x504BCED1, 0xBF8E4E45), /* ~= 10^-111 */
1471 U64(0xC06481FB, 0x9BCF8D39), U64(0xE45EC286, 0x2F71E1D6), /* ~= 10^-110 */
1472 U64(0xF07DA27A, 0x82C37088), U64(0x5D767327, 0xBB4E5A4C), /* ~= 10^-109 */
1473 U64(0x964E858C, 0x91BA2655), U64(0x3A6A07F8, 0xD510F86F), /* ~= 10^-108 */
1474 U64(0xBBE226EF, 0xB628AFEA), U64(0x890489F7, 0x0A55368B), /* ~= 10^-107 */
1475 U64(0xEADAB0AB, 0xA3B2DBE5), U64(0x2B45AC74, 0xCCEA842E), /* ~= 10^-106 */
1476 U64(0x92C8AE6B, 0x464FC96F), U64(0x3B0B8BC9, 0x0012929D), /* ~= 10^-105 */
1477 U64(0xB77ADA06, 0x17E3BBCB), U64(0x09CE6EBB, 0x40173744), /* ~= 10^-104 */
1478 U64(0xE5599087, 0x9DDCAABD), U64(0xCC420A6A, 0x101D0515), /* ~= 10^-103 */
1479 U64(0x8F57FA54, 0xC2A9EAB6), U64(0x9FA94682, 0x4A12232D), /* ~= 10^-102 */
1480 U64(0xB32DF8E9, 0xF3546564), U64(0x47939822, 0xDC96ABF9), /* ~= 10^-101 */
1481 U64(0xDFF97724, 0x70297EBD), U64(0x59787E2B, 0x93BC56F7), /* ~= 10^-100 */
1482 U64(0x8BFBEA76, 0xC619EF36), U64(0x57EB4EDB, 0x3C55B65A), /* ~= 10^-99 */
1483 U64(0xAEFAE514, 0x77A06B03), U64(0xEDE62292, 0x0B6B23F1), /* ~= 10^-98 */
1484 U64(0xDAB99E59, 0x958885C4), U64(0xE95FAB36, 0x8E45ECED), /* ~= 10^-97 */
1485 U64(0x88B402F7, 0xFD75539B), U64(0x11DBCB02, 0x18EBB414), /* ~= 10^-96 */
1486 U64(0xAAE103B5, 0xFCD2A881), U64(0xD652BDC2, 0x9F26A119), /* ~= 10^-95 */
1487 U64(0xD59944A3, 0x7C0752A2), U64(0x4BE76D33, 0x46F0495F), /* ~= 10^-94 */
1488 U64(0x857FCAE6, 0x2D8493A5), U64(0x6F70A440, 0x0C562DDB), /* ~= 10^-93 */
1489 U64(0xA6DFBD9F, 0xB8E5B88E), U64(0xCB4CCD50, 0x0F6BB952), /* ~= 10^-92 */
1490 U64(0xD097AD07, 0xA71F26B2), U64(0x7E2000A4, 0x1346A7A7), /* ~= 10^-91 */
1491 U64(0x825ECC24, 0xC873782F), U64(0x8ED40066, 0x8C0C28C8), /* ~= 10^-90 */
1492 U64(0xA2F67F2D, 0xFA90563B), U64(0x72890080, 0x2F0F32FA), /* ~= 10^-89 */
1493 U64(0xCBB41EF9, 0x79346BCA), U64(0x4F2B40A0, 0x3AD2FFB9), /* ~= 10^-88 */
1494 U64(0xFEA126B7, 0xD78186BC), U64(0xE2F610C8, 0x4987BFA8), /* ~= 10^-87 */
1495 U64(0x9F24B832, 0xE6B0F436), U64(0x0DD9CA7D, 0x2DF4D7C9), /* ~= 10^-86 */
1496 U64(0xC6EDE63F, 0xA05D3143), U64(0x91503D1C, 0x79720DBB), /* ~= 10^-85 */
1497 U64(0xF8A95FCF, 0x88747D94), U64(0x75A44C63, 0x97CE912A), /* ~= 10^-84 */
1498 U64(0x9B69DBE1, 0xB548CE7C), U64(0xC986AFBE, 0x3EE11ABA), /* ~= 10^-83 */
1499 U64(0xC24452DA, 0x229B021B), U64(0xFBE85BAD, 0xCE996168), /* ~= 10^-82 */
1500 U64(0xF2D56790, 0xAB41C2A2), U64(0xFAE27299, 0x423FB9C3), /* ~= 10^-81 */
1501 U64(0x97C560BA, 0x6B0919A5), U64(0xDCCD879F, 0xC967D41A), /* ~= 10^-80 */
1502 U64(0xBDB6B8E9, 0x05CB600F), U64(0x5400E987, 0xBBC1C920), /* ~= 10^-79 */
1503 U64(0xED246723, 0x473E3813), U64(0x290123E9, 0xAAB23B68), /* ~= 10^-78 */
1504 U64(0x9436C076, 0x0C86E30B), U64(0xF9A0B672, 0x0AAF6521), /* ~= 10^-77 */
1505 U64(0xB9447093, 0x8FA89BCE), U64(0xF808E40E, 0x8D5B3E69), /* ~= 10^-76 */
1506 U64(0xE7958CB8, 0x7392C2C2), U64(0xB60B1D12, 0x30B20E04), /* ~= 10^-75 */
1507 U64(0x90BD77F3, 0x483BB9B9), U64(0xB1C6F22B, 0x5E6F48C2), /* ~= 10^-74 */
1508 U64(0xB4ECD5F0, 0x1A4AA828), U64(0x1E38AEB6, 0x360B1AF3), /* ~= 10^-73 */
1509 U64(0xE2280B6C, 0x20DD5232), U64(0x25C6DA63, 0xC38DE1B0), /* ~= 10^-72 */
1510 U64(0x8D590723, 0x948A535F), U64(0x579C487E, 0x5A38AD0E), /* ~= 10^-71 */
1511 U64(0xB0AF48EC, 0x79ACE837), U64(0x2D835A9D, 0xF0C6D851), /* ~= 10^-70 */
1512 U64(0xDCDB1B27, 0x98182244), U64(0xF8E43145, 0x6CF88E65), /* ~= 10^-69 */
1513 U64(0x8A08F0F8, 0xBF0F156B), U64(0x1B8E9ECB, 0x641B58FF), /* ~= 10^-68 */
1514 U64(0xAC8B2D36, 0xEED2DAC5), U64(0xE272467E, 0x3D222F3F), /* ~= 10^-67 */
1515 U64(0xD7ADF884, 0xAA879177), U64(0x5B0ED81D, 0xCC6ABB0F), /* ~= 10^-66 */
1516 U64(0x86CCBB52, 0xEA94BAEA), U64(0x98E94712, 0x9FC2B4E9), /* ~= 10^-65 */
1517 U64(0xA87FEA27, 0xA539E9A5), U64(0x3F2398D7, 0x47B36224), /* ~= 10^-64 */
1518 U64(0xD29FE4B1, 0x8E88640E), U64(0x8EEC7F0D, 0x19A03AAD), /* ~= 10^-63 */
1519 U64(0x83A3EEEE, 0xF9153E89), U64(0x1953CF68, 0x300424AC), /* ~= 10^-62 */
1520 U64(0xA48CEAAA, 0xB75A8E2B), U64(0x5FA8C342, 0x3C052DD7), /* ~= 10^-61 */
1521 U64(0xCDB02555, 0x653131B6), U64(0x3792F412, 0xCB06794D), /* ~= 10^-60 */
1522 U64(0x808E1755, 0x5F3EBF11), U64(0xE2BBD88B, 0xBEE40BD0), /* ~= 10^-59 */
1523 U64(0xA0B19D2A, 0xB70E6ED6), U64(0x5B6ACEAE, 0xAE9D0EC4), /* ~= 10^-58 */
1524 U64(0xC8DE0475, 0x64D20A8B), U64(0xF245825A, 0x5A445275), /* ~= 10^-57 */
1525 U64(0xFB158592, 0xBE068D2E), U64(0xEED6E2F0, 0xF0D56712), /* ~= 10^-56 */
1526 U64(0x9CED737B, 0xB6C4183D), U64(0x55464DD6, 0x9685606B), /* ~= 10^-55 */
1527 U64(0xC428D05A, 0xA4751E4C), U64(0xAA97E14C, 0x3C26B886), /* ~= 10^-54 */
1528 U64(0xF5330471, 0x4D9265DF), U64(0xD53DD99F, 0x4B3066A8), /* ~= 10^-53 */
1529 U64(0x993FE2C6, 0xD07B7FAB), U64(0xE546A803, 0x8EFE4029), /* ~= 10^-52 */
1530 U64(0xBF8FDB78, 0x849A5F96), U64(0xDE985204, 0x72BDD033), /* ~= 10^-51 */
1531 U64(0xEF73D256, 0xA5C0F77C), U64(0x963E6685, 0x8F6D4440), /* ~= 10^-50 */
1532 U64(0x95A86376, 0x27989AAD), U64(0xDDE70013, 0x79A44AA8), /* ~= 10^-49 */
1533 U64(0xBB127C53, 0xB17EC159), U64(0x5560C018, 0x580D5D52), /* ~= 10^-48 */
1534 U64(0xE9D71B68, 0x9DDE71AF), U64(0xAAB8F01E, 0x6E10B4A6), /* ~= 10^-47 */
1535 U64(0x92267121, 0x62AB070D), U64(0xCAB39613, 0x04CA70E8), /* ~= 10^-46 */
1536 U64(0xB6B00D69, 0xBB55C8D1), U64(0x3D607B97, 0xC5FD0D22), /* ~= 10^-45 */
1537 U64(0xE45C10C4, 0x2A2B3B05), U64(0x8CB89A7D, 0xB77C506A), /* ~= 10^-44 */
1538 U64(0x8EB98A7A, 0x9A5B04E3), U64(0x77F3608E, 0x92ADB242), /* ~= 10^-43 */
1539 U64(0xB267ED19, 0x40F1C61C), U64(0x55F038B2, 0x37591ED3), /* ~= 10^-42 */
1540 U64(0xDF01E85F, 0x912E37A3), U64(0x6B6C46DE, 0xC52F6688), /* ~= 10^-41 */
1541 U64(0x8B61313B, 0xBABCE2C6), U64(0x2323AC4B, 0x3B3DA015), /* ~= 10^-40 */
1542 U64(0xAE397D8A, 0xA96C1B77), U64(0xABEC975E, 0x0A0D081A), /* ~= 10^-39 */
1543 U64(0xD9C7DCED, 0x53C72255), U64(0x96E7BD35, 0x8C904A21), /* ~= 10^-38 */
1544 U64(0x881CEA14, 0x545C7575), U64(0x7E50D641, 0x77DA2E54), /* ~= 10^-37 */
1545 U64(0xAA242499, 0x697392D2), U64(0xDDE50BD1, 0xD5D0B9E9), /* ~= 10^-36 */
1546 U64(0xD4AD2DBF, 0xC3D07787), U64(0x955E4EC6, 0x4B44E864), /* ~= 10^-35 */
1547 U64(0x84EC3C97, 0xDA624AB4), U64(0xBD5AF13B, 0xEF0B113E), /* ~= 10^-34 */
1548 U64(0xA6274BBD, 0xD0FADD61), U64(0xECB1AD8A, 0xEACDD58E), /* ~= 10^-33 */
1549 U64(0xCFB11EAD, 0x453994BA), U64(0x67DE18ED, 0xA5814AF2), /* ~= 10^-32 */
1550 U64(0x81CEB32C, 0x4B43FCF4), U64(0x80EACF94, 0x8770CED7), /* ~= 10^-31 */
1551 U64(0xA2425FF7, 0x5E14FC31), U64(0xA1258379, 0xA94D028D), /* ~= 10^-30 */
1552 U64(0xCAD2F7F5, 0x359A3B3E), U64(0x096EE458, 0x13A04330), /* ~= 10^-29 */
1553 U64(0xFD87B5F2, 0x8300CA0D), U64(0x8BCA9D6E, 0x188853FC), /* ~= 10^-28 */
1554 U64(0x9E74D1B7, 0x91E07E48), U64(0x775EA264, 0xCF55347D), /* ~= 10^-27 */
1555 U64(0xC6120625, 0x76589DDA), U64(0x95364AFE, 0x032A819D), /* ~= 10^-26 */
1556 U64(0xF79687AE, 0xD3EEC551), U64(0x3A83DDBD, 0x83F52204), /* ~= 10^-25 */
1557 U64(0x9ABE14CD, 0x44753B52), U64(0xC4926A96, 0x72793542), /* ~= 10^-24 */
1558 U64(0xC16D9A00, 0x95928A27), U64(0x75B7053C, 0x0F178293), /* ~= 10^-23 */
1559 U64(0xF1C90080, 0xBAF72CB1), U64(0x5324C68B, 0x12DD6338), /* ~= 10^-22 */
1560 U64(0x971DA050, 0x74DA7BEE), U64(0xD3F6FC16, 0xEBCA5E03), /* ~= 10^-21 */
1561 U64(0xBCE50864, 0x92111AEA), U64(0x88F4BB1C, 0xA6BCF584), /* ~= 10^-20 */
1562 U64(0xEC1E4A7D, 0xB69561A5), U64(0x2B31E9E3, 0xD06C32E5), /* ~= 10^-19 */
1563 U64(0x9392EE8E, 0x921D5D07), U64(0x3AFF322E, 0x62439FCF), /* ~= 10^-18 */
1564 U64(0xB877AA32, 0x36A4B449), U64(0x09BEFEB9, 0xFAD487C2), /* ~= 10^-17 */
1565 U64(0xE69594BE, 0xC44DE15B), U64(0x4C2EBE68, 0x7989A9B3), /* ~= 10^-16 */
1566 U64(0x901D7CF7, 0x3AB0ACD9), U64(0x0F9D3701, 0x4BF60A10), /* ~= 10^-15 */
1567 U64(0xB424DC35, 0x095CD80F), U64(0x538484C1, 0x9EF38C94), /* ~= 10^-14 */
1568 U64(0xE12E1342, 0x4BB40E13), U64(0x2865A5F2, 0x06B06FB9), /* ~= 10^-13 */
1569 U64(0x8CBCCC09, 0x6F5088CB), U64(0xF93F87B7, 0x442E45D3), /* ~= 10^-12 */
1570 U64(0xAFEBFF0B, 0xCB24AAFE), U64(0xF78F69A5, 0x1539D748), /* ~= 10^-11 */
1571 U64(0xDBE6FECE, 0xBDEDD5BE), U64(0xB573440E, 0x5A884D1B), /* ~= 10^-10 */
1572 U64(0x89705F41, 0x36B4A597), U64(0x31680A88, 0xF8953030), /* ~= 10^-9 */
1573 U64(0xABCC7711, 0x8461CEFC), U64(0xFDC20D2B, 0x36BA7C3D), /* ~= 10^-8 */
1574 U64(0xD6BF94D5, 0xE57A42BC), U64(0x3D329076, 0x04691B4C), /* ~= 10^-7 */
1575 U64(0x8637BD05, 0xAF6C69B5), U64(0xA63F9A49, 0xC2C1B10F), /* ~= 10^-6 */
1576 U64(0xA7C5AC47, 0x1B478423), U64(0x0FCF80DC, 0x33721D53), /* ~= 10^-5 */
1577 U64(0xD1B71758, 0xE219652B), U64(0xD3C36113, 0x404EA4A8), /* ~= 10^-4 */
1578 U64(0x83126E97, 0x8D4FDF3B), U64(0x645A1CAC, 0x083126E9), /* ~= 10^-3 */
1579 U64(0xA3D70A3D, 0x70A3D70A), U64(0x3D70A3D7, 0x0A3D70A3), /* ~= 10^-2 */
1580 U64(0xCCCCCCCC, 0xCCCCCCCC), U64(0xCCCCCCCC, 0xCCCCCCCC), /* ~= 10^-1 */
1581 U64(0x80000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^0 */
1582 U64(0xA0000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^1 */
1583 U64(0xC8000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^2 */
1584 U64(0xFA000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^3 */
1585 U64(0x9C400000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^4 */
1586 U64(0xC3500000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^5 */
1587 U64(0xF4240000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^6 */
1588 U64(0x98968000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^7 */
1589 U64(0xBEBC2000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^8 */
1590 U64(0xEE6B2800, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^9 */
1591 U64(0x9502F900, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^10 */
1592 U64(0xBA43B740, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^11 */
1593 U64(0xE8D4A510, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^12 */
1594 U64(0x9184E72A, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^13 */
1595 U64(0xB5E620F4, 0x80000000), U64(0x00000000, 0x00000000), /* == 10^14 */
1596 U64(0xE35FA931, 0xA0000000), U64(0x00000000, 0x00000000), /* == 10^15 */
1597 U64(0x8E1BC9BF, 0x04000000), U64(0x00000000, 0x00000000), /* == 10^16 */
1598 U64(0xB1A2BC2E, 0xC5000000), U64(0x00000000, 0x00000000), /* == 10^17 */
1599 U64(0xDE0B6B3A, 0x76400000), U64(0x00000000, 0x00000000), /* == 10^18 */
1600 U64(0x8AC72304, 0x89E80000), U64(0x00000000, 0x00000000), /* == 10^19 */
1601 U64(0xAD78EBC5, 0xAC620000), U64(0x00000000, 0x00000000), /* == 10^20 */
1602 U64(0xD8D726B7, 0x177A8000), U64(0x00000000, 0x00000000), /* == 10^21 */
1603 U64(0x87867832, 0x6EAC9000), U64(0x00000000, 0x00000000), /* == 10^22 */
1604 U64(0xA968163F, 0x0A57B400), U64(0x00000000, 0x00000000), /* == 10^23 */
1605 U64(0xD3C21BCE, 0xCCEDA100), U64(0x00000000, 0x00000000), /* == 10^24 */
1606 U64(0x84595161, 0x401484A0), U64(0x00000000, 0x00000000), /* == 10^25 */
1607 U64(0xA56FA5B9, 0x9019A5C8), U64(0x00000000, 0x00000000), /* == 10^26 */
1608 U64(0xCECB8F27, 0xF4200F3A), U64(0x00000000, 0x00000000), /* == 10^27 */
1609 U64(0x813F3978, 0xF8940984), U64(0x40000000, 0x00000000), /* == 10^28 */
1610 U64(0xA18F07D7, 0x36B90BE5), U64(0x50000000, 0x00000000), /* == 10^29 */
1611 U64(0xC9F2C9CD, 0x04674EDE), U64(0xA4000000, 0x00000000), /* == 10^30 */
1612 U64(0xFC6F7C40, 0x45812296), U64(0x4D000000, 0x00000000), /* == 10^31 */
1613 U64(0x9DC5ADA8, 0x2B70B59D), U64(0xF0200000, 0x00000000), /* == 10^32 */
1614 U64(0xC5371912, 0x364CE305), U64(0x6C280000, 0x00000000), /* == 10^33 */
1615 U64(0xF684DF56, 0xC3E01BC6), U64(0xC7320000, 0x00000000), /* == 10^34 */
1616 U64(0x9A130B96, 0x3A6C115C), U64(0x3C7F4000, 0x00000000), /* == 10^35 */
1617 U64(0xC097CE7B, 0xC90715B3), U64(0x4B9F1000, 0x00000000), /* == 10^36 */
1618 U64(0xF0BDC21A, 0xBB48DB20), U64(0x1E86D400, 0x00000000), /* == 10^37 */
1619 U64(0x96769950, 0xB50D88F4), U64(0x13144480, 0x00000000), /* == 10^38 */
1620 U64(0xBC143FA4, 0xE250EB31), U64(0x17D955A0, 0x00000000), /* == 10^39 */
1621 U64(0xEB194F8E, 0x1AE525FD), U64(0x5DCFAB08, 0x00000000), /* == 10^40 */
1622 U64(0x92EFD1B8, 0xD0CF37BE), U64(0x5AA1CAE5, 0x00000000), /* == 10^41 */
1623 U64(0xB7ABC627, 0x050305AD), U64(0xF14A3D9E, 0x40000000), /* == 10^42 */
1624 U64(0xE596B7B0, 0xC643C719), U64(0x6D9CCD05, 0xD0000000), /* == 10^43 */
1625 U64(0x8F7E32CE, 0x7BEA5C6F), U64(0xE4820023, 0xA2000000), /* == 10^44 */
1626 U64(0xB35DBF82, 0x1AE4F38B), U64(0xDDA2802C, 0x8A800000), /* == 10^45 */
1627 U64(0xE0352F62, 0xA19E306E), U64(0xD50B2037, 0xAD200000), /* == 10^46 */
1628 U64(0x8C213D9D, 0xA502DE45), U64(0x4526F422, 0xCC340000), /* == 10^47 */
1629 U64(0xAF298D05, 0x0E4395D6), U64(0x9670B12B, 0x7F410000), /* == 10^48 */
1630 U64(0xDAF3F046, 0x51D47B4C), U64(0x3C0CDD76, 0x5F114000), /* == 10^49 */
1631 U64(0x88D8762B, 0xF324CD0F), U64(0xA5880A69, 0xFB6AC800), /* == 10^50 */
1632 U64(0xAB0E93B6, 0xEFEE0053), U64(0x8EEA0D04, 0x7A457A00), /* == 10^51 */
1633 U64(0xD5D238A4, 0xABE98068), U64(0x72A49045, 0x98D6D880), /* == 10^52 */
1634 U64(0x85A36366, 0xEB71F041), U64(0x47A6DA2B, 0x7F864750), /* == 10^53 */
1635 U64(0xA70C3C40, 0xA64E6C51), U64(0x999090B6, 0x5F67D924), /* == 10^54 */
1636 U64(0xD0CF4B50, 0xCFE20765), U64(0xFFF4B4E3, 0xF741CF6D), /* == 10^55 */
1637 U64(0x82818F12, 0x81ED449F), U64(0xBFF8F10E, 0x7A8921A4), /* ~= 10^56 */
1638 U64(0xA321F2D7, 0x226895C7), U64(0xAFF72D52, 0x192B6A0D), /* ~= 10^57 */
1639 U64(0xCBEA6F8C, 0xEB02BB39), U64(0x9BF4F8A6, 0x9F764490), /* ~= 10^58 */
1640 U64(0xFEE50B70, 0x25C36A08), U64(0x02F236D0, 0x4753D5B4), /* ~= 10^59 */
1641 U64(0x9F4F2726, 0x179A2245), U64(0x01D76242, 0x2C946590), /* ~= 10^60 */
1642 U64(0xC722F0EF, 0x9D80AAD6), U64(0x424D3AD2, 0xB7B97EF5), /* ~= 10^61 */
1643 U64(0xF8EBAD2B, 0x84E0D58B), U64(0xD2E08987, 0x65A7DEB2), /* ~= 10^62 */
1644 U64(0x9B934C3B, 0x330C8577), U64(0x63CC55F4, 0x9F88EB2F), /* ~= 10^63 */
1645 U64(0xC2781F49, 0xFFCFA6D5), U64(0x3CBF6B71, 0xC76B25FB), /* ~= 10^64 */
1646 U64(0xF316271C, 0x7FC3908A), U64(0x8BEF464E, 0x3945EF7A), /* ~= 10^65 */
1647 U64(0x97EDD871, 0xCFDA3A56), U64(0x97758BF0, 0xE3CBB5AC), /* ~= 10^66 */
1648 U64(0xBDE94E8E, 0x43D0C8EC), U64(0x3D52EEED, 0x1CBEA317), /* ~= 10^67 */
1649 U64(0xED63A231, 0xD4C4FB27), U64(0x4CA7AAA8, 0x63EE4BDD), /* ~= 10^68 */
1650 U64(0x945E455F, 0x24FB1CF8), U64(0x8FE8CAA9, 0x3E74EF6A), /* ~= 10^69 */
1651 U64(0xB975D6B6, 0xEE39E436), U64(0xB3E2FD53, 0x8E122B44), /* ~= 10^70 */
1652 U64(0xE7D34C64, 0xA9C85D44), U64(0x60DBBCA8, 0x7196B616), /* ~= 10^71 */
1653 U64(0x90E40FBE, 0xEA1D3A4A), U64(0xBC8955E9, 0x46FE31CD), /* ~= 10^72 */
1654 U64(0xB51D13AE, 0xA4A488DD), U64(0x6BABAB63, 0x98BDBE41), /* ~= 10^73 */
1655 U64(0xE264589A, 0x4DCDAB14), U64(0xC696963C, 0x7EED2DD1), /* ~= 10^74 */
1656 U64(0x8D7EB760, 0x70A08AEC), U64(0xFC1E1DE5, 0xCF543CA2), /* ~= 10^75 */
1657 U64(0xB0DE6538, 0x8CC8ADA8), U64(0x3B25A55F, 0x43294BCB), /* ~= 10^76 */
1658 U64(0xDD15FE86, 0xAFFAD912), U64(0x49EF0EB7, 0x13F39EBE), /* ~= 10^77 */
1659 U64(0x8A2DBF14, 0x2DFCC7AB), U64(0x6E356932, 0x6C784337), /* ~= 10^78 */
1660 U64(0xACB92ED9, 0x397BF996), U64(0x49C2C37F, 0x07965404), /* ~= 10^79 */
1661 U64(0xD7E77A8F, 0x87DAF7FB), U64(0xDC33745E, 0xC97BE906), /* ~= 10^80 */
1662 U64(0x86F0AC99, 0xB4E8DAFD), U64(0x69A028BB, 0x3DED71A3), /* ~= 10^81 */
1663 U64(0xA8ACD7C0, 0x222311BC), U64(0xC40832EA, 0x0D68CE0C), /* ~= 10^82 */
1664 U64(0xD2D80DB0, 0x2AABD62B), U64(0xF50A3FA4, 0x90C30190), /* ~= 10^83 */
1665 U64(0x83C7088E, 0x1AAB65DB), U64(0x792667C6, 0xDA79E0FA), /* ~= 10^84 */
1666 U64(0xA4B8CAB1, 0xA1563F52), U64(0x577001B8, 0x91185938), /* ~= 10^85 */
1667 U64(0xCDE6FD5E, 0x09ABCF26), U64(0xED4C0226, 0xB55E6F86), /* ~= 10^86 */
1668 U64(0x80B05E5A, 0xC60B6178), U64(0x544F8158, 0x315B05B4), /* ~= 10^87 */
1669 U64(0xA0DC75F1, 0x778E39D6), U64(0x696361AE, 0x3DB1C721), /* ~= 10^88 */
1670 U64(0xC913936D, 0xD571C84C), U64(0x03BC3A19, 0xCD1E38E9), /* ~= 10^89 */
1671 U64(0xFB587849, 0x4ACE3A5F), U64(0x04AB48A0, 0x4065C723), /* ~= 10^90 */
1672 U64(0x9D174B2D, 0xCEC0E47B), U64(0x62EB0D64, 0x283F9C76), /* ~= 10^91 */
1673 U64(0xC45D1DF9, 0x42711D9A), U64(0x3BA5D0BD, 0x324F8394), /* ~= 10^92 */
1674 U64(0xF5746577, 0x930D6500), U64(0xCA8F44EC, 0x7EE36479), /* ~= 10^93 */
1675 U64(0x9968BF6A, 0xBBE85F20), U64(0x7E998B13, 0xCF4E1ECB), /* ~= 10^94 */
1676 U64(0xBFC2EF45, 0x6AE276E8), U64(0x9E3FEDD8, 0xC321A67E), /* ~= 10^95 */
1677 U64(0xEFB3AB16, 0xC59B14A2), U64(0xC5CFE94E, 0xF3EA101E), /* ~= 10^96 */
1678 U64(0x95D04AEE, 0x3B80ECE5), U64(0xBBA1F1D1, 0x58724A12), /* ~= 10^97 */
1679 U64(0xBB445DA9, 0xCA61281F), U64(0x2A8A6E45, 0xAE8EDC97), /* ~= 10^98 */
1680 U64(0xEA157514, 0x3CF97226), U64(0xF52D09D7, 0x1A3293BD), /* ~= 10^99 */
1681 U64(0x924D692C, 0xA61BE758), U64(0x593C2626, 0x705F9C56), /* ~= 10^100 */
1682 U64(0xB6E0C377, 0xCFA2E12E), U64(0x6F8B2FB0, 0x0C77836C), /* ~= 10^101 */
1683 U64(0xE498F455, 0xC38B997A), U64(0x0B6DFB9C, 0x0F956447), /* ~= 10^102 */
1684 U64(0x8EDF98B5, 0x9A373FEC), U64(0x4724BD41, 0x89BD5EAC), /* ~= 10^103 */
1685 U64(0xB2977EE3, 0x00C50FE7), U64(0x58EDEC91, 0xEC2CB657), /* ~= 10^104 */
1686 U64(0xDF3D5E9B, 0xC0F653E1), U64(0x2F2967B6, 0x6737E3ED), /* ~= 10^105 */
1687 U64(0x8B865B21, 0x5899F46C), U64(0xBD79E0D2, 0x0082EE74), /* ~= 10^106 */
1688 U64(0xAE67F1E9, 0xAEC07187), U64(0xECD85906, 0x80A3AA11), /* ~= 10^107 */
1689 U64(0xDA01EE64, 0x1A708DE9), U64(0xE80E6F48, 0x20CC9495), /* ~= 10^108 */
1690 U64(0x884134FE, 0x908658B2), U64(0x3109058D, 0x147FDCDD), /* ~= 10^109 */
1691 U64(0xAA51823E, 0x34A7EEDE), U64(0xBD4B46F0, 0x599FD415), /* ~= 10^110 */
1692 U64(0xD4E5E2CD, 0xC1D1EA96), U64(0x6C9E18AC, 0x7007C91A), /* ~= 10^111 */
1693 U64(0x850FADC0, 0x9923329E), U64(0x03E2CF6B, 0xC604DDB0), /* ~= 10^112 */
1694 U64(0xA6539930, 0xBF6BFF45), U64(0x84DB8346, 0xB786151C), /* ~= 10^113 */
1695 U64(0xCFE87F7C, 0xEF46FF16), U64(0xE6126418, 0x65679A63), /* ~= 10^114 */
1696 U64(0x81F14FAE, 0x158C5F6E), U64(0x4FCB7E8F, 0x3F60C07E), /* ~= 10^115 */
1697 U64(0xA26DA399, 0x9AEF7749), U64(0xE3BE5E33, 0x0F38F09D), /* ~= 10^116 */
1698 U64(0xCB090C80, 0x01AB551C), U64(0x5CADF5BF, 0xD3072CC5), /* ~= 10^117 */
1699 U64(0xFDCB4FA0, 0x02162A63), U64(0x73D9732F, 0xC7C8F7F6), /* ~= 10^118 */
1700 U64(0x9E9F11C4, 0x014DDA7E), U64(0x2867E7FD, 0xDCDD9AFA), /* ~= 10^119 */
1701 U64(0xC646D635, 0x01A1511D), U64(0xB281E1FD, 0x541501B8), /* ~= 10^120 */
1702 U64(0xF7D88BC2, 0x4209A565), U64(0x1F225A7C, 0xA91A4226), /* ~= 10^121 */
1703 U64(0x9AE75759, 0x6946075F), U64(0x3375788D, 0xE9B06958), /* ~= 10^122 */
1704 U64(0xC1A12D2F, 0xC3978937), U64(0x0052D6B1, 0x641C83AE), /* ~= 10^123 */
1705 U64(0xF209787B, 0xB47D6B84), U64(0xC0678C5D, 0xBD23A49A), /* ~= 10^124 */
1706 U64(0x9745EB4D, 0x50CE6332), U64(0xF840B7BA, 0x963646E0), /* ~= 10^125 */
1707 U64(0xBD176620, 0xA501FBFF), U64(0xB650E5A9, 0x3BC3D898), /* ~= 10^126 */
1708 U64(0xEC5D3FA8, 0xCE427AFF), U64(0xA3E51F13, 0x8AB4CEBE), /* ~= 10^127 */
1709 U64(0x93BA47C9, 0x80E98CDF), U64(0xC66F336C, 0x36B10137), /* ~= 10^128 */
1710 U64(0xB8A8D9BB, 0xE123F017), U64(0xB80B0047, 0x445D4184), /* ~= 10^129 */
1711 U64(0xE6D3102A, 0xD96CEC1D), U64(0xA60DC059, 0x157491E5), /* ~= 10^130 */
1712 U64(0x9043EA1A, 0xC7E41392), U64(0x87C89837, 0xAD68DB2F), /* ~= 10^131 */
1713 U64(0xB454E4A1, 0x79DD1877), U64(0x29BABE45, 0x98C311FB), /* ~= 10^132 */
1714 U64(0xE16A1DC9, 0xD8545E94), U64(0xF4296DD6, 0xFEF3D67A), /* ~= 10^133 */
1715 U64(0x8CE2529E, 0x2734BB1D), U64(0x1899E4A6, 0x5F58660C), /* ~= 10^134 */
1716 U64(0xB01AE745, 0xB101E9E4), U64(0x5EC05DCF, 0xF72E7F8F), /* ~= 10^135 */
1717 U64(0xDC21A117, 0x1D42645D), U64(0x76707543, 0xF4FA1F73), /* ~= 10^136 */
1718 U64(0x899504AE, 0x72497EBA), U64(0x6A06494A, 0x791C53A8), /* ~= 10^137 */
1719 U64(0xABFA45DA, 0x0EDBDE69), U64(0x0487DB9D, 0x17636892), /* ~= 10^138 */
1720 U64(0xD6F8D750, 0x9292D603), U64(0x45A9D284, 0x5D3C42B6), /* ~= 10^139 */
1721 U64(0x865B8692, 0x5B9BC5C2), U64(0x0B8A2392, 0xBA45A9B2), /* ~= 10^140 */
1722 U64(0xA7F26836, 0xF282B732), U64(0x8E6CAC77, 0x68D7141E), /* ~= 10^141 */
1723 U64(0xD1EF0244, 0xAF2364FF), U64(0x3207D795, 0x430CD926), /* ~= 10^142 */
1724 U64(0x8335616A, 0xED761F1F), U64(0x7F44E6BD, 0x49E807B8), /* ~= 10^143 */
1725 U64(0xA402B9C5, 0xA8D3A6E7), U64(0x5F16206C, 0x9C6209A6), /* ~= 10^144 */
1726 U64(0xCD036837, 0x130890A1), U64(0x36DBA887, 0xC37A8C0F), /* ~= 10^145 */
1727 U64(0x80222122, 0x6BE55A64), U64(0xC2494954, 0xDA2C9789), /* ~= 10^146 */
1728 U64(0xA02AA96B, 0x06DEB0FD), U64(0xF2DB9BAA, 0x10B7BD6C), /* ~= 10^147 */
1729 U64(0xC83553C5, 0xC8965D3D), U64(0x6F928294, 0x94E5ACC7), /* ~= 10^148 */
1730 U64(0xFA42A8B7, 0x3ABBF48C), U64(0xCB772339, 0xBA1F17F9), /* ~= 10^149 */
1731 U64(0x9C69A972, 0x84B578D7), U64(0xFF2A7604, 0x14536EFB), /* ~= 10^150 */
1732 U64(0xC38413CF, 0x25E2D70D), U64(0xFEF51385, 0x19684ABA), /* ~= 10^151 */
1733 U64(0xF46518C2, 0xEF5B8CD1), U64(0x7EB25866, 0x5FC25D69), /* ~= 10^152 */
1734 U64(0x98BF2F79, 0xD5993802), U64(0xEF2F773F, 0xFBD97A61), /* ~= 10^153 */
1735 U64(0xBEEEFB58, 0x4AFF8603), U64(0xAAFB550F, 0xFACFD8FA), /* ~= 10^154 */
1736 U64(0xEEAABA2E, 0x5DBF6784), U64(0x95BA2A53, 0xF983CF38), /* ~= 10^155 */
1737 U64(0x952AB45C, 0xFA97A0B2), U64(0xDD945A74, 0x7BF26183), /* ~= 10^156 */
1738 U64(0xBA756174, 0x393D88DF), U64(0x94F97111, 0x9AEEF9E4), /* ~= 10^157 */
1739 U64(0xE912B9D1, 0x478CEB17), U64(0x7A37CD56, 0x01AAB85D), /* ~= 10^158 */
1740 U64(0x91ABB422, 0xCCB812EE), U64(0xAC62E055, 0xC10AB33A), /* ~= 10^159 */
1741 U64(0xB616A12B, 0x7FE617AA), U64(0x577B986B, 0x314D6009), /* ~= 10^160 */
1742 U64(0xE39C4976, 0x5FDF9D94), U64(0xED5A7E85, 0xFDA0B80B), /* ~= 10^161 */
1743 U64(0x8E41ADE9, 0xFBEBC27D), U64(0x14588F13, 0xBE847307), /* ~= 10^162 */
1744 U64(0xB1D21964, 0x7AE6B31C), U64(0x596EB2D8, 0xAE258FC8), /* ~= 10^163 */
1745 U64(0xDE469FBD, 0x99A05FE3), U64(0x6FCA5F8E, 0xD9AEF3BB), /* ~= 10^164 */
1746 U64(0x8AEC23D6, 0x80043BEE), U64(0x25DE7BB9, 0x480D5854), /* ~= 10^165 */
1747 U64(0xADA72CCC, 0x20054AE9), U64(0xAF561AA7, 0x9A10AE6A), /* ~= 10^166 */
1748 U64(0xD910F7FF, 0x28069DA4), U64(0x1B2BA151, 0x8094DA04), /* ~= 10^167 */
1749 U64(0x87AA9AFF, 0x79042286), U64(0x90FB44D2, 0xF05D0842), /* ~= 10^168 */
1750 U64(0xA99541BF, 0x57452B28), U64(0x353A1607, 0xAC744A53), /* ~= 10^169 */
1751 U64(0xD3FA922F, 0x2D1675F2), U64(0x42889B89, 0x97915CE8), /* ~= 10^170 */
1752 U64(0x847C9B5D, 0x7C2E09B7), U64(0x69956135, 0xFEBADA11), /* ~= 10^171 */
1753 U64(0xA59BC234, 0xDB398C25), U64(0x43FAB983, 0x7E699095), /* ~= 10^172 */
1754 U64(0xCF02B2C2, 0x1207EF2E), U64(0x94F967E4, 0x5E03F4BB), /* ~= 10^173 */
1755 U64(0x8161AFB9, 0x4B44F57D), U64(0x1D1BE0EE, 0xBAC278F5), /* ~= 10^174 */
1756 U64(0xA1BA1BA7, 0x9E1632DC), U64(0x6462D92A, 0x69731732), /* ~= 10^175 */
1757 U64(0xCA28A291, 0x859BBF93), U64(0x7D7B8F75, 0x03CFDCFE), /* ~= 10^176 */
1758 U64(0xFCB2CB35, 0xE702AF78), U64(0x5CDA7352, 0x44C3D43E), /* ~= 10^177 */
1759 U64(0x9DEFBF01, 0xB061ADAB), U64(0x3A088813, 0x6AFA64A7), /* ~= 10^178 */
1760 U64(0xC56BAEC2, 0x1C7A1916), U64(0x088AAA18, 0x45B8FDD0), /* ~= 10^179 */
1761 U64(0xF6C69A72, 0xA3989F5B), U64(0x8AAD549E, 0x57273D45), /* ~= 10^180 */
1762 U64(0x9A3C2087, 0xA63F6399), U64(0x36AC54E2, 0xF678864B), /* ~= 10^181 */
1763 U64(0xC0CB28A9, 0x8FCF3C7F), U64(0x84576A1B, 0xB416A7DD), /* ~= 10^182 */
1764 U64(0xF0FDF2D3, 0xF3C30B9F), U64(0x656D44A2, 0xA11C51D5), /* ~= 10^183 */
1765 U64(0x969EB7C4, 0x7859E743), U64(0x9F644AE5, 0xA4B1B325), /* ~= 10^184 */
1766 U64(0xBC4665B5, 0x96706114), U64(0x873D5D9F, 0x0DDE1FEE), /* ~= 10^185 */
1767 U64(0xEB57FF22, 0xFC0C7959), U64(0xA90CB506, 0xD155A7EA), /* ~= 10^186 */
1768 U64(0x9316FF75, 0xDD87CBD8), U64(0x09A7F124, 0x42D588F2), /* ~= 10^187 */
1769 U64(0xB7DCBF53, 0x54E9BECE), U64(0x0C11ED6D, 0x538AEB2F), /* ~= 10^188 */
1770 U64(0xE5D3EF28, 0x2A242E81), U64(0x8F1668C8, 0xA86DA5FA), /* ~= 10^189 */
1771 U64(0x8FA47579, 0x1A569D10), U64(0xF96E017D, 0x694487BC), /* ~= 10^190 */
1772 U64(0xB38D92D7, 0x60EC4455), U64(0x37C981DC, 0xC395A9AC), /* ~= 10^191 */
1773 U64(0xE070F78D, 0x3927556A), U64(0x85BBE253, 0xF47B1417), /* ~= 10^192 */
1774 U64(0x8C469AB8, 0x43B89562), U64(0x93956D74, 0x78CCEC8E), /* ~= 10^193 */
1775 U64(0xAF584166, 0x54A6BABB), U64(0x387AC8D1, 0x970027B2), /* ~= 10^194 */
1776 U64(0xDB2E51BF, 0xE9D0696A), U64(0x06997B05, 0xFCC0319E), /* ~= 10^195 */
1777 U64(0x88FCF317, 0xF22241E2), U64(0x441FECE3, 0xBDF81F03), /* ~= 10^196 */
1778 U64(0xAB3C2FDD, 0xEEAAD25A), U64(0xD527E81C, 0xAD7626C3), /* ~= 10^197 */
1779 U64(0xD60B3BD5, 0x6A5586F1), U64(0x8A71E223, 0xD8D3B074), /* ~= 10^198 */
1780 U64(0x85C70565, 0x62757456), U64(0xF6872D56, 0x67844E49), /* ~= 10^199 */
1781 U64(0xA738C6BE, 0xBB12D16C), U64(0xB428F8AC, 0x016561DB), /* ~= 10^200 */
1782 U64(0xD106F86E, 0x69D785C7), U64(0xE13336D7, 0x01BEBA52), /* ~= 10^201 */
1783 U64(0x82A45B45, 0x0226B39C), U64(0xECC00246, 0x61173473), /* ~= 10^202 */
1784 U64(0xA34D7216, 0x42B06084), U64(0x27F002D7, 0xF95D0190), /* ~= 10^203 */
1785 U64(0xCC20CE9B, 0xD35C78A5), U64(0x31EC038D, 0xF7B441F4), /* ~= 10^204 */
1786 U64(0xFF290242, 0xC83396CE), U64(0x7E670471, 0x75A15271), /* ~= 10^205 */
1787 U64(0x9F79A169, 0xBD203E41), U64(0x0F0062C6, 0xE984D386), /* ~= 10^206 */
1788 U64(0xC75809C4, 0x2C684DD1), U64(0x52C07B78, 0xA3E60868), /* ~= 10^207 */
1789 U64(0xF92E0C35, 0x37826145), U64(0xA7709A56, 0xCCDF8A82), /* ~= 10^208 */
1790 U64(0x9BBCC7A1, 0x42B17CCB), U64(0x88A66076, 0x400BB691), /* ~= 10^209 */
1791 U64(0xC2ABF989, 0x935DDBFE), U64(0x6ACFF893, 0xD00EA435), /* ~= 10^210 */
1792 U64(0xF356F7EB, 0xF83552FE), U64(0x0583F6B8, 0xC4124D43), /* ~= 10^211 */
1793 U64(0x98165AF3, 0x7B2153DE), U64(0xC3727A33, 0x7A8B704A), /* ~= 10^212 */
1794 U64(0xBE1BF1B0, 0x59E9A8D6), U64(0x744F18C0, 0x592E4C5C), /* ~= 10^213 */
1795 U64(0xEDA2EE1C, 0x7064130C), U64(0x1162DEF0, 0x6F79DF73), /* ~= 10^214 */
1796 U64(0x9485D4D1, 0xC63E8BE7), U64(0x8ADDCB56, 0x45AC2BA8), /* ~= 10^215 */
1797 U64(0xB9A74A06, 0x37CE2EE1), U64(0x6D953E2B, 0xD7173692), /* ~= 10^216 */
1798 U64(0xE8111C87, 0xC5C1BA99), U64(0xC8FA8DB6, 0xCCDD0437), /* ~= 10^217 */
1799 U64(0x910AB1D4, 0xDB9914A0), U64(0x1D9C9892, 0x400A22A2), /* ~= 10^218 */
1800 U64(0xB54D5E4A, 0x127F59C8), U64(0x2503BEB6, 0xD00CAB4B), /* ~= 10^219 */
1801 U64(0xE2A0B5DC, 0x971F303A), U64(0x2E44AE64, 0x840FD61D), /* ~= 10^220 */
1802 U64(0x8DA471A9, 0xDE737E24), U64(0x5CEAECFE, 0xD289E5D2), /* ~= 10^221 */
1803 U64(0xB10D8E14, 0x56105DAD), U64(0x7425A83E, 0x872C5F47), /* ~= 10^222 */
1804 U64(0xDD50F199, 0x6B947518), U64(0xD12F124E, 0x28F77719), /* ~= 10^223 */
1805 U64(0x8A5296FF, 0xE33CC92F), U64(0x82BD6B70, 0xD99AAA6F), /* ~= 10^224 */
1806 U64(0xACE73CBF, 0xDC0BFB7B), U64(0x636CC64D, 0x1001550B), /* ~= 10^225 */
1807 U64(0xD8210BEF, 0xD30EFA5A), U64(0x3C47F7E0, 0x5401AA4E), /* ~= 10^226 */
1808 U64(0x8714A775, 0xE3E95C78), U64(0x65ACFAEC, 0x34810A71), /* ~= 10^227 */
1809 U64(0xA8D9D153, 0x5CE3B396), U64(0x7F1839A7, 0x41A14D0D), /* ~= 10^228 */
1810 U64(0xD31045A8, 0x341CA07C), U64(0x1EDE4811, 0x1209A050), /* ~= 10^229 */
1811 U64(0x83EA2B89, 0x2091E44D), U64(0x934AED0A, 0xAB460432), /* ~= 10^230 */
1812 U64(0xA4E4B66B, 0x68B65D60), U64(0xF81DA84D, 0x5617853F), /* ~= 10^231 */
1813 U64(0xCE1DE406, 0x42E3F4B9), U64(0x36251260, 0xAB9D668E), /* ~= 10^232 */
1814 U64(0x80D2AE83, 0xE9CE78F3), U64(0xC1D72B7C, 0x6B426019), /* ~= 10^233 */
1815 U64(0xA1075A24, 0xE4421730), U64(0xB24CF65B, 0x8612F81F), /* ~= 10^234 */
1816 U64(0xC94930AE, 0x1D529CFC), U64(0xDEE033F2, 0x6797B627), /* ~= 10^235 */
1817 U64(0xFB9B7CD9, 0xA4A7443C), U64(0x169840EF, 0x017DA3B1), /* ~= 10^236 */
1818 U64(0x9D412E08, 0x06E88AA5), U64(0x8E1F2895, 0x60EE864E), /* ~= 10^237 */
1819 U64(0xC491798A, 0x08A2AD4E), U64(0xF1A6F2BA, 0xB92A27E2), /* ~= 10^238 */
1820 U64(0xF5B5D7EC, 0x8ACB58A2), U64(0xAE10AF69, 0x6774B1DB), /* ~= 10^239 */
1821 U64(0x9991A6F3, 0xD6BF1765), U64(0xACCA6DA1, 0xE0A8EF29), /* ~= 10^240 */
1822 U64(0xBFF610B0, 0xCC6EDD3F), U64(0x17FD090A, 0x58D32AF3), /* ~= 10^241 */
1823 U64(0xEFF394DC, 0xFF8A948E), U64(0xDDFC4B4C, 0xEF07F5B0), /* ~= 10^242 */
1824 U64(0x95F83D0A, 0x1FB69CD9), U64(0x4ABDAF10, 0x1564F98E), /* ~= 10^243 */
1825 U64(0xBB764C4C, 0xA7A4440F), U64(0x9D6D1AD4, 0x1ABE37F1), /* ~= 10^244 */
1826 U64(0xEA53DF5F, 0xD18D5513), U64(0x84C86189, 0x216DC5ED), /* ~= 10^245 */
1827 U64(0x92746B9B, 0xE2F8552C), U64(0x32FD3CF5, 0xB4E49BB4), /* ~= 10^246 */
1828 U64(0xB7118682, 0xDBB66A77), U64(0x3FBC8C33, 0x221DC2A1), /* ~= 10^247 */
1829 U64(0xE4D5E823, 0x92A40515), U64(0x0FABAF3F, 0xEAA5334A), /* ~= 10^248 */
1830 U64(0x8F05B116, 0x3BA6832D), U64(0x29CB4D87, 0xF2A7400E), /* ~= 10^249 */
1831 U64(0xB2C71D5B, 0xCA9023F8), U64(0x743E20E9, 0xEF511012), /* ~= 10^250 */
1832 U64(0xDF78E4B2, 0xBD342CF6), U64(0x914DA924, 0x6B255416), /* ~= 10^251 */
1833 U64(0x8BAB8EEF, 0xB6409C1A), U64(0x1AD089B6, 0xC2F7548E), /* ~= 10^252 */
1834 U64(0xAE9672AB, 0xA3D0C320), U64(0xA184AC24, 0x73B529B1), /* ~= 10^253 */
1835 U64(0xDA3C0F56, 0x8CC4F3E8), U64(0xC9E5D72D, 0x90A2741E), /* ~= 10^254 */
1836 U64(0x88658996, 0x17FB1871), U64(0x7E2FA67C, 0x7A658892), /* ~= 10^255 */
1837 U64(0xAA7EEBFB, 0x9DF9DE8D), U64(0xDDBB901B, 0x98FEEAB7), /* ~= 10^256 */
1838 U64(0xD51EA6FA, 0x85785631), U64(0x552A7422, 0x7F3EA565), /* ~= 10^257 */
1839 U64(0x8533285C, 0x936B35DE), U64(0xD53A8895, 0x8F87275F), /* ~= 10^258 */
1840 U64(0xA67FF273, 0xB8460356), U64(0x8A892ABA, 0xF368F137), /* ~= 10^259 */
1841 U64(0xD01FEF10, 0xA657842C), U64(0x2D2B7569, 0xB0432D85), /* ~= 10^260 */
1842 U64(0x8213F56A, 0x67F6B29B), U64(0x9C3B2962, 0x0E29FC73), /* ~= 10^261 */
1843 U64(0xA298F2C5, 0x01F45F42), U64(0x8349F3BA, 0x91B47B8F), /* ~= 10^262 */
1844 U64(0xCB3F2F76, 0x42717713), U64(0x241C70A9, 0x36219A73), /* ~= 10^263 */
1845 U64(0xFE0EFB53, 0xD30DD4D7), U64(0xED238CD3, 0x83AA0110), /* ~= 10^264 */
1846 U64(0x9EC95D14, 0x63E8A506), U64(0xF4363804, 0x324A40AA), /* ~= 10^265 */
1847 U64(0xC67BB459, 0x7CE2CE48), U64(0xB143C605, 0x3EDCD0D5), /* ~= 10^266 */
1848 U64(0xF81AA16F, 0xDC1B81DA), U64(0xDD94B786, 0x8E94050A), /* ~= 10^267 */
1849 U64(0x9B10A4E5, 0xE9913128), U64(0xCA7CF2B4, 0x191C8326), /* ~= 10^268 */
1850 U64(0xC1D4CE1F, 0x63F57D72), U64(0xFD1C2F61, 0x1F63A3F0), /* ~= 10^269 */
1851 U64(0xF24A01A7, 0x3CF2DCCF), U64(0xBC633B39, 0x673C8CEC), /* ~= 10^270 */
1852 U64(0x976E4108, 0x8617CA01), U64(0xD5BE0503, 0xE085D813), /* ~= 10^271 */
1853 U64(0xBD49D14A, 0xA79DBC82), U64(0x4B2D8644, 0xD8A74E18), /* ~= 10^272 */
1854 U64(0xEC9C459D, 0x51852BA2), U64(0xDDF8E7D6, 0x0ED1219E), /* ~= 10^273 */
1855 U64(0x93E1AB82, 0x52F33B45), U64(0xCABB90E5, 0xC942B503), /* ~= 10^274 */
1856 U64(0xB8DA1662, 0xE7B00A17), U64(0x3D6A751F, 0x3B936243), /* ~= 10^275 */
1857 U64(0xE7109BFB, 0xA19C0C9D), U64(0x0CC51267, 0x0A783AD4), /* ~= 10^276 */
1858 U64(0x906A617D, 0x450187E2), U64(0x27FB2B80, 0x668B24C5), /* ~= 10^277 */
1859 U64(0xB484F9DC, 0x9641E9DA), U64(0xB1F9F660, 0x802DEDF6), /* ~= 10^278 */
1860 U64(0xE1A63853, 0xBBD26451), U64(0x5E7873F8, 0xA0396973), /* ~= 10^279 */
1861 U64(0x8D07E334, 0x55637EB2), U64(0xDB0B487B, 0x6423E1E8), /* ~= 10^280 */
1862 U64(0xB049DC01, 0x6ABC5E5F), U64(0x91CE1A9A, 0x3D2CDA62), /* ~= 10^281 */
1863 U64(0xDC5C5301, 0xC56B75F7), U64(0x7641A140, 0xCC7810FB), /* ~= 10^282 */
1864 U64(0x89B9B3E1, 0x1B6329BA), U64(0xA9E904C8, 0x7FCB0A9D), /* ~= 10^283 */
1865 U64(0xAC2820D9, 0x623BF429), U64(0x546345FA, 0x9FBDCD44), /* ~= 10^284 */
1866 U64(0xD732290F, 0xBACAF133), U64(0xA97C1779, 0x47AD4095), /* ~= 10^285 */
1867 U64(0x867F59A9, 0xD4BED6C0), U64(0x49ED8EAB, 0xCCCC485D), /* ~= 10^286 */
1868 U64(0xA81F3014, 0x49EE8C70), U64(0x5C68F256, 0xBFFF5A74), /* ~= 10^287 */
1869 U64(0xD226FC19, 0x5C6A2F8C), U64(0x73832EEC, 0x6FFF3111), /* ~= 10^288 */
1870 U64(0x83585D8F, 0xD9C25DB7), U64(0xC831FD53, 0xC5FF7EAB), /* ~= 10^289 */
1871 U64(0xA42E74F3, 0xD032F525), U64(0xBA3E7CA8, 0xB77F5E55), /* ~= 10^290 */
1872 U64(0xCD3A1230, 0xC43FB26F), U64(0x28CE1BD2, 0xE55F35EB), /* ~= 10^291 */
1873 U64(0x80444B5E, 0x7AA7CF85), U64(0x7980D163, 0xCF5B81B3), /* ~= 10^292 */
1874 U64(0xA0555E36, 0x1951C366), U64(0xD7E105BC, 0xC332621F), /* ~= 10^293 */
1875 U64(0xC86AB5C3, 0x9FA63440), U64(0x8DD9472B, 0xF3FEFAA7), /* ~= 10^294 */
1876 U64(0xFA856334, 0x878FC150), U64(0xB14F98F6, 0xF0FEB951), /* ~= 10^295 */
1877 U64(0x9C935E00, 0xD4B9D8D2), U64(0x6ED1BF9A, 0x569F33D3), /* ~= 10^296 */
1878 U64(0xC3B83581, 0x09E84F07), U64(0x0A862F80, 0xEC4700C8), /* ~= 10^297 */
1879 U64(0xF4A642E1, 0x4C6262C8), U64(0xCD27BB61, 0x2758C0FA), /* ~= 10^298 */
1880 U64(0x98E7E9CC, 0xCFBD7DBD), U64(0x8038D51C, 0xB897789C), /* ~= 10^299 */
1881 U64(0xBF21E440, 0x03ACDD2C), U64(0xE0470A63, 0xE6BD56C3), /* ~= 10^300 */
1882 U64(0xEEEA5D50, 0x04981478), U64(0x1858CCFC, 0xE06CAC74), /* ~= 10^301 */
1883 U64(0x95527A52, 0x02DF0CCB), U64(0x0F37801E, 0x0C43EBC8), /* ~= 10^302 */
1884 U64(0xBAA718E6, 0x8396CFFD), U64(0xD3056025, 0x8F54E6BA), /* ~= 10^303 */
1885 U64(0xE950DF20, 0x247C83FD), U64(0x47C6B82E, 0xF32A2069), /* ~= 10^304 */
1886 U64(0x91D28B74, 0x16CDD27E), U64(0x4CDC331D, 0x57FA5441), /* ~= 10^305 */
1887 U64(0xB6472E51, 0x1C81471D), U64(0xE0133FE4, 0xADF8E952), /* ~= 10^306 */
1888 U64(0xE3D8F9E5, 0x63A198E5), U64(0x58180FDD, 0xD97723A6), /* ~= 10^307 */
1889 U64(0x8E679C2F, 0x5E44FF8F), U64(0x570F09EA, 0xA7EA7648), /* ~= 10^308 */
1890 U64(0xB201833B, 0x35D63F73), U64(0x2CD2CC65, 0x51E513DA), /* ~= 10^309 */
1891 U64(0xDE81E40A, 0x034BCF4F), U64(0xF8077F7E, 0xA65E58D1), /* ~= 10^310 */
1892 U64(0x8B112E86, 0x420F6191), U64(0xFB04AFAF, 0x27FAF782), /* ~= 10^311 */
1893 U64(0xADD57A27, 0xD29339F6), U64(0x79C5DB9A, 0xF1F9B563), /* ~= 10^312 */
1894 U64(0xD94AD8B1, 0xC7380874), U64(0x18375281, 0xAE7822BC), /* ~= 10^313 */
1895 U64(0x87CEC76F, 0x1C830548), U64(0x8F229391, 0x0D0B15B5), /* ~= 10^314 */
1896 U64(0xA9C2794A, 0xE3A3C69A), U64(0xB2EB3875, 0x504DDB22), /* ~= 10^315 */
1897 U64(0xD433179D, 0x9C8CB841), U64(0x5FA60692, 0xA46151EB), /* ~= 10^316 */
1898 U64(0x849FEEC2, 0x81D7F328), U64(0xDBC7C41B, 0xA6BCD333), /* ~= 10^317 */
1899 U64(0xA5C7EA73, 0x224DEFF3), U64(0x12B9B522, 0x906C0800), /* ~= 10^318 */
1900 U64(0xCF39E50F, 0xEAE16BEF), U64(0xD768226B, 0x34870A00), /* ~= 10^319 */
1901 U64(0x81842F29, 0xF2CCE375), U64(0xE6A11583, 0x00D46640), /* ~= 10^320 */
1902 U64(0xA1E53AF4, 0x6F801C53), U64(0x60495AE3, 0xC1097FD0), /* ~= 10^321 */
1903 U64(0xCA5E89B1, 0x8B602368), U64(0x385BB19C, 0xB14BDFC4), /* ~= 10^322 */
1904 U64(0xFCF62C1D, 0xEE382C42), U64(0x46729E03, 0xDD9ED7B5), /* ~= 10^323 */
1905 U64(0x9E19DB92, 0xB4E31BA9), U64(0x6C07A2C2, 0x6A8346D1) /* ~= 10^324 */
1906};
1907
1908/**
1909 Get the cached pow10 value from `pow10_sig_table`.
1910 @param exp10 The exponent of pow(10, e). This value must be in the range
1911 `POW10_SIG_TABLE_MIN_EXP` to `POW10_SIG_TABLE_MAX_EXP`.
1912 @param hi The highest 64 bits of pow(10, e).
1913 @param lo The lower 64 bits after `hi`.
1914 */
1915static_inline void pow10_table_get_sig(i32 exp10, u64 *hi, u64 *lo) {
1916 i32 idx = exp10 - (POW10_SIG_TABLE_MIN_EXP);
1917 *hi = pow10_sig_table[idx * 2];
1918 *lo = pow10_sig_table[idx * 2 + 1];
1919}
1920
1921/**
1922 Get the exponent (base 2) for the highest 64-bit significand in
1923 `pow10_sig_table`.
1924 */
1925static_inline void pow10_table_get_exp(i32 exp10, i32 *exp2) {
1926 /* e2 = floor(log2(pow(10, e))) - 64 + 1 */
1927 /* = floor(e * log2(10) - 63) */
1928 *exp2 = (exp10 * 217706 - 4128768) >> 16;
1929}
1930
1931#endif
1932
1933
1934
1935/*==============================================================================
1936 * MARK: - Number and Bit Utils (Private)
1937 *============================================================================*/
1938
1939/** Convert bits to double. */
1940static_inline f64 f64_from_bits(u64 u) {
1941 f64 f;
1942 memcpy(&f, &u, sizeof(u));
1943 return f;
1944}
1945
1946/** Convert double to bits. */
1947static_inline u64 f64_to_bits(f64 f) {
1948 u64 u;
1949 memcpy(&u, &f, sizeof(u));
1950 return u;
1951}
1952
1953/** Convert float to bits. */
1954static_inline u32 f32_to_bits(f32 f) {
1955 u32 u;
1956 memcpy(&u, &f, sizeof(u));
1957 return u;
1958}
1959
1960/** Get 'infinity' bits with sign. */
1961static_inline u64 f64_bits_inf(bool sign) {
1962#if YYJSON_HAS_IEEE_754
1963 return F64_BITS_INF | ((u64)sign << 63);
1964#else
1965 return f64_to_bits(sign ? (f64)-INFINITY : (f64)INFINITY);
1966#endif
1967}
1968
1969/** Returns whether the double value is infinity (not NaN). */
1970static_inline bool f64_is_inf(f64 val) {
1971#if YYJSON_HAS_IEEE_754
1972 return (f64_to_bits(val) & F64_EXP_MASK) == F64_BITS_INF;
1973#else
1974 return val >= (f64)INFINITY || val <= (f64)-INFINITY;
1975#endif
1976}
1977
1978/** Get 'nan' bits with sign. */
1979static_inline u64 f64_bits_nan(bool sign) {
1980#if YYJSON_HAS_IEEE_754
1981 return F64_BITS_NAN | ((u64)sign << 63);
1982#else
1983 return f64_to_bits(sign ? (f64)-NAN : (f64)NAN);
1984#endif
1985}
1986
1987/** Casting double to float, allow overflow. */
1988#if yyjson_has_attribute(no_sanitize)
1989__attribute__((no_sanitize("undefined")))
1990#elif yyjson_gcc_available(4, 9, 0)
1991__attribute__((__no_sanitize_undefined__))
1992#endif
1993static_inline f32 f64_to_f32(f64 val) {
1994 return (f32)val;
1995}
1996
1997/** Returns the number of leading 0-bits in value (input should not be 0). */
1998static_inline u32 u64_lz_bits(u64 v) {
1999#if GCC_HAS_CLZLL
2000 return (u32)__builtin_clzll(v);
2001#elif MSC_HAS_BIT_SCAN_64
2002 unsigned long r;
2003 _BitScanReverse64(&r, v);
2004 return (u32)63 - (u32)r;
2005#elif MSC_HAS_BIT_SCAN
2006 unsigned long hi, lo;
2007 bool hi_set = _BitScanReverse(&hi, (u32)(v >> 32)) != 0;
2008 _BitScanReverse(&lo, (u32)v);
2009 hi |= 32;
2010 return (u32)63 - (u32)(hi_set ? hi : lo);
2011#else
2012 /* branchless, use De Bruijn sequence */
2013 /* see: https://www.chessprogramming.org/BitScan */
2014 const u8 table[64] = {
2015 63, 16, 62, 7, 15, 36, 61, 3, 6, 14, 22, 26, 35, 47, 60, 2,
2016 9, 5, 28, 11, 13, 21, 42, 19, 25, 31, 34, 40, 46, 52, 59, 1,
2017 17, 8, 37, 4, 23, 27, 48, 10, 29, 12, 43, 20, 32, 41, 53, 18,
2018 38, 24, 49, 30, 44, 33, 54, 39, 50, 45, 55, 51, 56, 57, 58, 0
2019 };
2020 v |= v >> 1;
2021 v |= v >> 2;
2022 v |= v >> 4;
2023 v |= v >> 8;
2024 v |= v >> 16;
2025 v |= v >> 32;
2026 return table[(v * U64(0x03F79D71, 0xB4CB0A89)) >> 58];
2027#endif
2028}
2029
2030/** Returns the number of trailing 0-bits in value (input should not be 0). */
2031static_inline u32 u64_tz_bits(u64 v) {
2032#if GCC_HAS_CTZLL
2033 return (u32)__builtin_ctzll(v);
2034#elif MSC_HAS_BIT_SCAN_64
2035 unsigned long r;
2036 _BitScanForward64(&r, v);
2037 return (u32)r;
2038#elif MSC_HAS_BIT_SCAN
2039 unsigned long lo, hi;
2040 bool lo_set = _BitScanForward(&lo, (u32)(v)) != 0;
2041 _BitScanForward(&hi, (u32)(v >> 32));
2042 hi += 32;
2043 return lo_set ? lo : hi;
2044#else
2045 /* branchless, use De Bruijn sequence */
2046 /* see: https://www.chessprogramming.org/BitScan */
2047 const u8 table[64] = {
2048 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28,
2049 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11,
2050 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
2051 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12
2052 };
2053 return table[((v & (~v + 1)) * U64(0x022FDD63, 0xCC95386D)) >> 58];
2054#endif
2055}
2056
2057/** Multiplies two 64-bit unsigned integers (a * b),
2058 returns the 128-bit result as 'hi' and 'lo'. */
2059static_inline void u128_mul(u64 a, u64 b, u64 *hi, u64 *lo) {
2060#if YYJSON_HAS_INT128
2061 u128 m = (u128)a * b;
2062 *hi = (u64)(m >> 64);
2063 *lo = (u64)(m);
2064#elif MSC_HAS_UMUL128
2065 *lo = _umul128(a, b, hi);
2066#else
2067 u32 a0 = (u32)(a), a1 = (u32)(a >> 32);
2068 u32 b0 = (u32)(b), b1 = (u32)(b >> 32);
2069 u64 p00 = (u64)a0 * b0, p01 = (u64)a0 * b1;
2070 u64 p10 = (u64)a1 * b0, p11 = (u64)a1 * b1;
2071 u64 m0 = p01 + (p00 >> 32);
2072 u32 m00 = (u32)(m0), m01 = (u32)(m0 >> 32);
2073 u64 m1 = p10 + m00;
2074 u32 m10 = (u32)(m1), m11 = (u32)(m1 >> 32);
2075 *hi = p11 + m01 + m11;
2076 *lo = ((u64)m10 << 32) | (u32)p00;
2077#endif
2078}
2079
2080/** Multiplies two 64-bit unsigned integers and add a value (a * b + c),
2081 returns the 128-bit result as 'hi' and 'lo'. */
2082static_inline void u128_mul_add(u64 a, u64 b, u64 c, u64 *hi, u64 *lo) {
2083#if YYJSON_HAS_INT128
2084 u128 m = (u128)a * b + c;
2085 *hi = (u64)(m >> 64);
2086 *lo = (u64)(m);
2087#else
2088 u64 h, l, t;
2089 u128_mul(a, b, &h, &l);
2090 t = l + c;
2091 h += (u64)(((t < l) | (t < c)));
2092 *hi = h;
2093 *lo = t;
2094#endif
2095}
2096
2097
2098
2099/*==============================================================================
2100 * MARK: - File Utils (Private)
2101 * These functions are used to read and write JSON files.
2102 *============================================================================*/
2103
2104#if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE
2105
2106#define YYJSON_FOPEN_E
2107#if !defined(_MSC_VER) && defined(__GLIBC__) && defined(__GLIBC_PREREQ)
2108# if __GLIBC_PREREQ(2, 7)
2109# undef YYJSON_FOPEN_E
2110# define YYJSON_FOPEN_E "e" /* glibc extension to enable O_CLOEXEC */
2111# endif
2112#endif
2113
2114static_inline FILE *fopen_safe(const char *path, const char *mode) {
2115#if YYJSON_MSC_VER >= 1400
2116 FILE *file = NULL;
2117 if (fopen_s(&file, path, mode) != 0) return NULL;
2118 return file;
2119#else
2120 return fopen(path, mode);
2121#endif
2122}
2123
2124static_inline FILE *fopen_readonly(const char *path) {
2125 return fopen_safe(path, "rb" YYJSON_FOPEN_E);
2126}
2127
2128static_inline FILE *fopen_writeonly(const char *path) {
2129 return fopen_safe(path, "wb" YYJSON_FOPEN_E);
2130}
2131
2132static_inline usize fread_safe(void *buf, usize size, FILE *file) {
2133#if YYJSON_MSC_VER >= 1400
2134 return fread_s(buf, size, 1, size, file);
2135#else
2136 return fread(buf, 1, size, file);
2137#endif
2138}
2139
2140#endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */
2141
2142
2143
2144/*==============================================================================
2145 * MARK: - Size Utils (Private)
2146 * These functions are used for memory allocation.
2147 *============================================================================*/
2148
2149/** Returns whether the size is overflow after increment. */
2150static_inline bool size_add_is_overflow(usize size, usize add) {
2151 return size > (size + add);
2152}
2153
2154/** Returns whether the size is power of 2 (size should not be 0). */
2155static_inline bool size_is_pow2(usize size) {
2156 return (size & (size - 1)) == 0;
2157}
2158
2159/** Align size upwards (may overflow). */
2160static_inline usize size_align_up(usize size, usize align) {
2161 if (size_is_pow2(align)) {
2162 return (size + (align - 1)) & ~(align - 1);
2163 } else {
2164 return size + align - (size + align - 1) % align - 1;
2165 }
2166}
2167
2168/** Align size downwards. */
2169static_inline usize size_align_down(usize size, usize align) {
2170 if (size_is_pow2(align)) {
2171 return size & ~(align - 1);
2172 } else {
2173 return size - (size % align);
2174 }
2175}
2176
2177/** Align address upwards (may overflow). */
2178static_inline void *mem_align_up(void *mem, usize align) {
2179 usize size;
2180 memcpy(&size, &mem, sizeof(usize));
2181 size = size_align_up(size, align);
2182 memcpy(&mem, &size, sizeof(usize));
2183 return mem;
2184}
2185
2186
2187
2188/*==============================================================================
2189 * MARK: - Null Memory Allocator (Private)
2190 * This allocator is just a placeholder to ensure that the internal
2191 * malloc/realloc/free function pointers are not null.
2192 *============================================================================*/
2193
2194static void *null_malloc(void *ctx, usize size) {
2195 return NULL;
2196}
2197
2198static void *null_realloc(void *ctx, void *ptr, usize old_size, usize size) {
2199 return NULL;
2200}
2201
2202static void null_free(void *ctx, void *ptr) {
2203 return;
2204}
2205
2206static const yyjson_alc YYJSON_NULL_ALC = {
2207 null_malloc, null_realloc, null_free, NULL
2208};
2209
2210
2211
2212/*==============================================================================
2213 * MARK: - Default Memory Allocator (Private)
2214 * This is a simple libc memory allocator wrapper.
2215 *============================================================================*/
2216
2217#if defined(YYJSON_CUSTOM_ALC)
2218
2219/* user-provided via macro */
2220extern const yyjson_alc YYJSON_CUSTOM_ALC;
2221#define YYJSON_DEFAULT_ALC YYJSON_CUSTOM_ALC
2222
2223#elif YYJSON_FREESTANDING
2224
2225/* null allocator */
2226static const yyjson_alc YYJSON_DEFAULT_ALC = {
2227 null_malloc, null_realloc, null_free, NULL
2228};
2229
2230#else /* YYJSON_FREESTANDING */
2231
2232/* default libc allocator */
2233static void *default_malloc(void *ctx, usize size) {
2234 return malloc(size);
2235}
2236static void *default_realloc(void *ctx, void *ptr, usize old_size, usize size) {
2237 return realloc(ptr, size);
2238}
2239static void default_free(void *ctx, void *ptr) {
2240 free(ptr);
2241}
2242static const yyjson_alc YYJSON_DEFAULT_ALC = {
2243 default_malloc, default_realloc, default_free, NULL
2244};
2245
2246#endif /* YYJSON_FREESTANDING */
2247
2248
2249
2250/*==============================================================================
2251 * MARK: - Pool Memory Allocator (Public)
2252 * This allocator is initialized with a fixed-size buffer.
2253 * The buffer is split into multiple memory chunks for memory allocation.
2254 *============================================================================*/
2255
2256/** memory chunk header */
2257typedef struct pool_chunk {
2258 usize size; /* chunk memory size, including chunk header */
2259 struct pool_chunk *next; /* linked list, nullable */
2260 /* char mem[]; flexible array member */
2261} pool_chunk;
2262
2263/** allocator ctx header */
2264typedef struct pool_ctx {
2265 usize size; /* total memory size, including ctx header */
2266 pool_chunk *free_list; /* linked list, nullable */
2267 /* pool_chunk chunks[]; flexible array member */
2268} pool_ctx;
2269
2270/** align up the input size to chunk size */
2271static_inline void pool_size_align(usize *size) {
2272 *size = size_align_up(*size, sizeof(pool_chunk)) + sizeof(pool_chunk);
2273}
2274
2275static void *pool_malloc(void *ctx_ptr, usize size) {
2276 /* assert(size != 0) */
2277 pool_ctx *ctx = (pool_ctx *)ctx_ptr;
2278 pool_chunk *next, *prev = NULL, *cur = ctx->free_list;
2279
2280 if (unlikely(size >= ctx->size)) return NULL;
2281 pool_size_align(&size);
2282
2283 while (cur) {
2284 if (cur->size < size) {
2285 /* not enough space, try next chunk */
2286 prev = cur;
2287 cur = cur->next;
2288 continue;
2289 }
2290 if (cur->size >= size + sizeof(pool_chunk) * 2) {
2291 /* too much space, split this chunk */
2292 next = (pool_chunk *)(void *)((u8 *)cur + size);
2293 next->size = cur->size - size;
2294 next->next = cur->next;
2295 cur->size = size;
2296 } else {
2297 /* just enough space, use whole chunk */
2298 next = cur->next;
2299 }
2300 if (prev) prev->next = next;
2301 else ctx->free_list = next;
2302 return (void *)(cur + 1);
2303 }
2304 return NULL;
2305}
2306
2307static void pool_free(void *ctx_ptr, void *ptr) {
2308 /* assert(ptr != NULL) */
2309 pool_ctx *ctx = (pool_ctx *)ctx_ptr;
2310 pool_chunk *cur = ((pool_chunk *)ptr) - 1;
2311 pool_chunk *prev = NULL, *next = ctx->free_list;
2312
2313 while (next && next < cur) {
2314 prev = next;
2315 next = next->next;
2316 }
2317 if (prev) prev->next = cur;
2318 else ctx->free_list = cur;
2319 cur->next = next;
2320
2321 if (next && ((u8 *)cur + cur->size) == (u8 *)next) {
2322 /* merge cur to higher chunk */
2323 cur->size += next->size;
2324 cur->next = next->next;
2325 }
2326 if (prev && ((u8 *)prev + prev->size) == (u8 *)cur) {
2327 /* merge cur to lower chunk */
2328 prev->size += cur->size;
2329 prev->next = cur->next;
2330 }
2331}
2332
2333static void *pool_realloc(void *ctx_ptr, void *ptr,
2334 usize old_size, usize size) {
2335 /* assert(ptr != NULL && size != 0 && old_size < size) */
2336 pool_ctx *ctx = (pool_ctx *)ctx_ptr;
2337 pool_chunk *cur = ((pool_chunk *)ptr) - 1, *prev, *next, *tmp;
2338
2339 /* check size */
2340 if (unlikely(size >= ctx->size)) return NULL;
2341 pool_size_align(&old_size);
2342 pool_size_align(&size);
2343 if (unlikely(old_size == size)) return ptr;
2344
2345 /* find next and prev chunk */
2346 prev = NULL;
2347 next = ctx->free_list;
2348 while (next && next < cur) {
2349 prev = next;
2350 next = next->next;
2351 }
2352
2353 if ((u8 *)cur + cur->size == (u8 *)next && cur->size + next->size >= size) {
2354 /* merge to higher chunk if they are contiguous */
2355 usize free_size = cur->size + next->size - size;
2356 if (free_size > sizeof(pool_chunk) * 2) {
2357 tmp = (pool_chunk *)(void *)((u8 *)cur + size);
2358 if (prev) prev->next = tmp;
2359 else ctx->free_list = tmp;
2360 tmp->next = next->next;
2361 tmp->size = free_size;
2362 cur->size = size;
2363 } else {
2364 if (prev) prev->next = next->next;
2365 else ctx->free_list = next->next;
2366 cur->size += next->size;
2367 }
2368 return ptr;
2369 } else {
2370 /* fallback to malloc and memcpy */
2371 void *new_ptr = pool_malloc(ctx_ptr, size - sizeof(pool_chunk));
2372 if (new_ptr) {
2373 memcpy(new_ptr, ptr, cur->size - sizeof(pool_chunk));
2374 pool_free(ctx_ptr, ptr);
2375 }
2376 return new_ptr;
2377 }
2378}
2379
2380bool yyjson_alc_pool_init(yyjson_alc *alc, void *buf, usize size) {
2381 pool_chunk *chunk;
2382 pool_ctx *ctx;
2383
2384 if (unlikely(!alc)) return false;
2385 *alc = YYJSON_NULL_ALC;
2386 if (size < sizeof(pool_ctx) * 4) return false;
2387 ctx = (pool_ctx *)mem_align_up(buf, sizeof(pool_ctx));
2388 if (unlikely(!ctx)) return false;
2389 size -= (usize)((u8 *)ctx - (u8 *)buf);
2390 size = size_align_down(size, sizeof(pool_ctx));
2391
2392 chunk = (pool_chunk *)(ctx + 1);
2393 chunk->size = size - sizeof(pool_ctx);
2394 chunk->next = NULL;
2395 ctx->size = size;
2396 ctx->free_list = chunk;
2397
2398 alc->malloc = pool_malloc;
2399 alc->realloc = pool_realloc;
2400 alc->free = pool_free;
2401 alc->ctx = (void *)ctx;
2402 return true;
2403}
2404
2405
2406
2407/*==============================================================================
2408 * MARK: - Dynamic Memory Allocator (Public)
2409 * This allocator allocates memory on demand and does not immediately release
2410 * unused memory. Instead, it places the unused memory into a freelist for
2411 * potential reuse in the future. It is only when the entire allocator is
2412 * destroyed that all previously allocated memory is released at once.
2413 *============================================================================*/
2414
2415/** memory chunk header */
2416typedef struct dyn_chunk {
2417 usize size; /* chunk size, including header */
2418 struct dyn_chunk *next;
2419 /* char mem[]; flexible array member */
2420} dyn_chunk;
2421
2422/** allocator ctx header */
2423typedef struct {
2424 dyn_chunk free_list; /* dummy header, sorted from small to large */
2425 dyn_chunk used_list; /* dummy header */
2426} dyn_ctx;
2427
2428/** align up the input size to chunk size */
2429static_inline bool dyn_size_align(usize *size) {
2430 usize alc_size = *size + sizeof(dyn_chunk);
2431 alc_size = size_align_up(alc_size, YYJSON_ALC_DYN_MIN_SIZE);
2432 if (unlikely(alc_size < *size)) return false; /* overflow */
2433 *size = alc_size;
2434 return true;
2435}
2436
2437/** remove a chunk from list (the chunk must already be in the list) */
2438static_inline void dyn_chunk_list_remove(dyn_chunk *list, dyn_chunk *chunk) {
2439 dyn_chunk *prev = list, *cur;
2440 for (cur = prev->next; cur; cur = cur->next) {
2441 if (cur == chunk) {
2442 prev->next = cur->next;
2443 cur->next = NULL;
2444 return;
2445 }
2446 prev = cur;
2447 }
2448}
2449
2450/** add a chunk to list header (the chunk must not be in the list) */
2451static_inline void dyn_chunk_list_add(dyn_chunk *list, dyn_chunk *chunk) {
2452 chunk->next = list->next;
2453 list->next = chunk;
2454}
2455
2456static void *dyn_malloc(void *ctx_ptr, usize size) {
2457 /* assert(size != 0) */
2458 const yyjson_alc def = YYJSON_DEFAULT_ALC;
2459 dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
2460 dyn_chunk *chunk, *prev;
2461 if (unlikely(!dyn_size_align(&size))) return NULL;
2462
2463 /* freelist is empty, create new chunk */
2464 if (!ctx->free_list.next) {
2465 chunk = (dyn_chunk *)def.malloc(def.ctx, size);
2466 if (unlikely(!chunk)) return NULL;
2467 chunk->size = size;
2468 chunk->next = NULL;
2469 dyn_chunk_list_add(&ctx->used_list, chunk);
2470 return (void *)(chunk + 1);
2471 }
2472
2473 /* find a large enough chunk, or resize the largest chunk */
2474 prev = &ctx->free_list;
2475 while (true) {
2476 chunk = prev->next;
2477 if (chunk->size >= size) { /* enough size, reuse this chunk */
2478 prev->next = chunk->next;
2479 dyn_chunk_list_add(&ctx->used_list, chunk);
2480 return (void *)(chunk + 1);
2481 }
2482 if (!chunk->next) { /* resize the largest chunk */
2483 chunk = (dyn_chunk *)def.realloc(def.ctx, chunk, chunk->size, size);
2484 if (unlikely(!chunk)) return NULL;
2485 prev->next = NULL;
2486 chunk->size = size;
2487 dyn_chunk_list_add(&ctx->used_list, chunk);
2488 return (void *)(chunk + 1);
2489 }
2490 prev = chunk;
2491 }
2492}
2493
2494static void *dyn_realloc(void *ctx_ptr, void *ptr,
2495 usize old_size, usize size) {
2496 /* assert(ptr != NULL && size != 0 && old_size < size) */
2497 const yyjson_alc def = YYJSON_DEFAULT_ALC;
2498 dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
2499 dyn_chunk *new_chunk, *chunk = (dyn_chunk *)ptr - 1;
2500 if (unlikely(!dyn_size_align(&size))) return NULL;
2501 if (chunk->size >= size) return ptr;
2502
2503 dyn_chunk_list_remove(&ctx->used_list, chunk);
2504 new_chunk = (dyn_chunk *)def.realloc(def.ctx, chunk, chunk->size, size);
2505 if (likely(new_chunk)) {
2506 new_chunk->size = size;
2507 chunk = new_chunk;
2508 }
2509 dyn_chunk_list_add(&ctx->used_list, chunk);
2510 return new_chunk ? (void *)(new_chunk + 1) : NULL;
2511}
2512
2513static void dyn_free(void *ctx_ptr, void *ptr) {
2514 /* assert(ptr != NULL) */
2515 dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
2516 dyn_chunk *chunk = (dyn_chunk *)ptr - 1, *prev;
2517
2518 dyn_chunk_list_remove(&ctx->used_list, chunk);
2519 for (prev = &ctx->free_list; prev; prev = prev->next) {
2520 if (!prev->next || prev->next->size >= chunk->size) {
2521 chunk->next = prev->next;
2522 prev->next = chunk;
2523 break;
2524 }
2525 }
2526}
2527
2528yyjson_alc *yyjson_alc_dyn_new(void) {
2529 const yyjson_alc def = YYJSON_DEFAULT_ALC;
2530 usize hdr_len = sizeof(yyjson_alc) + sizeof(dyn_ctx);
2531 yyjson_alc *alc;
2532 dyn_ctx *ctx;
2533 alc = (yyjson_alc *)def.malloc(def.ctx, hdr_len);
2534 if (unlikely(!alc)) return NULL;
2535 ctx = (dyn_ctx *)(void *)(alc + 1);
2536 alc->malloc = dyn_malloc;
2537 alc->realloc = dyn_realloc;
2538 alc->free = dyn_free;
2539 alc->ctx = alc + 1;
2540 memset(ctx, 0, sizeof(*ctx));
2541 return alc;
2542}
2543
2544void yyjson_alc_dyn_free(yyjson_alc *alc) {
2545 const yyjson_alc def = YYJSON_DEFAULT_ALC;
2546 dyn_ctx *ctx;
2547 dyn_chunk *chunk, *next;
2548 if (unlikely(!alc)) return;
2549 ctx = (dyn_ctx *)(void *)(alc + 1);
2550 for (chunk = ctx->free_list.next; chunk; chunk = next) {
2551 next = chunk->next;
2552 def.free(def.ctx, chunk);
2553 }
2554 for (chunk = ctx->used_list.next; chunk; chunk = next) {
2555 next = chunk->next;
2556 def.free(def.ctx, chunk);
2557 }
2558 def.free(def.ctx, alc);
2559}
2560
2561
2562
2563/*==============================================================================
2564 * MARK: - JSON Struct Utils (Public)
2565 * These functions are used for creating, copying, releasing, and comparing
2566 * JSON documents and values. They are widely used throughout this library.
2567 *============================================================================*/
2568
2569static_inline void unsafe_yyjson_str_pool_release(yyjson_str_pool *pool,
2570 yyjson_alc *alc) {
2571 yyjson_str_chunk *chunk = pool->chunks, *next;
2572 while (chunk) {
2573 next = chunk->next;
2574 alc->free(alc->ctx, chunk);
2575 chunk = next;
2576 }
2577}
2578
2579static_inline void unsafe_yyjson_val_pool_release(yyjson_val_pool *pool,
2580 yyjson_alc *alc) {
2581 yyjson_val_chunk *chunk = pool->chunks, *next;
2582 while (chunk) {
2583 next = chunk->next;
2584 alc->free(alc->ctx, chunk);
2585 chunk = next;
2586 }
2587}
2588
2589bool unsafe_yyjson_str_pool_grow(yyjson_str_pool *pool,
2590 const yyjson_alc *alc, usize len) {
2591 yyjson_str_chunk *chunk;
2592 usize size, max_len;
2593
2594 /* create a new chunk */
2595 max_len = USIZE_MAX - sizeof(yyjson_str_chunk);
2596 if (unlikely(len > max_len)) return false;
2597 size = len + sizeof(yyjson_str_chunk);
2598 size = yyjson_max(pool->chunk_size, size);
2599 chunk = (yyjson_str_chunk *)alc->malloc(alc->ctx, size);
2600 if (unlikely(!chunk)) return false;
2601
2602 /* insert the new chunk as the head of the linked list */
2603 chunk->next = pool->chunks;
2604 chunk->chunk_size = size;
2605 pool->chunks = chunk;
2606 pool->cur = (char *)chunk + sizeof(yyjson_str_chunk);
2607 pool->end = (char *)chunk + size;
2608
2609 /* the next chunk is twice the size of the current one */
2610 size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max);
2611 if (size < pool->chunk_size) size = pool->chunk_size_max; /* overflow */
2612 pool->chunk_size = size;
2613 return true;
2614}
2615
2616bool unsafe_yyjson_val_pool_grow(yyjson_val_pool *pool,
2617 const yyjson_alc *alc, usize count) {
2618 yyjson_val_chunk *chunk;
2619 usize size, max_count;
2620
2621 /* create a new chunk */
2622 max_count = USIZE_MAX / sizeof(yyjson_mut_val) - 1;
2623 if (unlikely(count > max_count)) return false;
2624 size = (count + 1) * sizeof(yyjson_mut_val);
2625 size = yyjson_max(pool->chunk_size, size);
2626 chunk = (yyjson_val_chunk *)alc->malloc(alc->ctx, size);
2627 if (unlikely(!chunk)) return false;
2628
2629 /* insert the new chunk as the head of the linked list */
2630 chunk->next = pool->chunks;
2631 chunk->chunk_size = size;
2632 pool->chunks = chunk;
2633 pool->cur = (yyjson_mut_val *)(void *)((u8 *)chunk) + 1;
2634 pool->end = (yyjson_mut_val *)(void *)((u8 *)chunk + size);
2635
2636 /* the next chunk is twice the size of the current one */
2637 size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max);
2638 if (size < pool->chunk_size) size = pool->chunk_size_max; /* overflow */
2639 pool->chunk_size = size;
2640 return true;
2641}
2642
2643bool yyjson_mut_doc_set_str_pool_size(yyjson_mut_doc *doc, size_t len) {
2644 usize max_size = USIZE_MAX - sizeof(yyjson_str_chunk);
2645 if (!doc || !len || len > max_size) return false;
2646 doc->str_pool.chunk_size = len + sizeof(yyjson_str_chunk);
2647 return true;
2648}
2649
2650bool yyjson_mut_doc_set_val_pool_size(yyjson_mut_doc *doc, size_t count) {
2651 usize max_count = USIZE_MAX / sizeof(yyjson_mut_val) - 1;
2652 if (!doc || !count || count > max_count) return false;
2653 doc->val_pool.chunk_size = (count + 1) * sizeof(yyjson_mut_val);
2654 return true;
2655}
2656
2657void yyjson_mut_doc_free(yyjson_mut_doc *doc) {
2658 if (doc) {
2659 yyjson_alc alc = doc->alc;
2660 memset(&doc->alc, 0, sizeof(alc));
2661 unsafe_yyjson_str_pool_release(&doc->str_pool, &alc);
2662 unsafe_yyjson_val_pool_release(&doc->val_pool, &alc);
2663 alc.free(alc.ctx, doc);
2664 }
2665}
2666
2667yyjson_mut_doc *yyjson_mut_doc_new(const yyjson_alc *alc) {
2668 yyjson_mut_doc *doc;
2669 if (!alc) alc = &YYJSON_DEFAULT_ALC;
2670 doc = (yyjson_mut_doc *)alc->malloc(alc->ctx, sizeof(yyjson_mut_doc));
2671 if (!doc) return NULL;
2672 memset(doc, 0, sizeof(yyjson_mut_doc));
2673
2674 doc->alc = *alc;
2675 doc->str_pool.chunk_size = YYJSON_MUT_DOC_STR_POOL_INIT_SIZE;
2676 doc->str_pool.chunk_size_max = YYJSON_MUT_DOC_STR_POOL_MAX_SIZE;
2677 doc->val_pool.chunk_size = YYJSON_MUT_DOC_VAL_POOL_INIT_SIZE;
2678 doc->val_pool.chunk_size_max = YYJSON_MUT_DOC_VAL_POOL_MAX_SIZE;
2679 return doc;
2680}
2681
2682yyjson_mut_doc *yyjson_doc_mut_copy(const yyjson_doc *doc,
2683 const yyjson_alc *alc) {
2684 yyjson_mut_doc *m_doc;
2685 yyjson_mut_val *m_val;
2686
2687 if (!doc || !doc->root) return NULL;
2688 m_doc = yyjson_mut_doc_new(alc);
2689 if (!m_doc) return NULL;
2690 m_val = yyjson_val_mut_copy(m_doc, doc->root);
2691 if (!m_val) {
2692 yyjson_mut_doc_free(m_doc);
2693 return NULL;
2694 }
2695 yyjson_mut_doc_set_root(m_doc, m_val);
2696 return m_doc;
2697}
2698
2699yyjson_mut_doc *yyjson_mut_doc_mut_copy(const yyjson_mut_doc *doc,
2700 const yyjson_alc *alc) {
2701 yyjson_mut_doc *m_doc;
2702 yyjson_mut_val *m_val;
2703
2704 if (!doc) return NULL;
2705 if (!doc->root) return yyjson_mut_doc_new(alc);
2706
2707 m_doc = yyjson_mut_doc_new(alc);
2708 if (!m_doc) return NULL;
2709 m_val = yyjson_mut_val_mut_copy(m_doc, doc->root);
2710 if (!m_val) {
2711 yyjson_mut_doc_free(m_doc);
2712 return NULL;
2713 }
2714 yyjson_mut_doc_set_root(m_doc, m_val);
2715 return m_doc;
2716}
2717
2718yyjson_mut_val *yyjson_val_mut_copy(yyjson_mut_doc *m_doc,
2719 const yyjson_val *i_vals) {
2720 /*
2721 The immutable object or array stores all sub-values in a contiguous memory,
2722 We copy them to another contiguous memory as mutable values,
2723 then reconnect the mutable values with the original relationship.
2724 */
2725 usize i_vals_len;
2726 yyjson_mut_val *m_vals, *m_val;
2727 yyjson_val *i_val, *i_end;
2728
2729 if (!m_doc || !i_vals) return NULL;
2730 i_end = unsafe_yyjson_get_next(i_vals);
2731 i_vals_len = (usize)(unsafe_yyjson_get_next(i_vals) - i_vals);
2732 m_vals = unsafe_yyjson_mut_val(m_doc, i_vals_len);
2733 if (!m_vals) return NULL;
2734 i_val = constcast(yyjson_val *)i_vals;
2735 m_val = m_vals;
2736
2737 for (; i_val < i_end; i_val++, m_val++) {
2738 yyjson_type type = unsafe_yyjson_get_type(i_val);
2739 m_val->tag = i_val->tag;
2740 m_val->uni.u64 = i_val->uni.u64;
2741 if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
2742 const char *str = i_val->uni.str;
2743 usize str_len = unsafe_yyjson_get_len(i_val);
2744 m_val->uni.str = unsafe_yyjson_mut_strncpy(m_doc, str, str_len);
2745 if (!m_val->uni.str) return NULL;
2746 } else if (type == YYJSON_TYPE_ARR) {
2747 usize len = unsafe_yyjson_get_len(i_val);
2748 if (len > 0) {
2749 yyjson_val *ii_val = i_val + 1, *ii_next;
2750 yyjson_mut_val *mm_val = m_val + 1, *mm_ctn = m_val, *mm_next;
2751 while (len-- > 1) {
2752 ii_next = unsafe_yyjson_get_next(ii_val);
2753 mm_next = mm_val + (ii_next - ii_val);
2754 mm_val->next = mm_next;
2755 ii_val = ii_next;
2756 mm_val = mm_next;
2757 }
2758 mm_val->next = mm_ctn + 1;
2759 mm_ctn->uni.ptr = mm_val;
2760 }
2761 } else if (type == YYJSON_TYPE_OBJ) {
2762 usize len = unsafe_yyjson_get_len(i_val);
2763 if (len > 0) {
2764 yyjson_val *ii_key = i_val + 1, *ii_nextkey;
2765 yyjson_mut_val *mm_key = m_val + 1, *mm_ctn = m_val;
2766 yyjson_mut_val *mm_nextkey;
2767 while (len-- > 1) {
2768 ii_nextkey = unsafe_yyjson_get_next(ii_key + 1);
2769 mm_nextkey = mm_key + (ii_nextkey - ii_key);
2770 mm_key->next = mm_key + 1;
2771 mm_key->next->next = mm_nextkey;
2772 ii_key = ii_nextkey;
2773 mm_key = mm_nextkey;
2774 }
2775 mm_key->next = mm_key + 1;
2776 mm_key->next->next = mm_ctn + 1;
2777 mm_ctn->uni.ptr = mm_key;
2778 }
2779 }
2780 }
2781 return m_vals;
2782}
2783
2784static yyjson_mut_val *unsafe_yyjson_mut_val_mut_copy(
2785 yyjson_mut_doc *m_doc, const yyjson_mut_val *m_vals) {
2786 /*
2787 The mutable object or array stores all sub-values in a circular linked
2788 list, so we can traverse them in the same loop. The traversal starts from
2789 the last item, continues with the first item in a list, and ends with the
2790 second to last item, which needs to be linked to the last item to close the
2791 circle.
2792 */
2793 yyjson_mut_val *m_val = unsafe_yyjson_mut_val(m_doc, 1);
2794 if (unlikely(!m_val)) return NULL;
2795 m_val->tag = m_vals->tag;
2796
2797 switch (unsafe_yyjson_get_type(m_vals)) {
2798 case YYJSON_TYPE_OBJ:
2799 case YYJSON_TYPE_ARR:
2800 if (unsafe_yyjson_get_len(m_vals) > 0) {
2801 yyjson_mut_val *last = (yyjson_mut_val *)m_vals->uni.ptr;
2802 yyjson_mut_val *next = last->next, *prev;
2803 prev = unsafe_yyjson_mut_val_mut_copy(m_doc, last);
2804 if (!prev) return NULL;
2805 m_val->uni.ptr = (void *)prev;
2806 while (next != last) {
2807 prev->next = unsafe_yyjson_mut_val_mut_copy(m_doc, next);
2808 if (!prev->next) return NULL;
2809 prev = prev->next;
2810 next = next->next;
2811 }
2812 prev->next = (yyjson_mut_val *)m_val->uni.ptr;
2813 }
2814 break;
2815 case YYJSON_TYPE_RAW:
2816 case YYJSON_TYPE_STR: {
2817 const char *str = m_vals->uni.str;
2818 usize str_len = unsafe_yyjson_get_len(m_vals);
2819 m_val->uni.str = unsafe_yyjson_mut_strncpy(m_doc, str, str_len);
2820 if (!m_val->uni.str) return NULL;
2821 break;
2822 }
2823 default:
2824 m_val->uni = m_vals->uni;
2825 break;
2826 }
2827 return m_val;
2828}
2829
2830yyjson_mut_val *yyjson_mut_val_mut_copy(yyjson_mut_doc *doc,
2831 const yyjson_mut_val *val) {
2832 if (doc && val) return unsafe_yyjson_mut_val_mut_copy(doc, val);
2833 return NULL;
2834}
2835
2836/* Count the number of values and the total length of the strings. */
2837static void yyjson_mut_stat(const yyjson_mut_val *val,
2838 usize *val_sum, usize *str_sum) {
2839 yyjson_type type = unsafe_yyjson_get_type(val);
2840 *val_sum += 1;
2841 if (type == YYJSON_TYPE_ARR || type == YYJSON_TYPE_OBJ) {
2842 yyjson_mut_val *child = (yyjson_mut_val *)val->uni.ptr;
2843 usize len = unsafe_yyjson_get_len(val), i;
2844 len <<= (u8)(type == YYJSON_TYPE_OBJ);
2845 *val_sum += len;
2846 for (i = 0; i < len; i++) {
2847 yyjson_type stype = unsafe_yyjson_get_type(child);
2848 if (stype == YYJSON_TYPE_STR || stype == YYJSON_TYPE_RAW) {
2849 *str_sum += unsafe_yyjson_get_len(child) + 1;
2850 } else if (stype == YYJSON_TYPE_ARR || stype == YYJSON_TYPE_OBJ) {
2851 yyjson_mut_stat(child, val_sum, str_sum);
2852 *val_sum -= 1;
2853 }
2854 child = child->next;
2855 }
2856 } else if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
2857 *str_sum += unsafe_yyjson_get_len(val) + 1;
2858 }
2859}
2860
2861/* Copy mutable values to immutable value pool. */
2862static usize yyjson_imut_copy(yyjson_val **val_ptr, char **buf_ptr,
2863 const yyjson_mut_val *mval) {
2864 yyjson_val *val = *val_ptr;
2865 yyjson_type type = unsafe_yyjson_get_type(mval);
2866 if (type == YYJSON_TYPE_ARR || type == YYJSON_TYPE_OBJ) {
2867 yyjson_mut_val *child = (yyjson_mut_val *)mval->uni.ptr;
2868 usize len = unsafe_yyjson_get_len(mval), i;
2869 usize val_sum = 1;
2870 if (type == YYJSON_TYPE_OBJ) {
2871 if (len) child = child->next->next;
2872 len <<= 1;
2873 } else {
2874 if (len) child = child->next;
2875 }
2876 *val_ptr = val + 1;
2877 for (i = 0; i < len; i++) {
2878 val_sum += yyjson_imut_copy(val_ptr, buf_ptr, child);
2879 child = child->next;
2880 }
2881 val->tag = mval->tag;
2882 val->uni.ofs = val_sum * sizeof(yyjson_val);
2883 return val_sum;
2884 } else if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
2885 char *buf = *buf_ptr;
2886 usize len = unsafe_yyjson_get_len(mval);
2887 memcpy((void *)buf, (const void *)mval->uni.str, len);
2888 buf[len] = '\0';
2889 val->tag = mval->tag;
2890 val->uni.str = buf;
2891 *val_ptr = val + 1;
2892 *buf_ptr = buf + len + 1;
2893 return 1;
2894 } else {
2895 val->tag = mval->tag;
2896 val->uni = mval->uni;
2897 *val_ptr = val + 1;
2898 return 1;
2899 }
2900}
2901
2902yyjson_doc *yyjson_mut_doc_imut_copy(const yyjson_mut_doc *mdoc,
2903 const yyjson_alc *alc) {
2904 if (!mdoc) return NULL;
2905 return yyjson_mut_val_imut_copy(mdoc->root, alc);
2906}
2907
2908yyjson_doc *yyjson_mut_val_imut_copy(const yyjson_mut_val *mval,
2909 const yyjson_alc *alc) {
2910 usize val_num = 0, str_sum = 0, hdr_size, buf_size;
2911 yyjson_doc *doc = NULL;
2912 yyjson_val *val_hdr = NULL;
2913
2914 /* This value should be NULL here. Setting a non-null value suppresses
2915 warning from the clang analyzer. */
2916 char *str_hdr = (char *)(void *)&str_sum;
2917 if (!mval) return NULL;
2918 if (!alc) alc = &YYJSON_DEFAULT_ALC;
2919
2920 /* traverse the input value to get pool size */
2921 yyjson_mut_stat(mval, &val_num, &str_sum);
2922
2923 /* create doc and val pool */
2924 hdr_size = size_align_up(sizeof(yyjson_doc), sizeof(yyjson_val));
2925 buf_size = hdr_size + val_num * sizeof(yyjson_val);
2926 doc = (yyjson_doc *)alc->malloc(alc->ctx, buf_size);
2927 if (!doc) return NULL;
2928 memset(doc, 0, sizeof(yyjson_doc));
2929 val_hdr = (yyjson_val *)(void *)((char *)(void *)doc + hdr_size);
2930 doc->root = val_hdr;
2931 doc->alc = *alc;
2932
2933 /* create str pool */
2934 if (str_sum > 0) {
2935 str_hdr = (char *)alc->malloc(alc->ctx, str_sum);
2936 doc->str_pool = str_hdr;
2937 if (!str_hdr) {
2938 alc->free(alc->ctx, (void *)doc);
2939 return NULL;
2940 }
2941 }
2942
2943 /* copy vals and strs */
2944 doc->val_read = yyjson_imut_copy(&val_hdr, &str_hdr, mval);
2945 doc->dat_read = str_sum + 1;
2946 return doc;
2947}
2948
2949static_inline bool unsafe_yyjson_num_equals(const void *lhs, const void *rhs) {
2950 const yyjson_val_uni *luni = &((const yyjson_val *)lhs)->uni;
2951 const yyjson_val_uni *runi = &((const yyjson_val *)rhs)->uni;
2952 yyjson_subtype lt = unsafe_yyjson_get_subtype(lhs);
2953 yyjson_subtype rt = unsafe_yyjson_get_subtype(rhs);
2954 if (lt == rt) return luni->u64 == runi->u64;
2955 if (lt == YYJSON_SUBTYPE_SINT && rt == YYJSON_SUBTYPE_UINT) {
2956 return luni->i64 >= 0 && luni->u64 == runi->u64;
2957 }
2958 if (lt == YYJSON_SUBTYPE_UINT && rt == YYJSON_SUBTYPE_SINT) {
2959 return runi->i64 >= 0 && luni->u64 == runi->u64;
2960 }
2961 return false;
2962}
2963
2964static_inline bool unsafe_yyjson_str_equals(const void *lhs, const void *rhs) {
2965 usize len = unsafe_yyjson_get_len(lhs);
2966 if (len != unsafe_yyjson_get_len(rhs)) return false;
2967 return !memcmp(unsafe_yyjson_get_str(lhs),
2968 unsafe_yyjson_get_str(rhs), len);
2969}
2970
2971bool unsafe_yyjson_equals(const yyjson_val *lhs, const yyjson_val *rhs) {
2972 yyjson_type type = unsafe_yyjson_get_type(lhs);
2973 if (type != unsafe_yyjson_get_type(rhs)) return false;
2974
2975 switch (type) {
2976 case YYJSON_TYPE_OBJ: {
2977 usize len = unsafe_yyjson_get_len(lhs);
2978 if (len != unsafe_yyjson_get_len(rhs)) return false;
2979 if (len > 0) {
2980 yyjson_obj_iter iter;
2981 yyjson_obj_iter_init(rhs, &iter);
2982 lhs = unsafe_yyjson_get_first(lhs);
2983 while (len-- > 0) {
2984 rhs = yyjson_obj_iter_getn(&iter, lhs->uni.str,
2985 unsafe_yyjson_get_len(lhs));
2986 if (!rhs) return false;
2987 if (!unsafe_yyjson_equals(lhs + 1, rhs)) return false;
2988 lhs = unsafe_yyjson_get_next(lhs + 1);
2989 }
2990 }
2991 /* yyjson allows duplicate keys, so the check may be inaccurate */
2992 return true;
2993 }
2994
2995 case YYJSON_TYPE_ARR: {
2996 usize len = unsafe_yyjson_get_len(lhs);
2997 if (len != unsafe_yyjson_get_len(rhs)) return false;
2998 if (len > 0) {
2999 lhs = unsafe_yyjson_get_first(lhs);
3000 rhs = unsafe_yyjson_get_first(rhs);
3001 while (len-- > 0) {
3002 if (!unsafe_yyjson_equals(lhs, rhs)) return false;
3003 lhs = unsafe_yyjson_get_next(lhs);
3004 rhs = unsafe_yyjson_get_next(rhs);
3005 }
3006 }
3007 return true;
3008 }
3009
3010 case YYJSON_TYPE_NUM:
3011 return unsafe_yyjson_num_equals(lhs, rhs);
3012
3013 case YYJSON_TYPE_RAW:
3014 case YYJSON_TYPE_STR:
3015 return unsafe_yyjson_str_equals(lhs, rhs);
3016
3017 case YYJSON_TYPE_NULL:
3018 case YYJSON_TYPE_BOOL:
3019 return lhs->tag == rhs->tag;
3020
3021 default:
3022 return false;
3023 }
3024}
3025
3026bool unsafe_yyjson_mut_equals(const yyjson_mut_val *lhs,
3027 const yyjson_mut_val *rhs) {
3028 yyjson_type type = unsafe_yyjson_get_type(lhs);
3029 if (type != unsafe_yyjson_get_type(rhs)) return false;
3030
3031 switch (type) {
3032 case YYJSON_TYPE_OBJ: {
3033 usize len = unsafe_yyjson_get_len(lhs);
3034 if (len != unsafe_yyjson_get_len(rhs)) return false;
3035 if (len > 0) {
3036 yyjson_mut_obj_iter iter;
3037 yyjson_mut_obj_iter_init(constcast(yyjson_mut_val *)rhs, &iter);
3038 lhs = (yyjson_mut_val *)lhs->uni.ptr;
3039 while (len-- > 0) {
3040 rhs = yyjson_mut_obj_iter_getn(&iter, lhs->uni.str,
3041 unsafe_yyjson_get_len(lhs));
3042 if (!rhs) return false;
3043 if (!unsafe_yyjson_mut_equals(lhs->next, rhs)) return false;
3044 lhs = lhs->next->next;
3045 }
3046 }
3047 /* yyjson allows duplicate keys, so the check may be inaccurate */
3048 return true;
3049 }
3050
3051 case YYJSON_TYPE_ARR: {
3052 usize len = unsafe_yyjson_get_len(lhs);
3053 if (len != unsafe_yyjson_get_len(rhs)) return false;
3054 if (len > 0) {
3055 lhs = (yyjson_mut_val *)lhs->uni.ptr;
3056 rhs = (yyjson_mut_val *)rhs->uni.ptr;
3057 while (len-- > 0) {
3058 if (!unsafe_yyjson_mut_equals(lhs, rhs)) return false;
3059 lhs = lhs->next;
3060 rhs = rhs->next;
3061 }
3062 }
3063 return true;
3064 }
3065
3066 case YYJSON_TYPE_NUM:
3067 return unsafe_yyjson_num_equals(lhs, rhs);
3068
3069 case YYJSON_TYPE_RAW:
3070 case YYJSON_TYPE_STR:
3071 return unsafe_yyjson_str_equals(lhs, rhs);
3072
3073 case YYJSON_TYPE_NULL:
3074 case YYJSON_TYPE_BOOL:
3075 return lhs->tag == rhs->tag;
3076
3077 default:
3078 return false;
3079 }
3080}
3081
3082bool yyjson_locate_pos(const char *str, size_t len, size_t pos,
3083 size_t *line, size_t *col, size_t *chr) {
3084 usize line_sum = 0, line_pos = 0, chr_sum = 0;
3085 const u8 *cur = (const u8 *)str;
3086 const u8 *end = cur + pos;
3087
3088 if (!str || pos > len) {
3089 if (line) *line = 0;
3090 if (col) *col = 0;
3091 if (chr) *chr = 0;
3092 return false;
3093 }
3094
3095 if (pos >= 3 && is_utf8_bom(cur)) cur += 3; /* don't count BOM */
3096 while (cur < end) {
3097 u8 c = *cur;
3098 chr_sum += 1;
3099 if (likely(c < 0x80)) { /* 0xxxxxxx (0x00-0x7F) ASCII */
3100 if (c == '\n') {
3101 line_sum += 1;
3102 line_pos = chr_sum;
3103 }
3104 cur += 1;
3105 }
3106 else if (c < 0xC0) cur += 1; /* 10xxxxxx (0x80-0xBF) Invalid */
3107 else if (c < 0xE0) cur += 2; /* 110xxxxx (0xC0-0xDF) 2-byte UTF-8 */
3108 else if (c < 0xF0) cur += 3; /* 1110xxxx (0xE0-0xEF) 3-byte UTF-8 */
3109 else if (c < 0xF8) cur += 4; /* 11110xxx (0xF0-0xF7) 4-byte UTF-8 */
3110 else cur += 1; /* 11111xxx (0xF8-0xFF) Invalid */
3111 }
3112 if (line) *line = line_sum + 1;
3113 if (col) *col = chr_sum - line_pos + 1;
3114 if (chr) *chr = chr_sum;
3115 return true;
3116}
3117
3118
3119
3120#if !YYJSON_DISABLE_READER /* reader begin */
3121
3122/* Check read flag, avoids `always false` warning when disabled. */
3123#define has_flg(_flg) unlikely(has_rflag(flg, YYJSON_READ_##_flg, 0))
3124#define has_allow(_flg) unlikely(has_rflag(flg, YYJSON_READ_ALLOW_##_flg, 1))
3125#define YYJSON_READ_ALLOW_TRIVIA (YYJSON_READ_ALLOW_COMMENTS | \
3126 YYJSON_READ_ALLOW_EXT_WHITESPACE)
3127static_inline bool has_rflag(yyjson_read_flag flg, yyjson_read_flag chk,
3128 bool non_standard) {
3129#if YYJSON_DISABLE_NON_STANDARD
3130 if (non_standard) return false;
3131#endif
3132 return (flg & chk) != 0;
3133}
3134
3135
3136
3137/*==============================================================================
3138 * MARK: - JSON Reader Utils (Private)
3139 * These functions are used by JSON reader to read literals and comments.
3140 *============================================================================*/
3141
3142/** Read `true` literal, `*ptr[0]` should be `t`. */
3143static_inline bool read_true(u8 **ptr, yyjson_val *val) {
3144 u8 *cur = *ptr;
3145 if (likely(byte_match_4(cur, "true"))) {
3146 val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_TRUE;
3147 *ptr = cur + 4;
3148 return true;
3149 }
3150 return false;
3151}
3152
3153/** Read `false` literal, `*ptr[0]` should be `f`. */
3154static_inline bool read_false(u8 **ptr, yyjson_val *val) {
3155 u8 *cur = *ptr;
3156 if (likely(byte_match_4(cur + 1, "alse"))) {
3157 val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_FALSE;
3158 *ptr = cur + 5;
3159 return true;
3160 }
3161 return false;
3162}
3163
3164/** Read `null` literal, `*ptr[0]` should be `n`. */
3165static_inline bool read_null(u8 **ptr, yyjson_val *val) {
3166 u8 *cur = *ptr;
3167 if (likely(byte_match_4(cur, "null"))) {
3168 val->tag = YYJSON_TYPE_NULL;
3169 *ptr = cur + 4;
3170 return true;
3171 }
3172 return false;
3173}
3174
3175/** Read `Inf` or `Infinity` literal (ignoring case). */
3176static_inline bool read_inf(u8 **ptr, u8 **pre,
3177 yyjson_read_flag flg, yyjson_val *val) {
3178 u8 *hdr = *ptr;
3179 u8 *cur = *ptr;
3180 u8 **end = ptr;
3181 bool sign = (*cur == '-');
3182 if (*cur == '+' && !has_allow(EXT_NUMBER)) return false;
3183 cur += char_is_sign(*cur);
3184 if (char_to_lower(cur[0]) == 'i' &&
3185 char_to_lower(cur[1]) == 'n' &&
3186 char_to_lower(cur[2]) == 'f') {
3187 if (char_to_lower(cur[3]) == 'i') {
3188 if (char_to_lower(cur[4]) == 'n' &&
3189 char_to_lower(cur[5]) == 'i' &&
3190 char_to_lower(cur[6]) == 't' &&
3191 char_to_lower(cur[7]) == 'y') {
3192 cur += 8;
3193 } else {
3194 return false;
3195 }
3196 } else {
3197 cur += 3;
3198 }
3199 *end = cur;
3200 if (has_flg(NUMBER_AS_RAW)) {
3201 **pre = '\0'; /* add null-terminator for previous raw string */
3202 *pre = cur; /* save end position for current raw string */
3203 val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
3204 val->uni.str = (const char *)hdr;
3205 } else {
3206 val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
3207 val->uni.u64 = f64_bits_inf(sign);
3208 }
3209 return true;
3210 }
3211 return false;
3212}
3213
3214/** Read `NaN` literal (ignoring case). */
3215static_inline bool read_nan(u8 **ptr, u8 **pre,
3216 yyjson_read_flag flg, yyjson_val *val) {
3217 u8 *hdr = *ptr;
3218 u8 *cur = *ptr;
3219 u8 **end = ptr;
3220 bool sign = (*cur == '-');
3221 if (*cur == '+' && !has_allow(EXT_NUMBER)) return false;
3222 cur += char_is_sign(*cur);
3223 if (char_to_lower(cur[0]) == 'n' &&
3224 char_to_lower(cur[1]) == 'a' &&
3225 char_to_lower(cur[2]) == 'n') {
3226 cur += 3;
3227 *end = cur;
3228 if (has_flg(NUMBER_AS_RAW)) {
3229 **pre = '\0'; /* add null-terminator for previous raw string */
3230 *pre = cur; /* save end position for current raw string */
3231 val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
3232 val->uni.str = (const char *)hdr;
3233 } else {
3234 val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
3235 val->uni.u64 = f64_bits_nan(sign);
3236 }
3237 return true;
3238 }
3239 return false;
3240}
3241
3242/** Read `Inf`, `Infinity` or `NaN` literal (ignoring case). */
3243static_inline bool read_inf_or_nan(u8 **ptr, u8 **pre,
3244 yyjson_read_flag flg, yyjson_val *val) {
3245 if (read_inf(ptr, pre, flg, val)) return true;
3246 if (read_nan(ptr, pre, flg, val)) return true;
3247 return false;
3248}
3249
3250/** Read a JSON number as raw string. */
3251static_noinline bool read_num_raw(u8 **ptr, u8 **pre, yyjson_read_flag flg,
3252 yyjson_val *val, const char **msg) {
3253#define return_err(_pos, _msg) do { \
3254 *msg = _msg; *end = _pos; return false; \
3255} while (false)
3256
3257#define return_raw() do { \
3258 val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
3259 val->uni.str = (const char *)hdr; \
3260 **pre = '\0'; *pre = cur; *end = cur; return true; \
3261} while (false)
3262
3263 u8 *hdr = *ptr;
3264 u8 *cur = *ptr;
3265 u8 **end = ptr;
3266
3267 /* skip sign */
3268 cur += (*cur == '-');
3269
3270 /* read first digit, check leading zero */
3271 while (unlikely(!char_is_digit(*cur))) {
3272 if (has_allow(EXT_NUMBER)) {
3273 if (*cur == '+' && cur == hdr) { /* leading `+` sign */
3274 cur++;
3275 continue;
3276 }
3277 if (*cur == '.' && char_is_digit(cur[1])) { /* e.g. '.123' */
3278 goto read_double;
3279 }
3280 }
3281 if (has_allow(INF_AND_NAN)) {
3282 if (read_inf_or_nan(ptr, pre, flg, val)) return true;
3283 }
3284 return_err(cur, "no digit after sign");
3285 }
3286
3287 /* read integral part */
3288 if (*cur == '0') {
3289 cur++;
3290 if (unlikely(char_is_digit(*cur))) {
3291 return_err(cur - 1, "number with leading zero is not allowed");
3292 }
3293 if (!char_is_fp(*cur)) {
3294 if (has_allow(EXT_NUMBER) && char_to_lower(*cur) == 'x') { /* hex */
3295 if (!char_is_hex(*++cur)) return_err(cur, "invalid hex number");
3296 while(char_is_hex(*cur)) cur++;
3297 }
3298 return_raw();
3299 }
3300 } else {
3301 while (char_is_digit(*cur)) cur++;
3302 if (!char_is_fp(*cur)) return_raw();
3303 }
3304
3305read_double:
3306 /* read fraction part */
3307 if (*cur == '.') {
3308 cur++;
3309 if (!char_is_digit(*cur)) {
3310 if (has_allow(EXT_NUMBER)) {
3311 if (!char_is_exp(*cur)) return_raw();
3312 } else {
3313 return_err(cur, "no digit after decimal point");
3314 }
3315 }
3316 while (char_is_digit(*cur)) cur++;
3317 }
3318
3319 /* read exponent part */
3320 if (char_is_exp(*cur)) {
3321 cur += 1 + char_is_sign(cur[1]);
3322 if (!char_is_digit(*cur++)) {
3323 return_err(cur, "no digit after exponent sign");
3324 }
3325 while (char_is_digit(*cur)) cur++;
3326 }
3327
3328 return_raw();
3329
3330#undef return_err
3331#undef return_raw
3332}
3333
3334/** Read a hex number. */
3335static_noinline bool read_num_hex(u8 **ptr, u8 **pre, yyjson_read_flag flg,
3336 yyjson_val *val, const char **msg) {
3337 u8 *hdr = *ptr;
3338 u8 *cur = *ptr;
3339 u8 **end = ptr;
3340 u64 sig = 0, i = 0;
3341 bool sign;
3342
3343 /* skip sign and '0x' */
3344 sign = (*cur == '-');
3345 cur += (*cur == '-' || *cur == '+') + 2;
3346
3347 /* read hex */
3348 for(; i < 16; i++) {
3349 u8 c = hex_conv_table[cur[i]];
3350 if (c == 0xF0) break;
3351 sig <<= 4;
3352 sig |= c;
3353 }
3354
3355 /* check error */
3356 if (unlikely(i == 0)) {
3357 *msg = "invalid hex number";
3358 return false;
3359 }
3360
3361 /* check overflow */
3362 if (unlikely(i == 16)) {
3363 if (char_is_hex(cur[16]) || (sign && sig > ((u64)1 << 63))) {
3364 if (!has_flg(BIGNUM_AS_RAW)) {
3365 *msg = "hex number overflow";
3366 return false;
3367 }
3368 cur += 16;
3369 while (char_is_hex(*cur)) cur++;
3370 **pre = '\0';
3371 val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
3372 val->uni.str = (const char *)hdr;
3373 *pre = cur; *end = cur;
3374 return true;
3375 }
3376 }
3377
3378 val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3);
3379 val->uni.u64 = (u64)(sign ? (u64)(~(sig) + 1) : (u64)(sig));
3380 *end = cur + i;
3381 return true;
3382}
3383
3384/**
3385 Skip trivia (whitespace and comments).
3386 This function should be used only when `char_is_trivia()` returns true.
3387 @param ptr (inout) Input current position, output end position.
3388 @param eof JSON end position.
3389 @param flg JSON read flags.
3390 @return true if at least one character was skipped.
3391 false if no characters were skipped,
3392 or if a multi-line comment is unterminated;
3393 in the latter case, `ptr` will be set to `eof`.
3394 */
3395static_noinline bool skip_trivia(u8 **ptr, u8 *eof, yyjson_read_flag flg) {
3396 u8 *hdr = *ptr, *cur = *ptr;
3397 usize len;
3398
3399 while (cur < eof) {
3400 u8 *loop_begin = cur;
3401
3402 /* skip standard whitespace */
3403 while(char_is_space(*cur)) cur++;
3404
3405 /* skip extended whitespace */
3406 if (has_allow(EXT_WHITESPACE)) {
3407 while (char_is_space_ext(*cur)) {
3408 cur += (len = ext_space_len(cur));
3409 if (!len) break;
3410 }
3411 }
3412
3413 /* skip comment, do not validate encoding */
3414 if (has_allow(COMMENTS) && cur[0] == '/') {
3415 if (cur[1] == '/') { /* single-line comment */
3416 cur += 2;
3417 if (has_allow(EXT_WHITESPACE)) {
3418 while (cur < eof) {
3419 if (char_is_eol_ext(*cur)) {
3420 cur += (len = ext_eol_len(cur));
3421 if (len) break;
3422 }
3423 cur++;
3424 }
3425 } else {
3426 while (cur < eof && !char_is_eol(*cur)) cur++;
3427 }
3428 } else if (cur[1] == '*') { /* multi-line comment */
3429 cur += 2;
3430 while (!byte_match_2(cur, "*/") && cur < eof) cur++;
3431 if (cur == eof) {
3432 *ptr = eof;
3433 return false; /* unclosed comment */
3434 }
3435 cur += 2;
3436 }
3437 }
3438 if (cur == loop_begin) break;
3439 }
3440 *ptr = cur;
3441 return cur > hdr;
3442}
3443
3444/**
3445 Check truncated UTF-8 character.
3446 Return true if `cur` starts a valid UTF-8 sequence that is truncated.
3447 */
3448static bool is_truncated_utf8(u8 *cur, u8 *eof) {
3449 u8 c0, c1, c2;
3450 usize len = (usize)(eof - cur);
3451 if (cur >= eof || len >= 4) return false;
3452 c0 = cur[0]; c1 = cur[1]; c2 = cur[2];
3453 /* 1-byte UTF-8, not truncated */
3454 if (c0 < 0x80) return false;
3455 if (len == 1) {
3456 /* 2-byte UTF-8, truncated */
3457 if ((c0 & 0xE0) == 0xC0 && (c0 & 0x1E) != 0x00) return true;
3458 /* 3-byte UTF-8, truncated */
3459 if ((c0 & 0xF0) == 0xE0) return true;
3460 /* 4-byte UTF-8, truncated */
3461 if ((c0 & 0xF8) == 0xF0 && (c0 & 0x07) <= 0x04) return true;
3462 } else if (len == 2) {
3463 /* 3-byte UTF-8, truncated */
3464 if ((c0 & 0xF0) == 0xE0 && (c1 & 0xC0) == 0x80) {
3465 u8 t = (u8)(((c0 & 0x0F) << 1) | ((c1 & 0x20) >> 5));
3466 return 0x01 <= t && t != 0x1B;
3467 }
3468 /* 4-byte UTF-8, truncated */
3469 if ((c0 & 0xF8) == 0xF0 && (c1 & 0xC0) == 0x80) {
3470 u8 t = (u8)(((c0 & 0x07) << 2) | ((c1 & 0x30) >> 4));
3471 return 0x01 <= t && t <= 0x10;
3472 }
3473 } else if (len == 3) {
3474 /* 4 bytes UTF-8, truncated */
3475 if ((c0 & 0xF8) == 0xF0 && (c1 & 0xC0) == 0x80 && (c2 & 0xC0) == 0x80) {
3476 u8 t = (u8)(((c0 & 0x07) << 2) | ((c1 & 0x30) >> 4));
3477 return 0x01 <= t && t <= 0x10;
3478 }
3479 }
3480 return false;
3481}
3482
3483/**
3484 Check truncated string.
3485 Returns true if `cur` match `str` but is truncated.
3486 The `str` should be lowercase ASCII letters.
3487 */
3488static bool is_truncated_str(u8 *cur, u8 *eof, const char *str,
3489 bool case_sensitive) {
3490 usize len = strlen(str);
3491 if (cur + len <= eof || eof <= cur) return false;
3492 if (case_sensitive) {
3493 return memcmp(cur, str, (usize)(eof - cur)) == 0;
3494 }
3495 for (; cur < eof; cur++, str++) {
3496 if (char_to_lower(*cur) != *(const u8 *)str) return false;
3497 }
3498 return true;
3499}
3500
3501/**
3502 Check truncated JSON on parsing errors.
3503 Returns true if the input is valid but truncated.
3504 */
3505static_noinline bool is_truncated_end(u8 *hdr, u8 *cur, u8 *eof,
3506 yyjson_read_code code,
3507 yyjson_read_flag flg) {
3508 if (cur >= eof) return true;
3509 if (code == YYJSON_READ_ERROR_LITERAL) {
3510 if (is_truncated_str(cur, eof, "true", true) ||
3511 is_truncated_str(cur, eof, "false", true) ||
3512 is_truncated_str(cur, eof, "null", true)) {
3513 return true;
3514 }
3515 }
3516 if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER ||
3517 code == YYJSON_READ_ERROR_INVALID_NUMBER ||
3518 code == YYJSON_READ_ERROR_LITERAL) {
3519 if (has_allow(INF_AND_NAN)) {
3520 if (*cur == '-') cur++;
3521 if (is_truncated_str(cur, eof, "infinity", false) ||
3522 is_truncated_str(cur, eof, "nan", false)) {
3523 return true;
3524 }
3525 }
3526 }
3527 if (code == YYJSON_READ_ERROR_UNEXPECTED_CONTENT) {
3528 if (has_allow(INF_AND_NAN)) {
3529 if (hdr + 3 <= cur &&
3530 is_truncated_str(cur - 3, eof, "infinity", false)) {
3531 return true; /* e.g. infin would be read as inf + in */
3532 }
3533 }
3534 }
3535 if (code == YYJSON_READ_ERROR_INVALID_STRING) {
3536 usize len = (usize)(eof - cur);
3537
3538 /* unicode escape sequence */
3539 if (*cur == '\\') {
3540 if (len == 1) return true;
3541 if (len <= 5) {
3542 if (*++cur != 'u') return false;
3543 for (++cur; cur < eof; cur++) {
3544 if (!char_is_hex(*cur)) return false;
3545 }
3546 return true;
3547 } else if (len <= 11) {
3548 /* incomplete surrogate pair? */
3549 u16 hi;
3550 if (*++cur != 'u') return false;
3551 if (!hex_load_4(++cur, &hi)) return false;
3552 if ((hi & 0xF800) != 0xD800) return false;
3553 cur += 4;
3554 if (cur >= eof) return true;
3555 /* valid low surrogate is DC00...DFFF */
3556 if (*cur != '\\') return false;
3557 if (++cur >= eof) return true;
3558 if (*cur != 'u') return false;
3559 if (++cur >= eof) return true;
3560 if (*cur != 'd' && *cur != 'D') return false;
3561 if (++cur >= eof) return true;
3562 if ((*cur < 'c' || *cur > 'f') && (*cur < 'C' || *cur > 'F'))
3563 return false;
3564 if (++cur >= eof) return true;
3565 if (!char_is_hex(*cur)) return false;
3566 return true;
3567 }
3568 return false;
3569 }
3570
3571 /* 2 to 4 bytes UTF-8 */
3572 if (is_truncated_utf8(cur, eof)) {
3573 return true;
3574 }
3575 }
3576 if (has_allow(COMMENTS)) {
3577 if (code == YYJSON_READ_ERROR_INVALID_COMMENT) {
3578 /* unclosed multiline comment */
3579 return true;
3580 }
3581 if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER &&
3582 *cur == '/' && cur + 1 == eof) {
3583 /* truncated beginning of comment */
3584 return true;
3585 }
3586 }
3587 if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER &&
3588 has_allow(BOM)) {
3589 /* truncated UTF-8 BOM */
3590 usize len = (usize)(eof - cur);
3591 if (cur == hdr && len < 3 && !memcmp(hdr, "\xEF\xBB\xBF", len)) {
3592 return true;
3593 }
3594 }
3595 return false;
3596}
3597
3598
3599
3600#if !YYJSON_DISABLE_FAST_FP_CONV /* FP_READER */
3601
3602/*==============================================================================
3603 * MARK: - BigInt For Floating Point Number Reader (Private)
3604 *
3605 * The bigint algorithm is used by floating-point number reader to get correctly
3606 * rounded result for numbers with lots of digits. This part of code is rarely
3607 * used for common numbers.
3608 *============================================================================*/
3609
3610/** Unsigned arbitrarily large integer */
3611typedef struct bigint {
3612 u32 used; /* used chunks count, should not be 0 */
3613 u64 bits[64]; /* chunks (58 is enough here) */
3614} bigint;
3615
3616/**
3617 Evaluate 'big += val'.
3618 @param big A big number (can be 0).
3619 @param val An unsigned integer (can be 0).
3620 */
3621static_inline void bigint_add_u64(bigint *big, u64 val) {
3622 u32 idx, max;
3623 u64 num = big->bits[0];
3624 u64 add = num + val;
3625 big->bits[0] = add;
3626 if (likely((add >= num) || (add >= val))) return;
3627 for ((void)(idx = 1), max = big->used; idx < max; idx++) {
3628 if (likely(big->bits[idx] != U64_MAX)) {
3629 big->bits[idx] += 1;
3630 return;
3631 }
3632 big->bits[idx] = 0;
3633 }
3634 big->bits[big->used++] = 1;
3635}
3636
3637/**
3638 Evaluate 'big *= val'.
3639 @param big A big number (can be 0).
3640 @param val An unsigned integer (cannot be 0).
3641 */
3642static_inline void bigint_mul_u64(bigint *big, u64 val) {
3643 u32 idx = 0, max = big->used;
3644 u64 hi, lo, carry = 0;
3645 for (; idx < max; idx++) {
3646 if (big->bits[idx]) break;
3647 }
3648 for (; idx < max; idx++) {
3649 u128_mul_add(big->bits[idx], val, carry, &hi, &lo);
3650 big->bits[idx] = lo;
3651 carry = hi;
3652 }
3653 if (carry) big->bits[big->used++] = carry;
3654}
3655
3656/**
3657 Evaluate 'big *= 2^exp'.
3658 @param big A big number (can be 0).
3659 @param exp An exponent integer (can be 0).
3660 */
3661static_inline void bigint_mul_pow2(bigint *big, u32 exp) {
3662 u32 shft = exp % 64;
3663 u32 move = exp / 64;
3664 u32 idx = big->used;
3665 if (unlikely(shft == 0)) {
3666 for (; idx > 0; idx--) {
3667 big->bits[idx + move - 1] = big->bits[idx - 1];
3668 }
3669 big->used += move;
3670 while (move) big->bits[--move] = 0;
3671 } else {
3672 big->bits[idx] = 0;
3673 for (; idx > 0; idx--) {
3674 u64 num = big->bits[idx] << shft;
3675 num |= big->bits[idx - 1] >> (64 - shft);
3676 big->bits[idx + move] = num;
3677 }
3678 big->bits[move] = big->bits[0] << shft;
3679 big->used += move + (big->bits[big->used + move] > 0);
3680 while (move) big->bits[--move] = 0;
3681 }
3682}
3683
3684/**
3685 Evaluate 'big *= 10^exp'.
3686 @param big A big number (can be 0).
3687 @param exp An exponent integer (cannot be 0).
3688 */
3689static_inline void bigint_mul_pow10(bigint *big, i32 exp) {
3690 for (; exp >= U64_POW10_MAX_EXACT_EXP; exp -= U64_POW10_MAX_EXACT_EXP) {
3691 bigint_mul_u64(big, u64_pow10_table[U64_POW10_MAX_EXACT_EXP]);
3692 }
3693 if (exp) {
3694 bigint_mul_u64(big, u64_pow10_table[exp]);
3695 }
3696}
3697
3698/**
3699 Compare two bigint.
3700 @return -1 if 'a < b', +1 if 'a > b', 0 if 'a == b'.
3701 */
3702static_inline i32 bigint_cmp(bigint *a, bigint *b) {
3703 u32 idx = a->used;
3704 if (a->used < b->used) return -1;
3705 if (a->used > b->used) return +1;
3706 while (idx-- > 0) {
3707 u64 av = a->bits[idx];
3708 u64 bv = b->bits[idx];
3709 if (av < bv) return -1;
3710 if (av > bv) return +1;
3711 }
3712 return 0;
3713}
3714
3715/**
3716 Evaluate 'big = val'.
3717 @param big A big number (can be 0).
3718 @param val An unsigned integer (can be 0).
3719 */
3720static_inline void bigint_set_u64(bigint *big, u64 val) {
3721 big->used = 1;
3722 big->bits[0] = val;
3723}
3724
3725/** Set a bigint with floating point number string. */
3726static_noinline void bigint_set_buf(bigint *big, u64 sig, i32 *exp,
3727 u8 *sig_cut, u8 *sig_end, u8 *dot_pos) {
3728
3729 if (unlikely(!sig_cut)) {
3730 /* no digit cut, set significant part only */
3731 bigint_set_u64(big, sig);
3732 return;
3733
3734 } else {
3735 /* some digits were cut, read them from 'sig_cut' to 'sig_end' */
3736 u8 *hdr = sig_cut;
3737 u8 *cur = hdr;
3738 u32 len = 0;
3739 u64 val = 0;
3740 bool dig_big_cut = false;
3741 bool has_dot = (hdr < dot_pos) & (dot_pos < sig_end);
3742 usize dig_len_total = U64_SAFE_DIG + (usize)(sig_end - hdr) - has_dot;
3743
3744 sig -= (*sig_cut >= '5'); /* sig was rounded before */
3745 if (dig_len_total > F64_MAX_DEC_DIG) {
3746 dig_big_cut = true;
3747 sig_end -= dig_len_total - (F64_MAX_DEC_DIG + 1);
3748 sig_end -= (dot_pos + 1 == sig_end);
3749 dig_len_total = (F64_MAX_DEC_DIG + 1);
3750 }
3751 *exp -= (i32)dig_len_total - U64_SAFE_DIG;
3752
3753 big->used = 1;
3754 big->bits[0] = sig;
3755 while (cur < sig_end) {
3756 if (likely(cur != dot_pos)) {
3757 val = val * 10 + (u8)(*cur++ - '0');
3758 len++;
3759 if (unlikely(cur == sig_end && dig_big_cut)) {
3760 /* The last digit must be non-zero, */
3761 /* set it to '1' for correct rounding. */
3762 val = val - (val % 10) + 1;
3763 }
3764 if (len == U64_SAFE_DIG || cur == sig_end) {
3765 bigint_mul_pow10(big, (i32)len);
3766 bigint_add_u64(big, val);
3767 val = 0;
3768 len = 0;
3769 }
3770 } else {
3771 cur++;
3772 }
3773 }
3774 }
3775}
3776
3777
3778
3779/*==============================================================================
3780 * MARK: - Diy Floating Point (Private)
3781 *============================================================================*/
3782
3783/** "Do It Yourself Floating Point" struct. */
3784typedef struct diy_fp {
3785 u64 sig; /* significand */
3786 i32 exp; /* exponent, base 2 */
3787 i32 pad; /* padding, useless */
3788} diy_fp;
3789
3790/** Get cached rounded diy_fp for pow(10, e). The input value must be in the
3791 range [POW10_SIG_TABLE_MIN_EXP, POW10_SIG_TABLE_MAX_EXP]. */
3792static_inline diy_fp diy_fp_get_cached_pow10(i32 exp10) {
3793 diy_fp fp;
3794 u64 sig_ext;
3795 pow10_table_get_sig(exp10, &fp.sig, &sig_ext);
3796 pow10_table_get_exp(exp10, &fp.exp);
3797 fp.sig += (sig_ext >> 63);
3798 return fp;
3799}
3800
3801/** Returns fp * fp2. */
3802static_inline diy_fp diy_fp_mul(diy_fp fp, diy_fp fp2) {
3803 u64 hi, lo;
3804 u128_mul(fp.sig, fp2.sig, &hi, &lo);
3805 fp.sig = hi + (lo >> 63);
3806 fp.exp += fp2.exp + 64;
3807 return fp;
3808}
3809
3810/** Convert diy_fp to IEEE-754 raw value. */
3811static_inline u64 diy_fp_to_ieee_raw(diy_fp fp) {
3812 u64 sig = fp.sig;
3813 i32 exp = fp.exp;
3814 u32 lz_bits;
3815 if (unlikely(fp.sig == 0)) return 0;
3816
3817 lz_bits = u64_lz_bits(sig);
3818 sig <<= lz_bits;
3819 sig >>= F64_BITS - F64_SIG_FULL_BITS;
3820 exp -= (i32)lz_bits;
3821 exp += F64_BITS - F64_SIG_FULL_BITS;
3822 exp += F64_SIG_BITS;
3823
3824 if (unlikely(exp >= F64_MAX_BIN_EXP)) {
3825 /* overflow */
3826 return F64_BITS_INF;
3827 } else if (likely(exp >= F64_MIN_BIN_EXP - 1)) {
3828 /* normal */
3829 exp += F64_EXP_BIAS;
3830 return ((u64)exp << F64_SIG_BITS) | (sig & F64_SIG_MASK);
3831 } else if (likely(exp >= F64_MIN_BIN_EXP - F64_SIG_FULL_BITS)) {
3832 /* subnormal */
3833 return sig >> (F64_MIN_BIN_EXP - exp - 1);
3834 } else {
3835 /* underflow */
3836 return 0;
3837 }
3838}
3839
3840
3841
3842/*==============================================================================
3843 * MARK: - Number Reader (Private)
3844 *============================================================================*/
3845
3846/**
3847 Read a JSON number.
3848
3849 1. This function assume that the floating-point number is in IEEE-754 format.
3850 2. This function support uint64/int64/double number. If an integer number
3851 cannot fit in uint64/int64, it will returns as a double number. If a double
3852 number is infinite, the return value is based on flag.
3853 3. This function (with inline attribute) may generate a lot of instructions.
3854 */
3855static_inline bool read_num(u8 **ptr, u8 **pre, yyjson_read_flag flg,
3856 yyjson_val *val, const char **msg) {
3857#define return_err(_pos, _msg) do { \
3858 *msg = _msg; \
3859 *end = _pos; \
3860 return false; \
3861} while (false)
3862
3863#define return_0() do { \
3864 val->tag = YYJSON_TYPE_NUM | (u8)((u8)sign << 3); \
3865 val->uni.u64 = 0; \
3866 *end = cur; return true; \
3867} while (false)
3868
3869#define return_i64(_v) do { \
3870 val->tag = YYJSON_TYPE_NUM | (u8)((u8)sign << 3); \
3871 val->uni.u64 = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \
3872 *end = cur; return true; \
3873} while (false)
3874
3875#define return_f64(_v) do { \
3876 val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
3877 val->uni.f64 = sign ? -(f64)(_v) : (f64)(_v); \
3878 *end = cur; return true; \
3879} while (false)
3880
3881#define return_f64_bin(_v) do { \
3882 val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
3883 val->uni.u64 = ((u64)sign << 63) | (u64)(_v); \
3884 *end = cur; return true; \
3885} while (false)
3886
3887#define return_inf() do { \
3888 if (has_flg(BIGNUM_AS_RAW)) return_raw(); \
3889 if (has_allow(INF_AND_NAN)) return_f64_bin(F64_BITS_INF); \
3890 else return_err(hdr, "number is infinity when parsed as double"); \
3891} while (false)
3892
3893#define return_raw() do { \
3894 **pre = '\0'; /* add null-terminator for previous raw string */ \
3895 val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
3896 val->uni.str = (const char *)hdr; \
3897 *pre = cur; *end = cur; return true; \
3898} while (false)
3899
3900 u8 *sig_cut = NULL; /* significant part cutting position for long number */
3901 u8 *sig_end = NULL; /* significant part ending position */
3902 u8 *dot_pos = NULL; /* decimal point position */
3903
3904 u64 sig = 0; /* significant part of the number */
3905 i32 exp = 0; /* exponent part of the number */
3906
3907 bool exp_sign; /* temporary exponent sign from literal part */
3908 i64 exp_sig = 0; /* temporary exponent number from significant part */
3909 i64 exp_lit = 0; /* temporary exponent number from exponent literal part */
3910 u64 num; /* temporary number for reading */
3911 u8 *tmp; /* temporary cursor for reading */
3912
3913 u8 *hdr = *ptr;
3914 u8 *cur = *ptr;
3915 u8 **end = ptr;
3916 bool sign;
3917
3918 /* read number as raw string if has `YYJSON_READ_NUMBER_AS_RAW` flag */
3919 if (has_flg(NUMBER_AS_RAW)) {
3920 return read_num_raw(ptr, pre, flg, val, msg);
3921 }
3922
3923 sign = (*hdr == '-');
3924 cur += sign;
3925
3926 /* begin with a leading zero or non-digit */
3927 while (unlikely(!char_is_nonzero(*cur))) { /* 0 or non-digit char */
3928 if (unlikely(*cur != '0')) { /* non-digit char */
3929 if (has_allow(EXT_NUMBER)) {
3930 if (*cur == '+' && cur == hdr) { /* leading `+` sign */
3931 cur++;
3932 continue;
3933 }
3934 if (*cur == '.' && char_is_digit(cur[1])) { /* e.g. '.123' */
3935 goto leading_dot;
3936 }
3937 }
3938 if (has_allow(INF_AND_NAN)) {
3939 if (read_inf_or_nan(ptr, pre, flg, val)) return true;
3940 }
3941 return_err(cur, "no digit after sign");
3942 }
3943 /* begin with 0 */
3944 if (likely(!char_is_digit_or_fp(*++cur))) {
3945 if (has_allow(EXT_NUMBER) && char_to_lower(*cur) == 'x') { /* hex */
3946 return read_num_hex(ptr, pre, flg, val, msg);
3947 }
3948 return_0();
3949 }
3950 if (likely(*cur == '.')) {
3951leading_dot:
3952 dot_pos = cur++;
3953 if (unlikely(!char_is_digit(*cur))) {
3954 if (has_allow(EXT_NUMBER)) {
3955 if (char_is_exp(*cur)) {
3956 goto digi_exp_more;
3957 } else {
3958 return_f64_bin(0);
3959 }
3960 }
3961 return_err(cur, "no digit after decimal point");
3962 }
3963 while (unlikely(*cur == '0')) cur++;
3964 if (likely(char_is_digit(*cur))) {
3965 /* first non-zero digit after decimal point */
3966 sig = (u64)(*cur - '0'); /* read first digit */
3967 cur--;
3968 goto digi_frac_1; /* continue read fraction part */
3969 }
3970 }
3971 if (unlikely(char_is_digit(*cur))) {
3972 return_err(cur - 1, "number with leading zero is not allowed");
3973 }
3974 if (unlikely(char_is_exp(*cur))) { /* 0 with any exponent is still 0 */
3975 cur += (usize)1 + char_is_sign(cur[1]);
3976 if (unlikely(!char_is_digit(*cur))) {
3977 return_err(cur, "no digit after exponent sign");
3978 }
3979 while (char_is_digit(*++cur));
3980 }
3981 return_f64_bin(0);
3982 }
3983
3984 /* begin with non-zero digit */
3985 sig = (u64)(*cur - '0');
3986
3987 /*
3988 Read integral part, same as the following code.
3989
3990 for (int i = 1; i <= 18; i++) {
3991 num = cur[i] - '0';
3992 if (num <= 9) sig = num + sig * 10;
3993 else goto digi_sepr_i;
3994 }
3995 */
3996#define expr_intg(i) \
3997 if (likely((num = (u64)(cur[i] - (u8)'0')) <= 9)) sig = num + sig * 10; \
3998 else { goto digi_sepr_##i; }
3999 repeat_in_1_18(expr_intg)
4000#undef expr_intg
4001
4002
4003 cur += 19; /* skip continuous 19 digits */
4004 if (!char_is_digit_or_fp(*cur)) {
4005 /* this number is an integer consisting of 19 digits */
4006 if (sign && (sig > ((u64)1 << 63))) { /* overflow */
4007 if (has_flg(BIGNUM_AS_RAW)) return_raw();
4008 return_f64(unsafe_yyjson_u64_to_f64(sig));
4009 }
4010 return_i64(sig);
4011 }
4012 goto digi_intg_more; /* read more digits in integral part */
4013
4014
4015 /* process first non-digit character */
4016#define expr_sepr(i) \
4017 digi_sepr_##i: \
4018 if (likely(!char_is_fp(cur[i]))) { cur += i; return_i64(sig); } \
4019 dot_pos = cur + i; \
4020 if (likely(cur[i] == '.')) goto digi_frac_##i; \
4021 cur += i; sig_end = cur; goto digi_exp_more;
4022 repeat_in_1_18(expr_sepr)
4023#undef expr_sepr
4024
4025
4026 /* read fraction part */
4027#define expr_frac(i) \
4028 digi_frac_##i: \
4029 if (likely((num = (u64)(cur[i + 1] - (u8)'0')) <= 9)) \
4030 sig = num + sig * 10; \
4031 else { goto digi_stop_##i; }
4032 repeat_in_1_18(expr_frac)
4033#undef expr_frac
4034
4035 cur += 20; /* skip 19 digits and 1 decimal point */
4036 if (!char_is_digit(*cur)) goto digi_frac_end; /* fraction part end */
4037 goto digi_frac_more; /* read more digits in fraction part */
4038
4039
4040 /* significant part end */
4041#define expr_stop(i) \
4042 digi_stop_##i: \
4043 cur += i + 1; \
4044 goto digi_frac_end;
4045 repeat_in_1_18(expr_stop)
4046#undef expr_stop
4047
4048
4049 /* read more digits in integral part */
4050digi_intg_more:
4051 if (char_is_digit(*cur)) {
4052 if (!char_is_digit_or_fp(cur[1])) {
4053 /* this number is an integer consisting of 20 digits */
4054 num = (u64)(*cur - '0');
4055 if ((sig < (U64_MAX / 10)) ||
4056 (sig == (U64_MAX / 10) && num <= (U64_MAX % 10))) {
4057 sig = num + sig * 10;
4058 cur++;
4059 /* convert to double if overflow */
4060 if (sign) {
4061 if (has_flg(BIGNUM_AS_RAW)) return_raw();
4062 return_f64(unsafe_yyjson_u64_to_f64(sig));
4063 }
4064 return_i64(sig);
4065 }
4066 }
4067 }
4068
4069 if (char_is_exp(*cur)) {
4070 dot_pos = cur;
4071 goto digi_exp_more;
4072 }
4073
4074 if (*cur == '.') {
4075 dot_pos = cur++;
4076 if (unlikely(!char_is_digit(*cur))) {
4077 if (has_allow(EXT_NUMBER)) {
4078 goto digi_frac_end;
4079 }
4080 return_err(cur, "no digit after decimal point");
4081 }
4082 }
4083
4084
4085 /* read more digits in fraction part */
4086digi_frac_more:
4087 sig_cut = cur; /* too large to fit in u64, excess digits need to be cut */
4088 sig += (*cur >= '5'); /* round */
4089 while (char_is_digit(*++cur));
4090 if (!dot_pos) {
4091 if (!char_is_fp(*cur) && has_flg(BIGNUM_AS_RAW)) {
4092 return_raw(); /* it's a large integer */
4093 }
4094 dot_pos = cur;
4095 if (*cur == '.') {
4096 if (unlikely(!char_is_digit(*++cur))) {
4097 if (!has_allow(EXT_NUMBER)) {
4098 return_err(cur, "no digit after decimal point");
4099 }
4100 }
4101 while (char_is_digit(*cur)) cur++;
4102 }
4103 }
4104 exp_sig = (i64)(dot_pos - sig_cut);
4105 exp_sig += (dot_pos < sig_cut);
4106
4107 /* ignore trailing zeros */
4108 tmp = cur - 1;
4109 while ((*tmp == '0' || *tmp == '.') && tmp > hdr) tmp--;
4110 if (tmp < sig_cut) {
4111 sig_cut = NULL;
4112 } else {
4113 sig_end = cur;
4114 }
4115
4116 if (char_is_exp(*cur)) goto digi_exp_more;
4117 goto digi_exp_finish;
4118
4119
4120 /* fraction part end */
4121digi_frac_end:
4122 if (unlikely(dot_pos + 1 == cur)) {
4123 if (!has_allow(EXT_NUMBER)) {
4124 return_err(cur, "no digit after decimal point");
4125 }
4126 }
4127 sig_end = cur;
4128 exp_sig = -(i64)((u64)(cur - dot_pos) - 1);
4129 if (likely(!char_is_exp(*cur))) {
4130 if (unlikely(exp_sig < F64_MIN_DEC_EXP - 19)) {
4131 return_f64_bin(0); /* underflow */
4132 }
4133 exp = (i32)exp_sig;
4134 goto digi_finish;
4135 } else {
4136 goto digi_exp_more;
4137 }
4138
4139
4140 /* read exponent part */
4141digi_exp_more:
4142 exp_sign = (*++cur == '-');
4143 cur += char_is_sign(*cur);
4144 if (unlikely(!char_is_digit(*cur))) {
4145 return_err(cur, "no digit after exponent sign");
4146 }
4147 while (*cur == '0') cur++;
4148
4149 /* read exponent literal */
4150 tmp = cur;
4151 while (char_is_digit(*cur)) {
4152 exp_lit = (i64)((u8)(*cur++ - '0') + (u64)exp_lit * 10);
4153 }
4154 if (unlikely(cur - tmp >= U64_SAFE_DIG)) {
4155 if (exp_sign) {
4156 return_f64_bin(0); /* underflow */
4157 } else {
4158 return_inf(); /* overflow */
4159 }
4160 }
4161 exp_sig += exp_sign ? -exp_lit : exp_lit;
4162
4163
4164 /* validate exponent value */
4165digi_exp_finish:
4166 if (unlikely(exp_sig < F64_MIN_DEC_EXP - 19)) {
4167 return_f64_bin(0); /* underflow */
4168 }
4169 if (unlikely(exp_sig > F64_MAX_DEC_EXP)) {
4170 return_inf(); /* overflow */
4171 }
4172 exp = (i32)exp_sig;
4173
4174
4175 /* all digit read finished */
4176digi_finish:
4177
4178 /*
4179 Fast path 1:
4180
4181 1. The floating-point number calculation should be accurate, see the
4182 comments of macro `YYJSON_DOUBLE_MATH_CORRECT`.
4183 2. Correct rounding should be performed (fegetround() == FE_TONEAREST).
4184 3. The input to floating-point calculations does not lose precision,
4185 which means: 64 - leading_zero(input) - trailing_zero(input) < 53.
4186
4187 We don't check all available inputs here, because that would make the code
4188 more complicated, and not friendly to branch predictor.
4189 */
4190#if YYJSON_DOUBLE_MATH_CORRECT
4191 if (sig < ((u64)1 << 53) &&
4192 exp >= -F64_POW10_MAX_EXACT_EXP &&
4193 exp <= +F64_POW10_MAX_EXACT_EXP) {
4194 f64 dbl = (f64)sig;
4195 if (exp < 0) {
4196 dbl /= f64_pow10_table[-exp];
4197 } else {
4198 dbl *= f64_pow10_table[+exp];
4199 }
4200 return_f64(dbl);
4201 }
4202#endif
4203 if (unlikely(sig == 0)) return_f64_bin(0);
4204
4205 /*
4206 Fast path 2:
4207
4208 To keep it simple, we only accept normal number here,
4209 let the slow path handle subnormal and infinite numbers.
4210 */
4211 if (likely(!sig_cut &&
4212 exp > -F64_MAX_DEC_EXP + 1 &&
4213 exp < +F64_MAX_DEC_EXP - 20)) {
4214 /*
4215 The result value is exactly equal to (sig * 10^exp),
4216 the exponent part (10^exp) can be converted to (sig2 * 2^exp2).
4217
4218 The sig2 can be an infinite length number, only the highest 128 bits
4219 is cached in the pow10_sig_table.
4220
4221 Now we have these bits:
4222 sig1 (normalized 64bit) : aaaaaaaa
4223 sig2 (higher 64bit) : bbbbbbbb
4224 sig2_ext (lower 64bit) : cccccccc
4225 sig2_cut (extra unknown bits) : dddddddddddd....
4226
4227 And the calculation process is:
4228 ----------------------------------------
4229 aaaaaaaa *
4230 bbbbbbbbccccccccdddddddddddd....
4231 ----------------------------------------
4232 abababababababab +
4233 acacacacacacacac +
4234 adadadadadadadadadad....
4235 ----------------------------------------
4236 [hi____][lo____] +
4237 [hi2___][lo2___] +
4238 [unknown___________....]
4239 ----------------------------------------
4240
4241 The addition with carry may affect higher bits, but if there is a 0
4242 in higher bits, the bits higher than 0 will not be affected.
4243
4244 `lo2` + `unknown` may get a carry bit and may affect `hi2`, the max
4245 value of `hi2` is 0xFFFFFFFFFFFFFFFE, so `hi2` will not overflow.
4246
4247 `lo` + `hi2` may also get a carry bit and may affect `hi`, but only
4248 the highest significant 53 bits of `hi` is needed. If there is a 0
4249 in the lower bits of `hi`, then all the following bits can be dropped.
4250
4251 To convert the result to IEEE-754 double number, we need to perform
4252 correct rounding:
4253 1. if bit 54 is 0, round down,
4254 2. if bit 54 is 1 and any bit beyond bit 54 is 1, round up,
4255 3. if bit 54 is 1 and all bits beyond bit 54 are 0, round to even,
4256 as the extra bits is unknown, this case will not be handled here.
4257 */
4258
4259 u64 raw;
4260 u64 sig1, sig2, sig2_ext, hi, lo, hi2, lo2, add, bits;
4261 i32 exp2;
4262 u32 lz;
4263 bool exact = false, carry, round_up;
4264
4265 /* convert (10^exp) to (sig2 * 2^exp2) */
4266 pow10_table_get_sig(exp, &sig2, &sig2_ext);
4267 pow10_table_get_exp(exp, &exp2);
4268
4269 /* normalize and multiply */
4270 lz = u64_lz_bits(sig);
4271 sig1 = sig << lz;
4272 exp2 -= (i32)lz;
4273 u128_mul(sig1, sig2, &hi, &lo);
4274
4275 /*
4276 The `hi` is in range [0x4000000000000000, 0xFFFFFFFFFFFFFFFE],
4277 To get normalized value, `hi` should be shifted to the left by 0 or 1.
4278
4279 The highest significant 53 bits is used by IEEE-754 double number,
4280 and the bit 54 is used to detect rounding direction.
4281
4282 The lowest (64 - 54 - 1) bits is used to check whether it contains 0.
4283 */
4284 bits = hi & (((u64)1 << (64 - 54 - 1)) - 1);
4285 if (bits - 1 < (((u64)1 << (64 - 54 - 1)) - 2)) {
4286 /*
4287 (bits != 0 && bits != 0x1FF) => (bits - 1 < 0x1FF - 1)
4288 The `bits` is not zero, so we don't need to check `round to even`
4289 case. The `bits` contains bit `0`, so we can drop the extra bits
4290 after `0`.
4291 */
4292 exact = true;
4293
4294 } else {
4295 /*
4296 (bits == 0 || bits == 0x1FF)
4297 The `bits` is filled with all `0` or all `1`, so we need to check
4298 lower bits with another 64-bit multiplication.
4299 */
4300 u128_mul(sig1, sig2_ext, &hi2, &lo2);
4301
4302 add = lo + hi2;
4303 if (add + 1 > (u64)1) {
4304 /*
4305 (add != 0 && add != U64_MAX) => (add + 1 > 1)
4306 The `add` is not zero, so we don't need to check `round to
4307 even` case. The `add` contains bit `0`, so we can drop the
4308 extra bits after `0`. The `hi` cannot be U64_MAX, so it will
4309 not overflow.
4310 */
4311 carry = add < lo || add < hi2;
4312 hi += carry;
4313 exact = true;
4314 }
4315 }
4316
4317 if (exact) {
4318 /* normalize */
4319 lz = hi < ((u64)1 << 63);
4320 hi <<= lz;
4321 exp2 -= (i32)lz;
4322 exp2 += 64;
4323
4324 /* test the bit 54 and get rounding direction */
4325 round_up = (hi & ((u64)1 << (64 - 54))) > (u64)0;
4326 hi += (round_up ? ((u64)1 << (64 - 54)) : (u64)0);
4327
4328 /* test overflow */
4329 if (hi < ((u64)1 << (64 - 54))) {
4330 hi = ((u64)1 << 63);
4331 exp2 += 1;
4332 }
4333
4334 /* This is a normal number, convert it to IEEE-754 format. */
4335 hi >>= F64_BITS - F64_SIG_FULL_BITS;
4336 exp2 += F64_BITS - F64_SIG_FULL_BITS + F64_SIG_BITS;
4337 exp2 += F64_EXP_BIAS;
4338 raw = ((u64)exp2 << F64_SIG_BITS) | (hi & F64_SIG_MASK);
4339 return_f64_bin(raw);
4340 }
4341 }
4342
4343 /*
4344 Slow path: read double number exactly with diyfp.
4345 1. Use cached diyfp to get an approximation value.
4346 2. Use bigcomp to check the approximation value if needed.
4347
4348 This algorithm refers to google's double-conversion project:
4349 https://github.com/google/double-conversion
4350 */
4351 {
4352 const i32 ERR_ULP_LOG = 3;
4353 const i32 ERR_ULP = 1 << ERR_ULP_LOG;
4354 const i32 ERR_CACHED_POW = ERR_ULP / 2;
4355 const i32 ERR_MUL_FIXED = ERR_ULP / 2;
4356 const i32 DIY_SIG_BITS = 64;
4357 const i32 EXP_BIAS = F64_EXP_BIAS + F64_SIG_BITS;
4358 const i32 EXP_SUBNORMAL = -EXP_BIAS + 1;
4359
4360 u64 fp_err;
4361 u32 bits;
4362 i32 order_of_magnitude;
4363 i32 effective_significand_size;
4364 i32 precision_digits_count;
4365 u64 precision_bits;
4366 u64 half_way;
4367
4368 u64 raw;
4369 diy_fp fp, fp_upper;
4370 bigint big_full, big_comp;
4371 i32 cmp;
4372
4373 fp.sig = sig;
4374 fp.exp = 0;
4375 fp_err = sig_cut ? (u64)(ERR_ULP / 2) : (u64)0;
4376
4377 /* normalize */
4378 bits = u64_lz_bits(fp.sig);
4379 fp.sig <<= bits;
4380 fp.exp -= (i32)bits;
4381 fp_err <<= bits;
4382
4383 /* multiply and add error */
4384 fp = diy_fp_mul(fp, diy_fp_get_cached_pow10(exp));
4385 fp_err += (u64)ERR_CACHED_POW + (fp_err != 0) + (u64)ERR_MUL_FIXED;
4386
4387 /* normalize */
4388 bits = u64_lz_bits(fp.sig);
4389 fp.sig <<= bits;
4390 fp.exp -= (i32)bits;
4391 fp_err <<= bits;
4392
4393 /* effective significand */
4394 order_of_magnitude = DIY_SIG_BITS + fp.exp;
4395 if (likely(order_of_magnitude >= EXP_SUBNORMAL + F64_SIG_FULL_BITS)) {
4396 effective_significand_size = F64_SIG_FULL_BITS;
4397 } else if (order_of_magnitude <= EXP_SUBNORMAL) {
4398 effective_significand_size = 0;
4399 } else {
4400 effective_significand_size = order_of_magnitude - EXP_SUBNORMAL;
4401 }
4402
4403 /* precision digits count */
4404 precision_digits_count = DIY_SIG_BITS - effective_significand_size;
4405 if (unlikely(precision_digits_count + ERR_ULP_LOG >= DIY_SIG_BITS)) {
4406 i32 shr = (precision_digits_count + ERR_ULP_LOG) - DIY_SIG_BITS + 1;
4407 fp.sig >>= shr;
4408 fp.exp += shr;
4409 fp_err = (fp_err >> shr) + 1 + (u32)ERR_ULP;
4410 precision_digits_count -= shr;
4411 }
4412
4413 /* half way */
4414 precision_bits = fp.sig & (((u64)1 << precision_digits_count) - 1);
4415 precision_bits *= (u32)ERR_ULP;
4416 half_way = (u64)1 << (precision_digits_count - 1);
4417 half_way *= (u32)ERR_ULP;
4418
4419 /* rounding */
4420 fp.sig >>= precision_digits_count;
4421 fp.sig += (precision_bits >= half_way + fp_err);
4422 fp.exp += precision_digits_count;
4423
4424 /* get IEEE double raw value */
4425 raw = diy_fp_to_ieee_raw(fp);
4426 if (unlikely(raw == F64_BITS_INF)) return_inf();
4427 if (likely(precision_bits <= half_way - fp_err ||
4428 precision_bits >= half_way + fp_err)) {
4429 return_f64_bin(raw); /* number is accurate */
4430 }
4431 /* now the number is the correct value, or the next lower value */
4432
4433 /* upper boundary */
4434 if (raw & F64_EXP_MASK) {
4435 fp_upper.sig = (raw & F64_SIG_MASK) + ((u64)1 << F64_SIG_BITS);
4436 fp_upper.exp = (i32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
4437 } else {
4438 fp_upper.sig = (raw & F64_SIG_MASK);
4439 fp_upper.exp = 1;
4440 }
4441 fp_upper.exp -= F64_EXP_BIAS + F64_SIG_BITS;
4442 fp_upper.sig <<= 1;
4443 fp_upper.exp -= 1;
4444 fp_upper.sig += 1; /* add half ulp */
4445
4446 /* compare with bigint */
4447 bigint_set_buf(&big_full, sig, &exp, sig_cut, sig_end, dot_pos);
4448 bigint_set_u64(&big_comp, fp_upper.sig);
4449 if (exp >= 0) {
4450 bigint_mul_pow10(&big_full, +exp);
4451 } else {
4452 bigint_mul_pow10(&big_comp, -exp);
4453 }
4454 if (fp_upper.exp > 0) {
4455 bigint_mul_pow2(&big_comp, (u32)+fp_upper.exp);
4456 } else {
4457 bigint_mul_pow2(&big_full, (u32)-fp_upper.exp);
4458 }
4459 cmp = bigint_cmp(&big_full, &big_comp);
4460 if (likely(cmp != 0)) {
4461 /* round down or round up */
4462 raw += (cmp > 0);
4463 } else {
4464 /* falls midway, round to even */
4465 raw += (raw & 1);
4466 }
4467
4468 if (unlikely(raw == F64_BITS_INF)) return_inf();
4469 return_f64_bin(raw);
4470 }
4471
4472#undef return_err
4473#undef return_inf
4474#undef return_0
4475#undef return_i64
4476#undef return_f64
4477#undef return_f64_bin
4478#undef return_raw
4479}
4480
4481
4482
4483#else /* FP_READER */
4484
4485/**
4486 Read a JSON number.
4487 This is a fallback function if the custom number reader is disabled.
4488 This function use libc's strtod() to read floating-point number.
4489 */
4490static_inline bool read_num(u8 **ptr, u8 **pre, yyjson_read_flag flg,
4491 yyjson_val *val, const char **msg) {
4492#define return_err(_pos, _msg) do { \
4493 *msg = _msg; \
4494 *end = _pos; \
4495 return false; \
4496} while (false)
4497
4498#define return_0() do { \
4499 val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); \
4500 val->uni.u64 = 0; \
4501 *end = cur; return true; \
4502} while (false)
4503
4504#define return_i64(_v) do { \
4505 val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); \
4506 val->uni.u64 = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \
4507 *end = cur; return true; \
4508} while (false)
4509
4510#define return_f64(_v) do { \
4511 val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
4512 val->uni.f64 = sign ? -(f64)(_v) : (f64)(_v); \
4513 *end = cur; return true; \
4514} while (false)
4515
4516#define return_f64_bin(_v) do { \
4517 val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
4518 val->uni.u64 = ((u64)sign << 63) | (u64)(_v); \
4519 *end = cur; return true; \
4520} while (false)
4521
4522#define return_inf() do { \
4523 if (has_flg(BIGNUM_AS_RAW)) return_raw(); \
4524 if (has_allow(INF_AND_NAN)) return_f64_bin(F64_BITS_INF); \
4525 else return_err(hdr, "number is infinity when parsed as double"); \
4526} while (false)
4527
4528#define return_raw() do { \
4529 val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
4530 val->uni.str = (const char *)hdr; \
4531 **pre = '\0'; *pre = cur; *end = cur; return true; \
4532} while (false)
4533
4534 u64 sig, num;
4535 u8 *hdr = *ptr;
4536 u8 *cur = *ptr;
4537 u8 **end = ptr;
4538 u8 *dot = NULL;
4539 u8 *f64_end = NULL;
4540 bool sign;
4541
4542 /* read number as raw string if has `YYJSON_READ_NUMBER_AS_RAW` flag */
4543 if (has_flg(NUMBER_AS_RAW)) {
4544 return read_num_raw(ptr, pre, flg, val, msg);
4545 }
4546
4547 sign = (*hdr == '-');
4548 cur += sign;
4549 sig = (u8)(*cur - '0');
4550
4551 /* read first digit, check leading zero */
4552 while (unlikely(!char_is_digit(*cur))) {
4553 if (has_allow(EXT_NUMBER)) {
4554 if (*cur == '+' && cur == hdr) { /* leading `+` sign */
4555 cur++;
4556 sig = (u8)(*cur - '0');
4557 continue;
4558 }
4559 if (*cur == '.' && char_is_num(cur[1])) { /* no integer part */
4560 goto read_double; /* e.g. '.123' */
4561 }
4562 }
4563 if (has_allow(INF_AND_NAN)) {
4564 if (read_inf_or_nan(ptr, pre, flg, val)) return true;
4565 }
4566 return_err(cur, "no digit after sign");
4567 }
4568 if (*cur == '0') {
4569 cur++;
4570 if (unlikely(char_is_digit(*cur))) {
4571 return_err(cur - 1, "number with leading zero is not allowed");
4572 }
4573 if (!char_is_fp(*cur)) {
4574 if (has_allow(EXT_NUMBER) &&
4575 (*cur == 'x' || *cur == 'X')) { /* hex integer */
4576 return read_num_hex(ptr, pre, flg, val, msg);
4577 }
4578 return_0();
4579 }
4580 goto read_double;
4581 }
4582
4583 /* read continuous digits, up to 19 characters */
4584#define expr_intg(i) \
4585 if (likely((num = (u64)(cur[i] - (u8)'0')) <= 9)) sig = num + sig * 10; \
4586 else { cur += i; goto intg_end; }
4587 repeat_in_1_18(expr_intg)
4588#undef expr_intg
4589
4590 /* here are 19 continuous digits, skip them */
4591 cur += 19;
4592 if (char_is_digit(cur[0]) && !char_is_digit_or_fp(cur[1])) {
4593 /* this number is an integer consisting of 20 digits */
4594 num = (u8)(*cur - '0');
4595 if ((sig < (U64_MAX / 10)) ||
4596 (sig == (U64_MAX / 10) && num <= (U64_MAX % 10))) {
4597 sig = num + sig * 10;
4598 cur++;
4599 if (sign) {
4600 if (has_flg(BIGNUM_AS_RAW)) return_raw();
4601 return_f64(unsafe_yyjson_u64_to_f64(sig));
4602 }
4603 return_i64(sig);
4604 }
4605 }
4606
4607intg_end:
4608 /* continuous digits ended */
4609 if (!char_is_digit_or_fp(*cur)) {
4610 /* this number is an integer consisting of 1 to 19 digits */
4611 if (sign && (sig > ((u64)1 << 63))) {
4612 if (has_flg(BIGNUM_AS_RAW)) return_raw();
4613 return_f64(unsafe_yyjson_u64_to_f64(sig));
4614 }
4615 return_i64(sig);
4616 }
4617
4618read_double:
4619 /* this number should be read as double */
4620 while (char_is_digit(*cur)) cur++;
4621 if (!char_is_fp(*cur) && has_flg(BIGNUM_AS_RAW)) {
4622 return_raw(); /* it's a large integer */
4623 }
4624 while (*cur == '.') {
4625 /* skip fraction part */
4626 dot = cur;
4627 cur++;
4628 if (!char_is_digit(*cur)) {
4629 if (has_allow(EXT_NUMBER)) {
4630 break;
4631 } else {
4632 return_err(cur, "no digit after decimal point");
4633 }
4634 }
4635 cur++;
4636 while (char_is_digit(*cur)) cur++;
4637 break;
4638 }
4639 if (char_is_exp(*cur)) {
4640 /* skip exponent part */
4641 cur += 1 + char_is_sign(cur[1]);
4642 if (!char_is_digit(*cur)) {
4643 return_err(cur, "no digit after exponent sign");
4644 }
4645 cur++;
4646 while (char_is_digit(*cur)) cur++;
4647 }
4648
4649 /*
4650 libc's strtod() is used to parse the floating-point number.
4651
4652 Note that the decimal point character used by strtod() is locale-dependent,
4653 and the rounding direction may affected by fesetround().
4654
4655 For currently known locales, (en, zh, ja, ko, am, he, hi) use '.' as the
4656 decimal point, while other locales use ',' as the decimal point.
4657
4658 Here strtod() is called twice for different locales, but if another thread
4659 happens calls setlocale() between two strtod(), parsing may still fail.
4660 */
4661 val->uni.f64 = strtod((const char *)hdr, (char **)&f64_end);
4662 if (unlikely(f64_end != cur)) {
4663 /* replace '.' with ',' for locale */
4664 bool cut = (*cur == ',');
4665 if (cut) *cur = ' ';
4666 if (dot) *dot = ',';
4667 val->uni.f64 = strtod((const char *)hdr, (char **)&f64_end);
4668 /* restore ',' to '.' */
4669 if (cut) *cur = ',';
4670 if (dot) *dot = '.';
4671 if (unlikely(f64_end != cur)) {
4672 return_err(hdr, "strtod() failed to parse the number");
4673 }
4674 }
4675 if (unlikely(f64_is_inf(val->uni.f64))) {
4676 return_inf();
4677 }
4678 val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
4679 *end = cur;
4680 return true;
4681
4682#undef return_err
4683#undef return_0
4684#undef return_i64
4685#undef return_f64
4686#undef return_f64_bin
4687#undef return_inf
4688#undef return_raw
4689}
4690
4691#endif /* FP_READER */
4692
4693
4694
4695/*==============================================================================
4696 * MARK: - String Reader (Private)
4697 *============================================================================*/
4698
4699/** Read unicode escape sequence. */
4700static_inline bool read_uni_esc(u8 **src_ptr, u8 **dst_ptr, const char **msg) {
4701#define return_err(_end, _msg) *msg = _msg; *src_ptr = _end; return false
4702
4703 u8 *src = *src_ptr;
4704 u8 *dst = *dst_ptr;
4705 u16 hi, lo;
4706 u32 uni;
4707
4708 src += 2; /* skip `\u` */
4709 if (unlikely(!hex_load_4(src, &hi))) {
4710 return_err(src - 2, "invalid escaped sequence in string");
4711 }
4712 src += 4; /* skip hex */
4713 if (likely((hi & 0xF800) != 0xD800)) {
4714 /* a BMP character */
4715 if (hi >= 0x800) {
4716 *dst++ = (u8)(0xE0 | (hi >> 12));
4717 *dst++ = (u8)(0x80 | ((hi >> 6) & 0x3F));
4718 *dst++ = (u8)(0x80 | (hi & 0x3F));
4719 } else if (hi >= 0x80) {
4720 *dst++ = (u8)(0xC0 | (hi >> 6));
4721 *dst++ = (u8)(0x80 | (hi & 0x3F));
4722 } else {
4723 *dst++ = (u8)hi;
4724 }
4725 } else {
4726 /* a non-BMP character, represented as a surrogate pair */
4727 if (unlikely((hi & 0xFC00) != 0xD800)) {
4728 return_err(src - 6, "invalid high surrogate in string");
4729 }
4730 if (unlikely(!byte_match_2(src, "\\u"))) {
4731 return_err(src - 6, "no low surrogate in string");
4732 }
4733 if (unlikely(!hex_load_4(src + 2, &lo))) {
4734 return_err(src - 6, "invalid escape in string");
4735 }
4736 if (unlikely((lo & 0xFC00) != 0xDC00)) {
4737 return_err(src - 6, "invalid low surrogate in string");
4738 }
4739 uni = ((((u32)hi - 0xD800) << 10) |
4740 ((u32)lo - 0xDC00)) + 0x10000;
4741 *dst++ = (u8)(0xF0 | (uni >> 18));
4742 *dst++ = (u8)(0x80 | ((uni >> 12) & 0x3F));
4743 *dst++ = (u8)(0x80 | ((uni >> 6) & 0x3F));
4744 *dst++ = (u8)(0x80 | (uni & 0x3F));
4745 src += 6;
4746 }
4747 *src_ptr = src;
4748 *dst_ptr = dst;
4749 return true;
4750#undef return_err
4751}
4752
4753/**
4754 Read a JSON string.
4755 @param quo The quote character (single quote or double quote).
4756 @param ptr The head pointer of string before quote (inout).
4757 @param eof JSON end position.
4758 @param flg JSON read flag.
4759 @param val The string value to be written.
4760 @param msg The error message pointer.
4761 @param con Continuation for incremental parsing.
4762 @return Whether success.
4763 */
4764static_inline bool read_str_opt(u8 quo, u8 **ptr, u8 *eof, yyjson_read_flag flg,
4765 yyjson_val *val, const char **msg, u8 *con[2]) {
4766 /*
4767 GCC may sometimes load variables into registers too early, causing
4768 unnecessary instructions and performance degradation. This inline assembly
4769 serves as a hint to GCC: 'This variable will be modified, so avoid loading
4770 it too early.' Other compilers like MSVC, Clang, and ICC can generate the
4771 expected instructions without needing this hint.
4772
4773 Check out this example: https://godbolt.org/z/YG6a5W5Ec
4774 */
4775#define return_err(_end, _msg) do { \
4776 *msg = _msg; \
4777 *end = _end; \
4778 if (con) { con[0] = _end; con[1] = dst; } \
4779 return false; \
4780} while (false)
4781
4782 u8 *hdr = *ptr + 1;
4783 u8 **end = ptr;
4784 u8 *src = hdr, *dst = NULL, *pos;
4785 u32 uni, tmp;
4786
4787 /* Resume incremental parsing. */
4788 if (con && unlikely(con[0])) {
4789 src = con[0];
4790 dst = con[1];
4791 if (dst) goto copy_ascii;
4792 }
4793
4794skip_ascii:
4795 /*
4796 Most strings have no escaped characters, so we can jump them quickly.
4797
4798 We want to make loop unrolling, as shown in the following code. Some
4799 compiler may not generate instructions as expected, so we rewrite it with
4800 explicit goto statements. We hope the compiler can generate instructions
4801 like this: https://godbolt.org/z/8vjsYq
4802
4803 while (true) repeat16({
4804 if (likely((char_is_ascii_skip(*src)))) src++;
4805 else break;
4806 })
4807 */
4808 if (quo == '"') {
4809#define expr_jump(i) \
4810 if (likely(char_is_ascii_skip(src[i]))) {} \
4811 else goto skip_ascii_stop##i;
4812
4813#define expr_stop(i) \
4814 skip_ascii_stop##i: \
4815 src += i; \
4816 goto skip_ascii_end;
4817
4818 repeat16_incr(expr_jump)
4819 src += 16;
4820 goto skip_ascii;
4821 repeat16_incr(expr_stop)
4822
4823#undef expr_jump
4824#undef expr_stop
4825 } else {
4826#define expr_jump(i) \
4827 if (likely(char_is_ascii_skip_sq(src[i]))) {} \
4828 else goto skip_ascii_stop_sq##i;
4829
4830#define expr_stop(i) \
4831 skip_ascii_stop_sq##i: \
4832 src += i; \
4833 goto skip_ascii_end;
4834
4835 repeat16_incr(expr_jump)
4836 src += 16;
4837 goto skip_ascii;
4838 repeat16_incr(expr_stop)
4839
4840#undef expr_jump
4841#undef expr_stop
4842 }
4843
4844skip_ascii_end:
4845 gcc_store_barrier(*src);
4846 if (likely(*src == quo)) {
4847 val->tag = ((u64)(src - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR |
4848 (quo == '"' ? YYJSON_SUBTYPE_NOESC : 0);
4849 val->uni.str = (const char *)hdr;
4850 *src = '\0';
4851 *end = src + 1;
4852 if (con) con[0] = con[1] = NULL;
4853 return true;
4854 }
4855
4856skip_utf8:
4857 if (*src & 0x80) { /* non-ASCII character */
4858 /*
4859 Non-ASCII character appears here, which means that the text is likely
4860 to be written in non-English or emoticons. According to some common
4861 data set statistics, byte sequences of the same length may appear
4862 consecutively. We process the byte sequences of the same length in each
4863 loop, which is more friendly to branch prediction.
4864 */
4865 pos = src;
4866#if YYJSON_DISABLE_UTF8_VALIDATION
4867 while (true) repeat8({
4868 if (likely((*src & 0xF0) == 0xE0)) src += 3;
4869 else break;
4870 })
4871 if (*src < 0x80) goto skip_ascii;
4872 while (true) repeat8({
4873 if (likely((*src & 0xE0) == 0xC0)) src += 2;
4874 else break;
4875 })
4876 while (true) repeat8({
4877 if (likely((*src & 0xF8) == 0xF0)) src += 4;
4878 else break;
4879 })
4880#else
4881 uni = byte_load_4(src);
4882 while (is_utf8_seq3(uni)) {
4883 src += 3;
4884 uni = byte_load_4(src);
4885 }
4886 if (is_utf8_seq1(uni)) goto skip_ascii;
4887 while (is_utf8_seq2(uni)) {
4888 src += 2;
4889 uni = byte_load_4(src);
4890 }
4891 while (is_utf8_seq4(uni)) {
4892 src += 4;
4893 uni = byte_load_4(src);
4894 }
4895#endif
4896 if (unlikely(pos == src)) {
4897 if (has_allow(INVALID_UNICODE)) ++src;
4898 else return_err(src, "invalid UTF-8 encoding in string");
4899 }
4900 goto skip_ascii;
4901 }
4902
4903 /* The escape character appears, we need to copy it. */
4904 dst = src;
4905copy_escape:
4906 if (likely(*src == '\\')) {
4907 switch (*++src) {
4908 case '"': *dst++ = '"'; src++; break;
4909 case '\\': *dst++ = '\\'; src++; break;
4910 case '/': *dst++ = '/'; src++; break;
4911 case 'b': *dst++ = '\b'; src++; break;
4912 case 'f': *dst++ = '\f'; src++; break;
4913 case 'n': *dst++ = '\n'; src++; break;
4914 case 'r': *dst++ = '\r'; src++; break;
4915 case 't': *dst++ = '\t'; src++; break;
4916 case 'u':
4917 src--;
4918 if (!read_uni_esc(&src, &dst, msg)) return_err(src, *msg);
4919 break;
4920 default: {
4921 if (has_allow(EXT_ESCAPE)) {
4922 /* read extended escape (non-standard) */
4923 switch (*src) {
4924 case '\'': *dst++ = '\''; src++; break;
4925 case 'a': *dst++ = '\a'; src++; break;
4926 case 'v': *dst++ = '\v'; src++; break;
4927 case '?': *dst++ = '\?'; src++; break;
4928 case 'e': *dst++ = 0x1B; src++; break;
4929 case '0':
4930 if (!char_is_digit(src[1])) {
4931 *dst++ = '\0'; src++; break;
4932 }
4933 return_err(src - 1, "octal escape is not allowed");
4934 case '1': case '2': case '3': case '4':
4935 case '5': case '6': case '7': case '8': case '9':
4936 return_err(src - 1, "invalid number escape");
4937 case 'x': {
4938 u8 c;
4939 if (hex_load_2(src + 1, &c)) {
4940 src += 3;
4941 if (c <= 0x7F) { /* 1-byte ASCII */
4942 *dst++ = c;
4943 } else { /* 2-byte UTF-8 */
4944 *dst++ = (u8)(0xC0 | (c >> 6));
4945 *dst++ = (u8)(0x80 | (c & 0x3F));
4946 }
4947 break;
4948 }
4949 return_err(src - 1, "invalid hex escape");
4950 }
4951 case '\n': src++; break;
4952 case '\r': src++; src += (*src == '\n'); break;
4953 case 0xE2: /* Line terminator: U+2028, U+2029 */
4954 if ((src[1] == 0x80 && src[2] == 0xA8) ||
4955 (src[1] == 0x80 && src[2] == 0xA9)) {
4956 src += 3;
4957 }
4958 break;
4959 default:
4960 break; /* skip */
4961 }
4962 } else if (quo == '\'' && *src == '\'') {
4963 *dst++ = '\''; src++; break;
4964 } else {
4965 return_err(src - 1, "invalid escaped sequence in string");
4966 }
4967 }
4968 }
4969 } else if (likely(*src == quo)) {
4970 val->tag = ((u64)(dst - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR;
4971 val->uni.str = (const char *)hdr;
4972 *dst = '\0';
4973 *end = src + 1;
4974 if (con) con[0] = con[1] = NULL;
4975 return true;
4976 } else {
4977 if (!has_allow(INVALID_UNICODE)) {
4978 return_err(src, "unexpected control character in string");
4979 }
4980 if (src >= eof) return_err(src, "unclosed string");
4981 *dst++ = *src++;
4982 }
4983
4984copy_ascii:
4985 /*
4986 Copy continuous ASCII, loop unrolling, same as the following code:
4987
4988 while (true) repeat16({
4989 if (char_is_ascii_skip(*src)) *dst++ = *src++;
4990 else break;
4991 })
4992 */
4993 if (quo == '"') {
4994#define expr_jump(i) \
4995 if (likely((char_is_ascii_skip(src[i])))) {} \
4996 else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; }
4997 repeat16_incr(expr_jump)
4998#undef expr_jump
4999 } else {
5000#define expr_jump(i) \
5001 if (likely((char_is_ascii_skip_sq(src[i])))) {} \
5002 else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; }
5003 repeat16_incr(expr_jump)
5004#undef expr_jump
5005 }
5006
5007 byte_move_16(dst, src);
5008 dst += 16; src += 16;
5009 goto copy_ascii;
5010
5011 /*
5012 The memory is copied forward since `dst < src`.
5013 So it's safe to move one extra byte to reduce instruction count.
5014 */
5015#define expr_jump(i) \
5016 copy_ascii_stop_##i: \
5017 byte_move_forward(dst, src, i); \
5018 dst += i; src += i; \
5019 goto copy_utf8;
5020 repeat16_incr(expr_jump)
5021#undef expr_jump
5022
5023copy_utf8:
5024 if (*src & 0x80) { /* non-ASCII character */
5025 pos = src;
5026 uni = byte_load_4(src);
5027#if YYJSON_DISABLE_UTF8_VALIDATION
5028 while (true) repeat4({
5029 if ((uni & utf8_seq(b3_mask)) == utf8_seq(b3_patt)) {
5030 byte_copy_4(dst, &uni);
5031 dst += 3; src += 3;
5032 uni = byte_load_4(src);
5033 } else break;
5034 })
5035 if ((uni & utf8_seq(b1_mask)) == utf8_seq(b1_patt)) goto copy_ascii;
5036 while (true) repeat4({
5037 if ((uni & utf8_seq(b2_mask)) == utf8_seq(b2_patt)) {
5038 byte_copy_2(dst, &uni);
5039 dst += 2; src += 2;
5040 uni = byte_load_4(src);
5041 } else break;
5042 })
5043 while (true) repeat4({
5044 if ((uni & utf8_seq(b4_mask)) == utf8_seq(b4_patt)) {
5045 byte_copy_4(dst, &uni);
5046 dst += 4; src += 4;
5047 uni = byte_load_4(src);
5048 } else break;
5049 })
5050#else
5051 while (is_utf8_seq3(uni)) {
5052 byte_copy_4(dst, &uni);
5053 dst += 3; src += 3;
5054 uni = byte_load_4(src);
5055 }
5056 if (is_utf8_seq1(uni)) goto copy_ascii;
5057 while (is_utf8_seq2(uni)) {
5058 byte_copy_2(dst, &uni);
5059 dst += 2; src += 2;
5060 uni = byte_load_4(src);
5061 }
5062 while (is_utf8_seq4(uni)) {
5063 byte_copy_4(dst, &uni);
5064 dst += 4; src += 4;
5065 uni = byte_load_4(src);
5066 }
5067#endif
5068 if (unlikely(pos == src)) {
5069 if (!has_allow(INVALID_UNICODE)) {
5070 return_err(src, MSG_ERR_UTF8);
5071 }
5072 goto copy_ascii_stop_1;
5073 }
5074 goto copy_ascii;
5075 }
5076 goto copy_escape;
5077
5078#undef return_err
5079}
5080
5081static_inline bool read_str(u8 **ptr, u8 *eof, yyjson_read_flag flg,
5082 yyjson_val *val, const char **msg) {
5083 return read_str_opt('\"', ptr, eof, flg, val, msg, NULL);
5084}
5085
5086static_inline bool read_str_con(u8 **ptr, u8 *eof, yyjson_read_flag flg,
5087 yyjson_val *val, const char **msg, u8 **con) {
5088 return read_str_opt('\"', ptr, eof, flg, val, msg, con);
5089}
5090
5091static_noinline bool read_str_sq(u8 **ptr, u8 *eof, yyjson_read_flag flg,
5092 yyjson_val *val, const char **msg) {
5093 return read_str_opt('\'', ptr, eof, flg, val, msg, NULL);
5094}
5095
5096/** Read unquoted key (identifier name). */
5097static_noinline bool read_str_id(u8 **ptr, u8 *eof, yyjson_read_flag flg,
5098 u8 **pre, yyjson_val *val, const char **msg) {
5099#define return_err(_end, _msg) do { \
5100 *msg = _msg; \
5101 *end = _end; \
5102 return false; \
5103} while (false)
5104
5105#define return_suc(_str_end, _cur_end) do { \
5106 val->tag = ((u64)(_str_end - hdr) << YYJSON_TAG_BIT) | \
5107 (u64)(YYJSON_TYPE_STR); \
5108 val->uni.str = (const char *)hdr; \
5109 *pre = _str_end; *end = _cur_end; \
5110 return true; \
5111} while (false)
5112
5113 u8 *hdr = *ptr;
5114 u8 **end = ptr;
5115 u8 *src = hdr, *dst = NULL;
5116 u32 uni, tmp;
5117
5118 /* add null-terminator for previous raw string */
5119 **pre = '\0';
5120
5121skip_ascii:
5122#define expr_jump(i) \
5123 if (likely(char_is_id_ascii(src[i]))) {} \
5124 else goto skip_ascii_stop##i;
5125
5126#define expr_stop(i) \
5127 skip_ascii_stop##i: \
5128 src += i; \
5129 goto skip_ascii_end;
5130
5131 repeat16_incr(expr_jump)
5132 src += 16;
5133 goto skip_ascii;
5134 repeat16_incr(expr_stop)
5135
5136#undef expr_jump
5137#undef expr_stop
5138
5139skip_ascii_end:
5140 gcc_store_barrier(*src);
5141 if (likely(!char_is_id_next(*src))) {
5142 return_suc(src, src);
5143 }
5144
5145skip_utf8:
5146 while (*src >= 0x80) {
5147 if (has_allow(EXT_WHITESPACE)) {
5148 if (char_is_space_ext(*src) && ext_space_len(src)) {
5149 return_suc(src, src);
5150 }
5151 }
5152 uni = byte_load_4(src);
5153 if (is_utf8_seq2(uni)) {
5154 src += 2;
5155 } else if (is_utf8_seq3(uni)) {
5156 src += 3;
5157 } else if (is_utf8_seq4(uni)) {
5158 src += 4;
5159 } else {
5160#if !YYJSON_DISABLE_UTF8_VALIDATION
5161 if (!has_allow(INVALID_UNICODE)) return_err(src, MSG_ERR_UTF8);
5162#endif
5163 src += 1;
5164 }
5165 }
5166 if (char_is_id_ascii(*src)) goto skip_ascii;
5167
5168 /* The escape character appears, we need to copy it. */
5169 dst = src;
5170copy_escape:
5171 if (byte_match_2(src, "\\u")) {
5172 if (!read_uni_esc(&src, &dst, msg)) return_err(src, *msg);
5173 } else {
5174 if (!char_is_id_next(*src)) return_suc(dst, src);
5175 return_err(src, "unexpected character in key");
5176 }
5177
5178copy_ascii:
5179 /*
5180 Copy continuous ASCII, loop unrolling, same as the following code:
5181
5182 while (true) repeat16({
5183 if (char_is_ascii_skip(*src)) *dst++ = *src++;
5184 else break;
5185 })
5186 */
5187#define expr_jump(i) \
5188 if (likely((char_is_id_ascii(src[i])))) {} \
5189 else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; }
5190 repeat16_incr(expr_jump)
5191#undef expr_jump
5192
5193 byte_move_16(dst, src);
5194 dst += 16; src += 16;
5195 goto copy_ascii;
5196
5197#define expr_jump(i) \
5198 copy_ascii_stop_##i: \
5199 byte_move_forward(dst, src, i); \
5200 dst += i; src += i; \
5201 goto copy_utf8;
5202 repeat16_incr(expr_jump)
5203#undef expr_jump
5204
5205copy_utf8:
5206 while (*src >= 0x80) { /* non-ASCII character */
5207 if (has_allow(EXT_WHITESPACE)) {
5208 if (char_is_space_ext(*src) && ext_space_len(src)) {
5209 return_suc(dst, src);
5210 }
5211 }
5212 uni = byte_load_4(src);
5213 if (is_utf8_seq2(uni)) {
5214 byte_copy_2(dst, &uni);
5215 dst += 2; src += 2;
5216 } else if (is_utf8_seq3(uni)) {
5217 byte_copy_4(dst, &uni);
5218 dst += 3; src += 3;
5219 } else if (is_utf8_seq4(uni)) {
5220 byte_copy_4(dst, &uni);
5221 dst += 4; src += 4;
5222 } else {
5223#if !YYJSON_DISABLE_UTF8_VALIDATION
5224 if (!has_allow(INVALID_UNICODE)) return_err(src, MSG_ERR_UTF8);
5225#endif
5226 *dst = *src;
5227 dst += 1; src += 1;
5228 }
5229 }
5230 if (char_is_id_ascii(*src)) goto copy_ascii;
5231 goto copy_escape;
5232
5233#undef return_err
5234#undef return_suc
5235}
5236
5237
5238
5239/*==============================================================================
5240 * MARK: - JSON Reader Implementation (Private)
5241 *
5242 * We use goto statements to build the finite state machine (FSM).
5243 * The FSM's state was held by program counter (PC) and the 'goto' make the
5244 * state transitions.
5245 *============================================================================*/
5246
5247/** Read single value JSON document. */
5248static_noinline yyjson_doc *read_root_single(u8 *hdr, u8 *cur, u8 *eof,
5249 yyjson_alc alc,
5250 yyjson_read_flag flg,
5251 yyjson_read_err *err) {
5252#define return_err(_pos, _code, _msg) do { \
5253 if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \
5254 err->pos = (usize)(eof - hdr); \
5255 err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
5256 err->msg = MSG_NOT_END; \
5257 } else { \
5258 err->pos = (usize)(_pos - hdr); \
5259 err->code = YYJSON_READ_ERROR_##_code; \
5260 err->msg = _msg; \
5261 } \
5262 if (val_hdr) alc.free(alc.ctx, val_hdr); \
5263 return NULL; \
5264} while (false)
5265
5266 usize hdr_len; /* value count used by doc */
5267 usize alc_num; /* value count capacity */
5268 yyjson_val *val_hdr; /* the head of allocated values */
5269 yyjson_val *val; /* current value */
5270 yyjson_doc *doc; /* the JSON document, equals to val_hdr */
5271 const char *msg; /* error message */
5272
5273 u8 raw_end[1]; /* raw end for null-terminator */
5274 u8 *raw_ptr = raw_end;
5275 u8 **pre = &raw_ptr; /* previous raw end pointer */
5276
5277 hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
5278 hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
5279 alc_num = hdr_len + 1; /* single value */
5280
5281 val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_num * sizeof(yyjson_val));
5282 if (unlikely(!val_hdr)) goto fail_alloc;
5283 val = val_hdr + hdr_len;
5284
5285 if (char_is_num(*cur)) {
5286 if (likely(read_num(&cur, pre, flg, val, &msg))) goto doc_end;
5287 goto fail_number;
5288 }
5289 if (*cur == '"') {
5290 if (likely(read_str(&cur, eof, flg, val, &msg))) goto doc_end;
5291 goto fail_string;
5292 }
5293 if (*cur == 't') {
5294 if (likely(read_true(&cur, val))) goto doc_end;
5295 goto fail_literal_true;
5296 }
5297 if (*cur == 'f') {
5298 if (likely(read_false(&cur, val))) goto doc_end;
5299 goto fail_literal_false;
5300 }
5301 if (*cur == 'n') {
5302 if (likely(read_null(&cur, val))) goto doc_end;
5303 if (has_allow(INF_AND_NAN)) {
5304 if (read_nan(&cur, pre, flg, val)) goto doc_end;
5305 }
5306 goto fail_literal_null;
5307 }
5308 if (has_allow(INF_AND_NAN)) {
5309 if (read_inf_or_nan(&cur, pre, flg, val)) goto doc_end;
5310 }
5311 if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
5312 if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto doc_end;
5313 goto fail_string;
5314 }
5315 goto fail_character;
5316
5317doc_end:
5318 /* check invalid contents after json document */
5319 if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) {
5320 while (char_is_space(*cur)) cur++;
5321 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5322 if (!skip_trivia(&cur, eof, flg) && cur == eof) {
5323 goto fail_comment;
5324 }
5325 }
5326 if (unlikely(cur < eof)) goto fail_garbage;
5327 }
5328
5329 **pre = '\0';
5330 doc = (yyjson_doc *)val_hdr;
5331 doc->root = val_hdr + hdr_len;
5332 doc->alc = alc;
5333 doc->dat_read = (usize)(cur - hdr);
5334 doc->val_read = 1;
5335 doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
5336 return doc;
5337
5338fail_string: return_err(cur, INVALID_STRING, msg);
5339fail_number: return_err(cur, INVALID_NUMBER, msg);
5340fail_alloc: return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
5341fail_literal_true: return_err(cur, LITERAL, MSG_CHAR_T);
5342fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F);
5343fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N);
5344fail_character: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
5345fail_comment: return_err(cur, INVALID_COMMENT, MSG_COMMENT);
5346fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
5347fail_depth: return_err(cur, DEPTH, MSG_DEPTH);
5348
5349#undef return_err
5350}
5351
5352/** Read JSON document (accept all style, but optimized for minify). */
5353static_inline yyjson_doc *read_root_minify(u8 *hdr, u8 *cur, u8 *eof,
5354 yyjson_alc alc,
5355 yyjson_read_flag flg,
5356 yyjson_read_err *err) {
5357#define return_err(_pos, _code, _msg) do { \
5358 if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \
5359 err->pos = (usize)(eof - hdr); \
5360 err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
5361 err->msg = MSG_NOT_END; \
5362 } else { \
5363 err->pos = (usize)(_pos - hdr); \
5364 err->code = YYJSON_READ_ERROR_##_code; \
5365 err->msg = _msg; \
5366 } \
5367 if (val_hdr) alc.free(alc.ctx, val_hdr); \
5368 return NULL; \
5369} while (false)
5370
5371#define val_incr() do { \
5372 val++; \
5373 if (unlikely(val >= val_end)) { \
5374 usize alc_old = alc_len; \
5375 usize val_ofs = (usize)(val - val_hdr); \
5376 usize ctn_ofs = (usize)(ctn - val_hdr); \
5377 alc_len += alc_len / 2; \
5378 if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \
5379 val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
5380 alc_old * sizeof(yyjson_val), \
5381 alc_len * sizeof(yyjson_val)); \
5382 if ((!val_tmp)) goto fail_alloc; \
5383 val = val_tmp + val_ofs; \
5384 ctn = val_tmp + ctn_ofs; \
5385 val_hdr = val_tmp; \
5386 val_end = val_tmp + (alc_len - 2); \
5387 } \
5388} while (false)
5389
5390 usize dat_len; /* data length in bytes, hint for allocator */
5391 usize hdr_len; /* value count used by yyjson_doc */
5392 usize alc_len; /* value count allocated */
5393 usize alc_max; /* maximum value count for allocator */
5394 usize ctn_len; /* the number of elements in current container */
5395 yyjson_val *val_hdr; /* the head of allocated values */
5396 yyjson_val *val_end; /* the end of allocated values */
5397 yyjson_val *val_tmp; /* temporary pointer for realloc */
5398 yyjson_val *val; /* current JSON value */
5399 yyjson_val *ctn; /* current container */
5400 yyjson_val *ctn_parent; /* parent of current container */
5401 yyjson_doc *doc; /* the JSON document, equals to val_hdr */
5402 const char *msg; /* error message */
5403
5404 u8 raw_end[1]; /* raw end for null-terminator */
5405 u8 *raw_ptr = raw_end;
5406 u8 **pre = &raw_ptr; /* previous raw end pointer */
5407
5408#if YYJSON_READER_DEPTH_LIMIT
5409 usize ctn_depth = 0; /* current array/object depth */
5410#endif
5411
5412 dat_len = has_flg(STOP_WHEN_DONE) ? 256 : (usize)(eof - cur);
5413 hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
5414 hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
5415 alc_max = USIZE_MAX / sizeof(yyjson_val);
5416 alc_len = hdr_len + (dat_len / YYJSON_READER_ESTIMATED_MINIFY_RATIO) + 4;
5417 alc_len = yyjson_min(alc_len, alc_max);
5418
5419 val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_len * sizeof(yyjson_val));
5420 if (unlikely(!val_hdr)) goto fail_alloc;
5421 val_end = val_hdr + (alc_len - 2); /* padding for key-value pair reading */
5422 val = val_hdr + hdr_len;
5423 ctn = val;
5424 ctn_len = 0;
5425
5426 if (*cur++ == '{') {
5427 ctn->tag = YYJSON_TYPE_OBJ;
5428 ctn->uni.ofs = 0;
5429 goto obj_key_begin;
5430 } else {
5431 ctn->tag = YYJSON_TYPE_ARR;
5432 ctn->uni.ofs = 0;
5433 goto arr_val_begin;
5434 }
5435
5436arr_begin:
5437#if YYJSON_READER_DEPTH_LIMIT
5438 ctn_depth++;
5439 if (unlikely(ctn_depth >= (usize)YYJSON_READER_DEPTH_LIMIT)) {
5440 goto fail_depth;
5441 }
5442#endif
5443 /* save current container */
5444 ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
5445 (ctn->tag & YYJSON_TAG_MASK);
5446
5447 /* create a new array value, save parent container offset */
5448 val_incr();
5449 val->tag = YYJSON_TYPE_ARR;
5450 val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
5451
5452 /* push the new array value as current container */
5453 ctn = val;
5454 ctn_len = 0;
5455
5456arr_val_begin:
5457 if (*cur == '{') {
5458 cur++;
5459 goto obj_begin;
5460 }
5461 if (*cur == '[') {
5462 cur++;
5463 goto arr_begin;
5464 }
5465 if (char_is_num(*cur)) {
5466 val_incr();
5467 ctn_len++;
5468 if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_end;
5469 goto fail_number;
5470 }
5471 if (*cur == '"') {
5472 val_incr();
5473 ctn_len++;
5474 if (likely(read_str(&cur, eof, flg, val, &msg))) goto arr_val_end;
5475 goto fail_string;
5476 }
5477 if (*cur == 't') {
5478 val_incr();
5479 ctn_len++;
5480 if (likely(read_true(&cur, val))) goto arr_val_end;
5481 goto fail_literal_true;
5482 }
5483 if (*cur == 'f') {
5484 val_incr();
5485 ctn_len++;
5486 if (likely(read_false(&cur, val))) goto arr_val_end;
5487 goto fail_literal_false;
5488 }
5489 if (*cur == 'n') {
5490 val_incr();
5491 ctn_len++;
5492 if (likely(read_null(&cur, val))) goto arr_val_end;
5493 if (has_allow(INF_AND_NAN)) {
5494 if (read_nan(&cur, pre, flg, val)) goto arr_val_end;
5495 }
5496 goto fail_literal_null;
5497 }
5498 if (*cur == ']') {
5499 cur++;
5500 if (likely(ctn_len == 0)) goto arr_end;
5501 if (has_allow(TRAILING_COMMAS)) goto arr_end;
5502 do { cur--; } while (*cur != ',');
5503 goto fail_trailing_comma;
5504 }
5505 if (char_is_space(*cur)) {
5506 while (char_is_space(*++cur));
5507 goto arr_val_begin;
5508 }
5509 if (has_allow(INF_AND_NAN) &&
5510 (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
5511 val_incr();
5512 ctn_len++;
5513 if (read_inf_or_nan(&cur, pre, flg, val)) goto arr_val_end;
5514 goto fail_character_val;
5515 }
5516 if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
5517 val_incr();
5518 ctn_len++;
5519 if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto arr_val_end;
5520 goto fail_string;
5521 }
5522 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5523 if (skip_trivia(&cur, eof, flg)) goto arr_val_begin;
5524 if (cur == eof) goto fail_comment;
5525 }
5526 goto fail_character_val;
5527
5528arr_val_end:
5529 if (*cur == ',') {
5530 cur++;
5531 goto arr_val_begin;
5532 }
5533 if (*cur == ']') {
5534 cur++;
5535 goto arr_end;
5536 }
5537 if (char_is_space(*cur)) {
5538 while (char_is_space(*++cur));
5539 goto arr_val_end;
5540 }
5541 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5542 if (skip_trivia(&cur, eof, flg)) goto arr_val_end;
5543 if (cur == eof) goto fail_comment;
5544 }
5545 goto fail_character_arr_end;
5546
5547arr_end:
5548#if YYJSON_READER_DEPTH_LIMIT
5549 ctn_depth--;
5550#endif
5551 /* get parent container */
5552 ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
5553
5554 /* save the next sibling value offset */
5555 ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
5556 ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
5557 if (unlikely(ctn == ctn_parent)) goto doc_end;
5558
5559 /* pop parent as current container */
5560 ctn = ctn_parent;
5561 ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
5562 if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
5563 goto obj_val_end;
5564 } else {
5565 goto arr_val_end;
5566 }
5567
5568obj_begin:
5569#if YYJSON_READER_DEPTH_LIMIT
5570 ctn_depth++;
5571 if (unlikely(ctn_depth >= (usize)YYJSON_READER_DEPTH_LIMIT)) {
5572 goto fail_depth;
5573 }
5574#endif
5575 /* push container */
5576 ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
5577 (ctn->tag & YYJSON_TAG_MASK);
5578 val_incr();
5579 val->tag = YYJSON_TYPE_OBJ;
5580 /* offset to the parent */
5581 val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
5582 ctn = val;
5583 ctn_len = 0;
5584
5585obj_key_begin:
5586 if (likely(*cur == '"')) {
5587 val_incr();
5588 ctn_len++;
5589 if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_key_end;
5590 goto fail_string;
5591 }
5592 if (likely(*cur == '}')) {
5593 cur++;
5594 if (likely(ctn_len == 0)) goto obj_end;
5595 if (has_allow(TRAILING_COMMAS)) goto obj_end;
5596 do { cur--; } while (*cur != ',');
5597 goto fail_trailing_comma;
5598 }
5599 if (char_is_space(*cur)) {
5600 while (char_is_space(*++cur));
5601 goto obj_key_begin;
5602 }
5603 if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
5604 val_incr();
5605 ctn_len++;
5606 if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_key_end;
5607 goto fail_string;
5608 }
5609 if (has_allow(UNQUOTED_KEY) && char_is_id_start(*cur)) {
5610 val_incr();
5611 ctn_len++;
5612 if (read_str_id(&cur, eof, flg, pre, val, &msg)) goto obj_key_end;
5613 goto fail_string;
5614 }
5615 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5616 if (skip_trivia(&cur, eof, flg)) goto obj_key_begin;
5617 if (cur == eof) goto fail_comment;
5618 }
5619 goto fail_character_obj_key;
5620
5621obj_key_end:
5622 if (*cur == ':') {
5623 cur++;
5624 goto obj_val_begin;
5625 }
5626 if (char_is_space(*cur)) {
5627 while (char_is_space(*++cur));
5628 goto obj_key_end;
5629 }
5630 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5631 if (skip_trivia(&cur, eof, flg)) goto obj_key_end;
5632 if (cur == eof) goto fail_comment;
5633 }
5634 goto fail_character_obj_sep;
5635
5636obj_val_begin:
5637 if (*cur == '"') {
5638 val++;
5639 ctn_len++;
5640 if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_val_end;
5641 goto fail_string;
5642 }
5643 if (char_is_num(*cur)) {
5644 val++;
5645 ctn_len++;
5646 if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_end;
5647 goto fail_number;
5648 }
5649 if (*cur == '{') {
5650 cur++;
5651 goto obj_begin;
5652 }
5653 if (*cur == '[') {
5654 cur++;
5655 goto arr_begin;
5656 }
5657 if (*cur == 't') {
5658 val++;
5659 ctn_len++;
5660 if (likely(read_true(&cur, val))) goto obj_val_end;
5661 goto fail_literal_true;
5662 }
5663 if (*cur == 'f') {
5664 val++;
5665 ctn_len++;
5666 if (likely(read_false(&cur, val))) goto obj_val_end;
5667 goto fail_literal_false;
5668 }
5669 if (*cur == 'n') {
5670 val++;
5671 ctn_len++;
5672 if (likely(read_null(&cur, val))) goto obj_val_end;
5673 if (has_allow(INF_AND_NAN)) {
5674 if (read_nan(&cur, pre, flg, val)) goto obj_val_end;
5675 }
5676 goto fail_literal_null;
5677 }
5678 if (char_is_space(*cur)) {
5679 while (char_is_space(*++cur));
5680 goto obj_val_begin;
5681 }
5682 if (has_allow(INF_AND_NAN) &&
5683 (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
5684 val++;
5685 ctn_len++;
5686 if (read_inf_or_nan(&cur, pre, flg, val)) goto obj_val_end;
5687 goto fail_character_val;
5688 }
5689 if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
5690 val++;
5691 ctn_len++;
5692 if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_val_end;
5693 goto fail_string;
5694 }
5695 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5696 if (skip_trivia(&cur, eof, flg)) goto obj_val_begin;
5697 if (cur == eof) goto fail_comment;
5698 }
5699 goto fail_character_val;
5700
5701obj_val_end:
5702 if (likely(*cur == ',')) {
5703 cur++;
5704 goto obj_key_begin;
5705 }
5706 if (likely(*cur == '}')) {
5707 cur++;
5708 goto obj_end;
5709 }
5710 if (char_is_space(*cur)) {
5711 while (char_is_space(*++cur));
5712 goto obj_val_end;
5713 }
5714 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5715 if (skip_trivia(&cur, eof, flg)) goto obj_val_end;
5716 if (cur == eof) goto fail_comment;
5717 }
5718 goto fail_character_obj_end;
5719
5720obj_end:
5721#if YYJSON_READER_DEPTH_LIMIT
5722 ctn_depth--;
5723#endif
5724 /* pop container */
5725 ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
5726 /* point to the next value */
5727 ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
5728 ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
5729 if (unlikely(ctn == ctn_parent)) goto doc_end;
5730 ctn = ctn_parent;
5731 ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
5732 if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
5733 goto obj_val_end;
5734 } else {
5735 goto arr_val_end;
5736 }
5737
5738doc_end:
5739 /* check invalid contents after json document */
5740 if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) {
5741 while (char_is_space(*cur)) cur++;
5742 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5743 if (!skip_trivia(&cur, eof, flg) && cur == eof) {
5744 goto fail_comment;
5745 }
5746 }
5747 if (unlikely(cur < eof)) goto fail_garbage;
5748 }
5749
5750 **pre = '\0';
5751 doc = (yyjson_doc *)val_hdr;
5752 doc->root = val_hdr + hdr_len;
5753 doc->alc = alc;
5754 doc->dat_read = (usize)(cur - hdr);
5755 doc->val_read = (usize)((val - doc->root) + 1);
5756 doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
5757 return doc;
5758
5759fail_string: return_err(cur, INVALID_STRING, msg);
5760fail_number: return_err(cur, INVALID_NUMBER, msg);
5761fail_alloc: return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
5762fail_trailing_comma: return_err(cur, JSON_STRUCTURE, MSG_COMMA);
5763fail_literal_true: return_err(cur, LITERAL, MSG_CHAR_T);
5764fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F);
5765fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N);
5766fail_character_val: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
5767fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END);
5768fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY);
5769fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
5770fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
5771fail_comment: return_err(cur, INVALID_COMMENT, MSG_COMMENT);
5772fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
5773fail_depth: return_err(cur, DEPTH, MSG_DEPTH);
5774
5775#undef val_incr
5776#undef return_err
5777}
5778
5779/** Read JSON document (accept all style, but optimized for pretty). */
5780static_inline yyjson_doc *read_root_pretty(u8 *hdr, u8 *cur, u8 *eof,
5781 yyjson_alc alc,
5782 yyjson_read_flag flg,
5783 yyjson_read_err *err) {
5784#define return_err(_pos, _code, _msg) do { \
5785 if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \
5786 err->pos = (usize)(eof - hdr); \
5787 err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
5788 err->msg = MSG_NOT_END; \
5789 } else { \
5790 err->pos = (usize)(_pos - hdr); \
5791 err->code = YYJSON_READ_ERROR_##_code; \
5792 err->msg = _msg; \
5793 } \
5794 if (val_hdr) alc.free(alc.ctx, val_hdr); \
5795 return NULL; \
5796} while (false)
5797
5798#define val_incr() do { \
5799 val++; \
5800 if (unlikely(val >= val_end)) { \
5801 usize alc_old = alc_len; \
5802 usize val_ofs = (usize)(val - val_hdr); \
5803 usize ctn_ofs = (usize)(ctn - val_hdr); \
5804 alc_len += alc_len / 2; \
5805 if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \
5806 val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
5807 alc_old * sizeof(yyjson_val), \
5808 alc_len * sizeof(yyjson_val)); \
5809 if ((!val_tmp)) goto fail_alloc; \
5810 val = val_tmp + val_ofs; \
5811 ctn = val_tmp + ctn_ofs; \
5812 val_hdr = val_tmp; \
5813 val_end = val_tmp + (alc_len - 2); \
5814 } \
5815} while (false)
5816
5817 usize dat_len; /* data length in bytes, hint for allocator */
5818 usize hdr_len; /* value count used by yyjson_doc */
5819 usize alc_len; /* value count allocated */
5820 usize alc_max; /* maximum value count for allocator */
5821 usize ctn_len; /* the number of elements in current container */
5822 yyjson_val *val_hdr; /* the head of allocated values */
5823 yyjson_val *val_end; /* the end of allocated values */
5824 yyjson_val *val_tmp; /* temporary pointer for realloc */
5825 yyjson_val *val; /* current JSON value */
5826 yyjson_val *ctn; /* current container */
5827 yyjson_val *ctn_parent; /* parent of current container */
5828 yyjson_doc *doc; /* the JSON document, equals to val_hdr */
5829 const char *msg; /* error message */
5830
5831 u8 raw_end[1]; /* raw end for null-terminator */
5832 u8 *raw_ptr = raw_end;
5833 u8 **pre = &raw_ptr; /* previous raw end pointer */
5834#if YYJSON_READER_DEPTH_LIMIT
5835 usize ctn_depth = 0; /* current array/object depth */
5836#endif
5837
5838 dat_len = has_flg(STOP_WHEN_DONE) ? 256 : (usize)(eof - cur);
5839 hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
5840 hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
5841 alc_max = USIZE_MAX / sizeof(yyjson_val);
5842 alc_len = hdr_len + (dat_len / YYJSON_READER_ESTIMATED_PRETTY_RATIO) + 4;
5843 alc_len = yyjson_min(alc_len, alc_max);
5844
5845 val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_len * sizeof(yyjson_val));
5846 if (unlikely(!val_hdr)) goto fail_alloc;
5847 val_end = val_hdr + (alc_len - 2); /* padding for key-value pair reading */
5848 val = val_hdr + hdr_len;
5849 ctn = val;
5850 ctn_len = 0;
5851
5852 if (*cur++ == '{') {
5853 ctn->tag = YYJSON_TYPE_OBJ;
5854 ctn->uni.ofs = 0;
5855 if (*cur == '\n') cur++;
5856 goto obj_key_begin;
5857 } else {
5858 ctn->tag = YYJSON_TYPE_ARR;
5859 ctn->uni.ofs = 0;
5860 if (*cur == '\n') cur++;
5861 goto arr_val_begin;
5862 }
5863
5864arr_begin:
5865#if YYJSON_READER_DEPTH_LIMIT
5866 ctn_depth++;
5867 if (unlikely(ctn_depth >= (usize)YYJSON_READER_DEPTH_LIMIT)) {
5868 goto fail_depth;
5869 }
5870#endif
5871
5872 /* save current container */
5873 ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
5874 (ctn->tag & YYJSON_TAG_MASK);
5875
5876 /* create a new array value, save parent container offset */
5877 val_incr();
5878 val->tag = YYJSON_TYPE_ARR;
5879 val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
5880
5881 /* push the new array value as current container */
5882 ctn = val;
5883 ctn_len = 0;
5884 if (*cur == '\n') cur++;
5885
5886arr_val_begin:
5887#if YYJSON_IS_REAL_GCC
5888 while (true) repeat16({
5889 if (byte_match_2(cur, " ")) cur += 2;
5890 else break;
5891 })
5892#else
5893 while (true) repeat16({
5894 if (likely(byte_match_2(cur, " "))) cur += 2;
5895 else break;
5896 })
5897#endif
5898
5899 if (*cur == '{') {
5900 cur++;
5901 goto obj_begin;
5902 }
5903 if (*cur == '[') {
5904 cur++;
5905 goto arr_begin;
5906 }
5907 if (char_is_num(*cur)) {
5908 val_incr();
5909 ctn_len++;
5910 if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_end;
5911 goto fail_number;
5912 }
5913 if (*cur == '"') {
5914 val_incr();
5915 ctn_len++;
5916 if (likely(read_str(&cur, eof, flg, val, &msg))) goto arr_val_end;
5917 goto fail_string;
5918 }
5919 if (*cur == 't') {
5920 val_incr();
5921 ctn_len++;
5922 if (likely(read_true(&cur, val))) goto arr_val_end;
5923 goto fail_literal_true;
5924 }
5925 if (*cur == 'f') {
5926 val_incr();
5927 ctn_len++;
5928 if (likely(read_false(&cur, val))) goto arr_val_end;
5929 goto fail_literal_false;
5930 }
5931 if (*cur == 'n') {
5932 val_incr();
5933 ctn_len++;
5934 if (likely(read_null(&cur, val))) goto arr_val_end;
5935 if (has_allow(INF_AND_NAN)) {
5936 if (read_nan(&cur, pre, flg, val)) goto arr_val_end;
5937 }
5938 goto fail_literal_null;
5939 }
5940 if (*cur == ']') {
5941 cur++;
5942 if (likely(ctn_len == 0)) goto arr_end;
5943 if (has_allow(TRAILING_COMMAS)) goto arr_end;
5944 do { cur--; } while (*cur != ',');
5945 goto fail_trailing_comma;
5946 }
5947 if (char_is_space(*cur)) {
5948 while (char_is_space(*++cur));
5949 goto arr_val_begin;
5950 }
5951 if (has_allow(INF_AND_NAN) &&
5952 (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
5953 val_incr();
5954 ctn_len++;
5955 if (read_inf_or_nan(&cur, pre, flg, val)) goto arr_val_end;
5956 goto fail_character_val;
5957 }
5958 if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
5959 val_incr();
5960 ctn_len++;
5961 if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto arr_val_end;
5962 goto fail_string;
5963 }
5964 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5965 if (skip_trivia(&cur, eof, flg)) goto arr_val_begin;
5966 if (cur == eof) goto fail_comment;
5967 }
5968 goto fail_character_val;
5969
5970arr_val_end:
5971 if (byte_match_2(cur, ",\n")) {
5972 cur += 2;
5973 goto arr_val_begin;
5974 }
5975 if (*cur == ',') {
5976 cur++;
5977 goto arr_val_begin;
5978 }
5979 if (*cur == ']') {
5980 cur++;
5981 goto arr_end;
5982 }
5983 if (char_is_space(*cur)) {
5984 while (char_is_space(*++cur));
5985 goto arr_val_end;
5986 }
5987 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5988 if (skip_trivia(&cur, eof, flg)) goto arr_val_end;
5989 if (cur == eof) goto fail_comment;
5990 }
5991 goto fail_character_arr_end;
5992
5993arr_end:
5994#if YYJSON_READER_DEPTH_LIMIT
5995 ctn_depth--;
5996#endif
5997 /* get parent container */
5998 ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
5999
6000 /* save the next sibling value offset */
6001 ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
6002 ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
6003 if (unlikely(ctn == ctn_parent)) goto doc_end;
6004
6005 /* pop parent as current container */
6006 ctn = ctn_parent;
6007 ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
6008 if (*cur == '\n') cur++;
6009 if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
6010 goto obj_val_end;
6011 } else {
6012 goto arr_val_end;
6013 }
6014
6015obj_begin:
6016#if YYJSON_READER_DEPTH_LIMIT
6017 ctn_depth++;
6018 if (unlikely(ctn_depth >= (usize)YYJSON_READER_DEPTH_LIMIT)) {
6019 goto fail_depth;
6020 }
6021#endif
6022
6023 /* push container */
6024 ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
6025 (ctn->tag & YYJSON_TAG_MASK);
6026 val_incr();
6027 val->tag = YYJSON_TYPE_OBJ;
6028 /* offset to the parent */
6029 val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
6030 ctn = val;
6031 ctn_len = 0;
6032 if (*cur == '\n') cur++;
6033
6034obj_key_begin:
6035#if YYJSON_IS_REAL_GCC
6036 while (true) repeat16({
6037 if (byte_match_2(cur, " ")) cur += 2;
6038 else break;
6039 })
6040#else
6041 while (true) repeat16({
6042 if (likely(byte_match_2(cur, " "))) cur += 2;
6043 else break;
6044 })
6045#endif
6046 if (likely(*cur == '"')) {
6047 val_incr();
6048 ctn_len++;
6049 if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_key_end;
6050 goto fail_string;
6051 }
6052 if (likely(*cur == '}')) {
6053 cur++;
6054 if (likely(ctn_len == 0)) goto obj_end;
6055 if (has_allow(TRAILING_COMMAS)) goto obj_end;
6056 do { cur--; } while (*cur != ',');
6057 goto fail_trailing_comma;
6058 }
6059 if (char_is_space(*cur)) {
6060 while (char_is_space(*++cur));
6061 goto obj_key_begin;
6062 }
6063 if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
6064 val_incr();
6065 ctn_len++;
6066 if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_key_end;
6067 goto fail_string;
6068 }
6069 if (has_allow(UNQUOTED_KEY) && char_is_id_start(*cur)) {
6070 val_incr();
6071 ctn_len++;
6072 if (read_str_id(&cur, eof, flg, pre, val, &msg)) goto obj_key_end;
6073 goto fail_string;
6074 }
6075 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
6076 if (skip_trivia(&cur, eof, flg)) goto obj_key_begin;
6077 if (cur == eof) goto fail_comment;
6078 }
6079 goto fail_character_obj_key;
6080
6081obj_key_end:
6082 if (byte_match_2(cur, ": ")) {
6083 cur += 2;
6084 goto obj_val_begin;
6085 }
6086 if (*cur == ':') {
6087 cur++;
6088 goto obj_val_begin;
6089 }
6090 if (char_is_space(*cur)) {
6091 while (char_is_space(*++cur));
6092 goto obj_key_end;
6093 }
6094 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
6095 if (skip_trivia(&cur, eof, flg)) goto obj_key_end;
6096 if (cur == eof) goto fail_comment;
6097 }
6098 goto fail_character_obj_sep;
6099
6100obj_val_begin:
6101 if (*cur == '"') {
6102 val++;
6103 ctn_len++;
6104 if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_val_end;
6105 goto fail_string;
6106 }
6107 if (char_is_num(*cur)) {
6108 val++;
6109 ctn_len++;
6110 if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_end;
6111 goto fail_number;
6112 }
6113 if (*cur == '{') {
6114 cur++;
6115 goto obj_begin;
6116 }
6117 if (*cur == '[') {
6118 cur++;
6119 goto arr_begin;
6120 }
6121 if (*cur == 't') {
6122 val++;
6123 ctn_len++;
6124 if (likely(read_true(&cur, val))) goto obj_val_end;
6125 goto fail_literal_true;
6126 }
6127 if (*cur == 'f') {
6128 val++;
6129 ctn_len++;
6130 if (likely(read_false(&cur, val))) goto obj_val_end;
6131 goto fail_literal_false;
6132 }
6133 if (*cur == 'n') {
6134 val++;
6135 ctn_len++;
6136 if (likely(read_null(&cur, val))) goto obj_val_end;
6137 if (has_allow(INF_AND_NAN)) {
6138 if (read_nan(&cur, pre, flg, val)) goto obj_val_end;
6139 }
6140 goto fail_literal_null;
6141 }
6142 if (char_is_space(*cur)) {
6143 while (char_is_space(*++cur));
6144 goto obj_val_begin;
6145 }
6146 if (has_allow(INF_AND_NAN) &&
6147 (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
6148 val++;
6149 ctn_len++;
6150 if (read_inf_or_nan(&cur, pre, flg, val)) goto obj_val_end;
6151 goto fail_character_val;
6152 }
6153 if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
6154 val++;
6155 ctn_len++;
6156 if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_val_end;
6157 goto fail_string;
6158 }
6159 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
6160 if (skip_trivia(&cur, eof, flg)) goto obj_val_begin;
6161 if (cur == eof) goto fail_comment;
6162 }
6163 goto fail_character_val;
6164
6165obj_val_end:
6166 if (byte_match_2(cur, ",\n")) {
6167 cur += 2;
6168 goto obj_key_begin;
6169 }
6170 if (likely(*cur == ',')) {
6171 cur++;
6172 goto obj_key_begin;
6173 }
6174 if (likely(*cur == '}')) {
6175 cur++;
6176 goto obj_end;
6177 }
6178 if (char_is_space(*cur)) {
6179 while (char_is_space(*++cur));
6180 goto obj_val_end;
6181 }
6182 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
6183 if (skip_trivia(&cur, eof, flg)) goto obj_val_end;
6184 if (cur == eof) goto fail_comment;
6185 }
6186 goto fail_character_obj_end;
6187
6188obj_end:
6189#if YYJSON_READER_DEPTH_LIMIT
6190 ctn_depth--;
6191#endif
6192
6193 /* pop container */
6194 ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
6195 /* point to the next value */
6196 ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
6197 ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
6198 if (unlikely(ctn == ctn_parent)) goto doc_end;
6199 ctn = ctn_parent;
6200 ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
6201 if (*cur == '\n') cur++;
6202 if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
6203 goto obj_val_end;
6204 } else {
6205 goto arr_val_end;
6206 }
6207
6208doc_end:
6209 /* check invalid contents after json document */
6210 if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) {
6211 while (char_is_space(*cur)) cur++;
6212 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
6213 if (!skip_trivia(&cur, eof, flg) && cur == eof) {
6214 goto fail_comment;
6215 }
6216 }
6217 if (unlikely(cur < eof)) goto fail_garbage;
6218 }
6219
6220 **pre = '\0';
6221 doc = (yyjson_doc *)val_hdr;
6222 doc->root = val_hdr + hdr_len;
6223 doc->alc = alc;
6224 doc->dat_read = (usize)(cur - hdr);
6225 doc->val_read = (usize)((val - doc->root) + 1);
6226 doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
6227 return doc;
6228
6229fail_string: return_err(cur, INVALID_STRING, msg);
6230fail_number: return_err(cur, INVALID_NUMBER, msg);
6231fail_alloc: return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
6232fail_trailing_comma: return_err(cur, JSON_STRUCTURE, MSG_COMMA);
6233fail_literal_true: return_err(cur, LITERAL, MSG_CHAR_T);
6234fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F);
6235fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N);
6236fail_character_val: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
6237fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END);
6238fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY);
6239fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
6240fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
6241fail_comment: return_err(cur, INVALID_COMMENT, MSG_COMMENT);
6242fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
6243fail_depth: return_err(cur, DEPTH, MSG_DEPTH);
6244
6245#undef val_incr
6246#undef return_err
6247}
6248
6249
6250
6251/*==============================================================================
6252 * MARK: - JSON Reader (Public)
6253 *============================================================================*/
6254
6255yyjson_doc *yyjson_read_opts(char *dat, usize len,
6256 yyjson_read_flag flg,
6257 const yyjson_alc *alc_ptr,
6258 yyjson_read_err *err) {
6259#define return_err(_pos, _code, _msg) do { \
6260 err->pos = (usize)(_pos); \
6261 err->msg = _msg; \
6262 err->code = YYJSON_READ_ERROR_##_code; \
6263 if (!has_flg(INSITU) && hdr) alc.free(alc.ctx, (void *)hdr); \
6264 return NULL; \
6265} while (false)
6266
6267 yyjson_read_err tmp_err;
6268 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
6269 yyjson_doc *doc;
6270 u8 *hdr = NULL, *eof, *cur;
6271
6272 /* validate input parameters */
6273 if (!err) err = &tmp_err;
6274 if (unlikely(!dat)) return_err(0, INVALID_PARAMETER, "input data is NULL");
6275 if (unlikely(!len)) return_err(0, INVALID_PARAMETER, "input length is 0");
6276
6277 /* add 4-byte zero padding for input data if necessary */
6278 if (has_flg(INSITU)) {
6279 hdr = (u8 *)dat;
6280 eof = (u8 *)dat + len;
6281 cur = (u8 *)dat;
6282 } else {
6283 if (unlikely(len >= USIZE_MAX - YYJSON_PADDING_SIZE)) {
6284 return_err(0, MEMORY_ALLOCATION, MSG_MALLOC);
6285 }
6286 hdr = (u8 *)alc.malloc(alc.ctx, len + YYJSON_PADDING_SIZE);
6287 if (unlikely(!hdr)) {
6288 return_err(0, MEMORY_ALLOCATION, MSG_MALLOC);
6289 }
6290 eof = hdr + len;
6291 cur = hdr;
6292 memcpy(hdr, dat, len);
6293 }
6294 memset(eof, 0, YYJSON_PADDING_SIZE);
6295
6296 if (has_allow(BOM)) {
6297 if (len >= 3 && is_utf8_bom(cur)) cur += 3;
6298 }
6299
6300 /* skip empty contents before json document */
6301 if (unlikely(!char_is_ctn(*cur))) {
6302 while (char_is_space(*cur)) cur++;
6303 if (unlikely(!char_is_ctn(*cur))) {
6304 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
6305 if (!skip_trivia(&cur, eof, flg) && cur == eof) {
6306 return_err(cur - hdr, INVALID_COMMENT, MSG_COMMENT);
6307 }
6308 }
6309 }
6310 if (unlikely(cur >= eof)) {
6311 return_err(0, EMPTY_CONTENT, "input data is empty");
6312 }
6313 }
6314
6315 /* read json document */
6316 if (likely(char_is_ctn(*cur))) {
6317 if (char_is_space(cur[1]) && char_is_space(cur[2])) {
6318 doc = read_root_pretty(hdr, cur, eof, alc, flg, err);
6319 } else {
6320 doc = read_root_minify(hdr, cur, eof, alc, flg, err);
6321 }
6322 } else {
6323 doc = read_root_single(hdr, cur, eof, alc, flg, err);
6324 }
6325
6326 /* check result */
6327 if (likely(doc)) {
6328 memset(err, 0, sizeof(yyjson_read_err));
6329 } else {
6330 /* RFC 8259: JSON text MUST be encoded using UTF-8 */
6331 if (err->pos == 0 && err->code != YYJSON_READ_ERROR_MEMORY_ALLOCATION) {
6332 if (is_utf8_bom(hdr)) err->msg = MSG_ERR_BOM;
6333 else if (len >= 4 && is_utf32_bom(hdr)) err->msg = MSG_ERR_UTF32;
6334 else if (len >= 2 && is_utf16_bom(hdr)) err->msg = MSG_ERR_UTF16;
6335 }
6336 if (!has_flg(INSITU)) alc.free(alc.ctx, hdr);
6337 }
6338 return doc;
6339
6340#undef return_err
6341}
6342
6343#if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE
6344
6345yyjson_doc *yyjson_read_file(const char *path,
6346 yyjson_read_flag flg,
6347 const yyjson_alc *alc_ptr,
6348 yyjson_read_err *err) {
6349#define return_err(_code, _msg) do { \
6350 err->pos = 0; \
6351 err->msg = _msg; \
6352 err->code = YYJSON_READ_ERROR_##_code; \
6353 return NULL; \
6354} while (false)
6355
6356 yyjson_read_err tmp_err;
6357 yyjson_doc *doc;
6358 FILE *file;
6359
6360 if (!err) err = &tmp_err;
6361 if (unlikely(!path)) return_err(INVALID_PARAMETER, "input path is NULL");
6362
6363 file = fopen_readonly(path);
6364 if (unlikely(!file)) return_err(FILE_OPEN, MSG_FREAD);
6365
6366 doc = yyjson_read_fp(file, flg, alc_ptr, err);
6367 fclose(file);
6368 return doc;
6369
6370#undef return_err
6371}
6372
6373yyjson_doc *yyjson_read_fp(FILE *file,
6374 yyjson_read_flag flg,
6375 const yyjson_alc *alc_ptr,
6376 yyjson_read_err *err) {
6377#define return_err(_code, _msg) do { \
6378 err->pos = 0; \
6379 err->msg = _msg; \
6380 err->code = YYJSON_READ_ERROR_##_code; \
6381 if (buf) alc.free(alc.ctx, buf); \
6382 return NULL; \
6383} while (false)
6384
6385 yyjson_read_err tmp_err;
6386 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
6387 yyjson_doc *doc;
6388
6389 long file_size = 0, file_pos;
6390 void *buf = NULL;
6391 usize buf_size = 0;
6392 usize dat_size = 0;
6393
6394 /* validate input parameters */
6395 if (!err) err = &tmp_err;
6396 if (unlikely(!file)) return_err(INVALID_PARAMETER, "input file is NULL");
6397
6398 /* get current position */
6399 file_pos = ftell(file);
6400 if (file_pos != -1) {
6401 /* get total file size, may fail */
6402 if (fseek(file, 0, SEEK_END) == 0) {
6403 file_size = ftell(file);
6404 if (file_size == -1) file_size = 0;
6405 }
6406 /* reset to original position, may fail */
6407 if (fseek(file, file_pos, SEEK_SET) != 0) file_size = 0;
6408 /* get file size from current position to end */
6409 if (file_size > 0) file_size -= file_pos;
6410 }
6411
6412 /* read file */
6413 if (file_size > 0) {
6414 /* read the entire file in one call */
6415 dat_size = (usize)file_size;
6416 buf_size = dat_size + YYJSON_PADDING_SIZE;
6417 buf = alc.malloc(alc.ctx, buf_size);
6418 if (buf == NULL) {
6419 return_err(MEMORY_ALLOCATION, MSG_MALLOC);
6420 }
6421 if (fread_safe(buf, dat_size, file) != dat_size) {
6422 return_err(FILE_READ, MSG_FREAD);
6423 }
6424 } else {
6425 /* failed to get file size, read it as a stream */
6426 usize chunk_min = (usize)64;
6427 usize chunk_max = (usize)512 * 1024 * 1024;
6428 usize chunk_now = chunk_min;
6429 usize read_size;
6430 void *tmp;
6431
6432 buf_size = YYJSON_PADDING_SIZE;
6433 while (true) {
6434 if (buf_size + chunk_now < buf_size) { /* overflow */
6435 return_err(MEMORY_ALLOCATION, MSG_MALLOC);
6436 }
6437 buf_size += chunk_now;
6438 if (!buf) {
6439 buf = alc.malloc(alc.ctx, buf_size);
6440 if (!buf) return_err(MEMORY_ALLOCATION, MSG_MALLOC);
6441 } else {
6442 tmp = alc.realloc(alc.ctx, buf, buf_size - chunk_now, buf_size);
6443 if (!tmp) return_err(MEMORY_ALLOCATION, MSG_MALLOC);
6444 buf = tmp;
6445 }
6446 tmp = ((u8 *)buf) + buf_size - YYJSON_PADDING_SIZE - chunk_now;
6447 read_size = fread_safe(tmp, chunk_now, file);
6448 dat_size += read_size;
6449 if (read_size != chunk_now) {
6450 if (ferror(file)) return_err(FILE_READ, MSG_FREAD);
6451 break;
6452 }
6453
6454 chunk_now *= 2;
6455 if (chunk_now > chunk_max) chunk_now = chunk_max;
6456 }
6457 }
6458
6459 /* read JSON */
6460 memset((u8 *)buf + dat_size, 0, YYJSON_PADDING_SIZE);
6461 flg |= YYJSON_READ_INSITU;
6462 doc = yyjson_read_opts((char *)buf, dat_size, flg, &alc, err);
6463 if (doc) {
6464 doc->str_pool = (char *)buf;
6465 return doc;
6466 } else {
6467 alc.free(alc.ctx, buf);
6468 return NULL;
6469 }
6470
6471#undef return_err
6472}
6473
6474#endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */
6475
6476const char *yyjson_read_number(const char *dat,
6477 yyjson_val *val,
6478 yyjson_read_flag flg,
6479 const yyjson_alc *alc,
6480 yyjson_read_err *err) {
6481#define return_err(_pos, _code, _msg) do { \
6482 err->pos = _pos > hdr ? (usize)(_pos - hdr) : 0; \
6483 err->msg = _msg; \
6484 err->code = YYJSON_READ_ERROR_##_code; \
6485 return NULL; \
6486} while (false)
6487
6488 u8 *hdr = constcast(u8 *)dat, *cur = hdr;
6489 u8 raw_end[1]; /* raw end for null-terminator */
6490 u8 *raw_ptr = raw_end;
6491 u8 **pre = &raw_ptr; /* previous raw end pointer */
6492 const char *msg;
6493 yyjson_read_err tmp_err;
6494
6495#if YYJSON_DISABLE_FAST_FP_CONV
6496 u8 buf[128];
6497 usize dat_len;
6498#endif
6499
6500 if (!err) err = &tmp_err;
6501 if (unlikely(!dat)) {
6502 return_err(cur, INVALID_PARAMETER, "input data is NULL");
6503 }
6504 if (unlikely(!val)) {
6505 return_err(cur, INVALID_PARAMETER, "output value is NULL");
6506 }
6507
6508#if YYJSON_DISABLE_FAST_FP_CONV
6509 if (!alc) alc = &YYJSON_DEFAULT_ALC;
6510 dat_len = strlen(dat);
6511 if (dat_len < sizeof(buf)) {
6512 memcpy(buf, dat, dat_len + 1);
6513 hdr = buf;
6514 cur = hdr;
6515 } else {
6516 hdr = (u8 *)alc->malloc(alc->ctx, dat_len + 1);
6517 cur = hdr;
6518 if (unlikely(!hdr)) {
6519 return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
6520 }
6521 memcpy(hdr, dat, dat_len + 1);
6522 }
6523 hdr[dat_len] = 0;
6524#endif
6525
6526#if YYJSON_DISABLE_FAST_FP_CONV
6527 if (!read_num(&cur, pre, flg, val, &msg)) {
6528 if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr);
6529 return_err(cur, INVALID_NUMBER, msg);
6530 }
6531 if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr);
6532 if (yyjson_is_raw(val)) val->uni.str = dat;
6533 return dat + (cur - hdr);
6534#else
6535 if (!read_num(&cur, pre, flg, val, &msg)) {
6536 return_err(cur, INVALID_NUMBER, msg);
6537 }
6538 return (const char *)cur;
6539#endif
6540
6541#undef return_err
6542}
6543
6544
6545
6546/*==============================================================================
6547 * MARK: - Incremental JSON Reader (Public)
6548 *============================================================================*/
6549
6550#if !YYJSON_DISABLE_INCR_READER
6551
6552/* labels within yyjson_incr_read() to resume incremental parsing */
6553#define LABEL_doc_begin 0
6554#define LABEL_arr_val_begin 1
6555#define LABEL_arr_val_end 2
6556#define LABEL_obj_key_begin 3
6557#define LABEL_obj_key_end 4
6558#define LABEL_obj_val_begin 5
6559#define LABEL_obj_val_end 6
6560#define LABEL_doc_end 7
6561
6562/** State for incremental JSON reader, opaque in the API. */
6563struct yyjson_incr_state {
6564 u32 label; /* current parser goto label */
6565 yyjson_alc alc; /* allocator */
6566 yyjson_read_flag flg; /* read flags */
6567 u8 *hdr; /* JSON data header */
6568 u8 *cur; /* current position in JSON data */
6569 usize buf_len; /* total buffer length (without padding) */
6570 usize hdr_len; /* value count used by yyjson_doc */
6571 usize alc_len; /* value count allocated */
6572 usize ctn_len; /* the number of elements in current container */
6573#if YYJSON_READER_DEPTH_LIMIT
6574 usize ctn_depth; /* current array/object depth */
6575#endif
6576 yyjson_val *val_hdr; /* the head of allocated values */
6577 yyjson_val *val_end; /* the end of allocated values */
6578 yyjson_val *val; /* current JSON value */
6579 yyjson_val *ctn; /* current container */
6580 u8 *str_con[2]; /* string parser incremental state */
6581 u8 *raw_ptr; /* pending position for a deferred raw null-terminator */
6582 u8 raw_end[1]; /* dummy target for the first deferred null-terminator */
6583};
6584
6585yyjson_incr_state *yyjson_incr_new(char *buf, size_t buf_len,
6586 yyjson_read_flag flg,
6587 const yyjson_alc *alc_ptr) {
6588 yyjson_incr_state *state = NULL;
6589 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
6590
6591 /* remove non-standard flags */
6592 flg &= ~YYJSON_READ_JSON5;
6593 flg &= ~YYJSON_READ_ALLOW_BOM;
6594 flg &= ~YYJSON_READ_ALLOW_INVALID_UNICODE;
6595
6596 if (unlikely(!buf)) return NULL;
6597 if (unlikely(buf_len >= USIZE_MAX - YYJSON_PADDING_SIZE)) return NULL;
6598 state = (yyjson_incr_state *)alc.malloc(alc.ctx, sizeof(*state));
6599 if (!state) return NULL;
6600 memset(state, 0, sizeof(yyjson_incr_state));
6601 state->alc = alc;
6602 state->flg = flg;
6603 state->buf_len = buf_len;
6604
6605 /* add 4-byte zero padding for input data if necessary */
6606 if (has_flg(INSITU)) {
6607 state->hdr = (u8 *)buf;
6608 } else {
6609 state->hdr = (u8 *)alc.malloc(alc.ctx, buf_len + YYJSON_PADDING_SIZE);
6610 if (unlikely(!state->hdr)) {
6611 alc.free(alc.ctx, state);
6612 return NULL;
6613 }
6614 memcpy(state->hdr, buf, buf_len);
6615 }
6616 memset(state->hdr + buf_len, 0, YYJSON_PADDING_SIZE);
6617 state->cur = state->hdr;
6618 state->raw_ptr = state->raw_end;
6619 state->label = LABEL_doc_begin;
6620 return state;
6621}
6622
6623void yyjson_incr_free(yyjson_incr_state *state) {
6624 if (state) {
6625 yyjson_alc alc = state->alc;
6626 memset(&state->alc, 0, sizeof(alc));
6627 if (state->val_hdr) {
6628 alc.free(alc.ctx, (void *)state->val_hdr);
6629 }
6630 if (state->hdr && !(state->flg & YYJSON_READ_INSITU)) {
6631 alc.free(alc.ctx, state->hdr);
6632 }
6633 alc.free(alc.ctx, state);
6634 }
6635}
6636
6637yyjson_doc *yyjson_incr_read(yyjson_incr_state *state, size_t len,
6638 yyjson_read_err *err) {
6639#define return_err_inv_param(_msg) do { \
6640 err->pos = 0; \
6641 err->msg = _msg; \
6642 err->code = YYJSON_READ_ERROR_INVALID_PARAMETER; \
6643 return NULL; \
6644} while (false)
6645
6646#define return_err(_pos, _code, _msg) do { \
6647 if (is_truncated_end(hdr, _pos, end, YYJSON_READ_ERROR_##_code, flg)) { \
6648 goto unexpected_end; \
6649 } else { \
6650 err->pos = (usize)(_pos - hdr); \
6651 err->code = YYJSON_READ_ERROR_##_code; \
6652 err->msg = _msg; \
6653 } \
6654 return NULL; \
6655} while (false)
6656
6657#define val_incr() do { \
6658 val++; \
6659 if (unlikely(val >= val_end)) { \
6660 usize alc_old = alc_len; \
6661 alc_len += alc_len / 2; \
6662 if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \
6663 val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
6664 alc_old * sizeof(yyjson_val), \
6665 alc_len * sizeof(yyjson_val)); \
6666 if ((!val_tmp)) goto fail_alloc; \
6667 val = val_tmp + (usize)(val - val_hdr); \
6668 ctn = val_tmp + (usize)(ctn - val_hdr); \
6669 state->val = val_tmp + (usize)(state->val - val_hdr); \
6670 state->val_hdr = val_hdr = val_tmp; \
6671 val_end = val_tmp + (alc_len - 2); \
6672 state->val_end = val_end; \
6673 } \
6674} while (false)
6675
6676 /* save position where it's possible to resume incremental parsing */
6677#if YYJSON_READER_DEPTH_LIMIT
6678#define save_incr_depth() (state->ctn_depth = ctn_depth)
6679#else
6680#define save_incr_depth() ((void)0)
6681#endif
6682#define save_incr_state(_label) do { \
6683 state->label = LABEL_##_label; \
6684 state->cur = cur; \
6685 state->val = val; \
6686 state->ctn_len = ctn_len; \
6687 save_incr_depth(); \
6688 state->hdr_len = hdr_len; \
6689 state->raw_ptr = raw_ptr; \
6690 if (unlikely(cur >= end)) goto unexpected_end; \
6691} while (false)
6692
6693#define check_maybe_truncated_number() do { \
6694 if (unlikely(cur >= end)) { \
6695 if (unlikely(cur > state->cur + INCR_NUM_MAX_LEN)) { \
6696 msg = "number too long"; \
6697 goto fail_number; \
6698 } \
6699 goto unexpected_end; \
6700 } \
6701} while (false)
6702
6703 u8 *hdr = NULL, *end = NULL, *cur = NULL;
6704 yyjson_read_flag flg;
6705 yyjson_alc alc;
6706 usize dat_len; /* data length in bytes, hint for allocator */
6707 usize hdr_len; /* value count used by yyjson_doc */
6708 usize alc_len; /* value count allocated */
6709 usize alc_max; /* maximum value count for allocator */
6710 usize ctn_len; /* the number of elements in current container */
6711 yyjson_val *val_hdr; /* the head of allocated values */
6712 yyjson_val *val_end; /* the end of allocated values */
6713 yyjson_val *val_tmp; /* temporary pointer for realloc */
6714 yyjson_val *val; /* current JSON value */
6715 yyjson_val *ctn; /* current container */
6716 yyjson_val *ctn_parent; /* parent of current container */
6717 yyjson_doc *doc; /* the JSON document, equals to val_hdr */
6718 const char *msg; /* error message */
6719
6720 yyjson_read_err tmp_err;
6721 u8 *raw_ptr; /* deferred raw null-terminator position, committed at save */
6722 u8 **pre = &raw_ptr; /* previous raw end pointer */
6723 u8 **con = NULL; /* for incremental string parsing */
6724 u8 saved_end = '\0'; /* saved end char */
6725
6726#if YYJSON_READER_DEPTH_LIMIT
6727 usize ctn_depth = 0; /* current array/object depth */
6728#endif
6729
6730 /* validate input parameters */
6731 if (!err) err = &tmp_err;
6732 if (unlikely(!state)) {
6733 return_err_inv_param("input state is NULL");
6734 }
6735 if (unlikely(!len)) {
6736 return_err_inv_param("input length is 0");
6737 }
6738 if (unlikely(len > state->buf_len)) {
6739 return_err_inv_param("length is greater than total input length");
6740 }
6741
6742 /* restore state saved from the previous call */
6743 hdr = state->hdr;
6744 end = state->hdr + len;
6745 cur = state->cur;
6746 flg = state->flg;
6747 alc = state->alc;
6748 ctn_len = state->ctn_len;
6749#if YYJSON_READER_DEPTH_LIMIT
6750 ctn_depth = state->ctn_depth;
6751#endif
6752 hdr_len = state->hdr_len;
6753 alc_len = state->alc_len;
6754 val = state->val;
6755 val_hdr = state->val_hdr;
6756 val_end = state->val_end;
6757 ctn = state->ctn;
6758 con = state->str_con;
6759 raw_ptr = state->raw_ptr;
6760 alc_max = USIZE_MAX / sizeof(yyjson_val);
6761
6762 /* insert null terminator to make us stop at the specified end, even if
6763 the data contains more valid JSON */
6764 saved_end = *end;
6765 *end = '\0';
6766
6767 /* resume parsing from the last save point */
6768 switch (state->label) {
6769 case LABEL_doc_begin: goto doc_begin;
6770 case LABEL_arr_val_begin: goto arr_val_begin;
6771 case LABEL_arr_val_end: goto arr_val_end;
6772 case LABEL_obj_key_begin: goto obj_key_begin;
6773 case LABEL_obj_key_end: goto obj_key_end;
6774 case LABEL_obj_val_begin: goto obj_val_begin;
6775 case LABEL_obj_val_end: goto obj_val_end;
6776 case LABEL_doc_end: goto doc_end;
6777 default: return_err_inv_param("invalid incremental state");
6778 }
6779
6780doc_begin:
6781 /* skip empty contents before json document */
6782 if (unlikely(!char_is_ctn(*cur))) {
6783 while (char_is_space(*cur)) cur++;
6784 if (unlikely(cur >= end)) goto unexpected_end; /* input data is empty */
6785 }
6786
6787 /* allocate memory for document */
6788 if (!val_hdr) {
6789 hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
6790 hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
6791 if (likely(char_is_ctn(*cur))) {
6792 dat_len = has_flg(STOP_WHEN_DONE) ? 256 : state->buf_len;
6793 alc_len = hdr_len +
6794 (dat_len / YYJSON_READER_ESTIMATED_MINIFY_RATIO) + 4;
6795 alc_len = yyjson_min(alc_len, alc_max);
6796 } else {
6797 alc_len = hdr_len + 1; /* single value */
6798 }
6799 val_hdr = (yyjson_val *)alc.malloc(alc.ctx,
6800 alc_len * sizeof(yyjson_val));
6801 if (unlikely(!val_hdr)) goto fail_alloc;
6802 val_end = val_hdr + (alc_len - 2); /* padding for kv pair reading */
6803 val = val_hdr + hdr_len;
6804 ctn = val;
6805 ctn_len = 0;
6806 state->val_hdr = val_hdr;
6807 state->val_end = val_end;
6808 save_incr_state(doc_begin);
6809 }
6810
6811 /* read json document */
6812 if (*cur == '{') {
6813 cur++;
6814 ctn->tag = YYJSON_TYPE_OBJ;
6815 ctn->uni.ofs = 0;
6816 goto obj_key_begin;
6817 }
6818 if (*cur == '[') {
6819 cur++;
6820 ctn->tag = YYJSON_TYPE_ARR;
6821 ctn->uni.ofs = 0;
6822 goto arr_val_begin;
6823 }
6824 if (char_is_num(*cur)) {
6825 if (likely(read_num(&cur, pre, flg, val, &msg))) {
6826 /* a root number may continue with more digits in a later chunk */
6827 if (unlikely(len < state->buf_len)) check_maybe_truncated_number();
6828 goto doc_end;
6829 }
6830 goto fail_number;
6831 }
6832 if (*cur == '"') {
6833 if (likely(read_str_con(&cur, end, flg, val, &msg, con))) goto doc_end;
6834 goto fail_string;
6835 }
6836 if (*cur == 't') {
6837 if (likely(read_true(&cur, val))) goto doc_end;
6838 goto fail_literal_true;
6839 }
6840 if (*cur == 'f') {
6841 if (likely(read_false(&cur, val))) goto doc_end;
6842 goto fail_literal_false;
6843 }
6844 if (*cur == 'n') {
6845 if (likely(read_null(&cur, val))) goto doc_end;
6846 goto fail_literal_null;
6847 }
6848
6849 msg = "unexpected character, expected a valid root value";
6850 if (cur == hdr) {
6851 /* RFC 8259: JSON text MUST be encoded using UTF-8 */
6852 if (is_utf8_bom(hdr)) msg = MSG_ERR_BOM;
6853 else if (len >= 4 && is_utf32_bom(hdr)) msg = MSG_ERR_UTF32;
6854 else if (len >= 2 && is_utf16_bom(hdr)) msg = MSG_ERR_UTF16;
6855 }
6856 return_err(cur, UNEXPECTED_CHARACTER, msg);
6857
6858arr_begin:
6859#if YYJSON_READER_DEPTH_LIMIT
6860 ctn_depth++;
6861 if (unlikely(ctn_depth >= (usize)YYJSON_READER_DEPTH_LIMIT)) {
6862 goto fail_depth;
6863 }
6864#endif
6865
6866 /* save current container */
6867 ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
6868 (ctn->tag & YYJSON_TAG_MASK);
6869
6870 /* create a new array value, save parent container offset */
6871 val_incr();
6872 val->tag = YYJSON_TYPE_ARR;
6873 val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
6874
6875 /* push the new array value as current container */
6876 ctn = val;
6877 ctn_len = 0;
6878
6879arr_val_begin:
6880 save_incr_state(arr_val_begin);
6881arr_val_continue:
6882 if (*cur == '{') {
6883 cur++;
6884 goto obj_begin;
6885 }
6886 if (*cur == '[') {
6887 cur++;
6888 goto arr_begin;
6889 }
6890 if (char_is_num(*cur)) {
6891 val_incr();
6892 ctn_len++;
6893 if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_maybe_end;
6894 goto fail_number;
6895 }
6896 if (*cur == '"') {
6897 val_incr();
6898 ctn_len++;
6899 if (likely(read_str_con(&cur, end, flg, val, &msg, con)))
6900 goto arr_val_end;
6901 goto fail_string;
6902 }
6903 if (*cur == 't') {
6904 val_incr();
6905 ctn_len++;
6906 if (likely(read_true(&cur, val))) goto arr_val_end;
6907 goto fail_literal_true;
6908 }
6909 if (*cur == 'f') {
6910 val_incr();
6911 ctn_len++;
6912 if (likely(read_false(&cur, val))) goto arr_val_end;
6913 goto fail_literal_false;
6914 }
6915 if (*cur == 'n') {
6916 val_incr();
6917 ctn_len++;
6918 if (likely(read_null(&cur, val))) goto arr_val_end;
6919 goto fail_literal_null;
6920 }
6921 if (*cur == ']') {
6922 cur++;
6923 if (likely(ctn_len == 0)) goto arr_end;
6924 do { cur--; } while (*cur != ',');
6925 goto fail_trailing_comma;
6926 }
6927 if (char_is_space(*cur)) {
6928 while (char_is_space(*++cur));
6929 goto arr_val_continue;
6930 }
6931 goto fail_character_val;
6932
6933arr_val_maybe_end:
6934 /* if incremental parsing stops in the middle of a number, it may continue
6935 with more digits, so arr val maybe didn't end yet */
6936 check_maybe_truncated_number();
6937
6938arr_val_end:
6939 save_incr_state(arr_val_end);
6940 if (*cur == ',') {
6941 cur++;
6942 goto arr_val_begin;
6943 }
6944 if (*cur == ']') {
6945 cur++;
6946 goto arr_end;
6947 }
6948 if (char_is_space(*cur)) {
6949 while (char_is_space(*++cur));
6950 goto arr_val_end;
6951 }
6952 goto fail_character_arr_end;
6953
6954arr_end:
6955#if YYJSON_READER_DEPTH_LIMIT
6956 ctn_depth--;
6957#endif
6958 /* get parent container */
6959 ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
6960
6961 /* save the next sibling value offset */
6962 ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
6963 ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
6964 if (unlikely(ctn == ctn_parent)) goto doc_end;
6965
6966 /* pop parent as current container */
6967 ctn = ctn_parent;
6968 ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
6969 if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
6970 goto obj_val_end;
6971 } else {
6972 goto arr_val_end;
6973 }
6974
6975obj_begin:
6976#if YYJSON_READER_DEPTH_LIMIT
6977 ctn_depth++;
6978 if (unlikely(ctn_depth >= (usize)YYJSON_READER_DEPTH_LIMIT)) {
6979 goto fail_depth;
6980 }
6981#endif
6982
6983 /* push container */
6984 ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
6985 (ctn->tag & YYJSON_TAG_MASK);
6986 val_incr();
6987 val->tag = YYJSON_TYPE_OBJ;
6988 /* offset to the parent */
6989 val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
6990 ctn = val;
6991 ctn_len = 0;
6992
6993obj_key_begin:
6994 save_incr_state(obj_key_begin);
6995obj_key_continue:
6996 if (likely(*cur == '"')) {
6997 val_incr();
6998 ctn_len++;
6999 if (likely(read_str_con(&cur, end, flg, val, &msg, con)))
7000 goto obj_key_end;
7001 goto fail_string;
7002 }
7003 if (likely(*cur == '}')) {
7004 cur++;
7005 if (likely(ctn_len == 0)) goto obj_end;
7006 do { cur--; } while (*cur != ',');
7007 goto fail_trailing_comma;
7008 }
7009 if (char_is_space(*cur)) {
7010 while (char_is_space(*++cur));
7011 goto obj_key_continue;
7012 }
7013 goto fail_character_obj_key;
7014
7015obj_key_end:
7016 save_incr_state(obj_key_end);
7017 if (*cur == ':') {
7018 cur++;
7019 goto obj_val_begin;
7020 }
7021 if (char_is_space(*cur)) {
7022 while (char_is_space(*++cur));
7023 goto obj_key_end;
7024 }
7025 goto fail_character_obj_sep;
7026
7027obj_val_begin:
7028 save_incr_state(obj_val_begin);
7029obj_val_continue:
7030 if (*cur == '"') {
7031 val++;
7032 ctn_len++;
7033 if (likely(read_str_con(&cur, end, flg, val, &msg, con)))
7034 goto obj_val_end;
7035 goto fail_string;
7036 }
7037 if (char_is_num(*cur)) {
7038 val++;
7039 ctn_len++;
7040 if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_maybe_end;
7041 goto fail_number;
7042 }
7043 if (*cur == '{') {
7044 cur++;
7045 goto obj_begin;
7046 }
7047 if (*cur == '[') {
7048 cur++;
7049 goto arr_begin;
7050 }
7051 if (*cur == 't') {
7052 val++;
7053 ctn_len++;
7054 if (likely(read_true(&cur, val))) goto obj_val_end;
7055 goto fail_literal_true;
7056 }
7057 if (*cur == 'f') {
7058 val++;
7059 ctn_len++;
7060 if (likely(read_false(&cur, val))) goto obj_val_end;
7061 goto fail_literal_false;
7062 }
7063 if (*cur == 'n') {
7064 val++;
7065 ctn_len++;
7066 if (likely(read_null(&cur, val))) goto obj_val_end;
7067 goto fail_literal_null;
7068 }
7069 if (char_is_space(*cur)) {
7070 while (char_is_space(*++cur));
7071 goto obj_val_continue;
7072 }
7073 goto fail_character_val;
7074
7075obj_val_maybe_end:
7076 /* if incremental parsing stops in the middle of a number, it may continue
7077 with more digits, so obj val maybe didn't end yet */
7078 check_maybe_truncated_number();
7079
7080obj_val_end:
7081 save_incr_state(obj_val_end);
7082 if (likely(*cur == ',')) {
7083 cur++;
7084 goto obj_key_begin;
7085 }
7086 if (likely(*cur == '}')) {
7087 cur++;
7088 goto obj_end;
7089 }
7090 if (char_is_space(*cur)) {
7091 while (char_is_space(*++cur));
7092 goto obj_val_end;
7093 }
7094 goto fail_character_obj_end;
7095
7096obj_end:
7097#if YYJSON_READER_DEPTH_LIMIT
7098 ctn_depth--;
7099#endif
7100
7101 /* pop container */
7102 ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
7103 /* point to the next value */
7104 ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
7105 ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
7106 if (unlikely(ctn == ctn_parent)) goto doc_end;
7107 ctn = ctn_parent;
7108 ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
7109 if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
7110 goto obj_val_end;
7111 } else {
7112 goto arr_val_end;
7113 }
7114
7115doc_end:
7116 /* check invalid contents after json document */
7117 if (unlikely(cur < end || len < state->buf_len) &&
7118 !has_flg(STOP_WHEN_DONE)) {
7119 save_incr_state(doc_end);
7120 while (char_is_space(*cur)) cur++;
7121 if (unlikely(cur < end)) goto fail_garbage;
7122 /* the document is complete for the bytes seen so far, but more input
7123 is still pending; it may hold trailing content that has to be
7124 rejected, so request the remaining data before finalizing */
7125 if (unlikely(len < state->buf_len)) goto unexpected_end;
7126 }
7127
7128 **pre = '\0';
7129 doc = (yyjson_doc *)val_hdr;
7130 doc->root = val_hdr + hdr_len;
7131 doc->alc = alc;
7132 doc->dat_read = (usize)(cur - hdr);
7133 doc->val_read = (usize)((val - doc->root) + 1);
7134 doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
7135 state->hdr = NULL;
7136 state->val_hdr = NULL;
7137 memset(err, 0, sizeof(yyjson_read_err));
7138 return doc;
7139
7140unexpected_end:
7141 err->pos = len;
7142 /* if no more data, stop the incr read */
7143 if (unlikely(len >= state->buf_len)) {
7144 err->code = YYJSON_READ_ERROR_UNEXPECTED_END;
7145 err->msg = MSG_NOT_END;
7146 return NULL;
7147 }
7148 /* save parser state in extended error struct, in addition to what was
7149 * stored in the last save_incr_state */
7150 err->code = YYJSON_READ_ERROR_MORE;
7151 err->msg = "need more data";
7152 state->val_end = val_end;
7153 state->ctn = ctn;
7154 state->alc_len = alc_len;
7155 /* restore the end where we've inserted a null terminator */
7156 *end = saved_end;
7157 return NULL;
7158
7159fail_string: return_err(cur, INVALID_STRING, msg);
7160fail_number: return_err(cur, INVALID_NUMBER, msg);
7161fail_alloc: return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
7162fail_trailing_comma: return_err(cur, JSON_STRUCTURE, MSG_COMMA);
7163fail_literal_true: return_err(cur, LITERAL, MSG_CHAR_T);
7164fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F);
7165fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N);
7166fail_character_val: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
7167fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END);
7168fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY);
7169fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
7170fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
7171fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
7172fail_depth: return_err(cur, DEPTH, MSG_DEPTH);
7173
7174#undef val_incr
7175#undef return_err
7176#undef return_err_inv_param
7177#undef save_incr_state
7178#undef save_incr_depth
7179#undef check_maybe_truncated_number
7180}
7181
7182#endif /* YYJSON_DISABLE_INCR_READER */
7183
7184#undef has_flg
7185#undef has_allow
7186#endif /* YYJSON_DISABLE_READER */
7187
7188
7189
7190#if !YYJSON_DISABLE_WRITER /* writer begin */
7191
7192/* Check write flag, avoids `always false` warning when disabled. */
7193#define has_flg(_flg) unlikely(has_wflag(flg, YYJSON_WRITE_##_flg, 0))
7194#define has_allow(_flg) unlikely(has_wflag(flg, YYJSON_WRITE_ALLOW_##_flg, 1))
7195static_inline bool has_wflag(yyjson_write_flag flg, yyjson_write_flag chk,
7196 bool non_standard) {
7197#if YYJSON_DISABLE_NON_STANDARD
7198 if (non_standard) return false;
7199#endif
7200 return (flg & chk) != 0;
7201}
7202
7203/*==============================================================================
7204 * MARK: - Integer Writer (Private)
7205 *
7206 * The maximum value of uint32_t is 4294967295 (10 digits),
7207 * these digits are named as 'aabbccddee' here.
7208 *
7209 * Although most compilers may convert the "division by constant value" into
7210 * "multiply and shift", manual conversion can still help some compilers
7211 * generate fewer and better instructions.
7212 *
7213 * Reference:
7214 * Division by Invariant Integers using Multiplication, 1994.
7215 * https://gmplib.org/~tege/divcnst-pldi94.pdf
7216 * Improved division by invariant integers, 2011.
7217 * https://gmplib.org/~tege/division-paper.pdf
7218 *============================================================================*/
7219
7220/** Digit table from 00 to 99. */
7221yyjson_align(2)
7222static const char digit_table[200] = {
7223 '0', '0', '0', '1', '0', '2', '0', '3', '0', '4',
7224 '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
7225 '1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
7226 '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
7227 '2', '0', '2', '1', '2', '2', '2', '3', '2', '4',
7228 '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
7229 '3', '0', '3', '1', '3', '2', '3', '3', '3', '4',
7230 '3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
7231 '4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
7232 '4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
7233 '5', '0', '5', '1', '5', '2', '5', '3', '5', '4',
7234 '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
7235 '6', '0', '6', '1', '6', '2', '6', '3', '6', '4',
7236 '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
7237 '7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
7238 '7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
7239 '8', '0', '8', '1', '8', '2', '8', '3', '8', '4',
7240 '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
7241 '9', '0', '9', '1', '9', '2', '9', '3', '9', '4',
7242 '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'
7243};
7244
7245static_inline u8 *write_u32_len_8(u32 val, u8 *buf) {
7246 u32 aa, bb, cc, dd, aabb, ccdd; /* 8 digits: aabbccdd */
7247 aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
7248 ccdd = val - aabb * 10000; /* (val % 10000) */
7249 aa = (aabb * 5243) >> 19; /* (aabb / 100) */
7250 cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */
7251 bb = aabb - aa * 100; /* (aabb % 100) */
7252 dd = ccdd - cc * 100; /* (ccdd % 100) */
7253 byte_copy_2(buf + 0, digit_table + aa * 2);
7254 byte_copy_2(buf + 2, digit_table + bb * 2);
7255 byte_copy_2(buf + 4, digit_table + cc * 2);
7256 byte_copy_2(buf + 6, digit_table + dd * 2);
7257 return buf + 8;
7258}
7259
7260static_inline u8 *write_u32_len_4(u32 val, u8 *buf) {
7261 u32 aa, bb; /* 4 digits: aabb */
7262 aa = (val * 5243) >> 19; /* (val / 100) */
7263 bb = val - aa * 100; /* (val % 100) */
7264 byte_copy_2(buf + 0, digit_table + aa * 2);
7265 byte_copy_2(buf + 2, digit_table + bb * 2);
7266 return buf + 4;
7267}
7268
7269static_inline u8 *write_u32_len_1_to_8(u32 val, u8 *buf) {
7270 u32 aa, bb, cc, dd, aabb, bbcc, ccdd, lz;
7271
7272 if (val < 100) { /* 1-2 digits: aa */
7273 lz = val < 10; /* leading zero: 0 or 1 */
7274 byte_copy_2(buf + 0, digit_table + val * 2 + lz);
7275 buf -= lz;
7276 return buf + 2;
7277
7278 } else if (val < 10000) { /* 3-4 digits: aabb */
7279 aa = (val * 5243) >> 19; /* (val / 100) */
7280 bb = val - aa * 100; /* (val % 100) */
7281 lz = aa < 10; /* leading zero: 0 or 1 */
7282 byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7283 buf -= lz;
7284 byte_copy_2(buf + 2, digit_table + bb * 2);
7285 return buf + 4;
7286
7287 } else if (val < 1000000) { /* 5-6 digits: aabbcc */
7288 aa = (u32)(((u64)val * 429497) >> 32); /* (val / 10000) */
7289 bbcc = val - aa * 10000; /* (val % 10000) */
7290 bb = (bbcc * 5243) >> 19; /* (bbcc / 100) */
7291 cc = bbcc - bb * 100; /* (bbcc % 100) */
7292 lz = aa < 10; /* leading zero: 0 or 1 */
7293 byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7294 buf -= lz;
7295 byte_copy_2(buf + 2, digit_table + bb * 2);
7296 byte_copy_2(buf + 4, digit_table + cc * 2);
7297 return buf + 6;
7298
7299 } else { /* 7-8 digits: aabbccdd */
7300 aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
7301 ccdd = val - aabb * 10000; /* (val % 10000) */
7302 aa = (aabb * 5243) >> 19; /* (aabb / 100) */
7303 cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */
7304 bb = aabb - aa * 100; /* (aabb % 100) */
7305 dd = ccdd - cc * 100; /* (ccdd % 100) */
7306 lz = aa < 10; /* leading zero: 0 or 1 */
7307 byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7308 buf -= lz;
7309 byte_copy_2(buf + 2, digit_table + bb * 2);
7310 byte_copy_2(buf + 4, digit_table + cc * 2);
7311 byte_copy_2(buf + 6, digit_table + dd * 2);
7312 return buf + 8;
7313 }
7314}
7315
7316static_inline u8 *write_u32_len_5_to_8(u32 val, u8 *buf) {
7317 u32 aa, bb, cc, dd, aabb, bbcc, ccdd, lz;
7318
7319 if (val < 1000000) { /* 5-6 digits: aabbcc */
7320 aa = (u32)(((u64)val * 429497) >> 32); /* (val / 10000) */
7321 bbcc = val - aa * 10000; /* (val % 10000) */
7322 bb = (bbcc * 5243) >> 19; /* (bbcc / 100) */
7323 cc = bbcc - bb * 100; /* (bbcc % 100) */
7324 lz = aa < 10; /* leading zero: 0 or 1 */
7325 byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7326 buf -= lz;
7327 byte_copy_2(buf + 2, digit_table + bb * 2);
7328 byte_copy_2(buf + 4, digit_table + cc * 2);
7329 return buf + 6;
7330
7331 } else { /* 7-8 digits: aabbccdd */
7332 aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
7333 ccdd = val - aabb * 10000; /* (val % 10000) */
7334 aa = (aabb * 5243) >> 19; /* (aabb / 100) */
7335 cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */
7336 bb = aabb - aa * 100; /* (aabb % 100) */
7337 dd = ccdd - cc * 100; /* (ccdd % 100) */
7338 lz = aa < 10; /* leading zero: 0 or 1 */
7339 byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7340 buf -= lz;
7341 byte_copy_2(buf + 2, digit_table + bb * 2);
7342 byte_copy_2(buf + 4, digit_table + cc * 2);
7343 byte_copy_2(buf + 6, digit_table + dd * 2);
7344 return buf + 8;
7345 }
7346}
7347
7348static_inline u8 *write_u64(u64 val, u8 *buf) {
7349 u64 tmp, hgh;
7350 u32 mid, low;
7351
7352 if (val < 100000000) { /* 1-8 digits */
7353 buf = write_u32_len_1_to_8((u32)val, buf);
7354 return buf;
7355
7356 } else if (val < (u64)100000000 * 100000000) { /* 9-16 digits */
7357 hgh = val / 100000000; /* (val / 100000000) */
7358 low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
7359 buf = write_u32_len_1_to_8((u32)hgh, buf);
7360 buf = write_u32_len_8(low, buf);
7361 return buf;
7362
7363 } else { /* 17-20 digits */
7364 tmp = val / 100000000; /* (val / 100000000) */
7365 low = (u32)(val - tmp * 100000000); /* (val % 100000000) */
7366 hgh = (u32)(tmp / 10000); /* (tmp / 10000) */
7367 mid = (u32)(tmp - hgh * 10000); /* (tmp % 10000) */
7368 buf = write_u32_len_5_to_8((u32)hgh, buf);
7369 buf = write_u32_len_4(mid, buf);
7370 buf = write_u32_len_8(low, buf);
7371 return buf;
7372 }
7373}
7374
7375
7376
7377/*==============================================================================
7378 * MARK: - Number Writer (Private)
7379 *============================================================================*/
7380
7381#if !YYJSON_DISABLE_FAST_FP_CONV /* FP_WRITER */
7382
7383/** Trailing zero count table for number 0 to 99.
7384 (generated with misc/make_tables.c) */
7385static const u8 dec_trailing_zero_table[] = {
7386 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7387 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7388 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7389 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7390 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7391 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7392 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7393 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7394 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7395 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
7396};
7397
7398static_inline u8 *write_u64_len_1_to_16(u64 val, u8 *buf) {
7399 u64 hgh;
7400 u32 low;
7401 if (val < 100000000) { /* 1-8 digits */
7402 buf = write_u32_len_1_to_8((u32)val, buf);
7403 return buf;
7404 } else { /* 9-16 digits */
7405 hgh = val / 100000000; /* (val / 100000000) */
7406 low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
7407 buf = write_u32_len_1_to_8((u32)hgh, buf);
7408 buf = write_u32_len_8(low, buf);
7409 return buf;
7410 }
7411}
7412
7413static_inline u8 *write_u64_len_1_to_17(u64 val, u8 *buf) {
7414 u64 hgh;
7415 u32 mid, low, one;
7416 if (val >= (u64)100000000 * 10000000) { /* len: 16 to 17 */
7417 hgh = val / 100000000; /* (val / 100000000) */
7418 low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
7419 one = (u32)(hgh / 100000000); /* (hgh / 100000000) */
7420 mid = (u32)(hgh - (u64)one * 100000000); /* (hgh % 100000000) */
7421 *buf = (u8)((u8)one + (u8)'0');
7422 buf += one > 0;
7423 buf = write_u32_len_8(mid, buf);
7424 buf = write_u32_len_8(low, buf);
7425 return buf;
7426 } else if (val >= (u64)100000000){ /* len: 9 to 15 */
7427 hgh = val / 100000000; /* (val / 100000000) */
7428 low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
7429 buf = write_u32_len_1_to_8((u32)hgh, buf);
7430 buf = write_u32_len_8(low, buf);
7431 return buf;
7432 } else { /* len: 1 to 8 */
7433 buf = write_u32_len_1_to_8((u32)val, buf);
7434 return buf;
7435 }
7436}
7437
7438/**
7439 Write an unsigned integer with a length of 7 to 9 with trailing zero trimmed.
7440 These digits are named as "abbccddee" here.
7441 For example, input 123456000, output "123456".
7442 */
7443static_inline u8 *write_u32_len_7_to_9_trim(u32 val, u8 *buf) {
7444 bool lz;
7445 u32 tz, tz1, tz2;
7446
7447 u32 abbcc = val / 10000; /* (abbccddee / 10000) */
7448 u32 ddee = val - abbcc * 10000; /* (abbccddee % 10000) */
7449 u32 abb = (u32)(((u64)abbcc * 167773) >> 24); /* (abbcc / 100) */
7450 u32 a = (abb * 41) >> 12; /* (abb / 100) */
7451 u32 bb = abb - a * 100; /* (abb % 100) */
7452 u32 cc = abbcc - abb * 100; /* (abbcc % 100) */
7453
7454 /* write abbcc */
7455 buf[0] = (u8)(a + '0');
7456 buf += a > 0;
7457 lz = bb < 10 && a == 0;
7458 byte_copy_2(buf + 0, digit_table + bb * 2 + lz);
7459 buf -= lz;
7460 byte_copy_2(buf + 2, digit_table + cc * 2);
7461
7462 if (ddee) {
7463 u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */
7464 u32 ee = ddee - dd * 100; /* (ddee % 100) */
7465 byte_copy_2(buf + 4, digit_table + dd * 2);
7466 byte_copy_2(buf + 6, digit_table + ee * 2);
7467 tz1 = dec_trailing_zero_table[dd];
7468 tz2 = dec_trailing_zero_table[ee];
7469 tz = ee ? tz2 : (tz1 + 2);
7470 buf += 8 - tz;
7471 return buf;
7472 } else {
7473 tz1 = dec_trailing_zero_table[bb];
7474 tz2 = dec_trailing_zero_table[cc];
7475 tz = cc ? tz2 : (tz1 + tz2);
7476 buf += 4 - tz;
7477 return buf;
7478 }
7479}
7480
7481/**
7482 Write an unsigned integer with a length of 16 or 17 with trailing zero trimmed.
7483 These digits are named as "abbccddeeffgghhii" here.
7484 For example, input 1234567890123000, output "1234567890123".
7485 */
7486static_inline u8 *write_u64_len_16_to_17_trim(u64 val, u8 *buf) {
7487 u32 tz, tz1, tz2;
7488
7489 u32 abbccddee = (u32)(val / 100000000);
7490 u32 ffgghhii = (u32)(val - (u64)abbccddee * 100000000);
7491 u32 abbcc = abbccddee / 10000;
7492 u32 ddee = abbccddee - abbcc * 10000;
7493 u32 abb = (u32)(((u64)abbcc * 167773) >> 24); /* (abbcc / 100) */
7494 u32 a = (abb * 41) >> 12; /* (abb / 100) */
7495 u32 bb = abb - a * 100; /* (abb % 100) */
7496 u32 cc = abbcc - abb * 100; /* (abbcc % 100) */
7497 buf[0] = (u8)(a + '0');
7498 buf += a > 0;
7499 byte_copy_2(buf + 0, digit_table + bb * 2);
7500 byte_copy_2(buf + 2, digit_table + cc * 2);
7501
7502 if (ffgghhii) {
7503 u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */
7504 u32 ee = ddee - dd * 100; /* (ddee % 100) */
7505 u32 ffgg = (u32)(((u64)ffgghhii * 109951163) >> 40); /* (val / 10000) */
7506 u32 hhii = ffgghhii - ffgg * 10000; /* (val % 10000) */
7507 u32 ff = (ffgg * 5243) >> 19; /* (aabb / 100) */
7508 u32 gg = ffgg - ff * 100; /* (aabb % 100) */
7509 byte_copy_2(buf + 4, digit_table + dd * 2);
7510 byte_copy_2(buf + 6, digit_table + ee * 2);
7511 byte_copy_2(buf + 8, digit_table + ff * 2);
7512 byte_copy_2(buf + 10, digit_table + gg * 2);
7513 if (hhii) {
7514 u32 hh = (hhii * 5243) >> 19; /* (ccdd / 100) */
7515 u32 ii = hhii - hh * 100; /* (ccdd % 100) */
7516 byte_copy_2(buf + 12, digit_table + hh * 2);
7517 byte_copy_2(buf + 14, digit_table + ii * 2);
7518 tz1 = dec_trailing_zero_table[hh];
7519 tz2 = dec_trailing_zero_table[ii];
7520 tz = ii ? tz2 : (tz1 + 2);
7521 return buf + 16 - tz;
7522 } else {
7523 tz1 = dec_trailing_zero_table[ff];
7524 tz2 = dec_trailing_zero_table[gg];
7525 tz = gg ? tz2 : (tz1 + 2);
7526 return buf + 12 - tz;
7527 }
7528 } else {
7529 if (ddee) {
7530 u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */
7531 u32 ee = ddee - dd * 100; /* (ddee % 100) */
7532 byte_copy_2(buf + 4, digit_table + dd * 2);
7533 byte_copy_2(buf + 6, digit_table + ee * 2);
7534 tz1 = dec_trailing_zero_table[dd];
7535 tz2 = dec_trailing_zero_table[ee];
7536 tz = ee ? tz2 : (tz1 + 2);
7537 return buf + 8 - tz;
7538 } else {
7539 tz1 = dec_trailing_zero_table[bb];
7540 tz2 = dec_trailing_zero_table[cc];
7541 tz = cc ? tz2 : (tz1 + tz2);
7542 return buf + 4 - tz;
7543 }
7544 }
7545}
7546
7547/** Write exponent part in range `e-45` to `e38`. */
7548static_inline u8 *write_f32_exp(i32 exp, u8 *buf) {
7549 bool lz;
7550 byte_copy_2(buf, "e-");
7551 buf += 2 - (exp >= 0);
7552 exp = exp < 0 ? -exp : exp;
7553 lz = exp < 10;
7554 byte_copy_2(buf + 0, digit_table + (u32)exp * 2 + lz);
7555 return buf + 2 - lz;
7556}
7557
7558/** Write exponent part in range `e-324` to `e308`. */
7559static_inline u8 *write_f64_exp(i32 exp, u8 *buf) {
7560 byte_copy_2(buf, "e-");
7561 buf += 2 - (exp >= 0);
7562 exp = exp < 0 ? -exp : exp;
7563 if (exp < 100) {
7564 bool lz = exp < 10;
7565 byte_copy_2(buf + 0, digit_table + (u32)exp * 2 + lz);
7566 return buf + 2 - lz;
7567 } else {
7568 u32 hi = ((u32)exp * 656) >> 16; /* exp / 100 */
7569 u32 lo = (u32)exp - hi * 100; /* exp % 100 */
7570 buf[0] = (u8)((u8)hi + (u8)'0');
7571 byte_copy_2(buf + 1, digit_table + lo * 2);
7572 return buf + 3;
7573 }
7574}
7575
7576/** Magic number for fast `divide by power of 10`. */
7577typedef struct {
7578 u64 p10, mul;
7579 u32 shr1, shr2;
7580} div_pow10_magic;
7581
7582/** Generated with llvm, see https://github.com/llvm/llvm-project/
7583 blob/main/llvm/lib/Support/DivisionByConstantInfo.cpp */
7584static const div_pow10_magic div_pow10_table[] = {
7585 { U64(0x00000000, 0x00000001), U64(0x00000000, 0x00000000), 0, 0 },
7586 { U64(0x00000000, 0x0000000A), U64(0xCCCCCCCC, 0xCCCCCCCD), 0, 3 },
7587 { U64(0x00000000, 0x00000064), U64(0x28F5C28F, 0x5C28F5C3), 2, 2 },
7588 { U64(0x00000000, 0x000003E8), U64(0x20C49BA5, 0xE353F7CF), 3, 4 },
7589 { U64(0x00000000, 0x00002710), U64(0x346DC5D6, 0x3886594B), 0, 11 },
7590 { U64(0x00000000, 0x000186A0), U64(0x0A7C5AC4, 0x71B47843), 5, 7 },
7591 { U64(0x00000000, 0x000F4240), U64(0x431BDE82, 0xD7B634DB), 0, 18 },
7592 { U64(0x00000000, 0x00989680), U64(0xD6BF94D5, 0xE57A42BD), 0, 23 },
7593 { U64(0x00000000, 0x05F5E100), U64(0xABCC7711, 0x8461CEFD), 0, 26 },
7594 { U64(0x00000000, 0x3B9ACA00), U64(0x0044B82F, 0xA09B5A53), 9, 11 },
7595 { U64(0x00000002, 0x540BE400), U64(0xDBE6FECE, 0xBDEDD5BF), 0, 33 },
7596 { U64(0x00000017, 0x4876E800), U64(0xAFEBFF0B, 0xCB24AAFF), 0, 36 },
7597 { U64(0x000000E8, 0xD4A51000), U64(0x232F3302, 0x5BD42233), 0, 37 },
7598 { U64(0x00000918, 0x4E72A000), U64(0x384B84D0, 0x92ED0385), 0, 41 },
7599 { U64(0x00005AF3, 0x107A4000), U64(0x0B424DC3, 0x5095CD81), 0, 42 },
7600 { U64(0x00038D7E, 0xA4C68000), U64(0x00024075, 0xF3DCEAC3), 15, 20 },
7601 { U64(0x002386F2, 0x6FC10000), U64(0x39A5652F, 0xB1137857), 0, 51 },
7602 { U64(0x01634578, 0x5D8A0000), U64(0x00005C3B, 0xD5191B53), 17, 22 },
7603 { U64(0x0DE0B6B3, 0xA7640000), U64(0x000049C9, 0x7747490F), 18, 24 },
7604 { U64(0x8AC72304, 0x89E80000), U64(0x760F253E, 0xDB4AB0d3), 0, 62 },
7605};
7606
7607/** Divide a number by power of 10. */
7608static_inline void div_pow10(u64 num, u32 exp, u64 *div, u64 *mod, u64 *p10) {
7609 u64 hi, lo;
7610 div_pow10_magic m = div_pow10_table[exp];
7611 u128_mul(num >> m.shr1, m.mul, &hi, &lo);
7612 *div = hi >> m.shr2;
7613 *mod = num - (*div * m.p10);
7614 *p10 = m.p10;
7615}
7616
7617/** Multiplies 64-bit integer and returns highest 64-bit rounded value. */
7618static_inline u32 u64_round_to_odd(u64 u, u32 cp) {
7619 u64 hi, lo;
7620 u32 y_hi, y_lo;
7621 u128_mul(cp, u, &hi, &lo);
7622 y_hi = (u32)hi;
7623 y_lo = (u32)(lo >> 32);
7624 return y_hi | (y_lo > 1);
7625}
7626
7627/** Multiplies 128-bit integer and returns highest 64-bit rounded value. */
7628static_inline u64 u128_round_to_odd(u64 hi, u64 lo, u64 cp) {
7629 u64 x_hi, x_lo, y_hi, y_lo;
7630 u128_mul(cp, lo, &x_hi, &x_lo);
7631 u128_mul_add(cp, hi, x_hi, &y_hi, &y_lo);
7632 return y_hi | (y_lo > 1);
7633}
7634
7635/** Convert f32 from binary to decimal (shortest but may have trailing zeros).
7636 The input should not be 0, inf or nan. */
7637static_inline void f32_bin_to_dec(u32 sig_raw, u32 exp_raw,
7638 u32 sig_bin, i32 exp_bin,
7639 u32 *sig_dec, i32 *exp_dec) {
7640
7641 bool is_even, irregular, round_up, trim;
7642 bool u0_inside, u1_inside, w0_inside, w1_inside;
7643 u64 p10_hi, p10_lo, hi, lo;
7644 u32 s, sp, cb, cbl, cbr, vb, vbl, vbr, upper, lower, mid;
7645 i32 k, h;
7646
7647 /* Fast path, see f64_bin_to_dec(). */
7648 while (likely(sig_raw)) {
7649 u32 mod, dec, add_1, add_10, s_hi, s_lo;
7650 u32 c, half_ulp, t0, t1;
7651
7652 /* k = floor(exp_bin * log10(2)); */
7653 /* h = exp_bin + floor(log2(10) * -k); (h = 0/1/2/3) */
7654 k = (i32)(exp_bin * 315653) >> 20;
7655 h = exp_bin + ((-k * 217707) >> 16);
7656 pow10_table_get_sig(-k, &p10_hi, &p10_lo);
7657
7658 /* sig_bin << (1/2/3/4) */
7659 cb = sig_bin << (h + 1);
7660 u128_mul(cb, p10_hi, &hi, &lo);
7661 s_hi = (u32)(hi);
7662 s_lo = (u32)(lo >> 32);
7663 mod = s_hi % 10;
7664 dec = s_hi - mod;
7665
7666 /* right shift 4 to fit in u32 */
7667 c = (mod << (32 - 4)) | (s_lo >> 4);
7668 half_ulp = (u32)(p10_hi >> (32 + 4 - h));
7669
7670 /* check w1, u0, w0 range */
7671 w1_inside = (s_lo >= ((u32)1 << 31));
7672 if (unlikely(s_lo == ((u32)1 << 31))) break;
7673 u0_inside = (half_ulp >= c);
7674 if (unlikely(half_ulp == c)) break;
7675 t0 = (u32)10 << (32 - 4);
7676 t1 = c + half_ulp;
7677 w0_inside = (t1 >= t0);
7678 if (unlikely(t0 - t1 <= (u32)1)) break;
7679
7680 trim = (u0_inside | w0_inside);
7681 add_10 = (w0_inside ? 10 : 0);
7682 add_1 = mod + w1_inside;
7683 *sig_dec = dec + (trim ? add_10 : add_1);
7684 *exp_dec = k;
7685 return;
7686 }
7687
7688 /* Schubfach algorithm, see f64_bin_to_dec(). */
7689 irregular = (sig_raw == 0 && exp_raw > 1);
7690 is_even = !(sig_bin & 1);
7691 cbl = 4 * sig_bin - 2 + irregular;
7692 cb = 4 * sig_bin;
7693 cbr = 4 * sig_bin + 2;
7694
7695 /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */
7696 /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */
7697 k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20;
7698 h = exp_bin + ((-k * 217707) >> 16) + 1;
7699 pow10_table_get_sig(-k, &p10_hi, &p10_lo);
7700 p10_hi += 1;
7701
7702 vbl = u64_round_to_odd(p10_hi, cbl << h);
7703 vb = u64_round_to_odd(p10_hi, cb << h);
7704 vbr = u64_round_to_odd(p10_hi, cbr << h);
7705 lower = vbl + !is_even;
7706 upper = vbr - !is_even;
7707
7708 s = vb / 4;
7709 if (s >= 10) {
7710 sp = s / 10;
7711 u0_inside = (lower <= 40 * sp);
7712 w0_inside = (upper >= 40 * sp + 40);
7713 if (u0_inside != w0_inside) {
7714 *sig_dec = sp * 10 + (w0_inside ? 10 : 0);
7715 *exp_dec = k;
7716 return;
7717 }
7718 }
7719 u1_inside = (lower <= 4 * s);
7720 w1_inside = (upper >= 4 * s + 4);
7721 mid = 4 * s + 2;
7722 round_up = (vb > mid) || (vb == mid && (s & 1) != 0);
7723 *sig_dec = s + ((u1_inside != w1_inside) ? w1_inside : round_up);
7724 *exp_dec = k;
7725}
7726
7727/** Convert f64 from binary to decimal (shortest but may have trailing zeros).
7728 The input should not be 0, inf or nan. */
7729static_inline void f64_bin_to_dec(u64 sig_raw, u32 exp_raw,
7730 u64 sig_bin, i32 exp_bin,
7731 u64 *sig_dec, i32 *exp_dec) {
7732
7733 bool is_even, irregular, round_up, trim;
7734 bool u0_inside, u1_inside, w0_inside, w1_inside;
7735 u64 s, sp, cb, cbl, cbr, vb, vbl, vbr, p10_hi, p10_lo, upper, lower, mid;
7736 i32 k, h;
7737
7738 /*
7739 Fast path:
7740 For regular spacing significand 'c', there are 4 candidates:
7741
7742 u0 u1 c w1 w0
7743 ----|----|----|----|----|-*--|----|----|----|----|----|----|----|----
7744 9 0 1 2 3 4 5 6 7 8 9 0 1
7745 |___________________|___________________|
7746 1ulp
7747
7748 The `1ulp` is in the range [1.0, 10.0).
7749 If (c - 0.5ulp < u0), trim the last digit and round down.
7750 If (c + 0.5ulp > w0), trim the last digit and round up.
7751 If (c - 0.5ulp < u1), round down.
7752 If (c + 0.5ulp > w1), round up.
7753 */
7754 while (likely(sig_raw)) {
7755 u64 mod, dec, add_1, add_10, s_hi, s_lo;
7756 u64 c, half_ulp, t0, t1;
7757
7758 /* k = floor(exp_bin * log10(2)); */
7759 /* h = exp_bin + floor(log2(10) * -k); (h = 0/1/2/3) */
7760 k = (i32)(exp_bin * 315653) >> 20;
7761 h = exp_bin + ((-k * 217707) >> 16);
7762 pow10_table_get_sig(-k, &p10_hi, &p10_lo);
7763
7764 /* sig_bin << (1/2/3/4) */
7765 cb = sig_bin << (h + 1);
7766 u128_mul(cb, p10_lo, &s_hi, &s_lo);
7767 u128_mul_add(cb, p10_hi, s_hi, &s_hi, &s_lo);
7768 mod = s_hi % 10;
7769 dec = s_hi - mod;
7770
7771 /* right shift 4 to fit in u64 */
7772 c = (mod << (64 - 4)) | (s_lo >> 4);
7773 half_ulp = p10_hi >> (4 - h);
7774
7775 /* check w1, u0, w0 range */
7776 w1_inside = (s_lo >= ((u64)1 << 63));
7777 if (unlikely(s_lo == ((u64)1 << 63))) break;
7778 u0_inside = (half_ulp >= c);
7779 if (unlikely(half_ulp == c)) break;
7780 t0 = ((u64)10 << (64 - 4));
7781 t1 = c + half_ulp;
7782 w0_inside = (t1 >= t0);
7783 if (unlikely(t0 - t1 <= (u64)1)) break;
7784
7785 trim = (u0_inside | w0_inside);
7786 add_10 = (w0_inside ? 10 : 0);
7787 add_1 = mod + w1_inside;
7788 *sig_dec = dec + (trim ? add_10 : add_1);
7789 *exp_dec = k;
7790 return;
7791 }
7792
7793 /*
7794 Schubfach algorithm:
7795 Raffaello Giulietti, The Schubfach way to render doubles, 2022.
7796 https://drive.google.com/file/d/1gp5xv4CAa78SVgCeWfGqqI4FfYYYuNFb (Paper)
7797 https://github.com/openjdk/jdk/pull/3402 (Java implementation)
7798 https://github.com/abolz/Drachennest (C++ implementation)
7799 */
7800 irregular = (sig_raw == 0 && exp_raw > 1);
7801 is_even = !(sig_bin & 1);
7802 cbl = 4 * sig_bin - 2 + irregular;
7803 cb = 4 * sig_bin;
7804 cbr = 4 * sig_bin + 2;
7805
7806 /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */
7807 /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */
7808 k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20;
7809 h = exp_bin + ((-k * 217707) >> 16) + 1;
7810 pow10_table_get_sig(-k, &p10_hi, &p10_lo);
7811 p10_lo += 1;
7812
7813 vbl = u128_round_to_odd(p10_hi, p10_lo, cbl << h);
7814 vb = u128_round_to_odd(p10_hi, p10_lo, cb << h);
7815 vbr = u128_round_to_odd(p10_hi, p10_lo, cbr << h);
7816 lower = vbl + !is_even;
7817 upper = vbr - !is_even;
7818
7819 s = vb / 4;
7820 if (s >= 10) {
7821 sp = s / 10;
7822 u0_inside = (lower <= 40 * sp);
7823 w0_inside = (upper >= 40 * sp + 40);
7824 if (u0_inside != w0_inside) {
7825 *sig_dec = sp * 10 + (w0_inside ? 10 : 0);
7826 *exp_dec = k;
7827 return;
7828 }
7829 }
7830 u1_inside = (lower <= 4 * s);
7831 w1_inside = (upper >= 4 * s + 4);
7832 mid = 4 * s + 2;
7833 round_up = (vb > mid) || (vb == mid && (s & 1) != 0);
7834 *sig_dec = s + ((u1_inside != w1_inside) ? w1_inside : round_up);
7835 *exp_dec = k;
7836}
7837
7838/** Convert f64 from binary to decimal (fast but not the shortest).
7839 The input should not be 0, inf, nan. */
7840static_inline void f64_bin_to_dec_fast(u64 sig_raw, u32 exp_raw,
7841 u64 sig_bin, i32 exp_bin,
7842 u64 *sig_dec, i32 *exp_dec,
7843 bool *round_up) {
7844 u64 cb, p10_hi, p10_lo, s_hi, s_lo;
7845 i32 k, h;
7846 bool irregular, u;
7847
7848 irregular = (sig_raw == 0 && exp_raw > 1);
7849
7850 /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */
7851 /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */
7852 k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20;
7853 h = exp_bin + ((-k * 217707) >> 16);
7854 pow10_table_get_sig(-k, &p10_hi, &p10_lo);
7855
7856 /* sig_bin << (1/2/3/4) */
7857 cb = sig_bin << (h + 1);
7858 u128_mul(cb, p10_lo, &s_hi, &s_lo);
7859 u128_mul_add(cb, p10_hi, s_hi, &s_hi, &s_lo);
7860
7861 /* round up */
7862 u = s_lo >= (irregular ? U64(0x55555555, 0x55555555) : ((u64)1 << 63));
7863
7864 *sig_dec = s_hi + u;
7865 *exp_dec = k;
7866 *round_up = u;
7867 return;
7868}
7869
7870/** Write inf/nan if allowed. */
7871static_inline u8 *write_inf_or_nan(u8 *buf, yyjson_write_flag flg,
7872 u64 sig_raw, bool sign) {
7873 if (has_flg(INF_AND_NAN_AS_NULL)) {
7874 byte_copy_4(buf, "null");
7875 return buf + 4;
7876 }
7877 if (has_allow(INF_AND_NAN)) {
7878 if (sig_raw == 0) {
7879 buf[0] = '-';
7880 buf += sign;
7881 byte_copy_8(buf, "Infinity");
7882 return buf + 8;
7883 } else {
7884 byte_copy_4(buf, "NaN");
7885 return buf + 3;
7886 }
7887 }
7888 return NULL;
7889}
7890
7891/**
7892 Write a float number (requires 40 bytes buffer).
7893 We follow the ECMAScript specification for printing floating-point numbers,
7894 similar to `Number.prototype.toString()`, but with the following changes:
7895 1. Keep the negative sign of `-0.0` to preserve input information.
7896 2. Keep the decimal point to indicate that the number is floating-point.
7897 3. Remove positive sign in the exponent part.
7898 */
7899static_noinline u8 *write_f32_raw(u8 *buf, u64 raw_f64,
7900 yyjson_write_flag flg) {
7901 u32 sig_bin, sig_dec, sig_raw;
7902 i32 exp_bin, exp_dec, sig_len, dot_ofs;
7903 u32 exp_raw, raw;
7904 u8 *end;
7905 bool sign;
7906
7907 /* cast double to float */
7908 raw = f32_to_bits(f64_to_f32(f64_from_bits(raw_f64)));
7909
7910 /* decode raw bytes from IEEE-754 double format. */
7911 sign = (bool)(raw >> (F32_BITS - 1));
7912 sig_raw = raw & F32_SIG_MASK;
7913 exp_raw = (raw & F32_EXP_MASK) >> F32_SIG_BITS;
7914
7915 /* return inf or nan */
7916 if (unlikely(exp_raw == ((u32)1 << F32_EXP_BITS) - 1)) {
7917 return write_inf_or_nan(buf, flg, sig_raw, sign);
7918 }
7919
7920 /* add sign for all finite number */
7921 buf[0] = '-';
7922 buf += sign;
7923
7924 /* return zero */
7925 if ((raw << 1) == 0) {
7926 byte_copy_4(buf, "0.0");
7927 return buf + 3;
7928 }
7929
7930 if (likely(exp_raw != 0)) {
7931 /* normal number */
7932 sig_bin = sig_raw | ((u32)1 << F32_SIG_BITS);
7933 exp_bin = (i32)exp_raw - F32_EXP_BIAS - F32_SIG_BITS;
7934
7935 /* fast path for small integer number without fraction */
7936 if ((-F32_SIG_BITS <= exp_bin && exp_bin <= 0) &&
7937 (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) {
7938 sig_dec = sig_bin >> -exp_bin; /* range: [1, 0xFFFFFF] */
7939 buf = write_u32_len_1_to_8(sig_dec, buf);
7940 byte_copy_2(buf, ".0");
7941 return buf + 2;
7942 }
7943
7944 /* binary to decimal */
7945 f32_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
7946
7947 /* the sig length is 7 or 9 */
7948 sig_len = 7 + (sig_dec >= (u32)10000000) + (sig_dec >= (u32)100000000);
7949
7950 /* the decimal point offset relative to the first digit */
7951 dot_ofs = sig_len + exp_dec;
7952
7953 if (-6 < dot_ofs && dot_ofs <= 21) {
7954 i32 num_sep_pos, dot_set_pos, pre_ofs;
7955 u8 *num_hdr, *num_end, *num_sep, *dot_end;
7956 bool no_pre_zero;
7957
7958 /* fill zeros */
7959 memset(buf, '0', 32);
7960
7961 /* not prefixed with zero, e.g. 1.234, 1234.0 */
7962 no_pre_zero = (dot_ofs > 0);
7963
7964 /* write the number as digits */
7965 pre_ofs = no_pre_zero ? 0 : (2 - dot_ofs);
7966 num_hdr = buf + pre_ofs;
7967 num_end = write_u32_len_7_to_9_trim(sig_dec, num_hdr);
7968
7969 /* separate these digits to leave a space for dot */
7970 num_sep_pos = no_pre_zero ? dot_ofs : 0;
7971 num_sep = num_hdr + num_sep_pos;
7972 byte_move_8(num_sep + no_pre_zero, num_sep);
7973 num_end += no_pre_zero;
7974
7975 /* write the dot */
7976 dot_set_pos = yyjson_max(dot_ofs, 1);
7977 buf[dot_set_pos] = '.';
7978
7979 /* return the ending */
7980 dot_end = buf + dot_ofs + 2;
7981 return yyjson_max(dot_end, num_end);
7982
7983 } else {
7984 /* write with scientific notation, e.g. 1.234e56 */
7985 end = write_u32_len_7_to_9_trim(sig_dec, buf + 1);
7986 end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */
7987 exp_dec += sig_len - 1;
7988 buf[0] = buf[1];
7989 buf[1] = '.';
7990 return write_f32_exp(exp_dec, end);
7991 }
7992
7993 } else {
7994 /* subnormal number */
7995 sig_bin = sig_raw;
7996 exp_bin = 1 - F32_EXP_BIAS - F32_SIG_BITS;
7997
7998 /* binary to decimal */
7999 f32_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
8000
8001 /* write significand part */
8002 end = write_u32_len_1_to_8(sig_dec, buf + 1);
8003 buf[0] = buf[1];
8004 buf[1] = '.';
8005 exp_dec += (i32)(end - buf) - 2;
8006
8007 /* trim trailing zeros */
8008 end -= *(end - 1) == '0'; /* branchless for last zero */
8009 end -= *(end - 1) == '0'; /* branchless for second last zero */
8010 while (*(end - 1) == '0') end--; /* for unlikely more zeros */
8011 end -= *(end - 1) == '.'; /* remove dot, e.g. 2.e-321 -> 2e-321 */
8012
8013 /* write exponent part */
8014 return write_f32_exp(exp_dec, end);
8015 }
8016}
8017
8018/**
8019 Write a double number (requires 40 bytes buffer).
8020 We follow the ECMAScript specification for printing floating-point numbers,
8021 similar to `Number.prototype.toString()`, but with the following changes:
8022 1. Keep the negative sign of `-0.0` to preserve input information.
8023 2. Keep the decimal point to indicate that the number is floating-point.
8024 3. Remove positive sign in the exponent part.
8025 */
8026static_noinline u8 *write_f64_raw(u8 *buf, u64 raw, yyjson_write_flag flg) {
8027 u64 sig_bin, sig_dec, sig_raw;
8028 i32 exp_bin, exp_dec, sig_len, dot_ofs;
8029 u32 exp_raw;
8030 u8 *end;
8031 bool sign;
8032
8033 /* decode raw bytes from IEEE-754 double format. */
8034 sign = (bool)(raw >> (F64_BITS - 1));
8035 sig_raw = raw & F64_SIG_MASK;
8036 exp_raw = (u32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
8037
8038 /* return inf or nan */
8039 if (unlikely(exp_raw == ((u32)1 << F64_EXP_BITS) - 1)) {
8040 return write_inf_or_nan(buf, flg, sig_raw, sign);
8041 }
8042
8043 /* add sign for all finite number */
8044 buf[0] = '-';
8045 buf += sign;
8046
8047 /* return zero */
8048 if ((raw << 1) == 0) {
8049 byte_copy_4(buf, "0.0");
8050 return buf + 3;
8051 }
8052
8053 if (likely(exp_raw != 0)) {
8054 /* normal number */
8055 sig_bin = sig_raw | ((u64)1 << F64_SIG_BITS);
8056 exp_bin = (i32)exp_raw - F64_EXP_BIAS - F64_SIG_BITS;
8057
8058 /* fast path for small integer number without fraction */
8059 if ((-F64_SIG_BITS <= exp_bin && exp_bin <= 0) &&
8060 (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) {
8061 sig_dec = sig_bin >> -exp_bin; /* range: [1, 0x1FFFFFFFFFFFFF] */
8062 buf = write_u64_len_1_to_16(sig_dec, buf);
8063 byte_copy_2(buf, ".0");
8064 return buf + 2;
8065 }
8066
8067 /* binary to decimal */
8068 f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
8069
8070 /* the sig length is 16 or 17 */
8071 sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
8072
8073 /* the decimal point offset relative to the first digit */
8074 dot_ofs = sig_len + exp_dec;
8075
8076 if (-6 < dot_ofs && dot_ofs <= 21) {
8077 i32 num_sep_pos, dot_set_pos, pre_ofs;
8078 u8 *num_hdr, *num_end, *num_sep, *dot_end;
8079 bool no_pre_zero;
8080
8081 /* fill zeros */
8082 memset(buf, '0', 32);
8083
8084 /* not prefixed with zero, e.g. 1.234, 1234.0 */
8085 no_pre_zero = (dot_ofs > 0);
8086
8087 /* write the number as digits */
8088 pre_ofs = no_pre_zero ? 0 : (2 - dot_ofs);
8089 num_hdr = buf + pre_ofs;
8090 num_end = write_u64_len_16_to_17_trim(sig_dec, num_hdr);
8091
8092 /* separate these digits to leave a space for dot */
8093 num_sep_pos = no_pre_zero ? dot_ofs : 0;
8094 num_sep = num_hdr + num_sep_pos;
8095 byte_move_16(num_sep + no_pre_zero, num_sep);
8096 num_end += no_pre_zero;
8097
8098 /* write the dot */
8099 dot_set_pos = yyjson_max(dot_ofs, 1);
8100 buf[dot_set_pos] = '.';
8101
8102 /* return the ending */
8103 dot_end = buf + dot_ofs + 2;
8104 return yyjson_max(dot_end, num_end);
8105
8106 } else {
8107 /* write with scientific notation, e.g. 1.234e56 */
8108 end = write_u64_len_16_to_17_trim(sig_dec, buf + 1);
8109 end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */
8110 exp_dec += sig_len - 1;
8111 buf[0] = buf[1];
8112 buf[1] = '.';
8113 return write_f64_exp(exp_dec, end);
8114 }
8115
8116 } else {
8117 /* subnormal number */
8118 sig_bin = sig_raw;
8119 exp_bin = 1 - F64_EXP_BIAS - F64_SIG_BITS;
8120
8121 /* binary to decimal */
8122 f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
8123
8124 /* write significand part */
8125 end = write_u64_len_1_to_17(sig_dec, buf + 1);
8126 buf[0] = buf[1];
8127 buf[1] = '.';
8128 exp_dec += (i32)(end - buf) - 2;
8129
8130 /* trim trailing zeros */
8131 end -= *(end - 1) == '0'; /* branchless for last zero */
8132 end -= *(end - 1) == '0'; /* branchless for second last zero */
8133 while (*(end - 1) == '0') end--; /* for unlikely more zeros */
8134 end -= *(end - 1) == '.'; /* remove dot, e.g. 2.e-321 -> 2e-321 */
8135
8136 /* write exponent part */
8137 return write_f64_exp(exp_dec, end);
8138 }
8139}
8140
8141/**
8142 Write a double number using fixed-point notation (requires 40 bytes buffer).
8143
8144 We follow the ECMAScript specification for printing floating-point numbers,
8145 similar to `Number.prototype.toFixed(prec)`, but with the following changes:
8146 1. Keep the negative sign of `-0.0` to preserve input information.
8147 2. Keep the decimal point to indicate that the number is floating-point.
8148 3. Remove positive sign in the exponent part.
8149 4. Remove trailing zeros and reduce unnecessary precision.
8150 */
8151static_noinline u8 *write_f64_raw_fixed(u8 *buf, u64 raw, yyjson_write_flag flg,
8152 u32 prec) {
8153 u64 sig_bin, sig_dec, sig_raw;
8154 i32 exp_bin, exp_dec, sig_len, dot_ofs;
8155 u32 exp_raw;
8156 u8 *end;
8157 bool sign;
8158
8159 /* decode raw bytes from IEEE-754 double format. */
8160 sign = (bool)(raw >> (F64_BITS - 1));
8161 sig_raw = raw & F64_SIG_MASK;
8162 exp_raw = (u32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
8163
8164 /* return inf or nan */
8165 if (unlikely(exp_raw == ((u32)1 << F64_EXP_BITS) - 1)) {
8166 return write_inf_or_nan(buf, flg, sig_raw, sign);
8167 }
8168
8169 /* add sign for all finite number */
8170 buf[0] = '-';
8171 buf += sign;
8172
8173 /* return zero */
8174 if ((raw << 1) == 0) {
8175 byte_copy_4(buf, "0.0");
8176 return buf + 3;
8177 }
8178
8179 if (likely(exp_raw != 0)) {
8180 /* normal number */
8181 sig_bin = sig_raw | ((u64)1 << F64_SIG_BITS);
8182 exp_bin = (i32)exp_raw - F64_EXP_BIAS - F64_SIG_BITS;
8183
8184 /* fast path for small integer number without fraction */
8185 if ((-F64_SIG_BITS <= exp_bin && exp_bin <= 0) &&
8186 (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) {
8187 sig_dec = sig_bin >> -exp_bin; /* range: [1, 0x1FFFFFFFFFFFFF] */
8188 buf = write_u64_len_1_to_16(sig_dec, buf);
8189 byte_copy_2(buf, ".0");
8190 return buf + 2;
8191 }
8192
8193 /* only `fabs(num) < 1e21` are processed here. */
8194 if ((raw << 1) < (U64(0x444B1AE4, 0xD6E2EF50) << 1)) {
8195 i32 num_sep_pos, dot_set_pos, pre_ofs;
8196 u8 *num_hdr, *num_end, *num_sep;
8197 bool round_up, no_pre_zero;
8198
8199 /* binary to decimal */
8200 f64_bin_to_dec_fast(sig_raw, exp_raw, sig_bin, exp_bin,
8201 &sig_dec, &exp_dec, &round_up);
8202
8203 /* the sig length is 16 or 17 */
8204 sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
8205
8206 /* limit the length of digits after the decimal point */
8207 if (exp_dec < -1) {
8208 i32 sig_len_cut = -exp_dec - (i32)prec;
8209 if (sig_len_cut > sig_len) {
8210 byte_copy_4(buf, "0.0");
8211 return buf + 3;
8212 }
8213 if (sig_len_cut > 0) {
8214 u64 div, mod, p10;
8215
8216 /* remove round up */
8217 sig_dec -= round_up;
8218 sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
8219
8220 /* cut off some digits */
8221 div_pow10(sig_dec, (u32)sig_len_cut, &div, &mod, &p10);
8222
8223 /* add round up */
8224 sig_dec = div + (mod >= p10 / 2);
8225
8226 /* update exp and sig length */
8227 exp_dec += sig_len_cut;
8228 sig_len -= sig_len_cut;
8229 sig_len += (sig_len >= 0) &&
8230 (sig_dec >= div_pow10_table[sig_len].p10);
8231 }
8232 if (sig_len <= 0) {
8233 byte_copy_4(buf, "0.0");
8234 return buf + 3;
8235 }
8236 }
8237
8238 /* fill zeros */
8239 memset(buf, '0', 32);
8240
8241 /* the decimal point offset relative to the first digit */
8242 dot_ofs = sig_len + exp_dec;
8243
8244 /* not prefixed with zero, e.g. 1.234, 1234.0 */
8245 no_pre_zero = (dot_ofs > 0);
8246
8247 /* write the number as digits */
8248 pre_ofs = no_pre_zero ? 0 : (1 - dot_ofs);
8249 num_hdr = buf + pre_ofs;
8250 num_end = write_u64_len_1_to_17(sig_dec, num_hdr);
8251
8252 /* separate these digits to leave a space for dot */
8253 num_sep_pos = no_pre_zero ? dot_ofs : -dot_ofs;
8254 num_sep = buf + num_sep_pos;
8255 byte_move_16(num_sep + 1, num_sep);
8256 num_end += (exp_dec < 0);
8257
8258 /* write the dot */
8259 dot_set_pos = yyjson_max(dot_ofs, 1);
8260 buf[dot_set_pos] = '.';
8261
8262 /* remove trailing zeros */
8263 buf += dot_set_pos + 2;
8264 buf = yyjson_max(buf, num_end);
8265 buf -= *(buf - 1) == '0'; /* branchless for last zero */
8266 buf -= *(buf - 1) == '0'; /* branchless for second last zero */
8267 while (*(buf - 1) == '0') buf--; /* for unlikely more zeros */
8268 buf += *(buf - 1) == '.'; /* keep a zero after dot */
8269 return buf;
8270
8271 } else {
8272 /* binary to decimal */
8273 f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin,
8274 &sig_dec, &exp_dec);
8275
8276 /* the sig length is 16 or 17 */
8277 sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
8278
8279 /* write with scientific notation, e.g. 1.234e56 */
8280 end = write_u64_len_16_to_17_trim(sig_dec, buf + 1);
8281 end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */
8282 exp_dec += sig_len - 1;
8283 buf[0] = buf[1];
8284 buf[1] = '.';
8285 return write_f64_exp(exp_dec, end);
8286 }
8287 } else {
8288 /* subnormal number */
8289 byte_copy_4(buf, "0.0");
8290 return buf + 3;
8291 }
8292}
8293
8294#else /* FP_WRITER */
8295
8296#if YYJSON_MSC_VER >= 1400
8297#define snprintf_num(buf, len, fmt, dig, val) \
8298 sprintf_s((char *)buf, len, fmt, dig, val)
8299#elif defined(snprintf) || (YYJSON_STDC_VER >= 199901L)
8300#define snprintf_num(buf, len, fmt, dig, val) \
8301 snprintf((char *)buf, len, fmt, dig, val)
8302#else
8303#define snprintf_num(buf, len, fmt, dig, val) \
8304 sprintf((char *)buf, fmt, dig, val)
8305#endif
8306
8307static_noinline u8 *write_fp_reformat(u8 *buf, int len,
8308 yyjson_write_flag flg, bool fixed) {
8309 u8 *cur = buf;
8310 if (unlikely(len < 1)) return NULL;
8311 cur += (*cur == '-');
8312 if (unlikely(!char_is_digit(*cur))) {
8313 /* nan, inf, or bad output */
8314 if (has_flg(INF_AND_NAN_AS_NULL)) {
8315 byte_copy_4(buf, "null");
8316 return buf + 4;
8317 } else if (has_allow(INF_AND_NAN)) {
8318 if (*cur == 'i') {
8319 byte_copy_8(cur, "Infinity");
8320 return cur + 8;
8321 } else if (*cur == 'n') {
8322 byte_copy_4(buf, "NaN");
8323 return buf + 3;
8324 }
8325 }
8326 return NULL;
8327 } else {
8328 /* finite number */
8329 u8 *end = buf + len, *dot = NULL, *exp = NULL;
8330
8331 /*
8332 The snprintf() function is locale-dependent. For currently known
8333 locales, (en, zh, ja, ko, am, he, hi) use '.' as the decimal point,
8334 while other locales use ',' as the decimal point. we need to replace
8335 ',' with '.' to avoid the locale setting.
8336 */
8337 for (; cur < end; cur++) {
8338 switch (*cur) {
8339 case ',': *cur = '.'; /* fallthrough */
8340 case '.': dot = cur; break;
8341 case 'e': exp = cur; break;
8342 default: break;
8343 }
8344 }
8345 if (fixed) {
8346 /* remove trailing zeros */
8347 while (*(end - 1) == '0') end--;
8348 end += *(end - 1) == '.';
8349 } else {
8350 if (!dot && !exp) {
8351 /* add decimal point, e.g. 123 -> 123.0 */
8352 byte_copy_2(end, ".0");
8353 end += 2;
8354 } else if (exp) {
8355 cur = exp + 1;
8356 /* remove positive sign in the exponent part */
8357 if (*cur == '+') {
8358 memmove(cur, cur + 1, (usize)(end - cur - 1));
8359 end--;
8360 }
8361 cur += (*cur == '-');
8362 /* remove leading zeros in the exponent part */
8363 if (*cur == '0') {
8364 u8 *hdr = cur++;
8365 while (*cur == '0') cur++;
8366 memmove(hdr, cur, (usize)(end - cur));
8367 end -= (usize)(cur - hdr);
8368 }
8369 }
8370 }
8371 return end;
8372 }
8373}
8374
8375/** Write a double number (requires 40 bytes buffer). */
8376static_noinline u8 *write_f64_raw(u8 *buf, u64 raw, yyjson_write_flag flg) {
8377#if defined(DBL_DECIMAL_DIG) && DBL_DECIMAL_DIG < F64_DEC_DIG
8378 int dig = DBL_DECIMAL_DIG;
8379#else
8380 int dig = F64_DEC_DIG;
8381#endif
8382 f64 val = f64_from_bits(raw);
8383 int len = snprintf_num(buf, FP_BUF_LEN, "%.*g", dig, val);
8384 return write_fp_reformat(buf, len, flg, false);
8385}
8386
8387/** Write a double number (requires 40 bytes buffer). */
8388static_noinline u8 *write_f32_raw(u8 *buf, u64 raw, yyjson_write_flag flg) {
8389#if defined(FLT_DECIMAL_DIG) && FLT_DECIMAL_DIG < F32_DEC_DIG
8390 int dig = FLT_DECIMAL_DIG;
8391#else
8392 int dig = F32_DEC_DIG;
8393#endif
8394 f64 val = (f64)f64_to_f32(f64_from_bits(raw));
8395 int len = snprintf_num(buf, FP_BUF_LEN, "%.*g", dig, val);
8396 return write_fp_reformat(buf, len, flg, false);
8397}
8398
8399/** Write a double number (requires 40 bytes buffer). */
8400static_noinline u8 *write_f64_raw_fixed(u8 *buf, u64 raw,
8401 yyjson_write_flag flg, u32 prec) {
8402 f64 val = (f64)f64_from_bits(raw);
8403 if (-1e21 < val && val < 1e21) {
8404 int len = snprintf_num(buf, FP_BUF_LEN, "%.*f", (int)prec, val);
8405 return write_fp_reformat(buf, len, flg, true);
8406 } else {
8407 return write_f64_raw(buf, raw, flg);
8408 }
8409}
8410
8411#endif /* FP_WRITER */
8412
8413/** Write a JSON number (requires 40 bytes buffer). */
8414static_inline u8 *write_num(u8 *cur, yyjson_val *val, yyjson_write_flag flg) {
8415 if (!(val->tag & YYJSON_SUBTYPE_REAL)) {
8416 u64 pos = val->uni.u64;
8417 u64 neg = ~pos + 1;
8418 usize sign = ((val->tag & YYJSON_SUBTYPE_SINT) > 0) & ((i64)pos < 0);
8419 *cur = '-';
8420 return write_u64(sign ? neg : pos, cur + sign);
8421 } else {
8422 u64 raw = val->uni.u64;
8423 u32 val_fmt = (u32)(val->tag >> 32);
8424 u32 all_fmt = flg;
8425 u32 fmt = val_fmt | all_fmt;
8426 if (likely(!(fmt >> (32 - YYJSON_WRITE_FP_FLAG_BITS)))) {
8427 /* double to shortest */
8428 return write_f64_raw(cur, raw, flg);
8429 } else if (fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS)) {
8430 /* double to fixed */
8431 u32 val_prec = val_fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS);
8432 u32 all_prec = all_fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS);
8433 u32 prec = val_prec ? val_prec : all_prec;
8434 return write_f64_raw_fixed(cur, raw, flg, prec);
8435 } else {
8436 if (fmt & YYJSON_WRITE_FP_TO_FLOAT) {
8437 /* float to shortest */
8438 return write_f32_raw(cur, raw, flg);
8439 } else {
8440 /* double to shortest */
8441 return write_f64_raw(cur, raw, flg);
8442 }
8443 }
8444 }
8445}
8446
8447char *yyjson_write_number(const yyjson_val *val, char *buf) {
8448 if (unlikely(!val || !buf)) return NULL;
8449 switch (val->tag & YYJSON_TAG_MASK) {
8450 case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_UINT: {
8451 buf = (char *)write_u64(val->uni.u64, (u8 *)buf);
8452 *buf = '\0';
8453 return buf;
8454 }
8455 case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_SINT: {
8456 u64 pos = val->uni.u64;
8457 u64 neg = ~pos + 1;
8458 usize sign = ((i64)pos < 0);
8459 *buf = '-';
8460 buf = (char *)write_u64(sign ? neg : pos, (u8 *)buf + sign);
8461 *buf = '\0';
8462 return buf;
8463 }
8464 case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL: {
8465 u64 raw = val->uni.u64;
8466 u32 fmt = (u32)(val->tag >> 32);
8467 u32 flg = YYJSON_WRITE_ALLOW_INF_AND_NAN;
8468 if (likely(!(fmt >> (32 - YYJSON_WRITE_FP_FLAG_BITS)))) {
8469 buf = (char *)write_f64_raw((u8 *)buf, raw, flg);
8470 } else if (fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS)) {
8471 u32 prec = fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS);
8472 buf = (char *)write_f64_raw_fixed((u8 *)buf, raw, flg, prec);
8473 } else {
8474 if (fmt & YYJSON_WRITE_FP_TO_FLOAT) {
8475 buf = (char *)write_f32_raw((u8 *)buf, raw, flg);
8476 } else {
8477 buf = (char *)write_f64_raw((u8 *)buf, raw, flg);
8478 }
8479 }
8480 if (buf) *buf = '\0';
8481 return buf;
8482 }
8483 default: return NULL;
8484 }
8485}
8486
8487
8488
8489/*==============================================================================
8490 * MARK: - String Writer (Private)
8491 *============================================================================*/
8492
8493/** Character encode type, if (type > CHAR_ENC_ERR_1) bytes = type / 2; */
8494typedef u8 char_enc_type;
8495#define CHAR_ENC_CPY_1 0 /* 1-byte UTF-8, copy. */
8496#define CHAR_ENC_ERR_1 1 /* 1-byte UTF-8, error. */
8497#define CHAR_ENC_ESC_A 2 /* 1-byte ASCII, escaped as '\x'. */
8498#define CHAR_ENC_ESC_1 3 /* 1-byte UTF-8, escaped as '\uXXXX'. */
8499#define CHAR_ENC_CPY_2 4 /* 2-byte UTF-8, copy. */
8500#define CHAR_ENC_ESC_2 5 /* 2-byte UTF-8, escaped as '\uXXXX'. */
8501#define CHAR_ENC_CPY_3 6 /* 3-byte UTF-8, copy. */
8502#define CHAR_ENC_ESC_3 7 /* 3-byte UTF-8, escaped as '\uXXXX'. */
8503#define CHAR_ENC_CPY_4 8 /* 4-byte UTF-8, copy. */
8504#define CHAR_ENC_ESC_4 9 /* 4-byte UTF-8, escaped as '\uXXXX\uXXXX'. */
8505
8506/** Character encode type table: don't escape unicode, don't escape '/'.
8507 (generated with misc/make_tables.c) */
8508static const char_enc_type enc_table_cpy[256] = {
8509 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
8510 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
8511 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8512 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8513 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8514 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
8515 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8516 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8517 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8518 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8519 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8520 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8521 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
8522 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
8523 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
8524 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1
8525};
8526
8527/** Character encode type table: don't escape unicode, escape '/'.
8528 (generated with misc/make_tables.c) */
8529static const char_enc_type enc_table_cpy_slash[256] = {
8530 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
8531 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
8532 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
8533 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8534 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8535 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
8536 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8537 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8538 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8539 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8540 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8541 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8542 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
8543 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
8544 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
8545 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1
8546};
8547
8548/** Character encode type table: escape unicode, don't escape '/'.
8549 (generated with misc/make_tables.c) */
8550static const char_enc_type enc_table_esc[256] = {
8551 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
8552 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
8553 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8554 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8555 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8556 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
8557 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8558 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8559 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8560 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8561 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8562 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8563 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
8564 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
8565 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
8566 9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1
8567};
8568
8569/** Character encode type table: escape unicode, escape '/'.
8570 (generated with misc/make_tables.c) */
8571static const char_enc_type enc_table_esc_slash[256] = {
8572 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
8573 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
8574 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
8575 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8576 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8577 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
8578 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8579 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8580 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8581 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8582 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8583 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8584 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
8585 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
8586 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
8587 9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1
8588};
8589
8590/** Escaped hex character table: ["00" "01" "02" ... "FD" "FE" "FF"].
8591 (generated with misc/make_tables.c) */
8592yyjson_align(2)
8593static const u8 esc_hex_char_table[512] = {
8594 '0', '0', '0', '1', '0', '2', '0', '3',
8595 '0', '4', '0', '5', '0', '6', '0', '7',
8596 '0', '8', '0', '9', '0', 'A', '0', 'B',
8597 '0', 'C', '0', 'D', '0', 'E', '0', 'F',
8598 '1', '0', '1', '1', '1', '2', '1', '3',
8599 '1', '4', '1', '5', '1', '6', '1', '7',
8600 '1', '8', '1', '9', '1', 'A', '1', 'B',
8601 '1', 'C', '1', 'D', '1', 'E', '1', 'F',
8602 '2', '0', '2', '1', '2', '2', '2', '3',
8603 '2', '4', '2', '5', '2', '6', '2', '7',
8604 '2', '8', '2', '9', '2', 'A', '2', 'B',
8605 '2', 'C', '2', 'D', '2', 'E', '2', 'F',
8606 '3', '0', '3', '1', '3', '2', '3', '3',
8607 '3', '4', '3', '5', '3', '6', '3', '7',
8608 '3', '8', '3', '9', '3', 'A', '3', 'B',
8609 '3', 'C', '3', 'D', '3', 'E', '3', 'F',
8610 '4', '0', '4', '1', '4', '2', '4', '3',
8611 '4', '4', '4', '5', '4', '6', '4', '7',
8612 '4', '8', '4', '9', '4', 'A', '4', 'B',
8613 '4', 'C', '4', 'D', '4', 'E', '4', 'F',
8614 '5', '0', '5', '1', '5', '2', '5', '3',
8615 '5', '4', '5', '5', '5', '6', '5', '7',
8616 '5', '8', '5', '9', '5', 'A', '5', 'B',
8617 '5', 'C', '5', 'D', '5', 'E', '5', 'F',
8618 '6', '0', '6', '1', '6', '2', '6', '3',
8619 '6', '4', '6', '5', '6', '6', '6', '7',
8620 '6', '8', '6', '9', '6', 'A', '6', 'B',
8621 '6', 'C', '6', 'D', '6', 'E', '6', 'F',
8622 '7', '0', '7', '1', '7', '2', '7', '3',
8623 '7', '4', '7', '5', '7', '6', '7', '7',
8624 '7', '8', '7', '9', '7', 'A', '7', 'B',
8625 '7', 'C', '7', 'D', '7', 'E', '7', 'F',
8626 '8', '0', '8', '1', '8', '2', '8', '3',
8627 '8', '4', '8', '5', '8', '6', '8', '7',
8628 '8', '8', '8', '9', '8', 'A', '8', 'B',
8629 '8', 'C', '8', 'D', '8', 'E', '8', 'F',
8630 '9', '0', '9', '1', '9', '2', '9', '3',
8631 '9', '4', '9', '5', '9', '6', '9', '7',
8632 '9', '8', '9', '9', '9', 'A', '9', 'B',
8633 '9', 'C', '9', 'D', '9', 'E', '9', 'F',
8634 'A', '0', 'A', '1', 'A', '2', 'A', '3',
8635 'A', '4', 'A', '5', 'A', '6', 'A', '7',
8636 'A', '8', 'A', '9', 'A', 'A', 'A', 'B',
8637 'A', 'C', 'A', 'D', 'A', 'E', 'A', 'F',
8638 'B', '0', 'B', '1', 'B', '2', 'B', '3',
8639 'B', '4', 'B', '5', 'B', '6', 'B', '7',
8640 'B', '8', 'B', '9', 'B', 'A', 'B', 'B',
8641 'B', 'C', 'B', 'D', 'B', 'E', 'B', 'F',
8642 'C', '0', 'C', '1', 'C', '2', 'C', '3',
8643 'C', '4', 'C', '5', 'C', '6', 'C', '7',
8644 'C', '8', 'C', '9', 'C', 'A', 'C', 'B',
8645 'C', 'C', 'C', 'D', 'C', 'E', 'C', 'F',
8646 'D', '0', 'D', '1', 'D', '2', 'D', '3',
8647 'D', '4', 'D', '5', 'D', '6', 'D', '7',
8648 'D', '8', 'D', '9', 'D', 'A', 'D', 'B',
8649 'D', 'C', 'D', 'D', 'D', 'E', 'D', 'F',
8650 'E', '0', 'E', '1', 'E', '2', 'E', '3',
8651 'E', '4', 'E', '5', 'E', '6', 'E', '7',
8652 'E', '8', 'E', '9', 'E', 'A', 'E', 'B',
8653 'E', 'C', 'E', 'D', 'E', 'E', 'E', 'F',
8654 'F', '0', 'F', '1', 'F', '2', 'F', '3',
8655 'F', '4', 'F', '5', 'F', '6', 'F', '7',
8656 'F', '8', 'F', '9', 'F', 'A', 'F', 'B',
8657 'F', 'C', 'F', 'D', 'F', 'E', 'F', 'F'
8658};
8659
8660/** Lowercase variant of esc_hex_char_table. */
8661yyjson_align(2)
8662static const u8 esc_hex_char_table_lower[512] = {
8663 '0', '0', '0', '1', '0', '2', '0', '3',
8664 '0', '4', '0', '5', '0', '6', '0', '7',
8665 '0', '8', '0', '9', '0', 'a', '0', 'b',
8666 '0', 'c', '0', 'd', '0', 'e', '0', 'f',
8667 '1', '0', '1', '1', '1', '2', '1', '3',
8668 '1', '4', '1', '5', '1', '6', '1', '7',
8669 '1', '8', '1', '9', '1', 'a', '1', 'b',
8670 '1', 'c', '1', 'd', '1', 'e', '1', 'f',
8671 '2', '0', '2', '1', '2', '2', '2', '3',
8672 '2', '4', '2', '5', '2', '6', '2', '7',
8673 '2', '8', '2', '9', '2', 'a', '2', 'b',
8674 '2', 'c', '2', 'd', '2', 'e', '2', 'f',
8675 '3', '0', '3', '1', '3', '2', '3', '3',
8676 '3', '4', '3', '5', '3', '6', '3', '7',
8677 '3', '8', '3', '9', '3', 'a', '3', 'b',
8678 '3', 'c', '3', 'd', '3', 'e', '3', 'f',
8679 '4', '0', '4', '1', '4', '2', '4', '3',
8680 '4', '4', '4', '5', '4', '6', '4', '7',
8681 '4', '8', '4', '9', '4', 'a', '4', 'b',
8682 '4', 'c', '4', 'd', '4', 'e', '4', 'f',
8683 '5', '0', '5', '1', '5', '2', '5', '3',
8684 '5', '4', '5', '5', '5', '6', '5', '7',
8685 '5', '8', '5', '9', '5', 'a', '5', 'b',
8686 '5', 'c', '5', 'd', '5', 'e', '5', 'f',
8687 '6', '0', '6', '1', '6', '2', '6', '3',
8688 '6', '4', '6', '5', '6', '6', '6', '7',
8689 '6', '8', '6', '9', '6', 'a', '6', 'b',
8690 '6', 'c', '6', 'd', '6', 'e', '6', 'f',
8691 '7', '0', '7', '1', '7', '2', '7', '3',
8692 '7', '4', '7', '5', '7', '6', '7', '7',
8693 '7', '8', '7', '9', '7', 'a', '7', 'b',
8694 '7', 'c', '7', 'd', '7', 'e', '7', 'f',
8695 '8', '0', '8', '1', '8', '2', '8', '3',
8696 '8', '4', '8', '5', '8', '6', '8', '7',
8697 '8', '8', '8', '9', '8', 'a', '8', 'b',
8698 '8', 'c', '8', 'd', '8', 'e', '8', 'f',
8699 '9', '0', '9', '1', '9', '2', '9', '3',
8700 '9', '4', '9', '5', '9', '6', '9', '7',
8701 '9', '8', '9', '9', '9', 'a', '9', 'b',
8702 '9', 'c', '9', 'd', '9', 'e', '9', 'f',
8703 'a', '0', 'a', '1', 'a', '2', 'a', '3',
8704 'a', '4', 'a', '5', 'a', '6', 'a', '7',
8705 'a', '8', 'a', '9', 'a', 'a', 'a', 'b',
8706 'a', 'c', 'a', 'd', 'a', 'e', 'a', 'f',
8707 'b', '0', 'b', '1', 'b', '2', 'b', '3',
8708 'b', '4', 'b', '5', 'b', '6', 'b', '7',
8709 'b', '8', 'b', '9', 'b', 'a', 'b', 'b',
8710 'b', 'c', 'b', 'd', 'b', 'e', 'b', 'f',
8711 'c', '0', 'c', '1', 'c', '2', 'c', '3',
8712 'c', '4', 'c', '5', 'c', '6', 'c', '7',
8713 'c', '8', 'c', '9', 'c', 'a', 'c', 'b',
8714 'c', 'c', 'c', 'd', 'c', 'e', 'c', 'f',
8715 'd', '0', 'd', '1', 'd', '2', 'd', '3',
8716 'd', '4', 'd', '5', 'd', '6', 'd', '7',
8717 'd', '8', 'd', '9', 'd', 'a', 'd', 'b',
8718 'd', 'c', 'd', 'd', 'd', 'e', 'd', 'f',
8719 'e', '0', 'e', '1', 'e', '2', 'e', '3',
8720 'e', '4', 'e', '5', 'e', '6', 'e', '7',
8721 'e', '8', 'e', '9', 'e', 'a', 'e', 'b',
8722 'e', 'c', 'e', 'd', 'e', 'e', 'e', 'f',
8723 'f', '0', 'f', '1', 'f', '2', 'f', '3',
8724 'f', '4', 'f', '5', 'f', '6', 'f', '7',
8725 'f', '8', 'f', '9', 'f', 'a', 'f', 'b',
8726 'f', 'c', 'f', 'd', 'f', 'e', 'f', 'f'
8727};
8728
8729/** Escaped single character table. (generated with misc/make_tables.c) */
8730yyjson_align(2)
8731static const u8 esc_single_char_table[512] = {
8732 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8733 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8734 '\\', 'b', '\\', 't', '\\', 'n', ' ', ' ',
8735 '\\', 'f', '\\', 'r', ' ', ' ', ' ', ' ',
8736 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8737 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8738 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8739 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8740 ' ', ' ', ' ', ' ', '\\', '"', ' ', ' ',
8741 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8742 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8743 ' ', ' ', ' ', ' ', ' ', ' ', '\\', '/',
8744 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8745 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8746 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8747 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8748 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8749 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8750 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8751 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8752 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8753 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8754 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8755 '\\', '\\', ' ', ' ', ' ', ' ', ' ', ' ',
8756 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8757 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8758 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8759 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8760 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8761 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8762 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8763 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8764 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8765 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8766 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8767 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8768 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8769 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8770 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8771 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8772 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8773 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8774 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8775 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8776 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8777 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8778 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8779 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8780 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8781 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8782 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8783 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8784 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8785 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8786 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8787 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8788 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8789 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8790 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8791 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8792 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8793 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8794 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8795 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
8796};
8797
8798/** Returns the hex digit table to use for \uXXXX escapes. */
8799static_inline const u8 *get_hex_table_with_flag(yyjson_write_flag flg) {
8800 return has_flg(LOWERCASE_HEX)
8801 ? esc_hex_char_table_lower
8802 : esc_hex_char_table;
8803}
8804
8805/** Returns the encode table with options. */
8806static_inline const char_enc_type *get_enc_table_with_flag(
8807 yyjson_write_flag flg) {
8808 if (has_flg(ESCAPE_UNICODE)) {
8809 if (has_flg(ESCAPE_SLASHES)) {
8810 return enc_table_esc_slash;
8811 } else {
8812 return enc_table_esc;
8813 }
8814 } else {
8815 if (has_flg(ESCAPE_SLASHES)) {
8816 return enc_table_cpy_slash;
8817 } else {
8818 return enc_table_cpy;
8819 }
8820 }
8821}
8822
8823/** Write raw string. */
8824static_inline u8 *write_raw(u8 *cur, const u8 *raw, usize raw_len) {
8825 memcpy(cur, raw, raw_len);
8826 return cur + raw_len;
8827}
8828
8829/**
8830 Write string no-escape.
8831 @param cur Buffer cursor.
8832 @param str A UTF-8 string, null-terminator is not required.
8833 @param str_len Length of string in bytes.
8834 @return The buffer cursor after string.
8835 */
8836static_inline u8 *write_str_noesc(u8 *cur, const u8 *str, usize str_len) {
8837 *cur++ = '"';
8838 while (str_len >= 16) {
8839 byte_copy_16(cur, str);
8840 cur += 16;
8841 str += 16;
8842 str_len -= 16;
8843 }
8844 while (str_len >= 4) {
8845 byte_copy_4(cur, str);
8846 cur += 4;
8847 str += 4;
8848 str_len -= 4;
8849 }
8850 while (str_len) {
8851 *cur++ = *str++;
8852 str_len -= 1;
8853 }
8854 *cur++ = '"';
8855 return cur;
8856}
8857
8858/**
8859 Write UTF-8 string (requires len * 6 + 2 bytes buffer).
8860 @param cur Buffer cursor.
8861 @param esc Escape unicode.
8862 @param inv Allow invalid unicode.
8863 @param str A UTF-8 string, null-terminator is not required.
8864 @param str_len Length of string in bytes.
8865 @param enc_table Encode type table for character.
8866 @return The buffer cursor after string, or NULL on invalid unicode.
8867 */
8868static_inline u8 *write_str(u8 *cur, bool esc, bool inv,
8869 const u8 *str, usize str_len,
8870 const char_enc_type *enc_table,
8871 const u8 *hex_table) {
8872 /* The replacement character U+FFFD, used to indicate invalid character.
8873 Looked up via hex_table so that LOWERCASE_HEX produces "fffd" while
8874 the default produces "FFFD". */
8875 const v32 pre = {{ '\\', 'u', '0', '0' }};
8876
8877 const u8 *src = str;
8878 const u8 *end = str + str_len;
8879 *cur++ = '"';
8880
8881copy_ascii:
8882 /*
8883 Copy continuous ASCII, loop unrolling, same as the following code:
8884
8885 while (end > src) (
8886 if (unlikely(enc_table[*src])) break;
8887 *cur++ = *src++;
8888 );
8889 */
8890#define expr_jump(i) \
8891 if (unlikely(enc_table[src[i]])) goto stop_char_##i;
8892
8893#define expr_stop(i) \
8894 stop_char_##i: \
8895 memcpy(cur, src, i); \
8896 cur += i; src += i; goto copy_utf8;
8897
8898 while (end - src >= 16) {
8899 repeat16_incr(expr_jump)
8900 byte_copy_16(cur, src);
8901 cur += 16; src += 16;
8902 }
8903
8904 while (end - src >= 4) {
8905 repeat4_incr(expr_jump)
8906 byte_copy_4(cur, src);
8907 cur += 4; src += 4;
8908 }
8909
8910 while (end > src) {
8911 expr_jump(0)
8912 *cur++ = *src++;
8913 }
8914
8915 *cur++ = '"';
8916 return cur;
8917
8918 repeat16_incr(expr_stop)
8919
8920#undef expr_jump
8921#undef expr_stop
8922
8923copy_utf8:
8924 if (unlikely(src + 4 > end)) {
8925 if (end == src) goto copy_end;
8926 if (end - src < enc_table[*src] / 2) goto err_one;
8927 }
8928 switch (enc_table[*src]) {
8929 case CHAR_ENC_CPY_1: {
8930 *cur++ = *src++;
8931 goto copy_ascii;
8932 }
8933 case CHAR_ENC_CPY_2: {
8934#if YYJSON_DISABLE_UTF8_VALIDATION
8935 byte_copy_2(cur, src);
8936#else
8937 u32 uni = 0;
8938 byte_copy_2(&uni, src);
8939 if (unlikely(!is_utf8_seq2(uni))) goto err_cpy;
8940 byte_copy_2(cur, &uni);
8941#endif
8942 cur += 2;
8943 src += 2;
8944 goto copy_utf8;
8945 }
8946 case CHAR_ENC_CPY_3: {
8947#if YYJSON_DISABLE_UTF8_VALIDATION
8948 if (likely(src + 4 <= end)) {
8949 byte_copy_4(cur, src);
8950 } else {
8951 byte_copy_2(cur, src);
8952 cur[2] = src[2];
8953 }
8954#else
8955 u32 uni, tmp;
8956 if (likely(src + 4 <= end)) {
8957 uni = byte_load_4(src);
8958 if (unlikely(!is_utf8_seq3(uni))) goto err_cpy;
8959 byte_copy_4(cur, src);
8960 } else {
8961 uni = byte_load_3(src);
8962 if (unlikely(!is_utf8_seq3(uni))) goto err_cpy;
8963 byte_copy_4(cur, &uni);
8964 }
8965#endif
8966 cur += 3;
8967 src += 3;
8968 goto copy_utf8;
8969 }
8970 case CHAR_ENC_CPY_4: {
8971#if YYJSON_DISABLE_UTF8_VALIDATION
8972 byte_copy_4(cur, src);
8973#else
8974 u32 uni, tmp;
8975 uni = byte_load_4(src);
8976 if (unlikely(!is_utf8_seq4(uni))) goto err_cpy;
8977 byte_copy_4(cur, src);
8978#endif
8979 cur += 4;
8980 src += 4;
8981 goto copy_utf8;
8982 }
8983 case CHAR_ENC_ESC_A: {
8984 byte_copy_2(cur, &esc_single_char_table[*src * 2]);
8985 cur += 2;
8986 src += 1;
8987 goto copy_utf8;
8988 }
8989 case CHAR_ENC_ESC_1: {
8990 byte_copy_4(cur + 0, &pre);
8991 byte_copy_2(cur + 4, &hex_table[*src * 2]);
8992 cur += 6;
8993 src += 1;
8994 goto copy_utf8;
8995 }
8996 case CHAR_ENC_ESC_2: {
8997 u16 u;
8998#if !YYJSON_DISABLE_UTF8_VALIDATION
8999 u32 v4 = 0;
9000 u16 v2 = byte_load_2(src);
9001 byte_copy_2(&v4, &v2);
9002 if (unlikely(!is_utf8_seq2(v4))) goto err_esc;
9003#endif
9004 u = (u16)(((u16)(src[0] & 0x1F) << 6) |
9005 ((u16)(src[1] & 0x3F) << 0));
9006 byte_copy_2(cur + 0, &pre);
9007 byte_copy_2(cur + 2, &hex_table[(u >> 8) * 2]);
9008 byte_copy_2(cur + 4, &hex_table[(u & 0xFF) * 2]);
9009 cur += 6;
9010 src += 2;
9011 goto copy_utf8;
9012 }
9013 case CHAR_ENC_ESC_3: {
9014 u16 u;
9015 u32 v, tmp;
9016#if !YYJSON_DISABLE_UTF8_VALIDATION
9017 v = byte_load_3(src);
9018 if (unlikely(!is_utf8_seq3(v))) goto err_esc;
9019#endif
9020 u = (u16)(((u16)(src[0] & 0x0F) << 12) |
9021 ((u16)(src[1] & 0x3F) << 6) |
9022 ((u16)(src[2] & 0x3F) << 0));
9023 byte_copy_2(cur + 0, &pre);
9024 byte_copy_2(cur + 2, &hex_table[(u >> 8) * 2]);
9025 byte_copy_2(cur + 4, &hex_table[(u & 0xFF) * 2]);
9026 cur += 6;
9027 src += 3;
9028 goto copy_utf8;
9029 }
9030 case CHAR_ENC_ESC_4: {
9031 u32 hi, lo, u, v, tmp;
9032#if !YYJSON_DISABLE_UTF8_VALIDATION
9033 v = byte_load_4(src);
9034 if (unlikely(!is_utf8_seq4(v))) goto err_esc;
9035#endif
9036 u = ((u32)(src[0] & 0x07) << 18) |
9037 ((u32)(src[1] & 0x3F) << 12) |
9038 ((u32)(src[2] & 0x3F) << 6) |
9039 ((u32)(src[3] & 0x3F) << 0);
9040 u -= 0x10000;
9041 hi = (u >> 10) + 0xD800;
9042 lo = (u & 0x3FF) + 0xDC00;
9043 byte_copy_2(cur + 0, &pre);
9044 byte_copy_2(cur + 2, &hex_table[(hi >> 8) * 2]);
9045 byte_copy_2(cur + 4, &hex_table[(hi & 0xFF) * 2]);
9046 byte_copy_2(cur + 6, &pre);
9047 byte_copy_2(cur + 8, &hex_table[(lo >> 8) * 2]);
9048 byte_copy_2(cur + 10, &hex_table[(lo & 0xFF) * 2]);
9049 cur += 12;
9050 src += 4;
9051 goto copy_utf8;
9052 }
9053 case CHAR_ENC_ERR_1: {
9054 goto err_one;
9055 }
9056 default: break; /* unreachable */
9057 }
9058
9059copy_end:
9060 *cur++ = '"';
9061 return cur;
9062
9063err_one:
9064 if (esc) goto err_esc;
9065 else goto err_cpy;
9066
9067err_cpy:
9068 if (!inv) return NULL;
9069 *cur++ = *src++;
9070 goto copy_utf8;
9071
9072err_esc:
9073 if (!inv) return NULL;
9074 byte_copy_2(cur + 0, &pre);
9075 /* U+FFFD = 0xFFFD, written as two pairs from hex_table so that
9076 LOWERCASE_HEX produces "fffd". Replaces a single byte_copy_4
9077 from a hardcoded uppercase "FFFD" v32; same total output, one
9078 extra load on the (rare) invalid-UTF-8-with-ALLOW path. */
9079 byte_copy_2(cur + 2, &hex_table[0xFF * 2]);
9080 byte_copy_2(cur + 4, &hex_table[0xFD * 2]);
9081 cur += 6;
9082 src += 1;
9083 goto copy_utf8;
9084}
9085
9086
9087
9088/*==============================================================================
9089 * MARK: - JSON Writer Utilities (Private)
9090 *============================================================================*/
9091
9092/** Write null (requires 8 bytes buffer). */
9093static_inline u8 *write_null(u8 *cur) {
9094 v64 v = {{ 'n', 'u', 'l', 'l', ',', '\n', 0, 0 }};
9095 byte_copy_8(cur, &v);
9096 return cur + 4;
9097}
9098
9099/** Write bool (requires 8 bytes buffer). */
9100static_inline u8 *write_bool(u8 *cur, bool val) {
9101 v64 v0 = {{ 'f', 'a', 'l', 's', 'e', ',', '\n', 0 }};
9102 v64 v1 = {{ 't', 'r', 'u', 'e', ',', '\n', 0, 0 }};
9103 if (val) {
9104 byte_copy_8(cur, &v1);
9105 } else {
9106 byte_copy_8(cur, &v0);
9107 }
9108 return cur + 5 - val;
9109}
9110
9111/** Write indent (requires level x 4 bytes buffer).
9112 Param spaces should not larger than 4. */
9113static_inline u8 *write_indent(u8 *cur, usize level, usize spaces) {
9114 while (level-- > 0) {
9115 byte_copy_4(cur, " ");
9116 cur += spaces;
9117 }
9118 return cur;
9119}
9120
9121#if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE
9122
9123/** Write data to file pointer. */
9124static bool write_dat_to_fp(FILE *fp, u8 *dat, usize len,
9125 yyjson_write_err *err) {
9126 if (fwrite(dat, 1, len, fp) != len) {
9127 err->msg = "file writing failed";
9128 err->code = YYJSON_WRITE_ERROR_FILE_WRITE;
9129 return false;
9130 }
9131 return true;
9132}
9133
9134/** Write data to file. */
9135static bool write_dat_to_file(const char *path, u8 *dat, usize len,
9136 yyjson_write_err *err) {
9137#define return_err(_code, _msg) do { \
9138 err->msg = _msg; \
9139 err->code = YYJSON_WRITE_ERROR_##_code; \
9140 if (file) fclose(file); \
9141 return false; \
9142} while (false)
9143
9144 FILE *file = fopen_writeonly(path);
9145 if (file == NULL) {
9146 return_err(FILE_OPEN, MSG_FOPEN);
9147 }
9148 if (fwrite(dat, 1, len, file) != len) {
9149 return_err(FILE_WRITE, MSG_FWRITE);
9150 }
9151 if (fclose(file) != 0) {
9152 file = NULL;
9153 return_err(FILE_WRITE, MSG_FCLOSE);
9154 }
9155 return true;
9156
9157#undef return_err
9158}
9159
9160#endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */
9161
9162
9163
9164/*==============================================================================
9165 * MARK: - JSON Writer Implementation (Private)
9166 *============================================================================*/
9167
9168typedef struct yyjson_write_ctx {
9169 usize tag;
9170} yyjson_write_ctx;
9171
9172static_inline void yyjson_write_ctx_set(yyjson_write_ctx *ctx,
9173 usize size, bool is_obj) {
9174 ctx->tag = (size << 1) | (usize)is_obj;
9175}
9176
9177static_inline void yyjson_write_ctx_get(yyjson_write_ctx *ctx,
9178 usize *size, bool *is_obj) {
9179 usize tag = ctx->tag;
9180 *size = tag >> 1;
9181 *is_obj = (bool)(tag & 1);
9182}
9183
9184/** Write single JSON value. */
9185static_inline u8 *write_root_single(yyjson_val *val,
9186 yyjson_write_flag flg,
9187 yyjson_alc alc,
9188 char *buf, usize *dat_len,
9189 yyjson_write_err *err) {
9190#define return_err(_code, _msg) do { \
9191 if (hdr) alc.free(alc.ctx, (void *)hdr); \
9192 *dat_len = 0; \
9193 err->code = YYJSON_WRITE_ERROR_##_code; \
9194 err->msg = _msg; \
9195 return NULL; \
9196} while (false)
9197
9198#define incr_len(_len) do { \
9199 if (buf) hdr = *dat_len >= _len ? (u8 *)buf : (u8 *)NULL; \
9200 else hdr = (u8 *)alc.malloc(alc.ctx, _len); \
9201 if (!hdr) goto fail_alloc; \
9202 cur = hdr; \
9203} while (false)
9204
9205#define check_str_len(_len) do { \
9206 if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
9207 goto fail_alloc; \
9208} while (false)
9209
9210 u8 *hdr = NULL, *cur;
9211 usize str_len;
9212 const u8 *str_ptr;
9213 const char_enc_type *enc_table = get_enc_table_with_flag(flg);
9214 const u8 *hex_table = get_hex_table_with_flag(flg);
9215 bool cpy = (enc_table == enc_table_cpy);
9216 bool esc = has_flg(ESCAPE_UNICODE) != 0;
9217 bool inv = has_allow(INVALID_UNICODE) != 0;
9218 bool newline = has_flg(NEWLINE_AT_END) != 0;
9219 const usize end_len = 2; /* '\n' and '\0' */
9220
9221 switch (unsafe_yyjson_get_type(val)) {
9222 case YYJSON_TYPE_RAW:
9223 str_len = unsafe_yyjson_get_len(val);
9224 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9225 check_str_len(str_len);
9226 incr_len(str_len + end_len);
9227 cur = write_raw(cur, str_ptr, str_len);
9228 break;
9229
9230 case YYJSON_TYPE_STR:
9231 str_len = unsafe_yyjson_get_len(val);
9232 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9233 check_str_len(str_len);
9234 incr_len(str_len * 6 + 2 + end_len);
9235 if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
9236 cur = write_str_noesc(cur, str_ptr, str_len);
9237 } else {
9238 cur = write_str(cur, esc, inv, str_ptr, str_len,
9239 enc_table, hex_table);
9240 if (unlikely(!cur)) goto fail_str;
9241 }
9242 break;
9243
9244 case YYJSON_TYPE_NUM:
9245 incr_len(FP_BUF_LEN + end_len);
9246 cur = write_num(cur, val, flg);
9247 if (unlikely(!cur)) goto fail_num;
9248 break;
9249
9250 case YYJSON_TYPE_BOOL:
9251 incr_len(8);
9252 cur = write_bool(cur, unsafe_yyjson_get_bool(val));
9253 break;
9254
9255 case YYJSON_TYPE_NULL:
9256 incr_len(8);
9257 cur = write_null(cur);
9258 break;
9259
9260 case YYJSON_TYPE_ARR:
9261 incr_len(2 + end_len);
9262 byte_copy_2(cur, "[]");
9263 cur += 2;
9264 break;
9265
9266 case YYJSON_TYPE_OBJ:
9267 incr_len(2 + end_len);
9268 byte_copy_2(cur, "{}");
9269 cur += 2;
9270 break;
9271
9272 default:
9273 goto fail_type;
9274 }
9275
9276 if (newline) *cur++ = '\n';
9277 *cur = '\0';
9278 *dat_len = (usize)(cur - hdr);
9279 memset(err, 0, sizeof(yyjson_write_err));
9280 return hdr;
9281
9282fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
9283fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
9284fail_num: return_err(NAN_OR_INF, MSG_NAN_INF);
9285fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8);
9286
9287#undef return_err
9288#undef check_str_len
9289#undef incr_len
9290}
9291
9292/** Write JSON document minify.
9293 The root of this document should be a non-empty container. */
9294static_inline u8 *write_root_minify(const yyjson_val *root,
9295 const yyjson_write_flag flg,
9296 const yyjson_alc alc,
9297 char *buf, usize *dat_len,
9298 yyjson_write_err *err) {
9299#define return_err(_code, _msg) do { \
9300 *dat_len = 0; \
9301 err->code = YYJSON_WRITE_ERROR_##_code; \
9302 err->msg = _msg; \
9303 if (hdr) alc.free(alc.ctx, hdr); \
9304 return NULL; \
9305} while (false)
9306
9307#define incr_len(_len) do { \
9308 ext_len = (usize)(_len); \
9309 if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
9310 usize ctx_pos = (usize)((u8 *)ctx - hdr); \
9311 usize cur_pos = (usize)(cur - hdr); \
9312 yyjson_assume((u8 *)ctx <= (u8 *)end); \
9313 ctx_len = (usize)((u8 *)end - (u8 *)ctx); \
9314 alc_inc = yyjson_max(alc_len / 2, ext_len); \
9315 alc_inc = size_align_up(alc_inc, sizeof(yyjson_write_ctx)); \
9316 if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
9317 goto fail_alloc; \
9318 alc_len += alc_inc; \
9319 tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
9320 if (unlikely(!tmp)) goto fail_alloc; \
9321 ctx_tmp = (yyjson_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
9322 memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
9323 ctx = ctx_tmp; \
9324 cur = tmp + cur_pos; \
9325 end = tmp + alc_len; \
9326 hdr = tmp; \
9327 } \
9328} while (false)
9329
9330#define check_str_len(_len) do { \
9331 if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
9332 goto fail_alloc; \
9333} while (false)
9334
9335 yyjson_val *val;
9336 yyjson_type val_type;
9337 usize ctn_len, ctn_len_tmp;
9338 bool ctn_obj, ctn_obj_tmp, is_key;
9339 u8 *hdr, *cur, *end, *tmp;
9340 yyjson_write_ctx *ctx, *ctx_tmp;
9341 usize alc_len, alc_inc, ctx_len, ext_len, str_len;
9342#if YYJSON_WRITER_DEPTH_LIMIT
9343 usize ctn_depth = 0;
9344#endif
9345 const u8 *str_ptr;
9346 const char_enc_type *enc_table = get_enc_table_with_flag(flg);
9347 const u8 *hex_table = get_hex_table_with_flag(flg);
9348 bool cpy = (enc_table == enc_table_cpy);
9349 bool esc = has_flg(ESCAPE_UNICODE) != 0;
9350 bool inv = has_allow(INVALID_UNICODE) != 0;
9351 bool newline = has_flg(NEWLINE_AT_END) != 0;
9352
9353 if (buf) {
9354 hdr = (u8 *)buf;
9355 alc_len = *dat_len;
9356 alc_len = size_align_down(alc_len, sizeof(yyjson_write_ctx));
9357 if (alc_len <= sizeof(yyjson_write_ctx)) goto fail_alloc;
9358 } else {
9359 alc_len = root->uni.ofs / sizeof(yyjson_val);
9360 alc_len = alc_len * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64;
9361 alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx));
9362 hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
9363 if (!hdr) goto fail_alloc;
9364 }
9365 cur = hdr;
9366 end = hdr + alc_len;
9367 ctx = (yyjson_write_ctx *)(void *)end;
9368
9369doc_begin:
9370 val = constcast(yyjson_val *)root;
9371 val_type = unsafe_yyjson_get_type(val);
9372 ctn_obj = (val_type == YYJSON_TYPE_OBJ);
9373 ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
9374 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9375 val++;
9376
9377val_begin:
9378 val_type = unsafe_yyjson_get_type(val);
9379 if (val_type == YYJSON_TYPE_STR) {
9380 is_key = ((u8)ctn_obj & (u8)~ctn_len);
9381 str_len = unsafe_yyjson_get_len(val);
9382 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9383 check_str_len(str_len);
9384 incr_len(str_len * 6 + 16);
9385 if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
9386 cur = write_str_noesc(cur, str_ptr, str_len);
9387 } else {
9388 cur = write_str(cur, esc, inv, str_ptr, str_len,
9389 enc_table, hex_table);
9390 if (unlikely(!cur)) goto fail_str;
9391 }
9392 *cur++ = is_key ? ':' : ',';
9393 goto val_end;
9394 }
9395 if (val_type == YYJSON_TYPE_NUM) {
9396 incr_len(FP_BUF_LEN);
9397 cur = write_num(cur, val, flg);
9398 if (unlikely(!cur)) goto fail_num;
9399 *cur++ = ',';
9400 goto val_end;
9401 }
9402 if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
9403 (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
9404 ctn_len_tmp = unsafe_yyjson_get_len(val);
9405 ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
9406 incr_len(2 * sizeof(*ctx));
9407#if YYJSON_WRITER_DEPTH_LIMIT
9408 ctn_depth++;
9409 if (unlikely(ctn_depth >= (usize)YYJSON_WRITER_DEPTH_LIMIT)) {
9410 goto fail_depth;
9411 }
9412#endif
9413 if (unlikely(ctn_len_tmp == 0)) {
9414#if YYJSON_WRITER_DEPTH_LIMIT
9415 ctn_depth--;
9416#endif
9417 /* write empty container */
9418 *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
9419 *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
9420 *cur++ = ',';
9421 goto val_end;
9422 } else {
9423 /* push context, setup new container */
9424 yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj);
9425 ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
9426 ctn_obj = ctn_obj_tmp;
9427 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9428 val++;
9429 goto val_begin;
9430 }
9431 }
9432 if (val_type == YYJSON_TYPE_BOOL) {
9433 incr_len(16);
9434 cur = write_bool(cur, unsafe_yyjson_get_bool(val));
9435 cur++;
9436 goto val_end;
9437 }
9438 if (val_type == YYJSON_TYPE_NULL) {
9439 incr_len(16);
9440 cur = write_null(cur);
9441 cur++;
9442 goto val_end;
9443 }
9444 if (val_type == YYJSON_TYPE_RAW) {
9445 str_len = unsafe_yyjson_get_len(val);
9446 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9447 check_str_len(str_len);
9448 incr_len(str_len + 2);
9449 cur = write_raw(cur, str_ptr, str_len);
9450 *cur++ = ',';
9451 goto val_end;
9452 }
9453 goto fail_type;
9454
9455val_end:
9456 val++;
9457 ctn_len--;
9458 if (unlikely(ctn_len == 0)) goto ctn_end;
9459 goto val_begin;
9460
9461ctn_end:
9462#if YYJSON_WRITER_DEPTH_LIMIT
9463 ctn_depth--;
9464#endif
9465 cur--;
9466 *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
9467 *cur++ = ',';
9468 if (unlikely((u8 *)ctx >= end)) goto doc_end;
9469 yyjson_write_ctx_get(ctx++, &ctn_len, &ctn_obj);
9470 ctn_len--;
9471 if (likely(ctn_len > 0)) {
9472 goto val_begin;
9473 } else {
9474 goto ctn_end;
9475 }
9476
9477doc_end:
9478 if (newline) {
9479 incr_len(2);
9480 *(cur - 1) = '\n';
9481 cur++;
9482 }
9483 *--cur = '\0';
9484 *dat_len = (usize)(cur - hdr);
9485 memset(err, 0, sizeof(yyjson_write_err));
9486 return hdr;
9487
9488fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
9489fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
9490fail_num: return_err(NAN_OR_INF, MSG_NAN_INF);
9491fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8);
9492#if YYJSON_WRITER_DEPTH_LIMIT
9493fail_depth: return_err(DEPTH, MSG_DEPTH);
9494#endif
9495
9496#undef return_err
9497#undef incr_len
9498#undef check_str_len
9499}
9500
9501/** Write JSON document pretty.
9502 The root of this document should be a non-empty container. */
9503static_inline u8 *write_root_pretty(const yyjson_val *root,
9504 const yyjson_write_flag flg,
9505 const yyjson_alc alc,
9506 char *buf, usize *dat_len,
9507 yyjson_write_err *err) {
9508#define return_err(_code, _msg) do { \
9509 *dat_len = 0; \
9510 err->code = YYJSON_WRITE_ERROR_##_code; \
9511 err->msg = _msg; \
9512 if (hdr) alc.free(alc.ctx, hdr); \
9513 return NULL; \
9514} while (false)
9515
9516#define incr_len(_len) do { \
9517 ext_len = (usize)(_len); \
9518 if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
9519 usize ctx_pos = (usize)((u8 *)ctx - hdr); \
9520 usize cur_pos = (usize)(cur - hdr); \
9521 yyjson_assume((u8 *)ctx <= (u8 *)end); \
9522 ctx_len = (usize)((u8 *)end - (u8 *)ctx); \
9523 alc_inc = yyjson_max(alc_len / 2, ext_len); \
9524 alc_inc = size_align_up(alc_inc, sizeof(yyjson_write_ctx)); \
9525 if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
9526 goto fail_alloc; \
9527 alc_len += alc_inc; \
9528 tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
9529 if (unlikely(!tmp)) goto fail_alloc; \
9530 ctx_tmp = (yyjson_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
9531 memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
9532 ctx = ctx_tmp; \
9533 cur = tmp + cur_pos; \
9534 end = tmp + alc_len; \
9535 hdr = tmp; \
9536 } \
9537} while (false)
9538
9539#define check_str_len(_len) do { \
9540 if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
9541 goto fail_alloc; \
9542} while (false)
9543
9544 yyjson_val *val;
9545 yyjson_type val_type;
9546 usize ctn_len, ctn_len_tmp;
9547 bool ctn_obj, ctn_obj_tmp, is_key, no_indent;
9548 u8 *hdr, *cur, *end, *tmp;
9549 yyjson_write_ctx *ctx, *ctx_tmp;
9550 usize alc_len, alc_inc, ctx_len, ext_len, str_len, level;
9551#if YYJSON_WRITER_DEPTH_LIMIT
9552 usize ctn_depth = 0;
9553#endif
9554 const u8 *str_ptr;
9555 const char_enc_type *enc_table = get_enc_table_with_flag(flg);
9556 const u8 *hex_table = get_hex_table_with_flag(flg);
9557 bool cpy = (enc_table == enc_table_cpy);
9558 bool esc = has_flg(ESCAPE_UNICODE) != 0;
9559 bool inv = has_allow(INVALID_UNICODE) != 0;
9560 usize spaces = has_flg(PRETTY_TWO_SPACES) ? 2 : 4;
9561 bool newline = has_flg(NEWLINE_AT_END) != 0;
9562
9563 if (buf) {
9564 hdr = (u8 *)buf;
9565 alc_len = *dat_len;
9566 alc_len = size_align_down(alc_len, sizeof(yyjson_write_ctx));
9567 if (alc_len <= sizeof(yyjson_write_ctx)) goto fail_alloc;
9568 } else {
9569 alc_len = root->uni.ofs / sizeof(yyjson_val);
9570 alc_len = alc_len * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64;
9571 alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx));
9572 hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
9573 if (!hdr) goto fail_alloc;
9574 }
9575 cur = hdr;
9576 end = hdr + alc_len;
9577 ctx = (yyjson_write_ctx *)(void *)end;
9578
9579doc_begin:
9580 val = constcast(yyjson_val *)root;
9581 val_type = unsafe_yyjson_get_type(val);
9582 ctn_obj = (val_type == YYJSON_TYPE_OBJ);
9583 ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
9584 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9585 *cur++ = '\n';
9586 val++;
9587 level = 1;
9588
9589val_begin:
9590 val_type = unsafe_yyjson_get_type(val);
9591 if (val_type == YYJSON_TYPE_STR) {
9592 is_key = (bool)((u8)ctn_obj & (u8)~ctn_len);
9593 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9594 str_len = unsafe_yyjson_get_len(val);
9595 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9596 check_str_len(str_len);
9597 if ((sizeof(usize) < 8) && !no_indent &&
9598 level > (USIZE_MAX - 16 - str_len * 6) / 4) goto fail_alloc;
9599 incr_len(str_len * 6 + 16 + (no_indent ? 0 : level * 4));
9600 cur = write_indent(cur, no_indent ? 0 : level, spaces);
9601 if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
9602 cur = write_str_noesc(cur, str_ptr, str_len);
9603 } else {
9604 cur = write_str(cur, esc, inv, str_ptr, str_len,
9605 enc_table, hex_table);
9606 if (unlikely(!cur)) goto fail_str;
9607 }
9608 *cur++ = is_key ? ':' : ',';
9609 *cur++ = is_key ? ' ' : '\n';
9610 goto val_end;
9611 }
9612 if (val_type == YYJSON_TYPE_NUM) {
9613 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9614 incr_len(FP_BUF_LEN + (no_indent ? 0 : level * 4));
9615 cur = write_indent(cur, no_indent ? 0 : level, spaces);
9616 cur = write_num(cur, val, flg);
9617 if (unlikely(!cur)) goto fail_num;
9618 *cur++ = ',';
9619 *cur++ = '\n';
9620 goto val_end;
9621 }
9622 if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
9623 (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
9624 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9625 ctn_len_tmp = unsafe_yyjson_get_len(val);
9626 ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
9627 incr_len(2 * sizeof(*ctx) + (no_indent ? 0 : level * 4));
9628#if YYJSON_WRITER_DEPTH_LIMIT
9629 ctn_depth++;
9630 if (unlikely(ctn_depth >= (usize)YYJSON_WRITER_DEPTH_LIMIT)) {
9631 goto fail_depth;
9632 }
9633#endif
9634 if (unlikely(ctn_len_tmp == 0)) {
9635#if YYJSON_WRITER_DEPTH_LIMIT
9636 ctn_depth--;
9637#endif
9638 /* write empty container */
9639 cur = write_indent(cur, no_indent ? 0 : level, spaces);
9640 *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
9641 *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
9642 *cur++ = ',';
9643 *cur++ = '\n';
9644 goto val_end;
9645 } else {
9646 /* push context, setup new container */
9647 yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj);
9648 ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
9649 ctn_obj = ctn_obj_tmp;
9650 cur = write_indent(cur, no_indent ? 0 : level, spaces);
9651 level++;
9652 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9653 *cur++ = '\n';
9654 val++;
9655 goto val_begin;
9656 }
9657 }
9658 if (val_type == YYJSON_TYPE_BOOL) {
9659 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9660 incr_len(16 + (no_indent ? 0 : level * 4));
9661 cur = write_indent(cur, no_indent ? 0 : level, spaces);
9662 cur = write_bool(cur, unsafe_yyjson_get_bool(val));
9663 cur += 2;
9664 goto val_end;
9665 }
9666 if (val_type == YYJSON_TYPE_NULL) {
9667 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9668 incr_len(16 + (no_indent ? 0 : level * 4));
9669 cur = write_indent(cur, no_indent ? 0 : level, spaces);
9670 cur = write_null(cur);
9671 cur += 2;
9672 goto val_end;
9673 }
9674 if (val_type == YYJSON_TYPE_RAW) {
9675 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9676 str_len = unsafe_yyjson_get_len(val);
9677 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9678 check_str_len(str_len);
9679 incr_len(str_len + 3 + (no_indent ? 0 : level * 4));
9680 cur = write_indent(cur, no_indent ? 0 : level, spaces);
9681 cur = write_raw(cur, str_ptr, str_len);
9682 *cur++ = ',';
9683 *cur++ = '\n';
9684 goto val_end;
9685 }
9686 goto fail_type;
9687
9688val_end:
9689 val++;
9690 ctn_len--;
9691 if (unlikely(ctn_len == 0)) goto ctn_end;
9692 goto val_begin;
9693
9694ctn_end:
9695#if YYJSON_WRITER_DEPTH_LIMIT
9696 ctn_depth--;
9697#endif
9698 cur -= 2;
9699 *cur++ = '\n';
9700 incr_len(level * 4);
9701 cur = write_indent(cur, --level, spaces);
9702 *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
9703 if (unlikely((u8 *)ctx >= end)) goto doc_end;
9704 yyjson_write_ctx_get(ctx++, &ctn_len, &ctn_obj);
9705 ctn_len--;
9706 *cur++ = ',';
9707 *cur++ = '\n';
9708 if (likely(ctn_len > 0)) {
9709 goto val_begin;
9710 } else {
9711 goto ctn_end;
9712 }
9713
9714doc_end:
9715 if (newline) {
9716 incr_len(2);
9717 *cur++ = '\n';
9718 }
9719 *cur = '\0';
9720 *dat_len = (usize)(cur - hdr);
9721 memset(err, 0, sizeof(yyjson_write_err));
9722 return hdr;
9723
9724fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
9725fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
9726fail_num: return_err(NAN_OR_INF, MSG_NAN_INF);
9727fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8);
9728#if YYJSON_WRITER_DEPTH_LIMIT
9729fail_depth: return_err(DEPTH, MSG_DEPTH);
9730#endif
9731
9732#undef return_err
9733#undef incr_len
9734#undef check_str_len
9735}
9736
9737static char *write_root(const yyjson_val *val,
9738 yyjson_write_flag flg,
9739 const yyjson_alc *alc_ptr,
9740 char *buf, usize *dat_len,
9741 yyjson_write_err *err) {
9742 yyjson_write_err tmp_err;
9743 usize tmp_dat_len;
9744 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
9745 yyjson_val *root = constcast(yyjson_val *)val;
9746
9747 if (!err) err = &tmp_err;
9748 if (!dat_len) dat_len = &tmp_dat_len;
9749
9750 if (unlikely(!root)) {
9751 *dat_len = 0;
9752 err->msg = "input JSON is NULL";
9753 err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
9754 return NULL;
9755 }
9756
9757 if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) {
9758 return (char *)write_root_single(root, flg, alc, buf, dat_len, err);
9759 } else if (flg & (YYJSON_WRITE_PRETTY | YYJSON_WRITE_PRETTY_TWO_SPACES)) {
9760 return (char *)write_root_pretty(root, flg, alc, buf, dat_len, err);
9761 } else {
9762 return (char *)write_root_minify(root, flg, alc, buf, dat_len, err);
9763 }
9764}
9765
9766
9767
9768/*==============================================================================
9769 * MARK: - JSON Writer (Public)
9770 *============================================================================*/
9771
9772char *yyjson_val_write_opts(const yyjson_val *val,
9773 yyjson_write_flag flg,
9774 const yyjson_alc *alc_ptr,
9775 usize *dat_len,
9776 yyjson_write_err *err) {
9777 return write_root(val, flg, alc_ptr, NULL, dat_len, err);
9778}
9779
9780char *yyjson_write_opts(const yyjson_doc *doc,
9781 yyjson_write_flag flg,
9782 const yyjson_alc *alc_ptr,
9783 usize *dat_len,
9784 yyjson_write_err *err) {
9785 yyjson_val *root = doc ? doc->root : NULL;
9786 return write_root(root, flg, alc_ptr, NULL, dat_len, err);
9787}
9788
9789#if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE
9790
9791bool yyjson_val_write_file(const char *path,
9792 const yyjson_val *val,
9793 yyjson_write_flag flg,
9794 const yyjson_alc *alc_ptr,
9795 yyjson_write_err *err) {
9796 yyjson_write_err tmp_err;
9797 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
9798 u8 *dat;
9799 usize dat_len = 0;
9800 yyjson_val *root = constcast(yyjson_val *)val;
9801 bool suc;
9802
9803 if (!err) err = &tmp_err;
9804 if (unlikely(!path || !*path)) {
9805 err->msg = "input path is invalid";
9806 err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
9807 return false;
9808 }
9809
9810 dat = (u8 *)write_root(root, flg, &alc, NULL, &dat_len, err);
9811 if (unlikely(!dat)) return false;
9812 suc = write_dat_to_file(path, dat, dat_len, err);
9813 alc.free(alc.ctx, dat);
9814 return suc;
9815}
9816
9817bool yyjson_val_write_fp(FILE *fp,
9818 const yyjson_val *val,
9819 yyjson_write_flag flg,
9820 const yyjson_alc *alc_ptr,
9821 yyjson_write_err *err) {
9822 yyjson_write_err tmp_err;
9823 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
9824 u8 *dat;
9825 usize dat_len = 0;
9826 yyjson_val *root = constcast(yyjson_val *)val;
9827 bool suc;
9828
9829 if (!err) err = &tmp_err;
9830 if (unlikely(!fp)) {
9831 err->msg = "input fp is invalid";
9832 err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
9833 return false;
9834 }
9835
9836 dat = (u8 *)write_root(root, flg, &alc, NULL, &dat_len, err);
9837 if (unlikely(!dat)) return false;
9838 suc = write_dat_to_fp(fp, dat, dat_len, err);
9839 alc.free(alc.ctx, dat);
9840 return suc;
9841}
9842
9843bool yyjson_write_file(const char *path,
9844 const yyjson_doc *doc,
9845 yyjson_write_flag flg,
9846 const yyjson_alc *alc_ptr,
9847 yyjson_write_err *err) {
9848 yyjson_val *root = doc ? doc->root : NULL;
9849 return yyjson_val_write_file(path, root, flg, alc_ptr, err);
9850}
9851
9852bool yyjson_write_fp(FILE *fp,
9853 const yyjson_doc *doc,
9854 yyjson_write_flag flg,
9855 const yyjson_alc *alc_ptr,
9856 yyjson_write_err *err) {
9857 yyjson_val *root = doc ? doc->root : NULL;
9858 return yyjson_val_write_fp(fp, root, flg, alc_ptr, err);
9859}
9860
9861#endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */
9862
9863size_t yyjson_val_write_buf(char *buf, size_t buf_len,
9864 const yyjson_val *val,
9865 yyjson_write_flag flg,
9866 yyjson_write_err *err) {
9867 if (unlikely(!buf || !buf_len)) {
9868 if (err) err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
9869 if (err) err->msg = "input buf or buf_len is invalid";
9870 return 0;
9871 } else {
9872 write_root(val, flg, &YYJSON_NULL_ALC, buf, &buf_len, err);
9873 return buf_len;
9874 }
9875}
9876
9877size_t yyjson_write_buf(char *buf, size_t buf_len,
9878 const yyjson_doc *doc,
9879 yyjson_write_flag flg,
9880 yyjson_write_err *err) {
9881 yyjson_val *root = doc ? doc->root : NULL;
9882 return yyjson_val_write_buf(buf, buf_len, root, flg, err);
9883}
9884
9885
9886
9887/*==============================================================================
9888 * MARK: - Mutable JSON Writer Implementation (Private)
9889 *============================================================================*/
9890
9891typedef struct yyjson_mut_write_ctx {
9892 usize tag;
9893 yyjson_mut_val *ctn;
9894} yyjson_mut_write_ctx;
9895
9896static_inline void yyjson_mut_write_ctx_set(yyjson_mut_write_ctx *ctx,
9897 yyjson_mut_val *ctn,
9898 usize size, bool is_obj) {
9899 ctx->tag = (size << 1) | (usize)is_obj;
9900 ctx->ctn = ctn;
9901}
9902
9903static_inline void yyjson_mut_write_ctx_get(yyjson_mut_write_ctx *ctx,
9904 yyjson_mut_val **ctn,
9905 usize *size, bool *is_obj) {
9906 usize tag = ctx->tag;
9907 *size = tag >> 1;
9908 *is_obj = (bool)(tag & 1);
9909 *ctn = ctx->ctn;
9910}
9911
9912/** Get the estimated number of values for the mutable JSON document. */
9913static_inline usize yyjson_mut_doc_estimated_val_num(
9914 const yyjson_mut_doc *doc) {
9915 usize sum = 0;
9916 yyjson_val_chunk *chunk = doc->val_pool.chunks;
9917 while (chunk) {
9918 sum += chunk->chunk_size / sizeof(yyjson_mut_val) - 1;
9919 if (chunk == doc->val_pool.chunks) {
9920 sum -= (usize)(doc->val_pool.end - doc->val_pool.cur);
9921 }
9922 chunk = chunk->next;
9923 }
9924 return sum;
9925}
9926
9927/** Write single JSON value. */
9928static_inline u8 *mut_write_root_single(yyjson_mut_val *val,
9929 yyjson_write_flag flg,
9930 yyjson_alc alc,
9931 char *buf, usize *dat_len,
9932 yyjson_write_err *err) {
9933 return write_root_single((yyjson_val *)val, flg, alc, buf, dat_len, err);
9934}
9935
9936/** Write JSON document minify.
9937 The root of this document should be a non-empty container. */
9938static_inline u8 *mut_write_root_minify(const yyjson_mut_val *root,
9939 usize estimated_val_num,
9940 yyjson_write_flag flg,
9941 yyjson_alc alc,
9942 char *buf, usize *dat_len,
9943 yyjson_write_err *err) {
9944#define return_err(_code, _msg) do { \
9945 *dat_len = 0; \
9946 err->code = YYJSON_WRITE_ERROR_##_code; \
9947 err->msg = _msg; \
9948 if (hdr) alc.free(alc.ctx, hdr); \
9949 return NULL; \
9950} while (false)
9951
9952#define incr_len(_len) do { \
9953 ext_len = (usize)(_len); \
9954 if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
9955 usize ctx_pos = (usize)((u8 *)ctx - hdr); \
9956 usize cur_pos = (usize)(cur - hdr); \
9957 yyjson_assume((u8 *)ctx <= (u8 *)end); \
9958 ctx_len = (usize)((u8 *)end - (u8 *)ctx); \
9959 alc_inc = yyjson_max(alc_len / 2, ext_len); \
9960 alc_inc = size_align_up(alc_inc, sizeof(yyjson_mut_write_ctx)); \
9961 if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
9962 goto fail_alloc; \
9963 alc_len += alc_inc; \
9964 tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
9965 if (unlikely(!tmp)) goto fail_alloc; \
9966 ctx_tmp = (yyjson_mut_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
9967 memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
9968 ctx = ctx_tmp; \
9969 cur = tmp + cur_pos; \
9970 end = tmp + alc_len; \
9971 hdr = tmp; \
9972 } \
9973} while (false)
9974
9975#define check_str_len(_len) do { \
9976 if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
9977 goto fail_alloc; \
9978} while (false)
9979
9980 yyjson_mut_val *val, *ctn;
9981 yyjson_type val_type;
9982 usize ctn_len, ctn_len_tmp;
9983 bool ctn_obj, ctn_obj_tmp, is_key;
9984 u8 *hdr, *cur, *end, *tmp;
9985 yyjson_mut_write_ctx *ctx, *ctx_tmp;
9986 usize alc_len, alc_inc, ctx_len, ext_len, str_len;
9987#if YYJSON_WRITER_DEPTH_LIMIT
9988 usize ctn_depth = 0;
9989#endif
9990 const u8 *str_ptr;
9991 const char_enc_type *enc_table = get_enc_table_with_flag(flg);
9992 const u8 *hex_table = get_hex_table_with_flag(flg);
9993 bool cpy = (enc_table == enc_table_cpy);
9994 bool esc = has_flg(ESCAPE_UNICODE) != 0;
9995 bool inv = has_allow(INVALID_UNICODE) != 0;
9996 bool newline = has_flg(NEWLINE_AT_END) != 0;
9997
9998 if (buf) {
9999 hdr = (u8 *)buf;
10000 alc_len = *dat_len;
10001 alc_len = size_align_down(alc_len, sizeof(yyjson_mut_write_ctx));
10002 if (alc_len <= sizeof(yyjson_mut_write_ctx)) goto fail_alloc;
10003 } else {
10004 alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64;
10005 alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx));
10006 hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
10007 if (!hdr) goto fail_alloc;
10008 }
10009 cur = hdr;
10010 end = hdr + alc_len;
10011 ctx = (yyjson_mut_write_ctx *)(void *)end;
10012
10013doc_begin:
10014 val = constcast(yyjson_mut_val *)root;
10015 val_type = unsafe_yyjson_get_type(val);
10016 ctn_obj = (val_type == YYJSON_TYPE_OBJ);
10017 ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
10018 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
10019 ctn = val;
10020 val = (yyjson_mut_val *)val->uni.ptr; /* tail */
10021 val = ctn_obj ? val->next->next : val->next;
10022
10023val_begin:
10024 val_type = unsafe_yyjson_get_type(val);
10025 if (val_type == YYJSON_TYPE_STR) {
10026 is_key = ((u8)ctn_obj & (u8)~ctn_len);
10027 str_len = unsafe_yyjson_get_len(val);
10028 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
10029 check_str_len(str_len);
10030 incr_len(str_len * 6 + 16);
10031 if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
10032 cur = write_str_noesc(cur, str_ptr, str_len);
10033 } else {
10034 cur = write_str(cur, esc, inv, str_ptr, str_len,
10035 enc_table, hex_table);
10036 if (unlikely(!cur)) goto fail_str;
10037 }
10038 *cur++ = is_key ? ':' : ',';
10039 goto val_end;
10040 }
10041 if (val_type == YYJSON_TYPE_NUM) {
10042 incr_len(FP_BUF_LEN);
10043 cur = write_num(cur, (yyjson_val *)val, flg);
10044 if (unlikely(!cur)) goto fail_num;
10045 *cur++ = ',';
10046 goto val_end;
10047 }
10048 if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
10049 (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
10050 ctn_len_tmp = unsafe_yyjson_get_len(val);
10051 ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
10052 incr_len(2 * sizeof(*ctx));
10053#if YYJSON_WRITER_DEPTH_LIMIT
10054 ctn_depth++;
10055 if (unlikely(ctn_depth >= (usize)YYJSON_WRITER_DEPTH_LIMIT)) {
10056 goto fail_depth;
10057 }
10058#endif
10059 if (unlikely(ctn_len_tmp == 0)) {
10060#if YYJSON_WRITER_DEPTH_LIMIT
10061 ctn_depth--;
10062#endif
10063 /* write empty container */
10064 *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
10065 *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
10066 *cur++ = ',';
10067 goto val_end;
10068 } else {
10069 /* push context, setup new container */
10070 yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj);
10071 ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
10072 ctn_obj = ctn_obj_tmp;
10073 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
10074 ctn = val;
10075 val = (yyjson_mut_val *)ctn->uni.ptr; /* tail */
10076 val = ctn_obj ? val->next->next : val->next;
10077 goto val_begin;
10078 }
10079 }
10080 if (val_type == YYJSON_TYPE_BOOL) {
10081 incr_len(16);
10082 cur = write_bool(cur, unsafe_yyjson_get_bool(val));
10083 cur++;
10084 goto val_end;
10085 }
10086 if (val_type == YYJSON_TYPE_NULL) {
10087 incr_len(16);
10088 cur = write_null(cur);
10089 cur++;
10090 goto val_end;
10091 }
10092 if (val_type == YYJSON_TYPE_RAW) {
10093 str_len = unsafe_yyjson_get_len(val);
10094 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
10095 check_str_len(str_len);
10096 incr_len(str_len + 2);
10097 cur = write_raw(cur, str_ptr, str_len);
10098 *cur++ = ',';
10099 goto val_end;
10100 }
10101 goto fail_type;
10102
10103val_end:
10104 ctn_len--;
10105 if (unlikely(ctn_len == 0)) goto ctn_end;
10106 val = val->next;
10107 goto val_begin;
10108
10109ctn_end:
10110#if YYJSON_WRITER_DEPTH_LIMIT
10111 ctn_depth--;
10112#endif
10113 cur--;
10114 *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
10115 *cur++ = ',';
10116 if (unlikely((u8 *)ctx >= end)) goto doc_end;
10117 val = ctn->next;
10118 yyjson_mut_write_ctx_get(ctx++, &ctn, &ctn_len, &ctn_obj);
10119 ctn_len--;
10120 if (likely(ctn_len > 0)) {
10121 goto val_begin;
10122 } else {
10123 goto ctn_end;
10124 }
10125
10126doc_end:
10127 if (newline) {
10128 incr_len(2);
10129 *(cur - 1) = '\n';
10130 cur++;
10131 }
10132 *--cur = '\0';
10133 *dat_len = (usize)(cur - hdr);
10134 err->code = YYJSON_WRITE_SUCCESS;
10135 err->msg = NULL;
10136 return hdr;
10137
10138fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
10139fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
10140fail_num: return_err(NAN_OR_INF, MSG_NAN_INF);
10141fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8);
10142#if YYJSON_WRITER_DEPTH_LIMIT
10143fail_depth: return_err(DEPTH, MSG_DEPTH);
10144#endif
10145
10146#undef return_err
10147#undef incr_len
10148#undef check_str_len
10149}
10150
10151/** Write JSON document pretty.
10152 The root of this document should be a non-empty container. */
10153static_inline u8 *mut_write_root_pretty(const yyjson_mut_val *root,
10154 usize estimated_val_num,
10155 yyjson_write_flag flg,
10156 yyjson_alc alc,
10157 char *buf, usize *dat_len,
10158 yyjson_write_err *err) {
10159#define return_err(_code, _msg) do { \
10160 *dat_len = 0; \
10161 err->code = YYJSON_WRITE_ERROR_##_code; \
10162 err->msg = _msg; \
10163 if (hdr) alc.free(alc.ctx, hdr); \
10164 return NULL; \
10165} while (false)
10166
10167#define incr_len(_len) do { \
10168 ext_len = (usize)(_len); \
10169 if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
10170 usize ctx_pos = (usize)((u8 *)ctx - hdr); \
10171 usize cur_pos = (usize)(cur - hdr); \
10172 yyjson_assume((u8 *)ctx <= (u8 *)end); \
10173 ctx_len = (usize)((u8 *)end - (u8 *)ctx); \
10174 alc_inc = yyjson_max(alc_len / 2, ext_len); \
10175 alc_inc = size_align_up(alc_inc, sizeof(yyjson_mut_write_ctx)); \
10176 if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
10177 goto fail_alloc; \
10178 alc_len += alc_inc; \
10179 tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
10180 if (unlikely(!tmp)) goto fail_alloc; \
10181 ctx_tmp = (yyjson_mut_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
10182 memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
10183 ctx = ctx_tmp; \
10184 cur = tmp + cur_pos; \
10185 end = tmp + alc_len; \
10186 hdr = tmp; \
10187 } \
10188} while (false)
10189
10190#define check_str_len(_len) do { \
10191 if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
10192 goto fail_alloc; \
10193} while (false)
10194
10195 yyjson_mut_val *val, *ctn;
10196 yyjson_type val_type;
10197 usize ctn_len, ctn_len_tmp;
10198 bool ctn_obj, ctn_obj_tmp, is_key, no_indent;
10199 u8 *hdr, *cur, *end, *tmp;
10200 yyjson_mut_write_ctx *ctx, *ctx_tmp;
10201 usize alc_len, alc_inc, ctx_len, ext_len, str_len, level;
10202#if YYJSON_WRITER_DEPTH_LIMIT
10203 usize ctn_depth = 0;
10204#endif
10205 const u8 *str_ptr;
10206 const char_enc_type *enc_table = get_enc_table_with_flag(flg);
10207 const u8 *hex_table = get_hex_table_with_flag(flg);
10208 bool cpy = (enc_table == enc_table_cpy);
10209 bool esc = has_flg(ESCAPE_UNICODE) != 0;
10210 bool inv = has_allow(INVALID_UNICODE) != 0;
10211 usize spaces = has_flg(PRETTY_TWO_SPACES) ? 2 : 4;
10212 bool newline = has_flg(NEWLINE_AT_END) != 0;
10213
10214 if (buf) {
10215 hdr = (u8 *)buf;
10216 alc_len = *dat_len;
10217 alc_len = size_align_down(alc_len, sizeof(yyjson_mut_write_ctx));
10218 if (alc_len <= sizeof(yyjson_mut_write_ctx)) goto fail_alloc;
10219 } else {
10220 alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64;
10221 alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx));
10222 hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
10223 if (!hdr) goto fail_alloc;
10224 }
10225 cur = hdr;
10226 end = hdr + alc_len;
10227 ctx = (yyjson_mut_write_ctx *)(void *)end;
10228
10229doc_begin:
10230 val = constcast(yyjson_mut_val *)root;
10231 val_type = unsafe_yyjson_get_type(val);
10232 ctn_obj = (val_type == YYJSON_TYPE_OBJ);
10233 ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
10234 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
10235 *cur++ = '\n';
10236 ctn = val;
10237 val = (yyjson_mut_val *)val->uni.ptr; /* tail */
10238 val = ctn_obj ? val->next->next : val->next;
10239 level = 1;
10240
10241val_begin:
10242 val_type = unsafe_yyjson_get_type(val);
10243 if (val_type == YYJSON_TYPE_STR) {
10244 is_key = (bool)((u8)ctn_obj & (u8)~ctn_len);
10245 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10246 str_len = unsafe_yyjson_get_len(val);
10247 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
10248 check_str_len(str_len);
10249 if ((sizeof(usize) < 8) && !no_indent &&
10250 level > (USIZE_MAX - 16 - str_len * 6) / 4) goto fail_alloc;
10251 incr_len(str_len * 6 + 16 + (no_indent ? 0 : level * 4));
10252 cur = write_indent(cur, no_indent ? 0 : level, spaces);
10253 if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
10254 cur = write_str_noesc(cur, str_ptr, str_len);
10255 } else {
10256 cur = write_str(cur, esc, inv, str_ptr, str_len,
10257 enc_table, hex_table);
10258 if (unlikely(!cur)) goto fail_str;
10259 }
10260 *cur++ = is_key ? ':' : ',';
10261 *cur++ = is_key ? ' ' : '\n';
10262 goto val_end;
10263 }
10264 if (val_type == YYJSON_TYPE_NUM) {
10265 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10266 incr_len(FP_BUF_LEN + (no_indent ? 0 : level * 4));
10267 cur = write_indent(cur, no_indent ? 0 : level, spaces);
10268 cur = write_num(cur, (yyjson_val *)val, flg);
10269 if (unlikely(!cur)) goto fail_num;
10270 *cur++ = ',';
10271 *cur++ = '\n';
10272 goto val_end;
10273 }
10274 if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
10275 (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
10276 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10277 ctn_len_tmp = unsafe_yyjson_get_len(val);
10278 ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
10279 incr_len(2 * sizeof(*ctx) + (no_indent ? 0 : level * 4));
10280#if YYJSON_WRITER_DEPTH_LIMIT
10281 ctn_depth++;
10282 if (unlikely(ctn_depth >= (usize)YYJSON_WRITER_DEPTH_LIMIT)) {
10283 goto fail_depth;
10284 }
10285#endif
10286 if (unlikely(ctn_len_tmp == 0)) {
10287#if YYJSON_WRITER_DEPTH_LIMIT
10288 ctn_depth--;
10289#endif
10290 /* write empty container */
10291 cur = write_indent(cur, no_indent ? 0 : level, spaces);
10292 *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
10293 *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
10294 *cur++ = ',';
10295 *cur++ = '\n';
10296 goto val_end;
10297 } else {
10298 /* push context, setup new container */
10299 yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj);
10300 ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
10301 ctn_obj = ctn_obj_tmp;
10302 cur = write_indent(cur, no_indent ? 0 : level, spaces);
10303 level++;
10304 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
10305 *cur++ = '\n';
10306 ctn = val;
10307 val = (yyjson_mut_val *)ctn->uni.ptr; /* tail */
10308 val = ctn_obj ? val->next->next : val->next;
10309 goto val_begin;
10310 }
10311 }
10312 if (val_type == YYJSON_TYPE_BOOL) {
10313 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10314 incr_len(16 + (no_indent ? 0 : level * 4));
10315 cur = write_indent(cur, no_indent ? 0 : level, spaces);
10316 cur = write_bool(cur, unsafe_yyjson_get_bool(val));
10317 cur += 2;
10318 goto val_end;
10319 }
10320 if (val_type == YYJSON_TYPE_NULL) {
10321 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10322 incr_len(16 + (no_indent ? 0 : level * 4));
10323 cur = write_indent(cur, no_indent ? 0 : level, spaces);
10324 cur = write_null(cur);
10325 cur += 2;
10326 goto val_end;
10327 }
10328 if (val_type == YYJSON_TYPE_RAW) {
10329 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10330 str_len = unsafe_yyjson_get_len(val);
10331 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
10332 check_str_len(str_len);
10333 incr_len(str_len + 3 + (no_indent ? 0 : level * 4));
10334 cur = write_indent(cur, no_indent ? 0 : level, spaces);
10335 cur = write_raw(cur, str_ptr, str_len);
10336 *cur++ = ',';
10337 *cur++ = '\n';
10338 goto val_end;
10339 }
10340 goto fail_type;
10341
10342val_end:
10343 ctn_len--;
10344 if (unlikely(ctn_len == 0)) goto ctn_end;
10345 val = val->next;
10346 goto val_begin;
10347
10348ctn_end:
10349#if YYJSON_WRITER_DEPTH_LIMIT
10350 ctn_depth--;
10351#endif
10352 cur -= 2;
10353 *cur++ = '\n';
10354 incr_len(level * 4);
10355 cur = write_indent(cur, --level, spaces);
10356 *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
10357 if (unlikely((u8 *)ctx >= end)) goto doc_end;
10358 val = ctn->next;
10359 yyjson_mut_write_ctx_get(ctx++, &ctn, &ctn_len, &ctn_obj);
10360 ctn_len--;
10361 *cur++ = ',';
10362 *cur++ = '\n';
10363 if (likely(ctn_len > 0)) {
10364 goto val_begin;
10365 } else {
10366 goto ctn_end;
10367 }
10368
10369doc_end:
10370 if (newline) {
10371 incr_len(2);
10372 *cur++ = '\n';
10373 }
10374 *cur = '\0';
10375 *dat_len = (usize)(cur - hdr);
10376 err->code = YYJSON_WRITE_SUCCESS;
10377 err->msg = NULL;
10378 return hdr;
10379
10380fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
10381fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
10382fail_num: return_err(NAN_OR_INF, MSG_NAN_INF);
10383fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8);
10384#if YYJSON_WRITER_DEPTH_LIMIT
10385fail_depth: return_err(DEPTH, MSG_DEPTH);
10386#endif
10387
10388#undef return_err
10389#undef incr_len
10390#undef check_str_len
10391}
10392
10393static char *mut_write_root(const yyjson_mut_val *val,
10394 usize estimated_val_num,
10395 yyjson_write_flag flg,
10396 const yyjson_alc *alc_ptr,
10397 char *buf, usize *dat_len,
10398 yyjson_write_err *err) {
10399 yyjson_write_err tmp_err;
10400 usize tmp_dat_len;
10401 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
10402 yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
10403
10404 if (!err) err = &tmp_err;
10405 if (!dat_len) dat_len = &tmp_dat_len;
10406
10407 if (unlikely(!root)) {
10408 *dat_len = 0;
10409 err->msg = "input JSON is NULL";
10410 err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
10411 return NULL;
10412 }
10413
10414 if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) {
10415 return (char *)mut_write_root_single(root, flg, alc, buf, dat_len, err);
10416 } else if (flg & (YYJSON_WRITE_PRETTY | YYJSON_WRITE_PRETTY_TWO_SPACES)) {
10417 return (char *)mut_write_root_pretty(root, estimated_val_num,
10418 flg, alc, buf, dat_len, err);
10419 } else {
10420 return (char *)mut_write_root_minify(root, estimated_val_num,
10421 flg, alc, buf, dat_len, err);
10422 }
10423}
10424
10425
10426
10427/*==============================================================================
10428 * MARK: - Mutable JSON Writer (Public)
10429 *============================================================================*/
10430
10431char *yyjson_mut_val_write_opts(const yyjson_mut_val *val,
10432 yyjson_write_flag flg,
10433 const yyjson_alc *alc_ptr,
10434 usize *dat_len,
10435 yyjson_write_err *err) {
10436 return mut_write_root(val, 0, flg, alc_ptr, NULL, dat_len, err);
10437}
10438
10439char *yyjson_mut_write_opts(const yyjson_mut_doc *doc,
10440 yyjson_write_flag flg,
10441 const yyjson_alc *alc_ptr,
10442 usize *dat_len,
10443 yyjson_write_err *err) {
10444 yyjson_mut_val *root;
10445 usize estimated_val_num;
10446 if (likely(doc)) {
10447 root = doc->root;
10448 estimated_val_num = yyjson_mut_doc_estimated_val_num(doc);
10449 } else {
10450 root = NULL;
10451 estimated_val_num = 0;
10452 }
10453 return mut_write_root(root, estimated_val_num,
10454 flg, alc_ptr, NULL, dat_len, err);
10455}
10456
10457size_t yyjson_mut_val_write_buf(char *buf, size_t buf_len,
10458 const yyjson_mut_val *val,
10459 yyjson_write_flag flg,
10460 yyjson_write_err *err) {
10461 if (unlikely(!buf || !buf_len)) {
10462 if (err) err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
10463 if (err) err->msg = "input buf or buf_len is invalid";
10464 return 0;
10465 } else {
10466 mut_write_root(val, 0, flg, &YYJSON_NULL_ALC, buf, &buf_len, err);
10467 return buf_len;
10468 }
10469}
10470
10471size_t yyjson_mut_write_buf(char *buf, size_t buf_len,
10472 const yyjson_mut_doc *doc,
10473 yyjson_write_flag flg,
10474 yyjson_write_err *err) {
10475 yyjson_mut_val *root = doc ? doc->root : NULL;
10476 return yyjson_mut_val_write_buf(buf, buf_len, root, flg, err);
10477}
10478
10479#if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE
10480
10481bool yyjson_mut_val_write_file(const char *path,
10482 const yyjson_mut_val *val,
10483 yyjson_write_flag flg,
10484 const yyjson_alc *alc_ptr,
10485 yyjson_write_err *err) {
10486 yyjson_write_err tmp_err;
10487 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
10488 u8 *dat;
10489 usize dat_len = 0;
10490 yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
10491 bool suc;
10492
10493 if (!err) err = &tmp_err;
10494 if (unlikely(!path || !*path)) {
10495 err->msg = "input path is invalid";
10496 err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
10497 return false;
10498 }
10499
10500 dat = (u8 *)yyjson_mut_val_write_opts(root, flg, &alc, &dat_len, err);
10501 if (unlikely(!dat)) return false;
10502 suc = write_dat_to_file(path, dat, dat_len, err);
10503 alc.free(alc.ctx, dat);
10504 return suc;
10505}
10506
10507bool yyjson_mut_val_write_fp(FILE *fp,
10508 const yyjson_mut_val *val,
10509 yyjson_write_flag flg,
10510 const yyjson_alc *alc_ptr,
10511 yyjson_write_err *err) {
10512 yyjson_write_err tmp_err;
10513 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
10514 u8 *dat;
10515 usize dat_len = 0;
10516 yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
10517 bool suc;
10518
10519 if (!err) err = &tmp_err;
10520 if (unlikely(!fp)) {
10521 err->msg = "input fp is invalid";
10522 err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
10523 return false;
10524 }
10525
10526 dat = (u8 *)yyjson_mut_val_write_opts(root, flg, &alc, &dat_len, err);
10527 if (unlikely(!dat)) return false;
10528 suc = write_dat_to_fp(fp, dat, dat_len, err);
10529 alc.free(alc.ctx, dat);
10530 return suc;
10531}
10532
10533bool yyjson_mut_write_file(const char *path,
10534 const yyjson_mut_doc *doc,
10535 yyjson_write_flag flg,
10536 const yyjson_alc *alc_ptr,
10537 yyjson_write_err *err) {
10538 yyjson_mut_val *root = doc ? doc->root : NULL;
10539 return yyjson_mut_val_write_file(path, root, flg, alc_ptr, err);
10540}
10541
10542bool yyjson_mut_write_fp(FILE *fp,
10543 const yyjson_mut_doc *doc,
10544 yyjson_write_flag flg,
10545 const yyjson_alc *alc_ptr,
10546 yyjson_write_err *err) {
10547 yyjson_mut_val *root = doc ? doc->root : NULL;
10548 return yyjson_mut_val_write_fp(fp, root, flg, alc_ptr, err);
10549}
10550
10551#endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */
10552
10553#undef has_flg
10554#undef has_allow
10555#endif /* YYJSON_DISABLE_WRITER */
10556
10557
10558
10559#if !YYJSON_DISABLE_UTILS
10560
10561/*==============================================================================
10562 * MARK: - JSON Pointer API (RFC 6901) (Public)
10563 *============================================================================*/
10564
10565/**
10566 Get a token from JSON pointer string.
10567 @param ptr [in] string that points to current token prefix `/`
10568 [out] string that points to next token prefix `/`, or string end
10569 @param end [in] end of the entire JSON Pointer string
10570 @param len [out] unescaped token length
10571 @param esc [out] number of escaped characters in this token
10572 @return head of the token, or NULL if syntax error
10573 */
10574static_inline const char *ptr_next_token(const char **ptr, const char *end,
10575 usize *len, usize *esc) {
10576 const char *hdr = *ptr + 1;
10577 const char *cur = hdr;
10578 /* skip unescaped characters */
10579 while (cur < end && *cur != '/' && *cur != '~') cur++;
10580 if (likely(cur == end || *cur != '~')) {
10581 /* no escaped characters, return */
10582 *ptr = cur;
10583 *len = (usize)(cur - hdr);
10584 *esc = 0;
10585 return hdr;
10586 } else {
10587 /* handle escaped characters */
10588 usize esc_num = 0;
10589 while (cur < end && *cur != '/') {
10590 if (*cur++ == '~') {
10591 if (cur == end || (*cur != '0' && *cur != '1')) {
10592 *ptr = cur - 1;
10593 return NULL;
10594 }
10595 esc_num++;
10596 }
10597 }
10598 *ptr = cur;
10599 *len = (usize)(cur - hdr) - esc_num;
10600 *esc = esc_num;
10601 return hdr;
10602 }
10603}
10604
10605/**
10606 Convert token string to index.
10607 @param cur [in] token head
10608 @param len [in] token length
10609 @param idx [out] the index number, or USIZE_MAX if token is '-'
10610 @return true if token is a valid array index
10611 */
10612static_inline bool ptr_token_to_idx(const char *cur, usize len, usize *idx) {
10613 const char *end = cur + len;
10614 usize num = 0, add;
10615 if (unlikely(len == 0 || len > USIZE_SAFE_DIG)) return false;
10616 if (*cur == '0') {
10617 if (unlikely(len > 1)) return false;
10618 *idx = 0;
10619 return true;
10620 }
10621 if (*cur == '-') {
10622 if (unlikely(len > 1)) return false;
10623 *idx = USIZE_MAX;
10624 return true;
10625 }
10626 for (; cur < end && (add = (usize)((u8)*cur - (u8)'0')) <= 9; cur++) {
10627 num = num * 10 + add;
10628 }
10629 if (unlikely(num == 0 || cur < end)) return false;
10630 *idx = num;
10631 return true;
10632}
10633
10634/**
10635 Compare JSON key with token.
10636 @param key a string key (yyjson_val or yyjson_mut_val)
10637 @param token a JSON pointer token
10638 @param len unescaped token length
10639 @param esc number of escaped characters in this token
10640 @return true if `str` is equal to `token`
10641 */
10642static_inline bool ptr_token_eq(void *key,
10643 const char *token, usize len, usize esc) {
10644 yyjson_val *val = (yyjson_val *)key;
10645 if (unsafe_yyjson_get_len(val) != len) return false;
10646 if (likely(!esc)) {
10647 return memcmp(val->uni.str, token, len) == 0;
10648 } else {
10649 const char *str = val->uni.str;
10650 for (; len-- > 0; token++, str++) {
10651 if (*token == '~') {
10652 if (*str != (*++token == '0' ? '~' : '/')) return false;
10653 } else {
10654 if (*str != *token) return false;
10655 }
10656 }
10657 return true;
10658 }
10659}
10660
10661/**
10662 Get a value from array by token.
10663 @param arr an array, should not be NULL or non-array type
10664 @param token a JSON pointer token
10665 @param len unescaped token length
10666 @param esc number of escaped characters in this token
10667 @return value at index, or NULL if token is not index or index is out of range
10668 */
10669static_inline yyjson_val *ptr_arr_get(const yyjson_val *arr, const char *token,
10670 usize len, usize esc) {
10671 yyjson_val *val = unsafe_yyjson_get_first(arr);
10672 usize num = unsafe_yyjson_get_len(arr), idx = 0;
10673 if (unlikely(num == 0)) return NULL;
10674 if (unlikely(!ptr_token_to_idx(token, len, &idx))) return NULL;
10675 if (unlikely(idx >= num)) return NULL;
10676 if (unsafe_yyjson_arr_is_flat(arr)) {
10677 return val + idx;
10678 } else {
10679 while (idx-- > 0) val = unsafe_yyjson_get_next(val);
10680 return val;
10681 }
10682}
10683
10684/**
10685 Get a value from object by token.
10686 @param obj [in] an object, should not be NULL or non-object type
10687 @param token [in] a JSON pointer token
10688 @param len [in] unescaped token length
10689 @param esc [in] number of escaped characters in this token
10690 @return value associated with the token, or NULL if no value
10691 */
10692static_inline yyjson_val *ptr_obj_get(const yyjson_val *obj, const char *token,
10693 usize len, usize esc) {
10694 yyjson_val *key = unsafe_yyjson_get_first(obj);
10695 usize num = unsafe_yyjson_get_len(obj);
10696 if (unlikely(num == 0)) return NULL;
10697 for (; num > 0; num--, key = unsafe_yyjson_get_next(key + 1)) {
10698 if (ptr_token_eq(key, token, len, esc)) return key + 1;
10699 }
10700 return NULL;
10701}
10702
10703/**
10704 Get a value from array by token.
10705 @param arr [in] an array, should not be NULL or non-array type
10706 @param token [in] a JSON pointer token
10707 @param len [in] unescaped token length
10708 @param esc [in] number of escaped characters in this token
10709 @param pre [out] previous (sibling) value of the returned value
10710 @param last [out] whether index is last
10711 @return value at index, or NULL if token is not index or index is out of range
10712 */
10713static_inline yyjson_mut_val *ptr_mut_arr_get(const yyjson_mut_val *arr,
10714 const char *token,
10715 usize len, usize esc,
10716 yyjson_mut_val **pre,
10717 bool *last) {
10718 yyjson_mut_val *val = (yyjson_mut_val *)arr->uni.ptr; /* last (tail) */
10719 usize num = unsafe_yyjson_get_len(arr), idx;
10720 if (last) *last = false;
10721 if (pre) *pre = NULL;
10722 if (unlikely(num == 0)) {
10723 if (last && len == 1 && (*token == '0' || *token == '-')) *last = true;
10724 return NULL;
10725 }
10726 if (unlikely(!ptr_token_to_idx(token, len, &idx))) return NULL;
10727 if (last) *last = (idx == num || idx == USIZE_MAX);
10728 if (unlikely(idx >= num)) return NULL;
10729 while (idx-- > 0) val = val->next;
10730 if (pre) *pre = val;
10731 return val->next;
10732}
10733
10734/**
10735 Get a value from object by token.
10736 @param obj [in] an object, should not be NULL or non-object type
10737 @param token [in] a JSON pointer token
10738 @param len [in] unescaped token length
10739 @param esc [in] number of escaped characters in this token
10740 @param pre [out] previous (sibling) key of the returned value's key
10741 @return value associated with the token, or NULL if no value
10742 */
10743static_inline yyjson_mut_val *ptr_mut_obj_get(const yyjson_mut_val *obj,
10744 const char *token,
10745 usize len, usize esc,
10746 yyjson_mut_val **pre) {
10747 yyjson_mut_val *pre_key = (yyjson_mut_val *)obj->uni.ptr, *key;
10748 usize num = unsafe_yyjson_get_len(obj);
10749 if (pre) *pre = NULL;
10750 if (unlikely(num == 0)) return NULL;
10751 for (; num > 0; num--, pre_key = key) {
10752 key = pre_key->next->next;
10753 if (ptr_token_eq(key, token, len, esc)) {
10754 if (pre) *pre = pre_key;
10755 return key->next;
10756 }
10757 }
10758 return NULL;
10759}
10760
10761/**
10762 Create a string value with JSON pointer token.
10763 @param token [in] a JSON pointer token
10764 @param len [in] unescaped token length
10765 @param esc [in] number of escaped characters in this token
10766 @param doc [in] used for memory allocation when creating value
10767 @return new string value, or NULL if memory allocation failed
10768 */
10769static_inline yyjson_mut_val *ptr_new_key(const char *token,
10770 usize len, usize esc,
10771 yyjson_mut_doc *doc) {
10772 const char *src = token;
10773 if (likely(!esc)) {
10774 return yyjson_mut_strncpy(doc, src, len);
10775 } else {
10776 const char *end = src + len + esc;
10777 char *dst = unsafe_yyjson_mut_str_alc(doc, len + esc);
10778 char *str = dst;
10779 if (unlikely(!dst)) return NULL;
10780 for (; src < end; src++, dst++) {
10781 if (*src != '~') *dst = *src;
10782 else *dst = (*++src == '0' ? '~' : '/');
10783 }
10784 *dst = '\0';
10785 return yyjson_mut_strn(doc, str, len);
10786 }
10787}
10788
10789/* macros for yyjson_ptr */
10790#define return_err(_ret, _code, _pos, _msg) do { \
10791 if (err) { \
10792 err->code = YYJSON_PTR_ERR_##_code; \
10793 err->msg = _msg; \
10794 err->pos = (usize)(_pos); \
10795 } \
10796 return _ret; \
10797} while (false)
10798
10799#define return_err_resolve(_ret, _pos) \
10800 return_err(_ret, RESOLVE, _pos, "JSON pointer cannot be resolved")
10801#define return_err_syntax(_ret, _pos) \
10802 return_err(_ret, SYNTAX, _pos, "invalid escaped character")
10803#define return_err_alloc(_ret) \
10804 return_err(_ret, MEMORY_ALLOCATION, 0, "failed to create value")
10805
10806yyjson_val *unsafe_yyjson_ptr_getx(const yyjson_val *val,
10807 const char *ptr, size_t ptr_len,
10808 yyjson_ptr_err *err) {
10809
10810 const char *hdr = ptr, *end = ptr + ptr_len, *token;
10811 usize len, esc;
10812 yyjson_type type;
10813
10814 while (true) {
10815 token = ptr_next_token(&ptr, end, &len, &esc);
10816 if (unlikely(!token)) return_err_syntax(NULL, ptr - hdr);
10817 type = unsafe_yyjson_get_type(val);
10818 if (type == YYJSON_TYPE_OBJ) {
10819 val = ptr_obj_get(val, token, len, esc);
10820 } else if (type == YYJSON_TYPE_ARR) {
10821 val = ptr_arr_get(val, token, len, esc);
10822 } else {
10823 val = NULL;
10824 }
10825 if (!val) return_err_resolve(NULL, token - hdr);
10826 if (ptr == end) return constcast(yyjson_val *)val;
10827 }
10828}
10829
10830yyjson_mut_val *unsafe_yyjson_mut_ptr_getx(
10831 const yyjson_mut_val *val, const char *ptr, size_t ptr_len,
10832 yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
10833
10834 const char *hdr = ptr, *end = ptr + ptr_len, *token;
10835 usize len, esc;
10836 yyjson_mut_val *ctn, *pre = NULL;
10837 yyjson_type type;
10838 bool idx_is_last = false;
10839
10840 while (true) {
10841 token = ptr_next_token(&ptr, end, &len, &esc);
10842 if (unlikely(!token)) return_err_syntax(NULL, ptr - hdr);
10843 ctn = constcast(yyjson_mut_val *)val;
10844 type = unsafe_yyjson_get_type(val);
10845 if (type == YYJSON_TYPE_OBJ) {
10846 val = ptr_mut_obj_get(val, token, len, esc, &pre);
10847 } else if (type == YYJSON_TYPE_ARR) {
10848 val = ptr_mut_arr_get(val, token, len, esc, &pre, &idx_is_last);
10849 } else {
10850 val = NULL;
10851 }
10852 if (ctx && (ptr == end)) {
10853 if (type == YYJSON_TYPE_OBJ ||
10854 (type == YYJSON_TYPE_ARR && (val || idx_is_last))) {
10855 ctx->ctn = ctn;
10856 ctx->pre = pre;
10857 }
10858 }
10859 if (!val) return_err_resolve(NULL, token - hdr);
10860 if (ptr == end) return constcast(yyjson_mut_val *)val;
10861 }
10862}
10863
10864bool unsafe_yyjson_mut_ptr_putx(
10865 yyjson_mut_val *val, const char *ptr, size_t ptr_len,
10866 yyjson_mut_val *new_val, yyjson_mut_doc *doc, bool create_parent,
10867 bool insert_new, yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
10868
10869 const char *hdr = ptr, *end = ptr + ptr_len, *token;
10870 usize token_len, esc, ctn_len;
10871 yyjson_mut_val *ctn, *key, *pre = NULL;
10872 yyjson_mut_val *sep_ctn = NULL, *sep_key = NULL, *sep_val = NULL;
10873 yyjson_type ctn_type;
10874 bool idx_is_last = false;
10875
10876 /* skip exist parent nodes */
10877 while (true) {
10878 token = ptr_next_token(&ptr, end, &token_len, &esc);
10879 if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
10880 ctn = val;
10881 ctn_type = unsafe_yyjson_get_type(ctn);
10882 if (ctn_type == YYJSON_TYPE_OBJ) {
10883 val = ptr_mut_obj_get(ctn, token, token_len, esc, &pre);
10884 } else if (ctn_type == YYJSON_TYPE_ARR) {
10885 val = ptr_mut_arr_get(ctn, token, token_len, esc, &pre,
10886 &idx_is_last);
10887 } else return_err_resolve(false, token - hdr);
10888 if (!val) break;
10889 if (ptr == end) break; /* is last token */
10890 }
10891
10892 /* create parent nodes if not exist */
10893 if (unlikely(ptr != end)) { /* not last token */
10894 if (!create_parent) return_err_resolve(false, token - hdr);
10895
10896 /* add value at last index if container is array */
10897 if (ctn_type == YYJSON_TYPE_ARR) {
10898 if (!idx_is_last || !insert_new) {
10899 return_err_resolve(false, token - hdr);
10900 }
10901 val = yyjson_mut_obj(doc);
10902 if (!val) return_err_alloc(false);
10903
10904 /* delay attaching until all operations are completed */
10905 sep_ctn = ctn;
10906 sep_key = NULL;
10907 sep_val = val;
10908
10909 /* move to next token */
10910 ctn = val;
10911 val = NULL;
10912 ctn_type = YYJSON_TYPE_OBJ;
10913 token = ptr_next_token(&ptr, end, &token_len, &esc);
10914 if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
10915 }
10916
10917 /* container is object, create parent nodes */
10918 while (ptr != end) { /* not last token */
10919 key = ptr_new_key(token, token_len, esc, doc);
10920 if (!key) return_err_alloc(false);
10921 val = yyjson_mut_obj(doc);
10922 if (!val) return_err_alloc(false);
10923
10924 /* delay attaching until all operations are completed */
10925 if (!sep_ctn) {
10926 sep_ctn = ctn;
10927 sep_key = key;
10928 sep_val = val;
10929 } else {
10930 yyjson_mut_obj_add(ctn, key, val);
10931 }
10932
10933 /* move to next token */
10934 ctn = val;
10935 val = NULL;
10936 token = ptr_next_token(&ptr, end, &token_len, &esc);
10937 if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
10938 }
10939 }
10940
10941 /* JSON pointer is resolved, insert or replace target value */
10942 ctn_len = unsafe_yyjson_get_len(ctn);
10943 if (ctn_type == YYJSON_TYPE_OBJ) {
10944 if (ctx) ctx->ctn = ctn;
10945 if (!val || insert_new) {
10946 /* insert new key-value pair */
10947 key = ptr_new_key(token, token_len, esc, doc);
10948 if (unlikely(!key)) return_err_alloc(false);
10949 if (ctx) ctx->pre = ctn_len ? (yyjson_mut_val *)ctn->uni.ptr : key;
10950 unsafe_yyjson_mut_obj_add(ctn, key, new_val, ctn_len);
10951 } else {
10952 /* replace exist value */
10953 key = pre->next->next;
10954 if (ctx) ctx->pre = pre;
10955 if (ctx) ctx->old = val;
10956 yyjson_mut_obj_put(ctn, key, new_val);
10957 }
10958 } else {
10959 /* array */
10960 if (ctx && (val || idx_is_last)) ctx->ctn = ctn;
10961 if (insert_new) {
10962 /* append new value */
10963 if (val) {
10964 pre->next = new_val;
10965 new_val->next = val;
10966 if (ctx) ctx->pre = pre;
10967 unsafe_yyjson_set_len(ctn, ctn_len + 1);
10968 } else if (idx_is_last) {
10969 if (ctx) ctx->pre = ctn_len ?
10970 (yyjson_mut_val *)ctn->uni.ptr : new_val;
10971 yyjson_mut_arr_append(ctn, new_val);
10972 } else {
10973 return_err_resolve(false, token - hdr);
10974 }
10975 } else {
10976 /* replace exist value */
10977 if (!val) return_err_resolve(false, token - hdr);
10978 if (ctn_len > 1) {
10979 new_val->next = val->next;
10980 pre->next = new_val;
10981 if (ctn->uni.ptr == val) ctn->uni.ptr = new_val;
10982 } else {
10983 new_val->next = new_val;
10984 ctn->uni.ptr = new_val;
10985 pre = new_val;
10986 }
10987 if (ctx) ctx->pre = pre;
10988 if (ctx) ctx->old = val;
10989 }
10990 }
10991
10992 /* all operations are completed, attach the new components to the target */
10993 if (unlikely(sep_ctn)) {
10994 if (sep_key) yyjson_mut_obj_add(sep_ctn, sep_key, sep_val);
10995 else yyjson_mut_arr_append(sep_ctn, sep_val);
10996 }
10997 return true;
10998}
10999
11000yyjson_mut_val *unsafe_yyjson_mut_ptr_replacex(
11001 yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val,
11002 yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
11003
11004 yyjson_mut_val *cur_val;
11005 yyjson_ptr_ctx cur_ctx;
11006 memset(&cur_ctx, 0, sizeof(cur_ctx));
11007 if (!ctx) ctx = &cur_ctx;
11008 cur_val = unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err);
11009 if (!cur_val) return NULL;
11010
11011 if (yyjson_mut_is_obj(ctx->ctn)) {
11012 yyjson_mut_val *key = ctx->pre->next->next;
11013 yyjson_mut_obj_put(ctx->ctn, key, new_val);
11014 } else {
11015 yyjson_ptr_ctx_replace(ctx, new_val);
11016 }
11017 ctx->old = cur_val;
11018 return cur_val;
11019}
11020
11021yyjson_mut_val *unsafe_yyjson_mut_ptr_removex(
11022 yyjson_mut_val *val, const char *ptr, size_t len,
11023 yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
11024
11025 yyjson_mut_val *cur_val;
11026 yyjson_ptr_ctx cur_ctx;
11027 memset(&cur_ctx, 0, sizeof(cur_ctx));
11028 if (!ctx) ctx = &cur_ctx;
11029 cur_val = unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err);
11030 if (cur_val) {
11031 if (yyjson_mut_is_obj(ctx->ctn)) {
11032 yyjson_mut_val *key = ctx->pre->next->next;
11033 yyjson_mut_obj_put(ctx->ctn, key, NULL);
11034 } else {
11035 yyjson_ptr_ctx_remove(ctx);
11036 }
11037 ctx->pre = NULL;
11038 ctx->old = cur_val;
11039 }
11040 return cur_val;
11041}
11042
11043/* macros for yyjson_ptr */
11044#undef return_err
11045#undef return_err_resolve
11046#undef return_err_syntax
11047#undef return_err_alloc
11048
11049
11050
11051/*==============================================================================
11052 * MARK: - JSON Patch API (RFC 6902) (Public)
11053 *============================================================================*/
11054
11055/* JSON Patch operation */
11056typedef enum patch_op {
11057 PATCH_OP_ADD, /* path, value */
11058 PATCH_OP_REMOVE, /* path */
11059 PATCH_OP_REPLACE, /* path, value */
11060 PATCH_OP_MOVE, /* from, path */
11061 PATCH_OP_COPY, /* from, path */
11062 PATCH_OP_TEST, /* path, value */
11063 PATCH_OP_NONE /* invalid */
11064} patch_op;
11065
11066static patch_op patch_op_get(yyjson_val *op) {
11067 const char *str = op->uni.str;
11068 switch (unsafe_yyjson_get_len(op)) {
11069 case 3:
11070 if (!memcmp(str, "add", 3)) return PATCH_OP_ADD;
11071 return PATCH_OP_NONE;
11072 case 4:
11073 if (!memcmp(str, "move", 4)) return PATCH_OP_MOVE;
11074 if (!memcmp(str, "copy", 4)) return PATCH_OP_COPY;
11075 if (!memcmp(str, "test", 4)) return PATCH_OP_TEST;
11076 return PATCH_OP_NONE;
11077 case 6:
11078 if (!memcmp(str, "remove", 6)) return PATCH_OP_REMOVE;
11079 return PATCH_OP_NONE;
11080 case 7:
11081 if (!memcmp(str, "replace", 7)) return PATCH_OP_REPLACE;
11082 return PATCH_OP_NONE;
11083 default:
11084 return PATCH_OP_NONE;
11085 }
11086}
11087
11088/* macros for yyjson_patch */
11089#define return_err(_code, _msg) do { \
11090 if (err->ptr.code == YYJSON_PTR_ERR_MEMORY_ALLOCATION) { \
11091 err->code = YYJSON_PATCH_ERROR_MEMORY_ALLOCATION; \
11092 err->msg = _msg; \
11093 memset(&err->ptr, 0, sizeof(yyjson_ptr_err)); \
11094 } else { \
11095 err->code = YYJSON_PATCH_ERROR_##_code; \
11096 err->msg = _msg; \
11097 err->idx = iter.idx ? iter.idx - 1 : 0; \
11098 } \
11099 return NULL; \
11100} while (false)
11101
11102#define return_err_copy() \
11103 return_err(MEMORY_ALLOCATION, "failed to copy value")
11104#define return_err_key(_key) \
11105 return_err(MISSING_KEY, "missing key " _key)
11106#define return_err_val(_key) \
11107 return_err(INVALID_MEMBER, "invalid member " _key)
11108
11109#define ptr_get(_ptr) yyjson_mut_ptr_getx( \
11110 root, _ptr->uni.str, _ptr##_len, NULL, &err->ptr)
11111#define ptr_add(_ptr, _val) yyjson_mut_ptr_addx( \
11112 root, _ptr->uni.str, _ptr##_len, _val, doc, false, NULL, &err->ptr)
11113#define ptr_remove(_ptr) yyjson_mut_ptr_removex( \
11114 root, _ptr->uni.str, _ptr##_len, NULL, &err->ptr)
11115#define ptr_replace(_ptr, _val)yyjson_mut_ptr_replacex( \
11116 root, _ptr->uni.str, _ptr##_len, _val, NULL, &err->ptr)
11117
11118yyjson_mut_val *yyjson_patch(yyjson_mut_doc *doc,
11119 const yyjson_val *orig,
11120 const yyjson_val *patch,
11121 yyjson_patch_err *err) {
11122
11123 yyjson_mut_val *root;
11124 yyjson_val *obj;
11125 yyjson_arr_iter iter;
11126 yyjson_patch_err err_tmp;
11127 if (!err) err = &err_tmp;
11128 memset(err, 0, sizeof(*err));
11129 memset(&iter, 0, sizeof(iter));
11130
11131 if (unlikely(!doc || !orig || !patch)) {
11132 return_err(INVALID_PARAMETER, "input parameter is NULL");
11133 }
11134 if (unlikely(!yyjson_is_arr(patch))) {
11135 return_err(INVALID_PARAMETER, "input patch is not array");
11136 }
11137 root = yyjson_val_mut_copy(doc, orig);
11138 if (unlikely(!root)) return_err_copy();
11139
11140 /* iterate through the patch array */
11141 yyjson_arr_iter_init(patch, &iter);
11142 while ((obj = yyjson_arr_iter_next(&iter))) {
11143 patch_op op_enum;
11144 yyjson_val *op, *path, *from = NULL, *value;
11145 yyjson_mut_val *val = NULL, *test;
11146 usize path_len, from_len = 0;
11147 if (unlikely(!unsafe_yyjson_is_obj(obj))) {
11148 return_err(INVALID_OPERATION, "JSON patch operation is not object");
11149 }
11150
11151 /* get required member: op */
11152 op = yyjson_obj_get(obj, "op");
11153 if (unlikely(!op)) return_err_key("`op`");
11154 if (unlikely(!yyjson_is_str(op))) return_err_val("`op`");
11155 op_enum = patch_op_get(op);
11156
11157 /* get required member: path */
11158 path = yyjson_obj_get(obj, "path");
11159 if (unlikely(!path)) return_err_key("`path`");
11160 if (unlikely(!yyjson_is_str(path))) return_err_val("`path`");
11161 path_len = unsafe_yyjson_get_len(path);
11162
11163 /* get required member: value, from */
11164 switch ((int)op_enum) {
11165 case PATCH_OP_ADD: case PATCH_OP_REPLACE: case PATCH_OP_TEST:
11166 value = yyjson_obj_get(obj, "value");
11167 if (unlikely(!value)) return_err_key("`value`");
11168 val = yyjson_val_mut_copy(doc, value);
11169 if (unlikely(!val)) return_err_copy();
11170 break;
11171 case PATCH_OP_MOVE: case PATCH_OP_COPY:
11172 from = yyjson_obj_get(obj, "from");
11173 if (unlikely(!from)) return_err_key("`from`");
11174 if (unlikely(!yyjson_is_str(from))) return_err_val("`from`");
11175 from_len = unsafe_yyjson_get_len(from);
11176 break;
11177 default:
11178 break;
11179 }
11180
11181 /* perform an operation */
11182 switch ((int)op_enum) {
11183 case PATCH_OP_ADD: /* add(path, val) */
11184 if (unlikely(path_len == 0)) { root = val; break; }
11185 if (unlikely(!ptr_add(path, val))) {
11186 return_err(POINTER, "failed to add `path`");
11187 }
11188 break;
11189 case PATCH_OP_REMOVE: /* remove(path) */
11190 if (unlikely(!ptr_remove(path))) {
11191 return_err(POINTER, "failed to remove `path`");
11192 }
11193 break;
11194 case PATCH_OP_REPLACE: /* replace(path, val) */
11195 if (unlikely(path_len == 0)) { root = val; break; }
11196 if (unlikely(!ptr_replace(path, val))) {
11197 return_err(POINTER, "failed to replace `path`");
11198 }
11199 break;
11200 case PATCH_OP_MOVE: /* val = remove(from), add(path, val) */
11201 if (unlikely(from_len == 0 && path_len == 0)) break;
11202 val = ptr_remove(from);
11203 if (unlikely(!val)) {
11204 return_err(POINTER, "failed to remove `from`");
11205 }
11206 if (unlikely(path_len == 0)) { root = val; break; }
11207 if (unlikely(!ptr_add(path, val))) {
11208 return_err(POINTER, "failed to add `path`");
11209 }
11210 break;
11211 case PATCH_OP_COPY: /* val = get(from).copy, add(path, val) */
11212 val = ptr_get(from);
11213 if (unlikely(!val)) {
11214 return_err(POINTER, "failed to get `from`");
11215 }
11216 if (unlikely(path_len == 0)) { root = val; break; }
11217 val = yyjson_mut_val_mut_copy(doc, val);
11218 if (unlikely(!val)) return_err_copy();
11219 if (unlikely(!ptr_add(path, val))) {
11220 return_err(POINTER, "failed to add `path`");
11221 }
11222 break;
11223 case PATCH_OP_TEST: /* test = get(path), test.eq(val) */
11224 test = ptr_get(path);
11225 if (unlikely(!test)) {
11226 return_err(POINTER, "failed to get `path`");
11227 }
11228 if (unlikely(!yyjson_mut_equals(val, test))) {
11229 return_err(EQUAL, "failed to test equal");
11230 }
11231 break;
11232 default:
11233 return_err(INVALID_MEMBER, "unsupported `op`");
11234 }
11235 }
11236 return root;
11237}
11238
11239yyjson_mut_val *yyjson_mut_patch(yyjson_mut_doc *doc,
11240 const yyjson_mut_val *orig,
11241 const yyjson_mut_val *patch,
11242 yyjson_patch_err *err) {
11243 yyjson_mut_val *root, *obj;
11244 yyjson_mut_arr_iter iter;
11245 yyjson_patch_err err_tmp;
11246 if (!err) err = &err_tmp;
11247 memset(err, 0, sizeof(*err));
11248 memset(&iter, 0, sizeof(iter));
11249
11250 if (unlikely(!doc || !orig || !patch)) {
11251 return_err(INVALID_PARAMETER, "input parameter is NULL");
11252 }
11253 if (unlikely(!yyjson_mut_is_arr(patch))) {
11254 return_err(INVALID_PARAMETER, "input patch is not array");
11255 }
11256 root = yyjson_mut_val_mut_copy(doc, orig);
11257 if (unlikely(!root)) return_err_copy();
11258
11259 /* iterate through the patch array */
11260 yyjson_mut_arr_iter_init(constcast(yyjson_mut_val *)patch, &iter);
11261 while ((obj = yyjson_mut_arr_iter_next(&iter))) {
11262 patch_op op_enum;
11263 yyjson_mut_val *op, *path, *from = NULL, *value;
11264 yyjson_mut_val *val = NULL, *test;
11265 usize path_len, from_len = 0;
11266 if (!unsafe_yyjson_is_obj(obj)) {
11267 return_err(INVALID_OPERATION, "JSON patch operation is not object");
11268 }
11269
11270 /* get required member: op */
11271 op = yyjson_mut_obj_get(obj, "op");
11272 if (unlikely(!op)) return_err_key("`op`");
11273 if (unlikely(!yyjson_mut_is_str(op))) return_err_val("`op`");
11274 op_enum = patch_op_get((yyjson_val *)(void *)op);
11275
11276 /* get required member: path */
11277 path = yyjson_mut_obj_get(obj, "path");
11278 if (unlikely(!path)) return_err_key("`path`");
11279 if (unlikely(!yyjson_mut_is_str(path))) return_err_val("`path`");
11280 path_len = unsafe_yyjson_get_len(path);
11281
11282 /* get required member: value, from */
11283 switch ((int)op_enum) {
11284 case PATCH_OP_ADD: case PATCH_OP_REPLACE: case PATCH_OP_TEST:
11285 value = yyjson_mut_obj_get(obj, "value");
11286 if (unlikely(!value)) return_err_key("`value`");
11287 val = yyjson_mut_val_mut_copy(doc, value);
11288 if (unlikely(!val)) return_err_copy();
11289 break;
11290 case PATCH_OP_MOVE: case PATCH_OP_COPY:
11291 from = yyjson_mut_obj_get(obj, "from");
11292 if (unlikely(!from)) return_err_key("`from`");
11293 if (unlikely(!yyjson_mut_is_str(from))) {
11294 return_err_val("`from`");
11295 }
11296 from_len = unsafe_yyjson_get_len(from);
11297 break;
11298 default:
11299 break;
11300 }
11301
11302 /* perform an operation */
11303 switch ((int)op_enum) {
11304 case PATCH_OP_ADD: /* add(path, val) */
11305 if (unlikely(path_len == 0)) { root = val; break; }
11306 if (unlikely(!ptr_add(path, val))) {
11307 return_err(POINTER, "failed to add `path`");
11308 }
11309 break;
11310 case PATCH_OP_REMOVE: /* remove(path) */
11311 if (unlikely(!ptr_remove(path))) {
11312 return_err(POINTER, "failed to remove `path`");
11313 }
11314 break;
11315 case PATCH_OP_REPLACE: /* replace(path, val) */
11316 if (unlikely(path_len == 0)) { root = val; break; }
11317 if (unlikely(!ptr_replace(path, val))) {
11318 return_err(POINTER, "failed to replace `path`");
11319 }
11320 break;
11321 case PATCH_OP_MOVE: /* val = remove(from), add(path, val) */
11322 if (unlikely(from_len == 0 && path_len == 0)) break;
11323 val = ptr_remove(from);
11324 if (unlikely(!val)) {
11325 return_err(POINTER, "failed to remove `from`");
11326 }
11327 if (unlikely(path_len == 0)) { root = val; break; }
11328 if (unlikely(!ptr_add(path, val))) {
11329 return_err(POINTER, "failed to add `path`");
11330 }
11331 break;
11332 case PATCH_OP_COPY: /* val = get(from).copy, add(path, val) */
11333 val = ptr_get(from);
11334 if (unlikely(!val)) {
11335 return_err(POINTER, "failed to get `from`");
11336 }
11337 if (unlikely(path_len == 0)) { root = val; break; }
11338 val = yyjson_mut_val_mut_copy(doc, val);
11339 if (unlikely(!val)) return_err_copy();
11340 if (unlikely(!ptr_add(path, val))) {
11341 return_err(POINTER, "failed to add `path`");
11342 }
11343 break;
11344 case PATCH_OP_TEST: /* test = get(path), test.eq(val) */
11345 test = ptr_get(path);
11346 if (unlikely(!test)) {
11347 return_err(POINTER, "failed to get `path`");
11348 }
11349 if (unlikely(!yyjson_mut_equals(val, test))) {
11350 return_err(EQUAL, "failed to test equal");
11351 }
11352 break;
11353 default:
11354 return_err(INVALID_MEMBER, "unsupported `op`");
11355 }
11356 }
11357 return root;
11358}
11359
11360/* macros for yyjson_patch */
11361#undef return_err
11362#undef return_err_copy
11363#undef return_err_key
11364#undef return_err_val
11365#undef ptr_get
11366#undef ptr_add
11367#undef ptr_remove
11368#undef ptr_replace
11369
11370
11371
11372/*==============================================================================
11373 * MARK: - JSON Merge-Patch API (RFC 7386) (Public)
11374 *============================================================================*/
11375
11376yyjson_mut_val *yyjson_merge_patch(yyjson_mut_doc *doc,
11377 const yyjson_val *orig,
11378 const yyjson_val *patch) {
11379 usize idx, max;
11380 yyjson_val *key, *orig_val, *patch_val, local_orig;
11381 yyjson_mut_val *builder, *mut_key, *mut_val, *merged_val;
11382
11383 if (unlikely(!yyjson_is_obj(patch))) {
11384 return yyjson_val_mut_copy(doc, patch);
11385 }
11386
11387 builder = yyjson_mut_obj(doc);
11388 if (unlikely(!builder)) return NULL;
11389
11390 memset(&local_orig, 0, sizeof(local_orig));
11391 if (!yyjson_is_obj(orig)) {
11392 local_orig.tag = builder->tag;
11393 local_orig.uni = builder->uni;
11394 orig = &local_orig;
11395 }
11396
11397 /* If orig is contributing, copy any items not modified by the patch */
11398 if (orig != &local_orig) {
11399 yyjson_obj_foreach(orig, idx, max, key, orig_val) {
11400 patch_val = yyjson_obj_getn(patch,
11401 unsafe_yyjson_get_str(key),
11402 unsafe_yyjson_get_len(key));
11403 if (!patch_val) {
11404 mut_key = yyjson_val_mut_copy(doc, key);
11405 mut_val = yyjson_val_mut_copy(doc, orig_val);
11406 if (!yyjson_mut_obj_add(builder, mut_key, mut_val)) return NULL;
11407 }
11408 }
11409 }
11410
11411 /* Merge items modified by the patch. */
11412 yyjson_obj_foreach(patch, idx, max, key, patch_val) {
11413 /* null indicates the field is removed. */
11414 if (unsafe_yyjson_is_null(patch_val)) {
11415 continue;
11416 }
11417 mut_key = yyjson_val_mut_copy(doc, key);
11418 orig_val = yyjson_obj_getn(orig,
11419 unsafe_yyjson_get_str(key),
11420 unsafe_yyjson_get_len(key));
11421 merged_val = yyjson_merge_patch(doc, orig_val, patch_val);
11422 if (!yyjson_mut_obj_add(builder, mut_key, merged_val)) return NULL;
11423 }
11424
11425 return builder;
11426}
11427
11428yyjson_mut_val *yyjson_mut_merge_patch(yyjson_mut_doc *doc,
11429 const yyjson_mut_val *orig,
11430 const yyjson_mut_val *patch) {
11431 usize idx, max;
11432 yyjson_mut_val *key, *orig_val, *patch_val, local_orig;
11433 yyjson_mut_val *builder, *mut_key, *mut_val, *merged_val;
11434
11435 if (unlikely(!yyjson_mut_is_obj(patch))) {
11436 return yyjson_mut_val_mut_copy(doc, patch);
11437 }
11438
11439 builder = yyjson_mut_obj(doc);
11440 if (unlikely(!builder)) return NULL;
11441
11442 memset(&local_orig, 0, sizeof(local_orig));
11443 if (!yyjson_mut_is_obj(orig)) {
11444 local_orig.tag = builder->tag;
11445 local_orig.uni = builder->uni;
11446 orig = &local_orig;
11447 }
11448
11449 /* If orig is contributing, copy any items not modified by the patch */
11450 if (orig != &local_orig) {
11451 yyjson_mut_obj_foreach(orig, idx, max, key, orig_val) {
11452 patch_val = yyjson_mut_obj_getn(patch,
11453 unsafe_yyjson_get_str(key),
11454 unsafe_yyjson_get_len(key));
11455 if (!patch_val) {
11456 mut_key = yyjson_mut_val_mut_copy(doc, key);
11457 mut_val = yyjson_mut_val_mut_copy(doc, orig_val);
11458 if (!yyjson_mut_obj_add(builder, mut_key, mut_val)) return NULL;
11459 }
11460 }
11461 }
11462
11463 /* Merge items modified by the patch. */
11464 yyjson_mut_obj_foreach(patch, idx, max, key, patch_val) {
11465 /* null indicates the field is removed. */
11466 if (unsafe_yyjson_is_null(patch_val)) {
11467 continue;
11468 }
11469 mut_key = yyjson_mut_val_mut_copy(doc, key);
11470 orig_val = yyjson_mut_obj_getn(orig,
11471 unsafe_yyjson_get_str(key),
11472 unsafe_yyjson_get_len(key));
11473 merged_val = yyjson_mut_merge_patch(doc, orig_val, patch_val);
11474 if (!yyjson_mut_obj_add(builder, mut_key, merged_val)) return NULL;
11475 }
11476
11477 return builder;
11478}
11479
11480#endif /* YYJSON_DISABLE_UTILS */