1/*==============================================================================
2 * Created by Yaoyuan on 2019/3/9.
3 * Copyright (C) 2019 Yaoyuan <ibireme@gmail.com>.
4 *
5 * Released under the MIT License:
6 * https://github.com/ibireme/yyjson/blob/master/LICENSE
7 *============================================================================*/
8
9#include "yyjson.h"
10#include <math.h>
11
12
13
14/*==============================================================================
15 * Compile Hint Begin
16 *============================================================================*/
17
18/* warning suppress begin */
19#if defined(__clang__)
20# pragma clang diagnostic push
21# pragma clang diagnostic ignored "-Wunused-function"
22# pragma clang diagnostic ignored "-Wunused-parameter"
23# pragma clang diagnostic ignored "-Wunused-label"
24# pragma clang diagnostic ignored "-Wunused-macros"
25#elif defined(__GNUC__)
26# if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
27# pragma GCC diagnostic push
28# endif
29# pragma GCC diagnostic ignored "-Wunused-function"
30# pragma GCC diagnostic ignored "-Wunused-parameter"
31# pragma GCC diagnostic ignored "-Wunused-label"
32# pragma GCC diagnostic ignored "-Wunused-macros"
33#elif defined(_MSC_VER)
34# pragma warning(push)
35# pragma warning(disable:4100) /* unreferenced formal parameter */
36# pragma warning(disable:4102) /* unreferenced label */
37# pragma warning(disable:4127) /* conditional expression is constant */
38# pragma warning(disable:4706) /* assignment within conditional expression */
39#endif
40
41
42
43/*==============================================================================
44 * Version
45 *============================================================================*/
46
47uint32_t yyjson_version(void) {
48 return YYJSON_VERSION_HEX;
49}
50
51
52
53/*==============================================================================
54 * Flags
55 *============================================================================*/
56
57/* gcc version check */
58#if defined(__GNUC__)
59# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
60# define yyjson_gcc_available(major, minor, patch) \
61 ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) \
62 >= (major * 10000 + minor * 100 + patch))
63# elif defined(__GNUC_MINOR__)
64# define yyjson_gcc_available(major, minor, patch) \
65 ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100) \
66 >= (major * 10000 + minor * 100 + patch))
67# else
68# define yyjson_gcc_available(major, minor, patch) \
69 ((__GNUC__ * 10000) >= (major * 10000 + minor * 100 + patch))
70# endif
71#else
72# define yyjson_gcc_available(major, minor, patch) 0
73#endif
74
75/* real gcc check */
76#if !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__ICC) && \
77 defined(__GNUC__) && defined(__GNUC_MINOR__)
78# define YYJSON_IS_REAL_GCC 1
79#else
80# define YYJSON_IS_REAL_GCC 0
81#endif
82
83/* msvc intrinsic */
84#if YYJSON_MSC_VER >= 1400
85# include <intrin.h>
86# if defined(_M_AMD64) || defined(_M_ARM64)
87# define MSC_HAS_BIT_SCAN_64 1
88# pragma intrinsic(_BitScanForward64)
89# pragma intrinsic(_BitScanReverse64)
90# else
91# define MSC_HAS_BIT_SCAN_64 0
92# endif
93# if defined(_M_AMD64) || defined(_M_ARM64) || \
94 defined(_M_IX86) || defined(_M_ARM)
95# define MSC_HAS_BIT_SCAN 1
96# pragma intrinsic(_BitScanForward)
97# pragma intrinsic(_BitScanReverse)
98# else
99# define MSC_HAS_BIT_SCAN 0
100# endif
101# if defined(_M_AMD64)
102# define MSC_HAS_UMUL128 1
103# pragma intrinsic(_umul128)
104# else
105# define MSC_HAS_UMUL128 0
106# endif
107#else
108# define MSC_HAS_BIT_SCAN_64 0
109# define MSC_HAS_BIT_SCAN 0
110# define MSC_HAS_UMUL128 0
111#endif
112
113/* gcc builtin */
114#if yyjson_has_builtin(__builtin_clzll) || yyjson_gcc_available(3, 4, 0)
115# define GCC_HAS_CLZLL 1
116#else
117# define GCC_HAS_CLZLL 0
118#endif
119
120#if yyjson_has_builtin(__builtin_ctzll) || yyjson_gcc_available(3, 4, 0)
121# define GCC_HAS_CTZLL 1
122#else
123# define GCC_HAS_CTZLL 0
124#endif
125
126/* int128 type */
127#if defined(__SIZEOF_INT128__) && (__SIZEOF_INT128__ == 16) && \
128 (defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER))
129# define YYJSON_HAS_INT128 1
130#else
131# define YYJSON_HAS_INT128 0
132#endif
133
134/* IEEE 754 floating-point binary representation */
135#if defined(__STDC_IEC_559__) || defined(__STDC_IEC_60559_BFP__)
136# define YYJSON_HAS_IEEE_754 1
137#elif (FLT_RADIX == 2) && (DBL_MANT_DIG == 53) && (DBL_DIG == 15) && \
138 (DBL_MIN_EXP == -1021) && (DBL_MAX_EXP == 1024) && \
139 (DBL_MIN_10_EXP == -307) && (DBL_MAX_10_EXP == 308)
140# define YYJSON_HAS_IEEE_754 1
141#else
142# define YYJSON_HAS_IEEE_754 0
143#endif
144
145/*
146 Correct rounding in double number computations.
147
148 On the x86 architecture, some compilers may use x87 FPU instructions for
149 floating-point arithmetic. The x87 FPU loads all floating point number as
150 80-bit double-extended precision internally, then rounds the result to original
151 precision, which may produce inaccurate results. For a more detailed
152 explanation, see the paper: https://arxiv.org/abs/cs/0701192
153
154 Here are some examples of double precision calculation error:
155
156 2877.0 / 1e6 == 0.002877, but x87 returns 0.0028770000000000002
157 43683.0 * 1e21 == 4.3683e25, but x87 returns 4.3683000000000004e25
158
159 Here are some examples of compiler flags to generate x87 instructions on x86:
160
161 clang -m32 -mno-sse
162 gcc/icc -m32 -mfpmath=387
163 msvc /arch:SSE or /arch:IA32
164
165 If we are sure that there's no similar error described above, we can define the
166 YYJSON_DOUBLE_MATH_CORRECT as 1 to enable the fast path calculation. This is
167 not an accurate detection, it's just try to avoid the error at compile-time.
168 An accurate detection can be done at run-time:
169
170 bool is_double_math_correct(void) {
171 volatile double r = 43683.0;
172 r *= 1e21;
173 return r == 4.3683e25;
174 }
175
176 See also: utils.h in https://github.com/google/double-conversion/
177 */
178#if !defined(FLT_EVAL_METHOD) && defined(__FLT_EVAL_METHOD__)
179# define FLT_EVAL_METHOD __FLT_EVAL_METHOD__
180#endif
181
182#if defined(FLT_EVAL_METHOD) && FLT_EVAL_METHOD != 0 && FLT_EVAL_METHOD != 1
183# define YYJSON_DOUBLE_MATH_CORRECT 0
184#elif defined(i386) || defined(__i386) || defined(__i386__) || \
185 defined(_X86_) || defined(__X86__) || defined(_M_IX86) || \
186 defined(__I86__) || defined(__IA32__) || defined(__THW_INTEL)
187# if (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP == 2) || \
188 (defined(__SSE2_MATH__) && __SSE2_MATH__)
189# define YYJSON_DOUBLE_MATH_CORRECT 1
190# else
191# define YYJSON_DOUBLE_MATH_CORRECT 0
192# endif
193#elif defined(__mc68000__) || defined(__pnacl__) || defined(__native_client__)
194# define YYJSON_DOUBLE_MATH_CORRECT 0
195#else
196# define YYJSON_DOUBLE_MATH_CORRECT 1
197#endif
198
199/* endian */
200#if yyjson_has_include(<sys/types.h>)
201# include <sys/types.h>
202#endif
203
204#if yyjson_has_include(<endian.h>)
205# include <endian.h>
206#elif yyjson_has_include(<machine/endian.h>)
207# include <machine/endian.h>
208#elif yyjson_has_include(<sys/endian.h>)
209# include <sys/endian.h>
210#endif
211
212#define YYJSON_BIG_ENDIAN 4321
213#define YYJSON_LITTLE_ENDIAN 1234
214
215#if defined(__BYTE_ORDER__) && __BYTE_ORDER__
216# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
217# define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
218# elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
219# define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
220# endif
221
222#elif defined(__BYTE_ORDER) && __BYTE_ORDER
223# if __BYTE_ORDER == __BIG_ENDIAN
224# define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
225# elif __BYTE_ORDER == __LITTLE_ENDIAN
226# define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
227# endif
228
229#elif defined(BYTE_ORDER) && BYTE_ORDER
230# if BYTE_ORDER == BIG_ENDIAN
231# define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
232# elif BYTE_ORDER == LITTLE_ENDIAN
233# define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
234# endif
235
236#elif (defined(__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__ == 1) || \
237 defined(__i386) || defined(__i386__) || \
238 defined(_X86_) || defined(__X86__) || \
239 defined(_M_IX86) || defined(__THW_INTEL__) || \
240 defined(__x86_64) || defined(__x86_64__) || \
241 defined(__amd64) || defined(__amd64__) || \
242 defined(_M_AMD64) || defined(_M_X64) || \
243 defined(__ia64) || defined(_IA64) || defined(__IA64__) || \
244 defined(__ia64__) || defined(_M_IA64) || defined(__itanium__) || \
245 defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \
246 defined(__alpha) || defined(__alpha__) || defined(_M_ALPHA) || \
247 defined(__riscv) || defined(__riscv__) || \
248 defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || \
249 defined(__EMSCRIPTEN__) || defined(__wasm__) || \
250 defined(__loongarch__)
251# define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
252
253#elif (defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ == 1) || \
254 defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \
255 defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) || \
256 defined(_ARCH_PPC) || defined(_ARCH_PPC64) || \
257 defined(__ppc) || defined(__ppc__) || \
258 defined(__sparc) || defined(__sparc__) || defined(__sparc64__) || \
259 defined(__or1k__) || defined(__OR1K__)
260# define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
261
262#else
263# define YYJSON_ENDIAN 0 /* unknown endian, detect at run-time */
264#endif
265
266/*
267 Unaligned memory access detection.
268
269 Some architectures cannot perform unaligned memory access, or unaligned memory
270 accesses can have a large performance penalty. Modern compilers can make some
271 optimizations for unaligned access. For example: https://godbolt.org/z/Ejo3Pa
272
273 typedef struct { char c[2] } vec2;
274 void copy_vec2(vec2 *dst, vec2 *src) {
275 *dst = *src;
276 }
277
278 Compiler may generate `load/store` or `move` instruction if target architecture
279 supports unaligned access, otherwise it may generate `call memcpy` instruction.
280
281 We want to avoid `memcpy` calls, so we should disable unaligned access by
282 define `YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS` as 1 on these architectures.
283 */
284#ifndef YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
285# if defined(i386) || defined(__i386) || defined(__i386__) || \
286 defined(__i486__) || defined(__i586__) || defined(__i686__) || \
287 defined(_X86_) || defined(__X86__) || defined(_M_IX86) || \
288 defined(__I86__) || defined(__IA32__) || \
289 defined(__THW_INTEL) || defined(__THW_INTEL__) || \
290 defined(__x86_64) || defined(__x86_64__) || \
291 defined(__amd64) || defined(__amd64__) || \
292 defined(_M_AMD64) || defined(_M_X64)
293# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 0 /* x86 */
294
295# elif defined(__ia64) || defined(_IA64) || defined(__IA64__) || \
296 defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
297# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* Itanium */
298
299# elif defined(__arm64) || defined(__arm64__) || \
300 defined(__AARCH64EL__) || defined(__AARCH64EB__) || \
301 defined(__aarch64__) || defined(_M_ARM64)
302# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 0 /* ARM64 */
303
304# elif defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) || \
305 defined(__ARM_ARCH_5TEJ__) || defined(__ARM_ARCH_5TE__) || \
306 defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6KZ__) || \
307 defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6K__)
308# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* ARM */
309
310# elif defined(__ppc64__) || defined(__PPC64__) || \
311 defined(__powerpc64__) || defined(_ARCH_PPC64) || \
312 defined(__ppc) || defined(__ppc__) || defined(__PPC__) || \
313 defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) || \
314 defined(_ARCH_PPC) || defined(_M_PPC) || \
315 defined(__PPCGECKO__) || defined(__PPCBROADWAY__) || defined(_XENON)
316# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 0 /* PowerPC */
317
318# elif defined(__loongarch__)
319# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 0 /* loongarch */
320
321# else
322# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 0 /* Unknown */
323# endif
324
325#endif
326
327/*
328 Estimated initial ratio of the JSON data (data_size / value_count).
329 For example:
330
331 data: {"id":12345678,"name":"Harry"}
332 data_size: 30
333 value_count: 5
334 ratio: 6
335
336 yyjson uses dynamic memory with a growth factor of 1.5 when reading and writing
337 JSON, the ratios below are used to determine the initial memory size.
338
339 A too large ratio will waste memory, and a too small ratio will cause multiple
340 memory growths and degrade performance. Currently, these ratios are generated
341 with some commonly used JSON datasets.
342 */
343#define YYJSON_READER_ESTIMATED_PRETTY_RATIO 16
344#define YYJSON_READER_ESTIMATED_MINIFY_RATIO 6
345#define YYJSON_WRITER_ESTIMATED_PRETTY_RATIO 32
346#define YYJSON_WRITER_ESTIMATED_MINIFY_RATIO 18
347
348/* The initial and maximum size of the memory pool's chunk in yyjson_mut_doc. */
349#define YYJSON_MUT_DOC_STR_POOL_INIT_SIZE 0x100
350#define YYJSON_MUT_DOC_STR_POOL_MAX_SIZE 0x10000000
351#define YYJSON_MUT_DOC_VAL_POOL_INIT_SIZE (0x10 * sizeof(yyjson_mut_val))
352#define YYJSON_MUT_DOC_VAL_POOL_MAX_SIZE (0x1000000 * sizeof(yyjson_mut_val))
353
354/* Default value for compile-time options. */
355#ifndef YYJSON_DISABLE_READER
356#define YYJSON_DISABLE_READER 0
357#endif
358#ifndef YYJSON_DISABLE_WRITER
359#define YYJSON_DISABLE_WRITER 0
360#endif
361#ifndef YYJSON_DISABLE_UTILS
362#define YYJSON_DISABLE_UTILS 0
363#endif
364#ifndef YYJSON_DISABLE_FAST_FP_CONV
365#define YYJSON_DISABLE_FAST_FP_CONV 0
366#endif
367#ifndef YYJSON_DISABLE_NON_STANDARD
368#define YYJSON_DISABLE_NON_STANDARD 0
369#endif
370
371
372
373/*==============================================================================
374 * Macros
375 *============================================================================*/
376
377/* Macros used for loop unrolling and other purpose. */
378#define repeat2(x) { x x }
379#define repeat3(x) { x x x }
380#define repeat4(x) { x x x x }
381#define repeat8(x) { x x x x x x x x }
382#define repeat16(x) { x x x x x x x x x x x x x x x x }
383
384#define repeat2_incr(x) { x(0) x(1) }
385#define repeat4_incr(x) { x(0) x(1) x(2) x(3) }
386#define repeat8_incr(x) { x(0) x(1) x(2) x(3) x(4) x(5) x(6) x(7) }
387#define repeat16_incr(x) { x(0) x(1) x(2) x(3) x(4) x(5) x(6) x(7) \
388 x(8) x(9) x(10) x(11) x(12) x(13) x(14) x(15) }
389
390#define repeat_in_1_18(x) { x(1) x(2) x(3) x(4) x(5) x(6) x(7) x(8) \
391 x(9) x(10) x(11) x(12) x(13) x(14) x(15) x(16) \
392 x(17) x(18) }
393
394/* Macros used to provide branch prediction information for compiler. */
395#undef likely
396#define likely(x) yyjson_likely(x)
397#undef unlikely
398#define unlikely(x) yyjson_unlikely(x)
399
400/* Macros used to provide inline information for compiler. */
401#undef static_inline
402#define static_inline static yyjson_inline
403#undef static_noinline
404#define static_noinline static yyjson_noinline
405
406/* Macros for min and max. */
407#undef yyjson_min
408#define yyjson_min(x, y) ((x) < (y) ? (x) : (y))
409#undef yyjson_max
410#define yyjson_max(x, y) ((x) > (y) ? (x) : (y))
411
412/* Used to write u64 literal for C89 which doesn't support "ULL" suffix. */
413#undef U64
414#define U64(hi, lo) ((((u64)hi##UL) << 32U) + lo##UL)
415
416/* Used to cast away (remove) const qualifier. */
417#define constcast(type) (type)(void *)(size_t)(const void *)
418
419
420
421/*==============================================================================
422 * Integer Constants
423 *============================================================================*/
424
425/* U64 constant values */
426#undef U64_MAX
427#define U64_MAX U64(0xFFFFFFFF, 0xFFFFFFFF)
428#undef I64_MAX
429#define I64_MAX U64(0x7FFFFFFF, 0xFFFFFFFF)
430#undef USIZE_MAX
431#define USIZE_MAX ((usize)(~(usize)0))
432
433/* Maximum number of digits for reading u32/u64/usize safety (not overflow). */
434#undef U32_SAFE_DIG
435#define U32_SAFE_DIG 9 /* u32 max is 4294967295, 10 digits */
436#undef U64_SAFE_DIG
437#define U64_SAFE_DIG 19 /* u64 max is 18446744073709551615, 20 digits */
438#undef USIZE_SAFE_DIG
439#define USIZE_SAFE_DIG (sizeof(usize) == 64 ? U64_SAFE_DIG : U32_SAFE_DIG)
440
441
442
443/*==============================================================================
444 * IEEE-754 Double Number Constants
445 *============================================================================*/
446
447/* Inf raw value (positive) */
448#define F64_RAW_INF U64(0x7FF00000, 0x00000000)
449
450/* NaN raw value (quiet NaN, no payload, no sign) */
451#if defined(__hppa__) || (defined(__mips__) && !defined(__mips_nan2008))
452#define F64_RAW_NAN U64(0x7FF7FFFF, 0xFFFFFFFF)
453#else
454#define F64_RAW_NAN U64(0x7FF80000, 0x00000000)
455#endif
456
457/* double number bits */
458#define F64_BITS 64
459
460/* double number exponent part bits */
461#define F64_EXP_BITS 11
462
463/* double number significand part bits */
464#define F64_SIG_BITS 52
465
466/* double number significand part bits (with 1 hidden bit) */
467#define F64_SIG_FULL_BITS 53
468
469/* double number significand bit mask */
470#define F64_SIG_MASK U64(0x000FFFFF, 0xFFFFFFFF)
471
472/* double number exponent bit mask */
473#define F64_EXP_MASK U64(0x7FF00000, 0x00000000)
474
475/* double number exponent bias */
476#define F64_EXP_BIAS 1023
477
478/* double number significant digits count in decimal */
479#define F64_DEC_DIG 17
480
481/* max significant digits count in decimal when reading double number */
482#define F64_MAX_DEC_DIG 768
483
484/* maximum decimal power of double number (1.7976931348623157e308) */
485#define F64_MAX_DEC_EXP 308
486
487/* minimum decimal power of double number (4.9406564584124654e-324) */
488#define F64_MIN_DEC_EXP (-324)
489
490/* maximum binary power of double number */
491#define F64_MAX_BIN_EXP 1024
492
493/* minimum binary power of double number */
494#define F64_MIN_BIN_EXP (-1021)
495
496
497
498/*==============================================================================
499 * Types
500 *============================================================================*/
501
502/** Type define for primitive types. */
503typedef float f32;
504typedef double f64;
505typedef int8_t i8;
506typedef uint8_t u8;
507typedef int16_t i16;
508typedef uint16_t u16;
509typedef int32_t i32;
510typedef uint32_t u32;
511typedef int64_t i64;
512typedef uint64_t u64;
513typedef size_t usize;
514
515/** 128-bit integer, used by floating-point number reader and writer. */
516#if YYJSON_HAS_INT128
517__extension__ typedef __int128 i128;
518__extension__ typedef unsigned __int128 u128;
519#endif
520
521/** 16/32/64-bit vector */
522typedef struct v16 { char c1, c2; } v16;
523typedef struct v32 { char c1, c2, c3, c4; } v32;
524typedef struct v64 { char c1, c2, c3, c4, c5, c6, c7, c8; } v64;
525
526/** 16/32/64-bit vector union, used for unaligned memory access on modern CPU */
527typedef union v16_uni { v16 v; u16 u; } v16_uni;
528typedef union v32_uni { v32 v; u32 u; } v32_uni;
529typedef union v64_uni { v64 v; u64 u; } v64_uni;
530
531
532
533/*==============================================================================
534 * Load/Store Utils
535 *============================================================================*/
536
537#define byte_move_idx(x) ((u8 *)dst)[x] = ((u8 *)src)[x];
538
539static_inline void byte_move_2(void *dst, const void *src) {
540#if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
541 repeat2_incr(byte_move_idx)
542#else
543 memmove(dst, src, 2);
544#endif
545}
546
547static_inline void byte_move_4(void *dst, const void *src) {
548#if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
549 repeat4_incr(byte_move_idx)
550#else
551 memmove(dst, src, 4);
552#endif
553}
554
555static_inline void byte_move_8(void *dst, const void *src) {
556#if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
557 repeat8_incr(byte_move_idx)
558#else
559 memmove(dst, src, 8);
560#endif
561}
562
563static_inline void byte_move_16(void *dst, const void *src) {
564#if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
565 repeat16_incr(byte_move_idx)
566#else
567 memmove(dst, src, 16);
568#endif
569}
570
571static_inline void byte_copy_2(void *dst, const void *src) {
572#if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
573 repeat2_incr(byte_move_idx)
574#else
575 memcpy(dst, src, 2);
576#endif
577}
578
579static_inline void byte_copy_4(void *dst, const void *src) {
580#if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
581 repeat4_incr(byte_move_idx)
582#else
583 memcpy(dst, src, 4);
584#endif
585}
586
587static_inline void byte_copy_8(void *dst, const void *src) {
588#if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
589 repeat8_incr(byte_move_idx)
590#else
591 memcpy(dst, src, 8);
592#endif
593}
594
595static_inline void byte_copy_16(void *dst, const void *src) {
596#if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
597 repeat16_incr(byte_move_idx)
598#else
599 memcpy(dst, src, 16);
600#endif
601}
602
603static_inline bool byte_match_2(void *buf, const char *pat) {
604#if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
605 return
606 ((u8 *)buf)[0] == ((const u8 *)pat)[0] &&
607 ((u8 *)buf)[1] == ((const u8 *)pat)[1];
608#else
609 v16_uni u1, u2;
610 u1.v = *(const v16 *)pat;
611 u2.v = *(const v16 *)buf;
612 return u1.u == u2.u;
613#endif
614}
615
616static_inline bool byte_match_4(void *buf, const char *pat) {
617#if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
618 return
619 ((u8 *)buf)[0] == ((const u8 *)pat)[0] &&
620 ((u8 *)buf)[1] == ((const u8 *)pat)[1] &&
621 ((u8 *)buf)[2] == ((const u8 *)pat)[2] &&
622 ((u8 *)buf)[3] == ((const u8 *)pat)[3];
623#else
624 v32_uni u1, u2;
625 u1.v = *(const v32 *)pat;
626 u2.v = *(const v32 *)buf;
627 return u1.u == u2.u;
628#endif
629}
630
631static_inline u16 byte_load_2(const void *src) {
632 v16_uni uni;
633 uni.v = *(const v16 *)src;
634 return uni.u;
635}
636
637static_inline u32 byte_load_3(const void *src) {
638 v32_uni uni;
639 ((v16_uni *)&uni)->v = *(const v16 *)src;
640 uni.v.c3 = ((const char *)src)[2];
641 uni.v.c4 = 0;
642 return uni.u;
643}
644
645static_inline u32 byte_load_4(const void *src) {
646 v32_uni uni;
647 uni.v = *(const v32 *)src;
648 return uni.u;
649}
650
651#undef byte_move_expr
652
653
654
655/*==============================================================================
656 * Number Utils
657 * These functions are used to detect and convert NaN and Inf numbers.
658 *============================================================================*/
659
660/**
661 This union is used to avoid violating the strict aliasing rule in C.
662 `memcpy` can be used in both C and C++, but it may reduce performance without
663 compiler optimization.
664 */
665typedef union { u64 u; f64 f; } f64_uni;
666
667/** Convert raw binary to double. */
668static_inline f64 f64_from_raw(u64 u) {
669#ifndef __cplusplus
670 f64_uni uni;
671 uni.u = u;
672 return uni.f;
673#else
674 f64 f;
675 memcpy(&f, &u, 8);
676 return f;
677#endif
678}
679
680/** Convert double to raw binary. */
681static_inline u64 f64_to_raw(f64 f) {
682#ifndef __cplusplus
683 f64_uni uni;
684 uni.f = f;
685 return uni.u;
686#else
687 u64 u;
688 memcpy(&u, &f, 8);
689 return u;
690#endif
691}
692
693/** Get raw 'infinity' with sign. */
694static_inline u64 f64_raw_get_inf(bool sign) {
695#if YYJSON_HAS_IEEE_754
696 return F64_RAW_INF | ((u64)sign << 63);
697#elif defined(INFINITY)
698 return f64_to_raw(sign ? -INFINITY : INFINITY);
699#else
700 return f64_to_raw(sign ? -HUGE_VAL : HUGE_VAL);
701#endif
702}
703
704/** Get raw 'nan' with sign. */
705static_inline u64 f64_raw_get_nan(bool sign) {
706#if YYJSON_HAS_IEEE_754
707 return F64_RAW_NAN | ((u64)sign << 63);
708#elif defined(NAN)
709 return f64_to_raw(sign ? (f64)-NAN : (f64)NAN);
710#else
711 return f64_to_raw((sign ? -0.0 : 0.0) / 0.0);
712#endif
713}
714
715/**
716 Convert normalized u64 (highest bit is 1) to f64.
717
718 Some compiler (such as Microsoft Visual C++ 6.0) do not support converting
719 number from u64 to f64. This function will first convert u64 to i64 and then
720 to f64, with `to nearest` rounding mode.
721 */
722static_inline f64 normalized_u64_to_f64(u64 val) {
723#if YYJSON_U64_TO_F64_NO_IMPL
724 i64 sig = (i64)((val >> 1) | (val & 1));
725 return ((f64)sig) * (f64)2.0;
726#else
727 return (f64)val;
728#endif
729}
730
731
732
733/*==============================================================================
734 * Size Utils
735 * These functions are used for memory allocation.
736 *============================================================================*/
737
738/** Returns whether the size is overflow after increment. */
739static_inline bool size_add_is_overflow(usize size, usize add) {
740 return size > (size + add);
741}
742
743/** Returns whether the size is power of 2 (size should not be 0). */
744static_inline bool size_is_pow2(usize size) {
745 return (size & (size - 1)) == 0;
746}
747
748/** Align size upwards (may overflow). */
749static_inline usize size_align_up(usize size, usize align) {
750 if (size_is_pow2(align)) {
751 return (size + (align - 1)) & ~(align - 1);
752 } else {
753 return size + align - (size + align - 1) % align - 1;
754 }
755}
756
757/** Align size downwards. */
758static_inline usize size_align_down(usize size, usize align) {
759 if (size_is_pow2(align)) {
760 return size & ~(align - 1);
761 } else {
762 return size - (size % align);
763 }
764}
765
766/** Align address upwards (may overflow). */
767static_inline void *mem_align_up(void *mem, usize align) {
768 usize size;
769 memcpy(&size, &mem, sizeof(usize));
770 size = size_align_up(size, align);
771 memcpy(&mem, &size, sizeof(usize));
772 return mem;
773}
774
775
776
777/*==============================================================================
778 * Bits Utils
779 * These functions are used by the floating-point number reader and writer.
780 *============================================================================*/
781
782/** Returns the number of leading 0-bits in value (input should not be 0). */
783static_inline u32 u64_lz_bits(u64 v) {
784#if GCC_HAS_CLZLL
785 return (u32)__builtin_clzll(v);
786#elif MSC_HAS_BIT_SCAN_64
787 unsigned long r;
788 _BitScanReverse64(&r, v);
789 return (u32)63 - (u32)r;
790#elif MSC_HAS_BIT_SCAN
791 unsigned long hi, lo;
792 bool hi_set = _BitScanReverse(&hi, (u32)(v >> 32)) != 0;
793 _BitScanReverse(&lo, (u32)v);
794 hi |= 32;
795 return (u32)63 - (u32)(hi_set ? hi : lo);
796#else
797 /*
798 branchless, use de Bruijn sequences
799 see: https://www.chessprogramming.org/BitScan
800 */
801 const u8 table[64] = {
802 63, 16, 62, 7, 15, 36, 61, 3, 6, 14, 22, 26, 35, 47, 60, 2,
803 9, 5, 28, 11, 13, 21, 42, 19, 25, 31, 34, 40, 46, 52, 59, 1,
804 17, 8, 37, 4, 23, 27, 48, 10, 29, 12, 43, 20, 32, 41, 53, 18,
805 38, 24, 49, 30, 44, 33, 54, 39, 50, 45, 55, 51, 56, 57, 58, 0
806 };
807 v |= v >> 1;
808 v |= v >> 2;
809 v |= v >> 4;
810 v |= v >> 8;
811 v |= v >> 16;
812 v |= v >> 32;
813 return table[(v * U64(0x03F79D71, 0xB4CB0A89)) >> 58];
814#endif
815}
816
817/** Returns the number of trailing 0-bits in value (input should not be 0). */
818static_inline u32 u64_tz_bits(u64 v) {
819#if GCC_HAS_CTZLL
820 return (u32)__builtin_ctzll(v);
821#elif MSC_HAS_BIT_SCAN_64
822 unsigned long r;
823 _BitScanForward64(&r, v);
824 return (u32)r;
825#elif MSC_HAS_BIT_SCAN
826 unsigned long lo, hi;
827 bool lo_set = _BitScanForward(&lo, (u32)(v)) != 0;
828 _BitScanForward(&hi, (u32)(v >> 32));
829 hi += 32;
830 return lo_set ? lo : hi;
831#else
832 /*
833 branchless, use de Bruijn sequences
834 see: https://www.chessprogramming.org/BitScan
835 */
836 const u8 table[64] = {
837 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28,
838 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11,
839 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
840 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12
841 };
842 return table[((v & (~v + 1)) * U64(0x022FDD63, 0xCC95386D)) >> 58];
843#endif
844}
845
846
847
848/*==============================================================================
849 * 128-bit Integer Utils
850 * These functions are used by the floating-point number reader and writer.
851 *============================================================================*/
852
853/** Multiplies two 64-bit unsigned integers (a * b),
854 returns the 128-bit result as 'hi' and 'lo'. */
855static_inline void u128_mul(u64 a, u64 b, u64 *hi, u64 *lo) {
856#if YYJSON_HAS_INT128
857 u128 m = (u128)a * b;
858 *hi = (u64)(m >> 64);
859 *lo = (u64)(m);
860#elif MSC_HAS_UMUL128
861 *lo = _umul128(a, b, hi);
862#else
863 u32 a0 = (u32)(a), a1 = (u32)(a >> 32);
864 u32 b0 = (u32)(b), b1 = (u32)(b >> 32);
865 u64 p00 = (u64)a0 * b0, p01 = (u64)a0 * b1;
866 u64 p10 = (u64)a1 * b0, p11 = (u64)a1 * b1;
867 u64 m0 = p01 + (p00 >> 32);
868 u32 m00 = (u32)(m0), m01 = (u32)(m0 >> 32);
869 u64 m1 = p10 + m00;
870 u32 m10 = (u32)(m1), m11 = (u32)(m1 >> 32);
871 *hi = p11 + m01 + m11;
872 *lo = ((u64)m10 << 32) | (u32)p00;
873#endif
874}
875
876/** Multiplies two 64-bit unsigned integers and add a value (a * b + c),
877 returns the 128-bit result as 'hi' and 'lo'. */
878static_inline void u128_mul_add(u64 a, u64 b, u64 c, u64 *hi, u64 *lo) {
879#if YYJSON_HAS_INT128
880 u128 m = (u128)a * b + c;
881 *hi = (u64)(m >> 64);
882 *lo = (u64)(m);
883#else
884 u64 h, l, t;
885 u128_mul(a, b, &h, &l);
886 t = l + c;
887 h += (u64)(((t < l) | (t < c)));
888 *hi = h;
889 *lo = t;
890#endif
891}
892
893
894
895/*==============================================================================
896 * File Utils
897 * These functions are used to read and write JSON files.
898 *============================================================================*/
899
900#define YYJSON_FOPEN_EXT
901#if !defined(_MSC_VER) && defined(__GLIBC__) && defined(__GLIBC_PREREQ)
902# if __GLIBC_PREREQ(2, 7)
903# undef YYJSON_FOPEN_EXT
904# define YYJSON_FOPEN_EXT "e" /* glibc extension to enable O_CLOEXEC */
905# endif
906#endif
907
908static_inline FILE *fopen_safe(const char *path, const char *mode) {
909#if YYJSON_MSC_VER >= 1400
910 FILE *file = NULL;
911 if (fopen_s(&file, path, mode) != 0) return NULL;
912 return file;
913#else
914 return fopen(path, mode);
915#endif
916}
917
918static_inline FILE *fopen_readonly(const char *path) {
919 return fopen_safe(path, "rb" YYJSON_FOPEN_EXT);
920}
921
922static_inline FILE *fopen_writeonly(const char *path) {
923 return fopen_safe(path, "wb" YYJSON_FOPEN_EXT);
924}
925
926static_inline usize fread_safe(void *buf, usize size, FILE *file) {
927#if YYJSON_MSC_VER >= 1400
928 return fread_s(buf, size, 1, size, file);
929#else
930 return fread(buf, 1, size, file);
931#endif
932}
933
934
935
936/*==============================================================================
937 * Default Memory Allocator
938 * This is a simple libc memory allocator wrapper.
939 *============================================================================*/
940
941static void *default_malloc(void *ctx, usize size) {
942 return malloc(size);
943}
944
945static void *default_realloc(void *ctx, void *ptr, usize old_size, usize size) {
946 return realloc(ptr, size);
947}
948
949static void default_free(void *ctx, void *ptr) {
950 free(ptr);
951}
952
953static const yyjson_alc YYJSON_DEFAULT_ALC = {
954 default_malloc,
955 default_realloc,
956 default_free,
957 NULL
958};
959
960static void *null_malloc(void *ctx, usize size) {
961 return NULL;
962}
963
964static void *null_realloc(void *ctx, void *ptr, usize old_size, usize size) {
965 return NULL;
966}
967
968static void null_free(void *ctx, void *ptr) {
969 return;
970}
971
972static const yyjson_alc YYJSON_NULL_ALC = {
973 null_malloc,
974 null_realloc,
975 null_free,
976 NULL
977};
978
979
980
981/*==============================================================================
982 * Pool Memory Allocator
983 * This is a simple memory allocator that uses linked list memory chunk.
984 * The following code will be executed only when the library user creates
985 * this allocator manually.
986 *============================================================================*/
987
988/** chunk header */
989typedef struct pool_chunk {
990 usize size; /* chunk memory size (include chunk header) */
991 struct pool_chunk *next;
992} pool_chunk;
993
994/** ctx header */
995typedef struct pool_ctx {
996 usize size; /* total memory size (include ctx header) */
997 pool_chunk *free_list;
998} pool_ctx;
999
1000static void *pool_malloc(void *ctx_ptr, usize size) {
1001 pool_ctx *ctx = (pool_ctx *)ctx_ptr;
1002 pool_chunk *next, *prev = NULL, *cur = ctx->free_list;
1003
1004 if (unlikely(size == 0 || size >= ctx->size)) return NULL;
1005 size = size_align_up(size, sizeof(pool_chunk)) + sizeof(pool_chunk);
1006
1007 while (cur) {
1008 if (cur->size < size) {
1009 /* not enough space, try next chunk */
1010 prev = cur;
1011 cur = cur->next;
1012 continue;
1013 }
1014 if (cur->size >= size + sizeof(pool_chunk) * 2) {
1015 /* too much space, split this chunk */
1016 next = (pool_chunk *)(void *)((u8 *)cur + size);
1017 next->size = cur->size - size;
1018 next->next = cur->next;
1019 cur->size = size;
1020 } else {
1021 /* just enough space, use whole chunk */
1022 next = cur->next;
1023 }
1024 if (prev) prev->next = next;
1025 else ctx->free_list = next;
1026 return (void *)(cur + 1);
1027 }
1028 return NULL;
1029}
1030
1031static void pool_free(void *ctx_ptr, void *ptr) {
1032 pool_ctx *ctx = (pool_ctx *)ctx_ptr;
1033 pool_chunk *cur = ((pool_chunk *)ptr) - 1;
1034 pool_chunk *prev = NULL, *next = ctx->free_list;
1035
1036 while (next && next < cur) {
1037 prev = next;
1038 next = next->next;
1039 }
1040 if (prev) prev->next = cur;
1041 else ctx->free_list = cur;
1042 cur->next = next;
1043
1044 if (next && ((u8 *)cur + cur->size) == (u8 *)next) {
1045 /* merge cur to higher chunk */
1046 cur->size += next->size;
1047 cur->next = next->next;
1048 }
1049 if (prev && ((u8 *)prev + prev->size) == (u8 *)cur) {
1050 /* merge cur to lower chunk */
1051 prev->size += cur->size;
1052 prev->next = cur->next;
1053 }
1054}
1055
1056static void *pool_realloc(void *ctx_ptr, void *ptr,
1057 usize old_size, usize size) {
1058 pool_ctx *ctx = (pool_ctx *)ctx_ptr;
1059 pool_chunk *cur = ((pool_chunk *)ptr) - 1, *prev, *next, *tmp;
1060 usize free_size;
1061 void *new_ptr;
1062
1063 if (unlikely(size == 0 || size >= ctx->size)) return NULL;
1064 size = size_align_up(size, sizeof(pool_chunk)) + sizeof(pool_chunk);
1065
1066 /* reduce size */
1067 if (unlikely(size <= cur->size)) {
1068 free_size = cur->size - size;
1069 if (free_size >= sizeof(pool_chunk) * 2) {
1070 tmp = (pool_chunk *)(void *)((u8 *)cur + cur->size - free_size);
1071 tmp->size = free_size;
1072 pool_free(ctx_ptr, (void *)(tmp + 1));
1073 cur->size -= free_size;
1074 }
1075 return ptr;
1076 }
1077
1078 /* find next and prev chunk */
1079 prev = NULL;
1080 next = ctx->free_list;
1081 while (next && next < cur) {
1082 prev = next;
1083 next = next->next;
1084 }
1085
1086 /* merge to higher chunk if they are contiguous */
1087 if ((u8 *)cur + cur->size == (u8 *)next &&
1088 cur->size + next->size >= size) {
1089 free_size = cur->size + next->size - size;
1090 if (free_size > sizeof(pool_chunk) * 2) {
1091 tmp = (pool_chunk *)(void *)((u8 *)cur + size);
1092 if (prev) prev->next = tmp;
1093 else ctx->free_list = tmp;
1094 tmp->next = next->next;
1095 tmp->size = free_size;
1096 cur->size = size;
1097 } else {
1098 if (prev) prev->next = next->next;
1099 else ctx->free_list = next->next;
1100 cur->size += next->size;
1101 }
1102 return ptr;
1103 }
1104
1105 /* fallback to malloc and memcpy */
1106 new_ptr = pool_malloc(ctx_ptr, size - sizeof(pool_chunk));
1107 if (new_ptr) {
1108 memcpy(new_ptr, ptr, cur->size - sizeof(pool_chunk));
1109 pool_free(ctx_ptr, ptr);
1110 }
1111 return new_ptr;
1112}
1113
1114bool yyjson_alc_pool_init(yyjson_alc *alc, void *buf, usize size) {
1115 pool_chunk *chunk;
1116 pool_ctx *ctx;
1117
1118 if (unlikely(!alc)) return false;
1119 *alc = YYJSON_NULL_ALC;
1120 if (size < sizeof(pool_ctx) * 4) return false;
1121 ctx = (pool_ctx *)mem_align_up(buf, sizeof(pool_ctx));
1122 if (unlikely(!ctx)) return false;
1123 size -= (usize)((u8 *)ctx - (u8 *)buf);
1124 size = size_align_down(size, sizeof(pool_ctx));
1125
1126 chunk = (pool_chunk *)(ctx + 1);
1127 chunk->size = size - sizeof(pool_ctx);
1128 chunk->next = NULL;
1129 ctx->size = size;
1130 ctx->free_list = chunk;
1131
1132 alc->malloc = pool_malloc;
1133 alc->realloc = pool_realloc;
1134 alc->free = pool_free;
1135 alc->ctx = (void *)ctx;
1136 return true;
1137}
1138
1139
1140
1141/*==============================================================================
1142 * JSON document and value
1143 *============================================================================*/
1144
1145static_inline void unsafe_yyjson_str_pool_release(yyjson_str_pool *pool,
1146 yyjson_alc *alc) {
1147 yyjson_str_chunk *chunk = pool->chunks, *next;
1148 while (chunk) {
1149 next = chunk->next;
1150 alc->free(alc->ctx, chunk);
1151 chunk = next;
1152 }
1153}
1154
1155static_inline void unsafe_yyjson_val_pool_release(yyjson_val_pool *pool,
1156 yyjson_alc *alc) {
1157 yyjson_val_chunk *chunk = pool->chunks, *next;
1158 while (chunk) {
1159 next = chunk->next;
1160 alc->free(alc->ctx, chunk);
1161 chunk = next;
1162 }
1163}
1164
1165bool unsafe_yyjson_str_pool_grow(yyjson_str_pool *pool,
1166 const yyjson_alc *alc, usize len) {
1167 yyjson_str_chunk *chunk;
1168 usize size, max_len;
1169
1170 /* create a new chunk */
1171 max_len = USIZE_MAX - sizeof(yyjson_str_chunk);
1172 if (unlikely(len > max_len)) return false;
1173 size = len + sizeof(yyjson_str_chunk);
1174 size = yyjson_max(pool->chunk_size, size);
1175 chunk = (yyjson_str_chunk *)alc->malloc(alc->ctx, size);
1176 if (unlikely(!chunk)) return false;
1177
1178 /* insert the new chunk as the head of the linked list */
1179 chunk->next = pool->chunks;
1180 chunk->chunk_size = size;
1181 pool->chunks = chunk;
1182 pool->cur = (char *)chunk + sizeof(yyjson_str_chunk);
1183 pool->end = (char *)chunk + size;
1184
1185 /* the next chunk is twice the size of the current one */
1186 size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max);
1187 if (size < pool->chunk_size) size = pool->chunk_size_max; /* overflow */
1188 pool->chunk_size = size;
1189 return true;
1190}
1191
1192bool unsafe_yyjson_val_pool_grow(yyjson_val_pool *pool,
1193 const yyjson_alc *alc, usize count) {
1194 yyjson_val_chunk *chunk;
1195 usize size, max_count;
1196
1197 /* create a new chunk */
1198 max_count = USIZE_MAX / sizeof(yyjson_mut_val) - 1;
1199 if (unlikely(count > max_count)) return false;
1200 size = (count + 1) * sizeof(yyjson_mut_val);
1201 size = yyjson_max(pool->chunk_size, size);
1202 chunk = (yyjson_val_chunk *)alc->malloc(alc->ctx, size);
1203 if (unlikely(!chunk)) return false;
1204
1205 /* insert the new chunk as the head of the linked list */
1206 chunk->next = pool->chunks;
1207 chunk->chunk_size = size;
1208 pool->chunks = chunk;
1209 pool->cur = (yyjson_mut_val *)(void *)((u8 *)chunk) + 1;
1210 pool->end = (yyjson_mut_val *)(void *)((u8 *)chunk + size);
1211
1212 /* the next chunk is twice the size of the current one */
1213 size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max);
1214 if (size < pool->chunk_size) size = pool->chunk_size_max; /* overflow */
1215 pool->chunk_size = size;
1216 return true;
1217}
1218
1219bool yyjson_mut_doc_set_str_pool_size(yyjson_mut_doc *doc, size_t len) {
1220 usize max_size = USIZE_MAX - sizeof(yyjson_str_chunk);
1221 if (!doc || !len || len > max_size) return false;
1222 doc->str_pool.chunk_size = len + sizeof(yyjson_str_chunk);
1223 return true;
1224}
1225
1226bool yyjson_mut_doc_set_val_pool_size(yyjson_mut_doc *doc, size_t count) {
1227 usize max_count = USIZE_MAX / sizeof(yyjson_mut_val) - 1;
1228 if (!doc || !count || count > max_count) return false;
1229 doc->val_pool.chunk_size = (count + 1) * sizeof(yyjson_mut_val);
1230 return true;
1231}
1232
1233void yyjson_mut_doc_free(yyjson_mut_doc *doc) {
1234 if (doc) {
1235 yyjson_alc alc = doc->alc;
1236 unsafe_yyjson_str_pool_release(&doc->str_pool, &alc);
1237 unsafe_yyjson_val_pool_release(&doc->val_pool, &alc);
1238 alc.free(alc.ctx, doc);
1239 }
1240}
1241
1242yyjson_mut_doc *yyjson_mut_doc_new(const yyjson_alc *alc) {
1243 yyjson_mut_doc *doc;
1244 if (!alc) alc = &YYJSON_DEFAULT_ALC;
1245 doc = (yyjson_mut_doc *)alc->malloc(alc->ctx, sizeof(yyjson_mut_doc));
1246 if (!doc) return NULL;
1247 memset(doc, 0, sizeof(yyjson_mut_doc));
1248
1249 doc->alc = *alc;
1250 doc->str_pool.chunk_size = YYJSON_MUT_DOC_STR_POOL_INIT_SIZE;
1251 doc->str_pool.chunk_size_max = YYJSON_MUT_DOC_STR_POOL_MAX_SIZE;
1252 doc->val_pool.chunk_size = YYJSON_MUT_DOC_VAL_POOL_INIT_SIZE;
1253 doc->val_pool.chunk_size_max = YYJSON_MUT_DOC_VAL_POOL_MAX_SIZE;
1254 return doc;
1255}
1256
1257yyjson_mut_doc *yyjson_doc_mut_copy(yyjson_doc *doc, const yyjson_alc *alc) {
1258 yyjson_mut_doc *m_doc;
1259 yyjson_mut_val *m_val;
1260
1261 if (!doc || !doc->root) return NULL;
1262 m_doc = yyjson_mut_doc_new(alc);
1263 if (!m_doc) return NULL;
1264 m_val = yyjson_val_mut_copy(m_doc, doc->root);
1265 if (!m_val) {
1266 yyjson_mut_doc_free(m_doc);
1267 return NULL;
1268 }
1269 yyjson_mut_doc_set_root(m_doc, m_val);
1270 return m_doc;
1271}
1272
1273yyjson_mut_doc *yyjson_mut_doc_mut_copy(yyjson_mut_doc *doc,
1274 const yyjson_alc *alc) {
1275 yyjson_mut_doc *m_doc;
1276 yyjson_mut_val *m_val;
1277
1278 if (!doc) return NULL;
1279 if (!doc->root) return yyjson_mut_doc_new(alc);
1280
1281 m_doc = yyjson_mut_doc_new(alc);
1282 if (!m_doc) return NULL;
1283 m_val = yyjson_mut_val_mut_copy(m_doc, doc->root);
1284 if (!m_val) {
1285 yyjson_mut_doc_free(m_doc);
1286 return NULL;
1287 }
1288 yyjson_mut_doc_set_root(m_doc, m_val);
1289 return m_doc;
1290}
1291
1292yyjson_mut_val *yyjson_val_mut_copy(yyjson_mut_doc *m_doc,
1293 yyjson_val *i_vals) {
1294 /*
1295 The immutable object or array stores all sub-values in a contiguous memory,
1296 We copy them to another contiguous memory as mutable values,
1297 then reconnect the mutable values with the original relationship.
1298 */
1299
1300 usize i_vals_len;
1301 yyjson_mut_val *m_vals, *m_val;
1302 yyjson_val *i_val, *i_end;
1303
1304 if (!m_doc || !i_vals) return NULL;
1305 i_end = unsafe_yyjson_get_next(i_vals);
1306 i_vals_len = (usize)(unsafe_yyjson_get_next(i_vals) - i_vals);
1307 m_vals = unsafe_yyjson_mut_val(m_doc, i_vals_len);
1308 if (!m_vals) return NULL;
1309 i_val = i_vals;
1310 m_val = m_vals;
1311
1312 for (; i_val < i_end; i_val++, m_val++) {
1313 yyjson_type type = unsafe_yyjson_get_type(i_val);
1314 m_val->tag = i_val->tag;
1315 m_val->uni.u64 = i_val->uni.u64;
1316 if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
1317 const char *str = i_val->uni.str;
1318 usize str_len = unsafe_yyjson_get_len(i_val);
1319 m_val->uni.str = unsafe_yyjson_mut_strncpy(m_doc, str, str_len);
1320 if (!m_val->uni.str) return NULL;
1321 } else if (type == YYJSON_TYPE_ARR) {
1322 usize len = unsafe_yyjson_get_len(i_val);
1323 if (len > 0) {
1324 yyjson_val *ii_val = i_val + 1, *ii_next;
1325 yyjson_mut_val *mm_val = m_val + 1, *mm_ctn = m_val, *mm_next;
1326 while (len-- > 1) {
1327 ii_next = unsafe_yyjson_get_next(ii_val);
1328 mm_next = mm_val + (ii_next - ii_val);
1329 mm_val->next = mm_next;
1330 ii_val = ii_next;
1331 mm_val = mm_next;
1332 }
1333 mm_val->next = mm_ctn + 1;
1334 mm_ctn->uni.ptr = mm_val;
1335 }
1336 } else if (type == YYJSON_TYPE_OBJ) {
1337 usize len = unsafe_yyjson_get_len(i_val);
1338 if (len > 0) {
1339 yyjson_val *ii_key = i_val + 1, *ii_nextkey;
1340 yyjson_mut_val *mm_key = m_val + 1, *mm_ctn = m_val;
1341 yyjson_mut_val *mm_nextkey;
1342 while (len-- > 1) {
1343 ii_nextkey = unsafe_yyjson_get_next(ii_key + 1);
1344 mm_nextkey = mm_key + (ii_nextkey - ii_key);
1345 mm_key->next = mm_key + 1;
1346 mm_key->next->next = mm_nextkey;
1347 ii_key = ii_nextkey;
1348 mm_key = mm_nextkey;
1349 }
1350 mm_key->next = mm_key + 1;
1351 mm_key->next->next = mm_ctn + 1;
1352 mm_ctn->uni.ptr = mm_key;
1353 }
1354 }
1355 }
1356
1357 return m_vals;
1358}
1359
1360static yyjson_mut_val *unsafe_yyjson_mut_val_mut_copy(yyjson_mut_doc *m_doc,
1361 yyjson_mut_val *m_vals) {
1362 /*
1363 The mutable object or array stores all sub-values in a circular linked
1364 list, so we can traverse them in the same loop. The traversal starts from
1365 the last item, continues with the first item in a list, and ends with the
1366 second to last item, which needs to be linked to the last item to close the
1367 circle.
1368 */
1369
1370 yyjson_mut_val *m_val = unsafe_yyjson_mut_val(m_doc, 1);
1371 if (unlikely(!m_val)) return NULL;
1372 m_val->tag = m_vals->tag;
1373
1374 switch (unsafe_yyjson_get_type(m_vals)) {
1375 case YYJSON_TYPE_OBJ:
1376 case YYJSON_TYPE_ARR:
1377 if (unsafe_yyjson_get_len(m_vals) > 0) {
1378 yyjson_mut_val *last = (yyjson_mut_val *)m_vals->uni.ptr;
1379 yyjson_mut_val *next = last->next, *prev;
1380 prev = unsafe_yyjson_mut_val_mut_copy(m_doc, last);
1381 if (!prev) return NULL;
1382 m_val->uni.ptr = (void *)prev;
1383 while (next != last) {
1384 prev->next = unsafe_yyjson_mut_val_mut_copy(m_doc, next);
1385 if (!prev->next) return NULL;
1386 prev = prev->next;
1387 next = next->next;
1388 }
1389 prev->next = (yyjson_mut_val *)m_val->uni.ptr;
1390 }
1391 break;
1392
1393 case YYJSON_TYPE_RAW:
1394 case YYJSON_TYPE_STR: {
1395 const char *str = m_vals->uni.str;
1396 usize str_len = unsafe_yyjson_get_len(m_vals);
1397 m_val->uni.str = unsafe_yyjson_mut_strncpy(m_doc, str, str_len);
1398 if (!m_val->uni.str) return NULL;
1399 break;
1400 }
1401
1402 default:
1403 m_val->uni = m_vals->uni;
1404 break;
1405 }
1406
1407 return m_val;
1408}
1409
1410yyjson_mut_val *yyjson_mut_val_mut_copy(yyjson_mut_doc *doc,
1411 yyjson_mut_val *val) {
1412 if (doc && val) return unsafe_yyjson_mut_val_mut_copy(doc, val);
1413 return NULL;
1414}
1415
1416/* Count the number of values and the total length of the strings. */
1417static void yyjson_mut_stat(yyjson_mut_val *val,
1418 usize *val_sum, usize *str_sum) {
1419 yyjson_type type = unsafe_yyjson_get_type(val);
1420 *val_sum += 1;
1421 if (type == YYJSON_TYPE_ARR || type == YYJSON_TYPE_OBJ) {
1422 yyjson_mut_val *child = (yyjson_mut_val *)val->uni.ptr;
1423 usize len = unsafe_yyjson_get_len(val), i;
1424 len <<= (u8)(type == YYJSON_TYPE_OBJ);
1425 *val_sum += len;
1426 for (i = 0; i < len; i++) {
1427 yyjson_type stype = unsafe_yyjson_get_type(child);
1428 if (stype == YYJSON_TYPE_STR || stype == YYJSON_TYPE_RAW) {
1429 *str_sum += unsafe_yyjson_get_len(child) + 1;
1430 } else if (stype == YYJSON_TYPE_ARR || stype == YYJSON_TYPE_OBJ) {
1431 yyjson_mut_stat(child, val_sum, str_sum);
1432 *val_sum -= 1;
1433 }
1434 child = child->next;
1435 }
1436 } else if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
1437 *str_sum += unsafe_yyjson_get_len(val) + 1;
1438 }
1439}
1440
1441/* Copy mutable values to immutable value pool. */
1442static usize yyjson_imut_copy(yyjson_val **val_ptr, char **buf_ptr,
1443 yyjson_mut_val *mval) {
1444 yyjson_val *val = *val_ptr;
1445 yyjson_type type = unsafe_yyjson_get_type(mval);
1446 if (type == YYJSON_TYPE_ARR || type == YYJSON_TYPE_OBJ) {
1447 yyjson_mut_val *child = (yyjson_mut_val *)mval->uni.ptr;
1448 usize len = unsafe_yyjson_get_len(mval), i;
1449 usize val_sum = 1;
1450 if (type == YYJSON_TYPE_OBJ) {
1451 if (len) child = child->next->next;
1452 len <<= 1;
1453 } else {
1454 if (len) child = child->next;
1455 }
1456 *val_ptr = val + 1;
1457 for (i = 0; i < len; i++) {
1458 val_sum += yyjson_imut_copy(val_ptr, buf_ptr, child);
1459 child = child->next;
1460 }
1461 val->tag = mval->tag;
1462 val->uni.ofs = val_sum * sizeof(yyjson_val);
1463 return val_sum;
1464 } else if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
1465 char *buf = *buf_ptr;
1466 usize len = unsafe_yyjson_get_len(mval);
1467 memcpy((void *)buf, (const void *)mval->uni.str, len);
1468 buf[len] = '\0';
1469 val->tag = mval->tag;
1470 val->uni.str = buf;
1471 *val_ptr = val + 1;
1472 *buf_ptr = buf + len + 1;
1473 return 1;
1474 } else {
1475 val->tag = mval->tag;
1476 val->uni = mval->uni;
1477 *val_ptr = val + 1;
1478 return 1;
1479 }
1480}
1481
1482yyjson_doc *yyjson_mut_doc_imut_copy(yyjson_mut_doc *mdoc,
1483 const yyjson_alc *alc) {
1484 if (!mdoc) return NULL;
1485 return yyjson_mut_val_imut_copy(mdoc->root, alc);
1486}
1487
1488yyjson_doc *yyjson_mut_val_imut_copy(yyjson_mut_val *mval,
1489 const yyjson_alc *alc) {
1490 usize val_num = 0, str_sum = 0, hdr_size, buf_size;
1491 yyjson_doc *doc = NULL;
1492 yyjson_val *val_hdr = NULL;
1493
1494 /* This value should be NULL here. Setting a non-null value suppresses
1495 warning from the clang analyzer. */
1496 char *str_hdr = (char *)(void *)&str_sum;
1497 if (!mval) return NULL;
1498 if (!alc) alc = &YYJSON_DEFAULT_ALC;
1499
1500 /* traverse the input value to get pool size */
1501 yyjson_mut_stat(mval, &val_num, &str_sum);
1502
1503 /* create doc and val pool */
1504 hdr_size = size_align_up(sizeof(yyjson_doc), sizeof(yyjson_val));
1505 buf_size = hdr_size + val_num * sizeof(yyjson_val);
1506 doc = (yyjson_doc *)alc->malloc(alc->ctx, buf_size);
1507 if (!doc) return NULL;
1508 memset(doc, 0, sizeof(yyjson_doc));
1509 val_hdr = (yyjson_val *)(void *)((char *)(void *)doc + hdr_size);
1510 doc->root = val_hdr;
1511 doc->alc = *alc;
1512
1513 /* create str pool */
1514 if (str_sum > 0) {
1515 str_hdr = (char *)alc->malloc(alc->ctx, str_sum);
1516 doc->str_pool = str_hdr;
1517 if (!str_hdr) {
1518 alc->free(alc->ctx, (void *)doc);
1519 return NULL;
1520 }
1521 }
1522
1523 /* copy vals and strs */
1524 doc->val_read = yyjson_imut_copy(&val_hdr, &str_hdr, mval);
1525 doc->dat_read = str_sum + 1;
1526 return doc;
1527}
1528
1529static_inline bool unsafe_yyjson_num_equals(void *lhs, void *rhs) {
1530 yyjson_val_uni *luni = &((yyjson_val *)lhs)->uni;
1531 yyjson_val_uni *runi = &((yyjson_val *)rhs)->uni;
1532 yyjson_subtype lt = unsafe_yyjson_get_subtype(lhs);
1533 yyjson_subtype rt = unsafe_yyjson_get_subtype(rhs);
1534 if (lt == rt)
1535 return luni->u64 == runi->u64;
1536 if (lt == YYJSON_SUBTYPE_SINT && rt == YYJSON_SUBTYPE_UINT)
1537 return luni->i64 >= 0 && luni->u64 == runi->u64;
1538 if (lt == YYJSON_SUBTYPE_UINT && rt == YYJSON_SUBTYPE_SINT)
1539 return runi->i64 >= 0 && luni->u64 == runi->u64;
1540 return false;
1541}
1542
1543static_inline bool unsafe_yyjson_str_equals(void *lhs, void *rhs) {
1544 usize len = unsafe_yyjson_get_len(lhs);
1545 if (len != unsafe_yyjson_get_len(rhs)) return false;
1546 return !memcmp(unsafe_yyjson_get_str(lhs),
1547 unsafe_yyjson_get_str(rhs), len);
1548}
1549
1550bool unsafe_yyjson_equals(yyjson_val *lhs, yyjson_val *rhs) {
1551 yyjson_type type = unsafe_yyjson_get_type(lhs);
1552 if (type != unsafe_yyjson_get_type(rhs)) return false;
1553
1554 switch (type) {
1555 case YYJSON_TYPE_OBJ: {
1556 usize len = unsafe_yyjson_get_len(lhs);
1557 if (len != unsafe_yyjson_get_len(rhs)) return false;
1558 if (len > 0) {
1559 yyjson_obj_iter iter;
1560 yyjson_obj_iter_init(rhs, &iter);
1561 lhs = unsafe_yyjson_get_first(lhs);
1562 while (len-- > 0) {
1563 rhs = yyjson_obj_iter_getn(&iter, lhs->uni.str,
1564 unsafe_yyjson_get_len(lhs));
1565 if (!rhs || !unsafe_yyjson_equals(lhs + 1, rhs))
1566 return false;
1567 lhs = unsafe_yyjson_get_next(lhs + 1);
1568 }
1569 }
1570 /* yyjson allows duplicate keys, so the check may be inaccurate */
1571 return true;
1572 }
1573
1574 case YYJSON_TYPE_ARR: {
1575 usize len = unsafe_yyjson_get_len(lhs);
1576 if (len != unsafe_yyjson_get_len(rhs)) return false;
1577 if (len > 0) {
1578 lhs = unsafe_yyjson_get_first(lhs);
1579 rhs = unsafe_yyjson_get_first(rhs);
1580 while (len-- > 0) {
1581 if (!unsafe_yyjson_equals(lhs, rhs)) return false;
1582 lhs = unsafe_yyjson_get_next(lhs);
1583 rhs = unsafe_yyjson_get_next(rhs);
1584 }
1585 }
1586 return true;
1587 }
1588
1589 case YYJSON_TYPE_NUM:
1590 return unsafe_yyjson_num_equals(lhs, rhs);
1591
1592 case YYJSON_TYPE_RAW:
1593 case YYJSON_TYPE_STR:
1594 return unsafe_yyjson_str_equals(lhs, rhs);
1595
1596 case YYJSON_TYPE_NULL:
1597 case YYJSON_TYPE_BOOL:
1598 return lhs->tag == rhs->tag;
1599
1600 default:
1601 return false;
1602 }
1603}
1604
1605bool unsafe_yyjson_mut_equals(yyjson_mut_val *lhs, yyjson_mut_val *rhs) {
1606 yyjson_type type = unsafe_yyjson_get_type(lhs);
1607 if (type != unsafe_yyjson_get_type(rhs)) return false;
1608
1609 switch (type) {
1610 case YYJSON_TYPE_OBJ: {
1611 usize len = unsafe_yyjson_get_len(lhs);
1612 if (len != unsafe_yyjson_get_len(rhs)) return false;
1613 if (len > 0) {
1614 yyjson_mut_obj_iter iter;
1615 yyjson_mut_obj_iter_init(rhs, &iter);
1616 lhs = (yyjson_mut_val *)lhs->uni.ptr;
1617 while (len-- > 0) {
1618 rhs = yyjson_mut_obj_iter_getn(&iter, lhs->uni.str,
1619 unsafe_yyjson_get_len(lhs));
1620 if (!rhs || !unsafe_yyjson_mut_equals(lhs->next, rhs))
1621 return false;
1622 lhs = lhs->next->next;
1623 }
1624 }
1625 /* yyjson allows duplicate keys, so the check may be inaccurate */
1626 return true;
1627 }
1628
1629 case YYJSON_TYPE_ARR: {
1630 usize len = unsafe_yyjson_get_len(lhs);
1631 if (len != unsafe_yyjson_get_len(rhs)) return false;
1632 if (len > 0) {
1633 lhs = (yyjson_mut_val *)lhs->uni.ptr;
1634 rhs = (yyjson_mut_val *)rhs->uni.ptr;
1635 while (len-- > 0) {
1636 if (!unsafe_yyjson_mut_equals(lhs, rhs)) return false;
1637 lhs = lhs->next;
1638 rhs = rhs->next;
1639 }
1640 }
1641 return true;
1642 }
1643
1644 case YYJSON_TYPE_NUM:
1645 return unsafe_yyjson_num_equals(lhs, rhs);
1646
1647 case YYJSON_TYPE_RAW:
1648 case YYJSON_TYPE_STR:
1649 return unsafe_yyjson_str_equals(lhs, rhs);
1650
1651 case YYJSON_TYPE_NULL:
1652 case YYJSON_TYPE_BOOL:
1653 return lhs->tag == rhs->tag;
1654
1655 default:
1656 return false;
1657 }
1658}
1659
1660
1661
1662#if !YYJSON_DISABLE_UTILS
1663
1664/*==============================================================================
1665 * JSON Pointer API (RFC 6901)
1666 *============================================================================*/
1667
1668/**
1669 Get a token from JSON pointer string.
1670 @param ptr [in,out]
1671 in: string that points to current token prefix `/`
1672 out: string that points to next token prefix `/`, or string end
1673 @param end [in] end of the entire JSON Pointer string
1674 @param len [out] unescaped token length
1675 @param esc [out] number of escaped characters in this token
1676 @return head of the token, or NULL if syntax error
1677 */
1678static_inline const char *ptr_next_token(const char **ptr, const char *end,
1679 usize *len, usize *esc) {
1680 const char *hdr = *ptr + 1;
1681 const char *cur = hdr;
1682 /* skip unescaped characters */
1683 while (cur < end && *cur != '/' && *cur != '~') cur++;
1684 if (likely(cur == end || *cur != '~')) {
1685 /* no escaped characters, return */
1686 *ptr = cur;
1687 *len = (usize)(cur - hdr);
1688 *esc = 0;
1689 return hdr;
1690 } else {
1691 /* handle escaped characters */
1692 usize esc_num = 0;
1693 while (cur < end && *cur != '/') {
1694 if (*cur++ == '~') {
1695 if (cur == end || (*cur != '0' && *cur != '1')) {
1696 *ptr = cur - 1;
1697 return NULL;
1698 }
1699 esc_num++;
1700 }
1701 }
1702 *ptr = cur;
1703 *len = (usize)(cur - hdr) - esc_num;
1704 *esc = esc_num;
1705 return hdr;
1706 }
1707}
1708
1709/**
1710 Convert token string to index.
1711 @param cur [in] token head
1712 @param len [in] token length
1713 @param idx [out] the index number, or USIZE_MAX if token is '-'
1714 @return true if token is a valid array index
1715 */
1716static_inline bool ptr_token_to_idx(const char *cur, usize len, usize *idx) {
1717 const char *end = cur + len;
1718 usize num = 0, add;
1719 if (unlikely(len == 0 || len > USIZE_SAFE_DIG)) return false;
1720 if (*cur == '0') {
1721 if (unlikely(len > 1)) return false;
1722 *idx = 0;
1723 return true;
1724 }
1725 if (*cur == '-') {
1726 if (unlikely(len > 1)) return false;
1727 *idx = USIZE_MAX;
1728 return true;
1729 }
1730 for (; cur < end && (add = (usize)((u8)*cur - (u8)'0')) <= 9; cur++) {
1731 num = num * 10 + add;
1732 }
1733 if (unlikely(num == 0 || cur < end)) return false;
1734 *idx = num;
1735 return true;
1736}
1737
1738/**
1739 Compare JSON key with token.
1740 @param key a string key (yyjson_val or yyjson_mut_val)
1741 @param token a JSON pointer token
1742 @param len unescaped token length
1743 @param esc number of escaped characters in this token
1744 @return true if `str` is equals to `token`
1745 */
1746static_inline bool ptr_token_eq(void *key,
1747 const char *token, usize len, usize esc) {
1748 yyjson_val *val = (yyjson_val *)key;
1749 if (unsafe_yyjson_get_len(val) != len) return false;
1750 if (likely(!esc)) {
1751 return memcmp(val->uni.str, token, len) == 0;
1752 } else {
1753 const char *str = val->uni.str;
1754 for (; len-- > 0; token++, str++) {
1755 if (*token == '~') {
1756 if (*str != (*++token == '0' ? '~' : '/')) return false;
1757 } else {
1758 if (*str != *token) return false;
1759 }
1760 }
1761 return true;
1762 }
1763}
1764
1765/**
1766 Get a value from array by token.
1767 @param arr an array, should not be NULL or non-array type
1768 @param token a JSON pointer token
1769 @param len unescaped token length
1770 @param esc number of escaped characters in this token
1771 @return value at index, or NULL if token is not index or index is out of range
1772 */
1773static_inline yyjson_val *ptr_arr_get(yyjson_val *arr, const char *token,
1774 usize len, usize esc) {
1775 yyjson_val *val = unsafe_yyjson_get_first(arr);
1776 usize num = unsafe_yyjson_get_len(arr), idx = 0;
1777 if (unlikely(num == 0)) return NULL;
1778 if (unlikely(!ptr_token_to_idx(token, len, &idx))) return NULL;
1779 if (unlikely(idx >= num)) return NULL;
1780 if (unsafe_yyjson_arr_is_flat(arr)) {
1781 return val + idx;
1782 } else {
1783 while (idx-- > 0) val = unsafe_yyjson_get_next(val);
1784 return val;
1785 }
1786}
1787
1788/**
1789 Get a value from object by token.
1790 @param obj [in] an object, should not be NULL or non-object type
1791 @param token [in] a JSON pointer token
1792 @param len [in] unescaped token length
1793 @param esc [in] number of escaped characters in this token
1794 @return value associated with the token, or NULL if no value
1795 */
1796static_inline yyjson_val *ptr_obj_get(yyjson_val *obj, const char *token,
1797 usize len, usize esc) {
1798 yyjson_val *key = unsafe_yyjson_get_first(obj);
1799 usize num = unsafe_yyjson_get_len(obj);
1800 if (unlikely(num == 0)) return NULL;
1801 for (; num > 0; num--, key = unsafe_yyjson_get_next(key + 1)) {
1802 if (ptr_token_eq(key, token, len, esc)) return key + 1;
1803 }
1804 return NULL;
1805}
1806
1807/**
1808 Get a value from array by token.
1809 @param arr [in] an array, should not be NULL or non-array type
1810 @param token [in] a JSON pointer token
1811 @param len [in] unescaped token length
1812 @param esc [in] number of escaped characters in this token
1813 @param pre [out] previous (sibling) value of the returned value
1814 @param last [out] whether index is last
1815 @return value at index, or NULL if token is not index or index is out of range
1816 */
1817static_inline yyjson_mut_val *ptr_mut_arr_get(yyjson_mut_val *arr,
1818 const char *token,
1819 usize len, usize esc,
1820 yyjson_mut_val **pre,
1821 bool *last) {
1822 yyjson_mut_val *val = (yyjson_mut_val *)arr->uni.ptr; /* last (tail) */
1823 usize num = unsafe_yyjson_get_len(arr), idx;
1824 if (last) *last = false;
1825 if (pre) *pre = NULL;
1826 if (unlikely(num == 0)) {
1827 if (last && len == 1 && (*token == '0' || *token == '-')) *last = true;
1828 return NULL;
1829 }
1830 if (unlikely(!ptr_token_to_idx(token, len, &idx))) return NULL;
1831 if (last) *last = (idx == num || idx == USIZE_MAX);
1832 if (unlikely(idx >= num)) return NULL;
1833 while (idx-- > 0) val = val->next;
1834 *pre = val;
1835 return val->next;
1836}
1837
1838/**
1839 Get a value from object by token.
1840 @param obj [in] an object, should not be NULL or non-object type
1841 @param token [in] a JSON pointer token
1842 @param len [in] unescaped token length
1843 @param esc [in] number of escaped characters in this token
1844 @param pre [out] previous (sibling) key of the returned value's key
1845 @return value associated with the token, or NULL if no value
1846 */
1847static_inline yyjson_mut_val *ptr_mut_obj_get(yyjson_mut_val *obj,
1848 const char *token,
1849 usize len, usize esc,
1850 yyjson_mut_val **pre) {
1851 yyjson_mut_val *pre_key = (yyjson_mut_val *)obj->uni.ptr, *key;
1852 usize num = unsafe_yyjson_get_len(obj);
1853 if (pre) *pre = NULL;
1854 if (unlikely(num == 0)) return NULL;
1855 for (; num > 0; num--, pre_key = key) {
1856 key = pre_key->next->next;
1857 if (ptr_token_eq(key, token, len, esc)) {
1858 *pre = pre_key;
1859 return key->next;
1860 }
1861 }
1862 return NULL;
1863}
1864
1865/**
1866 Create a string value with JSON pointer token.
1867 @param token [in] a JSON pointer token
1868 @param len [in] unescaped token length
1869 @param esc [in] number of escaped characters in this token
1870 @param doc [in] used for memory allocation when creating value
1871 @return new string value, or NULL if memory allocation failed
1872 */
1873static_inline yyjson_mut_val *ptr_new_key(const char *token,
1874 usize len, usize esc,
1875 yyjson_mut_doc *doc) {
1876 const char *src = token;
1877 if (likely(!esc)) {
1878 return yyjson_mut_strncpy(doc, src, len);
1879 } else {
1880 const char *end = src + len + esc;
1881 char *dst = unsafe_yyjson_mut_str_alc(doc, len + esc);
1882 char *str = dst;
1883 if (unlikely(!dst)) return NULL;
1884 for (; src < end; src++, dst++) {
1885 if (*src != '~') *dst = *src;
1886 else *dst = (*++src == '0' ? '~' : '/');
1887 }
1888 *dst = '\0';
1889 return yyjson_mut_strn(doc, str, len);
1890 }
1891}
1892
1893/* macros for yyjson_ptr */
1894#define return_err(_ret, _code, _pos, _msg) do { \
1895 if (err) { \
1896 err->code = YYJSON_PTR_ERR_##_code; \
1897 err->msg = _msg; \
1898 err->pos = (usize)(_pos); \
1899 } \
1900 return _ret; \
1901} while (false)
1902
1903#define return_err_resolve(_ret, _pos) \
1904 return_err(_ret, RESOLVE, _pos, "JSON pointer cannot be resolved")
1905#define return_err_syntax(_ret, _pos) \
1906 return_err(_ret, SYNTAX, _pos, "invalid escaped character")
1907#define return_err_alloc(_ret) \
1908 return_err(_ret, MEMORY_ALLOCATION, 0, "failed to create value")
1909
1910yyjson_val *unsafe_yyjson_ptr_getx(yyjson_val *val,
1911 const char *ptr, size_t ptr_len,
1912 yyjson_ptr_err *err) {
1913
1914 const char *hdr = ptr, *end = ptr + ptr_len, *token;
1915 usize len, esc;
1916 yyjson_type type;
1917
1918 while (true) {
1919 token = ptr_next_token(&ptr, end, &len, &esc);
1920 if (unlikely(!token)) return_err_syntax(NULL, ptr - hdr);
1921 type = unsafe_yyjson_get_type(val);
1922 if (type == YYJSON_TYPE_OBJ) {
1923 val = ptr_obj_get(val, token, len, esc);
1924 } else if (type == YYJSON_TYPE_ARR) {
1925 val = ptr_arr_get(val, token, len, esc);
1926 } else {
1927 val = NULL;
1928 }
1929 if (!val) return_err_resolve(NULL, token - hdr);
1930 if (ptr == end) return val;
1931 }
1932}
1933
1934yyjson_mut_val *unsafe_yyjson_mut_ptr_getx(yyjson_mut_val *val,
1935 const char *ptr,
1936 size_t ptr_len,
1937 yyjson_ptr_ctx *ctx,
1938 yyjson_ptr_err *err) {
1939
1940 const char *hdr = ptr, *end = ptr + ptr_len, *token;
1941 usize len, esc;
1942 yyjson_mut_val *ctn, *pre = NULL;
1943 yyjson_type type;
1944 bool idx_is_last = false;
1945
1946 while (true) {
1947 token = ptr_next_token(&ptr, end, &len, &esc);
1948 if (unlikely(!token)) return_err_syntax(NULL, ptr - hdr);
1949 ctn = val;
1950 type = unsafe_yyjson_get_type(val);
1951 if (type == YYJSON_TYPE_OBJ) {
1952 val = ptr_mut_obj_get(val, token, len, esc, &pre);
1953 } else if (type == YYJSON_TYPE_ARR) {
1954 val = ptr_mut_arr_get(val, token, len, esc, &pre, &idx_is_last);
1955 } else {
1956 val = NULL;
1957 }
1958 if (ctx && (ptr == end)) {
1959 if (type == YYJSON_TYPE_OBJ ||
1960 (type == YYJSON_TYPE_ARR && (val || idx_is_last))) {
1961 ctx->ctn = ctn;
1962 ctx->pre = pre;
1963 }
1964 }
1965 if (!val) return_err_resolve(NULL, token - hdr);
1966 if (ptr == end) return val;
1967 }
1968}
1969
1970bool unsafe_yyjson_mut_ptr_putx(yyjson_mut_val *val,
1971 const char *ptr, size_t ptr_len,
1972 yyjson_mut_val *new_val,
1973 yyjson_mut_doc *doc,
1974 bool create_parent, bool insert_new,
1975 yyjson_ptr_ctx *ctx,
1976 yyjson_ptr_err *err) {
1977
1978 const char *hdr = ptr, *end = ptr + ptr_len, *token;
1979 usize token_len, esc, ctn_len;
1980 yyjson_mut_val *ctn, *key, *pre = NULL;
1981 yyjson_mut_val *sep_ctn = NULL, *sep_key = NULL, *sep_val = NULL;
1982 yyjson_type ctn_type;
1983 bool idx_is_last = false;
1984
1985 /* skip exist parent nodes */
1986 while (true) {
1987 token = ptr_next_token(&ptr, end, &token_len, &esc);
1988 if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
1989 ctn = val;
1990 ctn_type = unsafe_yyjson_get_type(ctn);
1991 if (ctn_type == YYJSON_TYPE_OBJ) {
1992 val = ptr_mut_obj_get(ctn, token, token_len, esc, &pre);
1993 } else if (ctn_type == YYJSON_TYPE_ARR) {
1994 val = ptr_mut_arr_get(ctn, token, token_len, esc, &pre,
1995 &idx_is_last);
1996 } else return_err_resolve(false, token - hdr);
1997 if (!val) break;
1998 if (ptr == end) break; /* is last token */
1999 }
2000
2001 /* create parent nodes if not exist */
2002 if (unlikely(ptr != end)) { /* not last token */
2003 if (!create_parent) return_err_resolve(false, token - hdr);
2004
2005 /* add value at last index if container is array */
2006 if (ctn_type == YYJSON_TYPE_ARR) {
2007 if (!idx_is_last || !insert_new) {
2008 return_err_resolve(false, token - hdr);
2009 }
2010 val = yyjson_mut_obj(doc);
2011 if (!val) return_err_alloc(false);
2012
2013 /* delay attaching until all operations are completed */
2014 sep_ctn = ctn;
2015 sep_key = NULL;
2016 sep_val = val;
2017
2018 /* move to next token */
2019 ctn = val;
2020 val = NULL;
2021 ctn_type = YYJSON_TYPE_OBJ;
2022 token = ptr_next_token(&ptr, end, &token_len, &esc);
2023 if (unlikely(!token)) return_err_resolve(false, token - hdr);
2024 }
2025
2026 /* container is object, create parent nodes */
2027 while (ptr != end) { /* not last token */
2028 key = ptr_new_key(token, token_len, esc, doc);
2029 if (!key) return_err_alloc(false);
2030 val = yyjson_mut_obj(doc);
2031 if (!val) return_err_alloc(false);
2032
2033 /* delay attaching until all operations are completed */
2034 if (!sep_ctn) {
2035 sep_ctn = ctn;
2036 sep_key = key;
2037 sep_val = val;
2038 } else {
2039 yyjson_mut_obj_add(ctn, key, val);
2040 }
2041
2042 /* move to next token */
2043 ctn = val;
2044 val = NULL;
2045 token = ptr_next_token(&ptr, end, &token_len, &esc);
2046 if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
2047 }
2048 }
2049
2050 /* JSON pointer is resolved, insert or replace target value */
2051 ctn_len = unsafe_yyjson_get_len(ctn);
2052 if (ctn_type == YYJSON_TYPE_OBJ) {
2053 if (ctx) ctx->ctn = ctn;
2054 if (!val || insert_new) {
2055 /* insert new key-value pair */
2056 key = ptr_new_key(token, token_len, esc, doc);
2057 if (unlikely(!key)) return_err_alloc(false);
2058 if (ctx) ctx->pre = ctn_len ? (yyjson_mut_val *)ctn->uni.ptr : key;
2059 unsafe_yyjson_mut_obj_add(ctn, key, new_val, ctn_len);
2060 } else {
2061 /* replace exist value */
2062 key = pre->next->next;
2063 if (ctx) ctx->pre = pre;
2064 if (ctx) ctx->old = val;
2065 yyjson_mut_obj_put(ctn, key, new_val);
2066 }
2067 } else {
2068 /* array */
2069 if (ctx && (val || idx_is_last)) ctx->ctn = ctn;
2070 if (insert_new) {
2071 /* append new value */
2072 if (val) {
2073 pre->next = new_val;
2074 new_val->next = val;
2075 if (ctx) ctx->pre = pre;
2076 unsafe_yyjson_set_len(ctn, ctn_len + 1);
2077 } else if (idx_is_last) {
2078 if (ctx) ctx->pre = ctn_len ?
2079 (yyjson_mut_val *)ctn->uni.ptr : new_val;
2080 yyjson_mut_arr_append(ctn, new_val);
2081 } else {
2082 return_err_resolve(false, token - hdr);
2083 }
2084 } else {
2085 /* replace exist value */
2086 if (!val) return_err_resolve(false, token - hdr);
2087 if (ctn_len > 1) {
2088 new_val->next = val->next;
2089 pre->next = new_val;
2090 if (ctn->uni.ptr == val) ctn->uni.ptr = new_val;
2091 } else {
2092 new_val->next = new_val;
2093 ctn->uni.ptr = new_val;
2094 pre = new_val;
2095 }
2096 if (ctx) ctx->pre = pre;
2097 if (ctx) ctx->old = val;
2098 }
2099 }
2100
2101 /* all operations are completed, attach the new components to the target */
2102 if (unlikely(sep_ctn)) {
2103 if (sep_key) yyjson_mut_obj_add(sep_ctn, sep_key, sep_val);
2104 else yyjson_mut_arr_append(sep_ctn, sep_val);
2105 }
2106 return true;
2107}
2108
2109yyjson_mut_val *unsafe_yyjson_mut_ptr_replacex(
2110 yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val,
2111 yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
2112
2113 yyjson_mut_val *cur_val;
2114 yyjson_ptr_ctx cur_ctx;
2115 memset(&cur_ctx, 0, sizeof(cur_ctx));
2116 if (!ctx) ctx = &cur_ctx;
2117 cur_val = unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err);
2118 if (!cur_val) return NULL;
2119
2120 if (yyjson_mut_is_obj(ctx->ctn)) {
2121 yyjson_mut_val *key = ctx->pre->next->next;
2122 yyjson_mut_obj_put(ctx->ctn, key, new_val);
2123 } else {
2124 yyjson_ptr_ctx_replace(ctx, new_val);
2125 }
2126 ctx->old = cur_val;
2127 return cur_val;
2128}
2129
2130yyjson_mut_val *unsafe_yyjson_mut_ptr_removex(yyjson_mut_val *val,
2131 const char *ptr,
2132 size_t len,
2133 yyjson_ptr_ctx *ctx,
2134 yyjson_ptr_err *err) {
2135 yyjson_mut_val *cur_val;
2136 yyjson_ptr_ctx cur_ctx;
2137 memset(&cur_ctx, 0, sizeof(cur_ctx));
2138 if (!ctx) ctx = &cur_ctx;
2139 cur_val = unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err);
2140 if (cur_val) {
2141 if (yyjson_mut_is_obj(ctx->ctn)) {
2142 yyjson_mut_val *key = ctx->pre->next->next;
2143 yyjson_mut_obj_put(ctx->ctn, key, NULL);
2144 } else {
2145 yyjson_ptr_ctx_remove(ctx);
2146 }
2147 ctx->pre = NULL;
2148 ctx->old = cur_val;
2149 }
2150 return cur_val;
2151}
2152
2153/* macros for yyjson_ptr */
2154#undef return_err
2155#undef return_err_resolve
2156#undef return_err_syntax
2157#undef return_err_alloc
2158
2159
2160
2161/*==============================================================================
2162 * JSON Patch API (RFC 6902)
2163 *============================================================================*/
2164
2165/* JSON Patch operation */
2166typedef enum patch_op {
2167 PATCH_OP_ADD, /* path, value */
2168 PATCH_OP_REMOVE, /* path */
2169 PATCH_OP_REPLACE, /* path, value */
2170 PATCH_OP_MOVE, /* from, path */
2171 PATCH_OP_COPY, /* from, path */
2172 PATCH_OP_TEST, /* path, value */
2173 PATCH_OP_NONE /* invalid */
2174} patch_op;
2175
2176static patch_op patch_op_get(yyjson_val *op) {
2177 const char *str = op->uni.str;
2178 switch (unsafe_yyjson_get_len(op)) {
2179 case 3:
2180 if (!memcmp(str, "add", 3)) return PATCH_OP_ADD;
2181 return PATCH_OP_NONE;
2182 case 4:
2183 if (!memcmp(str, "move", 4)) return PATCH_OP_MOVE;
2184 if (!memcmp(str, "copy", 4)) return PATCH_OP_COPY;
2185 if (!memcmp(str, "test", 4)) return PATCH_OP_TEST;
2186 return PATCH_OP_NONE;
2187 case 6:
2188 if (!memcmp(str, "remove", 6)) return PATCH_OP_REMOVE;
2189 return PATCH_OP_NONE;
2190 case 7:
2191 if (!memcmp(str, "replace", 7)) return PATCH_OP_REPLACE;
2192 return PATCH_OP_NONE;
2193 default:
2194 return PATCH_OP_NONE;
2195 }
2196}
2197
2198/* macros for yyjson_patch */
2199#define return_err(_code, _msg) do { \
2200 if (err->ptr.code == YYJSON_PTR_ERR_MEMORY_ALLOCATION) { \
2201 err->code = YYJSON_PATCH_ERROR_MEMORY_ALLOCATION; \
2202 err->msg = _msg; \
2203 memset(&err->ptr, 0, sizeof(yyjson_ptr_err)); \
2204 } else { \
2205 err->code = YYJSON_PATCH_ERROR_##_code; \
2206 err->msg = _msg; \
2207 err->idx = iter.idx ? iter.idx - 1 : 0; \
2208 } \
2209 return NULL; \
2210} while (false)
2211
2212#define return_err_copy() \
2213 return_err(MEMORY_ALLOCATION, "failed to copy value")
2214#define return_err_key(_key) \
2215 return_err(MISSING_KEY, "missing key " _key)
2216#define return_err_val(_key) \
2217 return_err(INVALID_MEMBER, "invalid member " _key)
2218
2219#define ptr_get(_ptr) yyjson_mut_ptr_getx( \
2220 root, _ptr->uni.str, _ptr##_len, NULL, &err->ptr)
2221#define ptr_add(_ptr, _val) yyjson_mut_ptr_addx( \
2222 root, _ptr->uni.str, _ptr##_len, _val, doc, false, NULL, &err->ptr)
2223#define ptr_remove(_ptr) yyjson_mut_ptr_removex( \
2224 root, _ptr->uni.str, _ptr##_len, NULL, &err->ptr)
2225#define ptr_replace(_ptr, _val)yyjson_mut_ptr_replacex( \
2226 root, _ptr->uni.str, _ptr##_len, _val, NULL, &err->ptr)
2227
2228yyjson_mut_val *yyjson_patch(yyjson_mut_doc *doc,
2229 yyjson_val *orig,
2230 yyjson_val *patch,
2231 yyjson_patch_err *err) {
2232
2233 yyjson_mut_val *root;
2234 yyjson_val *obj;
2235 yyjson_arr_iter iter;
2236 yyjson_patch_err err_tmp;
2237 if (!err) err = &err_tmp;
2238 memset(err, 0, sizeof(*err));
2239 memset(&iter, 0, sizeof(iter));
2240
2241 if (unlikely(!doc || !orig || !patch)) {
2242 return_err(INVALID_PARAMETER, "input parameter is NULL");
2243 }
2244 if (unlikely(!yyjson_is_arr(patch))) {
2245 return_err(INVALID_PARAMETER, "input patch is not array");
2246 }
2247 root = yyjson_val_mut_copy(doc, orig);
2248 if (unlikely(!root)) return_err_copy();
2249
2250 /* iterate through the patch array */
2251 yyjson_arr_iter_init(patch, &iter);
2252 while ((obj = yyjson_arr_iter_next(&iter))) {
2253 patch_op op_enum;
2254 yyjson_val *op, *path, *from = NULL, *value;
2255 yyjson_mut_val *val = NULL, *test;
2256 usize path_len, from_len = 0;
2257 if (unlikely(!unsafe_yyjson_is_obj(obj))) {
2258 return_err(INVALID_OPERATION, "JSON patch operation is not object");
2259 }
2260
2261 /* get required member: op */
2262 op = yyjson_obj_get(obj, "op");
2263 if (unlikely(!op)) return_err_key("`op`");
2264 if (unlikely(!yyjson_is_str(op))) return_err_val("`op`");
2265 op_enum = patch_op_get(op);
2266
2267 /* get required member: path */
2268 path = yyjson_obj_get(obj, "path");
2269 if (unlikely(!path)) return_err_key("`path`");
2270 if (unlikely(!yyjson_is_str(path))) return_err_val("`path`");
2271 path_len = unsafe_yyjson_get_len(path);
2272
2273 /* get required member: value, from */
2274 switch (op_enum) {
2275 case PATCH_OP_ADD: case PATCH_OP_REPLACE: case PATCH_OP_TEST:
2276 value = yyjson_obj_get(obj, "value");
2277 if (unlikely(!value)) return_err_key("`value`");
2278 val = yyjson_val_mut_copy(doc, value);
2279 if (unlikely(!val)) return_err_copy();
2280 break;
2281 case PATCH_OP_MOVE: case PATCH_OP_COPY:
2282 from = yyjson_obj_get(obj, "from");
2283 if (unlikely(!from)) return_err_key("`from`");
2284 if (unlikely(!yyjson_is_str(from))) return_err_val("`from`");
2285 from_len = unsafe_yyjson_get_len(from);
2286 break;
2287 default:
2288 break;
2289 }
2290
2291 /* perform an operation */
2292 switch (op_enum) {
2293 case PATCH_OP_ADD: /* add(path, val) */
2294 if (unlikely(path_len == 0)) { root = val; break; }
2295 if (unlikely(!ptr_add(path, val))) {
2296 return_err(POINTER, "failed to add `path`");
2297 }
2298 break;
2299 case PATCH_OP_REMOVE: /* remove(path) */
2300 if (unlikely(!ptr_remove(path))) {
2301 return_err(POINTER, "failed to remove `path`");
2302 }
2303 break;
2304 case PATCH_OP_REPLACE: /* replace(path, val) */
2305 if (unlikely(path_len == 0)) { root = val; break; }
2306 if (unlikely(!ptr_replace(path, val))) {
2307 return_err(POINTER, "failed to replace `path`");
2308 }
2309 break;
2310 case PATCH_OP_MOVE: /* val = remove(from), add(path, val) */
2311 if (unlikely(from_len == 0 && path_len == 0)) break;
2312 val = ptr_remove(from);
2313 if (unlikely(!val)) {
2314 return_err(POINTER, "failed to remove `from`");
2315 }
2316 if (unlikely(path_len == 0)) { root = val; break; }
2317 if (unlikely(!ptr_add(path, val))) {
2318 return_err(POINTER, "failed to add `path`");
2319 }
2320 break;
2321 case PATCH_OP_COPY: /* val = get(from).copy, add(path, val) */
2322 val = ptr_get(from);
2323 if (unlikely(!val)) {
2324 return_err(POINTER, "failed to get `from`");
2325 }
2326 if (unlikely(path_len == 0)) { root = val; break; }
2327 val = yyjson_mut_val_mut_copy(doc, val);
2328 if (unlikely(!val)) return_err_copy();
2329 if (unlikely(!ptr_add(path, val))) {
2330 return_err(POINTER, "failed to add `path`");
2331 }
2332 break;
2333 case PATCH_OP_TEST: /* test = get(path), test.eq(val) */
2334 test = ptr_get(path);
2335 if (unlikely(!test)) {
2336 return_err(POINTER, "failed to get `path`");
2337 }
2338 if (unlikely(!yyjson_mut_equals(val, test))) {
2339 return_err(EQUAL, "failed to test equal");
2340 }
2341 break;
2342 default:
2343 return_err(INVALID_MEMBER, "unsupported `op`");
2344 }
2345 }
2346 return root;
2347}
2348
2349yyjson_mut_val *yyjson_mut_patch(yyjson_mut_doc *doc,
2350 yyjson_mut_val *orig,
2351 yyjson_mut_val *patch,
2352 yyjson_patch_err *err) {
2353 yyjson_mut_val *root, *obj;
2354 yyjson_mut_arr_iter iter;
2355 yyjson_patch_err err_tmp;
2356 if (!err) err = &err_tmp;
2357 memset(err, 0, sizeof(*err));
2358 memset(&iter, 0, sizeof(iter));
2359
2360 if (unlikely(!doc || !orig || !patch)) {
2361 return_err(INVALID_PARAMETER, "input parameter is NULL");
2362 }
2363 if (unlikely(!yyjson_mut_is_arr(patch))) {
2364 return_err(INVALID_PARAMETER, "input patch is not array");
2365 }
2366 root = yyjson_mut_val_mut_copy(doc, orig);
2367 if (unlikely(!root)) return_err_copy();
2368
2369 /* iterate through the patch array */
2370 yyjson_mut_arr_iter_init(patch, &iter);
2371 while ((obj = yyjson_mut_arr_iter_next(&iter))) {
2372 patch_op op_enum;
2373 yyjson_mut_val *op, *path, *from = NULL, *value;
2374 yyjson_mut_val *val = NULL, *test;
2375 usize path_len, from_len = 0;
2376 if (!unsafe_yyjson_is_obj(obj)) {
2377 return_err(INVALID_OPERATION, "JSON patch operation is not object");
2378 }
2379
2380 /* get required member: op */
2381 op = yyjson_mut_obj_get(obj, "op");
2382 if (unlikely(!op)) return_err_key("`op`");
2383 if (unlikely(!yyjson_mut_is_str(op))) return_err_val("`op`");
2384 op_enum = patch_op_get((yyjson_val *)(void *)op);
2385
2386 /* get required member: path */
2387 path = yyjson_mut_obj_get(obj, "path");
2388 if (unlikely(!path)) return_err_key("`path`");
2389 if (unlikely(!yyjson_mut_is_str(path))) return_err_val("`path`");
2390 path_len = unsafe_yyjson_get_len(path);
2391
2392 /* get required member: value, from */
2393 switch (op_enum) {
2394 case PATCH_OP_ADD: case PATCH_OP_REPLACE: case PATCH_OP_TEST:
2395 value = yyjson_mut_obj_get(obj, "value");
2396 if (unlikely(!value)) return_err_key("`value`");
2397 val = yyjson_mut_val_mut_copy(doc, value);
2398 if (unlikely(!val)) return_err_copy();
2399 break;
2400 case PATCH_OP_MOVE: case PATCH_OP_COPY:
2401 from = yyjson_mut_obj_get(obj, "from");
2402 if (unlikely(!from)) return_err_key("`from`");
2403 if (unlikely(!yyjson_mut_is_str(from))) {
2404 return_err_val("`from`");
2405 }
2406 from_len = unsafe_yyjson_get_len(from);
2407 break;
2408 default:
2409 break;
2410 }
2411
2412 /* perform an operation */
2413 switch (op_enum) {
2414 case PATCH_OP_ADD: /* add(path, val) */
2415 if (unlikely(path_len == 0)) { root = val; break; }
2416 if (unlikely(!ptr_add(path, val))) {
2417 return_err(POINTER, "failed to add `path`");
2418 }
2419 break;
2420 case PATCH_OP_REMOVE: /* remove(path) */
2421 if (unlikely(!ptr_remove(path))) {
2422 return_err(POINTER, "failed to remove `path`");
2423 }
2424 break;
2425 case PATCH_OP_REPLACE: /* replace(path, val) */
2426 if (unlikely(path_len == 0)) { root = val; break; }
2427 if (unlikely(!ptr_replace(path, val))) {
2428 return_err(POINTER, "failed to replace `path`");
2429 }
2430 break;
2431 case PATCH_OP_MOVE: /* val = remove(from), add(path, val) */
2432 if (unlikely(from_len == 0 && path_len == 0)) break;
2433 val = ptr_remove(from);
2434 if (unlikely(!val)) {
2435 return_err(POINTER, "failed to remove `from`");
2436 }
2437 if (unlikely(path_len == 0)) { root = val; break; }
2438 if (unlikely(!ptr_add(path, val))) {
2439 return_err(POINTER, "failed to add `path`");
2440 }
2441 break;
2442 case PATCH_OP_COPY: /* val = get(from).copy, add(path, val) */
2443 val = ptr_get(from);
2444 if (unlikely(!val)) {
2445 return_err(POINTER, "failed to get `from`");
2446 }
2447 if (unlikely(path_len == 0)) { root = val; break; }
2448 val = yyjson_mut_val_mut_copy(doc, val);
2449 if (unlikely(!val)) return_err_copy();
2450 if (unlikely(!ptr_add(path, val))) {
2451 return_err(POINTER, "failed to add `path`");
2452 }
2453 break;
2454 case PATCH_OP_TEST: /* test = get(path), test.eq(val) */
2455 test = ptr_get(path);
2456 if (unlikely(!test)) {
2457 return_err(POINTER, "failed to get `path`");
2458 }
2459 if (unlikely(!yyjson_mut_equals(val, test))) {
2460 return_err(EQUAL, "failed to test equal");
2461 }
2462 break;
2463 default:
2464 return_err(INVALID_MEMBER, "unsupported `op`");
2465 }
2466 }
2467 return root;
2468}
2469
2470/* macros for yyjson_patch */
2471#undef return_err
2472#undef return_err_copy
2473#undef return_err_key
2474#undef return_err_val
2475#undef ptr_get
2476#undef ptr_add
2477#undef ptr_remove
2478#undef ptr_replace
2479
2480
2481
2482/*==============================================================================
2483 * JSON Merge-Patch API (RFC 7386)
2484 *============================================================================*/
2485
2486yyjson_mut_val *yyjson_merge_patch(yyjson_mut_doc *doc,
2487 yyjson_val *orig,
2488 yyjson_val *patch) {
2489 usize idx, max;
2490 yyjson_val *key, *orig_val, *patch_val, local_orig;
2491 yyjson_mut_val *builder, *mut_key, *mut_val, *merged_val;
2492
2493 if (unlikely(!yyjson_is_obj(patch))) {
2494 return yyjson_val_mut_copy(doc, patch);
2495 }
2496
2497 builder = yyjson_mut_obj(doc);
2498 if (unlikely(!builder)) return NULL;
2499
2500 if (!yyjson_is_obj(orig)) {
2501 orig = &local_orig;
2502 orig->tag = builder->tag;
2503 orig->uni = builder->uni;
2504 }
2505
2506 /* If orig is contributing, copy any items not modified by the patch */
2507 if (orig != &local_orig) {
2508 yyjson_obj_foreach(orig, idx, max, key, orig_val) {
2509 patch_val = yyjson_obj_getn(patch,
2510 unsafe_yyjson_get_str(key),
2511 unsafe_yyjson_get_len(key));
2512 if (!patch_val) {
2513 mut_key = yyjson_val_mut_copy(doc, key);
2514 mut_val = yyjson_val_mut_copy(doc, orig_val);
2515 if (!yyjson_mut_obj_add(builder, mut_key, mut_val)) return NULL;
2516 }
2517 }
2518 }
2519
2520 /* Merge items modified by the patch. */
2521 yyjson_obj_foreach(patch, idx, max, key, patch_val) {
2522 /* null indicates the field is removed. */
2523 if (unsafe_yyjson_is_null(patch_val)) {
2524 continue;
2525 }
2526 mut_key = yyjson_val_mut_copy(doc, key);
2527 orig_val = yyjson_obj_getn(orig,
2528 unsafe_yyjson_get_str(key),
2529 unsafe_yyjson_get_len(key));
2530 merged_val = yyjson_merge_patch(doc, orig_val, patch_val);
2531 if (!yyjson_mut_obj_add(builder, mut_key, merged_val)) return NULL;
2532 }
2533
2534 return builder;
2535}
2536
2537yyjson_mut_val *yyjson_mut_merge_patch(yyjson_mut_doc *doc,
2538 yyjson_mut_val *orig,
2539 yyjson_mut_val *patch) {
2540 usize idx, max;
2541 yyjson_mut_val *key, *orig_val, *patch_val, local_orig;
2542 yyjson_mut_val *builder, *mut_key, *mut_val, *merged_val;
2543
2544 if (unlikely(!yyjson_mut_is_obj(patch))) {
2545 return yyjson_mut_val_mut_copy(doc, patch);
2546 }
2547
2548 builder = yyjson_mut_obj(doc);
2549 if (unlikely(!builder)) return NULL;
2550
2551 if (!yyjson_mut_is_obj(orig)) {
2552 orig = &local_orig;
2553 orig->tag = builder->tag;
2554 orig->uni = builder->uni;
2555 }
2556
2557 /* If orig is contributing, copy any items not modified by the patch */
2558 if (orig != &local_orig) {
2559 yyjson_mut_obj_foreach(orig, idx, max, key, orig_val) {
2560 patch_val = yyjson_mut_obj_getn(patch,
2561 unsafe_yyjson_get_str(key),
2562 unsafe_yyjson_get_len(key));
2563 if (!patch_val) {
2564 mut_key = yyjson_mut_val_mut_copy(doc, key);
2565 mut_val = yyjson_mut_val_mut_copy(doc, orig_val);
2566 if (!yyjson_mut_obj_add(builder, mut_key, mut_val)) return NULL;
2567 }
2568 }
2569 }
2570
2571 /* Merge items modified by the patch. */
2572 yyjson_mut_obj_foreach(patch, idx, max, key, patch_val) {
2573 /* null indicates the field is removed. */
2574 if (unsafe_yyjson_is_null(patch_val)) {
2575 continue;
2576 }
2577 mut_key = yyjson_mut_val_mut_copy(doc, key);
2578 orig_val = yyjson_mut_obj_getn(orig,
2579 unsafe_yyjson_get_str(key),
2580 unsafe_yyjson_get_len(key));
2581 merged_val = yyjson_mut_merge_patch(doc, orig_val, patch_val);
2582 if (!yyjson_mut_obj_add(builder, mut_key, merged_val)) return NULL;
2583 }
2584
2585 return builder;
2586}
2587
2588#endif /* YYJSON_DISABLE_UTILS */
2589
2590
2591
2592/*==============================================================================
2593 * Power10 Lookup Table
2594 * These data are used by the floating-point number reader and writer.
2595 *============================================================================*/
2596
2597#if (!YYJSON_DISABLE_READER || !YYJSON_DISABLE_WRITER) && \
2598 (!YYJSON_DISABLE_FAST_FP_CONV)
2599
2600/** Minimum decimal exponent in pow10_sig_table. */
2601#define POW10_SIG_TABLE_MIN_EXP -343
2602
2603/** Maximum decimal exponent in pow10_sig_table. */
2604#define POW10_SIG_TABLE_MAX_EXP 324
2605
2606/** Minimum exact decimal exponent in pow10_sig_table */
2607#define POW10_SIG_TABLE_MIN_EXACT_EXP 0
2608
2609/** Maximum exact decimal exponent in pow10_sig_table */
2610#define POW10_SIG_TABLE_MAX_EXACT_EXP 55
2611
2612/** Normalized significant 128 bits of pow10, no rounded up (size: 10.4KB).
2613 This lookup table is used by both the double number reader and writer.
2614 (generate with misc/make_tables.c) */
2615static const u64 pow10_sig_table[] = {
2616 U64(0xBF29DCAB, 0xA82FDEAE), U64(0x7432EE87, 0x3880FC33), /* ~= 10^-343 */
2617 U64(0xEEF453D6, 0x923BD65A), U64(0x113FAA29, 0x06A13B3F), /* ~= 10^-342 */
2618 U64(0x9558B466, 0x1B6565F8), U64(0x4AC7CA59, 0xA424C507), /* ~= 10^-341 */
2619 U64(0xBAAEE17F, 0xA23EBF76), U64(0x5D79BCF0, 0x0D2DF649), /* ~= 10^-340 */
2620 U64(0xE95A99DF, 0x8ACE6F53), U64(0xF4D82C2C, 0x107973DC), /* ~= 10^-339 */
2621 U64(0x91D8A02B, 0xB6C10594), U64(0x79071B9B, 0x8A4BE869), /* ~= 10^-338 */
2622 U64(0xB64EC836, 0xA47146F9), U64(0x9748E282, 0x6CDEE284), /* ~= 10^-337 */
2623 U64(0xE3E27A44, 0x4D8D98B7), U64(0xFD1B1B23, 0x08169B25), /* ~= 10^-336 */
2624 U64(0x8E6D8C6A, 0xB0787F72), U64(0xFE30F0F5, 0xE50E20F7), /* ~= 10^-335 */
2625 U64(0xB208EF85, 0x5C969F4F), U64(0xBDBD2D33, 0x5E51A935), /* ~= 10^-334 */
2626 U64(0xDE8B2B66, 0xB3BC4723), U64(0xAD2C7880, 0x35E61382), /* ~= 10^-333 */
2627 U64(0x8B16FB20, 0x3055AC76), U64(0x4C3BCB50, 0x21AFCC31), /* ~= 10^-332 */
2628 U64(0xADDCB9E8, 0x3C6B1793), U64(0xDF4ABE24, 0x2A1BBF3D), /* ~= 10^-331 */
2629 U64(0xD953E862, 0x4B85DD78), U64(0xD71D6DAD, 0x34A2AF0D), /* ~= 10^-330 */
2630 U64(0x87D4713D, 0x6F33AA6B), U64(0x8672648C, 0x40E5AD68), /* ~= 10^-329 */
2631 U64(0xA9C98D8C, 0xCB009506), U64(0x680EFDAF, 0x511F18C2), /* ~= 10^-328 */
2632 U64(0xD43BF0EF, 0xFDC0BA48), U64(0x0212BD1B, 0x2566DEF2), /* ~= 10^-327 */
2633 U64(0x84A57695, 0xFE98746D), U64(0x014BB630, 0xF7604B57), /* ~= 10^-326 */
2634 U64(0xA5CED43B, 0x7E3E9188), U64(0x419EA3BD, 0x35385E2D), /* ~= 10^-325 */
2635 U64(0xCF42894A, 0x5DCE35EA), U64(0x52064CAC, 0x828675B9), /* ~= 10^-324 */
2636 U64(0x818995CE, 0x7AA0E1B2), U64(0x7343EFEB, 0xD1940993), /* ~= 10^-323 */
2637 U64(0xA1EBFB42, 0x19491A1F), U64(0x1014EBE6, 0xC5F90BF8), /* ~= 10^-322 */
2638 U64(0xCA66FA12, 0x9F9B60A6), U64(0xD41A26E0, 0x77774EF6), /* ~= 10^-321 */
2639 U64(0xFD00B897, 0x478238D0), U64(0x8920B098, 0x955522B4), /* ~= 10^-320 */
2640 U64(0x9E20735E, 0x8CB16382), U64(0x55B46E5F, 0x5D5535B0), /* ~= 10^-319 */
2641 U64(0xC5A89036, 0x2FDDBC62), U64(0xEB2189F7, 0x34AA831D), /* ~= 10^-318 */
2642 U64(0xF712B443, 0xBBD52B7B), U64(0xA5E9EC75, 0x01D523E4), /* ~= 10^-317 */
2643 U64(0x9A6BB0AA, 0x55653B2D), U64(0x47B233C9, 0x2125366E), /* ~= 10^-316 */
2644 U64(0xC1069CD4, 0xEABE89F8), U64(0x999EC0BB, 0x696E840A), /* ~= 10^-315 */
2645 U64(0xF148440A, 0x256E2C76), U64(0xC00670EA, 0x43CA250D), /* ~= 10^-314 */
2646 U64(0x96CD2A86, 0x5764DBCA), U64(0x38040692, 0x6A5E5728), /* ~= 10^-313 */
2647 U64(0xBC807527, 0xED3E12BC), U64(0xC6050837, 0x04F5ECF2), /* ~= 10^-312 */
2648 U64(0xEBA09271, 0xE88D976B), U64(0xF7864A44, 0xC633682E), /* ~= 10^-311 */
2649 U64(0x93445B87, 0x31587EA3), U64(0x7AB3EE6A, 0xFBE0211D), /* ~= 10^-310 */
2650 U64(0xB8157268, 0xFDAE9E4C), U64(0x5960EA05, 0xBAD82964), /* ~= 10^-309 */
2651 U64(0xE61ACF03, 0x3D1A45DF), U64(0x6FB92487, 0x298E33BD), /* ~= 10^-308 */
2652 U64(0x8FD0C162, 0x06306BAB), U64(0xA5D3B6D4, 0x79F8E056), /* ~= 10^-307 */
2653 U64(0xB3C4F1BA, 0x87BC8696), U64(0x8F48A489, 0x9877186C), /* ~= 10^-306 */
2654 U64(0xE0B62E29, 0x29ABA83C), U64(0x331ACDAB, 0xFE94DE87), /* ~= 10^-305 */
2655 U64(0x8C71DCD9, 0xBA0B4925), U64(0x9FF0C08B, 0x7F1D0B14), /* ~= 10^-304 */
2656 U64(0xAF8E5410, 0x288E1B6F), U64(0x07ECF0AE, 0x5EE44DD9), /* ~= 10^-303 */
2657 U64(0xDB71E914, 0x32B1A24A), U64(0xC9E82CD9, 0xF69D6150), /* ~= 10^-302 */
2658 U64(0x892731AC, 0x9FAF056E), U64(0xBE311C08, 0x3A225CD2), /* ~= 10^-301 */
2659 U64(0xAB70FE17, 0xC79AC6CA), U64(0x6DBD630A, 0x48AAF406), /* ~= 10^-300 */
2660 U64(0xD64D3D9D, 0xB981787D), U64(0x092CBBCC, 0xDAD5B108), /* ~= 10^-299 */
2661 U64(0x85F04682, 0x93F0EB4E), U64(0x25BBF560, 0x08C58EA5), /* ~= 10^-298 */
2662 U64(0xA76C5823, 0x38ED2621), U64(0xAF2AF2B8, 0x0AF6F24E), /* ~= 10^-297 */
2663 U64(0xD1476E2C, 0x07286FAA), U64(0x1AF5AF66, 0x0DB4AEE1), /* ~= 10^-296 */
2664 U64(0x82CCA4DB, 0x847945CA), U64(0x50D98D9F, 0xC890ED4D), /* ~= 10^-295 */
2665 U64(0xA37FCE12, 0x6597973C), U64(0xE50FF107, 0xBAB528A0), /* ~= 10^-294 */
2666 U64(0xCC5FC196, 0xFEFD7D0C), U64(0x1E53ED49, 0xA96272C8), /* ~= 10^-293 */
2667 U64(0xFF77B1FC, 0xBEBCDC4F), U64(0x25E8E89C, 0x13BB0F7A), /* ~= 10^-292 */
2668 U64(0x9FAACF3D, 0xF73609B1), U64(0x77B19161, 0x8C54E9AC), /* ~= 10^-291 */
2669 U64(0xC795830D, 0x75038C1D), U64(0xD59DF5B9, 0xEF6A2417), /* ~= 10^-290 */
2670 U64(0xF97AE3D0, 0xD2446F25), U64(0x4B057328, 0x6B44AD1D), /* ~= 10^-289 */
2671 U64(0x9BECCE62, 0x836AC577), U64(0x4EE367F9, 0x430AEC32), /* ~= 10^-288 */
2672 U64(0xC2E801FB, 0x244576D5), U64(0x229C41F7, 0x93CDA73F), /* ~= 10^-287 */
2673 U64(0xF3A20279, 0xED56D48A), U64(0x6B435275, 0x78C1110F), /* ~= 10^-286 */
2674 U64(0x9845418C, 0x345644D6), U64(0x830A1389, 0x6B78AAA9), /* ~= 10^-285 */
2675 U64(0xBE5691EF, 0x416BD60C), U64(0x23CC986B, 0xC656D553), /* ~= 10^-284 */
2676 U64(0xEDEC366B, 0x11C6CB8F), U64(0x2CBFBE86, 0xB7EC8AA8), /* ~= 10^-283 */
2677 U64(0x94B3A202, 0xEB1C3F39), U64(0x7BF7D714, 0x32F3D6A9), /* ~= 10^-282 */
2678 U64(0xB9E08A83, 0xA5E34F07), U64(0xDAF5CCD9, 0x3FB0CC53), /* ~= 10^-281 */
2679 U64(0xE858AD24, 0x8F5C22C9), U64(0xD1B3400F, 0x8F9CFF68), /* ~= 10^-280 */
2680 U64(0x91376C36, 0xD99995BE), U64(0x23100809, 0xB9C21FA1), /* ~= 10^-279 */
2681 U64(0xB5854744, 0x8FFFFB2D), U64(0xABD40A0C, 0x2832A78A), /* ~= 10^-278 */
2682 U64(0xE2E69915, 0xB3FFF9F9), U64(0x16C90C8F, 0x323F516C), /* ~= 10^-277 */
2683 U64(0x8DD01FAD, 0x907FFC3B), U64(0xAE3DA7D9, 0x7F6792E3), /* ~= 10^-276 */
2684 U64(0xB1442798, 0xF49FFB4A), U64(0x99CD11CF, 0xDF41779C), /* ~= 10^-275 */
2685 U64(0xDD95317F, 0x31C7FA1D), U64(0x40405643, 0xD711D583), /* ~= 10^-274 */
2686 U64(0x8A7D3EEF, 0x7F1CFC52), U64(0x482835EA, 0x666B2572), /* ~= 10^-273 */
2687 U64(0xAD1C8EAB, 0x5EE43B66), U64(0xDA324365, 0x0005EECF), /* ~= 10^-272 */
2688 U64(0xD863B256, 0x369D4A40), U64(0x90BED43E, 0x40076A82), /* ~= 10^-271 */
2689 U64(0x873E4F75, 0xE2224E68), U64(0x5A7744A6, 0xE804A291), /* ~= 10^-270 */
2690 U64(0xA90DE353, 0x5AAAE202), U64(0x711515D0, 0xA205CB36), /* ~= 10^-269 */
2691 U64(0xD3515C28, 0x31559A83), U64(0x0D5A5B44, 0xCA873E03), /* ~= 10^-268 */
2692 U64(0x8412D999, 0x1ED58091), U64(0xE858790A, 0xFE9486C2), /* ~= 10^-267 */
2693 U64(0xA5178FFF, 0x668AE0B6), U64(0x626E974D, 0xBE39A872), /* ~= 10^-266 */
2694 U64(0xCE5D73FF, 0x402D98E3), U64(0xFB0A3D21, 0x2DC8128F), /* ~= 10^-265 */
2695 U64(0x80FA687F, 0x881C7F8E), U64(0x7CE66634, 0xBC9D0B99), /* ~= 10^-264 */
2696 U64(0xA139029F, 0x6A239F72), U64(0x1C1FFFC1, 0xEBC44E80), /* ~= 10^-263 */
2697 U64(0xC9874347, 0x44AC874E), U64(0xA327FFB2, 0x66B56220), /* ~= 10^-262 */
2698 U64(0xFBE91419, 0x15D7A922), U64(0x4BF1FF9F, 0x0062BAA8), /* ~= 10^-261 */
2699 U64(0x9D71AC8F, 0xADA6C9B5), U64(0x6F773FC3, 0x603DB4A9), /* ~= 10^-260 */
2700 U64(0xC4CE17B3, 0x99107C22), U64(0xCB550FB4, 0x384D21D3), /* ~= 10^-259 */
2701 U64(0xF6019DA0, 0x7F549B2B), U64(0x7E2A53A1, 0x46606A48), /* ~= 10^-258 */
2702 U64(0x99C10284, 0x4F94E0FB), U64(0x2EDA7444, 0xCBFC426D), /* ~= 10^-257 */
2703 U64(0xC0314325, 0x637A1939), U64(0xFA911155, 0xFEFB5308), /* ~= 10^-256 */
2704 U64(0xF03D93EE, 0xBC589F88), U64(0x793555AB, 0x7EBA27CA), /* ~= 10^-255 */
2705 U64(0x96267C75, 0x35B763B5), U64(0x4BC1558B, 0x2F3458DE), /* ~= 10^-254 */
2706 U64(0xBBB01B92, 0x83253CA2), U64(0x9EB1AAED, 0xFB016F16), /* ~= 10^-253 */
2707 U64(0xEA9C2277, 0x23EE8BCB), U64(0x465E15A9, 0x79C1CADC), /* ~= 10^-252 */
2708 U64(0x92A1958A, 0x7675175F), U64(0x0BFACD89, 0xEC191EC9), /* ~= 10^-251 */
2709 U64(0xB749FAED, 0x14125D36), U64(0xCEF980EC, 0x671F667B), /* ~= 10^-250 */
2710 U64(0xE51C79A8, 0x5916F484), U64(0x82B7E127, 0x80E7401A), /* ~= 10^-249 */
2711 U64(0x8F31CC09, 0x37AE58D2), U64(0xD1B2ECB8, 0xB0908810), /* ~= 10^-248 */
2712 U64(0xB2FE3F0B, 0x8599EF07), U64(0x861FA7E6, 0xDCB4AA15), /* ~= 10^-247 */
2713 U64(0xDFBDCECE, 0x67006AC9), U64(0x67A791E0, 0x93E1D49A), /* ~= 10^-246 */
2714 U64(0x8BD6A141, 0x006042BD), U64(0xE0C8BB2C, 0x5C6D24E0), /* ~= 10^-245 */
2715 U64(0xAECC4991, 0x4078536D), U64(0x58FAE9F7, 0x73886E18), /* ~= 10^-244 */
2716 U64(0xDA7F5BF5, 0x90966848), U64(0xAF39A475, 0x506A899E), /* ~= 10^-243 */
2717 U64(0x888F9979, 0x7A5E012D), U64(0x6D8406C9, 0x52429603), /* ~= 10^-242 */
2718 U64(0xAAB37FD7, 0xD8F58178), U64(0xC8E5087B, 0xA6D33B83), /* ~= 10^-241 */
2719 U64(0xD5605FCD, 0xCF32E1D6), U64(0xFB1E4A9A, 0x90880A64), /* ~= 10^-240 */
2720 U64(0x855C3BE0, 0xA17FCD26), U64(0x5CF2EEA0, 0x9A55067F), /* ~= 10^-239 */
2721 U64(0xA6B34AD8, 0xC9DFC06F), U64(0xF42FAA48, 0xC0EA481E), /* ~= 10^-238 */
2722 U64(0xD0601D8E, 0xFC57B08B), U64(0xF13B94DA, 0xF124DA26), /* ~= 10^-237 */
2723 U64(0x823C1279, 0x5DB6CE57), U64(0x76C53D08, 0xD6B70858), /* ~= 10^-236 */
2724 U64(0xA2CB1717, 0xB52481ED), U64(0x54768C4B, 0x0C64CA6E), /* ~= 10^-235 */
2725 U64(0xCB7DDCDD, 0xA26DA268), U64(0xA9942F5D, 0xCF7DFD09), /* ~= 10^-234 */
2726 U64(0xFE5D5415, 0x0B090B02), U64(0xD3F93B35, 0x435D7C4C), /* ~= 10^-233 */
2727 U64(0x9EFA548D, 0x26E5A6E1), U64(0xC47BC501, 0x4A1A6DAF), /* ~= 10^-232 */
2728 U64(0xC6B8E9B0, 0x709F109A), U64(0x359AB641, 0x9CA1091B), /* ~= 10^-231 */
2729 U64(0xF867241C, 0x8CC6D4C0), U64(0xC30163D2, 0x03C94B62), /* ~= 10^-230 */
2730 U64(0x9B407691, 0xD7FC44F8), U64(0x79E0DE63, 0x425DCF1D), /* ~= 10^-229 */
2731 U64(0xC2109436, 0x4DFB5636), U64(0x985915FC, 0x12F542E4), /* ~= 10^-228 */
2732 U64(0xF294B943, 0xE17A2BC4), U64(0x3E6F5B7B, 0x17B2939D), /* ~= 10^-227 */
2733 U64(0x979CF3CA, 0x6CEC5B5A), U64(0xA705992C, 0xEECF9C42), /* ~= 10^-226 */
2734 U64(0xBD8430BD, 0x08277231), U64(0x50C6FF78, 0x2A838353), /* ~= 10^-225 */
2735 U64(0xECE53CEC, 0x4A314EBD), U64(0xA4F8BF56, 0x35246428), /* ~= 10^-224 */
2736 U64(0x940F4613, 0xAE5ED136), U64(0x871B7795, 0xE136BE99), /* ~= 10^-223 */
2737 U64(0xB9131798, 0x99F68584), U64(0x28E2557B, 0x59846E3F), /* ~= 10^-222 */
2738 U64(0xE757DD7E, 0xC07426E5), U64(0x331AEADA, 0x2FE589CF), /* ~= 10^-221 */
2739 U64(0x9096EA6F, 0x3848984F), U64(0x3FF0D2C8, 0x5DEF7621), /* ~= 10^-220 */
2740 U64(0xB4BCA50B, 0x065ABE63), U64(0x0FED077A, 0x756B53A9), /* ~= 10^-219 */
2741 U64(0xE1EBCE4D, 0xC7F16DFB), U64(0xD3E84959, 0x12C62894), /* ~= 10^-218 */
2742 U64(0x8D3360F0, 0x9CF6E4BD), U64(0x64712DD7, 0xABBBD95C), /* ~= 10^-217 */
2743 U64(0xB080392C, 0xC4349DEC), U64(0xBD8D794D, 0x96AACFB3), /* ~= 10^-216 */
2744 U64(0xDCA04777, 0xF541C567), U64(0xECF0D7A0, 0xFC5583A0), /* ~= 10^-215 */
2745 U64(0x89E42CAA, 0xF9491B60), U64(0xF41686C4, 0x9DB57244), /* ~= 10^-214 */
2746 U64(0xAC5D37D5, 0xB79B6239), U64(0x311C2875, 0xC522CED5), /* ~= 10^-213 */
2747 U64(0xD77485CB, 0x25823AC7), U64(0x7D633293, 0x366B828B), /* ~= 10^-212 */
2748 U64(0x86A8D39E, 0xF77164BC), U64(0xAE5DFF9C, 0x02033197), /* ~= 10^-211 */
2749 U64(0xA8530886, 0xB54DBDEB), U64(0xD9F57F83, 0x0283FDFC), /* ~= 10^-210 */
2750 U64(0xD267CAA8, 0x62A12D66), U64(0xD072DF63, 0xC324FD7B), /* ~= 10^-209 */
2751 U64(0x8380DEA9, 0x3DA4BC60), U64(0x4247CB9E, 0x59F71E6D), /* ~= 10^-208 */
2752 U64(0xA4611653, 0x8D0DEB78), U64(0x52D9BE85, 0xF074E608), /* ~= 10^-207 */
2753 U64(0xCD795BE8, 0x70516656), U64(0x67902E27, 0x6C921F8B), /* ~= 10^-206 */
2754 U64(0x806BD971, 0x4632DFF6), U64(0x00BA1CD8, 0xA3DB53B6), /* ~= 10^-205 */
2755 U64(0xA086CFCD, 0x97BF97F3), U64(0x80E8A40E, 0xCCD228A4), /* ~= 10^-204 */
2756 U64(0xC8A883C0, 0xFDAF7DF0), U64(0x6122CD12, 0x8006B2CD), /* ~= 10^-203 */
2757 U64(0xFAD2A4B1, 0x3D1B5D6C), U64(0x796B8057, 0x20085F81), /* ~= 10^-202 */
2758 U64(0x9CC3A6EE, 0xC6311A63), U64(0xCBE33036, 0x74053BB0), /* ~= 10^-201 */
2759 U64(0xC3F490AA, 0x77BD60FC), U64(0xBEDBFC44, 0x11068A9C), /* ~= 10^-200 */
2760 U64(0xF4F1B4D5, 0x15ACB93B), U64(0xEE92FB55, 0x15482D44), /* ~= 10^-199 */
2761 U64(0x99171105, 0x2D8BF3C5), U64(0x751BDD15, 0x2D4D1C4A), /* ~= 10^-198 */
2762 U64(0xBF5CD546, 0x78EEF0B6), U64(0xD262D45A, 0x78A0635D), /* ~= 10^-197 */
2763 U64(0xEF340A98, 0x172AACE4), U64(0x86FB8971, 0x16C87C34), /* ~= 10^-196 */
2764 U64(0x9580869F, 0x0E7AAC0E), U64(0xD45D35E6, 0xAE3D4DA0), /* ~= 10^-195 */
2765 U64(0xBAE0A846, 0xD2195712), U64(0x89748360, 0x59CCA109), /* ~= 10^-194 */
2766 U64(0xE998D258, 0x869FACD7), U64(0x2BD1A438, 0x703FC94B), /* ~= 10^-193 */
2767 U64(0x91FF8377, 0x5423CC06), U64(0x7B6306A3, 0x4627DDCF), /* ~= 10^-192 */
2768 U64(0xB67F6455, 0x292CBF08), U64(0x1A3BC84C, 0x17B1D542), /* ~= 10^-191 */
2769 U64(0xE41F3D6A, 0x7377EECA), U64(0x20CABA5F, 0x1D9E4A93), /* ~= 10^-190 */
2770 U64(0x8E938662, 0x882AF53E), U64(0x547EB47B, 0x7282EE9C), /* ~= 10^-189 */
2771 U64(0xB23867FB, 0x2A35B28D), U64(0xE99E619A, 0x4F23AA43), /* ~= 10^-188 */
2772 U64(0xDEC681F9, 0xF4C31F31), U64(0x6405FA00, 0xE2EC94D4), /* ~= 10^-187 */
2773 U64(0x8B3C113C, 0x38F9F37E), U64(0xDE83BC40, 0x8DD3DD04), /* ~= 10^-186 */
2774 U64(0xAE0B158B, 0x4738705E), U64(0x9624AB50, 0xB148D445), /* ~= 10^-185 */
2775 U64(0xD98DDAEE, 0x19068C76), U64(0x3BADD624, 0xDD9B0957), /* ~= 10^-184 */
2776 U64(0x87F8A8D4, 0xCFA417C9), U64(0xE54CA5D7, 0x0A80E5D6), /* ~= 10^-183 */
2777 U64(0xA9F6D30A, 0x038D1DBC), U64(0x5E9FCF4C, 0xCD211F4C), /* ~= 10^-182 */
2778 U64(0xD47487CC, 0x8470652B), U64(0x7647C320, 0x0069671F), /* ~= 10^-181 */
2779 U64(0x84C8D4DF, 0xD2C63F3B), U64(0x29ECD9F4, 0x0041E073), /* ~= 10^-180 */
2780 U64(0xA5FB0A17, 0xC777CF09), U64(0xF4681071, 0x00525890), /* ~= 10^-179 */
2781 U64(0xCF79CC9D, 0xB955C2CC), U64(0x7182148D, 0x4066EEB4), /* ~= 10^-178 */
2782 U64(0x81AC1FE2, 0x93D599BF), U64(0xC6F14CD8, 0x48405530), /* ~= 10^-177 */
2783 U64(0xA21727DB, 0x38CB002F), U64(0xB8ADA00E, 0x5A506A7C), /* ~= 10^-176 */
2784 U64(0xCA9CF1D2, 0x06FDC03B), U64(0xA6D90811, 0xF0E4851C), /* ~= 10^-175 */
2785 U64(0xFD442E46, 0x88BD304A), U64(0x908F4A16, 0x6D1DA663), /* ~= 10^-174 */
2786 U64(0x9E4A9CEC, 0x15763E2E), U64(0x9A598E4E, 0x043287FE), /* ~= 10^-173 */
2787 U64(0xC5DD4427, 0x1AD3CDBA), U64(0x40EFF1E1, 0x853F29FD), /* ~= 10^-172 */
2788 U64(0xF7549530, 0xE188C128), U64(0xD12BEE59, 0xE68EF47C), /* ~= 10^-171 */
2789 U64(0x9A94DD3E, 0x8CF578B9), U64(0x82BB74F8, 0x301958CE), /* ~= 10^-170 */
2790 U64(0xC13A148E, 0x3032D6E7), U64(0xE36A5236, 0x3C1FAF01), /* ~= 10^-169 */
2791 U64(0xF18899B1, 0xBC3F8CA1), U64(0xDC44E6C3, 0xCB279AC1), /* ~= 10^-168 */
2792 U64(0x96F5600F, 0x15A7B7E5), U64(0x29AB103A, 0x5EF8C0B9), /* ~= 10^-167 */
2793 U64(0xBCB2B812, 0xDB11A5DE), U64(0x7415D448, 0xF6B6F0E7), /* ~= 10^-166 */
2794 U64(0xEBDF6617, 0x91D60F56), U64(0x111B495B, 0x3464AD21), /* ~= 10^-165 */
2795 U64(0x936B9FCE, 0xBB25C995), U64(0xCAB10DD9, 0x00BEEC34), /* ~= 10^-164 */
2796 U64(0xB84687C2, 0x69EF3BFB), U64(0x3D5D514F, 0x40EEA742), /* ~= 10^-163 */
2797 U64(0xE65829B3, 0x046B0AFA), U64(0x0CB4A5A3, 0x112A5112), /* ~= 10^-162 */
2798 U64(0x8FF71A0F, 0xE2C2E6DC), U64(0x47F0E785, 0xEABA72AB), /* ~= 10^-161 */
2799 U64(0xB3F4E093, 0xDB73A093), U64(0x59ED2167, 0x65690F56), /* ~= 10^-160 */
2800 U64(0xE0F218B8, 0xD25088B8), U64(0x306869C1, 0x3EC3532C), /* ~= 10^-159 */
2801 U64(0x8C974F73, 0x83725573), U64(0x1E414218, 0xC73A13FB), /* ~= 10^-158 */
2802 U64(0xAFBD2350, 0x644EEACF), U64(0xE5D1929E, 0xF90898FA), /* ~= 10^-157 */
2803 U64(0xDBAC6C24, 0x7D62A583), U64(0xDF45F746, 0xB74ABF39), /* ~= 10^-156 */
2804 U64(0x894BC396, 0xCE5DA772), U64(0x6B8BBA8C, 0x328EB783), /* ~= 10^-155 */
2805 U64(0xAB9EB47C, 0x81F5114F), U64(0x066EA92F, 0x3F326564), /* ~= 10^-154 */
2806 U64(0xD686619B, 0xA27255A2), U64(0xC80A537B, 0x0EFEFEBD), /* ~= 10^-153 */
2807 U64(0x8613FD01, 0x45877585), U64(0xBD06742C, 0xE95F5F36), /* ~= 10^-152 */
2808 U64(0xA798FC41, 0x96E952E7), U64(0x2C481138, 0x23B73704), /* ~= 10^-151 */
2809 U64(0xD17F3B51, 0xFCA3A7A0), U64(0xF75A1586, 0x2CA504C5), /* ~= 10^-150 */
2810 U64(0x82EF8513, 0x3DE648C4), U64(0x9A984D73, 0xDBE722FB), /* ~= 10^-149 */
2811 U64(0xA3AB6658, 0x0D5FDAF5), U64(0xC13E60D0, 0xD2E0EBBA), /* ~= 10^-148 */
2812 U64(0xCC963FEE, 0x10B7D1B3), U64(0x318DF905, 0x079926A8), /* ~= 10^-147 */
2813 U64(0xFFBBCFE9, 0x94E5C61F), U64(0xFDF17746, 0x497F7052), /* ~= 10^-146 */
2814 U64(0x9FD561F1, 0xFD0F9BD3), U64(0xFEB6EA8B, 0xEDEFA633), /* ~= 10^-145 */
2815 U64(0xC7CABA6E, 0x7C5382C8), U64(0xFE64A52E, 0xE96B8FC0), /* ~= 10^-144 */
2816 U64(0xF9BD690A, 0x1B68637B), U64(0x3DFDCE7A, 0xA3C673B0), /* ~= 10^-143 */
2817 U64(0x9C1661A6, 0x51213E2D), U64(0x06BEA10C, 0xA65C084E), /* ~= 10^-142 */
2818 U64(0xC31BFA0F, 0xE5698DB8), U64(0x486E494F, 0xCFF30A62), /* ~= 10^-141 */
2819 U64(0xF3E2F893, 0xDEC3F126), U64(0x5A89DBA3, 0xC3EFCCFA), /* ~= 10^-140 */
2820 U64(0x986DDB5C, 0x6B3A76B7), U64(0xF8962946, 0x5A75E01C), /* ~= 10^-139 */
2821 U64(0xBE895233, 0x86091465), U64(0xF6BBB397, 0xF1135823), /* ~= 10^-138 */
2822 U64(0xEE2BA6C0, 0x678B597F), U64(0x746AA07D, 0xED582E2C), /* ~= 10^-137 */
2823 U64(0x94DB4838, 0x40B717EF), U64(0xA8C2A44E, 0xB4571CDC), /* ~= 10^-136 */
2824 U64(0xBA121A46, 0x50E4DDEB), U64(0x92F34D62, 0x616CE413), /* ~= 10^-135 */
2825 U64(0xE896A0D7, 0xE51E1566), U64(0x77B020BA, 0xF9C81D17), /* ~= 10^-134 */
2826 U64(0x915E2486, 0xEF32CD60), U64(0x0ACE1474, 0xDC1D122E), /* ~= 10^-133 */
2827 U64(0xB5B5ADA8, 0xAAFF80B8), U64(0x0D819992, 0x132456BA), /* ~= 10^-132 */
2828 U64(0xE3231912, 0xD5BF60E6), U64(0x10E1FFF6, 0x97ED6C69), /* ~= 10^-131 */
2829 U64(0x8DF5EFAB, 0xC5979C8F), U64(0xCA8D3FFA, 0x1EF463C1), /* ~= 10^-130 */
2830 U64(0xB1736B96, 0xB6FD83B3), U64(0xBD308FF8, 0xA6B17CB2), /* ~= 10^-129 */
2831 U64(0xDDD0467C, 0x64BCE4A0), U64(0xAC7CB3F6, 0xD05DDBDE), /* ~= 10^-128 */
2832 U64(0x8AA22C0D, 0xBEF60EE4), U64(0x6BCDF07A, 0x423AA96B), /* ~= 10^-127 */
2833 U64(0xAD4AB711, 0x2EB3929D), U64(0x86C16C98, 0xD2C953C6), /* ~= 10^-126 */
2834 U64(0xD89D64D5, 0x7A607744), U64(0xE871C7BF, 0x077BA8B7), /* ~= 10^-125 */
2835 U64(0x87625F05, 0x6C7C4A8B), U64(0x11471CD7, 0x64AD4972), /* ~= 10^-124 */
2836 U64(0xA93AF6C6, 0xC79B5D2D), U64(0xD598E40D, 0x3DD89BCF), /* ~= 10^-123 */
2837 U64(0xD389B478, 0x79823479), U64(0x4AFF1D10, 0x8D4EC2C3), /* ~= 10^-122 */
2838 U64(0x843610CB, 0x4BF160CB), U64(0xCEDF722A, 0x585139BA), /* ~= 10^-121 */
2839 U64(0xA54394FE, 0x1EEDB8FE), U64(0xC2974EB4, 0xEE658828), /* ~= 10^-120 */
2840 U64(0xCE947A3D, 0xA6A9273E), U64(0x733D2262, 0x29FEEA32), /* ~= 10^-119 */
2841 U64(0x811CCC66, 0x8829B887), U64(0x0806357D, 0x5A3F525F), /* ~= 10^-118 */
2842 U64(0xA163FF80, 0x2A3426A8), U64(0xCA07C2DC, 0xB0CF26F7), /* ~= 10^-117 */
2843 U64(0xC9BCFF60, 0x34C13052), U64(0xFC89B393, 0xDD02F0B5), /* ~= 10^-116 */
2844 U64(0xFC2C3F38, 0x41F17C67), U64(0xBBAC2078, 0xD443ACE2), /* ~= 10^-115 */
2845 U64(0x9D9BA783, 0x2936EDC0), U64(0xD54B944B, 0x84AA4C0D), /* ~= 10^-114 */
2846 U64(0xC5029163, 0xF384A931), U64(0x0A9E795E, 0x65D4DF11), /* ~= 10^-113 */
2847 U64(0xF64335BC, 0xF065D37D), U64(0x4D4617B5, 0xFF4A16D5), /* ~= 10^-112 */
2848 U64(0x99EA0196, 0x163FA42E), U64(0x504BCED1, 0xBF8E4E45), /* ~= 10^-111 */
2849 U64(0xC06481FB, 0x9BCF8D39), U64(0xE45EC286, 0x2F71E1D6), /* ~= 10^-110 */
2850 U64(0xF07DA27A, 0x82C37088), U64(0x5D767327, 0xBB4E5A4C), /* ~= 10^-109 */
2851 U64(0x964E858C, 0x91BA2655), U64(0x3A6A07F8, 0xD510F86F), /* ~= 10^-108 */
2852 U64(0xBBE226EF, 0xB628AFEA), U64(0x890489F7, 0x0A55368B), /* ~= 10^-107 */
2853 U64(0xEADAB0AB, 0xA3B2DBE5), U64(0x2B45AC74, 0xCCEA842E), /* ~= 10^-106 */
2854 U64(0x92C8AE6B, 0x464FC96F), U64(0x3B0B8BC9, 0x0012929D), /* ~= 10^-105 */
2855 U64(0xB77ADA06, 0x17E3BBCB), U64(0x09CE6EBB, 0x40173744), /* ~= 10^-104 */
2856 U64(0xE5599087, 0x9DDCAABD), U64(0xCC420A6A, 0x101D0515), /* ~= 10^-103 */
2857 U64(0x8F57FA54, 0xC2A9EAB6), U64(0x9FA94682, 0x4A12232D), /* ~= 10^-102 */
2858 U64(0xB32DF8E9, 0xF3546564), U64(0x47939822, 0xDC96ABF9), /* ~= 10^-101 */
2859 U64(0xDFF97724, 0x70297EBD), U64(0x59787E2B, 0x93BC56F7), /* ~= 10^-100 */
2860 U64(0x8BFBEA76, 0xC619EF36), U64(0x57EB4EDB, 0x3C55B65A), /* ~= 10^-99 */
2861 U64(0xAEFAE514, 0x77A06B03), U64(0xEDE62292, 0x0B6B23F1), /* ~= 10^-98 */
2862 U64(0xDAB99E59, 0x958885C4), U64(0xE95FAB36, 0x8E45ECED), /* ~= 10^-97 */
2863 U64(0x88B402F7, 0xFD75539B), U64(0x11DBCB02, 0x18EBB414), /* ~= 10^-96 */
2864 U64(0xAAE103B5, 0xFCD2A881), U64(0xD652BDC2, 0x9F26A119), /* ~= 10^-95 */
2865 U64(0xD59944A3, 0x7C0752A2), U64(0x4BE76D33, 0x46F0495F), /* ~= 10^-94 */
2866 U64(0x857FCAE6, 0x2D8493A5), U64(0x6F70A440, 0x0C562DDB), /* ~= 10^-93 */
2867 U64(0xA6DFBD9F, 0xB8E5B88E), U64(0xCB4CCD50, 0x0F6BB952), /* ~= 10^-92 */
2868 U64(0xD097AD07, 0xA71F26B2), U64(0x7E2000A4, 0x1346A7A7), /* ~= 10^-91 */
2869 U64(0x825ECC24, 0xC873782F), U64(0x8ED40066, 0x8C0C28C8), /* ~= 10^-90 */
2870 U64(0xA2F67F2D, 0xFA90563B), U64(0x72890080, 0x2F0F32FA), /* ~= 10^-89 */
2871 U64(0xCBB41EF9, 0x79346BCA), U64(0x4F2B40A0, 0x3AD2FFB9), /* ~= 10^-88 */
2872 U64(0xFEA126B7, 0xD78186BC), U64(0xE2F610C8, 0x4987BFA8), /* ~= 10^-87 */
2873 U64(0x9F24B832, 0xE6B0F436), U64(0x0DD9CA7D, 0x2DF4D7C9), /* ~= 10^-86 */
2874 U64(0xC6EDE63F, 0xA05D3143), U64(0x91503D1C, 0x79720DBB), /* ~= 10^-85 */
2875 U64(0xF8A95FCF, 0x88747D94), U64(0x75A44C63, 0x97CE912A), /* ~= 10^-84 */
2876 U64(0x9B69DBE1, 0xB548CE7C), U64(0xC986AFBE, 0x3EE11ABA), /* ~= 10^-83 */
2877 U64(0xC24452DA, 0x229B021B), U64(0xFBE85BAD, 0xCE996168), /* ~= 10^-82 */
2878 U64(0xF2D56790, 0xAB41C2A2), U64(0xFAE27299, 0x423FB9C3), /* ~= 10^-81 */
2879 U64(0x97C560BA, 0x6B0919A5), U64(0xDCCD879F, 0xC967D41A), /* ~= 10^-80 */
2880 U64(0xBDB6B8E9, 0x05CB600F), U64(0x5400E987, 0xBBC1C920), /* ~= 10^-79 */
2881 U64(0xED246723, 0x473E3813), U64(0x290123E9, 0xAAB23B68), /* ~= 10^-78 */
2882 U64(0x9436C076, 0x0C86E30B), U64(0xF9A0B672, 0x0AAF6521), /* ~= 10^-77 */
2883 U64(0xB9447093, 0x8FA89BCE), U64(0xF808E40E, 0x8D5B3E69), /* ~= 10^-76 */
2884 U64(0xE7958CB8, 0x7392C2C2), U64(0xB60B1D12, 0x30B20E04), /* ~= 10^-75 */
2885 U64(0x90BD77F3, 0x483BB9B9), U64(0xB1C6F22B, 0x5E6F48C2), /* ~= 10^-74 */
2886 U64(0xB4ECD5F0, 0x1A4AA828), U64(0x1E38AEB6, 0x360B1AF3), /* ~= 10^-73 */
2887 U64(0xE2280B6C, 0x20DD5232), U64(0x25C6DA63, 0xC38DE1B0), /* ~= 10^-72 */
2888 U64(0x8D590723, 0x948A535F), U64(0x579C487E, 0x5A38AD0E), /* ~= 10^-71 */
2889 U64(0xB0AF48EC, 0x79ACE837), U64(0x2D835A9D, 0xF0C6D851), /* ~= 10^-70 */
2890 U64(0xDCDB1B27, 0x98182244), U64(0xF8E43145, 0x6CF88E65), /* ~= 10^-69 */
2891 U64(0x8A08F0F8, 0xBF0F156B), U64(0x1B8E9ECB, 0x641B58FF), /* ~= 10^-68 */
2892 U64(0xAC8B2D36, 0xEED2DAC5), U64(0xE272467E, 0x3D222F3F), /* ~= 10^-67 */
2893 U64(0xD7ADF884, 0xAA879177), U64(0x5B0ED81D, 0xCC6ABB0F), /* ~= 10^-66 */
2894 U64(0x86CCBB52, 0xEA94BAEA), U64(0x98E94712, 0x9FC2B4E9), /* ~= 10^-65 */
2895 U64(0xA87FEA27, 0xA539E9A5), U64(0x3F2398D7, 0x47B36224), /* ~= 10^-64 */
2896 U64(0xD29FE4B1, 0x8E88640E), U64(0x8EEC7F0D, 0x19A03AAD), /* ~= 10^-63 */
2897 U64(0x83A3EEEE, 0xF9153E89), U64(0x1953CF68, 0x300424AC), /* ~= 10^-62 */
2898 U64(0xA48CEAAA, 0xB75A8E2B), U64(0x5FA8C342, 0x3C052DD7), /* ~= 10^-61 */
2899 U64(0xCDB02555, 0x653131B6), U64(0x3792F412, 0xCB06794D), /* ~= 10^-60 */
2900 U64(0x808E1755, 0x5F3EBF11), U64(0xE2BBD88B, 0xBEE40BD0), /* ~= 10^-59 */
2901 U64(0xA0B19D2A, 0xB70E6ED6), U64(0x5B6ACEAE, 0xAE9D0EC4), /* ~= 10^-58 */
2902 U64(0xC8DE0475, 0x64D20A8B), U64(0xF245825A, 0x5A445275), /* ~= 10^-57 */
2903 U64(0xFB158592, 0xBE068D2E), U64(0xEED6E2F0, 0xF0D56712), /* ~= 10^-56 */
2904 U64(0x9CED737B, 0xB6C4183D), U64(0x55464DD6, 0x9685606B), /* ~= 10^-55 */
2905 U64(0xC428D05A, 0xA4751E4C), U64(0xAA97E14C, 0x3C26B886), /* ~= 10^-54 */
2906 U64(0xF5330471, 0x4D9265DF), U64(0xD53DD99F, 0x4B3066A8), /* ~= 10^-53 */
2907 U64(0x993FE2C6, 0xD07B7FAB), U64(0xE546A803, 0x8EFE4029), /* ~= 10^-52 */
2908 U64(0xBF8FDB78, 0x849A5F96), U64(0xDE985204, 0x72BDD033), /* ~= 10^-51 */
2909 U64(0xEF73D256, 0xA5C0F77C), U64(0x963E6685, 0x8F6D4440), /* ~= 10^-50 */
2910 U64(0x95A86376, 0x27989AAD), U64(0xDDE70013, 0x79A44AA8), /* ~= 10^-49 */
2911 U64(0xBB127C53, 0xB17EC159), U64(0x5560C018, 0x580D5D52), /* ~= 10^-48 */
2912 U64(0xE9D71B68, 0x9DDE71AF), U64(0xAAB8F01E, 0x6E10B4A6), /* ~= 10^-47 */
2913 U64(0x92267121, 0x62AB070D), U64(0xCAB39613, 0x04CA70E8), /* ~= 10^-46 */
2914 U64(0xB6B00D69, 0xBB55C8D1), U64(0x3D607B97, 0xC5FD0D22), /* ~= 10^-45 */
2915 U64(0xE45C10C4, 0x2A2B3B05), U64(0x8CB89A7D, 0xB77C506A), /* ~= 10^-44 */
2916 U64(0x8EB98A7A, 0x9A5B04E3), U64(0x77F3608E, 0x92ADB242), /* ~= 10^-43 */
2917 U64(0xB267ED19, 0x40F1C61C), U64(0x55F038B2, 0x37591ED3), /* ~= 10^-42 */
2918 U64(0xDF01E85F, 0x912E37A3), U64(0x6B6C46DE, 0xC52F6688), /* ~= 10^-41 */
2919 U64(0x8B61313B, 0xBABCE2C6), U64(0x2323AC4B, 0x3B3DA015), /* ~= 10^-40 */
2920 U64(0xAE397D8A, 0xA96C1B77), U64(0xABEC975E, 0x0A0D081A), /* ~= 10^-39 */
2921 U64(0xD9C7DCED, 0x53C72255), U64(0x96E7BD35, 0x8C904A21), /* ~= 10^-38 */
2922 U64(0x881CEA14, 0x545C7575), U64(0x7E50D641, 0x77DA2E54), /* ~= 10^-37 */
2923 U64(0xAA242499, 0x697392D2), U64(0xDDE50BD1, 0xD5D0B9E9), /* ~= 10^-36 */
2924 U64(0xD4AD2DBF, 0xC3D07787), U64(0x955E4EC6, 0x4B44E864), /* ~= 10^-35 */
2925 U64(0x84EC3C97, 0xDA624AB4), U64(0xBD5AF13B, 0xEF0B113E), /* ~= 10^-34 */
2926 U64(0xA6274BBD, 0xD0FADD61), U64(0xECB1AD8A, 0xEACDD58E), /* ~= 10^-33 */
2927 U64(0xCFB11EAD, 0x453994BA), U64(0x67DE18ED, 0xA5814AF2), /* ~= 10^-32 */
2928 U64(0x81CEB32C, 0x4B43FCF4), U64(0x80EACF94, 0x8770CED7), /* ~= 10^-31 */
2929 U64(0xA2425FF7, 0x5E14FC31), U64(0xA1258379, 0xA94D028D), /* ~= 10^-30 */
2930 U64(0xCAD2F7F5, 0x359A3B3E), U64(0x096EE458, 0x13A04330), /* ~= 10^-29 */
2931 U64(0xFD87B5F2, 0x8300CA0D), U64(0x8BCA9D6E, 0x188853FC), /* ~= 10^-28 */
2932 U64(0x9E74D1B7, 0x91E07E48), U64(0x775EA264, 0xCF55347D), /* ~= 10^-27 */
2933 U64(0xC6120625, 0x76589DDA), U64(0x95364AFE, 0x032A819D), /* ~= 10^-26 */
2934 U64(0xF79687AE, 0xD3EEC551), U64(0x3A83DDBD, 0x83F52204), /* ~= 10^-25 */
2935 U64(0x9ABE14CD, 0x44753B52), U64(0xC4926A96, 0x72793542), /* ~= 10^-24 */
2936 U64(0xC16D9A00, 0x95928A27), U64(0x75B7053C, 0x0F178293), /* ~= 10^-23 */
2937 U64(0xF1C90080, 0xBAF72CB1), U64(0x5324C68B, 0x12DD6338), /* ~= 10^-22 */
2938 U64(0x971DA050, 0x74DA7BEE), U64(0xD3F6FC16, 0xEBCA5E03), /* ~= 10^-21 */
2939 U64(0xBCE50864, 0x92111AEA), U64(0x88F4BB1C, 0xA6BCF584), /* ~= 10^-20 */
2940 U64(0xEC1E4A7D, 0xB69561A5), U64(0x2B31E9E3, 0xD06C32E5), /* ~= 10^-19 */
2941 U64(0x9392EE8E, 0x921D5D07), U64(0x3AFF322E, 0x62439FCF), /* ~= 10^-18 */
2942 U64(0xB877AA32, 0x36A4B449), U64(0x09BEFEB9, 0xFAD487C2), /* ~= 10^-17 */
2943 U64(0xE69594BE, 0xC44DE15B), U64(0x4C2EBE68, 0x7989A9B3), /* ~= 10^-16 */
2944 U64(0x901D7CF7, 0x3AB0ACD9), U64(0x0F9D3701, 0x4BF60A10), /* ~= 10^-15 */
2945 U64(0xB424DC35, 0x095CD80F), U64(0x538484C1, 0x9EF38C94), /* ~= 10^-14 */
2946 U64(0xE12E1342, 0x4BB40E13), U64(0x2865A5F2, 0x06B06FB9), /* ~= 10^-13 */
2947 U64(0x8CBCCC09, 0x6F5088CB), U64(0xF93F87B7, 0x442E45D3), /* ~= 10^-12 */
2948 U64(0xAFEBFF0B, 0xCB24AAFE), U64(0xF78F69A5, 0x1539D748), /* ~= 10^-11 */
2949 U64(0xDBE6FECE, 0xBDEDD5BE), U64(0xB573440E, 0x5A884D1B), /* ~= 10^-10 */
2950 U64(0x89705F41, 0x36B4A597), U64(0x31680A88, 0xF8953030), /* ~= 10^-9 */
2951 U64(0xABCC7711, 0x8461CEFC), U64(0xFDC20D2B, 0x36BA7C3D), /* ~= 10^-8 */
2952 U64(0xD6BF94D5, 0xE57A42BC), U64(0x3D329076, 0x04691B4C), /* ~= 10^-7 */
2953 U64(0x8637BD05, 0xAF6C69B5), U64(0xA63F9A49, 0xC2C1B10F), /* ~= 10^-6 */
2954 U64(0xA7C5AC47, 0x1B478423), U64(0x0FCF80DC, 0x33721D53), /* ~= 10^-5 */
2955 U64(0xD1B71758, 0xE219652B), U64(0xD3C36113, 0x404EA4A8), /* ~= 10^-4 */
2956 U64(0x83126E97, 0x8D4FDF3B), U64(0x645A1CAC, 0x083126E9), /* ~= 10^-3 */
2957 U64(0xA3D70A3D, 0x70A3D70A), U64(0x3D70A3D7, 0x0A3D70A3), /* ~= 10^-2 */
2958 U64(0xCCCCCCCC, 0xCCCCCCCC), U64(0xCCCCCCCC, 0xCCCCCCCC), /* ~= 10^-1 */
2959 U64(0x80000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^0 */
2960 U64(0xA0000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^1 */
2961 U64(0xC8000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^2 */
2962 U64(0xFA000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^3 */
2963 U64(0x9C400000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^4 */
2964 U64(0xC3500000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^5 */
2965 U64(0xF4240000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^6 */
2966 U64(0x98968000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^7 */
2967 U64(0xBEBC2000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^8 */
2968 U64(0xEE6B2800, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^9 */
2969 U64(0x9502F900, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^10 */
2970 U64(0xBA43B740, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^11 */
2971 U64(0xE8D4A510, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^12 */
2972 U64(0x9184E72A, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^13 */
2973 U64(0xB5E620F4, 0x80000000), U64(0x00000000, 0x00000000), /* == 10^14 */
2974 U64(0xE35FA931, 0xA0000000), U64(0x00000000, 0x00000000), /* == 10^15 */
2975 U64(0x8E1BC9BF, 0x04000000), U64(0x00000000, 0x00000000), /* == 10^16 */
2976 U64(0xB1A2BC2E, 0xC5000000), U64(0x00000000, 0x00000000), /* == 10^17 */
2977 U64(0xDE0B6B3A, 0x76400000), U64(0x00000000, 0x00000000), /* == 10^18 */
2978 U64(0x8AC72304, 0x89E80000), U64(0x00000000, 0x00000000), /* == 10^19 */
2979 U64(0xAD78EBC5, 0xAC620000), U64(0x00000000, 0x00000000), /* == 10^20 */
2980 U64(0xD8D726B7, 0x177A8000), U64(0x00000000, 0x00000000), /* == 10^21 */
2981 U64(0x87867832, 0x6EAC9000), U64(0x00000000, 0x00000000), /* == 10^22 */
2982 U64(0xA968163F, 0x0A57B400), U64(0x00000000, 0x00000000), /* == 10^23 */
2983 U64(0xD3C21BCE, 0xCCEDA100), U64(0x00000000, 0x00000000), /* == 10^24 */
2984 U64(0x84595161, 0x401484A0), U64(0x00000000, 0x00000000), /* == 10^25 */
2985 U64(0xA56FA5B9, 0x9019A5C8), U64(0x00000000, 0x00000000), /* == 10^26 */
2986 U64(0xCECB8F27, 0xF4200F3A), U64(0x00000000, 0x00000000), /* == 10^27 */
2987 U64(0x813F3978, 0xF8940984), U64(0x40000000, 0x00000000), /* == 10^28 */
2988 U64(0xA18F07D7, 0x36B90BE5), U64(0x50000000, 0x00000000), /* == 10^29 */
2989 U64(0xC9F2C9CD, 0x04674EDE), U64(0xA4000000, 0x00000000), /* == 10^30 */
2990 U64(0xFC6F7C40, 0x45812296), U64(0x4D000000, 0x00000000), /* == 10^31 */
2991 U64(0x9DC5ADA8, 0x2B70B59D), U64(0xF0200000, 0x00000000), /* == 10^32 */
2992 U64(0xC5371912, 0x364CE305), U64(0x6C280000, 0x00000000), /* == 10^33 */
2993 U64(0xF684DF56, 0xC3E01BC6), U64(0xC7320000, 0x00000000), /* == 10^34 */
2994 U64(0x9A130B96, 0x3A6C115C), U64(0x3C7F4000, 0x00000000), /* == 10^35 */
2995 U64(0xC097CE7B, 0xC90715B3), U64(0x4B9F1000, 0x00000000), /* == 10^36 */
2996 U64(0xF0BDC21A, 0xBB48DB20), U64(0x1E86D400, 0x00000000), /* == 10^37 */
2997 U64(0x96769950, 0xB50D88F4), U64(0x13144480, 0x00000000), /* == 10^38 */
2998 U64(0xBC143FA4, 0xE250EB31), U64(0x17D955A0, 0x00000000), /* == 10^39 */
2999 U64(0xEB194F8E, 0x1AE525FD), U64(0x5DCFAB08, 0x00000000), /* == 10^40 */
3000 U64(0x92EFD1B8, 0xD0CF37BE), U64(0x5AA1CAE5, 0x00000000), /* == 10^41 */
3001 U64(0xB7ABC627, 0x050305AD), U64(0xF14A3D9E, 0x40000000), /* == 10^42 */
3002 U64(0xE596B7B0, 0xC643C719), U64(0x6D9CCD05, 0xD0000000), /* == 10^43 */
3003 U64(0x8F7E32CE, 0x7BEA5C6F), U64(0xE4820023, 0xA2000000), /* == 10^44 */
3004 U64(0xB35DBF82, 0x1AE4F38B), U64(0xDDA2802C, 0x8A800000), /* == 10^45 */
3005 U64(0xE0352F62, 0xA19E306E), U64(0xD50B2037, 0xAD200000), /* == 10^46 */
3006 U64(0x8C213D9D, 0xA502DE45), U64(0x4526F422, 0xCC340000), /* == 10^47 */
3007 U64(0xAF298D05, 0x0E4395D6), U64(0x9670B12B, 0x7F410000), /* == 10^48 */
3008 U64(0xDAF3F046, 0x51D47B4C), U64(0x3C0CDD76, 0x5F114000), /* == 10^49 */
3009 U64(0x88D8762B, 0xF324CD0F), U64(0xA5880A69, 0xFB6AC800), /* == 10^50 */
3010 U64(0xAB0E93B6, 0xEFEE0053), U64(0x8EEA0D04, 0x7A457A00), /* == 10^51 */
3011 U64(0xD5D238A4, 0xABE98068), U64(0x72A49045, 0x98D6D880), /* == 10^52 */
3012 U64(0x85A36366, 0xEB71F041), U64(0x47A6DA2B, 0x7F864750), /* == 10^53 */
3013 U64(0xA70C3C40, 0xA64E6C51), U64(0x999090B6, 0x5F67D924), /* == 10^54 */
3014 U64(0xD0CF4B50, 0xCFE20765), U64(0xFFF4B4E3, 0xF741CF6D), /* == 10^55 */
3015 U64(0x82818F12, 0x81ED449F), U64(0xBFF8F10E, 0x7A8921A4), /* ~= 10^56 */
3016 U64(0xA321F2D7, 0x226895C7), U64(0xAFF72D52, 0x192B6A0D), /* ~= 10^57 */
3017 U64(0xCBEA6F8C, 0xEB02BB39), U64(0x9BF4F8A6, 0x9F764490), /* ~= 10^58 */
3018 U64(0xFEE50B70, 0x25C36A08), U64(0x02F236D0, 0x4753D5B4), /* ~= 10^59 */
3019 U64(0x9F4F2726, 0x179A2245), U64(0x01D76242, 0x2C946590), /* ~= 10^60 */
3020 U64(0xC722F0EF, 0x9D80AAD6), U64(0x424D3AD2, 0xB7B97EF5), /* ~= 10^61 */
3021 U64(0xF8EBAD2B, 0x84E0D58B), U64(0xD2E08987, 0x65A7DEB2), /* ~= 10^62 */
3022 U64(0x9B934C3B, 0x330C8577), U64(0x63CC55F4, 0x9F88EB2F), /* ~= 10^63 */
3023 U64(0xC2781F49, 0xFFCFA6D5), U64(0x3CBF6B71, 0xC76B25FB), /* ~= 10^64 */
3024 U64(0xF316271C, 0x7FC3908A), U64(0x8BEF464E, 0x3945EF7A), /* ~= 10^65 */
3025 U64(0x97EDD871, 0xCFDA3A56), U64(0x97758BF0, 0xE3CBB5AC), /* ~= 10^66 */
3026 U64(0xBDE94E8E, 0x43D0C8EC), U64(0x3D52EEED, 0x1CBEA317), /* ~= 10^67 */
3027 U64(0xED63A231, 0xD4C4FB27), U64(0x4CA7AAA8, 0x63EE4BDD), /* ~= 10^68 */
3028 U64(0x945E455F, 0x24FB1CF8), U64(0x8FE8CAA9, 0x3E74EF6A), /* ~= 10^69 */
3029 U64(0xB975D6B6, 0xEE39E436), U64(0xB3E2FD53, 0x8E122B44), /* ~= 10^70 */
3030 U64(0xE7D34C64, 0xA9C85D44), U64(0x60DBBCA8, 0x7196B616), /* ~= 10^71 */
3031 U64(0x90E40FBE, 0xEA1D3A4A), U64(0xBC8955E9, 0x46FE31CD), /* ~= 10^72 */
3032 U64(0xB51D13AE, 0xA4A488DD), U64(0x6BABAB63, 0x98BDBE41), /* ~= 10^73 */
3033 U64(0xE264589A, 0x4DCDAB14), U64(0xC696963C, 0x7EED2DD1), /* ~= 10^74 */
3034 U64(0x8D7EB760, 0x70A08AEC), U64(0xFC1E1DE5, 0xCF543CA2), /* ~= 10^75 */
3035 U64(0xB0DE6538, 0x8CC8ADA8), U64(0x3B25A55F, 0x43294BCB), /* ~= 10^76 */
3036 U64(0xDD15FE86, 0xAFFAD912), U64(0x49EF0EB7, 0x13F39EBE), /* ~= 10^77 */
3037 U64(0x8A2DBF14, 0x2DFCC7AB), U64(0x6E356932, 0x6C784337), /* ~= 10^78 */
3038 U64(0xACB92ED9, 0x397BF996), U64(0x49C2C37F, 0x07965404), /* ~= 10^79 */
3039 U64(0xD7E77A8F, 0x87DAF7FB), U64(0xDC33745E, 0xC97BE906), /* ~= 10^80 */
3040 U64(0x86F0AC99, 0xB4E8DAFD), U64(0x69A028BB, 0x3DED71A3), /* ~= 10^81 */
3041 U64(0xA8ACD7C0, 0x222311BC), U64(0xC40832EA, 0x0D68CE0C), /* ~= 10^82 */
3042 U64(0xD2D80DB0, 0x2AABD62B), U64(0xF50A3FA4, 0x90C30190), /* ~= 10^83 */
3043 U64(0x83C7088E, 0x1AAB65DB), U64(0x792667C6, 0xDA79E0FA), /* ~= 10^84 */
3044 U64(0xA4B8CAB1, 0xA1563F52), U64(0x577001B8, 0x91185938), /* ~= 10^85 */
3045 U64(0xCDE6FD5E, 0x09ABCF26), U64(0xED4C0226, 0xB55E6F86), /* ~= 10^86 */
3046 U64(0x80B05E5A, 0xC60B6178), U64(0x544F8158, 0x315B05B4), /* ~= 10^87 */
3047 U64(0xA0DC75F1, 0x778E39D6), U64(0x696361AE, 0x3DB1C721), /* ~= 10^88 */
3048 U64(0xC913936D, 0xD571C84C), U64(0x03BC3A19, 0xCD1E38E9), /* ~= 10^89 */
3049 U64(0xFB587849, 0x4ACE3A5F), U64(0x04AB48A0, 0x4065C723), /* ~= 10^90 */
3050 U64(0x9D174B2D, 0xCEC0E47B), U64(0x62EB0D64, 0x283F9C76), /* ~= 10^91 */
3051 U64(0xC45D1DF9, 0x42711D9A), U64(0x3BA5D0BD, 0x324F8394), /* ~= 10^92 */
3052 U64(0xF5746577, 0x930D6500), U64(0xCA8F44EC, 0x7EE36479), /* ~= 10^93 */
3053 U64(0x9968BF6A, 0xBBE85F20), U64(0x7E998B13, 0xCF4E1ECB), /* ~= 10^94 */
3054 U64(0xBFC2EF45, 0x6AE276E8), U64(0x9E3FEDD8, 0xC321A67E), /* ~= 10^95 */
3055 U64(0xEFB3AB16, 0xC59B14A2), U64(0xC5CFE94E, 0xF3EA101E), /* ~= 10^96 */
3056 U64(0x95D04AEE, 0x3B80ECE5), U64(0xBBA1F1D1, 0x58724A12), /* ~= 10^97 */
3057 U64(0xBB445DA9, 0xCA61281F), U64(0x2A8A6E45, 0xAE8EDC97), /* ~= 10^98 */
3058 U64(0xEA157514, 0x3CF97226), U64(0xF52D09D7, 0x1A3293BD), /* ~= 10^99 */
3059 U64(0x924D692C, 0xA61BE758), U64(0x593C2626, 0x705F9C56), /* ~= 10^100 */
3060 U64(0xB6E0C377, 0xCFA2E12E), U64(0x6F8B2FB0, 0x0C77836C), /* ~= 10^101 */
3061 U64(0xE498F455, 0xC38B997A), U64(0x0B6DFB9C, 0x0F956447), /* ~= 10^102 */
3062 U64(0x8EDF98B5, 0x9A373FEC), U64(0x4724BD41, 0x89BD5EAC), /* ~= 10^103 */
3063 U64(0xB2977EE3, 0x00C50FE7), U64(0x58EDEC91, 0xEC2CB657), /* ~= 10^104 */
3064 U64(0xDF3D5E9B, 0xC0F653E1), U64(0x2F2967B6, 0x6737E3ED), /* ~= 10^105 */
3065 U64(0x8B865B21, 0x5899F46C), U64(0xBD79E0D2, 0x0082EE74), /* ~= 10^106 */
3066 U64(0xAE67F1E9, 0xAEC07187), U64(0xECD85906, 0x80A3AA11), /* ~= 10^107 */
3067 U64(0xDA01EE64, 0x1A708DE9), U64(0xE80E6F48, 0x20CC9495), /* ~= 10^108 */
3068 U64(0x884134FE, 0x908658B2), U64(0x3109058D, 0x147FDCDD), /* ~= 10^109 */
3069 U64(0xAA51823E, 0x34A7EEDE), U64(0xBD4B46F0, 0x599FD415), /* ~= 10^110 */
3070 U64(0xD4E5E2CD, 0xC1D1EA96), U64(0x6C9E18AC, 0x7007C91A), /* ~= 10^111 */
3071 U64(0x850FADC0, 0x9923329E), U64(0x03E2CF6B, 0xC604DDB0), /* ~= 10^112 */
3072 U64(0xA6539930, 0xBF6BFF45), U64(0x84DB8346, 0xB786151C), /* ~= 10^113 */
3073 U64(0xCFE87F7C, 0xEF46FF16), U64(0xE6126418, 0x65679A63), /* ~= 10^114 */
3074 U64(0x81F14FAE, 0x158C5F6E), U64(0x4FCB7E8F, 0x3F60C07E), /* ~= 10^115 */
3075 U64(0xA26DA399, 0x9AEF7749), U64(0xE3BE5E33, 0x0F38F09D), /* ~= 10^116 */
3076 U64(0xCB090C80, 0x01AB551C), U64(0x5CADF5BF, 0xD3072CC5), /* ~= 10^117 */
3077 U64(0xFDCB4FA0, 0x02162A63), U64(0x73D9732F, 0xC7C8F7F6), /* ~= 10^118 */
3078 U64(0x9E9F11C4, 0x014DDA7E), U64(0x2867E7FD, 0xDCDD9AFA), /* ~= 10^119 */
3079 U64(0xC646D635, 0x01A1511D), U64(0xB281E1FD, 0x541501B8), /* ~= 10^120 */
3080 U64(0xF7D88BC2, 0x4209A565), U64(0x1F225A7C, 0xA91A4226), /* ~= 10^121 */
3081 U64(0x9AE75759, 0x6946075F), U64(0x3375788D, 0xE9B06958), /* ~= 10^122 */
3082 U64(0xC1A12D2F, 0xC3978937), U64(0x0052D6B1, 0x641C83AE), /* ~= 10^123 */
3083 U64(0xF209787B, 0xB47D6B84), U64(0xC0678C5D, 0xBD23A49A), /* ~= 10^124 */
3084 U64(0x9745EB4D, 0x50CE6332), U64(0xF840B7BA, 0x963646E0), /* ~= 10^125 */
3085 U64(0xBD176620, 0xA501FBFF), U64(0xB650E5A9, 0x3BC3D898), /* ~= 10^126 */
3086 U64(0xEC5D3FA8, 0xCE427AFF), U64(0xA3E51F13, 0x8AB4CEBE), /* ~= 10^127 */
3087 U64(0x93BA47C9, 0x80E98CDF), U64(0xC66F336C, 0x36B10137), /* ~= 10^128 */
3088 U64(0xB8A8D9BB, 0xE123F017), U64(0xB80B0047, 0x445D4184), /* ~= 10^129 */
3089 U64(0xE6D3102A, 0xD96CEC1D), U64(0xA60DC059, 0x157491E5), /* ~= 10^130 */
3090 U64(0x9043EA1A, 0xC7E41392), U64(0x87C89837, 0xAD68DB2F), /* ~= 10^131 */
3091 U64(0xB454E4A1, 0x79DD1877), U64(0x29BABE45, 0x98C311FB), /* ~= 10^132 */
3092 U64(0xE16A1DC9, 0xD8545E94), U64(0xF4296DD6, 0xFEF3D67A), /* ~= 10^133 */
3093 U64(0x8CE2529E, 0x2734BB1D), U64(0x1899E4A6, 0x5F58660C), /* ~= 10^134 */
3094 U64(0xB01AE745, 0xB101E9E4), U64(0x5EC05DCF, 0xF72E7F8F), /* ~= 10^135 */
3095 U64(0xDC21A117, 0x1D42645D), U64(0x76707543, 0xF4FA1F73), /* ~= 10^136 */
3096 U64(0x899504AE, 0x72497EBA), U64(0x6A06494A, 0x791C53A8), /* ~= 10^137 */
3097 U64(0xABFA45DA, 0x0EDBDE69), U64(0x0487DB9D, 0x17636892), /* ~= 10^138 */
3098 U64(0xD6F8D750, 0x9292D603), U64(0x45A9D284, 0x5D3C42B6), /* ~= 10^139 */
3099 U64(0x865B8692, 0x5B9BC5C2), U64(0x0B8A2392, 0xBA45A9B2), /* ~= 10^140 */
3100 U64(0xA7F26836, 0xF282B732), U64(0x8E6CAC77, 0x68D7141E), /* ~= 10^141 */
3101 U64(0xD1EF0244, 0xAF2364FF), U64(0x3207D795, 0x430CD926), /* ~= 10^142 */
3102 U64(0x8335616A, 0xED761F1F), U64(0x7F44E6BD, 0x49E807B8), /* ~= 10^143 */
3103 U64(0xA402B9C5, 0xA8D3A6E7), U64(0x5F16206C, 0x9C6209A6), /* ~= 10^144 */
3104 U64(0xCD036837, 0x130890A1), U64(0x36DBA887, 0xC37A8C0F), /* ~= 10^145 */
3105 U64(0x80222122, 0x6BE55A64), U64(0xC2494954, 0xDA2C9789), /* ~= 10^146 */
3106 U64(0xA02AA96B, 0x06DEB0FD), U64(0xF2DB9BAA, 0x10B7BD6C), /* ~= 10^147 */
3107 U64(0xC83553C5, 0xC8965D3D), U64(0x6F928294, 0x94E5ACC7), /* ~= 10^148 */
3108 U64(0xFA42A8B7, 0x3ABBF48C), U64(0xCB772339, 0xBA1F17F9), /* ~= 10^149 */
3109 U64(0x9C69A972, 0x84B578D7), U64(0xFF2A7604, 0x14536EFB), /* ~= 10^150 */
3110 U64(0xC38413CF, 0x25E2D70D), U64(0xFEF51385, 0x19684ABA), /* ~= 10^151 */
3111 U64(0xF46518C2, 0xEF5B8CD1), U64(0x7EB25866, 0x5FC25D69), /* ~= 10^152 */
3112 U64(0x98BF2F79, 0xD5993802), U64(0xEF2F773F, 0xFBD97A61), /* ~= 10^153 */
3113 U64(0xBEEEFB58, 0x4AFF8603), U64(0xAAFB550F, 0xFACFD8FA), /* ~= 10^154 */
3114 U64(0xEEAABA2E, 0x5DBF6784), U64(0x95BA2A53, 0xF983CF38), /* ~= 10^155 */
3115 U64(0x952AB45C, 0xFA97A0B2), U64(0xDD945A74, 0x7BF26183), /* ~= 10^156 */
3116 U64(0xBA756174, 0x393D88DF), U64(0x94F97111, 0x9AEEF9E4), /* ~= 10^157 */
3117 U64(0xE912B9D1, 0x478CEB17), U64(0x7A37CD56, 0x01AAB85D), /* ~= 10^158 */
3118 U64(0x91ABB422, 0xCCB812EE), U64(0xAC62E055, 0xC10AB33A), /* ~= 10^159 */
3119 U64(0xB616A12B, 0x7FE617AA), U64(0x577B986B, 0x314D6009), /* ~= 10^160 */
3120 U64(0xE39C4976, 0x5FDF9D94), U64(0xED5A7E85, 0xFDA0B80B), /* ~= 10^161 */
3121 U64(0x8E41ADE9, 0xFBEBC27D), U64(0x14588F13, 0xBE847307), /* ~= 10^162 */
3122 U64(0xB1D21964, 0x7AE6B31C), U64(0x596EB2D8, 0xAE258FC8), /* ~= 10^163 */
3123 U64(0xDE469FBD, 0x99A05FE3), U64(0x6FCA5F8E, 0xD9AEF3BB), /* ~= 10^164 */
3124 U64(0x8AEC23D6, 0x80043BEE), U64(0x25DE7BB9, 0x480D5854), /* ~= 10^165 */
3125 U64(0xADA72CCC, 0x20054AE9), U64(0xAF561AA7, 0x9A10AE6A), /* ~= 10^166 */
3126 U64(0xD910F7FF, 0x28069DA4), U64(0x1B2BA151, 0x8094DA04), /* ~= 10^167 */
3127 U64(0x87AA9AFF, 0x79042286), U64(0x90FB44D2, 0xF05D0842), /* ~= 10^168 */
3128 U64(0xA99541BF, 0x57452B28), U64(0x353A1607, 0xAC744A53), /* ~= 10^169 */
3129 U64(0xD3FA922F, 0x2D1675F2), U64(0x42889B89, 0x97915CE8), /* ~= 10^170 */
3130 U64(0x847C9B5D, 0x7C2E09B7), U64(0x69956135, 0xFEBADA11), /* ~= 10^171 */
3131 U64(0xA59BC234, 0xDB398C25), U64(0x43FAB983, 0x7E699095), /* ~= 10^172 */
3132 U64(0xCF02B2C2, 0x1207EF2E), U64(0x94F967E4, 0x5E03F4BB), /* ~= 10^173 */
3133 U64(0x8161AFB9, 0x4B44F57D), U64(0x1D1BE0EE, 0xBAC278F5), /* ~= 10^174 */
3134 U64(0xA1BA1BA7, 0x9E1632DC), U64(0x6462D92A, 0x69731732), /* ~= 10^175 */
3135 U64(0xCA28A291, 0x859BBF93), U64(0x7D7B8F75, 0x03CFDCFE), /* ~= 10^176 */
3136 U64(0xFCB2CB35, 0xE702AF78), U64(0x5CDA7352, 0x44C3D43E), /* ~= 10^177 */
3137 U64(0x9DEFBF01, 0xB061ADAB), U64(0x3A088813, 0x6AFA64A7), /* ~= 10^178 */
3138 U64(0xC56BAEC2, 0x1C7A1916), U64(0x088AAA18, 0x45B8FDD0), /* ~= 10^179 */
3139 U64(0xF6C69A72, 0xA3989F5B), U64(0x8AAD549E, 0x57273D45), /* ~= 10^180 */
3140 U64(0x9A3C2087, 0xA63F6399), U64(0x36AC54E2, 0xF678864B), /* ~= 10^181 */
3141 U64(0xC0CB28A9, 0x8FCF3C7F), U64(0x84576A1B, 0xB416A7DD), /* ~= 10^182 */
3142 U64(0xF0FDF2D3, 0xF3C30B9F), U64(0x656D44A2, 0xA11C51D5), /* ~= 10^183 */
3143 U64(0x969EB7C4, 0x7859E743), U64(0x9F644AE5, 0xA4B1B325), /* ~= 10^184 */
3144 U64(0xBC4665B5, 0x96706114), U64(0x873D5D9F, 0x0DDE1FEE), /* ~= 10^185 */
3145 U64(0xEB57FF22, 0xFC0C7959), U64(0xA90CB506, 0xD155A7EA), /* ~= 10^186 */
3146 U64(0x9316FF75, 0xDD87CBD8), U64(0x09A7F124, 0x42D588F2), /* ~= 10^187 */
3147 U64(0xB7DCBF53, 0x54E9BECE), U64(0x0C11ED6D, 0x538AEB2F), /* ~= 10^188 */
3148 U64(0xE5D3EF28, 0x2A242E81), U64(0x8F1668C8, 0xA86DA5FA), /* ~= 10^189 */
3149 U64(0x8FA47579, 0x1A569D10), U64(0xF96E017D, 0x694487BC), /* ~= 10^190 */
3150 U64(0xB38D92D7, 0x60EC4455), U64(0x37C981DC, 0xC395A9AC), /* ~= 10^191 */
3151 U64(0xE070F78D, 0x3927556A), U64(0x85BBE253, 0xF47B1417), /* ~= 10^192 */
3152 U64(0x8C469AB8, 0x43B89562), U64(0x93956D74, 0x78CCEC8E), /* ~= 10^193 */
3153 U64(0xAF584166, 0x54A6BABB), U64(0x387AC8D1, 0x970027B2), /* ~= 10^194 */
3154 U64(0xDB2E51BF, 0xE9D0696A), U64(0x06997B05, 0xFCC0319E), /* ~= 10^195 */
3155 U64(0x88FCF317, 0xF22241E2), U64(0x441FECE3, 0xBDF81F03), /* ~= 10^196 */
3156 U64(0xAB3C2FDD, 0xEEAAD25A), U64(0xD527E81C, 0xAD7626C3), /* ~= 10^197 */
3157 U64(0xD60B3BD5, 0x6A5586F1), U64(0x8A71E223, 0xD8D3B074), /* ~= 10^198 */
3158 U64(0x85C70565, 0x62757456), U64(0xF6872D56, 0x67844E49), /* ~= 10^199 */
3159 U64(0xA738C6BE, 0xBB12D16C), U64(0xB428F8AC, 0x016561DB), /* ~= 10^200 */
3160 U64(0xD106F86E, 0x69D785C7), U64(0xE13336D7, 0x01BEBA52), /* ~= 10^201 */
3161 U64(0x82A45B45, 0x0226B39C), U64(0xECC00246, 0x61173473), /* ~= 10^202 */
3162 U64(0xA34D7216, 0x42B06084), U64(0x27F002D7, 0xF95D0190), /* ~= 10^203 */
3163 U64(0xCC20CE9B, 0xD35C78A5), U64(0x31EC038D, 0xF7B441F4), /* ~= 10^204 */
3164 U64(0xFF290242, 0xC83396CE), U64(0x7E670471, 0x75A15271), /* ~= 10^205 */
3165 U64(0x9F79A169, 0xBD203E41), U64(0x0F0062C6, 0xE984D386), /* ~= 10^206 */
3166 U64(0xC75809C4, 0x2C684DD1), U64(0x52C07B78, 0xA3E60868), /* ~= 10^207 */
3167 U64(0xF92E0C35, 0x37826145), U64(0xA7709A56, 0xCCDF8A82), /* ~= 10^208 */
3168 U64(0x9BBCC7A1, 0x42B17CCB), U64(0x88A66076, 0x400BB691), /* ~= 10^209 */
3169 U64(0xC2ABF989, 0x935DDBFE), U64(0x6ACFF893, 0xD00EA435), /* ~= 10^210 */
3170 U64(0xF356F7EB, 0xF83552FE), U64(0x0583F6B8, 0xC4124D43), /* ~= 10^211 */
3171 U64(0x98165AF3, 0x7B2153DE), U64(0xC3727A33, 0x7A8B704A), /* ~= 10^212 */
3172 U64(0xBE1BF1B0, 0x59E9A8D6), U64(0x744F18C0, 0x592E4C5C), /* ~= 10^213 */
3173 U64(0xEDA2EE1C, 0x7064130C), U64(0x1162DEF0, 0x6F79DF73), /* ~= 10^214 */
3174 U64(0x9485D4D1, 0xC63E8BE7), U64(0x8ADDCB56, 0x45AC2BA8), /* ~= 10^215 */
3175 U64(0xB9A74A06, 0x37CE2EE1), U64(0x6D953E2B, 0xD7173692), /* ~= 10^216 */
3176 U64(0xE8111C87, 0xC5C1BA99), U64(0xC8FA8DB6, 0xCCDD0437), /* ~= 10^217 */
3177 U64(0x910AB1D4, 0xDB9914A0), U64(0x1D9C9892, 0x400A22A2), /* ~= 10^218 */
3178 U64(0xB54D5E4A, 0x127F59C8), U64(0x2503BEB6, 0xD00CAB4B), /* ~= 10^219 */
3179 U64(0xE2A0B5DC, 0x971F303A), U64(0x2E44AE64, 0x840FD61D), /* ~= 10^220 */
3180 U64(0x8DA471A9, 0xDE737E24), U64(0x5CEAECFE, 0xD289E5D2), /* ~= 10^221 */
3181 U64(0xB10D8E14, 0x56105DAD), U64(0x7425A83E, 0x872C5F47), /* ~= 10^222 */
3182 U64(0xDD50F199, 0x6B947518), U64(0xD12F124E, 0x28F77719), /* ~= 10^223 */
3183 U64(0x8A5296FF, 0xE33CC92F), U64(0x82BD6B70, 0xD99AAA6F), /* ~= 10^224 */
3184 U64(0xACE73CBF, 0xDC0BFB7B), U64(0x636CC64D, 0x1001550B), /* ~= 10^225 */
3185 U64(0xD8210BEF, 0xD30EFA5A), U64(0x3C47F7E0, 0x5401AA4E), /* ~= 10^226 */
3186 U64(0x8714A775, 0xE3E95C78), U64(0x65ACFAEC, 0x34810A71), /* ~= 10^227 */
3187 U64(0xA8D9D153, 0x5CE3B396), U64(0x7F1839A7, 0x41A14D0D), /* ~= 10^228 */
3188 U64(0xD31045A8, 0x341CA07C), U64(0x1EDE4811, 0x1209A050), /* ~= 10^229 */
3189 U64(0x83EA2B89, 0x2091E44D), U64(0x934AED0A, 0xAB460432), /* ~= 10^230 */
3190 U64(0xA4E4B66B, 0x68B65D60), U64(0xF81DA84D, 0x5617853F), /* ~= 10^231 */
3191 U64(0xCE1DE406, 0x42E3F4B9), U64(0x36251260, 0xAB9D668E), /* ~= 10^232 */
3192 U64(0x80D2AE83, 0xE9CE78F3), U64(0xC1D72B7C, 0x6B426019), /* ~= 10^233 */
3193 U64(0xA1075A24, 0xE4421730), U64(0xB24CF65B, 0x8612F81F), /* ~= 10^234 */
3194 U64(0xC94930AE, 0x1D529CFC), U64(0xDEE033F2, 0x6797B627), /* ~= 10^235 */
3195 U64(0xFB9B7CD9, 0xA4A7443C), U64(0x169840EF, 0x017DA3B1), /* ~= 10^236 */
3196 U64(0x9D412E08, 0x06E88AA5), U64(0x8E1F2895, 0x60EE864E), /* ~= 10^237 */
3197 U64(0xC491798A, 0x08A2AD4E), U64(0xF1A6F2BA, 0xB92A27E2), /* ~= 10^238 */
3198 U64(0xF5B5D7EC, 0x8ACB58A2), U64(0xAE10AF69, 0x6774B1DB), /* ~= 10^239 */
3199 U64(0x9991A6F3, 0xD6BF1765), U64(0xACCA6DA1, 0xE0A8EF29), /* ~= 10^240 */
3200 U64(0xBFF610B0, 0xCC6EDD3F), U64(0x17FD090A, 0x58D32AF3), /* ~= 10^241 */
3201 U64(0xEFF394DC, 0xFF8A948E), U64(0xDDFC4B4C, 0xEF07F5B0), /* ~= 10^242 */
3202 U64(0x95F83D0A, 0x1FB69CD9), U64(0x4ABDAF10, 0x1564F98E), /* ~= 10^243 */
3203 U64(0xBB764C4C, 0xA7A4440F), U64(0x9D6D1AD4, 0x1ABE37F1), /* ~= 10^244 */
3204 U64(0xEA53DF5F, 0xD18D5513), U64(0x84C86189, 0x216DC5ED), /* ~= 10^245 */
3205 U64(0x92746B9B, 0xE2F8552C), U64(0x32FD3CF5, 0xB4E49BB4), /* ~= 10^246 */
3206 U64(0xB7118682, 0xDBB66A77), U64(0x3FBC8C33, 0x221DC2A1), /* ~= 10^247 */
3207 U64(0xE4D5E823, 0x92A40515), U64(0x0FABAF3F, 0xEAA5334A), /* ~= 10^248 */
3208 U64(0x8F05B116, 0x3BA6832D), U64(0x29CB4D87, 0xF2A7400E), /* ~= 10^249 */
3209 U64(0xB2C71D5B, 0xCA9023F8), U64(0x743E20E9, 0xEF511012), /* ~= 10^250 */
3210 U64(0xDF78E4B2, 0xBD342CF6), U64(0x914DA924, 0x6B255416), /* ~= 10^251 */
3211 U64(0x8BAB8EEF, 0xB6409C1A), U64(0x1AD089B6, 0xC2F7548E), /* ~= 10^252 */
3212 U64(0xAE9672AB, 0xA3D0C320), U64(0xA184AC24, 0x73B529B1), /* ~= 10^253 */
3213 U64(0xDA3C0F56, 0x8CC4F3E8), U64(0xC9E5D72D, 0x90A2741E), /* ~= 10^254 */
3214 U64(0x88658996, 0x17FB1871), U64(0x7E2FA67C, 0x7A658892), /* ~= 10^255 */
3215 U64(0xAA7EEBFB, 0x9DF9DE8D), U64(0xDDBB901B, 0x98FEEAB7), /* ~= 10^256 */
3216 U64(0xD51EA6FA, 0x85785631), U64(0x552A7422, 0x7F3EA565), /* ~= 10^257 */
3217 U64(0x8533285C, 0x936B35DE), U64(0xD53A8895, 0x8F87275F), /* ~= 10^258 */
3218 U64(0xA67FF273, 0xB8460356), U64(0x8A892ABA, 0xF368F137), /* ~= 10^259 */
3219 U64(0xD01FEF10, 0xA657842C), U64(0x2D2B7569, 0xB0432D85), /* ~= 10^260 */
3220 U64(0x8213F56A, 0x67F6B29B), U64(0x9C3B2962, 0x0E29FC73), /* ~= 10^261 */
3221 U64(0xA298F2C5, 0x01F45F42), U64(0x8349F3BA, 0x91B47B8F), /* ~= 10^262 */
3222 U64(0xCB3F2F76, 0x42717713), U64(0x241C70A9, 0x36219A73), /* ~= 10^263 */
3223 U64(0xFE0EFB53, 0xD30DD4D7), U64(0xED238CD3, 0x83AA0110), /* ~= 10^264 */
3224 U64(0x9EC95D14, 0x63E8A506), U64(0xF4363804, 0x324A40AA), /* ~= 10^265 */
3225 U64(0xC67BB459, 0x7CE2CE48), U64(0xB143C605, 0x3EDCD0D5), /* ~= 10^266 */
3226 U64(0xF81AA16F, 0xDC1B81DA), U64(0xDD94B786, 0x8E94050A), /* ~= 10^267 */
3227 U64(0x9B10A4E5, 0xE9913128), U64(0xCA7CF2B4, 0x191C8326), /* ~= 10^268 */
3228 U64(0xC1D4CE1F, 0x63F57D72), U64(0xFD1C2F61, 0x1F63A3F0), /* ~= 10^269 */
3229 U64(0xF24A01A7, 0x3CF2DCCF), U64(0xBC633B39, 0x673C8CEC), /* ~= 10^270 */
3230 U64(0x976E4108, 0x8617CA01), U64(0xD5BE0503, 0xE085D813), /* ~= 10^271 */
3231 U64(0xBD49D14A, 0xA79DBC82), U64(0x4B2D8644, 0xD8A74E18), /* ~= 10^272 */
3232 U64(0xEC9C459D, 0x51852BA2), U64(0xDDF8E7D6, 0x0ED1219E), /* ~= 10^273 */
3233 U64(0x93E1AB82, 0x52F33B45), U64(0xCABB90E5, 0xC942B503), /* ~= 10^274 */
3234 U64(0xB8DA1662, 0xE7B00A17), U64(0x3D6A751F, 0x3B936243), /* ~= 10^275 */
3235 U64(0xE7109BFB, 0xA19C0C9D), U64(0x0CC51267, 0x0A783AD4), /* ~= 10^276 */
3236 U64(0x906A617D, 0x450187E2), U64(0x27FB2B80, 0x668B24C5), /* ~= 10^277 */
3237 U64(0xB484F9DC, 0x9641E9DA), U64(0xB1F9F660, 0x802DEDF6), /* ~= 10^278 */
3238 U64(0xE1A63853, 0xBBD26451), U64(0x5E7873F8, 0xA0396973), /* ~= 10^279 */
3239 U64(0x8D07E334, 0x55637EB2), U64(0xDB0B487B, 0x6423E1E8), /* ~= 10^280 */
3240 U64(0xB049DC01, 0x6ABC5E5F), U64(0x91CE1A9A, 0x3D2CDA62), /* ~= 10^281 */
3241 U64(0xDC5C5301, 0xC56B75F7), U64(0x7641A140, 0xCC7810FB), /* ~= 10^282 */
3242 U64(0x89B9B3E1, 0x1B6329BA), U64(0xA9E904C8, 0x7FCB0A9D), /* ~= 10^283 */
3243 U64(0xAC2820D9, 0x623BF429), U64(0x546345FA, 0x9FBDCD44), /* ~= 10^284 */
3244 U64(0xD732290F, 0xBACAF133), U64(0xA97C1779, 0x47AD4095), /* ~= 10^285 */
3245 U64(0x867F59A9, 0xD4BED6C0), U64(0x49ED8EAB, 0xCCCC485D), /* ~= 10^286 */
3246 U64(0xA81F3014, 0x49EE8C70), U64(0x5C68F256, 0xBFFF5A74), /* ~= 10^287 */
3247 U64(0xD226FC19, 0x5C6A2F8C), U64(0x73832EEC, 0x6FFF3111), /* ~= 10^288 */
3248 U64(0x83585D8F, 0xD9C25DB7), U64(0xC831FD53, 0xC5FF7EAB), /* ~= 10^289 */
3249 U64(0xA42E74F3, 0xD032F525), U64(0xBA3E7CA8, 0xB77F5E55), /* ~= 10^290 */
3250 U64(0xCD3A1230, 0xC43FB26F), U64(0x28CE1BD2, 0xE55F35EB), /* ~= 10^291 */
3251 U64(0x80444B5E, 0x7AA7CF85), U64(0x7980D163, 0xCF5B81B3), /* ~= 10^292 */
3252 U64(0xA0555E36, 0x1951C366), U64(0xD7E105BC, 0xC332621F), /* ~= 10^293 */
3253 U64(0xC86AB5C3, 0x9FA63440), U64(0x8DD9472B, 0xF3FEFAA7), /* ~= 10^294 */
3254 U64(0xFA856334, 0x878FC150), U64(0xB14F98F6, 0xF0FEB951), /* ~= 10^295 */
3255 U64(0x9C935E00, 0xD4B9D8D2), U64(0x6ED1BF9A, 0x569F33D3), /* ~= 10^296 */
3256 U64(0xC3B83581, 0x09E84F07), U64(0x0A862F80, 0xEC4700C8), /* ~= 10^297 */
3257 U64(0xF4A642E1, 0x4C6262C8), U64(0xCD27BB61, 0x2758C0FA), /* ~= 10^298 */
3258 U64(0x98E7E9CC, 0xCFBD7DBD), U64(0x8038D51C, 0xB897789C), /* ~= 10^299 */
3259 U64(0xBF21E440, 0x03ACDD2C), U64(0xE0470A63, 0xE6BD56C3), /* ~= 10^300 */
3260 U64(0xEEEA5D50, 0x04981478), U64(0x1858CCFC, 0xE06CAC74), /* ~= 10^301 */
3261 U64(0x95527A52, 0x02DF0CCB), U64(0x0F37801E, 0x0C43EBC8), /* ~= 10^302 */
3262 U64(0xBAA718E6, 0x8396CFFD), U64(0xD3056025, 0x8F54E6BA), /* ~= 10^303 */
3263 U64(0xE950DF20, 0x247C83FD), U64(0x47C6B82E, 0xF32A2069), /* ~= 10^304 */
3264 U64(0x91D28B74, 0x16CDD27E), U64(0x4CDC331D, 0x57FA5441), /* ~= 10^305 */
3265 U64(0xB6472E51, 0x1C81471D), U64(0xE0133FE4, 0xADF8E952), /* ~= 10^306 */
3266 U64(0xE3D8F9E5, 0x63A198E5), U64(0x58180FDD, 0xD97723A6), /* ~= 10^307 */
3267 U64(0x8E679C2F, 0x5E44FF8F), U64(0x570F09EA, 0xA7EA7648), /* ~= 10^308 */
3268 U64(0xB201833B, 0x35D63F73), U64(0x2CD2CC65, 0x51E513DA), /* ~= 10^309 */
3269 U64(0xDE81E40A, 0x034BCF4F), U64(0xF8077F7E, 0xA65E58D1), /* ~= 10^310 */
3270 U64(0x8B112E86, 0x420F6191), U64(0xFB04AFAF, 0x27FAF782), /* ~= 10^311 */
3271 U64(0xADD57A27, 0xD29339F6), U64(0x79C5DB9A, 0xF1F9B563), /* ~= 10^312 */
3272 U64(0xD94AD8B1, 0xC7380874), U64(0x18375281, 0xAE7822BC), /* ~= 10^313 */
3273 U64(0x87CEC76F, 0x1C830548), U64(0x8F229391, 0x0D0B15B5), /* ~= 10^314 */
3274 U64(0xA9C2794A, 0xE3A3C69A), U64(0xB2EB3875, 0x504DDB22), /* ~= 10^315 */
3275 U64(0xD433179D, 0x9C8CB841), U64(0x5FA60692, 0xA46151EB), /* ~= 10^316 */
3276 U64(0x849FEEC2, 0x81D7F328), U64(0xDBC7C41B, 0xA6BCD333), /* ~= 10^317 */
3277 U64(0xA5C7EA73, 0x224DEFF3), U64(0x12B9B522, 0x906C0800), /* ~= 10^318 */
3278 U64(0xCF39E50F, 0xEAE16BEF), U64(0xD768226B, 0x34870A00), /* ~= 10^319 */
3279 U64(0x81842F29, 0xF2CCE375), U64(0xE6A11583, 0x00D46640), /* ~= 10^320 */
3280 U64(0xA1E53AF4, 0x6F801C53), U64(0x60495AE3, 0xC1097FD0), /* ~= 10^321 */
3281 U64(0xCA5E89B1, 0x8B602368), U64(0x385BB19C, 0xB14BDFC4), /* ~= 10^322 */
3282 U64(0xFCF62C1D, 0xEE382C42), U64(0x46729E03, 0xDD9ED7B5), /* ~= 10^323 */
3283 U64(0x9E19DB92, 0xB4E31BA9), U64(0x6C07A2C2, 0x6A8346D1) /* ~= 10^324 */
3284};
3285
3286/**
3287 Get the cached pow10 value from pow10_sig_table.
3288 @param exp10 The exponent of pow(10, e). This value must in range
3289 POW10_SIG_TABLE_MIN_EXP to POW10_SIG_TABLE_MAX_EXP.
3290 @param hi The highest 64 bits of pow(10, e).
3291 @param lo The lower 64 bits after `hi`.
3292 */
3293static_inline void pow10_table_get_sig(i32 exp10, u64 *hi, u64 *lo) {
3294 i32 idx = exp10 - (POW10_SIG_TABLE_MIN_EXP);
3295 *hi = pow10_sig_table[idx * 2];
3296 *lo = pow10_sig_table[idx * 2 + 1];
3297}
3298
3299/**
3300 Get the exponent (base 2) for highest 64 bits significand in pow10_sig_table.
3301 */
3302static_inline void pow10_table_get_exp(i32 exp10, i32 *exp2) {
3303 /* e2 = floor(log2(pow(10, e))) - 64 + 1 */
3304 /* = floor(e * log2(10) - 63) */
3305 *exp2 = (exp10 * 217706 - 4128768) >> 16;
3306}
3307
3308#endif
3309
3310
3311
3312#if !YYJSON_DISABLE_READER
3313
3314/*==============================================================================
3315 * JSON Character Matcher
3316 *============================================================================*/
3317
3318/** Character type */
3319typedef u8 char_type;
3320
3321/** Whitespace character: ' ', '\\t', '\\n', '\\r'. */
3322static const char_type CHAR_TYPE_SPACE = 1 << 0;
3323
3324/** Number character: '-', [0-9]. */
3325static const char_type CHAR_TYPE_NUMBER = 1 << 1;
3326
3327/** JSON Escaped character: '"', '\', [0x00-0x1F]. */
3328static const char_type CHAR_TYPE_ESC_ASCII = 1 << 2;
3329
3330/** Non-ASCII character: [0x80-0xFF]. */
3331static const char_type CHAR_TYPE_NON_ASCII = 1 << 3;
3332
3333/** JSON container character: '{', '['. */
3334static const char_type CHAR_TYPE_CONTAINER = 1 << 4;
3335
3336/** Comment character: '/'. */
3337static const char_type CHAR_TYPE_COMMENT = 1 << 5;
3338
3339/** Line end character: '\\n', '\\r', '\0'. */
3340static const char_type CHAR_TYPE_LINE_END = 1 << 6;
3341
3342/** Hexadecimal numeric character: [0-9a-fA-F]. */
3343static const char_type CHAR_TYPE_HEX = 1 << 7;
3344
3345/** Character type table (generate with misc/make_tables.c) */
3346static const char_type char_table[256] = {
3347 0x44, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
3348 0x04, 0x05, 0x45, 0x04, 0x04, 0x45, 0x04, 0x04,
3349 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
3350 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
3351 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
3352 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x20,
3353 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
3354 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3355 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
3356 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3357 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3358 0x00, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00,
3359 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
3360 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3361 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3362 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
3363 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3364 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3365 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3366 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3367 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3368 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3369 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3370 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3371 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3372 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3373 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3374 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3375 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3376 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3377 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
3378 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
3379};
3380
3381/** Match a character with specified type. */
3382static_inline bool char_is_type(u8 c, char_type type) {
3383 return (char_table[c] & type) != 0;
3384}
3385
3386/** Match a whitespace: ' ', '\\t', '\\n', '\\r'. */
3387static_inline bool char_is_space(u8 c) {
3388 return char_is_type(c, (char_type)CHAR_TYPE_SPACE);
3389}
3390
3391/** Match a whitespace or comment: ' ', '\\t', '\\n', '\\r', '/'. */
3392static_inline bool char_is_space_or_comment(u8 c) {
3393 return char_is_type(c, (char_type)(CHAR_TYPE_SPACE | CHAR_TYPE_COMMENT));
3394}
3395
3396/** Match a JSON number: '-', [0-9]. */
3397static_inline bool char_is_number(u8 c) {
3398 return char_is_type(c, (char_type)CHAR_TYPE_NUMBER);
3399}
3400
3401/** Match a JSON container: '{', '['. */
3402static_inline bool char_is_container(u8 c) {
3403 return char_is_type(c, (char_type)CHAR_TYPE_CONTAINER);
3404}
3405
3406/** Match a stop character in ASCII string: '"', '\', [0x00-0x1F,0x80-0xFF]. */
3407static_inline bool char_is_ascii_stop(u8 c) {
3408 return char_is_type(c, (char_type)(CHAR_TYPE_ESC_ASCII |
3409 CHAR_TYPE_NON_ASCII));
3410}
3411
3412/** Match a line end character: '\\n', '\\r', '\0'. */
3413static_inline bool char_is_line_end(u8 c) {
3414 return char_is_type(c, (char_type)CHAR_TYPE_LINE_END);
3415}
3416
3417/** Match a hexadecimal numeric character: [0-9a-fA-F]. */
3418static_inline bool char_is_hex(u8 c) {
3419 return char_is_type(c, (char_type)CHAR_TYPE_HEX);
3420}
3421
3422
3423
3424/*==============================================================================
3425 * Digit Character Matcher
3426 *============================================================================*/
3427
3428/** Digit type */
3429typedef u8 digi_type;
3430
3431/** Digit: '0'. */
3432static const digi_type DIGI_TYPE_ZERO = 1 << 0;
3433
3434/** Digit: [1-9]. */
3435static const digi_type DIGI_TYPE_NONZERO = 1 << 1;
3436
3437/** Plus sign (positive): '+'. */
3438static const digi_type DIGI_TYPE_POS = 1 << 2;
3439
3440/** Minus sign (negative): '-'. */
3441static const digi_type DIGI_TYPE_NEG = 1 << 3;
3442
3443/** Decimal point: '.' */
3444static const digi_type DIGI_TYPE_DOT = 1 << 4;
3445
3446/** Exponent sign: 'e, 'E'. */
3447static const digi_type DIGI_TYPE_EXP = 1 << 5;
3448
3449/** Digit type table (generate with misc/make_tables.c) */
3450static const digi_type digi_table[256] = {
3451 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3452 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3453 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3454 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3455 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3456 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x10, 0x00,
3457 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
3458 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3459 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
3460 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3461 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3462 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3463 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
3464 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3465 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3466 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
3467};
3468
3469/** Match a character with specified type. */
3470static_inline bool digi_is_type(u8 d, digi_type type) {
3471 return (digi_table[d] & type) != 0;
3472}
3473
3474/** Match a sign: '+', '-' */
3475static_inline bool digi_is_sign(u8 d) {
3476 return digi_is_type(d, (digi_type)(DIGI_TYPE_POS | DIGI_TYPE_NEG));
3477}
3478
3479/** Match a none zero digit: [1-9] */
3480static_inline bool digi_is_nonzero(u8 d) {
3481 return digi_is_type(d, (digi_type)DIGI_TYPE_NONZERO);
3482}
3483
3484/** Match a digit: [0-9] */
3485static_inline bool digi_is_digit(u8 d) {
3486 return digi_is_type(d, (digi_type)(DIGI_TYPE_ZERO | DIGI_TYPE_NONZERO));
3487}
3488
3489/** Match an exponent sign: 'e', 'E'. */
3490static_inline bool digi_is_exp(u8 d) {
3491 return digi_is_type(d, (digi_type)DIGI_TYPE_EXP);
3492}
3493
3494/** Match a floating point indicator: '.', 'e', 'E'. */
3495static_inline bool digi_is_fp(u8 d) {
3496 return digi_is_type(d, (digi_type)(DIGI_TYPE_DOT | DIGI_TYPE_EXP));
3497}
3498
3499/** Match a digit or floating point indicator: [0-9], '.', 'e', 'E'. */
3500static_inline bool digi_is_digit_or_fp(u8 d) {
3501 return digi_is_type(d, (digi_type)(DIGI_TYPE_ZERO | DIGI_TYPE_NONZERO |
3502 DIGI_TYPE_DOT | DIGI_TYPE_EXP));
3503}
3504
3505
3506
3507/*==============================================================================
3508 * Hex Character Reader
3509 * This function is used by JSON reader to read escaped characters.
3510 *============================================================================*/
3511
3512/**
3513 This table is used to convert 4 hex character sequence to a number.
3514 A valid hex character [0-9A-Fa-f] will mapped to it's raw number [0x00, 0x0F],
3515 an invalid hex character will mapped to [0xF0].
3516 (generate with misc/make_tables.c)
3517 */
3518static const u8 hex_conv_table[256] = {
3519 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3520 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3521 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3522 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3523 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3524 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3525 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
3526 0x08, 0x09, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3527 0xF0, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF0,
3528 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3529 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3530 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3531 0xF0, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF0,
3532 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3533 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3534 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3535 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3536 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3537 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3538 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3539 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3540 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3541 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3542 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3543 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3544 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3545 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3546 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3547 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3548 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3549 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
3550 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0
3551};
3552
3553/**
3554 Scans an escaped character sequence as a UTF-16 code unit (branchless).
3555 e.g. "\\u005C" should pass "005C" as `cur`.
3556
3557 This requires the string has 4-byte zero padding.
3558 */
3559static_inline bool read_hex_u16(const u8 *cur, u16 *val) {
3560 u16 c0, c1, c2, c3, t0, t1;
3561 c0 = hex_conv_table[cur[0]];
3562 c1 = hex_conv_table[cur[1]];
3563 c2 = hex_conv_table[cur[2]];
3564 c3 = hex_conv_table[cur[3]];
3565 t0 = (u16)((c0 << 8) | c2);
3566 t1 = (u16)((c1 << 8) | c3);
3567 *val = (u16)((t0 << 4) | t1);
3568 return ((t0 | t1) & (u16)0xF0F0) == 0;
3569}
3570
3571
3572
3573/*==============================================================================
3574 * JSON Reader Utils
3575 * These functions are used by JSON reader to read literals and comments.
3576 *============================================================================*/
3577
3578/** Read 'true' literal, '*cur' should be 't'. */
3579static_inline bool read_true(u8 **ptr, yyjson_val *val) {
3580 u8 *cur = *ptr;
3581 u8 **end = ptr;
3582 if (likely(byte_match_4(cur, "true"))) {
3583 val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_TRUE;
3584 *end = cur + 4;
3585 return true;
3586 }
3587 return false;
3588}
3589
3590/** Read 'false' literal, '*cur' should be 'f'. */
3591static_inline bool read_false(u8 **ptr, yyjson_val *val) {
3592 u8 *cur = *ptr;
3593 u8 **end = ptr;
3594 if (likely(byte_match_4(cur + 1, "alse"))) {
3595 val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_FALSE;
3596 *end = cur + 5;
3597 return true;
3598 }
3599 return false;
3600}
3601
3602/** Read 'null' literal, '*cur' should be 'n'. */
3603static_inline bool read_null(u8 **ptr, yyjson_val *val) {
3604 u8 *cur = *ptr;
3605 u8 **end = ptr;
3606 if (likely(byte_match_4(cur, "null"))) {
3607 val->tag = YYJSON_TYPE_NULL;
3608 *end = cur + 4;
3609 return true;
3610 }
3611 return false;
3612}
3613
3614/** Read 'Inf' or 'Infinity' literal (ignoring case). */
3615static_inline bool read_inf(bool sign, u8 **ptr, u8 **pre, yyjson_val *val) {
3616#if !YYJSON_DISABLE_NON_STANDARD
3617 u8 *hdr = *ptr - sign;
3618 u8 *cur = *ptr;
3619 u8 **end = ptr;
3620 if ((cur[0] == 'I' || cur[0] == 'i') &&
3621 (cur[1] == 'N' || cur[1] == 'n') &&
3622 (cur[2] == 'F' || cur[2] == 'f')) {
3623 if ((cur[3] == 'I' || cur[3] == 'i') &&
3624 (cur[4] == 'N' || cur[4] == 'n') &&
3625 (cur[5] == 'I' || cur[5] == 'i') &&
3626 (cur[6] == 'T' || cur[6] == 't') &&
3627 (cur[7] == 'Y' || cur[7] == 'y')) {
3628 cur += 8;
3629 } else {
3630 cur += 3;
3631 }
3632 *end = cur;
3633 if (pre) {
3634 /* add null-terminator for previous raw string */
3635 if (*pre) **pre = '\0';
3636 *pre = cur;
3637 val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
3638 val->uni.str = (const char *)hdr;
3639 } else {
3640 val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
3641 val->uni.u64 = f64_raw_get_inf(sign);
3642 }
3643 return true;
3644 }
3645#endif
3646 return false;
3647}
3648
3649/** Read 'NaN' literal (ignoring case). */
3650static_inline bool read_nan(bool sign, u8 **ptr, u8 **pre, yyjson_val *val) {
3651#if !YYJSON_DISABLE_NON_STANDARD
3652 u8 *hdr = *ptr - sign;
3653 u8 *cur = *ptr;
3654 u8 **end = ptr;
3655 if ((cur[0] == 'N' || cur[0] == 'n') &&
3656 (cur[1] == 'A' || cur[1] == 'a') &&
3657 (cur[2] == 'N' || cur[2] == 'n')) {
3658 cur += 3;
3659 *end = cur;
3660 if (pre) {
3661 /* add null-terminator for previous raw string */
3662 if (*pre) **pre = '\0';
3663 *pre = cur;
3664 val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
3665 val->uni.str = (const char *)hdr;
3666 } else {
3667 val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
3668 val->uni.u64 = f64_raw_get_nan(sign);
3669 }
3670 return true;
3671 }
3672#endif
3673 return false;
3674}
3675
3676/** Read 'Inf', 'Infinity' or 'NaN' literal (ignoring case). */
3677static_inline bool read_inf_or_nan(bool sign, u8 **ptr, u8 **pre,
3678 yyjson_val *val) {
3679 if (read_inf(sign, ptr, pre, val)) return true;
3680 if (read_nan(sign, ptr, pre, val)) return true;
3681 return false;
3682}
3683
3684/** Read a JSON number as raw string. */
3685static_noinline bool read_number_raw(u8 **ptr,
3686 u8 **pre,
3687 yyjson_read_flag flg,
3688 yyjson_val *val,
3689 const char **msg) {
3690
3691#define return_err(_pos, _msg) do { \
3692 *msg = _msg; \
3693 *end = _pos; \
3694 return false; \
3695} while (false)
3696
3697#define return_raw() do { \
3698 val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
3699 val->uni.str = (const char *)hdr; \
3700 *pre = cur; *end = cur; return true; \
3701} while (false)
3702
3703 u8 *hdr = *ptr;
3704 u8 *cur = *ptr;
3705 u8 **end = ptr;
3706
3707 /* add null-terminator for previous raw string */
3708 if (*pre) **pre = '\0';
3709
3710 /* skip sign */
3711 cur += (*cur == '-');
3712
3713 /* read first digit, check leading zero */
3714 if (unlikely(!digi_is_digit(*cur))) {
3715 if (flg & YYJSON_READ_ALLOW_INF_AND_NAN) {
3716 if (read_inf_or_nan(*hdr == '-', &cur, pre, val)) return_raw();
3717 }
3718 return_err(cur, "no digit after minus sign");
3719 }
3720
3721 /* read integral part */
3722 if (*cur == '0') {
3723 cur++;
3724 if (unlikely(digi_is_digit(*cur))) {
3725 return_err(cur - 1, "number with leading zero is not allowed");
3726 }
3727 if (!digi_is_fp(*cur)) return_raw();
3728 } else {
3729 while (digi_is_digit(*cur)) cur++;
3730 if (!digi_is_fp(*cur)) return_raw();
3731 }
3732
3733 /* read fraction part */
3734 if (*cur == '.') {
3735 cur++;
3736 if (!digi_is_digit(*cur++)) {
3737 return_err(cur, "no digit after decimal point");
3738 }
3739 while (digi_is_digit(*cur)) cur++;
3740 }
3741
3742 /* read exponent part */
3743 if (digi_is_exp(*cur)) {
3744 cur += 1 + digi_is_sign(cur[1]);
3745 if (!digi_is_digit(*cur++)) {
3746 return_err(cur, "no digit after exponent sign");
3747 }
3748 while (digi_is_digit(*cur)) cur++;
3749 }
3750
3751 return_raw();
3752
3753#undef return_err
3754#undef return_raw
3755}
3756
3757/**
3758 Skips spaces and comments as many as possible.
3759
3760 It will return false in these cases:
3761 1. No character is skipped. The 'end' pointer is set as input cursor.
3762 2. A multiline comment is not closed. The 'end' pointer is set as the head
3763 of this comment block.
3764 */
3765static_noinline bool skip_spaces_and_comments(u8 **ptr) {
3766 u8 *hdr = *ptr;
3767 u8 *cur = *ptr;
3768 u8 **end = ptr;
3769 while (true) {
3770 if (byte_match_2(cur, "/*")) {
3771 hdr = cur;
3772 cur += 2;
3773 while (true) {
3774 if (byte_match_2(cur, "*/")) {
3775 cur += 2;
3776 break;
3777 }
3778 if (*cur == 0) {
3779 *end = hdr;
3780 return false;
3781 }
3782 cur++;
3783 }
3784 continue;
3785 }
3786 if (byte_match_2(cur, "//")) {
3787 cur += 2;
3788 while (!char_is_line_end(*cur)) cur++;
3789 continue;
3790 }
3791 if (char_is_space(*cur)) {
3792 cur += 1;
3793 while (char_is_space(*cur)) cur++;
3794 continue;
3795 }
3796 break;
3797 }
3798 *end = cur;
3799 return hdr != cur;
3800}
3801
3802/**
3803 Check truncated string.
3804 Returns true if `cur` match `str` but is truncated.
3805 */
3806static_inline bool is_truncated_str(u8 *cur, u8 *end,
3807 const char *str,
3808 bool case_sensitive) {
3809 usize len = strlen(str);
3810 if (cur + len <= end || end <= cur) return false;
3811 if (case_sensitive) {
3812 return memcmp(cur, str, (usize)(end - cur)) == 0;
3813 }
3814 for (; cur < end; cur++, str++) {
3815 if ((*cur != (u8)*str) && (*cur != (u8)*str - 'a' + 'A')) {
3816 return false;
3817 }
3818 }
3819 return true;
3820}
3821
3822/**
3823 Check truncated JSON on parsing errors.
3824 Returns true if the input is valid but truncated.
3825 */
3826static_noinline bool is_truncated_end(u8 *hdr, u8 *cur, u8 *end,
3827 yyjson_read_code code,
3828 yyjson_read_flag flg) {
3829 if (cur >= end) return true;
3830 if (code == YYJSON_READ_ERROR_LITERAL) {
3831 if (is_truncated_str(cur, end, "true", true) ||
3832 is_truncated_str(cur, end, "false", true) ||
3833 is_truncated_str(cur, end, "null", true)) {
3834 return true;
3835 }
3836 }
3837 if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER ||
3838 code == YYJSON_READ_ERROR_INVALID_NUMBER ||
3839 code == YYJSON_READ_ERROR_LITERAL) {
3840 if ((flg & YYJSON_READ_ALLOW_INF_AND_NAN)) {
3841 if (*cur == '-') cur++;
3842 if (is_truncated_str(cur, end, "infinity", false) ||
3843 is_truncated_str(cur, end, "nan", false)) {
3844 return true;
3845 }
3846 }
3847 }
3848 if (code == YYJSON_READ_ERROR_UNEXPECTED_CONTENT) {
3849 if (flg & YYJSON_READ_ALLOW_INF_AND_NAN) {
3850 if (hdr + 3 <= cur &&
3851 is_truncated_str(cur - 3, end, "infinity", false)) {
3852 return true; /* e.g. infin would be read as inf + in */
3853 }
3854 }
3855 }
3856 if (code == YYJSON_READ_ERROR_INVALID_STRING) {
3857 usize len = (usize)(end - cur);
3858
3859 /* unicode escape sequence */
3860 if (*cur == '\\') {
3861 if (len == 1) return true;
3862 if (len <= 5) {
3863 if (*++cur != 'u') return false;
3864 for (++cur; cur < end; cur++) {
3865 if (!char_is_hex(*cur)) return false;
3866 }
3867 return true;
3868 }
3869 return false;
3870 }
3871
3872 /* 2 to 4 bytes UTF-8, see `read_string()` for details. */
3873 if (*cur & 0x80) {
3874 u8 c0 = cur[0], c1 = cur[1], c2 = cur[2];
3875 if (len == 1) {
3876 /* 2 bytes UTF-8, truncated */
3877 if ((c0 & 0xE0) == 0xC0 && (c0 & 0x1E) != 0x00) return true;
3878 /* 3 bytes UTF-8, truncated */
3879 if ((c0 & 0xF0) == 0xE0) return true;
3880 /* 4 bytes UTF-8, truncated */
3881 if ((c0 & 0xF8) == 0xF0 && (c0 & 0x07) <= 0x04) return true;
3882 }
3883 if (len == 2) {
3884 /* 3 bytes UTF-8, truncated */
3885 if ((c0 & 0xF0) == 0xE0 &&
3886 (c1 & 0xC0) == 0x80) {
3887 u8 pat = (u8)(((c0 & 0x0F) << 1) | ((c1 & 0x20) >> 5));
3888 return 0x01 <= pat && pat != 0x1B;
3889 }
3890 /* 4 bytes UTF-8, truncated */
3891 if ((c0 & 0xF8) == 0xF0 &&
3892 (c1 & 0xC0) == 0x80) {
3893 u8 pat = (u8)(((c0 & 0x07) << 2) | ((c1 & 0x30) >> 4));
3894 return 0x01 <= pat && pat <= 0x10;
3895 }
3896 }
3897 if (len == 3) {
3898 /* 4 bytes UTF-8, truncated */
3899 if ((c0 & 0xF8) == 0xF0 &&
3900 (c1 & 0xC0) == 0x80 &&
3901 (c2 & 0xC0) == 0x80) {
3902 u8 pat = (u8)(((c0 & 0x07) << 2) | ((c1 & 0x30) >> 4));
3903 return 0x01 <= pat && pat <= 0x10;
3904 }
3905 }
3906 }
3907 }
3908 return false;
3909}
3910
3911
3912
3913#if YYJSON_HAS_IEEE_754 && !YYJSON_DISABLE_FAST_FP_CONV /* FP_READER */
3914
3915/*==============================================================================
3916 * BigInt For Floating Point Number Reader
3917 *
3918 * The bigint algorithm is used by floating-point number reader to get correctly
3919 * rounded result for numbers with lots of digits. This part of code is rarely
3920 * used for common numbers.
3921 *============================================================================*/
3922
3923/** Maximum exponent of exact pow10 */
3924#define U64_POW10_MAX_EXP 19
3925
3926/** Table: [ 10^0, ..., 10^19 ] (generate with misc/make_tables.c) */
3927static const u64 u64_pow10_table[U64_POW10_MAX_EXP + 1] = {
3928 U64(0x00000000, 0x00000001), U64(0x00000000, 0x0000000A),
3929 U64(0x00000000, 0x00000064), U64(0x00000000, 0x000003E8),
3930 U64(0x00000000, 0x00002710), U64(0x00000000, 0x000186A0),
3931 U64(0x00000000, 0x000F4240), U64(0x00000000, 0x00989680),
3932 U64(0x00000000, 0x05F5E100), U64(0x00000000, 0x3B9ACA00),
3933 U64(0x00000002, 0x540BE400), U64(0x00000017, 0x4876E800),
3934 U64(0x000000E8, 0xD4A51000), U64(0x00000918, 0x4E72A000),
3935 U64(0x00005AF3, 0x107A4000), U64(0x00038D7E, 0xA4C68000),
3936 U64(0x002386F2, 0x6FC10000), U64(0x01634578, 0x5D8A0000),
3937 U64(0x0DE0B6B3, 0xA7640000), U64(0x8AC72304, 0x89E80000)
3938};
3939
3940/** Maximum numbers of chunks used by a bigint (58 is enough here). */
3941#define BIGINT_MAX_CHUNKS 64
3942
3943/** Unsigned arbitrarily large integer */
3944typedef struct bigint {
3945 u32 used; /* used chunks count, should not be 0 */
3946 u64 bits[BIGINT_MAX_CHUNKS]; /* chunks */
3947} bigint;
3948
3949/**
3950 Evaluate 'big += val'.
3951 @param big A big number (can be 0).
3952 @param val An unsigned integer (can be 0).
3953 */
3954static_inline void bigint_add_u64(bigint *big, u64 val) {
3955 u32 idx, max;
3956 u64 num = big->bits[0];
3957 u64 add = num + val;
3958 big->bits[0] = add;
3959 if (likely((add >= num) || (add >= val))) return;
3960 for ((void)(idx = 1), max = big->used; idx < max; idx++) {
3961 if (likely(big->bits[idx] != U64_MAX)) {
3962 big->bits[idx] += 1;
3963 return;
3964 }
3965 big->bits[idx] = 0;
3966 }
3967 big->bits[big->used++] = 1;
3968}
3969
3970/**
3971 Evaluate 'big *= val'.
3972 @param big A big number (can be 0).
3973 @param val An unsigned integer (cannot be 0).
3974 */
3975static_inline void bigint_mul_u64(bigint *big, u64 val) {
3976 u32 idx = 0, max = big->used;
3977 u64 hi, lo, carry = 0;
3978 for (; idx < max; idx++) {
3979 if (big->bits[idx]) break;
3980 }
3981 for (; idx < max; idx++) {
3982 u128_mul_add(big->bits[idx], val, carry, &hi, &lo);
3983 big->bits[idx] = lo;
3984 carry = hi;
3985 }
3986 if (carry) big->bits[big->used++] = carry;
3987}
3988
3989/**
3990 Evaluate 'big *= 2^exp'.
3991 @param big A big number (can be 0).
3992 @param exp An exponent integer (can be 0).
3993 */
3994static_inline void bigint_mul_pow2(bigint *big, u32 exp) {
3995 u32 shft = exp % 64;
3996 u32 move = exp / 64;
3997 u32 idx = big->used;
3998 if (unlikely(shft == 0)) {
3999 for (; idx > 0; idx--) {
4000 big->bits[idx + move - 1] = big->bits[idx - 1];
4001 }
4002 big->used += move;
4003 while (move) big->bits[--move] = 0;
4004 } else {
4005 big->bits[idx] = 0;
4006 for (; idx > 0; idx--) {
4007 u64 num = big->bits[idx] << shft;
4008 num |= big->bits[idx - 1] >> (64 - shft);
4009 big->bits[idx + move] = num;
4010 }
4011 big->bits[move] = big->bits[0] << shft;
4012 big->used += move + (big->bits[big->used + move] > 0);
4013 while (move) big->bits[--move] = 0;
4014 }
4015}
4016
4017/**
4018 Evaluate 'big *= 10^exp'.
4019 @param big A big number (can be 0).
4020 @param exp An exponent integer (cannot be 0).
4021 */
4022static_inline void bigint_mul_pow10(bigint *big, i32 exp) {
4023 for (; exp >= U64_POW10_MAX_EXP; exp -= U64_POW10_MAX_EXP) {
4024 bigint_mul_u64(big, u64_pow10_table[U64_POW10_MAX_EXP]);
4025 }
4026 if (exp) {
4027 bigint_mul_u64(big, u64_pow10_table[exp]);
4028 }
4029}
4030
4031/**
4032 Compare two bigint.
4033 @return -1 if 'a < b', +1 if 'a > b', 0 if 'a == b'.
4034 */
4035static_inline i32 bigint_cmp(bigint *a, bigint *b) {
4036 u32 idx = a->used;
4037 if (a->used < b->used) return -1;
4038 if (a->used > b->used) return +1;
4039 while (idx-- > 0) {
4040 u64 av = a->bits[idx];
4041 u64 bv = b->bits[idx];
4042 if (av < bv) return -1;
4043 if (av > bv) return +1;
4044 }
4045 return 0;
4046}
4047
4048/**
4049 Evaluate 'big = val'.
4050 @param big A big number (can be 0).
4051 @param val An unsigned integer (can be 0).
4052 */
4053static_inline void bigint_set_u64(bigint *big, u64 val) {
4054 big->used = 1;
4055 big->bits[0] = val;
4056}
4057
4058/** Set a bigint with floating point number string. */
4059static_noinline void bigint_set_buf(bigint *big, u64 sig, i32 *exp,
4060 u8 *sig_cut, u8 *sig_end, u8 *dot_pos) {
4061
4062 if (unlikely(!sig_cut)) {
4063 /* no digit cut, set significant part only */
4064 bigint_set_u64(big, sig);
4065 return;
4066
4067 } else {
4068 /* some digits were cut, read them from 'sig_cut' to 'sig_end' */
4069 u8 *hdr = sig_cut;
4070 u8 *cur = hdr;
4071 u32 len = 0;
4072 u64 val = 0;
4073 bool dig_big_cut = false;
4074 bool has_dot = (hdr < dot_pos) & (dot_pos < sig_end);
4075 u32 dig_len_total = U64_SAFE_DIG + (u32)(sig_end - hdr) - has_dot;
4076
4077 sig -= (*sig_cut >= '5'); /* sig was rounded before */
4078 if (dig_len_total > F64_MAX_DEC_DIG) {
4079 dig_big_cut = true;
4080 sig_end -= dig_len_total - (F64_MAX_DEC_DIG + 1);
4081 sig_end -= (dot_pos + 1 == sig_end);
4082 dig_len_total = (F64_MAX_DEC_DIG + 1);
4083 }
4084 *exp -= (i32)dig_len_total - U64_SAFE_DIG;
4085
4086 big->used = 1;
4087 big->bits[0] = sig;
4088 while (cur < sig_end) {
4089 if (likely(cur != dot_pos)) {
4090 val = val * 10 + (u8)(*cur++ - '0');
4091 len++;
4092 if (unlikely(cur == sig_end && dig_big_cut)) {
4093 /* The last digit must be non-zero, */
4094 /* set it to '1' for correct rounding. */
4095 val = val - (val % 10) + 1;
4096 }
4097 if (len == U64_SAFE_DIG || cur == sig_end) {
4098 bigint_mul_pow10(big, (i32)len);
4099 bigint_add_u64(big, val);
4100 val = 0;
4101 len = 0;
4102 }
4103 } else {
4104 cur++;
4105 }
4106 }
4107 }
4108}
4109
4110
4111
4112/*==============================================================================
4113 * Diy Floating Point
4114 *============================================================================*/
4115
4116/** "Do It Yourself Floating Point" struct. */
4117typedef struct diy_fp {
4118 u64 sig; /* significand */
4119 i32 exp; /* exponent, base 2 */
4120 i32 pad; /* padding, useless */
4121} diy_fp;
4122
4123/** Get cached rounded diy_fp with pow(10, e) The input value must in range
4124 [POW10_SIG_TABLE_MIN_EXP, POW10_SIG_TABLE_MAX_EXP]. */
4125static_inline diy_fp diy_fp_get_cached_pow10(i32 exp10) {
4126 diy_fp fp;
4127 u64 sig_ext;
4128 pow10_table_get_sig(exp10, &fp.sig, &sig_ext);
4129 pow10_table_get_exp(exp10, &fp.exp);
4130 fp.sig += (sig_ext >> 63);
4131 return fp;
4132}
4133
4134/** Returns fp * fp2. */
4135static_inline diy_fp diy_fp_mul(diy_fp fp, diy_fp fp2) {
4136 u64 hi, lo;
4137 u128_mul(fp.sig, fp2.sig, &hi, &lo);
4138 fp.sig = hi + (lo >> 63);
4139 fp.exp += fp2.exp + 64;
4140 return fp;
4141}
4142
4143/** Convert diy_fp to IEEE-754 raw value. */
4144static_inline u64 diy_fp_to_ieee_raw(diy_fp fp) {
4145 u64 sig = fp.sig;
4146 i32 exp = fp.exp;
4147 u32 lz_bits;
4148 if (unlikely(fp.sig == 0)) return 0;
4149
4150 lz_bits = u64_lz_bits(sig);
4151 sig <<= lz_bits;
4152 sig >>= F64_BITS - F64_SIG_FULL_BITS;
4153 exp -= (i32)lz_bits;
4154 exp += F64_BITS - F64_SIG_FULL_BITS;
4155 exp += F64_SIG_BITS;
4156
4157 if (unlikely(exp >= F64_MAX_BIN_EXP)) {
4158 /* overflow */
4159 return F64_RAW_INF;
4160 } else if (likely(exp >= F64_MIN_BIN_EXP - 1)) {
4161 /* normal */
4162 exp += F64_EXP_BIAS;
4163 return ((u64)exp << F64_SIG_BITS) | (sig & F64_SIG_MASK);
4164 } else if (likely(exp >= F64_MIN_BIN_EXP - F64_SIG_FULL_BITS)) {
4165 /* subnormal */
4166 return sig >> (F64_MIN_BIN_EXP - exp - 1);
4167 } else {
4168 /* underflow */
4169 return 0;
4170 }
4171}
4172
4173
4174
4175/*==============================================================================
4176 * JSON Number Reader (IEEE-754)
4177 *============================================================================*/
4178
4179/** Maximum exact pow10 exponent for double value. */
4180#define F64_POW10_EXP_MAX_EXACT 22
4181
4182/** Cached pow10 table. */
4183static const f64 f64_pow10_table[] = {
4184 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12,
4185 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22
4186};
4187
4188/**
4189 Read a JSON number.
4190
4191 1. This function assume that the floating-point number is in IEEE-754 format.
4192 2. This function support uint64/int64/double number. If an integer number
4193 cannot fit in uint64/int64, it will returns as a double number. If a double
4194 number is infinite, the return value is based on flag.
4195 3. This function (with inline attribute) may generate a lot of instructions.
4196 */
4197static_inline bool read_number(u8 **ptr,
4198 u8 **pre,
4199 yyjson_read_flag flg,
4200 yyjson_val *val,
4201 const char **msg) {
4202
4203#define return_err(_pos, _msg) do { \
4204 *msg = _msg; \
4205 *end = _pos; \
4206 return false; \
4207} while (false)
4208
4209#define return_0() do { \
4210 val->tag = YYJSON_TYPE_NUM | (u8)((u8)sign << 3); \
4211 val->uni.u64 = 0; \
4212 *end = cur; return true; \
4213} while (false)
4214
4215#define return_i64(_v) do { \
4216 val->tag = YYJSON_TYPE_NUM | (u8)((u8)sign << 3); \
4217 val->uni.u64 = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \
4218 *end = cur; return true; \
4219} while (false)
4220
4221#define return_f64(_v) do { \
4222 val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
4223 val->uni.f64 = sign ? -(f64)(_v) : (f64)(_v); \
4224 *end = cur; return true; \
4225} while (false)
4226
4227#define return_f64_bin(_v) do { \
4228 val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
4229 val->uni.u64 = ((u64)sign << 63) | (u64)(_v); \
4230 *end = cur; return true; \
4231} while (false)
4232
4233#define return_inf() do { \
4234 if (flg & YYJSON_READ_BIGNUM_AS_RAW) return_raw(); \
4235 if (flg & YYJSON_READ_ALLOW_INF_AND_NAN) return_f64_bin(F64_RAW_INF); \
4236 else return_err(hdr, "number is infinity when parsed as double"); \
4237} while (false)
4238
4239#define return_raw() do { \
4240 if (*pre) **pre = '\0'; /* add null-terminator for previous raw string */ \
4241 val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
4242 val->uni.str = (const char *)hdr; \
4243 *pre = cur; *end = cur; return true; \
4244} while (false)
4245
4246 u8 *sig_cut = NULL; /* significant part cutting position for long number */
4247 u8 *sig_end = NULL; /* significant part ending position */
4248 u8 *dot_pos = NULL; /* decimal point position */
4249
4250 u64 sig = 0; /* significant part of the number */
4251 i32 exp = 0; /* exponent part of the number */
4252
4253 bool exp_sign; /* temporary exponent sign from literal part */
4254 i64 exp_sig = 0; /* temporary exponent number from significant part */
4255 i64 exp_lit = 0; /* temporary exponent number from exponent literal part */
4256 u64 num; /* temporary number for reading */
4257 u8 *tmp; /* temporary cursor for reading */
4258
4259 u8 *hdr = *ptr;
4260 u8 *cur = *ptr;
4261 u8 **end = ptr;
4262 bool sign;
4263
4264 /* read number as raw string if has `YYJSON_READ_NUMBER_AS_RAW` flag */
4265 if (unlikely(pre && !(flg & YYJSON_READ_BIGNUM_AS_RAW))) {
4266 return read_number_raw(ptr, pre, flg, val, msg);
4267 }
4268
4269 sign = (*hdr == '-');
4270 cur += sign;
4271
4272 /* begin with a leading zero or non-digit */
4273 if (unlikely(!digi_is_nonzero(*cur))) { /* 0 or non-digit char */
4274 if (unlikely(*cur != '0')) { /* non-digit char */
4275 if (flg & YYJSON_READ_ALLOW_INF_AND_NAN) {
4276 if (read_inf_or_nan(sign, &cur, pre, val)) {
4277 *end = cur;
4278 return true;
4279 }
4280 }
4281 return_err(cur, "no digit after minus sign");
4282 }
4283 /* begin with 0 */
4284 if (likely(!digi_is_digit_or_fp(*++cur))) return_0();
4285 if (likely(*cur == '.')) {
4286 dot_pos = cur++;
4287 if (unlikely(!digi_is_digit(*cur))) {
4288 return_err(cur, "no digit after decimal point");
4289 }
4290 while (unlikely(*cur == '0')) cur++;
4291 if (likely(digi_is_digit(*cur))) {
4292 /* first non-zero digit after decimal point */
4293 sig = (u64)(*cur - '0'); /* read first digit */
4294 cur--;
4295 goto digi_frac_1; /* continue read fraction part */
4296 }
4297 }
4298 if (unlikely(digi_is_digit(*cur))) {
4299 return_err(cur - 1, "number with leading zero is not allowed");
4300 }
4301 if (unlikely(digi_is_exp(*cur))) { /* 0 with any exponent is still 0 */
4302 cur += (usize)1 + digi_is_sign(cur[1]);
4303 if (unlikely(!digi_is_digit(*cur))) {
4304 return_err(cur, "no digit after exponent sign");
4305 }
4306 while (digi_is_digit(*++cur));
4307 }
4308 return_f64_bin(0);
4309 }
4310
4311 /* begin with non-zero digit */
4312 sig = (u64)(*cur - '0');
4313
4314 /*
4315 Read integral part, same as the following code.
4316
4317 for (int i = 1; i <= 18; i++) {
4318 num = cur[i] - '0';
4319 if (num <= 9) sig = num + sig * 10;
4320 else goto digi_sepr_i;
4321 }
4322 */
4323#define expr_intg(i) \
4324 if (likely((num = (u64)(cur[i] - (u8)'0')) <= 9)) sig = num + sig * 10; \
4325 else { goto digi_sepr_##i; }
4326 repeat_in_1_18(expr_intg)
4327#undef expr_intg
4328
4329
4330 cur += 19; /* skip continuous 19 digits */
4331 if (!digi_is_digit_or_fp(*cur)) {
4332 /* this number is an integer consisting of 19 digits */
4333 if (sign && (sig > ((u64)1 << 63))) { /* overflow */
4334 if (flg & YYJSON_READ_BIGNUM_AS_RAW) return_raw();
4335 return_f64(normalized_u64_to_f64(sig));
4336 }
4337 return_i64(sig);
4338 }
4339 goto digi_intg_more; /* read more digits in integral part */
4340
4341
4342 /* process first non-digit character */
4343#define expr_sepr(i) \
4344 digi_sepr_##i: \
4345 if (likely(!digi_is_fp(cur[i]))) { cur += i; return_i64(sig); } \
4346 dot_pos = cur + i; \
4347 if (likely(cur[i] == '.')) goto digi_frac_##i; \
4348 cur += i; sig_end = cur; goto digi_exp_more;
4349 repeat_in_1_18(expr_sepr)
4350#undef expr_sepr
4351
4352
4353 /* read fraction part */
4354#define expr_frac(i) \
4355 digi_frac_##i: \
4356 if (likely((num = (u64)(cur[i + 1] - (u8)'0')) <= 9)) \
4357 sig = num + sig * 10; \
4358 else { goto digi_stop_##i; }
4359 repeat_in_1_18(expr_frac)
4360#undef expr_frac
4361
4362 cur += 20; /* skip 19 digits and 1 decimal point */
4363 if (!digi_is_digit(*cur)) goto digi_frac_end; /* fraction part end */
4364 goto digi_frac_more; /* read more digits in fraction part */
4365
4366
4367 /* significant part end */
4368#define expr_stop(i) \
4369 digi_stop_##i: \
4370 cur += i + 1; \
4371 goto digi_frac_end;
4372 repeat_in_1_18(expr_stop)
4373#undef expr_stop
4374
4375
4376 /* read more digits in integral part */
4377digi_intg_more:
4378 if (digi_is_digit(*cur)) {
4379 if (!digi_is_digit_or_fp(cur[1])) {
4380 /* this number is an integer consisting of 20 digits */
4381 num = (u64)(*cur - '0');
4382 if ((sig < (U64_MAX / 10)) ||
4383 (sig == (U64_MAX / 10) && num <= (U64_MAX % 10))) {
4384 sig = num + sig * 10;
4385 cur++;
4386 /* convert to double if overflow */
4387 if (sign) {
4388 if (flg & YYJSON_READ_BIGNUM_AS_RAW) return_raw();
4389 return_f64(normalized_u64_to_f64(sig));
4390 }
4391 return_i64(sig);
4392 }
4393 }
4394 }
4395
4396 if (digi_is_exp(*cur)) {
4397 dot_pos = cur;
4398 goto digi_exp_more;
4399 }
4400
4401 if (*cur == '.') {
4402 dot_pos = cur++;
4403 if (!digi_is_digit(*cur)) {
4404 return_err(cur, "no digit after decimal point");
4405 }
4406 }
4407
4408
4409 /* read more digits in fraction part */
4410digi_frac_more:
4411 sig_cut = cur; /* too large to fit in u64, excess digits need to be cut */
4412 sig += (*cur >= '5'); /* round */
4413 while (digi_is_digit(*++cur));
4414 if (!dot_pos) {
4415 if (!digi_is_fp(*cur) && (flg & YYJSON_READ_BIGNUM_AS_RAW)) {
4416 return_raw(); /* it's a large integer */
4417 }
4418 dot_pos = cur;
4419 if (*cur == '.') {
4420 if (!digi_is_digit(*++cur)) {
4421 return_err(cur, "no digit after decimal point");
4422 }
4423 while (digi_is_digit(*cur)) cur++;
4424 }
4425 }
4426 exp_sig = (i64)(dot_pos - sig_cut);
4427 exp_sig += (dot_pos < sig_cut);
4428
4429 /* ignore trailing zeros */
4430 tmp = cur - 1;
4431 while (*tmp == '0' || *tmp == '.') tmp--;
4432 if (tmp < sig_cut) {
4433 sig_cut = NULL;
4434 } else {
4435 sig_end = cur;
4436 }
4437
4438 if (digi_is_exp(*cur)) goto digi_exp_more;
4439 goto digi_exp_finish;
4440
4441
4442 /* fraction part end */
4443digi_frac_end:
4444 if (unlikely(dot_pos + 1 == cur)) {
4445 return_err(cur, "no digit after decimal point");
4446 }
4447 sig_end = cur;
4448 exp_sig = -(i64)((u64)(cur - dot_pos) - 1);
4449 if (likely(!digi_is_exp(*cur))) {
4450 if (unlikely(exp_sig < F64_MIN_DEC_EXP - 19)) {
4451 return_f64_bin(0); /* underflow */
4452 }
4453 exp = (i32)exp_sig;
4454 goto digi_finish;
4455 } else {
4456 goto digi_exp_more;
4457 }
4458
4459
4460 /* read exponent part */
4461digi_exp_more:
4462 exp_sign = (*++cur == '-');
4463 cur += digi_is_sign(*cur);
4464 if (unlikely(!digi_is_digit(*cur))) {
4465 return_err(cur, "no digit after exponent sign");
4466 }
4467 while (*cur == '0') cur++;
4468
4469 /* read exponent literal */
4470 tmp = cur;
4471 while (digi_is_digit(*cur)) {
4472 exp_lit = (i64)((u8)(*cur++ - '0') + (u64)exp_lit * 10);
4473 }
4474 if (unlikely(cur - tmp >= U64_SAFE_DIG)) {
4475 if (exp_sign) {
4476 return_f64_bin(0); /* underflow */
4477 } else {
4478 return_inf(); /* overflow */
4479 }
4480 }
4481 exp_sig += exp_sign ? -exp_lit : exp_lit;
4482
4483
4484 /* validate exponent value */
4485digi_exp_finish:
4486 if (unlikely(exp_sig < F64_MIN_DEC_EXP - 19)) {
4487 return_f64_bin(0); /* underflow */
4488 }
4489 if (unlikely(exp_sig > F64_MAX_DEC_EXP)) {
4490 return_inf(); /* overflow */
4491 }
4492 exp = (i32)exp_sig;
4493
4494
4495 /* all digit read finished */
4496digi_finish:
4497
4498 /*
4499 Fast path 1:
4500
4501 1. The floating-point number calculation should be accurate, see the
4502 comments of macro `YYJSON_DOUBLE_MATH_CORRECT`.
4503 2. Correct rounding should be performed (fegetround() == FE_TONEAREST).
4504 3. The input of floating point number calculation does not lose precision,
4505 which means: 64 - leading_zero(input) - trailing_zero(input) < 53.
4506
4507 We don't check all available inputs here, because that would make the code
4508 more complicated, and not friendly to branch predictor.
4509 */
4510#if YYJSON_DOUBLE_MATH_CORRECT
4511 if (sig < ((u64)1 << 53) &&
4512 exp >= -F64_POW10_EXP_MAX_EXACT &&
4513 exp <= +F64_POW10_EXP_MAX_EXACT) {
4514 f64 dbl = (f64)sig;
4515 if (exp < 0) {
4516 dbl /= f64_pow10_table[-exp];
4517 } else {
4518 dbl *= f64_pow10_table[+exp];
4519 }
4520 return_f64(dbl);
4521 }
4522#endif
4523
4524 /*
4525 Fast path 2:
4526
4527 To keep it simple, we only accept normal number here,
4528 let the slow path to handle subnormal and infinity number.
4529 */
4530 if (likely(!sig_cut &&
4531 exp > -F64_MAX_DEC_EXP + 1 &&
4532 exp < +F64_MAX_DEC_EXP - 20)) {
4533 /*
4534 The result value is exactly equal to (sig * 10^exp),
4535 the exponent part (10^exp) can be converted to (sig2 * 2^exp2).
4536
4537 The sig2 can be an infinite length number, only the highest 128 bits
4538 is cached in the pow10_sig_table.
4539
4540 Now we have these bits:
4541 sig1 (normalized 64bit) : aaaaaaaa
4542 sig2 (higher 64bit) : bbbbbbbb
4543 sig2_ext (lower 64bit) : cccccccc
4544 sig2_cut (extra unknown bits) : dddddddddddd....
4545
4546 And the calculation process is:
4547 ----------------------------------------
4548 aaaaaaaa *
4549 bbbbbbbbccccccccdddddddddddd....
4550 ----------------------------------------
4551 abababababababab +
4552 acacacacacacacac +
4553 adadadadadadadadadad....
4554 ----------------------------------------
4555 [hi____][lo____] +
4556 [hi2___][lo2___] +
4557 [unknown___________....]
4558 ----------------------------------------
4559
4560 The addition with carry may affect higher bits, but if there is a 0
4561 in higher bits, the bits higher than 0 will not be affected.
4562
4563 `lo2` + `unknown` may get a carry bit and may affect `hi2`, the max
4564 value of `hi2` is 0xFFFFFFFFFFFFFFFE, so `hi2` will not overflow.
4565
4566 `lo` + `hi2` may also get a carry bit and may affect `hi`, but only
4567 the highest significant 53 bits of `hi` is needed. If there is a 0
4568 in the lower bits of `hi`, then all the following bits can be dropped.
4569
4570 To convert the result to IEEE-754 double number, we need to perform
4571 correct rounding:
4572 1. if bit 54 is 0, round down,
4573 2. if bit 54 is 1 and any bit beyond bit 54 is 1, round up,
4574 3. if bit 54 is 1 and all bits beyond bit 54 are 0, round to even,
4575 as the extra bits is unknown, this case will not be handled here.
4576 */
4577
4578 u64 raw;
4579 u64 sig1, sig2, sig2_ext, hi, lo, hi2, lo2, add, bits;
4580 i32 exp2;
4581 u32 lz;
4582 bool exact = false, carry, round_up;
4583
4584 /* convert (10^exp) to (sig2 * 2^exp2) */
4585 pow10_table_get_sig(exp, &sig2, &sig2_ext);
4586 pow10_table_get_exp(exp, &exp2);
4587
4588 /* normalize and multiply */
4589 lz = u64_lz_bits(sig);
4590 sig1 = sig << lz;
4591 exp2 -= (i32)lz;
4592 u128_mul(sig1, sig2, &hi, &lo);
4593
4594 /*
4595 The `hi` is in range [0x4000000000000000, 0xFFFFFFFFFFFFFFFE],
4596 To get normalized value, `hi` should be shifted to the left by 0 or 1.
4597
4598 The highest significant 53 bits is used by IEEE-754 double number,
4599 and the bit 54 is used to detect rounding direction.
4600
4601 The lowest (64 - 54 - 1) bits is used to check whether it contains 0.
4602 */
4603 bits = hi & (((u64)1 << (64 - 54 - 1)) - 1);
4604 if (bits - 1 < (((u64)1 << (64 - 54 - 1)) - 2)) {
4605 /*
4606 (bits != 0 && bits != 0x1FF) => (bits - 1 < 0x1FF - 1)
4607 The `bits` is not zero, so we don't need to check `round to even`
4608 case. The `bits` contains bit `0`, so we can drop the extra bits
4609 after `0`.
4610 */
4611 exact = true;
4612
4613 } else {
4614 /*
4615 (bits == 0 || bits == 0x1FF)
4616 The `bits` is filled with all `0` or all `1`, so we need to check
4617 lower bits with another 64-bit multiplication.
4618 */
4619 u128_mul(sig1, sig2_ext, &hi2, &lo2);
4620
4621 add = lo + hi2;
4622 if (add + 1 > (u64)1) {
4623 /*
4624 (add != 0 && add != U64_MAX) => (add + 1 > 1)
4625 The `add` is not zero, so we don't need to check `round to
4626 even` case. The `add` contains bit `0`, so we can drop the
4627 extra bits after `0`. The `hi` cannot be U64_MAX, so it will
4628 not overflow.
4629 */
4630 carry = add < lo || add < hi2;
4631 hi += carry;
4632 exact = true;
4633 }
4634 }
4635
4636 if (exact) {
4637 /* normalize */
4638 lz = hi < ((u64)1 << 63);
4639 hi <<= lz;
4640 exp2 -= (i32)lz;
4641 exp2 += 64;
4642
4643 /* test the bit 54 and get rounding direction */
4644 round_up = (hi & ((u64)1 << (64 - 54))) > (u64)0;
4645 hi += (round_up ? ((u64)1 << (64 - 54)) : (u64)0);
4646
4647 /* test overflow */
4648 if (hi < ((u64)1 << (64 - 54))) {
4649 hi = ((u64)1 << 63);
4650 exp2 += 1;
4651 }
4652
4653 /* This is a normal number, convert it to IEEE-754 format. */
4654 hi >>= F64_BITS - F64_SIG_FULL_BITS;
4655 exp2 += F64_BITS - F64_SIG_FULL_BITS + F64_SIG_BITS;
4656 exp2 += F64_EXP_BIAS;
4657 raw = ((u64)exp2 << F64_SIG_BITS) | (hi & F64_SIG_MASK);
4658 return_f64_bin(raw);
4659 }
4660 }
4661
4662 /*
4663 Slow path: read double number exactly with diyfp.
4664 1. Use cached diyfp to get an approximation value.
4665 2. Use bigcomp to check the approximation value if needed.
4666
4667 This algorithm refers to google's double-conversion project:
4668 https://github.com/google/double-conversion
4669 */
4670 {
4671 const i32 ERR_ULP_LOG = 3;
4672 const i32 ERR_ULP = 1 << ERR_ULP_LOG;
4673 const i32 ERR_CACHED_POW = ERR_ULP / 2;
4674 const i32 ERR_MUL_FIXED = ERR_ULP / 2;
4675 const i32 DIY_SIG_BITS = 64;
4676 const i32 EXP_BIAS = F64_EXP_BIAS + F64_SIG_BITS;
4677 const i32 EXP_SUBNORMAL = -EXP_BIAS + 1;
4678
4679 u64 fp_err;
4680 u32 bits;
4681 i32 order_of_magnitude;
4682 i32 effective_significand_size;
4683 i32 precision_digits_count;
4684 u64 precision_bits;
4685 u64 half_way;
4686
4687 u64 raw;
4688 diy_fp fp, fp_upper;
4689 bigint big_full, big_comp;
4690 i32 cmp;
4691
4692 fp.sig = sig;
4693 fp.exp = 0;
4694 fp_err = sig_cut ? (u64)(ERR_ULP / 2) : (u64)0;
4695
4696 /* normalize */
4697 bits = u64_lz_bits(fp.sig);
4698 fp.sig <<= bits;
4699 fp.exp -= (i32)bits;
4700 fp_err <<= bits;
4701
4702 /* multiply and add error */
4703 fp = diy_fp_mul(fp, diy_fp_get_cached_pow10(exp));
4704 fp_err += (u64)ERR_CACHED_POW + (fp_err != 0) + (u64)ERR_MUL_FIXED;
4705
4706 /* normalize */
4707 bits = u64_lz_bits(fp.sig);
4708 fp.sig <<= bits;
4709 fp.exp -= (i32)bits;
4710 fp_err <<= bits;
4711
4712 /* effective significand */
4713 order_of_magnitude = DIY_SIG_BITS + fp.exp;
4714 if (likely(order_of_magnitude >= EXP_SUBNORMAL + F64_SIG_FULL_BITS)) {
4715 effective_significand_size = F64_SIG_FULL_BITS;
4716 } else if (order_of_magnitude <= EXP_SUBNORMAL) {
4717 effective_significand_size = 0;
4718 } else {
4719 effective_significand_size = order_of_magnitude - EXP_SUBNORMAL;
4720 }
4721
4722 /* precision digits count */
4723 precision_digits_count = DIY_SIG_BITS - effective_significand_size;
4724 if (unlikely(precision_digits_count + ERR_ULP_LOG >= DIY_SIG_BITS)) {
4725 i32 shr = (precision_digits_count + ERR_ULP_LOG) - DIY_SIG_BITS + 1;
4726 fp.sig >>= shr;
4727 fp.exp += shr;
4728 fp_err = (fp_err >> shr) + 1 + (u32)ERR_ULP;
4729 precision_digits_count -= shr;
4730 }
4731
4732 /* half way */
4733 precision_bits = fp.sig & (((u64)1 << precision_digits_count) - 1);
4734 precision_bits *= (u32)ERR_ULP;
4735 half_way = (u64)1 << (precision_digits_count - 1);
4736 half_way *= (u32)ERR_ULP;
4737
4738 /* rounding */
4739 fp.sig >>= precision_digits_count;
4740 fp.sig += (precision_bits >= half_way + fp_err);
4741 fp.exp += precision_digits_count;
4742
4743 /* get IEEE double raw value */
4744 raw = diy_fp_to_ieee_raw(fp);
4745 if (unlikely(raw == F64_RAW_INF)) return_inf();
4746 if (likely(precision_bits <= half_way - fp_err ||
4747 precision_bits >= half_way + fp_err)) {
4748 return_f64_bin(raw); /* number is accurate */
4749 }
4750 /* now the number is the correct value, or the next lower value */
4751
4752 /* upper boundary */
4753 if (raw & F64_EXP_MASK) {
4754 fp_upper.sig = (raw & F64_SIG_MASK) + ((u64)1 << F64_SIG_BITS);
4755 fp_upper.exp = (i32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
4756 } else {
4757 fp_upper.sig = (raw & F64_SIG_MASK);
4758 fp_upper.exp = 1;
4759 }
4760 fp_upper.exp -= F64_EXP_BIAS + F64_SIG_BITS;
4761 fp_upper.sig <<= 1;
4762 fp_upper.exp -= 1;
4763 fp_upper.sig += 1; /* add half ulp */
4764
4765 /* compare with bigint */
4766 bigint_set_buf(&big_full, sig, &exp, sig_cut, sig_end, dot_pos);
4767 bigint_set_u64(&big_comp, fp_upper.sig);
4768 if (exp >= 0) {
4769 bigint_mul_pow10(&big_full, +exp);
4770 } else {
4771 bigint_mul_pow10(&big_comp, -exp);
4772 }
4773 if (fp_upper.exp > 0) {
4774 bigint_mul_pow2(&big_comp, (u32)+fp_upper.exp);
4775 } else {
4776 bigint_mul_pow2(&big_full, (u32)-fp_upper.exp);
4777 }
4778 cmp = bigint_cmp(&big_full, &big_comp);
4779 if (likely(cmp != 0)) {
4780 /* round down or round up */
4781 raw += (cmp > 0);
4782 } else {
4783 /* falls midway, round to even */
4784 raw += (raw & 1);
4785 }
4786
4787 if (unlikely(raw == F64_RAW_INF)) return_inf();
4788 return_f64_bin(raw);
4789 }
4790
4791#undef return_err
4792#undef return_inf
4793#undef return_0
4794#undef return_i64
4795#undef return_f64
4796#undef return_f64_bin
4797#undef return_raw
4798}
4799
4800
4801
4802#else /* FP_READER */
4803
4804/**
4805 Read a JSON number.
4806 This is a fallback function if the custom number reader is disabled.
4807 This function use libc's strtod() to read floating-point number.
4808 */
4809static_inline bool read_number(u8 **ptr,
4810 u8 **pre,
4811 yyjson_read_flag flg,
4812 yyjson_val *val,
4813 const char **msg) {
4814
4815#define return_err(_pos, _msg) do { \
4816 *msg = _msg; \
4817 *end = _pos; \
4818 return false; \
4819} while (false)
4820
4821#define return_0() do { \
4822 val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); \
4823 val->uni.u64 = 0; \
4824 *end = cur; return true; \
4825} while (false)
4826
4827#define return_i64(_v) do { \
4828 val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); \
4829 val->uni.u64 = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \
4830 *end = cur; return true; \
4831} while (false)
4832
4833#define return_f64(_v) do { \
4834 val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
4835 val->uni.f64 = sign ? -(f64)(_v) : (f64)(_v); \
4836 *end = cur; return true; \
4837} while (false)
4838
4839#define return_f64_bin(_v) do { \
4840 val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
4841 val->uni.u64 = ((u64)sign << 63) | (u64)(_v); \
4842 *end = cur; return true; \
4843} while (false)
4844
4845#define return_inf() do { \
4846 if (flg & YYJSON_READ_BIGNUM_AS_RAW) return_raw(); \
4847 if (flg & YYJSON_READ_ALLOW_INF_AND_NAN) return_f64_bin(F64_RAW_INF); \
4848 else return_err(hdr, "number is infinity when parsed as double"); \
4849} while (false)
4850
4851#define return_raw() do { \
4852 if (*pre) **pre = '\0'; /* add null-terminator for previous raw string */ \
4853 val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
4854 val->uni.str = (const char *)hdr; \
4855 *pre = cur; *end = cur; return true; \
4856} while (false)
4857
4858 u64 sig, num;
4859 u8 *hdr = *ptr;
4860 u8 *cur = *ptr;
4861 u8 **end = ptr;
4862 u8 *dot = NULL;
4863 u8 *f64_end = NULL;
4864 bool sign;
4865
4866 /* read number as raw string if has `YYJSON_READ_NUMBER_AS_RAW` flag */
4867 if (unlikely(pre && !(flg & YYJSON_READ_BIGNUM_AS_RAW))) {
4868 return read_number_raw(ptr, pre, flg, val, msg);
4869 }
4870
4871 sign = (*hdr == '-');
4872 cur += sign;
4873 sig = (u8)(*cur - '0');
4874
4875 /* read first digit, check leading zero */
4876 if (unlikely(!digi_is_digit(*cur))) {
4877 if (flg & YYJSON_READ_ALLOW_INF_AND_NAN) {
4878 if (read_inf_or_nan(sign, &cur, pre, val)) {
4879 *end = cur;
4880 return true;
4881 }
4882 }
4883 return_err(cur, "no digit after minus sign");
4884 }
4885 if (*cur == '0') {
4886 cur++;
4887 if (unlikely(digi_is_digit(*cur))) {
4888 return_err(cur - 1, "number with leading zero is not allowed");
4889 }
4890 if (!digi_is_fp(*cur)) return_0();
4891 goto read_double;
4892 }
4893
4894 /* read continuous digits, up to 19 characters */
4895#define expr_intg(i) \
4896 if (likely((num = (u64)(cur[i] - (u8)'0')) <= 9)) sig = num + sig * 10; \
4897 else { cur += i; goto intg_end; }
4898 repeat_in_1_18(expr_intg)
4899#undef expr_intg
4900
4901 /* here are 19 continuous digits, skip them */
4902 cur += 19;
4903 if (digi_is_digit(cur[0]) && !digi_is_digit_or_fp(cur[1])) {
4904 /* this number is an integer consisting of 20 digits */
4905 num = (u8)(*cur - '0');
4906 if ((sig < (U64_MAX / 10)) ||
4907 (sig == (U64_MAX / 10) && num <= (U64_MAX % 10))) {
4908 sig = num + sig * 10;
4909 cur++;
4910 if (sign) {
4911 if (flg & YYJSON_READ_BIGNUM_AS_RAW) return_raw();
4912 return_f64(normalized_u64_to_f64(sig));
4913 }
4914 return_i64(sig);
4915 }
4916 }
4917
4918intg_end:
4919 /* continuous digits ended */
4920 if (!digi_is_digit_or_fp(*cur)) {
4921 /* this number is an integer consisting of 1 to 19 digits */
4922 if (sign && (sig > ((u64)1 << 63))) {
4923 if (flg & YYJSON_READ_BIGNUM_AS_RAW) return_raw();
4924 return_f64(normalized_u64_to_f64(sig));
4925 }
4926 return_i64(sig);
4927 }
4928
4929read_double:
4930 /* this number should be read as double */
4931 while (digi_is_digit(*cur)) cur++;
4932 if (!digi_is_fp(*cur) && (flg & YYJSON_READ_BIGNUM_AS_RAW)) {
4933 return_raw(); /* it's a large integer */
4934 }
4935 if (*cur == '.') {
4936 /* skip fraction part */
4937 dot = cur;
4938 cur++;
4939 if (!digi_is_digit(*cur)) {
4940 return_err(cur, "no digit after decimal point");
4941 }
4942 cur++;
4943 while (digi_is_digit(*cur)) cur++;
4944 }
4945 if (digi_is_exp(*cur)) {
4946 /* skip exponent part */
4947 cur += 1 + digi_is_sign(cur[1]);
4948 if (!digi_is_digit(*cur)) {
4949 return_err(cur, "no digit after exponent sign");
4950 }
4951 cur++;
4952 while (digi_is_digit(*cur)) cur++;
4953 }
4954
4955 /*
4956 libc's strtod() is used to parse the floating-point number.
4957
4958 Note that the decimal point character used by strtod() is locale-dependent,
4959 and the rounding direction may affected by fesetround().
4960
4961 For currently known locales, (en, zh, ja, ko, am, he, hi) use '.' as the
4962 decimal point, while other locales use ',' as the decimal point.
4963
4964 Here strtod() is called twice for different locales, but if another thread
4965 happens calls setlocale() between two strtod(), parsing may still fail.
4966 */
4967 val->uni.f64 = strtod((const char *)hdr, (char **)&f64_end);
4968 if (unlikely(f64_end != cur)) {
4969 /* replace '.' with ',' for locale */
4970 bool cut = (*cur == ',');
4971 if (cut) *cur = ' ';
4972 if (dot) *dot = ',';
4973 val->uni.f64 = strtod((const char *)hdr, (char **)&f64_end);
4974 /* restore ',' to '.' */
4975 if (cut) *cur = ',';
4976 if (dot) *dot = '.';
4977 if (unlikely(f64_end != cur)) {
4978 return_err(hdr, "strtod() failed to parse the number");
4979 }
4980 }
4981 if (unlikely(val->uni.f64 >= HUGE_VAL || val->uni.f64 <= -HUGE_VAL)) {
4982 return_inf();
4983 }
4984 val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
4985 *end = cur;
4986 return true;
4987
4988#undef return_err
4989#undef return_0
4990#undef return_i64
4991#undef return_f64
4992#undef return_f64_bin
4993#undef return_inf
4994#undef return_raw
4995}
4996
4997#endif /* FP_READER */
4998
4999
5000
5001/*==============================================================================
5002 * JSON String Reader
5003 *============================================================================*/
5004
5005/**
5006 Read a JSON string.
5007 @param ptr The head pointer of string before '"' prefix (inout).
5008 @param lst JSON last position.
5009 @param inv Allow invalid unicode.
5010 @param val The string value to be written.
5011 @param msg The error message pointer.
5012 @return Whether success.
5013 */
5014static_inline bool read_string(u8 **ptr,
5015 u8 *lst,
5016 bool inv,
5017 yyjson_val *val,
5018 const char **msg) {
5019 /*
5020 Each unicode code point is encoded as 1 to 4 bytes in UTF-8 encoding,
5021 we use 4-byte mask and pattern value to validate UTF-8 byte sequence,
5022 this requires the input data to have 4-byte zero padding.
5023 ---------------------------------------------------
5024 1 byte
5025 unicode range [U+0000, U+007F]
5026 unicode min [.......0]
5027 unicode max [.1111111]
5028 bit pattern [0.......]
5029 ---------------------------------------------------
5030 2 byte
5031 unicode range [U+0080, U+07FF]
5032 unicode min [......10 ..000000]
5033 unicode max [...11111 ..111111]
5034 bit require [...xxxx. ........] (1E 00)
5035 bit mask [xxx..... xx......] (E0 C0)
5036 bit pattern [110..... 10......] (C0 80)
5037 ---------------------------------------------------
5038 3 byte
5039 unicode range [U+0800, U+FFFF]
5040 unicode min [........ ..100000 ..000000]
5041 unicode max [....1111 ..111111 ..111111]
5042 bit require [....xxxx ..x..... ........] (0F 20 00)
5043 bit mask [xxxx.... xx...... xx......] (F0 C0 C0)
5044 bit pattern [1110.... 10...... 10......] (E0 80 80)
5045 ---------------------------------------------------
5046 3 byte invalid (reserved for surrogate halves)
5047 unicode range [U+D800, U+DFFF]
5048 unicode min [....1101 ..100000 ..000000]
5049 unicode max [....1101 ..111111 ..111111]
5050 bit mask [....xxxx ..x..... ........] (0F 20 00)
5051 bit pattern [....1101 ..1..... ........] (0D 20 00)
5052 ---------------------------------------------------
5053 4 byte
5054 unicode range [U+10000, U+10FFFF]
5055 unicode min [........ ...10000 ..000000 ..000000]
5056 unicode max [.....100 ..001111 ..111111 ..111111]
5057 bit require [.....xxx ..xx.... ........ ........] (07 30 00 00)
5058 bit mask [xxxxx... xx...... xx...... xx......] (F8 C0 C0 C0)
5059 bit pattern [11110... 10...... 10...... 10......] (F0 80 80 80)
5060 ---------------------------------------------------
5061 */
5062#if YYJSON_ENDIAN == YYJSON_BIG_ENDIAN
5063 const u32 b1_mask = 0x80000000UL;
5064 const u32 b1_patt = 0x00000000UL;
5065 const u32 b2_mask = 0xE0C00000UL;
5066 const u32 b2_patt = 0xC0800000UL;
5067 const u32 b2_requ = 0x1E000000UL;
5068 const u32 b3_mask = 0xF0C0C000UL;
5069 const u32 b3_patt = 0xE0808000UL;
5070 const u32 b3_requ = 0x0F200000UL;
5071 const u32 b3_erro = 0x0D200000UL;
5072 const u32 b4_mask = 0xF8C0C0C0UL;
5073 const u32 b4_patt = 0xF0808080UL;
5074 const u32 b4_requ = 0x07300000UL;
5075 const u32 b4_err0 = 0x04000000UL;
5076 const u32 b4_err1 = 0x03300000UL;
5077#elif YYJSON_ENDIAN == YYJSON_LITTLE_ENDIAN
5078 const u32 b1_mask = 0x00000080UL;
5079 const u32 b1_patt = 0x00000000UL;
5080 const u32 b2_mask = 0x0000C0E0UL;
5081 const u32 b2_patt = 0x000080C0UL;
5082 const u32 b2_requ = 0x0000001EUL;
5083 const u32 b3_mask = 0x00C0C0F0UL;
5084 const u32 b3_patt = 0x008080E0UL;
5085 const u32 b3_requ = 0x0000200FUL;
5086 const u32 b3_erro = 0x0000200DUL;
5087 const u32 b4_mask = 0xC0C0C0F8UL;
5088 const u32 b4_patt = 0x808080F0UL;
5089 const u32 b4_requ = 0x00003007UL;
5090 const u32 b4_err0 = 0x00000004UL;
5091 const u32 b4_err1 = 0x00003003UL;
5092#else
5093 v32_uni b1_mask_uni = {{ 0x80, 0x00, 0x00, 0x00 }};
5094 v32_uni b1_patt_uni = {{ 0x00, 0x00, 0x00, 0x00 }};
5095 v32_uni b2_mask_uni = {{ 0xE0, 0xC0, 0x00, 0x00 }};
5096 v32_uni b2_patt_uni = {{ 0xC0, 0x80, 0x00, 0x00 }};
5097 v32_uni b2_requ_uni = {{ 0x1E, 0x00, 0x00, 0x00 }};
5098 v32_uni b3_mask_uni = {{ 0xF0, 0xC0, 0xC0, 0x00 }};
5099 v32_uni b3_patt_uni = {{ 0xE0, 0x80, 0x80, 0x00 }};
5100 v32_uni b3_requ_uni = {{ 0x0F, 0x20, 0x00, 0x00 }};
5101 v32_uni b3_erro_uni = {{ 0x0D, 0x20, 0x00, 0x00 }};
5102 v32_uni b4_mask_uni = {{ 0xF8, 0xC0, 0xC0, 0xC0 }};
5103 v32_uni b4_patt_uni = {{ 0xF0, 0x80, 0x80, 0x80 }};
5104 v32_uni b4_requ_uni = {{ 0x07, 0x30, 0x00, 0x00 }};
5105 v32_uni b4_err0_uni = {{ 0x04, 0x00, 0x00, 0x00 }};
5106 v32_uni b4_err1_uni = {{ 0x03, 0x30, 0x00, 0x00 }};
5107 u32 b1_mask = b1_mask_uni.u;
5108 u32 b1_patt = b1_patt_uni.u;
5109 u32 b2_mask = b2_mask_uni.u;
5110 u32 b2_patt = b2_patt_uni.u;
5111 u32 b2_requ = b2_requ_uni.u;
5112 u32 b3_mask = b3_mask_uni.u;
5113 u32 b3_patt = b3_patt_uni.u;
5114 u32 b3_requ = b3_requ_uni.u;
5115 u32 b3_erro = b3_erro_uni.u;
5116 u32 b4_mask = b4_mask_uni.u;
5117 u32 b4_patt = b4_patt_uni.u;
5118 u32 b4_requ = b4_requ_uni.u;
5119 u32 b4_err0 = b4_err0_uni.u;
5120 u32 b4_err1 = b4_err1_uni.u;
5121#endif
5122
5123#define is_valid_seq_1(uni) ( \
5124 ((uni & b1_mask) == b1_patt) \
5125)
5126
5127#define is_valid_seq_2(uni) ( \
5128 ((uni & b2_mask) == b2_patt) && \
5129 ((uni & b2_requ)) \
5130)
5131
5132#define is_valid_seq_3(uni) ( \
5133 ((uni & b3_mask) == b3_patt) && \
5134 ((tmp = (uni & b3_requ))) && \
5135 ((tmp != b3_erro)) \
5136)
5137
5138#define is_valid_seq_4(uni) ( \
5139 ((uni & b4_mask) == b4_patt) && \
5140 ((tmp = (uni & b4_requ))) && \
5141 ((tmp & b4_err0) == 0 || (tmp & b4_err1) == 0) \
5142)
5143
5144#define return_err(_end, _msg) do { \
5145 *msg = _msg; \
5146 *end = _end; \
5147 return false; \
5148} while (false)
5149
5150 u8 *cur = *ptr;
5151 u8 **end = ptr;
5152 u8 *src = ++cur, *dst, *pos;
5153 u16 hi, lo;
5154 u32 uni, tmp;
5155
5156skip_ascii:
5157 /* Most strings have no escaped characters, so we can jump them quickly. */
5158
5159skip_ascii_begin:
5160 /*
5161 We want to make loop unrolling, as shown in the following code. Some
5162 compiler may not generate instructions as expected, so we rewrite it with
5163 explicit goto statements. We hope the compiler can generate instructions
5164 like this: https://godbolt.org/z/8vjsYq
5165
5166 while (true) repeat16({
5167 if (likely(!(char_is_ascii_stop(*src)))) src++;
5168 else break;
5169 })
5170 */
5171#define expr_jump(i) \
5172 if (likely(!char_is_ascii_stop(src[i]))) {} \
5173 else goto skip_ascii_stop##i;
5174
5175#define expr_stop(i) \
5176 skip_ascii_stop##i: \
5177 src += i; \
5178 goto skip_ascii_end;
5179
5180 repeat16_incr(expr_jump)
5181 src += 16;
5182 goto skip_ascii_begin;
5183 repeat16_incr(expr_stop)
5184
5185#undef expr_jump
5186#undef expr_stop
5187
5188skip_ascii_end:
5189
5190 /*
5191 GCC may store src[i] in a register at each line of expr_jump(i) above.
5192 These instructions are useless and will degrade performance.
5193 This inline asm is a hint for gcc: "the memory has been modified,
5194 do not cache it".
5195
5196 MSVC, Clang, ICC can generate expected instructions without this hint.
5197 */
5198#if YYJSON_IS_REAL_GCC
5199 __asm__ volatile("":"=m"(*src));
5200#endif
5201 if (likely(*src == '"')) {
5202 val->tag = ((u64)(src - cur) << YYJSON_TAG_BIT) |
5203 (u64)(YYJSON_TYPE_STR | YYJSON_SUBTYPE_NOESC);
5204 val->uni.str = (const char *)cur;
5205 *src = '\0';
5206 *end = src + 1;
5207 return true;
5208 }
5209
5210skip_utf8:
5211 if (*src & 0x80) { /* non-ASCII character */
5212 /*
5213 Non-ASCII character appears here, which means that the text is likely
5214 to be written in non-English or emoticons. According to some common
5215 data set statistics, byte sequences of the same length may appear
5216 consecutively. We process the byte sequences of the same length in each
5217 loop, which is more friendly to branch prediction.
5218 */
5219 pos = src;
5220 uni = byte_load_4(src);
5221 while (is_valid_seq_3(uni)) {
5222 src += 3;
5223 uni = byte_load_4(src);
5224 }
5225 if (is_valid_seq_1(uni)) goto skip_ascii;
5226 while (is_valid_seq_2(uni)) {
5227 src += 2;
5228 uni = byte_load_4(src);
5229 }
5230 while (is_valid_seq_4(uni)) {
5231 src += 4;
5232 uni = byte_load_4(src);
5233 }
5234 if (unlikely(pos == src)) {
5235 if (!inv) return_err(src, "invalid UTF-8 encoding in string");
5236 ++src;
5237 }
5238 goto skip_ascii;
5239 }
5240
5241 /* The escape character appears, we need to copy it. */
5242 dst = src;
5243copy_escape:
5244 if (likely(*src == '\\')) {
5245 switch (*++src) {
5246 case '"': *dst++ = '"'; src++; break;
5247 case '\\': *dst++ = '\\'; src++; break;
5248 case '/': *dst++ = '/'; src++; break;
5249 case 'b': *dst++ = '\b'; src++; break;
5250 case 'f': *dst++ = '\f'; src++; break;
5251 case 'n': *dst++ = '\n'; src++; break;
5252 case 'r': *dst++ = '\r'; src++; break;
5253 case 't': *dst++ = '\t'; src++; break;
5254 case 'u':
5255 if (unlikely(!read_hex_u16(++src, &hi))) {
5256 return_err(src - 2, "invalid escaped sequence in string");
5257 }
5258 src += 4;
5259 if (likely((hi & 0xF800) != 0xD800)) {
5260 /* a BMP character */
5261 if (hi >= 0x800) {
5262 *dst++ = (u8)(0xE0 | (hi >> 12));
5263 *dst++ = (u8)(0x80 | ((hi >> 6) & 0x3F));
5264 *dst++ = (u8)(0x80 | (hi & 0x3F));
5265 } else if (hi >= 0x80) {
5266 *dst++ = (u8)(0xC0 | (hi >> 6));
5267 *dst++ = (u8)(0x80 | (hi & 0x3F));
5268 } else {
5269 *dst++ = (u8)hi;
5270 }
5271 } else {
5272 /* a non-BMP character, represented as a surrogate pair */
5273 if (unlikely((hi & 0xFC00) != 0xD800)) {
5274 return_err(src - 6, "invalid high surrogate in string");
5275 }
5276 if (unlikely(!byte_match_2(src, "\\u"))) {
5277 return_err(src, "no low surrogate in string");
5278 }
5279 if (unlikely(!read_hex_u16(src + 2, &lo))) {
5280 return_err(src, "invalid escaped sequence in string");
5281 }
5282 if (unlikely((lo & 0xFC00) != 0xDC00)) {
5283 return_err(src, "invalid low surrogate in string");
5284 }
5285 uni = ((((u32)hi - 0xD800) << 10) |
5286 ((u32)lo - 0xDC00)) + 0x10000;
5287 *dst++ = (u8)(0xF0 | (uni >> 18));
5288 *dst++ = (u8)(0x80 | ((uni >> 12) & 0x3F));
5289 *dst++ = (u8)(0x80 | ((uni >> 6) & 0x3F));
5290 *dst++ = (u8)(0x80 | (uni & 0x3F));
5291 src += 6;
5292 }
5293 break;
5294 default: return_err(src, "invalid escaped character in string");
5295 }
5296 } else if (likely(*src == '"')) {
5297 val->tag = ((u64)(dst - cur) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR;
5298 val->uni.str = (const char *)cur;
5299 *dst = '\0';
5300 *end = src + 1;
5301 return true;
5302 } else {
5303 if (!inv) return_err(src, "unexpected control character in string");
5304 if (src >= lst) return_err(src, "unclosed string");
5305 *dst++ = *src++;
5306 }
5307
5308copy_ascii:
5309 /*
5310 Copy continuous ASCII, loop unrolling, same as the following code:
5311
5312 while (true) repeat16({
5313 if (unlikely(char_is_ascii_stop(*src))) break;
5314 *dst++ = *src++;
5315 })
5316 */
5317#if YYJSON_IS_REAL_GCC
5318# define expr_jump(i) \
5319 if (likely(!(char_is_ascii_stop(src[i])))) {} \
5320 else { __asm__ volatile("":"=m"(src[i])); goto copy_ascii_stop_##i; }
5321#else
5322# define expr_jump(i) \
5323 if (likely(!(char_is_ascii_stop(src[i])))) {} \
5324 else { goto copy_ascii_stop_##i; }
5325#endif
5326 repeat16_incr(expr_jump)
5327#undef expr_jump
5328
5329 byte_move_16(dst, src);
5330 src += 16;
5331 dst += 16;
5332 goto copy_ascii;
5333
5334copy_ascii_stop_0:
5335 goto copy_utf8;
5336copy_ascii_stop_1:
5337 byte_move_2(dst, src);
5338 src += 1;
5339 dst += 1;
5340 goto copy_utf8;
5341copy_ascii_stop_2:
5342 byte_move_2(dst, src);
5343 src += 2;
5344 dst += 2;
5345 goto copy_utf8;
5346copy_ascii_stop_3:
5347 byte_move_4(dst, src);
5348 src += 3;
5349 dst += 3;
5350 goto copy_utf8;
5351copy_ascii_stop_4:
5352 byte_move_4(dst, src);
5353 src += 4;
5354 dst += 4;
5355 goto copy_utf8;
5356copy_ascii_stop_5:
5357 byte_move_4(dst, src);
5358 byte_move_2(dst + 4, src + 4);
5359 src += 5;
5360 dst += 5;
5361 goto copy_utf8;
5362copy_ascii_stop_6:
5363 byte_move_4(dst, src);
5364 byte_move_2(dst + 4, src + 4);
5365 src += 6;
5366 dst += 6;
5367 goto copy_utf8;
5368copy_ascii_stop_7:
5369 byte_move_8(dst, src);
5370 src += 7;
5371 dst += 7;
5372 goto copy_utf8;
5373copy_ascii_stop_8:
5374 byte_move_8(dst, src);
5375 src += 8;
5376 dst += 8;
5377 goto copy_utf8;
5378copy_ascii_stop_9:
5379 byte_move_8(dst, src);
5380 byte_move_2(dst + 8, src + 8);
5381 src += 9;
5382 dst += 9;
5383 goto copy_utf8;
5384copy_ascii_stop_10:
5385 byte_move_8(dst, src);
5386 byte_move_2(dst + 8, src + 8);
5387 src += 10;
5388 dst += 10;
5389 goto copy_utf8;
5390copy_ascii_stop_11:
5391 byte_move_8(dst, src);
5392 byte_move_4(dst + 8, src + 8);
5393 src += 11;
5394 dst += 11;
5395 goto copy_utf8;
5396copy_ascii_stop_12:
5397 byte_move_8(dst, src);
5398 byte_move_4(dst + 8, src + 8);
5399 src += 12;
5400 dst += 12;
5401 goto copy_utf8;
5402copy_ascii_stop_13:
5403 byte_move_8(dst, src);
5404 byte_move_4(dst + 8, src + 8);
5405 byte_move_2(dst + 12, src + 12);
5406 src += 13;
5407 dst += 13;
5408 goto copy_utf8;
5409copy_ascii_stop_14:
5410 byte_move_8(dst, src);
5411 byte_move_4(dst + 8, src + 8);
5412 byte_move_2(dst + 12, src + 12);
5413 src += 14;
5414 dst += 14;
5415 goto copy_utf8;
5416copy_ascii_stop_15:
5417 byte_move_16(dst, src);
5418 src += 15;
5419 dst += 15;
5420 goto copy_utf8;
5421
5422copy_utf8:
5423 if (*src & 0x80) { /* non-ASCII character */
5424 pos = src;
5425 uni = byte_load_4(src);
5426 while (is_valid_seq_3(uni)) {
5427 byte_copy_4(dst, &uni);
5428 dst += 3;
5429 src += 3;
5430 uni = byte_load_4(src);
5431 }
5432 if (is_valid_seq_1(uni)) goto copy_ascii;
5433 while (is_valid_seq_2(uni)) {
5434 byte_copy_2(dst, &uni);
5435 dst += 2;
5436 src += 2;
5437 uni = byte_load_4(src);
5438 }
5439 while (is_valid_seq_4(uni)) {
5440 byte_copy_4(dst, &uni);
5441 dst += 4;
5442 src += 4;
5443 uni = byte_load_4(src);
5444 }
5445 if (unlikely(pos == src)) {
5446 if (!inv) return_err(src, "invalid UTF-8 encoding in string");
5447 goto copy_ascii_stop_1;
5448 }
5449 goto copy_ascii;
5450 }
5451 goto copy_escape;
5452
5453#undef return_err
5454#undef is_valid_seq_1
5455#undef is_valid_seq_2
5456#undef is_valid_seq_3
5457#undef is_valid_seq_4
5458}
5459
5460
5461
5462/*==============================================================================
5463 * JSON Reader Implementation
5464 *
5465 * We use goto statements to build the finite state machine (FSM).
5466 * The FSM's state was held by program counter (PC) and the 'goto' make the
5467 * state transitions.
5468 *============================================================================*/
5469
5470/** Read single value JSON document. */
5471static_noinline yyjson_doc *read_root_single(u8 *hdr,
5472 u8 *cur,
5473 u8 *end,
5474 yyjson_alc alc,
5475 yyjson_read_flag flg,
5476 yyjson_read_err *err) {
5477
5478#define has_flag(_flag) unlikely((flg & YYJSON_READ_##_flag) != 0)
5479
5480#define return_err(_pos, _code, _msg) do { \
5481 if (is_truncated_end(hdr, _pos, end, YYJSON_READ_ERROR_##_code, flg)) { \
5482 err->pos = (usize)(end - hdr); \
5483 err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
5484 err->msg = "unexpected end of data"; \
5485 } else { \
5486 err->pos = (usize)(_pos - hdr); \
5487 err->code = YYJSON_READ_ERROR_##_code; \
5488 err->msg = _msg; \
5489 } \
5490 if (val_hdr) alc.free(alc.ctx, (void *)val_hdr); \
5491 return NULL; \
5492} while (false)
5493
5494 usize hdr_len; /* value count used by doc */
5495 usize alc_num; /* value count capacity */
5496 yyjson_val *val_hdr; /* the head of allocated values */
5497 yyjson_val *val; /* current value */
5498 yyjson_doc *doc; /* the JSON document, equals to val_hdr */
5499 const char *msg; /* error message */
5500
5501 bool raw; /* read number as raw */
5502 bool inv; /* allow invalid unicode */
5503 u8 *raw_end; /* raw end for null-terminator */
5504 u8 **pre; /* previous raw end pointer */
5505
5506 hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
5507 hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
5508 alc_num = hdr_len + 1; /* single value */
5509
5510 val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_num * sizeof(yyjson_val));
5511 if (unlikely(!val_hdr)) goto fail_alloc;
5512 val = val_hdr + hdr_len;
5513 raw = (flg & (YYJSON_READ_NUMBER_AS_RAW | YYJSON_READ_BIGNUM_AS_RAW)) != 0;
5514 inv = (flg & YYJSON_READ_ALLOW_INVALID_UNICODE) != 0;
5515 raw_end = NULL;
5516 pre = raw ? &raw_end : NULL;
5517
5518 if (char_is_number(*cur)) {
5519 if (likely(read_number(&cur, pre, flg, val, &msg))) goto doc_end;
5520 goto fail_number;
5521 }
5522 if (*cur == '"') {
5523 if (likely(read_string(&cur, end, inv, val, &msg))) goto doc_end;
5524 goto fail_string;
5525 }
5526 if (*cur == 't') {
5527 if (likely(read_true(&cur, val))) goto doc_end;
5528 goto fail_literal;
5529 }
5530 if (*cur == 'f') {
5531 if (likely(read_false(&cur, val))) goto doc_end;
5532 goto fail_literal;
5533 }
5534 if (*cur == 'n') {
5535 if (likely(read_null(&cur, val))) goto doc_end;
5536 if (unlikely(flg & YYJSON_READ_ALLOW_INF_AND_NAN)) {
5537 if (read_nan(false, &cur, pre, val)) goto doc_end;
5538 }
5539 goto fail_literal;
5540 }
5541 if (unlikely(flg & YYJSON_READ_ALLOW_INF_AND_NAN)) {
5542 if (read_inf_or_nan(false, &cur, pre, val)) goto doc_end;
5543 }
5544 goto fail_character;
5545
5546doc_end:
5547 /* check invalid contents after json document */
5548 if (unlikely(cur < end) && !has_flag(STOP_WHEN_DONE)) {
5549 if (has_flag(ALLOW_COMMENTS)) {
5550 if (!skip_spaces_and_comments(&cur)) {
5551 if (byte_match_2(cur, "/*")) goto fail_comment;
5552 }
5553 } else {
5554 while (char_is_space(*cur)) cur++;
5555 }
5556 if (unlikely(cur < end)) goto fail_garbage;
5557 }
5558
5559 if (pre && *pre) **pre = '\0';
5560 doc = (yyjson_doc *)val_hdr;
5561 doc->root = val_hdr + hdr_len;
5562 doc->alc = alc;
5563 doc->dat_read = (usize)(cur - hdr);
5564 doc->val_read = 1;
5565 doc->str_pool = has_flag(INSITU) ? NULL : (char *)hdr;
5566 return doc;
5567
5568fail_string:
5569 return_err(cur, INVALID_STRING, msg);
5570fail_number:
5571 return_err(cur, INVALID_NUMBER, msg);
5572fail_alloc:
5573 return_err(cur, MEMORY_ALLOCATION, "memory allocation failed");
5574fail_literal:
5575 return_err(cur, LITERAL, "invalid literal");
5576fail_comment:
5577 return_err(cur, INVALID_COMMENT, "unclosed multiline comment");
5578fail_character:
5579 return_err(cur, UNEXPECTED_CHARACTER, "unexpected character");
5580fail_garbage:
5581 return_err(cur, UNEXPECTED_CONTENT, "unexpected content after document");
5582
5583#undef has_flag
5584#undef return_err
5585}
5586
5587/** Read JSON document (accept all style, but optimized for minify). */
5588static_inline yyjson_doc *read_root_minify(u8 *hdr,
5589 u8 *cur,
5590 u8 *end,
5591 yyjson_alc alc,
5592 yyjson_read_flag flg,
5593 yyjson_read_err *err) {
5594
5595#define has_flag(_flag) unlikely((flg & YYJSON_READ_##_flag) != 0)
5596
5597#define return_err(_pos, _code, _msg) do { \
5598 if (is_truncated_end(hdr, _pos, end, YYJSON_READ_ERROR_##_code, flg)) { \
5599 err->pos = (usize)(end - hdr); \
5600 err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
5601 err->msg = "unexpected end of data"; \
5602 } else { \
5603 err->pos = (usize)(_pos - hdr); \
5604 err->code = YYJSON_READ_ERROR_##_code; \
5605 err->msg = _msg; \
5606 } \
5607 if (val_hdr) alc.free(alc.ctx, (void *)val_hdr); \
5608 return NULL; \
5609} while (false)
5610
5611#define val_incr() do { \
5612 val++; \
5613 if (unlikely(val >= val_end)) { \
5614 usize alc_old = alc_len; \
5615 alc_len += alc_len / 2; \
5616 if ((alc_len >= alc_max)) goto fail_alloc; \
5617 val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
5618 alc_old * sizeof(yyjson_val), \
5619 alc_len * sizeof(yyjson_val)); \
5620 if ((!val_tmp)) goto fail_alloc; \
5621 val = val_tmp + (usize)(val - val_hdr); \
5622 ctn = val_tmp + (usize)(ctn - val_hdr); \
5623 val_hdr = val_tmp; \
5624 val_end = val_tmp + (alc_len - 2); \
5625 } \
5626} while (false)
5627
5628 usize dat_len; /* data length in bytes, hint for allocator */
5629 usize hdr_len; /* value count used by yyjson_doc */
5630 usize alc_len; /* value count allocated */
5631 usize alc_max; /* maximum value count for allocator */
5632 usize ctn_len; /* the number of elements in current container */
5633 yyjson_val *val_hdr; /* the head of allocated values */
5634 yyjson_val *val_end; /* the end of allocated values */
5635 yyjson_val *val_tmp; /* temporary pointer for realloc */
5636 yyjson_val *val; /* current JSON value */
5637 yyjson_val *ctn; /* current container */
5638 yyjson_val *ctn_parent; /* parent of current container */
5639 yyjson_doc *doc; /* the JSON document, equals to val_hdr */
5640 const char *msg; /* error message */
5641
5642 bool raw; /* read number as raw */
5643 bool inv; /* allow invalid unicode */
5644 u8 *raw_end; /* raw end for null-terminator */
5645 u8 **pre; /* previous raw end pointer */
5646
5647 dat_len = has_flag(STOP_WHEN_DONE) ? 256 : (usize)(end - cur);
5648 hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
5649 hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
5650 alc_max = USIZE_MAX / sizeof(yyjson_val);
5651 alc_len = hdr_len + (dat_len / YYJSON_READER_ESTIMATED_MINIFY_RATIO) + 4;
5652 alc_len = yyjson_min(alc_len, alc_max);
5653
5654 val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_len * sizeof(yyjson_val));
5655 if (unlikely(!val_hdr)) goto fail_alloc;
5656 val_end = val_hdr + (alc_len - 2); /* padding for key-value pair reading */
5657 val = val_hdr + hdr_len;
5658 ctn = val;
5659 ctn_len = 0;
5660 raw = (flg & (YYJSON_READ_NUMBER_AS_RAW | YYJSON_READ_BIGNUM_AS_RAW)) != 0;
5661 inv = (flg & YYJSON_READ_ALLOW_INVALID_UNICODE) != 0;
5662 raw_end = NULL;
5663 pre = raw ? &raw_end : NULL;
5664
5665 if (*cur++ == '{') {
5666 ctn->tag = YYJSON_TYPE_OBJ;
5667 ctn->uni.ofs = 0;
5668 goto obj_key_begin;
5669 } else {
5670 ctn->tag = YYJSON_TYPE_ARR;
5671 ctn->uni.ofs = 0;
5672 goto arr_val_begin;
5673 }
5674
5675arr_begin:
5676 /* save current container */
5677 ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
5678 (ctn->tag & YYJSON_TAG_MASK);
5679
5680 /* create a new array value, save parent container offset */
5681 val_incr();
5682 val->tag = YYJSON_TYPE_ARR;
5683 val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
5684
5685 /* push the new array value as current container */
5686 ctn = val;
5687 ctn_len = 0;
5688
5689arr_val_begin:
5690 if (*cur == '{') {
5691 cur++;
5692 goto obj_begin;
5693 }
5694 if (*cur == '[') {
5695 cur++;
5696 goto arr_begin;
5697 }
5698 if (char_is_number(*cur)) {
5699 val_incr();
5700 ctn_len++;
5701 if (likely(read_number(&cur, pre, flg, val, &msg))) goto arr_val_end;
5702 goto fail_number;
5703 }
5704 if (*cur == '"') {
5705 val_incr();
5706 ctn_len++;
5707 if (likely(read_string(&cur, end, inv, val, &msg))) goto arr_val_end;
5708 goto fail_string;
5709 }
5710 if (*cur == 't') {
5711 val_incr();
5712 ctn_len++;
5713 if (likely(read_true(&cur, val))) goto arr_val_end;
5714 goto fail_literal;
5715 }
5716 if (*cur == 'f') {
5717 val_incr();
5718 ctn_len++;
5719 if (likely(read_false(&cur, val))) goto arr_val_end;
5720 goto fail_literal;
5721 }
5722 if (*cur == 'n') {
5723 val_incr();
5724 ctn_len++;
5725 if (likely(read_null(&cur, val))) goto arr_val_end;
5726 if (unlikely(flg & YYJSON_READ_ALLOW_INF_AND_NAN)) {
5727 if (read_nan(false, &cur, pre, val)) goto arr_val_end;
5728 }
5729 goto fail_literal;
5730 }
5731 if (*cur == ']') {
5732 cur++;
5733 if (likely(ctn_len == 0)) goto arr_end;
5734 if (has_flag(ALLOW_TRAILING_COMMAS)) goto arr_end;
5735 while (*cur != ',') cur--;
5736 goto fail_trailing_comma;
5737 }
5738 if (char_is_space(*cur)) {
5739 while (char_is_space(*++cur));
5740 goto arr_val_begin;
5741 }
5742 if (unlikely(flg & YYJSON_READ_ALLOW_INF_AND_NAN) &&
5743 (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
5744 val_incr();
5745 ctn_len++;
5746 if (read_inf_or_nan(false, &cur, pre, val)) goto arr_val_end;
5747 goto fail_character;
5748 }
5749 if (has_flag(ALLOW_COMMENTS)) {
5750 if (skip_spaces_and_comments(&cur)) goto arr_val_begin;
5751 if (byte_match_2(cur, "/*")) goto fail_comment;
5752 }
5753 goto fail_character;
5754
5755arr_val_end:
5756 if (*cur == ',') {
5757 cur++;
5758 goto arr_val_begin;
5759 }
5760 if (*cur == ']') {
5761 cur++;
5762 goto arr_end;
5763 }
5764 if (char_is_space(*cur)) {
5765 while (char_is_space(*++cur));
5766 goto arr_val_end;
5767 }
5768 if (has_flag(ALLOW_COMMENTS)) {
5769 if (skip_spaces_and_comments(&cur)) goto arr_val_end;
5770 if (byte_match_2(cur, "/*")) goto fail_comment;
5771 }
5772 goto fail_character;
5773
5774arr_end:
5775 /* get parent container */
5776 ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
5777
5778 /* save the next sibling value offset */
5779 ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
5780 ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
5781 if (unlikely(ctn == ctn_parent)) goto doc_end;
5782
5783 /* pop parent as current container */
5784 ctn = ctn_parent;
5785 ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
5786 if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
5787 goto obj_val_end;
5788 } else {
5789 goto arr_val_end;
5790 }
5791
5792obj_begin:
5793 /* push container */
5794 ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
5795 (ctn->tag & YYJSON_TAG_MASK);
5796 val_incr();
5797 val->tag = YYJSON_TYPE_OBJ;
5798 /* offset to the parent */
5799 val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
5800 ctn = val;
5801 ctn_len = 0;
5802
5803obj_key_begin:
5804 if (likely(*cur == '"')) {
5805 val_incr();
5806 ctn_len++;
5807 if (likely(read_string(&cur, end, inv, val, &msg))) goto obj_key_end;
5808 goto fail_string;
5809 }
5810 if (likely(*cur == '}')) {
5811 cur++;
5812 if (likely(ctn_len == 0)) goto obj_end;
5813 if (has_flag(ALLOW_TRAILING_COMMAS)) goto obj_end;
5814 while (*cur != ',') cur--;
5815 goto fail_trailing_comma;
5816 }
5817 if (char_is_space(*cur)) {
5818 while (char_is_space(*++cur));
5819 goto obj_key_begin;
5820 }
5821 if (has_flag(ALLOW_COMMENTS)) {
5822 if (skip_spaces_and_comments(&cur)) goto obj_key_begin;
5823 if (byte_match_2(cur, "/*")) goto fail_comment;
5824 }
5825 goto fail_character;
5826
5827obj_key_end:
5828 if (*cur == ':') {
5829 cur++;
5830 goto obj_val_begin;
5831 }
5832 if (char_is_space(*cur)) {
5833 while (char_is_space(*++cur));
5834 goto obj_key_end;
5835 }
5836 if (has_flag(ALLOW_COMMENTS)) {
5837 if (skip_spaces_and_comments(&cur)) goto obj_key_end;
5838 if (byte_match_2(cur, "/*")) goto fail_comment;
5839 }
5840 goto fail_character;
5841
5842obj_val_begin:
5843 if (*cur == '"') {
5844 val++;
5845 ctn_len++;
5846 if (likely(read_string(&cur, end, inv, val, &msg))) goto obj_val_end;
5847 goto fail_string;
5848 }
5849 if (char_is_number(*cur)) {
5850 val++;
5851 ctn_len++;
5852 if (likely(read_number(&cur, pre, flg, val, &msg))) goto obj_val_end;
5853 goto fail_number;
5854 }
5855 if (*cur == '{') {
5856 cur++;
5857 goto obj_begin;
5858 }
5859 if (*cur == '[') {
5860 cur++;
5861 goto arr_begin;
5862 }
5863 if (*cur == 't') {
5864 val++;
5865 ctn_len++;
5866 if (likely(read_true(&cur, val))) goto obj_val_end;
5867 goto fail_literal;
5868 }
5869 if (*cur == 'f') {
5870 val++;
5871 ctn_len++;
5872 if (likely(read_false(&cur, val))) goto obj_val_end;
5873 goto fail_literal;
5874 }
5875 if (*cur == 'n') {
5876 val++;
5877 ctn_len++;
5878 if (likely(read_null(&cur, val))) goto obj_val_end;
5879 if (unlikely(flg & YYJSON_READ_ALLOW_INF_AND_NAN)) {
5880 if (read_nan(false, &cur, pre, val)) goto obj_val_end;
5881 }
5882 goto fail_literal;
5883 }
5884 if (char_is_space(*cur)) {
5885 while (char_is_space(*++cur));
5886 goto obj_val_begin;
5887 }
5888 if (unlikely(flg & YYJSON_READ_ALLOW_INF_AND_NAN) &&
5889 (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
5890 val++;
5891 ctn_len++;
5892 if (read_inf_or_nan(false, &cur, pre, val)) goto obj_val_end;
5893 goto fail_character;
5894 }
5895 if (has_flag(ALLOW_COMMENTS)) {
5896 if (skip_spaces_and_comments(&cur)) goto obj_val_begin;
5897 if (byte_match_2(cur, "/*")) goto fail_comment;
5898 }
5899 goto fail_character;
5900
5901obj_val_end:
5902 if (likely(*cur == ',')) {
5903 cur++;
5904 goto obj_key_begin;
5905 }
5906 if (likely(*cur == '}')) {
5907 cur++;
5908 goto obj_end;
5909 }
5910 if (char_is_space(*cur)) {
5911 while (char_is_space(*++cur));
5912 goto obj_val_end;
5913 }
5914 if (has_flag(ALLOW_COMMENTS)) {
5915 if (skip_spaces_and_comments(&cur)) goto obj_val_end;
5916 if (byte_match_2(cur, "/*")) goto fail_comment;
5917 }
5918 goto fail_character;
5919
5920obj_end:
5921 /* pop container */
5922 ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
5923 /* point to the next value */
5924 ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
5925 ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
5926 if (unlikely(ctn == ctn_parent)) goto doc_end;
5927 ctn = ctn_parent;
5928 ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
5929 if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
5930 goto obj_val_end;
5931 } else {
5932 goto arr_val_end;
5933 }
5934
5935doc_end:
5936 /* check invalid contents after json document */
5937 if (unlikely(cur < end) && !has_flag(STOP_WHEN_DONE)) {
5938 if (has_flag(ALLOW_COMMENTS)) {
5939 skip_spaces_and_comments(&cur);
5940 if (byte_match_2(cur, "/*")) goto fail_comment;
5941 }
5942 else while (char_is_space(*cur)) cur++;
5943 if (unlikely(cur < end)) goto fail_garbage;
5944 }
5945
5946 if (pre && *pre) **pre = '\0';
5947 doc = (yyjson_doc *)val_hdr;
5948 doc->root = val_hdr + hdr_len;
5949 doc->alc = alc;
5950 doc->dat_read = (usize)(cur - hdr);
5951 doc->val_read = (usize)((val - doc->root) + 1);
5952 doc->str_pool = has_flag(INSITU) ? NULL : (char *)hdr;
5953 return doc;
5954
5955fail_string:
5956 return_err(cur, INVALID_STRING, msg);
5957fail_number:
5958 return_err(cur, INVALID_NUMBER, msg);
5959fail_alloc:
5960 return_err(cur, MEMORY_ALLOCATION, "memory allocation failed");
5961fail_trailing_comma:
5962 return_err(cur, JSON_STRUCTURE, "trailing comma is not allowed");
5963fail_literal:
5964 return_err(cur, LITERAL, "invalid literal");
5965fail_comment:
5966 return_err(cur, INVALID_COMMENT, "unclosed multiline comment");
5967fail_character:
5968 return_err(cur, UNEXPECTED_CHARACTER, "unexpected character");
5969fail_garbage:
5970 return_err(cur, UNEXPECTED_CONTENT, "unexpected content after document");
5971
5972#undef has_flag
5973#undef val_incr
5974#undef return_err
5975}
5976
5977/** Read JSON document (accept all style, but optimized for pretty). */
5978static_inline yyjson_doc *read_root_pretty(u8 *hdr,
5979 u8 *cur,
5980 u8 *end,
5981 yyjson_alc alc,
5982 yyjson_read_flag flg,
5983 yyjson_read_err *err) {
5984
5985#define has_flag(_flag) unlikely((flg & YYJSON_READ_##_flag) != 0)
5986
5987#define return_err(_pos, _code, _msg) do { \
5988 if (is_truncated_end(hdr, _pos, end, YYJSON_READ_ERROR_##_code, flg)) { \
5989 err->pos = (usize)(end - hdr); \
5990 err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
5991 err->msg = "unexpected end of data"; \
5992 } else { \
5993 err->pos = (usize)(_pos - hdr); \
5994 err->code = YYJSON_READ_ERROR_##_code; \
5995 err->msg = _msg; \
5996 } \
5997 if (val_hdr) alc.free(alc.ctx, (void *)val_hdr); \
5998 return NULL; \
5999} while (false)
6000
6001#define val_incr() do { \
6002 val++; \
6003 if (unlikely(val >= val_end)) { \
6004 usize alc_old = alc_len; \
6005 alc_len += alc_len / 2; \
6006 if ((alc_len >= alc_max)) goto fail_alloc; \
6007 val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
6008 alc_old * sizeof(yyjson_val), \
6009 alc_len * sizeof(yyjson_val)); \
6010 if ((!val_tmp)) goto fail_alloc; \
6011 val = val_tmp + (usize)(val - val_hdr); \
6012 ctn = val_tmp + (usize)(ctn - val_hdr); \
6013 val_hdr = val_tmp; \
6014 val_end = val_tmp + (alc_len - 2); \
6015 } \
6016} while (false)
6017
6018 usize dat_len; /* data length in bytes, hint for allocator */
6019 usize hdr_len; /* value count used by yyjson_doc */
6020 usize alc_len; /* value count allocated */
6021 usize alc_max; /* maximum value count for allocator */
6022 usize ctn_len; /* the number of elements in current container */
6023 yyjson_val *val_hdr; /* the head of allocated values */
6024 yyjson_val *val_end; /* the end of allocated values */
6025 yyjson_val *val_tmp; /* temporary pointer for realloc */
6026 yyjson_val *val; /* current JSON value */
6027 yyjson_val *ctn; /* current container */
6028 yyjson_val *ctn_parent; /* parent of current container */
6029 yyjson_doc *doc; /* the JSON document, equals to val_hdr */
6030 const char *msg; /* error message */
6031
6032 bool raw; /* read number as raw */
6033 bool inv; /* allow invalid unicode */
6034 u8 *raw_end; /* raw end for null-terminator */
6035 u8 **pre; /* previous raw end pointer */
6036
6037 dat_len = has_flag(STOP_WHEN_DONE) ? 256 : (usize)(end - cur);
6038 hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
6039 hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
6040 alc_max = USIZE_MAX / sizeof(yyjson_val);
6041 alc_len = hdr_len + (dat_len / YYJSON_READER_ESTIMATED_PRETTY_RATIO) + 4;
6042 alc_len = yyjson_min(alc_len, alc_max);
6043
6044 val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_len * sizeof(yyjson_val));
6045 if (unlikely(!val_hdr)) goto fail_alloc;
6046 val_end = val_hdr + (alc_len - 2); /* padding for key-value pair reading */
6047 val = val_hdr + hdr_len;
6048 ctn = val;
6049 ctn_len = 0;
6050 raw = (flg & (YYJSON_READ_NUMBER_AS_RAW | YYJSON_READ_BIGNUM_AS_RAW)) != 0;
6051 inv = (flg & YYJSON_READ_ALLOW_INVALID_UNICODE) != 0;
6052 raw_end = NULL;
6053 pre = raw ? &raw_end : NULL;
6054
6055 if (*cur++ == '{') {
6056 ctn->tag = YYJSON_TYPE_OBJ;
6057 ctn->uni.ofs = 0;
6058 if (*cur == '\n') cur++;
6059 goto obj_key_begin;
6060 } else {
6061 ctn->tag = YYJSON_TYPE_ARR;
6062 ctn->uni.ofs = 0;
6063 if (*cur == '\n') cur++;
6064 goto arr_val_begin;
6065 }
6066
6067arr_begin:
6068 /* save current container */
6069 ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
6070 (ctn->tag & YYJSON_TAG_MASK);
6071
6072 /* create a new array value, save parent container offset */
6073 val_incr();
6074 val->tag = YYJSON_TYPE_ARR;
6075 val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
6076
6077 /* push the new array value as current container */
6078 ctn = val;
6079 ctn_len = 0;
6080 if (*cur == '\n') cur++;
6081
6082arr_val_begin:
6083#if YYJSON_IS_REAL_GCC
6084 while (true) repeat16({
6085 if (byte_match_2(cur, " ")) cur += 2;
6086 else break;
6087 })
6088#else
6089 while (true) repeat16({
6090 if (likely(byte_match_2(cur, " "))) cur += 2;
6091 else break;
6092 })
6093#endif
6094
6095 if (*cur == '{') {
6096 cur++;
6097 goto obj_begin;
6098 }
6099 if (*cur == '[') {
6100 cur++;
6101 goto arr_begin;
6102 }
6103 if (char_is_number(*cur)) {
6104 val_incr();
6105 ctn_len++;
6106 if (likely(read_number(&cur, pre, flg, val, &msg))) goto arr_val_end;
6107 goto fail_number;
6108 }
6109 if (*cur == '"') {
6110 val_incr();
6111 ctn_len++;
6112 if (likely(read_string(&cur, end, inv, val, &msg))) goto arr_val_end;
6113 goto fail_string;
6114 }
6115 if (*cur == 't') {
6116 val_incr();
6117 ctn_len++;
6118 if (likely(read_true(&cur, val))) goto arr_val_end;
6119 goto fail_literal;
6120 }
6121 if (*cur == 'f') {
6122 val_incr();
6123 ctn_len++;
6124 if (likely(read_false(&cur, val))) goto arr_val_end;
6125 goto fail_literal;
6126 }
6127 if (*cur == 'n') {
6128 val_incr();
6129 ctn_len++;
6130 if (likely(read_null(&cur, val))) goto arr_val_end;
6131 if (unlikely(flg & YYJSON_READ_ALLOW_INF_AND_NAN)) {
6132 if (read_nan(false, &cur, pre, val)) goto arr_val_end;
6133 }
6134 goto fail_literal;
6135 }
6136 if (*cur == ']') {
6137 cur++;
6138 if (likely(ctn_len == 0)) goto arr_end;
6139 if (has_flag(ALLOW_TRAILING_COMMAS)) goto arr_end;
6140 while (*cur != ',') cur--;
6141 goto fail_trailing_comma;
6142 }
6143 if (char_is_space(*cur)) {
6144 while (char_is_space(*++cur));
6145 goto arr_val_begin;
6146 }
6147 if (unlikely(flg & YYJSON_READ_ALLOW_INF_AND_NAN) &&
6148 (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
6149 val_incr();
6150 ctn_len++;
6151 if (read_inf_or_nan(false, &cur, pre, val)) goto arr_val_end;
6152 goto fail_character;
6153 }
6154 if (has_flag(ALLOW_COMMENTS)) {
6155 if (skip_spaces_and_comments(&cur)) goto arr_val_begin;
6156 if (byte_match_2(cur, "/*")) goto fail_comment;
6157 }
6158 goto fail_character;
6159
6160arr_val_end:
6161 if (byte_match_2(cur, ",\n")) {
6162 cur += 2;
6163 goto arr_val_begin;
6164 }
6165 if (*cur == ',') {
6166 cur++;
6167 goto arr_val_begin;
6168 }
6169 if (*cur == ']') {
6170 cur++;
6171 goto arr_end;
6172 }
6173 if (char_is_space(*cur)) {
6174 while (char_is_space(*++cur));
6175 goto arr_val_end;
6176 }
6177 if (has_flag(ALLOW_COMMENTS)) {
6178 if (skip_spaces_and_comments(&cur)) goto arr_val_end;
6179 if (byte_match_2(cur, "/*")) goto fail_comment;
6180 }
6181 goto fail_character;
6182
6183arr_end:
6184 /* get parent container */
6185 ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
6186
6187 /* save the next sibling value offset */
6188 ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
6189 ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
6190 if (unlikely(ctn == ctn_parent)) goto doc_end;
6191
6192 /* pop parent as current container */
6193 ctn = ctn_parent;
6194 ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
6195 if (*cur == '\n') cur++;
6196 if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
6197 goto obj_val_end;
6198 } else {
6199 goto arr_val_end;
6200 }
6201
6202obj_begin:
6203 /* push container */
6204 ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
6205 (ctn->tag & YYJSON_TAG_MASK);
6206 val_incr();
6207 val->tag = YYJSON_TYPE_OBJ;
6208 /* offset to the parent */
6209 val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
6210 ctn = val;
6211 ctn_len = 0;
6212 if (*cur == '\n') cur++;
6213
6214obj_key_begin:
6215#if YYJSON_IS_REAL_GCC
6216 while (true) repeat16({
6217 if (byte_match_2(cur, " ")) cur += 2;
6218 else break;
6219 })
6220#else
6221 while (true) repeat16({
6222 if (likely(byte_match_2(cur, " "))) cur += 2;
6223 else break;
6224 })
6225#endif
6226 if (likely(*cur == '"')) {
6227 val_incr();
6228 ctn_len++;
6229 if (likely(read_string(&cur, end, inv, val, &msg))) goto obj_key_end;
6230 goto fail_string;
6231 }
6232 if (likely(*cur == '}')) {
6233 cur++;
6234 if (likely(ctn_len == 0)) goto obj_end;
6235 if (has_flag(ALLOW_TRAILING_COMMAS)) goto obj_end;
6236 while (*cur != ',') cur--;
6237 goto fail_trailing_comma;
6238 }
6239 if (char_is_space(*cur)) {
6240 while (char_is_space(*++cur));
6241 goto obj_key_begin;
6242 }
6243 if (has_flag(ALLOW_COMMENTS)) {
6244 if (skip_spaces_and_comments(&cur)) goto obj_key_begin;
6245 if (byte_match_2(cur, "/*")) goto fail_comment;
6246 }
6247 goto fail_character;
6248
6249obj_key_end:
6250 if (byte_match_2(cur, ": ")) {
6251 cur += 2;
6252 goto obj_val_begin;
6253 }
6254 if (*cur == ':') {
6255 cur++;
6256 goto obj_val_begin;
6257 }
6258 if (char_is_space(*cur)) {
6259 while (char_is_space(*++cur));
6260 goto obj_key_end;
6261 }
6262 if (has_flag(ALLOW_COMMENTS)) {
6263 if (skip_spaces_and_comments(&cur)) goto obj_key_end;
6264 if (byte_match_2(cur, "/*")) goto fail_comment;
6265 }
6266 goto fail_character;
6267
6268obj_val_begin:
6269 if (*cur == '"') {
6270 val++;
6271 ctn_len++;
6272 if (likely(read_string(&cur, end, inv, val, &msg))) goto obj_val_end;
6273 goto fail_string;
6274 }
6275 if (char_is_number(*cur)) {
6276 val++;
6277 ctn_len++;
6278 if (likely(read_number(&cur, pre, flg, val, &msg))) goto obj_val_end;
6279 goto fail_number;
6280 }
6281 if (*cur == '{') {
6282 cur++;
6283 goto obj_begin;
6284 }
6285 if (*cur == '[') {
6286 cur++;
6287 goto arr_begin;
6288 }
6289 if (*cur == 't') {
6290 val++;
6291 ctn_len++;
6292 if (likely(read_true(&cur, val))) goto obj_val_end;
6293 goto fail_literal;
6294 }
6295 if (*cur == 'f') {
6296 val++;
6297 ctn_len++;
6298 if (likely(read_false(&cur, val))) goto obj_val_end;
6299 goto fail_literal;
6300 }
6301 if (*cur == 'n') {
6302 val++;
6303 ctn_len++;
6304 if (likely(read_null(&cur, val))) goto obj_val_end;
6305 if (unlikely(flg & YYJSON_READ_ALLOW_INF_AND_NAN)) {
6306 if (read_nan(false, &cur, pre, val)) goto obj_val_end;
6307 }
6308 goto fail_literal;
6309 }
6310 if (char_is_space(*cur)) {
6311 while (char_is_space(*++cur));
6312 goto obj_val_begin;
6313 }
6314 if (unlikely(flg & YYJSON_READ_ALLOW_INF_AND_NAN) &&
6315 (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
6316 val++;
6317 ctn_len++;
6318 if (read_inf_or_nan(false, &cur, pre, val)) goto obj_val_end;
6319 goto fail_character;
6320 }
6321 if (has_flag(ALLOW_COMMENTS)) {
6322 if (skip_spaces_and_comments(&cur)) goto obj_val_begin;
6323 if (byte_match_2(cur, "/*")) goto fail_comment;
6324 }
6325 goto fail_character;
6326
6327obj_val_end:
6328 if (byte_match_2(cur, ",\n")) {
6329 cur += 2;
6330 goto obj_key_begin;
6331 }
6332 if (likely(*cur == ',')) {
6333 cur++;
6334 goto obj_key_begin;
6335 }
6336 if (likely(*cur == '}')) {
6337 cur++;
6338 goto obj_end;
6339 }
6340 if (char_is_space(*cur)) {
6341 while (char_is_space(*++cur));
6342 goto obj_val_end;
6343 }
6344 if (has_flag(ALLOW_COMMENTS)) {
6345 if (skip_spaces_and_comments(&cur)) goto obj_val_end;
6346 if (byte_match_2(cur, "/*")) goto fail_comment;
6347 }
6348 goto fail_character;
6349
6350obj_end:
6351 /* pop container */
6352 ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
6353 /* point to the next value */
6354 ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
6355 ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
6356 if (unlikely(ctn == ctn_parent)) goto doc_end;
6357 ctn = ctn_parent;
6358 ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
6359 if (*cur == '\n') cur++;
6360 if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
6361 goto obj_val_end;
6362 } else {
6363 goto arr_val_end;
6364 }
6365
6366doc_end:
6367 /* check invalid contents after json document */
6368 if (unlikely(cur < end) && !has_flag(STOP_WHEN_DONE)) {
6369 if (has_flag(ALLOW_COMMENTS)) {
6370 skip_spaces_and_comments(&cur);
6371 if (byte_match_2(cur, "/*")) goto fail_comment;
6372 }
6373 else while (char_is_space(*cur)) cur++;
6374 if (unlikely(cur < end)) goto fail_garbage;
6375 }
6376
6377 if (pre && *pre) **pre = '\0';
6378 doc = (yyjson_doc *)val_hdr;
6379 doc->root = val_hdr + hdr_len;
6380 doc->alc = alc;
6381 doc->dat_read = (usize)(cur - hdr);
6382 doc->val_read = (usize)((val - val_hdr)) - hdr_len + 1;
6383 doc->str_pool = has_flag(INSITU) ? NULL : (char *)hdr;
6384 return doc;
6385
6386fail_string:
6387 return_err(cur, INVALID_STRING, msg);
6388fail_number:
6389 return_err(cur, INVALID_NUMBER, msg);
6390fail_alloc:
6391 return_err(cur, MEMORY_ALLOCATION, "memory allocation failed");
6392fail_trailing_comma:
6393 return_err(cur, JSON_STRUCTURE, "trailing comma is not allowed");
6394fail_literal:
6395 return_err(cur, LITERAL, "invalid literal");
6396fail_comment:
6397 return_err(cur, INVALID_COMMENT, "unclosed multiline comment");
6398fail_character:
6399 return_err(cur, UNEXPECTED_CHARACTER, "unexpected character");
6400fail_garbage:
6401 return_err(cur, UNEXPECTED_CONTENT, "unexpected content after document");
6402
6403#undef has_flag
6404#undef val_incr
6405#undef return_err
6406}
6407
6408
6409
6410/*==============================================================================
6411 * JSON Reader Entrance
6412 *============================================================================*/
6413
6414yyjson_doc *yyjson_read_opts(char *dat,
6415 usize len,
6416 yyjson_read_flag flg,
6417 const yyjson_alc *alc_ptr,
6418 yyjson_read_err *err) {
6419
6420#define has_flag(_flag) unlikely((flg & YYJSON_READ_##_flag) != 0)
6421
6422#define return_err(_pos, _code, _msg) do { \
6423 err->pos = (usize)(_pos); \
6424 err->msg = _msg; \
6425 err->code = YYJSON_READ_ERROR_##_code; \
6426 if (!has_flag(INSITU) && hdr) alc.free(alc.ctx, (void *)hdr); \
6427 return NULL; \
6428} while (false)
6429
6430 yyjson_read_err dummy_err;
6431 yyjson_alc alc;
6432 yyjson_doc *doc;
6433 u8 *hdr = NULL, *end, *cur;
6434
6435#if YYJSON_DISABLE_NON_STANDARD
6436 flg &= ~YYJSON_READ_ALLOW_TRAILING_COMMAS;
6437 flg &= ~YYJSON_READ_ALLOW_COMMENTS;
6438 flg &= ~YYJSON_READ_ALLOW_INF_AND_NAN;
6439 flg &= ~YYJSON_READ_ALLOW_INVALID_UNICODE;
6440#endif
6441
6442 /* validate input parameters */
6443 if (!err) err = &dummy_err;
6444 if (likely(!alc_ptr)) {
6445 alc = YYJSON_DEFAULT_ALC;
6446 } else {
6447 alc = *alc_ptr;
6448 }
6449 if (unlikely(!dat)) {
6450 return_err(0, INVALID_PARAMETER, "input data is NULL");
6451 }
6452 if (unlikely(!len)) {
6453 return_err(0, INVALID_PARAMETER, "input length is 0");
6454 }
6455
6456 /* add 4-byte zero padding for input data if necessary */
6457 if (has_flag(INSITU)) {
6458 hdr = (u8 *)dat;
6459 end = (u8 *)dat + len;
6460 cur = (u8 *)dat;
6461 } else {
6462 if (unlikely(len >= USIZE_MAX - YYJSON_PADDING_SIZE)) {
6463 return_err(0, MEMORY_ALLOCATION, "memory allocation failed");
6464 }
6465 hdr = (u8 *)alc.malloc(alc.ctx, len + YYJSON_PADDING_SIZE);
6466 if (unlikely(!hdr)) {
6467 return_err(0, MEMORY_ALLOCATION, "memory allocation failed");
6468 }
6469 end = hdr + len;
6470 cur = hdr;
6471 memcpy(hdr, dat, len);
6472 memset(end, 0, YYJSON_PADDING_SIZE);
6473 }
6474
6475 /* skip empty contents before json document */
6476 if (unlikely(char_is_space_or_comment(*cur))) {
6477 if (has_flag(ALLOW_COMMENTS)) {
6478 if (!skip_spaces_and_comments(&cur)) {
6479 return_err(cur - hdr, INVALID_COMMENT,
6480 "unclosed multiline comment");
6481 }
6482 } else {
6483 if (likely(char_is_space(*cur))) {
6484 while (char_is_space(*++cur));
6485 }
6486 }
6487 if (unlikely(cur >= end)) {
6488 return_err(0, EMPTY_CONTENT, "input data is empty");
6489 }
6490 }
6491
6492 /* read json document */
6493 if (likely(char_is_container(*cur))) {
6494 if (char_is_space(cur[1]) && char_is_space(cur[2])) {
6495 doc = read_root_pretty(hdr, cur, end, alc, flg, err);
6496 } else {
6497 doc = read_root_minify(hdr, cur, end, alc, flg, err);
6498 }
6499 } else {
6500 doc = read_root_single(hdr, cur, end, alc, flg, err);
6501 }
6502
6503 /* check result */
6504 if (likely(doc)) {
6505 memset(err, 0, sizeof(yyjson_read_err));
6506 } else {
6507 /* RFC 8259: JSON text MUST be encoded using UTF-8 */
6508 if (err->pos == 0 && err->code != YYJSON_READ_ERROR_MEMORY_ALLOCATION) {
6509 if ((hdr[0] == 0xEF && hdr[1] == 0xBB && hdr[2] == 0xBF)) {
6510 err->msg = "byte order mark (BOM) is not supported";
6511 } else if (len >= 4 &&
6512 ((hdr[0] == 0x00 && hdr[1] == 0x00 &&
6513 hdr[2] == 0xFE && hdr[3] == 0xFF) ||
6514 (hdr[0] == 0xFF && hdr[1] == 0xFE &&
6515 hdr[2] == 0x00 && hdr[3] == 0x00))) {
6516 err->msg = "UTF-32 encoding is not supported";
6517 } else if (len >= 2 &&
6518 ((hdr[0] == 0xFE && hdr[1] == 0xFF) ||
6519 (hdr[0] == 0xFF && hdr[1] == 0xFE))) {
6520 err->msg = "UTF-16 encoding is not supported";
6521 }
6522 }
6523 if (!has_flag(INSITU)) alc.free(alc.ctx, (void *)hdr);
6524 }
6525 return doc;
6526
6527#undef has_flag
6528#undef return_err
6529}
6530
6531yyjson_doc *yyjson_read_file(const char *path,
6532 yyjson_read_flag flg,
6533 const yyjson_alc *alc_ptr,
6534 yyjson_read_err *err) {
6535#define return_err(_code, _msg) do { \
6536 err->pos = 0; \
6537 err->msg = _msg; \
6538 err->code = YYJSON_READ_ERROR_##_code; \
6539 return NULL; \
6540} while (false)
6541
6542 yyjson_read_err dummy_err;
6543 yyjson_doc *doc;
6544 FILE *file;
6545
6546 if (!err) err = &dummy_err;
6547 if (unlikely(!path)) return_err(INVALID_PARAMETER, "input path is NULL");
6548
6549 file = fopen_readonly(path);
6550 if (unlikely(!file)) return_err(FILE_OPEN, "file opening failed");
6551
6552 doc = yyjson_read_fp(file, flg, alc_ptr, err);
6553 fclose(file);
6554 return doc;
6555
6556#undef return_err
6557}
6558
6559yyjson_doc *yyjson_read_fp(FILE *file,
6560 yyjson_read_flag flg,
6561 const yyjson_alc *alc_ptr,
6562 yyjson_read_err *err) {
6563#define return_err(_code, _msg) do { \
6564 err->pos = 0; \
6565 err->msg = _msg; \
6566 err->code = YYJSON_READ_ERROR_##_code; \
6567 if (buf) alc.free(alc.ctx, buf); \
6568 return NULL; \
6569} while (false)
6570
6571 yyjson_read_err dummy_err;
6572 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
6573 yyjson_doc *doc;
6574
6575 long file_size = 0, file_pos;
6576 void *buf = NULL;
6577 usize buf_size = 0;
6578
6579 /* validate input parameters */
6580 if (!err) err = &dummy_err;
6581 if (unlikely(!file)) return_err(INVALID_PARAMETER, "input file is NULL");
6582
6583 /* get current position */
6584 file_pos = ftell(file);
6585 if (file_pos != -1) {
6586 /* get total file size, may fail */
6587 if (fseek(file, 0, SEEK_END) == 0) file_size = ftell(file);
6588 /* reset to original position, may fail */
6589 if (fseek(file, file_pos, SEEK_SET) != 0) file_size = 0;
6590 /* get file size from current postion to end */
6591 if (file_size > 0) file_size -= file_pos;
6592 }
6593
6594 /* read file */
6595 if (file_size > 0) {
6596 /* read the entire file in one call */
6597 buf_size = (usize)file_size + YYJSON_PADDING_SIZE;
6598 buf = alc.malloc(alc.ctx, buf_size);
6599 if (buf == NULL) {
6600 return_err(MEMORY_ALLOCATION, "fail to alloc memory");
6601 }
6602 if (fread_safe(buf, (usize)file_size, file) != (usize)file_size) {
6603 return_err(FILE_READ, "file reading failed");
6604 }
6605 } else {
6606 /* failed to get file size, read it as a stream */
6607 usize chunk_min = (usize)64;
6608 usize chunk_max = (usize)512 * 1024 * 1024;
6609 usize chunk_now = chunk_min;
6610 usize read_size;
6611 void *tmp;
6612
6613 buf_size = YYJSON_PADDING_SIZE;
6614 while (true) {
6615 if (buf_size + chunk_now < buf_size) { /* overflow */
6616 return_err(MEMORY_ALLOCATION, "fail to alloc memory");
6617 }
6618 buf_size += chunk_now;
6619 if (!buf) {
6620 buf = alc.malloc(alc.ctx, buf_size);
6621 if (!buf) return_err(MEMORY_ALLOCATION, "fail to alloc memory");
6622 } else {
6623 tmp = alc.realloc(alc.ctx, buf, buf_size - chunk_now, buf_size);
6624 if (!tmp) return_err(MEMORY_ALLOCATION, "fail to alloc memory");
6625 buf = tmp;
6626 }
6627 tmp = ((u8 *)buf) + buf_size - YYJSON_PADDING_SIZE - chunk_now;
6628 read_size = fread_safe(tmp, chunk_now, file);
6629 file_size += (long)read_size;
6630 if (read_size != chunk_now) break;
6631
6632 chunk_now *= 2;
6633 if (chunk_now > chunk_max) chunk_now = chunk_max;
6634 }
6635 }
6636
6637 /* read JSON */
6638 memset((u8 *)buf + file_size, 0, YYJSON_PADDING_SIZE);
6639 flg |= YYJSON_READ_INSITU;
6640 doc = yyjson_read_opts((char *)buf, (usize)file_size, flg, &alc, err);
6641 if (doc) {
6642 doc->str_pool = (char *)buf;
6643 return doc;
6644 } else {
6645 alc.free(alc.ctx, buf);
6646 return NULL;
6647 }
6648
6649#undef return_err
6650}
6651
6652const char *yyjson_read_number(const char *dat,
6653 yyjson_val *val,
6654 yyjson_read_flag flg,
6655 const yyjson_alc *alc,
6656 yyjson_read_err *err) {
6657#define return_err(_pos, _code, _msg) do { \
6658 err->pos = _pos > hdr ? (usize)(_pos - hdr) : 0; \
6659 err->msg = _msg; \
6660 err->code = YYJSON_READ_ERROR_##_code; \
6661 return NULL; \
6662} while (false)
6663
6664 u8 *hdr = constcast(u8 *)dat, *cur = hdr;
6665 bool raw; /* read number as raw */
6666 u8 *raw_end; /* raw end for null-terminator */
6667 u8 **pre; /* previous raw end pointer */
6668 const char *msg;
6669 yyjson_read_err dummy_err;
6670
6671#if !YYJSON_HAS_IEEE_754 || YYJSON_DISABLE_FAST_FP_CONV
6672 u8 buf[128];
6673 usize dat_len;
6674#endif
6675
6676 if (!err) err = &dummy_err;
6677 if (unlikely(!dat)) {
6678 return_err(cur, INVALID_PARAMETER, "input data is NULL");
6679 }
6680 if (unlikely(!val)) {
6681 return_err(cur, INVALID_PARAMETER, "output value is NULL");
6682 }
6683
6684#if !YYJSON_HAS_IEEE_754 || YYJSON_DISABLE_FAST_FP_CONV
6685 if (!alc) alc = &YYJSON_DEFAULT_ALC;
6686 dat_len = strlen(dat);
6687 if (dat_len < sizeof(buf)) {
6688 memcpy(buf, dat, dat_len + 1);
6689 hdr = buf;
6690 cur = hdr;
6691 } else {
6692 hdr = (u8 *)alc->malloc(alc->ctx, dat_len + 1);
6693 cur = hdr;
6694 if (unlikely(!hdr)) {
6695 return_err(cur, MEMORY_ALLOCATION, "memory allocation failed");
6696 }
6697 memcpy(hdr, dat, dat_len + 1);
6698 }
6699 hdr[dat_len] = 0;
6700#endif
6701
6702#if YYJSON_DISABLE_NON_STANDARD
6703 flg &= ~YYJSON_READ_ALLOW_INF_AND_NAN;
6704#endif
6705
6706 raw = (flg & (YYJSON_READ_NUMBER_AS_RAW | YYJSON_READ_BIGNUM_AS_RAW)) != 0;
6707 raw_end = NULL;
6708 pre = raw ? &raw_end : NULL;
6709
6710#if !YYJSON_HAS_IEEE_754 || YYJSON_DISABLE_FAST_FP_CONV
6711 if (!read_number(&cur, pre, flg, val, &msg)) {
6712 if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr);
6713 return_err(cur, INVALID_NUMBER, msg);
6714 }
6715 if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr);
6716 if (yyjson_is_raw(val)) val->uni.str = dat;
6717 return dat + (cur - hdr);
6718#else
6719 if (!read_number(&cur, pre, flg, val, &msg)) {
6720 return_err(cur, INVALID_NUMBER, msg);
6721 }
6722 return (const char *)cur;
6723#endif
6724
6725#undef return_err
6726}
6727
6728#endif /* YYJSON_DISABLE_READER */
6729
6730
6731
6732#if !YYJSON_DISABLE_WRITER
6733
6734/*==============================================================================
6735 * Integer Writer
6736 *
6737 * The maximum value of uint32_t is 4294967295 (10 digits),
6738 * these digits are named as 'aabbccddee' here.
6739 *
6740 * Although most compilers may convert the "division by constant value" into
6741 * "multiply and shift", manual conversion can still help some compilers
6742 * generate fewer and better instructions.
6743 *
6744 * Reference:
6745 * Division by Invariant Integers using Multiplication, 1994.
6746 * https://gmplib.org/~tege/divcnst-pldi94.pdf
6747 * Improved division by invariant integers, 2011.
6748 * https://gmplib.org/~tege/division-paper.pdf
6749 *============================================================================*/
6750
6751/** Digit table from 00 to 99. */
6752yyjson_align(2)
6753static const char digit_table[200] = {
6754 '0', '0', '0', '1', '0', '2', '0', '3', '0', '4',
6755 '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
6756 '1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
6757 '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
6758 '2', '0', '2', '1', '2', '2', '2', '3', '2', '4',
6759 '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
6760 '3', '0', '3', '1', '3', '2', '3', '3', '3', '4',
6761 '3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
6762 '4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
6763 '4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
6764 '5', '0', '5', '1', '5', '2', '5', '3', '5', '4',
6765 '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
6766 '6', '0', '6', '1', '6', '2', '6', '3', '6', '4',
6767 '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
6768 '7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
6769 '7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
6770 '8', '0', '8', '1', '8', '2', '8', '3', '8', '4',
6771 '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
6772 '9', '0', '9', '1', '9', '2', '9', '3', '9', '4',
6773 '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'
6774};
6775
6776static_inline u8 *write_u32_len_8(u32 val, u8 *buf) {
6777 u32 aa, bb, cc, dd, aabb, ccdd; /* 8 digits: aabbccdd */
6778 aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
6779 ccdd = val - aabb * 10000; /* (val % 10000) */
6780 aa = (aabb * 5243) >> 19; /* (aabb / 100) */
6781 cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */
6782 bb = aabb - aa * 100; /* (aabb % 100) */
6783 dd = ccdd - cc * 100; /* (ccdd % 100) */
6784 byte_copy_2(buf + 0, digit_table + aa * 2);
6785 byte_copy_2(buf + 2, digit_table + bb * 2);
6786 byte_copy_2(buf + 4, digit_table + cc * 2);
6787 byte_copy_2(buf + 6, digit_table + dd * 2);
6788 return buf + 8;
6789}
6790
6791static_inline u8 *write_u32_len_4(u32 val, u8 *buf) {
6792 u32 aa, bb; /* 4 digits: aabb */
6793 aa = (val * 5243) >> 19; /* (val / 100) */
6794 bb = val - aa * 100; /* (val % 100) */
6795 byte_copy_2(buf + 0, digit_table + aa * 2);
6796 byte_copy_2(buf + 2, digit_table + bb * 2);
6797 return buf + 4;
6798}
6799
6800static_inline u8 *write_u32_len_1_8(u32 val, u8 *buf) {
6801 u32 aa, bb, cc, dd, aabb, bbcc, ccdd, lz;
6802
6803 if (val < 100) { /* 1-2 digits: aa */
6804 lz = val < 10; /* leading zero: 0 or 1 */
6805 byte_copy_2(buf + 0, digit_table + val * 2 + lz);
6806 buf -= lz;
6807 return buf + 2;
6808
6809 } else if (val < 10000) { /* 3-4 digits: aabb */
6810 aa = (val * 5243) >> 19; /* (val / 100) */
6811 bb = val - aa * 100; /* (val % 100) */
6812 lz = aa < 10; /* leading zero: 0 or 1 */
6813 byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
6814 buf -= lz;
6815 byte_copy_2(buf + 2, digit_table + bb * 2);
6816 return buf + 4;
6817
6818 } else if (val < 1000000) { /* 5-6 digits: aabbcc */
6819 aa = (u32)(((u64)val * 429497) >> 32); /* (val / 10000) */
6820 bbcc = val - aa * 10000; /* (val % 10000) */
6821 bb = (bbcc * 5243) >> 19; /* (bbcc / 100) */
6822 cc = bbcc - bb * 100; /* (bbcc % 100) */
6823 lz = aa < 10; /* leading zero: 0 or 1 */
6824 byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
6825 buf -= lz;
6826 byte_copy_2(buf + 2, digit_table + bb * 2);
6827 byte_copy_2(buf + 4, digit_table + cc * 2);
6828 return buf + 6;
6829
6830 } else { /* 7-8 digits: aabbccdd */
6831 aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
6832 ccdd = val - aabb * 10000; /* (val % 10000) */
6833 aa = (aabb * 5243) >> 19; /* (aabb / 100) */
6834 cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */
6835 bb = aabb - aa * 100; /* (aabb % 100) */
6836 dd = ccdd - cc * 100; /* (ccdd % 100) */
6837 lz = aa < 10; /* leading zero: 0 or 1 */
6838 byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
6839 buf -= lz;
6840 byte_copy_2(buf + 2, digit_table + bb * 2);
6841 byte_copy_2(buf + 4, digit_table + cc * 2);
6842 byte_copy_2(buf + 6, digit_table + dd * 2);
6843 return buf + 8;
6844 }
6845}
6846
6847static_inline u8 *write_u64_len_5_8(u32 val, u8 *buf) {
6848 u32 aa, bb, cc, dd, aabb, bbcc, ccdd, lz;
6849
6850 if (val < 1000000) { /* 5-6 digits: aabbcc */
6851 aa = (u32)(((u64)val * 429497) >> 32); /* (val / 10000) */
6852 bbcc = val - aa * 10000; /* (val % 10000) */
6853 bb = (bbcc * 5243) >> 19; /* (bbcc / 100) */
6854 cc = bbcc - bb * 100; /* (bbcc % 100) */
6855 lz = aa < 10; /* leading zero: 0 or 1 */
6856 byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
6857 buf -= lz;
6858 byte_copy_2(buf + 2, digit_table + bb * 2);
6859 byte_copy_2(buf + 4, digit_table + cc * 2);
6860 return buf + 6;
6861
6862 } else { /* 7-8 digits: aabbccdd */
6863 aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
6864 ccdd = val - aabb * 10000; /* (val % 10000) */
6865 aa = (aabb * 5243) >> 19; /* (aabb / 100) */
6866 cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */
6867 bb = aabb - aa * 100; /* (aabb % 100) */
6868 dd = ccdd - cc * 100; /* (ccdd % 100) */
6869 lz = aa < 10; /* leading zero: 0 or 1 */
6870 byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
6871 buf -= lz;
6872 byte_copy_2(buf + 2, digit_table + bb * 2);
6873 byte_copy_2(buf + 4, digit_table + cc * 2);
6874 byte_copy_2(buf + 6, digit_table + dd * 2);
6875 return buf + 8;
6876 }
6877}
6878
6879static_inline u8 *write_u64(u64 val, u8 *buf) {
6880 u64 tmp, hgh;
6881 u32 mid, low;
6882
6883 if (val < 100000000) { /* 1-8 digits */
6884 buf = write_u32_len_1_8((u32)val, buf);
6885 return buf;
6886
6887 } else if (val < (u64)100000000 * 100000000) { /* 9-16 digits */
6888 hgh = val / 100000000; /* (val / 100000000) */
6889 low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
6890 buf = write_u32_len_1_8((u32)hgh, buf);
6891 buf = write_u32_len_8(low, buf);
6892 return buf;
6893
6894 } else { /* 17-20 digits */
6895 tmp = val / 100000000; /* (val / 100000000) */
6896 low = (u32)(val - tmp * 100000000); /* (val % 100000000) */
6897 hgh = (u32)(tmp / 10000); /* (tmp / 10000) */
6898 mid = (u32)(tmp - hgh * 10000); /* (tmp % 10000) */
6899 buf = write_u64_len_5_8((u32)hgh, buf);
6900 buf = write_u32_len_4(mid, buf);
6901 buf = write_u32_len_8(low, buf);
6902 return buf;
6903 }
6904}
6905
6906
6907
6908/*==============================================================================
6909 * Number Writer
6910 *============================================================================*/
6911
6912#if YYJSON_HAS_IEEE_754 && !YYJSON_DISABLE_FAST_FP_CONV /* FP_WRITER */
6913
6914/** Trailing zero count table for number 0 to 99.
6915 (generate with misc/make_tables.c) */
6916static const u8 dec_trailing_zero_table[] = {
6917 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6918 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6919 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6920 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6921 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6922 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6923 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6924 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6925 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6926 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
6927};
6928
6929/** Write an unsigned integer with a length of 1 to 16. */
6930static_inline u8 *write_u64_len_1_to_16(u64 val, u8 *buf) {
6931 u64 hgh;
6932 u32 low;
6933 if (val < 100000000) { /* 1-8 digits */
6934 buf = write_u32_len_1_8((u32)val, buf);
6935 return buf;
6936 } else { /* 9-16 digits */
6937 hgh = val / 100000000; /* (val / 100000000) */
6938 low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
6939 buf = write_u32_len_1_8((u32)hgh, buf);
6940 buf = write_u32_len_8(low, buf);
6941 return buf;
6942 }
6943}
6944
6945/** Write an unsigned integer with a length of 1 to 17. */
6946static_inline u8 *write_u64_len_1_to_17(u64 val, u8 *buf) {
6947 u64 hgh;
6948 u32 mid, low, one;
6949 if (val >= (u64)100000000 * 10000000) { /* len: 16 to 17 */
6950 hgh = val / 100000000; /* (val / 100000000) */
6951 low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
6952 one = (u32)(hgh / 100000000); /* (hgh / 100000000) */
6953 mid = (u32)(hgh - (u64)one * 100000000); /* (hgh % 100000000) */
6954 *buf = (u8)((u8)one + (u8)'0');
6955 buf += one > 0;
6956 buf = write_u32_len_8(mid, buf);
6957 buf = write_u32_len_8(low, buf);
6958 return buf;
6959 } else if (val >= (u64)100000000){ /* len: 9 to 15 */
6960 hgh = val / 100000000; /* (val / 100000000) */
6961 low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
6962 buf = write_u32_len_1_8((u32)hgh, buf);
6963 buf = write_u32_len_8(low, buf);
6964 return buf;
6965 } else { /* len: 1 to 8 */
6966 buf = write_u32_len_1_8((u32)val, buf);
6967 return buf;
6968 }
6969}
6970
6971/**
6972 Write an unsigned integer with a length of 15 to 17 with trailing zero trimmed.
6973 These digits are named as "aabbccddeeffgghhii" here.
6974 For example, input 1234567890123000, output "1234567890123".
6975 */
6976static_inline u8 *write_u64_len_15_to_17_trim(u8 *buf, u64 sig) {
6977 bool lz; /* leading zero */
6978 u32 tz1, tz2, tz; /* trailing zero */
6979
6980 u32 abbccddee = (u32)(sig / 100000000);
6981 u32 ffgghhii = (u32)(sig - (u64)abbccddee * 100000000);
6982 u32 abbcc = abbccddee / 10000; /* (abbccddee / 10000) */
6983 u32 ddee = abbccddee - abbcc * 10000; /* (abbccddee % 10000) */
6984 u32 abb = (u32)(((u64)abbcc * 167773) >> 24); /* (abbcc / 100) */
6985 u32 a = (abb * 41) >> 12; /* (abb / 100) */
6986 u32 bb = abb - a * 100; /* (abb % 100) */
6987 u32 cc = abbcc - abb * 100; /* (abbcc % 100) */
6988
6989 /* write abbcc */
6990 buf[0] = (u8)(a + '0');
6991 buf += a > 0;
6992 lz = bb < 10 && a == 0;
6993 byte_copy_2(buf + 0, digit_table + bb * 2 + lz);
6994 buf -= lz;
6995 byte_copy_2(buf + 2, digit_table + cc * 2);
6996
6997 if (ffgghhii) {
6998 u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */
6999 u32 ee = ddee - dd * 100; /* (ddee % 100) */
7000 u32 ffgg = (u32)(((u64)ffgghhii * 109951163) >> 40); /* (val / 10000) */
7001 u32 hhii = ffgghhii - ffgg * 10000; /* (val % 10000) */
7002 u32 ff = (ffgg * 5243) >> 19; /* (aabb / 100) */
7003 u32 gg = ffgg - ff * 100; /* (aabb % 100) */
7004 byte_copy_2(buf + 4, digit_table + dd * 2);
7005 byte_copy_2(buf + 6, digit_table + ee * 2);
7006 byte_copy_2(buf + 8, digit_table + ff * 2);
7007 byte_copy_2(buf + 10, digit_table + gg * 2);
7008 if (hhii) {
7009 u32 hh = (hhii * 5243) >> 19; /* (ccdd / 100) */
7010 u32 ii = hhii - hh * 100; /* (ccdd % 100) */
7011 byte_copy_2(buf + 12, digit_table + hh * 2);
7012 byte_copy_2(buf + 14, digit_table + ii * 2);
7013 tz1 = dec_trailing_zero_table[hh];
7014 tz2 = dec_trailing_zero_table[ii];
7015 tz = ii ? tz2 : (tz1 + 2);
7016 buf += 16 - tz;
7017 return buf;
7018 } else {
7019 tz1 = dec_trailing_zero_table[ff];
7020 tz2 = dec_trailing_zero_table[gg];
7021 tz = gg ? tz2 : (tz1 + 2);
7022 buf += 12 - tz;
7023 return buf;
7024 }
7025 } else {
7026 if (ddee) {
7027 u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */
7028 u32 ee = ddee - dd * 100; /* (ddee % 100) */
7029 byte_copy_2(buf + 4, digit_table + dd * 2);
7030 byte_copy_2(buf + 6, digit_table + ee * 2);
7031 tz1 = dec_trailing_zero_table[dd];
7032 tz2 = dec_trailing_zero_table[ee];
7033 tz = ee ? tz2 : (tz1 + 2);
7034 buf += 8 - tz;
7035 return buf;
7036 } else {
7037 tz1 = dec_trailing_zero_table[bb];
7038 tz2 = dec_trailing_zero_table[cc];
7039 tz = cc ? tz2 : (tz1 + tz2);
7040 buf += 4 - tz;
7041 return buf;
7042 }
7043 }
7044}
7045
7046/** Write a signed integer in the range -324 to 308. */
7047static_inline u8 *write_f64_exp(i32 exp, u8 *buf) {
7048 buf[0] = '-';
7049 buf += exp < 0;
7050 exp = exp < 0 ? -exp : exp;
7051 if (exp < 100) {
7052 u32 lz = exp < 10;
7053 byte_copy_2(buf + 0, digit_table + (u32)exp * 2 + lz);
7054 return buf + 2 - lz;
7055 } else {
7056 u32 hi = ((u32)exp * 656) >> 16; /* exp / 100 */
7057 u32 lo = (u32)exp - hi * 100; /* exp % 100 */
7058 buf[0] = (u8)((u8)hi + (u8)'0');
7059 byte_copy_2(buf + 1, digit_table + lo * 2);
7060 return buf + 3;
7061 }
7062}
7063
7064/** Multiplies 128-bit integer and returns highest 64-bit rounded value. */
7065static_inline u64 round_to_odd(u64 hi, u64 lo, u64 cp) {
7066 u64 x_hi, x_lo, y_hi, y_lo;
7067 u128_mul(cp, lo, &x_hi, &x_lo);
7068 u128_mul_add(cp, hi, x_hi, &y_hi, &y_lo);
7069 return y_hi | (y_lo > 1);
7070}
7071
7072/**
7073 Convert double number from binary to decimal.
7074 The output significand is shortest decimal but may have trailing zeros.
7075
7076 This function use the Schubfach algorithm:
7077 Raffaello Giulietti, The Schubfach way to render doubles (5th version), 2022.
7078 https://drive.google.com/file/d/1gp5xv4CAa78SVgCeWfGqqI4FfYYYuNFb
7079 https://mail.openjdk.java.net/pipermail/core-libs-dev/2021-November/083536.html
7080 https://github.com/openjdk/jdk/pull/3402 (Java implementation)
7081 https://github.com/abolz/Drachennest (C++ implementation)
7082
7083 See also:
7084 Dragonbox: A New Floating-Point Binary-to-Decimal Conversion Algorithm, 2022.
7085 https://github.com/jk-jeon/dragonbox/blob/master/other_files/Dragonbox.pdf
7086 https://github.com/jk-jeon/dragonbox
7087
7088 @param sig_raw The raw value of significand in IEEE 754 format.
7089 @param exp_raw The raw value of exponent in IEEE 754 format.
7090 @param sig_bin The decoded value of significand in binary.
7091 @param exp_bin The decoded value of exponent in binary.
7092 @param sig_dec The output value of significand in decimal.
7093 @param exp_dec The output value of exponent in decimal.
7094 @warning The input double number should not be 0, inf, nan.
7095 */
7096static_inline void f64_bin_to_dec(u64 sig_raw, u32 exp_raw,
7097 u64 sig_bin, i32 exp_bin,
7098 u64 *sig_dec, i32 *exp_dec) {
7099
7100 bool is_even, regular_spacing, u_inside, w_inside, round_up;
7101 u64 s, sp, cb, cbl, cbr, vb, vbl, vbr, pow10hi, pow10lo, upper, lower, mid;
7102 i32 k, h, exp10;
7103
7104 is_even = !(sig_bin & 1);
7105 regular_spacing = (sig_raw == 0 && exp_raw > 1);
7106
7107 cbl = 4 * sig_bin - 2 + regular_spacing;
7108 cb = 4 * sig_bin;
7109 cbr = 4 * sig_bin + 2;
7110
7111 /* exp_bin: [-1074, 971] */
7112 /* k = regular_spacing ? floor(log10(pow(2, exp_bin))) */
7113 /* : floor(log10(pow(2, exp_bin) * 3.0 / 4.0)) */
7114 /* = regular_spacing ? floor(exp_bin * log10(2)) */
7115 /* : floor(exp_bin * log10(2) + log10(3.0 / 4.0)) */
7116 k = (i32)(exp_bin * 315653 - (regular_spacing ? 131237 : 0)) >> 20;
7117
7118 /* k: [-324, 292] */
7119 /* h = exp_bin + floor(log2(pow(10, e))) */
7120 /* = exp_bin + floor(log2(10) * e) */
7121 exp10 = -k;
7122 h = exp_bin + ((exp10 * 217707) >> 16) + 1;
7123
7124 pow10_table_get_sig(exp10, &pow10hi, &pow10lo);
7125 pow10lo += (exp10 < POW10_SIG_TABLE_MIN_EXACT_EXP ||
7126 exp10 > POW10_SIG_TABLE_MAX_EXACT_EXP);
7127 vbl = round_to_odd(pow10hi, pow10lo, cbl << h);
7128 vb = round_to_odd(pow10hi, pow10lo, cb << h);
7129 vbr = round_to_odd(pow10hi, pow10lo, cbr << h);
7130
7131 lower = vbl + !is_even;
7132 upper = vbr - !is_even;
7133
7134 s = vb / 4;
7135 if (s >= 10) {
7136 sp = s / 10;
7137 u_inside = (lower <= 40 * sp);
7138 w_inside = (upper >= 40 * sp + 40);
7139 if (u_inside != w_inside) {
7140 *sig_dec = sp + w_inside;
7141 *exp_dec = k + 1;
7142 return;
7143 }
7144 }
7145
7146 u_inside = (lower <= 4 * s);
7147 w_inside = (upper >= 4 * s + 4);
7148
7149 mid = 4 * s + 2;
7150 round_up = (vb > mid) || (vb == mid && (s & 1) != 0);
7151
7152 *sig_dec = s + ((u_inside != w_inside) ? w_inside : round_up);
7153 *exp_dec = k;
7154}
7155
7156/**
7157 Write a double number (requires 32 bytes buffer).
7158
7159 We follows the ECMAScript specification to print floating point numbers,
7160 but with the following changes:
7161 1. Keep the negative sign of 0.0 to preserve input information.
7162 2. Keep decimal point to indicate the number is floating point.
7163 3. Remove positive sign of exponent part.
7164 */
7165static_inline u8 *write_f64_raw(u8 *buf, u64 raw, yyjson_write_flag flg) {
7166 u64 sig_bin, sig_dec, sig_raw;
7167 i32 exp_bin, exp_dec, sig_len, dot_pos, i, max;
7168 u32 exp_raw, hi, lo;
7169 u8 *hdr, *num_hdr, *num_end, *dot_end;
7170 bool sign;
7171
7172 /* decode raw bytes from IEEE-754 double format. */
7173 sign = (bool)(raw >> (F64_BITS - 1));
7174 sig_raw = raw & F64_SIG_MASK;
7175 exp_raw = (u32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
7176
7177 /* return inf and nan */
7178 if (unlikely(exp_raw == ((u32)1 << F64_EXP_BITS) - 1)) {
7179 if (flg & YYJSON_WRITE_INF_AND_NAN_AS_NULL) {
7180 byte_copy_4(buf, "null");
7181 return buf + 4;
7182 } else if (flg & YYJSON_WRITE_ALLOW_INF_AND_NAN) {
7183 if (sig_raw == 0) {
7184 buf[0] = '-';
7185 buf += sign;
7186 byte_copy_8(buf, "Infinity");
7187 buf += 8;
7188 return buf;
7189 } else {
7190 byte_copy_4(buf, "NaN");
7191 return buf + 3;
7192 }
7193 } else {
7194 return NULL;
7195 }
7196 }
7197
7198 /* add sign for all finite double value, including 0.0 and inf */
7199 buf[0] = '-';
7200 buf += sign;
7201 hdr = buf;
7202
7203 /* return zero */
7204 if ((raw << 1) == 0) {
7205 byte_copy_4(buf, "0.0");
7206 buf += 3;
7207 return buf;
7208 }
7209
7210 if (likely(exp_raw != 0)) {
7211 /* normal number */
7212 sig_bin = sig_raw | ((u64)1 << F64_SIG_BITS);
7213 exp_bin = (i32)exp_raw - F64_EXP_BIAS - F64_SIG_BITS;
7214
7215 /* fast path for small integer number without fraction */
7216 if (-F64_SIG_BITS <= exp_bin && exp_bin <= 0) {
7217 if (u64_tz_bits(sig_bin) >= (u32)-exp_bin) {
7218 /* number is integer in range 1 to 0x1FFFFFFFFFFFFF */
7219 sig_dec = sig_bin >> -exp_bin;
7220 buf = write_u64_len_1_to_16(sig_dec, buf);
7221 byte_copy_2(buf, ".0");
7222 buf += 2;
7223 return buf;
7224 }
7225 }
7226
7227 /* binary to decimal */
7228 f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
7229
7230 /* the sig length is 15 to 17 */
7231 sig_len = 17;
7232 sig_len -= (sig_dec < (u64)100000000 * 100000000);
7233 sig_len -= (sig_dec < (u64)100000000 * 10000000);
7234
7235 /* the decimal point position relative to the first digit */
7236 dot_pos = sig_len + exp_dec;
7237
7238 if (-6 < dot_pos && dot_pos <= 21) {
7239 /* no need to write exponent part */
7240 if (dot_pos <= 0) {
7241 /* dot before first digit */
7242 /* such as 0.1234, 0.000001234 */
7243 num_hdr = hdr + (2 - dot_pos);
7244 num_end = write_u64_len_15_to_17_trim(num_hdr, sig_dec);
7245 hdr[0] = '0';
7246 hdr[1] = '.';
7247 hdr += 2;
7248 max = -dot_pos;
7249 for (i = 0; i < max; i++) hdr[i] = '0';
7250 return num_end;
7251 } else {
7252 /* dot after first digit */
7253 /* such as 1.234, 1234.0, 123400000000000000000.0 */
7254 memset(hdr + 0, '0', 8);
7255 memset(hdr + 8, '0', 8);
7256 memset(hdr + 16, '0', 8);
7257 num_hdr = hdr + 1;
7258 num_end = write_u64_len_15_to_17_trim(num_hdr, sig_dec);
7259 for (i = 0; i < dot_pos; i++) hdr[i] = hdr[i + 1];
7260 hdr[dot_pos] = '.';
7261 dot_end = hdr + dot_pos + 2;
7262 return dot_end < num_end ? num_end : dot_end;
7263 }
7264 } else {
7265 /* write with scientific notation */
7266 /* such as 1.234e56 */
7267 u8 *end = write_u64_len_15_to_17_trim(buf + 1, sig_dec);
7268 end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */
7269 exp_dec += sig_len - 1;
7270 hdr[0] = hdr[1];
7271 hdr[1] = '.';
7272 end[0] = 'e';
7273 buf = write_f64_exp(exp_dec, end + 1);
7274 return buf;
7275 }
7276
7277 } else {
7278 /* subnormal number */
7279 sig_bin = sig_raw;
7280 exp_bin = 1 - F64_EXP_BIAS - F64_SIG_BITS;
7281
7282 /* binary to decimal */
7283 f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
7284
7285 /* write significand part */
7286 buf = write_u64_len_1_to_17(sig_dec, buf + 1);
7287 hdr[0] = hdr[1];
7288 hdr[1] = '.';
7289 do {
7290 buf--;
7291 exp_dec++;
7292 } while (*buf == '0');
7293 exp_dec += (i32)(buf - hdr - 2);
7294 buf += (*buf != '.');
7295 buf[0] = 'e';
7296 buf++;
7297
7298 /* write exponent part */
7299 buf[0] = '-';
7300 buf++;
7301 exp_dec = -exp_dec;
7302 hi = ((u32)exp_dec * 656) >> 16; /* exp / 100 */
7303 lo = (u32)exp_dec - hi * 100; /* exp % 100 */
7304 buf[0] = (u8)((u8)hi + (u8)'0');
7305 byte_copy_2(buf + 1, digit_table + lo * 2);
7306 buf += 3;
7307 return buf;
7308 }
7309}
7310
7311#else /* FP_WRITER */
7312
7313/** Write a double number (requires 32 bytes buffer). */
7314static_inline u8 *write_f64_raw(u8 *buf, u64 raw, yyjson_write_flag flg) {
7315 /*
7316 For IEEE 754, `DBL_DECIMAL_DIG` is 17 for round-trip.
7317 For non-IEEE formats, 17 is used to avoid buffer overflow,
7318 round-trip is not guaranteed.
7319 */
7320#if defined(DBL_DECIMAL_DIG) && DBL_DECIMAL_DIG != 17
7321 int dig = DBL_DECIMAL_DIG > 17 ? 17 : DBL_DECIMAL_DIG;
7322#else
7323 int dig = 17;
7324#endif
7325
7326 /*
7327 The snprintf() function is locale-dependent. For currently known locales,
7328 (en, zh, ja, ko, am, he, hi) use '.' as the decimal point, while other
7329 locales use ',' as the decimal point. we need to replace ',' with '.'
7330 to avoid the locale setting.
7331 */
7332 f64 val = f64_from_raw(raw);
7333#if YYJSON_MSC_VER >= 1400
7334 int len = sprintf_s((char *)buf, 32, "%.*g", dig, val);
7335#elif defined(snprintf) || (YYJSON_STDC_VER >= 199901L)
7336 int len = snprintf((char *)buf, 32, "%.*g", dig, val);
7337#else
7338 int len = sprintf((char *)buf, "%.*g", dig, val);
7339#endif
7340
7341 u8 *cur = buf;
7342 if (unlikely(len < 1)) return NULL;
7343 cur += (*cur == '-');
7344 if (unlikely(!digi_is_digit(*cur))) {
7345 /* nan, inf, or bad output */
7346 if (flg & YYJSON_WRITE_INF_AND_NAN_AS_NULL) {
7347 byte_copy_4(buf, "null");
7348 return buf + 4;
7349 } else if (flg & YYJSON_WRITE_ALLOW_INF_AND_NAN) {
7350 if (*cur == 'i') {
7351 byte_copy_8(cur, "Infinity");
7352 cur += 8;
7353 return cur;
7354 } else if (*cur == 'n') {
7355 byte_copy_4(buf, "NaN");
7356 return buf + 3;
7357 }
7358 }
7359 return NULL;
7360 } else {
7361 /* finite number */
7362 int i = 0;
7363 bool fp = false;
7364 for (; i < len; i++) {
7365 if (buf[i] == ',') buf[i] = '.';
7366 if (digi_is_fp((u8)buf[i])) fp = true;
7367 }
7368 if (!fp) {
7369 buf[len++] = '.';
7370 buf[len++] = '0';
7371 }
7372 }
7373 return buf + len;
7374}
7375
7376#endif /* FP_WRITER */
7377
7378/** Write a JSON number (requires 32 bytes buffer). */
7379static_inline u8 *write_number(u8 *cur, yyjson_val *val,
7380 yyjson_write_flag flg) {
7381 if (val->tag & YYJSON_SUBTYPE_REAL) {
7382 u64 raw = val->uni.u64;
7383 return write_f64_raw(cur, raw, flg);
7384 } else {
7385 u64 pos = val->uni.u64;
7386 u64 neg = ~pos + 1;
7387 usize sgn = ((val->tag & YYJSON_SUBTYPE_SINT) > 0) & ((i64)pos < 0);
7388 *cur = '-';
7389 return write_u64(sgn ? neg : pos, cur + sgn);
7390 }
7391}
7392
7393
7394
7395/*==============================================================================
7396 * String Writer
7397 *============================================================================*/
7398
7399/** Character encode type, if (type > CHAR_ENC_ERR_1) bytes = type / 2; */
7400typedef u8 char_enc_type;
7401#define CHAR_ENC_CPY_1 0 /* 1-byte UTF-8, copy. */
7402#define CHAR_ENC_ERR_1 1 /* 1-byte UTF-8, error. */
7403#define CHAR_ENC_ESC_A 2 /* 1-byte ASCII, escaped as '\x'. */
7404#define CHAR_ENC_ESC_1 3 /* 1-byte UTF-8, escaped as '\uXXXX'. */
7405#define CHAR_ENC_CPY_2 4 /* 2-byte UTF-8, copy. */
7406#define CHAR_ENC_ESC_2 5 /* 2-byte UTF-8, escaped as '\uXXXX'. */
7407#define CHAR_ENC_CPY_3 6 /* 3-byte UTF-8, copy. */
7408#define CHAR_ENC_ESC_3 7 /* 3-byte UTF-8, escaped as '\uXXXX'. */
7409#define CHAR_ENC_CPY_4 8 /* 4-byte UTF-8, copy. */
7410#define CHAR_ENC_ESC_4 9 /* 4-byte UTF-8, escaped as '\uXXXX\uXXXX'. */
7411
7412/** Character encode type table: don't escape unicode, don't escape '/'.
7413 (generate with misc/make_tables.c) */
7414static const char_enc_type enc_table_cpy[256] = {
7415 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
7416 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7417 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7418 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7419 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7420 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
7421 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7422 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7423 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7424 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7425 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7426 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7427 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7428 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7429 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7430 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1
7431};
7432
7433/** Character encode type table: don't escape unicode, escape '/'.
7434 (generate with misc/make_tables.c) */
7435static const char_enc_type enc_table_cpy_slash[256] = {
7436 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
7437 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7438 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
7439 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7440 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7441 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
7442 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7443 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7444 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7445 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7446 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7447 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7448 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7449 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7450 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7451 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1
7452};
7453
7454/** Character encode type table: escape unicode, don't escape '/'.
7455 (generate with misc/make_tables.c) */
7456static const char_enc_type enc_table_esc[256] = {
7457 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
7458 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7459 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7460 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7461 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7462 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
7463 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7464 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7465 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7466 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7467 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7468 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7469 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7470 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7471 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7472 9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1
7473};
7474
7475/** Character encode type table: escape unicode, escape '/'.
7476 (generate with misc/make_tables.c) */
7477static const char_enc_type enc_table_esc_slash[256] = {
7478 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
7479 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7480 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
7481 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7482 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7483 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
7484 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7485 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7486 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7487 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7488 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7489 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7490 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7491 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7492 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7493 9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1
7494};
7495
7496/** Escaped hex character table: ["00" "01" "02" ... "FD" "FE" "FF"].
7497 (generate with misc/make_tables.c) */
7498yyjson_align(2)
7499static const u8 esc_hex_char_table[512] = {
7500 '0', '0', '0', '1', '0', '2', '0', '3',
7501 '0', '4', '0', '5', '0', '6', '0', '7',
7502 '0', '8', '0', '9', '0', 'A', '0', 'B',
7503 '0', 'C', '0', 'D', '0', 'E', '0', 'F',
7504 '1', '0', '1', '1', '1', '2', '1', '3',
7505 '1', '4', '1', '5', '1', '6', '1', '7',
7506 '1', '8', '1', '9', '1', 'A', '1', 'B',
7507 '1', 'C', '1', 'D', '1', 'E', '1', 'F',
7508 '2', '0', '2', '1', '2', '2', '2', '3',
7509 '2', '4', '2', '5', '2', '6', '2', '7',
7510 '2', '8', '2', '9', '2', 'A', '2', 'B',
7511 '2', 'C', '2', 'D', '2', 'E', '2', 'F',
7512 '3', '0', '3', '1', '3', '2', '3', '3',
7513 '3', '4', '3', '5', '3', '6', '3', '7',
7514 '3', '8', '3', '9', '3', 'A', '3', 'B',
7515 '3', 'C', '3', 'D', '3', 'E', '3', 'F',
7516 '4', '0', '4', '1', '4', '2', '4', '3',
7517 '4', '4', '4', '5', '4', '6', '4', '7',
7518 '4', '8', '4', '9', '4', 'A', '4', 'B',
7519 '4', 'C', '4', 'D', '4', 'E', '4', 'F',
7520 '5', '0', '5', '1', '5', '2', '5', '3',
7521 '5', '4', '5', '5', '5', '6', '5', '7',
7522 '5', '8', '5', '9', '5', 'A', '5', 'B',
7523 '5', 'C', '5', 'D', '5', 'E', '5', 'F',
7524 '6', '0', '6', '1', '6', '2', '6', '3',
7525 '6', '4', '6', '5', '6', '6', '6', '7',
7526 '6', '8', '6', '9', '6', 'A', '6', 'B',
7527 '6', 'C', '6', 'D', '6', 'E', '6', 'F',
7528 '7', '0', '7', '1', '7', '2', '7', '3',
7529 '7', '4', '7', '5', '7', '6', '7', '7',
7530 '7', '8', '7', '9', '7', 'A', '7', 'B',
7531 '7', 'C', '7', 'D', '7', 'E', '7', 'F',
7532 '8', '0', '8', '1', '8', '2', '8', '3',
7533 '8', '4', '8', '5', '8', '6', '8', '7',
7534 '8', '8', '8', '9', '8', 'A', '8', 'B',
7535 '8', 'C', '8', 'D', '8', 'E', '8', 'F',
7536 '9', '0', '9', '1', '9', '2', '9', '3',
7537 '9', '4', '9', '5', '9', '6', '9', '7',
7538 '9', '8', '9', '9', '9', 'A', '9', 'B',
7539 '9', 'C', '9', 'D', '9', 'E', '9', 'F',
7540 'A', '0', 'A', '1', 'A', '2', 'A', '3',
7541 'A', '4', 'A', '5', 'A', '6', 'A', '7',
7542 'A', '8', 'A', '9', 'A', 'A', 'A', 'B',
7543 'A', 'C', 'A', 'D', 'A', 'E', 'A', 'F',
7544 'B', '0', 'B', '1', 'B', '2', 'B', '3',
7545 'B', '4', 'B', '5', 'B', '6', 'B', '7',
7546 'B', '8', 'B', '9', 'B', 'A', 'B', 'B',
7547 'B', 'C', 'B', 'D', 'B', 'E', 'B', 'F',
7548 'C', '0', 'C', '1', 'C', '2', 'C', '3',
7549 'C', '4', 'C', '5', 'C', '6', 'C', '7',
7550 'C', '8', 'C', '9', 'C', 'A', 'C', 'B',
7551 'C', 'C', 'C', 'D', 'C', 'E', 'C', 'F',
7552 'D', '0', 'D', '1', 'D', '2', 'D', '3',
7553 'D', '4', 'D', '5', 'D', '6', 'D', '7',
7554 'D', '8', 'D', '9', 'D', 'A', 'D', 'B',
7555 'D', 'C', 'D', 'D', 'D', 'E', 'D', 'F',
7556 'E', '0', 'E', '1', 'E', '2', 'E', '3',
7557 'E', '4', 'E', '5', 'E', '6', 'E', '7',
7558 'E', '8', 'E', '9', 'E', 'A', 'E', 'B',
7559 'E', 'C', 'E', 'D', 'E', 'E', 'E', 'F',
7560 'F', '0', 'F', '1', 'F', '2', 'F', '3',
7561 'F', '4', 'F', '5', 'F', '6', 'F', '7',
7562 'F', '8', 'F', '9', 'F', 'A', 'F', 'B',
7563 'F', 'C', 'F', 'D', 'F', 'E', 'F', 'F'
7564};
7565
7566/** Escaped single character table. (generate with misc/make_tables.c) */
7567yyjson_align(2)
7568static const u8 esc_single_char_table[512] = {
7569 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7570 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7571 '\\', 'b', '\\', 't', '\\', 'n', ' ', ' ',
7572 '\\', 'f', '\\', 'r', ' ', ' ', ' ', ' ',
7573 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7574 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7575 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7576 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7577 ' ', ' ', ' ', ' ', '\\', '"', ' ', ' ',
7578 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7579 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7580 ' ', ' ', ' ', ' ', ' ', ' ', '\\', '/',
7581 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7582 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7583 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7584 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7585 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7586 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7587 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7588 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7589 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7590 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7591 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7592 '\\', '\\', ' ', ' ', ' ', ' ', ' ', ' ',
7593 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7594 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7595 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7596 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7597 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7598 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7599 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7600 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7601 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7602 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7603 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7604 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7605 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7606 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7607 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7608 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7609 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7610 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7611 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7612 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7613 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7614 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7615 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7616 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7617 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7618 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7619 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7620 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7621 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7622 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7623 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7624 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7625 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7626 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7627 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7628 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7629 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7630 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7631 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
7632 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
7633};
7634
7635/** Returns the encode table with options. */
7636static_inline const char_enc_type *get_enc_table_with_flag(
7637 yyjson_read_flag flg) {
7638 if (unlikely(flg & YYJSON_WRITE_ESCAPE_UNICODE)) {
7639 if (unlikely(flg & YYJSON_WRITE_ESCAPE_SLASHES)) {
7640 return enc_table_esc_slash;
7641 } else {
7642 return enc_table_esc;
7643 }
7644 } else {
7645 if (unlikely(flg & YYJSON_WRITE_ESCAPE_SLASHES)) {
7646 return enc_table_cpy_slash;
7647 } else {
7648 return enc_table_cpy;
7649 }
7650 }
7651}
7652
7653/** Write raw string. */
7654static_inline u8 *write_raw(u8 *cur, const u8 *raw, usize raw_len) {
7655 memcpy(cur, raw, raw_len);
7656 return cur + raw_len;
7657}
7658
7659/**
7660 Write string no-escape.
7661 @param cur Buffer cursor.
7662 @param str A UTF-8 string, null-terminator is not required.
7663 @param str_len Length of string in bytes.
7664 @return The buffer cursor after string.
7665 */
7666static_inline u8 *write_string_noesc(u8 *cur, const u8 *str, usize str_len) {
7667 *cur++ = '"';
7668 while (str_len >= 16) {
7669 byte_copy_16(cur, str);
7670 cur += 16;
7671 str += 16;
7672 str_len -= 16;
7673 }
7674 while (str_len >= 4) {
7675 byte_copy_4(cur, str);
7676 cur += 4;
7677 str += 4;
7678 str_len -= 4;
7679 }
7680 while (str_len) {
7681 *cur++ = *str++;
7682 str_len -= 1;
7683 }
7684 *cur++ = '"';
7685 return cur;
7686}
7687
7688/**
7689 Write UTF-8 string (requires len * 6 + 2 bytes buffer).
7690 @param cur Buffer cursor.
7691 @param esc Escape unicode.
7692 @param inv Allow invalid unicode.
7693 @param str A UTF-8 string, null-terminator is not required.
7694 @param str_len Length of string in bytes.
7695 @param enc_table Encode type table for character.
7696 @return The buffer cursor after string, or NULL on invalid unicode.
7697 */
7698static_inline u8 *write_string(u8 *cur, bool esc, bool inv,
7699 const u8 *str, usize str_len,
7700 const char_enc_type *enc_table) {
7701
7702 /* UTF-8 character mask and pattern, see `read_string()` for details. */
7703#if YYJSON_ENDIAN == YYJSON_BIG_ENDIAN
7704 const u16 b2_mask = 0xE0C0UL;
7705 const u16 b2_patt = 0xC080UL;
7706 const u16 b2_requ = 0x1E00UL;
7707 const u32 b3_mask = 0xF0C0C000UL;
7708 const u32 b3_patt = 0xE0808000UL;
7709 const u32 b3_requ = 0x0F200000UL;
7710 const u32 b3_erro = 0x0D200000UL;
7711 const u32 b4_mask = 0xF8C0C0C0UL;
7712 const u32 b4_patt = 0xF0808080UL;
7713 const u32 b4_requ = 0x07300000UL;
7714 const u32 b4_err0 = 0x04000000UL;
7715 const u32 b4_err1 = 0x03300000UL;
7716#elif YYJSON_ENDIAN == YYJSON_LITTLE_ENDIAN
7717 const u16 b2_mask = 0xC0E0UL;
7718 const u16 b2_patt = 0x80C0UL;
7719 const u16 b2_requ = 0x001EUL;
7720 const u32 b3_mask = 0x00C0C0F0UL;
7721 const u32 b3_patt = 0x008080E0UL;
7722 const u32 b3_requ = 0x0000200FUL;
7723 const u32 b3_erro = 0x0000200DUL;
7724 const u32 b4_mask = 0xC0C0C0F8UL;
7725 const u32 b4_patt = 0x808080F0UL;
7726 const u32 b4_requ = 0x00003007UL;
7727 const u32 b4_err0 = 0x00000004UL;
7728 const u32 b4_err1 = 0x00003003UL;
7729#else
7730 v16_uni b2_mask_uni = {{ 0xE0, 0xC0 }};
7731 v16_uni b2_patt_uni = {{ 0xC0, 0x80 }};
7732 v16_uni b2_requ_uni = {{ 0x1E, 0x00 }};
7733 v32_uni b3_mask_uni = {{ 0xF0, 0xC0, 0xC0, 0x00 }};
7734 v32_uni b3_patt_uni = {{ 0xE0, 0x80, 0x80, 0x00 }};
7735 v32_uni b3_requ_uni = {{ 0x0F, 0x20, 0x00, 0x00 }};
7736 v32_uni b3_erro_uni = {{ 0x0D, 0x20, 0x00, 0x00 }};
7737 v32_uni b4_mask_uni = {{ 0xF8, 0xC0, 0xC0, 0xC0 }};
7738 v32_uni b4_patt_uni = {{ 0xF0, 0x80, 0x80, 0x80 }};
7739 v32_uni b4_requ_uni = {{ 0x07, 0x30, 0x00, 0x00 }};
7740 v32_uni b4_err0_uni = {{ 0x04, 0x00, 0x00, 0x00 }};
7741 v32_uni b4_err1_uni = {{ 0x03, 0x30, 0x00, 0x00 }};
7742 u16 b2_mask = b2_mask_uni.u;
7743 u16 b2_patt = b2_patt_uni.u;
7744 u16 b2_requ = b2_requ_uni.u;
7745 u32 b3_mask = b3_mask_uni.u;
7746 u32 b3_patt = b3_patt_uni.u;
7747 u32 b3_requ = b3_requ_uni.u;
7748 u32 b3_erro = b3_erro_uni.u;
7749 u32 b4_mask = b4_mask_uni.u;
7750 u32 b4_patt = b4_patt_uni.u;
7751 u32 b4_requ = b4_requ_uni.u;
7752 u32 b4_err0 = b4_err0_uni.u;
7753 u32 b4_err1 = b4_err1_uni.u;
7754#endif
7755
7756#define is_valid_seq_2(uni) ( \
7757 ((uni & b2_mask) == b2_patt) && \
7758 ((uni & b2_requ)) \
7759)
7760
7761#define is_valid_seq_3(uni) ( \
7762 ((uni & b3_mask) == b3_patt) && \
7763 ((tmp = (uni & b3_requ))) && \
7764 ((tmp != b3_erro)) \
7765)
7766
7767#define is_valid_seq_4(uni) ( \
7768 ((uni & b4_mask) == b4_patt) && \
7769 ((tmp = (uni & b4_requ))) && \
7770 ((tmp & b4_err0) == 0 || (tmp & b4_err1) == 0) \
7771)
7772
7773 /* The replacement character U+FFFD, used to indicate invalid character. */
7774 const v32 rep = { 'F', 'F', 'F', 'D' };
7775 const v32 pre = { '\\', 'u', '0', '0' };
7776
7777 const u8 *src = str;
7778 const u8 *end = str + str_len;
7779 *cur++ = '"';
7780
7781copy_ascii:
7782 /*
7783 Copy continuous ASCII, loop unrolling, same as the following code:
7784
7785 while (end > src) (
7786 if (unlikely(enc_table[*src])) break;
7787 *cur++ = *src++;
7788 );
7789 */
7790#define expr_jump(i) \
7791 if (unlikely(enc_table[src[i]])) goto stop_char_##i;
7792
7793#define expr_stop(i) \
7794 stop_char_##i: \
7795 memcpy(cur, src, i); \
7796 cur += i; src += i; goto copy_utf8;
7797
7798 while (end - src >= 16) {
7799 repeat16_incr(expr_jump)
7800 byte_copy_16(cur, src);
7801 cur += 16; src += 16;
7802 }
7803
7804 while (end - src >= 4) {
7805 repeat4_incr(expr_jump)
7806 byte_copy_4(cur, src);
7807 cur += 4; src += 4;
7808 }
7809
7810 while (end > src) {
7811 expr_jump(0)
7812 *cur++ = *src++;
7813 }
7814
7815 *cur++ = '"';
7816 return cur;
7817
7818 repeat16_incr(expr_stop)
7819
7820#undef expr_jump
7821#undef expr_stop
7822
7823copy_utf8:
7824 if (unlikely(src + 4 > end)) {
7825 if (end == src) goto copy_end;
7826 if (end - src < enc_table[*src] / 2) goto err_one;
7827 }
7828 switch (enc_table[*src]) {
7829 case CHAR_ENC_CPY_1: {
7830 *cur++ = *src++;
7831 goto copy_ascii;
7832 }
7833 case CHAR_ENC_CPY_2: {
7834 u16 v;
7835 v = byte_load_2(src);
7836 if (unlikely(!is_valid_seq_2(v))) goto err_cpy;
7837
7838 byte_copy_2(cur, src);
7839 cur += 2;
7840 src += 2;
7841 goto copy_utf8;
7842 }
7843 case CHAR_ENC_CPY_3: {
7844 u32 v, tmp;
7845 if (likely(src + 4 <= end)) {
7846 v = byte_load_4(src);
7847 if (unlikely(!is_valid_seq_3(v))) goto err_cpy;
7848 byte_copy_4(cur, src);
7849 } else {
7850 v = byte_load_3(src);
7851 if (unlikely(!is_valid_seq_3(v))) goto err_cpy;
7852 byte_copy_4(cur, &v);
7853 }
7854 cur += 3;
7855 src += 3;
7856 goto copy_utf8;
7857 }
7858 case CHAR_ENC_CPY_4: {
7859 u32 v, tmp;
7860 v = byte_load_4(src);
7861 if (unlikely(!is_valid_seq_4(v))) goto err_cpy;
7862
7863 byte_copy_4(cur, src);
7864 cur += 4;
7865 src += 4;
7866 goto copy_utf8;
7867 }
7868 case CHAR_ENC_ESC_A: {
7869 byte_copy_2(cur, &esc_single_char_table[*src * 2]);
7870 cur += 2;
7871 src += 1;
7872 goto copy_utf8;
7873 }
7874 case CHAR_ENC_ESC_1: {
7875 byte_copy_4(cur + 0, &pre);
7876 byte_copy_2(cur + 4, &esc_hex_char_table[*src * 2]);
7877 cur += 6;
7878 src += 1;
7879 goto copy_utf8;
7880 }
7881 case CHAR_ENC_ESC_2: {
7882 u16 u, v;
7883 v = byte_load_2(src);
7884 if (unlikely(!is_valid_seq_2(v))) goto err_esc;
7885
7886 u = (u16)(((u16)(src[0] & 0x1F) << 6) |
7887 ((u16)(src[1] & 0x3F) << 0));
7888 byte_copy_2(cur + 0, &pre);
7889 byte_copy_2(cur + 2, &esc_hex_char_table[(u >> 8) * 2]);
7890 byte_copy_2(cur + 4, &esc_hex_char_table[(u & 0xFF) * 2]);
7891 cur += 6;
7892 src += 2;
7893 goto copy_utf8;
7894 }
7895 case CHAR_ENC_ESC_3: {
7896 u16 u;
7897 u32 v, tmp;
7898 v = byte_load_3(src);
7899 if (unlikely(!is_valid_seq_3(v))) goto err_esc;
7900
7901 u = (u16)(((u16)(src[0] & 0x0F) << 12) |
7902 ((u16)(src[1] & 0x3F) << 6) |
7903 ((u16)(src[2] & 0x3F) << 0));
7904 byte_copy_2(cur + 0, &pre);
7905 byte_copy_2(cur + 2, &esc_hex_char_table[(u >> 8) * 2]);
7906 byte_copy_2(cur + 4, &esc_hex_char_table[(u & 0xFF) * 2]);
7907 cur += 6;
7908 src += 3;
7909 goto copy_utf8;
7910 }
7911 case CHAR_ENC_ESC_4: {
7912 u32 hi, lo, u, v, tmp;
7913 v = byte_load_4(src);
7914 if (unlikely(!is_valid_seq_4(v))) goto err_esc;
7915
7916 u = ((u32)(src[0] & 0x07) << 18) |
7917 ((u32)(src[1] & 0x3F) << 12) |
7918 ((u32)(src[2] & 0x3F) << 6) |
7919 ((u32)(src[3] & 0x3F) << 0);
7920 u -= 0x10000;
7921 hi = (u >> 10) + 0xD800;
7922 lo = (u & 0x3FF) + 0xDC00;
7923 byte_copy_2(cur + 0, &pre);
7924 byte_copy_2(cur + 2, &esc_hex_char_table[(hi >> 8) * 2]);
7925 byte_copy_2(cur + 4, &esc_hex_char_table[(hi & 0xFF) * 2]);
7926 byte_copy_2(cur + 6, &pre);
7927 byte_copy_2(cur + 8, &esc_hex_char_table[(lo >> 8) * 2]);
7928 byte_copy_2(cur + 10, &esc_hex_char_table[(lo & 0xFF) * 2]);
7929 cur += 12;
7930 src += 4;
7931 goto copy_utf8;
7932 }
7933 case CHAR_ENC_ERR_1: {
7934 goto err_one;
7935 }
7936 default: break;
7937 }
7938
7939copy_end:
7940 *cur++ = '"';
7941 return cur;
7942
7943err_one:
7944 if (esc) goto err_esc;
7945 else goto err_cpy;
7946
7947err_cpy:
7948 if (!inv) return NULL;
7949 *cur++ = *src++;
7950 goto copy_utf8;
7951
7952err_esc:
7953 if (!inv) return NULL;
7954 byte_copy_2(cur + 0, &pre);
7955 byte_copy_4(cur + 2, &rep);
7956 cur += 6;
7957 src += 1;
7958 goto copy_utf8;
7959
7960#undef is_valid_seq_2
7961#undef is_valid_seq_3
7962#undef is_valid_seq_4
7963}
7964
7965
7966
7967/*==============================================================================
7968 * Writer Utilities
7969 *============================================================================*/
7970
7971/** Write null (requires 8 bytes buffer). */
7972static_inline u8 *write_null(u8 *cur) {
7973 v64 v = { 'n', 'u', 'l', 'l', ',', '\n', 0, 0 };
7974 byte_copy_8(cur, &v);
7975 return cur + 4;
7976}
7977
7978/** Write bool (requires 8 bytes buffer). */
7979static_inline u8 *write_bool(u8 *cur, bool val) {
7980 v64 v0 = { 'f', 'a', 'l', 's', 'e', ',', '\n', 0 };
7981 v64 v1 = { 't', 'r', 'u', 'e', ',', '\n', 0, 0 };
7982 if (val) {
7983 byte_copy_8(cur, &v1);
7984 } else {
7985 byte_copy_8(cur, &v0);
7986 }
7987 return cur + 5 - val;
7988}
7989
7990/** Write indent (requires level x 4 bytes buffer).
7991 Param spaces should not larger than 4. */
7992static_inline u8 *write_indent(u8 *cur, usize level, usize spaces) {
7993 while (level-- > 0) {
7994 byte_copy_4(cur, " ");
7995 cur += spaces;
7996 }
7997 return cur;
7998}
7999
8000/** Write data to file pointer. */
8001static bool write_dat_to_fp(FILE *fp, u8 *dat, usize len,
8002 yyjson_write_err *err) {
8003 if (fwrite(dat, len, 1, fp) != 1) {
8004 err->msg = "file writing failed";
8005 err->code = YYJSON_WRITE_ERROR_FILE_WRITE;
8006 return false;
8007 }
8008 return true;
8009}
8010
8011/** Write data to file. */
8012static bool write_dat_to_file(const char *path, u8 *dat, usize len,
8013 yyjson_write_err *err) {
8014
8015#define return_err(_code, _msg) do { \
8016 err->msg = _msg; \
8017 err->code = YYJSON_WRITE_ERROR_##_code; \
8018 if (file) fclose(file); \
8019 return false; \
8020} while (false)
8021
8022 FILE *file = fopen_writeonly(path);
8023 if (file == NULL) {
8024 return_err(FILE_OPEN, "file opening failed");
8025 }
8026 if (fwrite(dat, len, 1, file) != 1) {
8027 return_err(FILE_WRITE, "file writing failed");
8028 }
8029 if (fclose(file) != 0) {
8030 file = NULL;
8031 return_err(FILE_WRITE, "file closing failed");
8032 }
8033 return true;
8034
8035#undef return_err
8036}
8037
8038
8039
8040/*==============================================================================
8041 * JSON Writer Implementation
8042 *============================================================================*/
8043
8044typedef struct yyjson_write_ctx {
8045 usize tag;
8046} yyjson_write_ctx;
8047
8048static_inline void yyjson_write_ctx_set(yyjson_write_ctx *ctx,
8049 usize size, bool is_obj) {
8050 ctx->tag = (size << 1) | (usize)is_obj;
8051}
8052
8053static_inline void yyjson_write_ctx_get(yyjson_write_ctx *ctx,
8054 usize *size, bool *is_obj) {
8055 usize tag = ctx->tag;
8056 *size = tag >> 1;
8057 *is_obj = (bool)(tag & 1);
8058}
8059
8060/** Write single JSON value. */
8061static_inline u8 *yyjson_write_single(yyjson_val *val,
8062 yyjson_write_flag flg,
8063 yyjson_alc alc,
8064 usize *dat_len,
8065 yyjson_write_err *err) {
8066
8067#define return_err(_code, _msg) do { \
8068 if (hdr) alc.free(alc.ctx, (void *)hdr); \
8069 *dat_len = 0; \
8070 err->code = YYJSON_WRITE_ERROR_##_code; \
8071 err->msg = _msg; \
8072 return NULL; \
8073} while (false)
8074
8075#define incr_len(_len) do { \
8076 hdr = (u8 *)alc.malloc(alc.ctx, _len); \
8077 if (!hdr) goto fail_alloc; \
8078 cur = hdr; \
8079} while (false)
8080
8081#define check_str_len(_len) do { \
8082 if ((USIZE_MAX < U64_MAX) && (_len >= (USIZE_MAX - 16) / 6)) \
8083 goto fail_alloc; \
8084} while (false)
8085
8086 u8 *hdr = NULL, *cur;
8087 usize str_len;
8088 const u8 *str_ptr;
8089 const char_enc_type *enc_table = get_enc_table_with_flag(flg);
8090 bool cpy = (enc_table == enc_table_cpy);
8091 bool esc = (flg & YYJSON_WRITE_ESCAPE_UNICODE) != 0;
8092 bool inv = (flg & YYJSON_WRITE_ALLOW_INVALID_UNICODE) != 0;
8093
8094 switch (unsafe_yyjson_get_type(val)) {
8095 case YYJSON_TYPE_RAW:
8096 str_len = unsafe_yyjson_get_len(val);
8097 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
8098 check_str_len(str_len);
8099 incr_len(str_len + 1);
8100 cur = write_raw(cur, str_ptr, str_len);
8101 break;
8102
8103 case YYJSON_TYPE_STR:
8104 str_len = unsafe_yyjson_get_len(val);
8105 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
8106 check_str_len(str_len);
8107 incr_len(str_len * 6 + 4);
8108 if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
8109 cur = write_string_noesc(cur, str_ptr, str_len);
8110 } else {
8111 cur = write_string(cur, esc, inv, str_ptr, str_len, enc_table);
8112 if (unlikely(!cur)) goto fail_str;
8113 }
8114 break;
8115
8116 case YYJSON_TYPE_NUM:
8117 incr_len(32);
8118 cur = write_number(cur, val, flg);
8119 if (unlikely(!cur)) goto fail_num;
8120 break;
8121
8122 case YYJSON_TYPE_BOOL:
8123 incr_len(8);
8124 cur = write_bool(cur, unsafe_yyjson_get_bool(val));
8125 break;
8126
8127 case YYJSON_TYPE_NULL:
8128 incr_len(8);
8129 cur = write_null(cur);
8130 break;
8131
8132 case YYJSON_TYPE_ARR:
8133 incr_len(4);
8134 byte_copy_2(cur, "[]");
8135 cur += 2;
8136 break;
8137
8138 case YYJSON_TYPE_OBJ:
8139 incr_len(4);
8140 byte_copy_2(cur, "{}");
8141 cur += 2;
8142 break;
8143
8144 default:
8145 goto fail_type;
8146 }
8147
8148 *cur = '\0';
8149 *dat_len = (usize)(cur - hdr);
8150 memset(err, 0, sizeof(yyjson_write_err));
8151 return hdr;
8152
8153fail_alloc:
8154 return_err(MEMORY_ALLOCATION, "memory allocation failed");
8155fail_type:
8156 return_err(INVALID_VALUE_TYPE, "invalid JSON value type");
8157fail_num:
8158 return_err(NAN_OR_INF, "nan or inf number is not allowed");
8159fail_str:
8160 return_err(INVALID_STRING, "invalid utf-8 encoding in string");
8161
8162#undef return_err
8163#undef check_str_len
8164#undef incr_len
8165}
8166
8167/** Write JSON document minify.
8168 The root of this document should be a non-empty container. */
8169static_inline u8 *yyjson_write_minify(const yyjson_val *root,
8170 const yyjson_write_flag flg,
8171 const yyjson_alc alc,
8172 usize *dat_len,
8173 yyjson_write_err *err) {
8174
8175#define return_err(_code, _msg) do { \
8176 *dat_len = 0; \
8177 err->code = YYJSON_WRITE_ERROR_##_code; \
8178 err->msg = _msg; \
8179 if (hdr) alc.free(alc.ctx, hdr); \
8180 return NULL; \
8181} while (false)
8182
8183#define incr_len(_len) do { \
8184 ext_len = (usize)(_len); \
8185 if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
8186 alc_inc = yyjson_max(alc_len / 2, ext_len); \
8187 alc_inc = size_align_up(alc_inc, sizeof(yyjson_write_ctx)); \
8188 if (size_add_is_overflow(alc_len, alc_inc)) goto fail_alloc; \
8189 alc_len += alc_inc; \
8190 tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
8191 if (unlikely(!tmp)) goto fail_alloc; \
8192 ctx_len = (usize)(end - (u8 *)ctx); \
8193 ctx_tmp = (yyjson_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
8194 memmove((void *)ctx_tmp, (void *)(tmp + ((u8 *)ctx - hdr)), ctx_len); \
8195 ctx = ctx_tmp; \
8196 cur = tmp + (cur - hdr); \
8197 end = tmp + alc_len; \
8198 hdr = tmp; \
8199 } \
8200} while (false)
8201
8202#define check_str_len(_len) do { \
8203 if ((USIZE_MAX < U64_MAX) && (_len >= (USIZE_MAX - 16) / 6)) \
8204 goto fail_alloc; \
8205} while (false)
8206
8207 yyjson_val *val;
8208 yyjson_type val_type;
8209 usize ctn_len, ctn_len_tmp;
8210 bool ctn_obj, ctn_obj_tmp, is_key;
8211 u8 *hdr, *cur, *end, *tmp;
8212 yyjson_write_ctx *ctx, *ctx_tmp;
8213 usize alc_len, alc_inc, ctx_len, ext_len, str_len;
8214 const u8 *str_ptr;
8215 const char_enc_type *enc_table = get_enc_table_with_flag(flg);
8216 bool cpy = (enc_table == enc_table_cpy);
8217 bool esc = (flg & YYJSON_WRITE_ESCAPE_UNICODE) != 0;
8218 bool inv = (flg & YYJSON_WRITE_ALLOW_INVALID_UNICODE) != 0;
8219
8220 alc_len = root->uni.ofs / sizeof(yyjson_val);
8221 alc_len = alc_len * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64;
8222 alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx));
8223 hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
8224 if (!hdr) goto fail_alloc;
8225 cur = hdr;
8226 end = hdr + alc_len;
8227 ctx = (yyjson_write_ctx *)(void *)end;
8228
8229doc_begin:
8230 val = constcast(yyjson_val *)root;
8231 val_type = unsafe_yyjson_get_type(val);
8232 ctn_obj = (val_type == YYJSON_TYPE_OBJ);
8233 ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
8234 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
8235 val++;
8236
8237val_begin:
8238 val_type = unsafe_yyjson_get_type(val);
8239 if (val_type == YYJSON_TYPE_STR) {
8240 is_key = ((u8)ctn_obj & (u8)~ctn_len);
8241 str_len = unsafe_yyjson_get_len(val);
8242 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
8243 check_str_len(str_len);
8244 incr_len(str_len * 6 + 16);
8245 if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
8246 cur = write_string_noesc(cur, str_ptr, str_len);
8247 } else {
8248 cur = write_string(cur, esc, inv, str_ptr, str_len, enc_table);
8249 if (unlikely(!cur)) goto fail_str;
8250 }
8251 *cur++ = is_key ? ':' : ',';
8252 goto val_end;
8253 }
8254 if (val_type == YYJSON_TYPE_NUM) {
8255 incr_len(32);
8256 cur = write_number(cur, val, flg);
8257 if (unlikely(!cur)) goto fail_num;
8258 *cur++ = ',';
8259 goto val_end;
8260 }
8261 if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
8262 (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
8263 ctn_len_tmp = unsafe_yyjson_get_len(val);
8264 ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
8265 incr_len(16);
8266 if (unlikely(ctn_len_tmp == 0)) {
8267 /* write empty container */
8268 *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
8269 *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
8270 *cur++ = ',';
8271 goto val_end;
8272 } else {
8273 /* push context, setup new container */
8274 yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj);
8275 ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
8276 ctn_obj = ctn_obj_tmp;
8277 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
8278 val++;
8279 goto val_begin;
8280 }
8281 }
8282 if (val_type == YYJSON_TYPE_BOOL) {
8283 incr_len(16);
8284 cur = write_bool(cur, unsafe_yyjson_get_bool(val));
8285 cur++;
8286 goto val_end;
8287 }
8288 if (val_type == YYJSON_TYPE_NULL) {
8289 incr_len(16);
8290 cur = write_null(cur);
8291 cur++;
8292 goto val_end;
8293 }
8294 if (val_type == YYJSON_TYPE_RAW) {
8295 str_len = unsafe_yyjson_get_len(val);
8296 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
8297 check_str_len(str_len);
8298 incr_len(str_len + 2);
8299 cur = write_raw(cur, str_ptr, str_len);
8300 *cur++ = ',';
8301 goto val_end;
8302 }
8303 goto fail_type;
8304
8305val_end:
8306 val++;
8307 ctn_len--;
8308 if (unlikely(ctn_len == 0)) goto ctn_end;
8309 goto val_begin;
8310
8311ctn_end:
8312 cur--;
8313 *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
8314 *cur++ = ',';
8315 if (unlikely((u8 *)ctx >= end)) goto doc_end;
8316 yyjson_write_ctx_get(ctx++, &ctn_len, &ctn_obj);
8317 ctn_len--;
8318 if (likely(ctn_len > 0)) {
8319 goto val_begin;
8320 } else {
8321 goto ctn_end;
8322 }
8323
8324doc_end:
8325 *--cur = '\0';
8326 *dat_len = (usize)(cur - hdr);
8327 memset(err, 0, sizeof(yyjson_write_err));
8328 return hdr;
8329
8330fail_alloc:
8331 return_err(MEMORY_ALLOCATION, "memory allocation failed");
8332fail_type:
8333 return_err(INVALID_VALUE_TYPE, "invalid JSON value type");
8334fail_num:
8335 return_err(NAN_OR_INF, "nan or inf number is not allowed");
8336fail_str:
8337 return_err(INVALID_STRING, "invalid utf-8 encoding in string");
8338
8339#undef return_err
8340#undef incr_len
8341#undef check_str_len
8342}
8343
8344/** Write JSON document pretty.
8345 The root of this document should be a non-empty container. */
8346static_inline u8 *yyjson_write_pretty(const yyjson_val *root,
8347 const yyjson_write_flag flg,
8348 const yyjson_alc alc,
8349 usize *dat_len,
8350 yyjson_write_err *err) {
8351
8352#define return_err(_code, _msg) do { \
8353 *dat_len = 0; \
8354 err->code = YYJSON_WRITE_ERROR_##_code; \
8355 err->msg = _msg; \
8356 if (hdr) alc.free(alc.ctx, hdr); \
8357 return NULL; \
8358} while (false)
8359
8360#define incr_len(_len) do { \
8361 ext_len = (usize)(_len); \
8362 if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
8363 alc_inc = yyjson_max(alc_len / 2, ext_len); \
8364 alc_inc = size_align_up(alc_inc, sizeof(yyjson_write_ctx)); \
8365 if (size_add_is_overflow(alc_len, alc_inc)) goto fail_alloc; \
8366 alc_len += alc_inc; \
8367 tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
8368 if (unlikely(!tmp)) goto fail_alloc; \
8369 ctx_len = (usize)(end - (u8 *)ctx); \
8370 ctx_tmp = (yyjson_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
8371 memmove((void *)ctx_tmp, (void *)(tmp + ((u8 *)ctx - hdr)), ctx_len); \
8372 ctx = ctx_tmp; \
8373 cur = tmp + (cur - hdr); \
8374 end = tmp + alc_len; \
8375 hdr = tmp; \
8376 } \
8377} while (false)
8378
8379#define check_str_len(_len) do { \
8380 if ((USIZE_MAX < U64_MAX) && (_len >= (USIZE_MAX - 16) / 6)) \
8381 goto fail_alloc; \
8382} while (false)
8383
8384 yyjson_val *val;
8385 yyjson_type val_type;
8386 usize ctn_len, ctn_len_tmp;
8387 bool ctn_obj, ctn_obj_tmp, is_key, no_indent;
8388 u8 *hdr, *cur, *end, *tmp;
8389 yyjson_write_ctx *ctx, *ctx_tmp;
8390 usize alc_len, alc_inc, ctx_len, ext_len, str_len, level;
8391 const u8 *str_ptr;
8392 const char_enc_type *enc_table = get_enc_table_with_flag(flg);
8393 bool cpy = (enc_table == enc_table_cpy);
8394 bool esc = (flg & YYJSON_WRITE_ESCAPE_UNICODE) != 0;
8395 bool inv = (flg & YYJSON_WRITE_ALLOW_INVALID_UNICODE) != 0;
8396 usize spaces = (flg & YYJSON_WRITE_PRETTY_TWO_SPACES) ? 2 : 4;
8397
8398 alc_len = root->uni.ofs / sizeof(yyjson_val);
8399 alc_len = alc_len * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64;
8400 alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx));
8401 hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
8402 if (!hdr) goto fail_alloc;
8403 cur = hdr;
8404 end = hdr + alc_len;
8405 ctx = (yyjson_write_ctx *)(void *)end;
8406
8407doc_begin:
8408 val = constcast(yyjson_val *)root;
8409 val_type = unsafe_yyjson_get_type(val);
8410 ctn_obj = (val_type == YYJSON_TYPE_OBJ);
8411 ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
8412 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
8413 *cur++ = '\n';
8414 val++;
8415 level = 1;
8416
8417val_begin:
8418 val_type = unsafe_yyjson_get_type(val);
8419 if (val_type == YYJSON_TYPE_STR) {
8420 is_key = (bool)((u8)ctn_obj & (u8)~ctn_len);
8421 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
8422 str_len = unsafe_yyjson_get_len(val);
8423 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
8424 check_str_len(str_len);
8425 incr_len(str_len * 6 + 16 + (no_indent ? 0 : level * 4));
8426 cur = write_indent(cur, no_indent ? 0 : level, spaces);
8427 if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
8428 cur = write_string_noesc(cur, str_ptr, str_len);
8429 } else {
8430 cur = write_string(cur, esc, inv, str_ptr, str_len, enc_table);
8431 if (unlikely(!cur)) goto fail_str;
8432 }
8433 *cur++ = is_key ? ':' : ',';
8434 *cur++ = is_key ? ' ' : '\n';
8435 goto val_end;
8436 }
8437 if (val_type == YYJSON_TYPE_NUM) {
8438 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
8439 incr_len(32 + (no_indent ? 0 : level * 4));
8440 cur = write_indent(cur, no_indent ? 0 : level, spaces);
8441 cur = write_number(cur, val, flg);
8442 if (unlikely(!cur)) goto fail_num;
8443 *cur++ = ',';
8444 *cur++ = '\n';
8445 goto val_end;
8446 }
8447 if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
8448 (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
8449 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
8450 ctn_len_tmp = unsafe_yyjson_get_len(val);
8451 ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
8452 if (unlikely(ctn_len_tmp == 0)) {
8453 /* write empty container */
8454 incr_len(16 + (no_indent ? 0 : level * 4));
8455 cur = write_indent(cur, no_indent ? 0 : level, spaces);
8456 *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
8457 *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
8458 *cur++ = ',';
8459 *cur++ = '\n';
8460 goto val_end;
8461 } else {
8462 /* push context, setup new container */
8463 incr_len(32 + (no_indent ? 0 : level * 4));
8464 yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj);
8465 ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
8466 ctn_obj = ctn_obj_tmp;
8467 cur = write_indent(cur, no_indent ? 0 : level, spaces);
8468 level++;
8469 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
8470 *cur++ = '\n';
8471 val++;
8472 goto val_begin;
8473 }
8474 }
8475 if (val_type == YYJSON_TYPE_BOOL) {
8476 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
8477 incr_len(16 + (no_indent ? 0 : level * 4));
8478 cur = write_indent(cur, no_indent ? 0 : level, spaces);
8479 cur = write_bool(cur, unsafe_yyjson_get_bool(val));
8480 cur += 2;
8481 goto val_end;
8482 }
8483 if (val_type == YYJSON_TYPE_NULL) {
8484 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
8485 incr_len(16 + (no_indent ? 0 : level * 4));
8486 cur = write_indent(cur, no_indent ? 0 : level, spaces);
8487 cur = write_null(cur);
8488 cur += 2;
8489 goto val_end;
8490 }
8491 if (val_type == YYJSON_TYPE_RAW) {
8492 str_len = unsafe_yyjson_get_len(val);
8493 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
8494 check_str_len(str_len);
8495 incr_len(str_len + 3);
8496 cur = write_raw(cur, str_ptr, str_len);
8497 *cur++ = ',';
8498 *cur++ = '\n';
8499 goto val_end;
8500 }
8501 goto fail_type;
8502
8503val_end:
8504 val++;
8505 ctn_len--;
8506 if (unlikely(ctn_len == 0)) goto ctn_end;
8507 goto val_begin;
8508
8509ctn_end:
8510 cur -= 2;
8511 *cur++ = '\n';
8512 incr_len(level * 4);
8513 cur = write_indent(cur, --level, spaces);
8514 *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
8515 if (unlikely((u8 *)ctx >= end)) goto doc_end;
8516 yyjson_write_ctx_get(ctx++, &ctn_len, &ctn_obj);
8517 ctn_len--;
8518 *cur++ = ',';
8519 *cur++ = '\n';
8520 if (likely(ctn_len > 0)) {
8521 goto val_begin;
8522 } else {
8523 goto ctn_end;
8524 }
8525
8526doc_end:
8527 *cur = '\0';
8528 *dat_len = (usize)(cur - hdr);
8529 memset(err, 0, sizeof(yyjson_write_err));
8530 return hdr;
8531
8532fail_alloc:
8533 return_err(MEMORY_ALLOCATION, "memory allocation failed");
8534fail_type:
8535 return_err(INVALID_VALUE_TYPE, "invalid JSON value type");
8536fail_num:
8537 return_err(NAN_OR_INF, "nan or inf number is not allowed");
8538fail_str:
8539 return_err(INVALID_STRING, "invalid utf-8 encoding in string");
8540
8541#undef return_err
8542#undef incr_len
8543#undef check_str_len
8544}
8545
8546char *yyjson_val_write_opts(const yyjson_val *val,
8547 yyjson_write_flag flg,
8548 const yyjson_alc *alc_ptr,
8549 usize *dat_len,
8550 yyjson_write_err *err) {
8551 yyjson_write_err dummy_err;
8552 usize dummy_dat_len;
8553 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
8554 yyjson_val *root = constcast(yyjson_val *)val;
8555
8556 err = err ? err : &dummy_err;
8557 dat_len = dat_len ? dat_len : &dummy_dat_len;
8558
8559#if YYJSON_DISABLE_NON_STANDARD
8560 flg &= ~YYJSON_WRITE_ALLOW_INF_AND_NAN;
8561 flg &= ~YYJSON_WRITE_ALLOW_INVALID_UNICODE;
8562#endif
8563
8564 if (unlikely(!root)) {
8565 *dat_len = 0;
8566 err->msg = "input JSON is NULL";
8567 err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
8568 return NULL;
8569 }
8570
8571 if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) {
8572 return (char *)yyjson_write_single(root, flg, alc, dat_len, err);
8573 } else if (flg & (YYJSON_WRITE_PRETTY | YYJSON_WRITE_PRETTY_TWO_SPACES)) {
8574 return (char *)yyjson_write_pretty(root, flg, alc, dat_len, err);
8575 } else {
8576 return (char *)yyjson_write_minify(root, flg, alc, dat_len, err);
8577 }
8578}
8579
8580char *yyjson_write_opts(const yyjson_doc *doc,
8581 yyjson_write_flag flg,
8582 const yyjson_alc *alc_ptr,
8583 usize *dat_len,
8584 yyjson_write_err *err) {
8585 yyjson_val *root = doc ? doc->root : NULL;
8586 return yyjson_val_write_opts(root, flg, alc_ptr, dat_len, err);
8587}
8588
8589bool yyjson_val_write_file(const char *path,
8590 const yyjson_val *val,
8591 yyjson_write_flag flg,
8592 const yyjson_alc *alc_ptr,
8593 yyjson_write_err *err) {
8594 yyjson_write_err dummy_err;
8595 u8 *dat;
8596 usize dat_len = 0;
8597 yyjson_val *root = constcast(yyjson_val *)val;
8598 bool suc;
8599
8600 alc_ptr = alc_ptr ? alc_ptr : &YYJSON_DEFAULT_ALC;
8601 err = err ? err : &dummy_err;
8602 if (unlikely(!path || !*path)) {
8603 err->msg = "input path is invalid";
8604 err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
8605 return false;
8606 }
8607
8608 dat = (u8 *)yyjson_val_write_opts(root, flg, alc_ptr, &dat_len, err);
8609 if (unlikely(!dat)) return false;
8610 suc = write_dat_to_file(path, dat, dat_len, err);
8611 alc_ptr->free(alc_ptr->ctx, dat);
8612 return suc;
8613}
8614
8615bool yyjson_val_write_fp(FILE *fp,
8616 const yyjson_val *val,
8617 yyjson_write_flag flg,
8618 const yyjson_alc *alc_ptr,
8619 yyjson_write_err *err) {
8620 yyjson_write_err dummy_err;
8621 u8 *dat;
8622 usize dat_len = 0;
8623 yyjson_val *root = constcast(yyjson_val *)val;
8624 bool suc;
8625
8626 alc_ptr = alc_ptr ? alc_ptr : &YYJSON_DEFAULT_ALC;
8627 err = err ? err : &dummy_err;
8628 if (unlikely(!fp)) {
8629 err->msg = "input fp is invalid";
8630 err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
8631 return false;
8632 }
8633
8634 dat = (u8 *)yyjson_val_write_opts(root, flg, alc_ptr, &dat_len, err);
8635 if (unlikely(!dat)) return false;
8636 suc = write_dat_to_fp(fp, dat, dat_len, err);
8637 alc_ptr->free(alc_ptr->ctx, dat);
8638 return suc;
8639}
8640
8641bool yyjson_write_file(const char *path,
8642 const yyjson_doc *doc,
8643 yyjson_write_flag flg,
8644 const yyjson_alc *alc_ptr,
8645 yyjson_write_err *err) {
8646 yyjson_val *root = doc ? doc->root : NULL;
8647 return yyjson_val_write_file(path, root, flg, alc_ptr, err);
8648}
8649
8650bool yyjson_write_fp(FILE *fp,
8651 const yyjson_doc *doc,
8652 yyjson_write_flag flg,
8653 const yyjson_alc *alc_ptr,
8654 yyjson_write_err *err) {
8655 yyjson_val *root = doc ? doc->root : NULL;
8656 return yyjson_val_write_fp(fp, root, flg, alc_ptr, err);
8657}
8658
8659
8660
8661/*==============================================================================
8662 * Mutable JSON Writer Implementation
8663 *============================================================================*/
8664
8665typedef struct yyjson_mut_write_ctx {
8666 usize tag;
8667 yyjson_mut_val *ctn;
8668} yyjson_mut_write_ctx;
8669
8670static_inline void yyjson_mut_write_ctx_set(yyjson_mut_write_ctx *ctx,
8671 yyjson_mut_val *ctn,
8672 usize size, bool is_obj) {
8673 ctx->tag = (size << 1) | (usize)is_obj;
8674 ctx->ctn = ctn;
8675}
8676
8677static_inline void yyjson_mut_write_ctx_get(yyjson_mut_write_ctx *ctx,
8678 yyjson_mut_val **ctn,
8679 usize *size, bool *is_obj) {
8680 usize tag = ctx->tag;
8681 *size = tag >> 1;
8682 *is_obj = (bool)(tag & 1);
8683 *ctn = ctx->ctn;
8684}
8685
8686/** Get the estimated number of values for the mutable JSON document. */
8687static_inline usize yyjson_mut_doc_estimated_val_num(
8688 const yyjson_mut_doc *doc) {
8689 usize sum = 0;
8690 yyjson_val_chunk *chunk = doc->val_pool.chunks;
8691 while (chunk) {
8692 sum += chunk->chunk_size / sizeof(yyjson_mut_val) - 1;
8693 if (chunk == doc->val_pool.chunks) {
8694 sum -= (usize)(doc->val_pool.end - doc->val_pool.cur);
8695 }
8696 chunk = chunk->next;
8697 }
8698 return sum;
8699}
8700
8701/** Write single JSON value. */
8702static_inline u8 *yyjson_mut_write_single(yyjson_mut_val *val,
8703 yyjson_write_flag flg,
8704 yyjson_alc alc,
8705 usize *dat_len,
8706 yyjson_write_err *err) {
8707 return yyjson_write_single((yyjson_val *)val, flg, alc, dat_len, err);
8708}
8709
8710/** Write JSON document minify.
8711 The root of this document should be a non-empty container. */
8712static_inline u8 *yyjson_mut_write_minify(const yyjson_mut_val *root,
8713 usize estimated_val_num,
8714 yyjson_write_flag flg,
8715 yyjson_alc alc,
8716 usize *dat_len,
8717 yyjson_write_err *err) {
8718
8719#define return_err(_code, _msg) do { \
8720 *dat_len = 0; \
8721 err->code = YYJSON_WRITE_ERROR_##_code; \
8722 err->msg = _msg; \
8723 if (hdr) alc.free(alc.ctx, hdr); \
8724 return NULL; \
8725} while (false)
8726
8727#define incr_len(_len) do { \
8728 ext_len = (usize)(_len); \
8729 if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
8730 alc_inc = yyjson_max(alc_len / 2, ext_len); \
8731 alc_inc = size_align_up(alc_inc, sizeof(yyjson_mut_write_ctx)); \
8732 if (size_add_is_overflow(alc_len, alc_inc)) goto fail_alloc; \
8733 alc_len += alc_inc; \
8734 tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
8735 if (unlikely(!tmp)) goto fail_alloc; \
8736 ctx_len = (usize)(end - (u8 *)ctx); \
8737 ctx_tmp = (yyjson_mut_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
8738 memmove((void *)ctx_tmp, (void *)(tmp + ((u8 *)ctx - hdr)), ctx_len); \
8739 ctx = ctx_tmp; \
8740 cur = tmp + (cur - hdr); \
8741 end = tmp + alc_len; \
8742 hdr = tmp; \
8743 } \
8744} while (false)
8745
8746#define check_str_len(_len) do { \
8747 if ((USIZE_MAX < U64_MAX) && (_len >= (USIZE_MAX - 16) / 6)) \
8748 goto fail_alloc; \
8749} while (false)
8750
8751 yyjson_mut_val *val, *ctn;
8752 yyjson_type val_type;
8753 usize ctn_len, ctn_len_tmp;
8754 bool ctn_obj, ctn_obj_tmp, is_key;
8755 u8 *hdr, *cur, *end, *tmp;
8756 yyjson_mut_write_ctx *ctx, *ctx_tmp;
8757 usize alc_len, alc_inc, ctx_len, ext_len, str_len;
8758 const u8 *str_ptr;
8759 const char_enc_type *enc_table = get_enc_table_with_flag(flg);
8760 bool cpy = (enc_table == enc_table_cpy);
8761 bool esc = (flg & YYJSON_WRITE_ESCAPE_UNICODE) != 0;
8762 bool inv = (flg & YYJSON_WRITE_ALLOW_INVALID_UNICODE) != 0;
8763
8764 alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64;
8765 alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx));
8766 hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
8767 if (!hdr) goto fail_alloc;
8768 cur = hdr;
8769 end = hdr + alc_len;
8770 ctx = (yyjson_mut_write_ctx *)(void *)end;
8771
8772doc_begin:
8773 val = constcast(yyjson_mut_val *)root;
8774 val_type = unsafe_yyjson_get_type(val);
8775 ctn_obj = (val_type == YYJSON_TYPE_OBJ);
8776 ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
8777 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
8778 ctn = val;
8779 val = (yyjson_mut_val *)val->uni.ptr; /* tail */
8780 val = ctn_obj ? val->next->next : val->next;
8781
8782val_begin:
8783 val_type = unsafe_yyjson_get_type(val);
8784 if (val_type == YYJSON_TYPE_STR) {
8785 is_key = ((u8)ctn_obj & (u8)~ctn_len);
8786 str_len = unsafe_yyjson_get_len(val);
8787 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
8788 check_str_len(str_len);
8789 incr_len(str_len * 6 + 16);
8790 if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
8791 cur = write_string_noesc(cur, str_ptr, str_len);
8792 } else {
8793 cur = write_string(cur, esc, inv, str_ptr, str_len, enc_table);
8794 if (unlikely(!cur)) goto fail_str;
8795 }
8796 *cur++ = is_key ? ':' : ',';
8797 goto val_end;
8798 }
8799 if (val_type == YYJSON_TYPE_NUM) {
8800 incr_len(32);
8801 cur = write_number(cur, (yyjson_val *)val, flg);
8802 if (unlikely(!cur)) goto fail_num;
8803 *cur++ = ',';
8804 goto val_end;
8805 }
8806 if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
8807 (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
8808 ctn_len_tmp = unsafe_yyjson_get_len(val);
8809 ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
8810 incr_len(16);
8811 if (unlikely(ctn_len_tmp == 0)) {
8812 /* write empty container */
8813 *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
8814 *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
8815 *cur++ = ',';
8816 goto val_end;
8817 } else {
8818 /* push context, setup new container */
8819 yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj);
8820 ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
8821 ctn_obj = ctn_obj_tmp;
8822 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
8823 ctn = val;
8824 val = (yyjson_mut_val *)ctn->uni.ptr; /* tail */
8825 val = ctn_obj ? val->next->next : val->next;
8826 goto val_begin;
8827 }
8828 }
8829 if (val_type == YYJSON_TYPE_BOOL) {
8830 incr_len(16);
8831 cur = write_bool(cur, unsafe_yyjson_get_bool(val));
8832 cur++;
8833 goto val_end;
8834 }
8835 if (val_type == YYJSON_TYPE_NULL) {
8836 incr_len(16);
8837 cur = write_null(cur);
8838 cur++;
8839 goto val_end;
8840 }
8841 if (val_type == YYJSON_TYPE_RAW) {
8842 str_len = unsafe_yyjson_get_len(val);
8843 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
8844 check_str_len(str_len);
8845 incr_len(str_len + 2);
8846 cur = write_raw(cur, str_ptr, str_len);
8847 *cur++ = ',';
8848 goto val_end;
8849 }
8850 goto fail_type;
8851
8852val_end:
8853 ctn_len--;
8854 if (unlikely(ctn_len == 0)) goto ctn_end;
8855 val = val->next;
8856 goto val_begin;
8857
8858ctn_end:
8859 cur--;
8860 *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
8861 *cur++ = ',';
8862 if (unlikely((u8 *)ctx >= end)) goto doc_end;
8863 val = ctn->next;
8864 yyjson_mut_write_ctx_get(ctx++, &ctn, &ctn_len, &ctn_obj);
8865 ctn_len--;
8866 if (likely(ctn_len > 0)) {
8867 goto val_begin;
8868 } else {
8869 goto ctn_end;
8870 }
8871
8872doc_end:
8873 *--cur = '\0';
8874 *dat_len = (usize)(cur - hdr);
8875 err->code = YYJSON_WRITE_SUCCESS;
8876 err->msg = "success";
8877 return hdr;
8878
8879fail_alloc:
8880 return_err(MEMORY_ALLOCATION, "memory allocation failed");
8881fail_type:
8882 return_err(INVALID_VALUE_TYPE, "invalid JSON value type");
8883fail_num:
8884 return_err(NAN_OR_INF, "nan or inf number is not allowed");
8885fail_str:
8886 return_err(INVALID_STRING, "invalid utf-8 encoding in string");
8887
8888#undef return_err
8889#undef incr_len
8890#undef check_str_len
8891}
8892
8893/** Write JSON document pretty.
8894 The root of this document should be a non-empty container. */
8895static_inline u8 *yyjson_mut_write_pretty(const yyjson_mut_val *root,
8896 usize estimated_val_num,
8897 yyjson_write_flag flg,
8898 yyjson_alc alc,
8899 usize *dat_len,
8900 yyjson_write_err *err) {
8901
8902#define return_err(_code, _msg) do { \
8903 *dat_len = 0; \
8904 err->code = YYJSON_WRITE_ERROR_##_code; \
8905 err->msg = _msg; \
8906 if (hdr) alc.free(alc.ctx, hdr); \
8907 return NULL; \
8908} while (false)
8909
8910#define incr_len(_len) do { \
8911 ext_len = (usize)(_len); \
8912 if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
8913 alc_inc = yyjson_max(alc_len / 2, ext_len); \
8914 alc_inc = size_align_up(alc_inc, sizeof(yyjson_mut_write_ctx)); \
8915 if (size_add_is_overflow(alc_len, alc_inc)) goto fail_alloc; \
8916 alc_len += alc_inc; \
8917 tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
8918 if (unlikely(!tmp)) goto fail_alloc; \
8919 ctx_len = (usize)(end - (u8 *)ctx); \
8920 ctx_tmp = (yyjson_mut_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
8921 memmove((void *)ctx_tmp, (void *)(tmp + ((u8 *)ctx - hdr)), ctx_len); \
8922 ctx = ctx_tmp; \
8923 cur = tmp + (cur - hdr); \
8924 end = tmp + alc_len; \
8925 hdr = tmp; \
8926 } \
8927} while (false)
8928
8929#define check_str_len(_len) do { \
8930 if ((USIZE_MAX < U64_MAX) && (_len >= (USIZE_MAX - 16) / 6)) \
8931 goto fail_alloc; \
8932} while (false)
8933
8934 yyjson_mut_val *val, *ctn;
8935 yyjson_type val_type;
8936 usize ctn_len, ctn_len_tmp;
8937 bool ctn_obj, ctn_obj_tmp, is_key, no_indent;
8938 u8 *hdr, *cur, *end, *tmp;
8939 yyjson_mut_write_ctx *ctx, *ctx_tmp;
8940 usize alc_len, alc_inc, ctx_len, ext_len, str_len, level;
8941 const u8 *str_ptr;
8942 const char_enc_type *enc_table = get_enc_table_with_flag(flg);
8943 bool cpy = (enc_table == enc_table_cpy);
8944 bool esc = (flg & YYJSON_WRITE_ESCAPE_UNICODE) != 0;
8945 bool inv = (flg & YYJSON_WRITE_ALLOW_INVALID_UNICODE) != 0;
8946 usize spaces = (flg & YYJSON_WRITE_PRETTY_TWO_SPACES) ? 2 : 4;
8947
8948 alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64;
8949 alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx));
8950 hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
8951 if (!hdr) goto fail_alloc;
8952 cur = hdr;
8953 end = hdr + alc_len;
8954 ctx = (yyjson_mut_write_ctx *)(void *)end;
8955
8956doc_begin:
8957 val = constcast(yyjson_mut_val *)root;
8958 val_type = unsafe_yyjson_get_type(val);
8959 ctn_obj = (val_type == YYJSON_TYPE_OBJ);
8960 ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
8961 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
8962 *cur++ = '\n';
8963 ctn = val;
8964 val = (yyjson_mut_val *)val->uni.ptr; /* tail */
8965 val = ctn_obj ? val->next->next : val->next;
8966 level = 1;
8967
8968val_begin:
8969 val_type = unsafe_yyjson_get_type(val);
8970 if (val_type == YYJSON_TYPE_STR) {
8971 is_key = (bool)((u8)ctn_obj & (u8)~ctn_len);
8972 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
8973 str_len = unsafe_yyjson_get_len(val);
8974 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
8975 check_str_len(str_len);
8976 incr_len(str_len * 6 + 16 + (no_indent ? 0 : level * 4));
8977 cur = write_indent(cur, no_indent ? 0 : level, spaces);
8978 if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
8979 cur = write_string_noesc(cur, str_ptr, str_len);
8980 } else {
8981 cur = write_string(cur, esc, inv, str_ptr, str_len, enc_table);
8982 if (unlikely(!cur)) goto fail_str;
8983 }
8984 *cur++ = is_key ? ':' : ',';
8985 *cur++ = is_key ? ' ' : '\n';
8986 goto val_end;
8987 }
8988 if (val_type == YYJSON_TYPE_NUM) {
8989 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
8990 incr_len(32 + (no_indent ? 0 : level * 4));
8991 cur = write_indent(cur, no_indent ? 0 : level, spaces);
8992 cur = write_number(cur, (yyjson_val *)val, flg);
8993 if (unlikely(!cur)) goto fail_num;
8994 *cur++ = ',';
8995 *cur++ = '\n';
8996 goto val_end;
8997 }
8998 if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
8999 (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
9000 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9001 ctn_len_tmp = unsafe_yyjson_get_len(val);
9002 ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
9003 if (unlikely(ctn_len_tmp == 0)) {
9004 /* write empty container */
9005 incr_len(16 + (no_indent ? 0 : level * 4));
9006 cur = write_indent(cur, no_indent ? 0 : level, spaces);
9007 *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
9008 *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
9009 *cur++ = ',';
9010 *cur++ = '\n';
9011 goto val_end;
9012 } else {
9013 /* push context, setup new container */
9014 incr_len(32 + (no_indent ? 0 : level * 4));
9015 yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj);
9016 ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
9017 ctn_obj = ctn_obj_tmp;
9018 cur = write_indent(cur, no_indent ? 0 : level, spaces);
9019 level++;
9020 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9021 *cur++ = '\n';
9022 ctn = val;
9023 val = (yyjson_mut_val *)ctn->uni.ptr; /* tail */
9024 val = ctn_obj ? val->next->next : val->next;
9025 goto val_begin;
9026 }
9027 }
9028 if (val_type == YYJSON_TYPE_BOOL) {
9029 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9030 incr_len(16 + (no_indent ? 0 : level * 4));
9031 cur = write_indent(cur, no_indent ? 0 : level, spaces);
9032 cur = write_bool(cur, unsafe_yyjson_get_bool(val));
9033 cur += 2;
9034 goto val_end;
9035 }
9036 if (val_type == YYJSON_TYPE_NULL) {
9037 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9038 incr_len(16 + (no_indent ? 0 : level * 4));
9039 cur = write_indent(cur, no_indent ? 0 : level, spaces);
9040 cur = write_null(cur);
9041 cur += 2;
9042 goto val_end;
9043 }
9044 if (val_type == YYJSON_TYPE_RAW) {
9045 str_len = unsafe_yyjson_get_len(val);
9046 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9047 check_str_len(str_len);
9048 incr_len(str_len + 3);
9049 cur = write_raw(cur, str_ptr, str_len);
9050 *cur++ = ',';
9051 *cur++ = '\n';
9052 goto val_end;
9053 }
9054 goto fail_type;
9055
9056val_end:
9057 ctn_len--;
9058 if (unlikely(ctn_len == 0)) goto ctn_end;
9059 val = val->next;
9060 goto val_begin;
9061
9062ctn_end:
9063 cur -= 2;
9064 *cur++ = '\n';
9065 incr_len(level * 4);
9066 cur = write_indent(cur, --level, spaces);
9067 *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
9068 if (unlikely((u8 *)ctx >= end)) goto doc_end;
9069 val = ctn->next;
9070 yyjson_mut_write_ctx_get(ctx++, &ctn, &ctn_len, &ctn_obj);
9071 ctn_len--;
9072 *cur++ = ',';
9073 *cur++ = '\n';
9074 if (likely(ctn_len > 0)) {
9075 goto val_begin;
9076 } else {
9077 goto ctn_end;
9078 }
9079
9080doc_end:
9081 *cur = '\0';
9082 *dat_len = (usize)(cur - hdr);
9083 err->code = YYJSON_WRITE_SUCCESS;
9084 err->msg = "success";
9085 return hdr;
9086
9087fail_alloc:
9088 return_err(MEMORY_ALLOCATION, "memory allocation failed");
9089fail_type:
9090 return_err(INVALID_VALUE_TYPE, "invalid JSON value type");
9091fail_num:
9092 return_err(NAN_OR_INF, "nan or inf number is not allowed");
9093fail_str:
9094 return_err(INVALID_STRING, "invalid utf-8 encoding in string");
9095
9096#undef return_err
9097#undef incr_len
9098#undef check_str_len
9099}
9100
9101static char *yyjson_mut_write_opts_impl(const yyjson_mut_val *val,
9102 usize estimated_val_num,
9103 yyjson_write_flag flg,
9104 const yyjson_alc *alc_ptr,
9105 usize *dat_len,
9106 yyjson_write_err *err) {
9107 yyjson_write_err dummy_err;
9108 usize dummy_dat_len;
9109 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
9110 yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
9111
9112 err = err ? err : &dummy_err;
9113 dat_len = dat_len ? dat_len : &dummy_dat_len;
9114
9115#if YYJSON_DISABLE_NON_STANDARD
9116 flg &= ~YYJSON_WRITE_ALLOW_INF_AND_NAN;
9117 flg &= ~YYJSON_WRITE_ALLOW_INVALID_UNICODE;
9118#endif
9119
9120 if (unlikely(!root)) {
9121 *dat_len = 0;
9122 err->msg = "input JSON is NULL";
9123 err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
9124 return NULL;
9125 }
9126
9127 if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) {
9128 return (char *)yyjson_mut_write_single(root, flg, alc, dat_len, err);
9129 } else if (flg & (YYJSON_WRITE_PRETTY | YYJSON_WRITE_PRETTY_TWO_SPACES)) {
9130 return (char *)yyjson_mut_write_pretty(root, estimated_val_num,
9131 flg, alc, dat_len, err);
9132 } else {
9133 return (char *)yyjson_mut_write_minify(root, estimated_val_num,
9134 flg, alc, dat_len, err);
9135 }
9136}
9137
9138char *yyjson_mut_val_write_opts(const yyjson_mut_val *val,
9139 yyjson_write_flag flg,
9140 const yyjson_alc *alc_ptr,
9141 usize *dat_len,
9142 yyjson_write_err *err) {
9143 return yyjson_mut_write_opts_impl(val, 0, flg, alc_ptr, dat_len, err);
9144}
9145
9146char *yyjson_mut_write_opts(const yyjson_mut_doc *doc,
9147 yyjson_write_flag flg,
9148 const yyjson_alc *alc_ptr,
9149 usize *dat_len,
9150 yyjson_write_err *err) {
9151 yyjson_mut_val *root;
9152 usize estimated_val_num;
9153 if (likely(doc)) {
9154 root = doc->root;
9155 estimated_val_num = yyjson_mut_doc_estimated_val_num(doc);
9156 } else {
9157 root = NULL;
9158 estimated_val_num = 0;
9159 }
9160 return yyjson_mut_write_opts_impl(root, estimated_val_num,
9161 flg, alc_ptr, dat_len, err);
9162}
9163
9164bool yyjson_mut_val_write_file(const char *path,
9165 const yyjson_mut_val *val,
9166 yyjson_write_flag flg,
9167 const yyjson_alc *alc_ptr,
9168 yyjson_write_err *err) {
9169 yyjson_write_err dummy_err;
9170 u8 *dat;
9171 usize dat_len = 0;
9172 yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
9173 bool suc;
9174
9175 alc_ptr = alc_ptr ? alc_ptr : &YYJSON_DEFAULT_ALC;
9176 err = err ? err : &dummy_err;
9177 if (unlikely(!path || !*path)) {
9178 err->msg = "input path is invalid";
9179 err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
9180 return false;
9181 }
9182
9183 dat = (u8 *)yyjson_mut_val_write_opts(root, flg, alc_ptr, &dat_len, err);
9184 if (unlikely(!dat)) return false;
9185 suc = write_dat_to_file(path, dat, dat_len, err);
9186 alc_ptr->free(alc_ptr->ctx, dat);
9187 return suc;
9188}
9189
9190bool yyjson_mut_val_write_fp(FILE *fp,
9191 const yyjson_mut_val *val,
9192 yyjson_write_flag flg,
9193 const yyjson_alc *alc_ptr,
9194 yyjson_write_err *err) {
9195 yyjson_write_err dummy_err;
9196 u8 *dat;
9197 usize dat_len = 0;
9198 yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
9199 bool suc;
9200
9201 alc_ptr = alc_ptr ? alc_ptr : &YYJSON_DEFAULT_ALC;
9202 err = err ? err : &dummy_err;
9203 if (unlikely(!fp)) {
9204 err->msg = "input fp is invalid";
9205 err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
9206 return false;
9207 }
9208
9209 dat = (u8 *)yyjson_mut_val_write_opts(root, flg, alc_ptr, &dat_len, err);
9210 if (unlikely(!dat)) return false;
9211 suc = write_dat_to_fp(fp, dat, dat_len, err);
9212 alc_ptr->free(alc_ptr->ctx, dat);
9213 return suc;
9214}
9215
9216bool yyjson_mut_write_file(const char *path,
9217 const yyjson_mut_doc *doc,
9218 yyjson_write_flag flg,
9219 const yyjson_alc *alc_ptr,
9220 yyjson_write_err *err) {
9221 yyjson_mut_val *root = doc ? doc->root : NULL;
9222 return yyjson_mut_val_write_file(path, root, flg, alc_ptr, err);
9223}
9224
9225bool yyjson_mut_write_fp(FILE *fp,
9226 const yyjson_mut_doc *doc,
9227 yyjson_write_flag flg,
9228 const yyjson_alc *alc_ptr,
9229 yyjson_write_err *err) {
9230 yyjson_mut_val *root = doc ? doc->root : NULL;
9231 return yyjson_mut_val_write_fp(fp, root, flg, alc_ptr, err);
9232}
9233
9234#endif /* YYJSON_DISABLE_WRITER */
9235
9236
9237
9238/*==============================================================================
9239 * Compiler Hint End
9240 *============================================================================*/
9241
9242#if defined(__clang__)
9243# pragma clang diagnostic pop
9244#elif defined(__GNUC__)
9245# if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
9246# pragma GCC diagnostic pop
9247# endif
9248#elif defined(_MSC_VER)
9249# pragma warning(pop)
9250#endif /* warning suppress end */
9251