Pharos 0.7.23
Modern Web Framework & Web App Hosting Service.
Loading...
Searching...
No Matches
yyjson.c
Go to the documentation of this file.
1/*==============================================================================
2 Copyright (c) 2020 YaoYuan <ibireme@gmail.com>
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21 *============================================================================*/
22
23#include "yyjson.h"
24
25
26
27/*==============================================================================
28 * MARK: - Warning Suppress (Private)
29 *============================================================================*/
30
31#if defined(__clang__)
32# pragma clang diagnostic ignored "-Wunused-function"
33# pragma clang diagnostic ignored "-Wunused-parameter"
34# pragma clang diagnostic ignored "-Wunused-label"
35# pragma clang diagnostic ignored "-Wunused-macros"
36# pragma clang diagnostic ignored "-Wunused-variable"
37#elif YYJSON_IS_REAL_GCC && yyjson_gcc_available(4, 2, 0)
38# pragma GCC diagnostic ignored "-Wunused-function"
39# pragma GCC diagnostic ignored "-Wunused-parameter"
40# pragma GCC diagnostic ignored "-Wunused-label"
41# pragma GCC diagnostic ignored "-Wunused-macros"
42# pragma GCC diagnostic ignored "-Wunused-variable"
43#elif defined(_MSC_VER)
44# pragma warning(disable:4100) /* unreferenced formal parameter */
45# pragma warning(disable:4101) /* unreferenced variable */
46# pragma warning(disable:4102) /* unreferenced label */
47# pragma warning(disable:4127) /* conditional expression is constant */
48# pragma warning(disable:4702) /* unreachable code */
49# pragma warning(disable:4706) /* assignment within conditional expression */
50#endif
51
52
53
54/*==============================================================================
55 * MARK: - Version (Public)
56 *============================================================================*/
57
58uint32_t yyjson_version(void) {
59 return YYJSON_VERSION_HEX;
60}
61
62
63
64/*==============================================================================
65 * MARK: - Flags (Private)
66 *============================================================================*/
67
68/* msvc intrinsic */
69#if YYJSON_MSC_VER >= 1400
70# include <intrin.h>
71# if defined(_M_AMD64) || defined(_M_ARM64)
72# define MSC_HAS_BIT_SCAN_64 1
73# pragma intrinsic(_BitScanForward64)
74# pragma intrinsic(_BitScanReverse64)
75# else
76# define MSC_HAS_BIT_SCAN_64 0
77# endif
78# if defined(_M_AMD64) || defined(_M_ARM64) || \
79 defined(_M_IX86) || defined(_M_ARM)
80# define MSC_HAS_BIT_SCAN 1
81# pragma intrinsic(_BitScanForward)
82# pragma intrinsic(_BitScanReverse)
83# else
84# define MSC_HAS_BIT_SCAN 0
85# endif
86# if defined(_M_AMD64)
87# define MSC_HAS_UMUL128 1
88# pragma intrinsic(_umul128)
89# else
90# define MSC_HAS_UMUL128 0
91# endif
92#else
93# define MSC_HAS_BIT_SCAN_64 0
94# define MSC_HAS_BIT_SCAN 0
95# define MSC_HAS_UMUL128 0
96#endif
97
98/* gcc builtin */
99#if yyjson_has_builtin(__builtin_clzll) || yyjson_gcc_available(3, 4, 0)
100# define GCC_HAS_CLZLL 1
101#else
102# define GCC_HAS_CLZLL 0
103#endif
104
105#if yyjson_has_builtin(__builtin_ctzll) || yyjson_gcc_available(3, 4, 0)
106# define GCC_HAS_CTZLL 1
107#else
108# define GCC_HAS_CTZLL 0
109#endif
110
111/* int128 type */
112#ifndef YYJSON_HAS_INT128
113# if defined(__SIZEOF_INT128__) && (__SIZEOF_INT128__ == 16) && \
114 (defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER)) && \
115 (!defined(__EMSCRIPTEN__) && !defined(__wasm__))
116# define YYJSON_HAS_INT128 1
117# else
118# define YYJSON_HAS_INT128 0
119# endif
120#endif
121
122/* IEEE 754 floating-point binary representation */
123#ifndef YYJSON_HAS_IEEE_754
124# if defined(__STDC_IEC_559__) || defined(__STDC_IEC_60559_BFP__)
125# define YYJSON_HAS_IEEE_754 1
126# elif FLT_RADIX == 2 && \
127 FLT_MANT_DIG == 24 && FLT_DIG == 6 && \
128 FLT_MIN_EXP == -125 && FLT_MAX_EXP == 128 && \
129 FLT_MIN_10_EXP == -37 && FLT_MAX_10_EXP == 38 && \
130 DBL_MANT_DIG == 53 && DBL_DIG == 15 && \
131 DBL_MIN_EXP == -1021 && DBL_MAX_EXP == 1024 && \
132 DBL_MIN_10_EXP == -307 && DBL_MAX_10_EXP == 308
133# define YYJSON_HAS_IEEE_754 1
134# else
135# define YYJSON_HAS_IEEE_754 0
136# undef YYJSON_DISABLE_FAST_FP_CONV
137# define YYJSON_DISABLE_FAST_FP_CONV 1
138# endif
139#endif
140
141#if YYJSON_DISABLE_FAST_FP_CONV && YYJSON_FREESTANDING
142# error DISABLE_FAST_FP_CONV and FREESTANDING cannot be used together
143#endif
144
145/* Inf and NaN */
146#ifndef INFINITY
147# ifndef HUGE_VAL
148# define INFINITY ((double)(1.0 / 0.0))
149# else
150# define INFINITY HUGE_VAL
151# endif
152#endif
153#ifndef NAN
154# define NAN ((double)(0.0 / 0.0))
155#endif
156
157/*
158 Correct rounding in double number computations.
159
160 On the x86 architecture, some compilers may use x87 FPU instructions for
161 floating-point arithmetic. The x87 FPU loads all floating-point numbers as
162 80-bit double-extended precision internally, then rounds the result to the
163 original precision, which may produce inaccurate results. For a more detailed
164 explanation, see the paper: https://arxiv.org/abs/cs/0701192
165
166 Here are some examples of double precision calculation error:
167
168 2877.0 / 1e6 == 0.002877, but x87 returns 0.0028770000000000002
169 43683.0 * 1e21 == 4.3683e25, but x87 returns 4.3683000000000004e25
170
171 Here are some examples of compiler flags to generate x87 instructions on x86:
172
173 clang -m32 -mno-sse
174 gcc/icc -m32 -mfpmath=387
175 msvc /arch:SSE or /arch:IA32
176
177 If we are sure that there's no similar error described above, we can define the
178 YYJSON_DOUBLE_MATH_CORRECT as 1 to enable the fast path calculation. This is
179 not an accurate detection; it just tries to avoid the error at compile-time.
180 An accurate detection can be done at run-time:
181
182 bool is_double_math_correct(void) {
183 volatile double r = 43683.0;
184 r *= 1e21;
185 return r == 4.3683e25;
186 }
187
188 See also: utils.h in https://github.com/google/double-conversion/
189 */
190#if !defined(FLT_EVAL_METHOD) && defined(__FLT_EVAL_METHOD__)
191# define FLT_EVAL_METHOD __FLT_EVAL_METHOD__
192#endif
193
194#if defined(FLT_EVAL_METHOD) && FLT_EVAL_METHOD != 0 && FLT_EVAL_METHOD != 1
195# define YYJSON_DOUBLE_MATH_CORRECT 0
196#elif defined(i386) || defined(__i386) || defined(__i386__) || \
197 defined(_X86_) || defined(__X86__) || defined(_M_IX86) || \
198 defined(__I86__) || defined(__IA32__) || defined(__THW_INTEL)
199# if (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP == 2) || \
200 (defined(__SSE2_MATH__) && __SSE2_MATH__)
201# define YYJSON_DOUBLE_MATH_CORRECT 1
202# else
203# define YYJSON_DOUBLE_MATH_CORRECT 0
204# endif
205#elif defined(__mc68000__) || defined(__pnacl__) || defined(__native_client__)
206# define YYJSON_DOUBLE_MATH_CORRECT 0
207#else
208# define YYJSON_DOUBLE_MATH_CORRECT 1
209#endif
210
211/*
212 Detect the endianness at compile-time.
213 YYJSON_ENDIAN == YYJSON_BIG_ENDIAN
214 YYJSON_ENDIAN == YYJSON_LITTLE_ENDIAN
215 */
216#define YYJSON_BIG_ENDIAN 4321
217#define YYJSON_LITTLE_ENDIAN 1234
218
219#if yyjson_has_include(<sys/types.h>)
220# include <sys/types.h> /* POSIX */
221#endif
222#if yyjson_has_include(<endian.h>)
223# include <endian.h> /* Linux */
224#elif yyjson_has_include(<sys/endian.h>)
225# include <sys/endian.h> /* BSD, Android */
226#elif yyjson_has_include(<machine/endian.h>)
227# include <machine/endian.h> /* BSD, Darwin */
228#endif
229
230#if defined(BYTE_ORDER) && BYTE_ORDER
231# if defined(BIG_ENDIAN) && (BYTE_ORDER == BIG_ENDIAN)
232# define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
233# elif defined(LITTLE_ENDIAN) && (BYTE_ORDER == LITTLE_ENDIAN)
234# define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
235# endif
236#elif defined(__BYTE_ORDER) && __BYTE_ORDER
237# if defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN)
238# define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
239# elif defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN)
240# define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
241# endif
242#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__
243# if defined(__ORDER_BIG_ENDIAN__) && \
244 (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
245# define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
246# elif defined(__ORDER_LITTLE_ENDIAN__) && \
247 (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
248# define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
249# endif
250#elif (defined(__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__ == 1) || \
251 defined(__i386) || defined(__i386__) || \
252 defined(_X86_) || defined(__X86__) || \
253 defined(_M_IX86) || defined(__THW_INTEL__) || \
254 defined(__x86_64) || defined(__x86_64__) || \
255 defined(__amd64) || defined(__amd64__) || \
256 defined(_M_AMD64) || defined(_M_X64) || \
257 defined(_M_ARM) || defined(_M_ARM64) || \
258 defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \
259 defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || \
260 defined(__EMSCRIPTEN__) || defined(__wasm__) || \
261 defined(__loongarch__)
262# define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
263#elif (defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ == 1) || \
264 defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \
265 defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) || \
266 defined(__or1k__) || defined(__OR1K__)
267# define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
268#else
269# define YYJSON_ENDIAN 0 /* unknown endian, detect at run-time */
270#endif
271
272/*
273 This macro controls how yyjson handles unaligned memory accesses.
274
275 By default, yyjson uses `memcpy()` for memory copying. This allows the compiler
276 to optimize the code and emit unaligned memory access instructions when
277 supported by the target architecture.
278
279 However, on some older compilers or architectures where `memcpy()` is not
280 well-optimized and may result in unnecessary function calls, defining this
281 macro as 1 may help. In such cases, yyjson switches to manual byte-by-byte
282 access, which can potentially improve performance.
283
284 An example of the generated assembly code for ARM can be found here:
285 https://godbolt.org/z/334jjhxPT
286
287 This flag is already enabled for common architectures in the following code,
288 so manual configuration is usually unnecessary. If unsure, you can check the
289 generated assembly or run benchmarks to make an informed decision.
290 */
291#ifndef YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
292# if defined(__ia64) || defined(_IA64) || defined(__IA64__) || \
293 defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
294# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* Itanium */
295# elif (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) && \
296 (defined(__GNUC__) || defined(__clang__)) && \
297 (!defined(__ARM_FEATURE_UNALIGNED) || !__ARM_FEATURE_UNALIGNED)
298# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* ARM */
299# elif defined(__sparc) || defined(__sparc__)
300# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* SPARC */
301# elif defined(__mips) || defined(__mips__) || defined(__MIPS__)
302# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* MIPS */
303# elif defined(__m68k__) || defined(M68000)
304# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* M68K */
305# else
306# define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 0
307# endif
308#endif
309
310/*
311 Estimated initial ratio of the JSON data (data_size / value_count).
312 For example:
313
314 data: {"id":12345678,"name":"Harry"}
315 data_size: 30
316 value_count: 5
317 ratio: 6
318
319 yyjson uses dynamic memory with a growth factor of 1.5 when reading and writing
320 JSON, the ratios below are used to determine the initial memory size.
321
322 A too large ratio will waste memory, and a too small ratio will cause multiple
323 memory growths and degrade performance. Currently, these ratios are generated
324 with some commonly used JSON datasets.
325 */
326#define YYJSON_READER_ESTIMATED_PRETTY_RATIO 16
327#define YYJSON_READER_ESTIMATED_MINIFY_RATIO 6
328#define YYJSON_WRITER_ESTIMATED_PRETTY_RATIO 32
329#define YYJSON_WRITER_ESTIMATED_MINIFY_RATIO 18
330
331/* The initial and maximum size of the memory pool's chunk in yyjson_mut_doc. */
332#define YYJSON_MUT_DOC_STR_POOL_INIT_SIZE 0x100
333#define YYJSON_MUT_DOC_STR_POOL_MAX_SIZE 0x10000000
334#define YYJSON_MUT_DOC_VAL_POOL_INIT_SIZE (0x10 * sizeof(yyjson_mut_val))
335#define YYJSON_MUT_DOC_VAL_POOL_MAX_SIZE (0x1000000 * sizeof(yyjson_mut_val))
336
337/* The minimum size of the dynamic allocator's chunk. */
338#define YYJSON_ALC_DYN_MIN_SIZE 0x1000
339
340/* Default value for compile-time options. */
341
342#ifndef YYJSON_READER_DEPTH_LIMIT
343#define YYJSON_READER_DEPTH_LIMIT 0
344#endif
345
346/*==============================================================================
347 * MARK: - Macros (Private)
348 *============================================================================*/
349
350/* Macros used for loop unrolling and other purposes. */
351#define repeat2(x) { x x }
352#define repeat4(x) { x x x x }
353#define repeat8(x) { x x x x x x x x }
354#define repeat16(x) { x x x x x x x x x x x x x x x x }
355
356#define repeat2_incr(x) { x(0) x(1) }
357#define repeat4_incr(x) { x(0) x(1) x(2) x(3) }
358#define repeat8_incr(x) { x(0) x(1) x(2) x(3) x(4) x(5) x(6) x(7) }
359#define repeat16_incr(x) { x(0) x(1) x(2) x(3) x(4) x(5) x(6) x(7) \
360 x(8) x(9) x(10) x(11) x(12) x(13) x(14) x(15) }
361#define repeat_in_1_18(x) { x(1) x(2) x(3) x(4) x(5) x(6) x(7) x(8) \
362 x(9) x(10) x(11) x(12) x(13) x(14) x(15) x(16) \
363 x(17) x(18) }
364
365/* Macros used to provide branch prediction information for compiler. */
366#undef likely
367#define likely(x) yyjson_likely(x)
368#undef unlikely
369#define unlikely(x) yyjson_unlikely(x)
370
371/* Macros used to provide inline information for compiler. */
372#undef static_inline
373#define static_inline static yyjson_inline
374#undef static_noinline
375#define static_noinline static yyjson_noinline
376
377/* Macros for min and max. */
378#undef yyjson_min
379#define yyjson_min(x, y) ((x) < (y) ? (x) : (y))
380#undef yyjson_max
381#define yyjson_max(x, y) ((x) > (y) ? (x) : (y))
382
383/* Used to write u64 literal for C89 which doesn't support "ULL" suffix. */
384#undef U64
385#define U64(hi, lo) ((((u64)hi##UL) << 32U) + lo##UL)
386#undef U32
387#define U32(hi) ((u32)(hi##UL))
388
389/* Used to cast away (remove) const qualifier. */
390#define constcast yyjson_constcast
391
392/*
393 Compiler barriers for single variables.
394
395 These macros inform GCC that a read or write access to the given memory
396 location will occur, preventing certain compiler optimizations or reordering
397 around the access to 'val'. They do not emit any actual instructions.
398
399 This is useful when GCC's default optimization strategies are suboptimal and
400 precise control over memory access patterns is required.
401 These barriers are not needed when using Clang or MSVC.
402 */
403#if YYJSON_IS_REAL_GCC
404# define gcc_load_barrier(val) __asm__ volatile(""::"m"(val))
405# define gcc_store_barrier(val) __asm__ volatile("":"=m"(val))
406# define gcc_full_barrier(val) __asm__ volatile("":"=m"(val):"m"(val))
407#else
408# define gcc_load_barrier(val)
409# define gcc_store_barrier(val)
410# define gcc_full_barrier(val)
411#endif
412
413
414
415/*==============================================================================
416 * MARK: - Constants (Private)
417 *============================================================================*/
418
419/* Common error messages. */
420#define MSG_FOPEN "failed to open file"
421#define MSG_FREAD "failed to read file"
422#define MSG_FWRITE "failed to write file"
423#define MSG_FCLOSE "failed to close file"
424#define MSG_MALLOC "failed to allocate memory"
425#define MSG_CHAR_T "invalid literal, expected 'true'"
426#define MSG_CHAR_F "invalid literal, expected 'false'"
427#define MSG_CHAR_N "invalid literal, expected 'null'"
428#define MSG_CHAR "unexpected character, expected a JSON value"
429#define MSG_ARR_END "unexpected character, expected ',' or ']'"
430#define MSG_OBJ_KEY "unexpected character, expected a string key"
431#define MSG_OBJ_SEP "unexpected character, expected ':' after key"
432#define MSG_OBJ_END "unexpected character, expected ',' or '}'"
433#define MSG_GARBAGE "unexpected content after document"
434#define MSG_NOT_END "unexpected end of data"
435#define MSG_COMMENT "unclosed multiline comment"
436#define MSG_COMMA "trailing comma is not allowed"
437#define MSG_NAN_INF "nan or inf number is not allowed"
438#define MSG_ERR_TYPE "invalid JSON value type"
439#define MSG_ERR_BOM "UTF-8 byte order mark (BOM) is not supported"
440#define MSG_ERR_UTF8 "invalid utf-8 encoding in string"
441#define MSG_ERR_UTF16 "UTF-16 encoding is not supported"
442#define MSG_ERR_UTF32 "UTF-32 encoding is not supported"
443#define MSG_DEPTH "depth limit exceeded"
444
445/* U64 constant values */
446#undef U64_MAX
447#define U64_MAX U64(0xFFFFFFFF, 0xFFFFFFFF)
448#undef I64_MAX
449#define I64_MAX U64(0x7FFFFFFF, 0xFFFFFFFF)
450#undef USIZE_MAX
451#define USIZE_MAX ((usize)(~(usize)0))
452
453/* Maximum number of digits for reading u32/u64/usize safety (not overflow). */
454#undef U32_SAFE_DIG
455#define U32_SAFE_DIG 9 /* u32 max is 4294967295, 10 digits */
456#undef U64_SAFE_DIG
457#define U64_SAFE_DIG 19 /* u64 max is 18446744073709551615, 20 digits */
458#undef USIZE_SAFE_DIG
459#define USIZE_SAFE_DIG (sizeof(usize) == 8 ? U64_SAFE_DIG : U32_SAFE_DIG)
460
461/* Inf bits (positive) */
462#define F64_BITS_INF U64(0x7FF00000, 0x00000000)
463
464/* NaN bits (quiet NaN, no payload, no sign) */
465#if defined(__hppa__) || (defined(__mips__) && !defined(__mips_nan2008))
466#define F64_BITS_NAN U64(0x7FF7FFFF, 0xFFFFFFFF)
467#else
468#define F64_BITS_NAN U64(0x7FF80000, 0x00000000)
469#endif
470
471/* maximum significant digits count in decimal when reading double number */
472#define F64_MAX_DEC_DIG 768
473
474/* maximum decimal power of double number (1.7976931348623157e308) */
475#define F64_MAX_DEC_EXP 308
476
477/* minimum decimal power of double number (4.9406564584124654e-324) */
478#define F64_MIN_DEC_EXP (-324)
479
480/* maximum binary power of double number */
481#define F64_MAX_BIN_EXP 1024
482
483/* minimum binary power of double number */
484#define F64_MIN_BIN_EXP (-1021)
485
486/* float/double number bits */
487#define F32_BITS 32
488#define F64_BITS 64
489
490/* float/double number exponent part bits */
491#define F32_EXP_BITS 8
492#define F64_EXP_BITS 11
493
494/* float/double number significand part bits */
495#define F32_SIG_BITS 23
496#define F64_SIG_BITS 52
497
498/* float/double number significand part bits (with 1 hidden bit) */
499#define F32_SIG_FULL_BITS 24
500#define F64_SIG_FULL_BITS 53
501
502/* float/double number significand bit mask */
503#define F32_SIG_MASK U32(0x007FFFFF)
504#define F64_SIG_MASK U64(0x000FFFFF, 0xFFFFFFFF)
505
506/* float/double number exponent bit mask */
507#define F32_EXP_MASK U32(0x7F800000)
508#define F64_EXP_MASK U64(0x7FF00000, 0x00000000)
509
510/* float/double number exponent bias */
511#define F32_EXP_BIAS 127
512#define F64_EXP_BIAS 1023
513
514/* float/double number significant digits count in decimal */
515#define F32_DEC_DIG 9
516#define F64_DEC_DIG 17
517
518/* buffer length required for float/double number writer */
519#define FP_BUF_LEN 40
520
521/* maximum length of a number in incremental parsing */
522#define INCR_NUM_MAX_LEN 1024
523
524
525
526/*==============================================================================
527 * MARK: - Types (Private)
528 *============================================================================*/
529
530/** Type aliases for primitive types. */
531typedef float f32;
532typedef double f64;
533typedef int8_t i8;
534typedef uint8_t u8;
535typedef int16_t i16;
536typedef uint16_t u16;
537typedef int32_t i32;
538typedef uint32_t u32;
539typedef int64_t i64;
540typedef uint64_t u64;
541typedef size_t usize;
542
543/** 128-bit integer, used by floating-point number reader and writer. */
544#if YYJSON_HAS_INT128
545__extension__ typedef __int128 i128;
546__extension__ typedef unsigned __int128 u128;
547#endif
548
549/** 16/32/64-bit vector */
550typedef struct v16 { char c[2]; } v16;
551typedef struct v32 { char c[4]; } v32;
552typedef struct v64 { char c[8]; } v64;
553
554/** 16/32/64-bit vector union */
555typedef union v16_uni { v16 v; u16 u; } v16_uni;
556typedef union v32_uni { v32 v; u32 u; } v32_uni;
557typedef union v64_uni { v64 v; u64 u; } v64_uni;
558
559
560
561/*==============================================================================
562 * MARK: - Load/Store Utils (Private)
563 *============================================================================*/
564
565#define byte_move_idx(x) ((char *)dst)[x] = ((const char *)src)[x];
566#define byte_move_src(x) ((char *)tmp)[x] = ((const char *)src)[x];
567#define byte_move_dst(x) ((char *)dst)[x] = ((const char *)tmp)[x];
568
569/** Same as `memcpy(dst, src, 2)`, no overlap. */
570static_inline void byte_copy_2(void *dst, const void *src) {
571#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
572 memcpy(dst, src, 2);
573#else
575#endif
576}
577
578/** Same as `memcpy(dst, src, 4)`, no overlap. */
579static_inline void byte_copy_4(void *dst, const void *src) {
580#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
581 memcpy(dst, src, 4);
582#else
584#endif
585}
586
587/** Same as `memcpy(dst, src, 8)`, no overlap. */
588static_inline void byte_copy_8(void *dst, const void *src) {
589#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
590 memcpy(dst, src, 8);
591#else
593#endif
594}
595
596/** Same as `memcpy(dst, src, 16)`, no overlap. */
597static_inline void byte_copy_16(void *dst, const void *src) {
598#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
599 memcpy(dst, src, 16);
600#else
602#endif
603}
604
605/** Same as `memmove(dst, src, 2)`, allows overlap. */
606static_inline void byte_move_2(void *dst, const void *src) {
607#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
608 u16 tmp;
609 memcpy(&tmp, src, 2);
610 memcpy(dst, &tmp, 2);
611#else
612 char tmp[2];
615#endif
616}
617
618/** Same as `memmove(dst, src, 4)`, allows overlap. */
619static_inline void byte_move_4(void *dst, const void *src) {
620#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
621 u32 tmp;
622 memcpy(&tmp, src, 4);
623 memcpy(dst, &tmp, 4);
624#else
625 char tmp[4];
628#endif
629}
630
631/** Same as `memmove(dst, src, 8)`, allows overlap. */
632static_inline void byte_move_8(void *dst, const void *src) {
633#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
634 u64 tmp;
635 memcpy(&tmp, src, 8);
636 memcpy(dst, &tmp, 8);
637#else
638 char tmp[8];
641#endif
642}
643
644/** Same as `memmove(dst, src, 16)`, allows overlap. */
645static_inline void byte_move_16(void *dst, const void *src) {
646#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
647 char *pdst = (char *)dst;
648 const char *psrc = (const char *)src;
649 u64 tmp1, tmp2;
650 memcpy(&tmp1, psrc, 8);
651 memcpy(&tmp2, psrc + 8, 8);
652 memcpy(pdst, &tmp1, 8);
653 memcpy(pdst + 8, &tmp2, 8);
654#else
655 char tmp[16];
658#endif
659}
660
661/** Same as `memmove(dst, src, n)`, but only `dst <= src` and `n <= 16`. */
662static_inline void byte_move_forward(void *dst, void *src, usize n) {
663 char *d = (char *)dst, *s = (char *)src;
664 n += (n % 2); /* round up to even */
665 if (n == 16) { byte_move_16(d, s); return; }
666 if (n >= 8) { byte_move_8(d, s); n -= 8; d += 8; s += 8; }
667 if (n >= 4) { byte_move_4(d, s); n -= 4; d += 4; s += 4; }
668 if (n >= 2) { byte_move_2(d, s); }
669}
670
671/** Same as `memcmp(buf, pat, 2) == 0`. */
672static_inline bool byte_match_2(void *buf, const char *pat) {
673#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
674 v16_uni u1, u2;
675 memcpy(&u1, buf, 2);
676 memcpy(&u2, pat, 2);
677 return u1.u == u2.u;
678#else
679 return ((char *)buf)[0] == ((const char *)pat)[0] &&
680 ((char *)buf)[1] == ((const char *)pat)[1];
681#endif
682}
683
684/** Same as `memcmp(buf, pat, 4) == 0`. */
685static_inline bool byte_match_4(void *buf, const char *pat) {
686#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
687 v32_uni u1, u2;
688 memcpy(&u1, buf, 4);
689 memcpy(&u2, pat, 4);
690 return u1.u == u2.u;
691#else
692 return ((char *)buf)[0] == ((const char *)pat)[0] &&
693 ((char *)buf)[1] == ((const char *)pat)[1] &&
694 ((char *)buf)[2] == ((const char *)pat)[2] &&
695 ((char *)buf)[3] == ((const char *)pat)[3];
696#endif
697}
698
699/** Loads 2 bytes from `src` as a u16 (native-endian). */
700static_inline u16 byte_load_2(const void *src) {
701 v16_uni uni;
702#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
703 memcpy(&uni, src, 2);
704#else
705 uni.v.c[0] = ((const char *)src)[0];
706 uni.v.c[1] = ((const char *)src)[1];
707#endif
708 return uni.u;
709}
710
711/** Loads 3 bytes from `src` as a u32 (native-endian). */
712static_inline u32 byte_load_3(const void *src) {
713 v32_uni uni;
714#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
715 memcpy(&uni, src, 2);
716 uni.v.c[2] = ((const char *)src)[2];
717 uni.v.c[3] = 0;
718#else
719 uni.v.c[0] = ((const char *)src)[0];
720 uni.v.c[1] = ((const char *)src)[1];
721 uni.v.c[2] = ((const char *)src)[2];
722 uni.v.c[3] = 0;
723#endif
724 return uni.u;
725}
726
727/** Loads 4 bytes from `src` as a u32 (native-endian). */
728static_inline u32 byte_load_4(const void *src) {
729 v32_uni uni;
730#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
731 memcpy(&uni, src, 4);
732#else
733 uni.v.c[0] = ((const char *)src)[0];
734 uni.v.c[1] = ((const char *)src)[1];
735 uni.v.c[2] = ((const char *)src)[2];
736 uni.v.c[3] = ((const char *)src)[3];
737#endif
738 return uni.u;
739}
740
741
742
743/*==============================================================================
744 * MARK: - Character Utils (Private)
745 * These lookup tables were generated by `misc/make_tables.c`.
746 *============================================================================*/
747
748/* char_table1 */
749#define CHAR_TYPE_ASCII (1 << 0) /* Except: ["\‍], [0x00-0x1F, 0x80-0xFF] */
750#define CHAR_TYPE_ASCII_SQ (1 << 1) /* Except: ['\‍], [0x00-0x1F, 0x80-0xFF] */
751#define CHAR_TYPE_SPACE (1 << 2) /* Whitespace: [ \t\n\r] */
752#define CHAR_TYPE_SPACE_EXT (1 << 3) /* Whitespace: [ \t\n\r\v\f], JSON5 */
753#define CHAR_TYPE_NUM (1 << 4) /* Number: [.-+0-9] */
754#define CHAR_TYPE_COMMENT (1 << 5) /* Comment: [/] */
755
756/* char_table2 */
757#define CHAR_TYPE_EOL (1 << 0) /* End of line: [\r\n] */
758#define CHAR_TYPE_EOL_EXT (1 << 1) /* End of line: [\r\n], JSON5 */
759#define CHAR_TYPE_ID_START (1 << 2) /* ID start: [_$A-Za-z\‍], U+0080+ */
760#define CHAR_TYPE_ID_NEXT (1 << 3) /* ID next: [_$A-Za-z0-9\‍], U+0080+ */
761#define CHAR_TYPE_ID_ASCII (1 << 4) /* ID next ASCII: [_$A-Za-z0-9] */
762
763/* char_table3 */
764#define CHAR_TYPE_SIGN (1 << 0) /* [-+] */
765#define CHAR_TYPE_DIGIT (1 << 1) /* [0-9] */
766#define CHAR_TYPE_NONZERO (1 << 2) /* [1-9] */
767#define CHAR_TYPE_EXP (1 << 3) /* [eE] */
768#define CHAR_TYPE_DOT (1 << 4) /* [.] */
769
770static const u8 char_table1[256] = {
771 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
772 0x00, 0x0C, 0x0C, 0x08, 0x08, 0x0C, 0x00, 0x00,
773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
774 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
775 0x0F, 0x03, 0x02, 0x03, 0x03, 0x03, 0x03, 0x01,
776 0x03, 0x03, 0x03, 0x13, 0x03, 0x13, 0x13, 0x23,
777 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
778 0x13, 0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
779 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
780 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
781 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
782 0x03, 0x03, 0x03, 0x03, 0x00, 0x03, 0x03, 0x03,
783 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
784 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
785 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
786 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
787 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
788 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
789 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
790 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
791 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
792 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
793 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
794 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
795 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
796 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
797 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
798 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
799 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
800 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
801 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
802 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
803};
804
805static const u8 char_table2[256] = {
806 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
807 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
808 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
809 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
810 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
811 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
812 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
813 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
814 0x00, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
815 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
816 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
817 0x1C, 0x1C, 0x1C, 0x00, 0x0C, 0x00, 0x00, 0x1C,
818 0x00, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
819 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
820 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
821 0x1C, 0x1C, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00,
822 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
823 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
824 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
825 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
826 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
827 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
828 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
829 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
830 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
831 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
832 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
833 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
834 0x0C, 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
835 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
836 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
837 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C
838};
839
840static const u8 char_table3[256] = {
841 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
842 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
843 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
844 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
845 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
846 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x10, 0x00,
847 0x02, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
848 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
849 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
850 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
851 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
852 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
853 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
854 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
855 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
856 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
857 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
858 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
859 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
860 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
861 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
862 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
863 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
864 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
865 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
866 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
867 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
868 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
869 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
870 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
871 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
872 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
873};
874
875/** Match a whitespace: [ \t\n\r]. */
877 return !!(char_table1[c] & CHAR_TYPE_SPACE);
878}
879
880/** Match an extended whitespace: [ \t\n\r\\v\\f], JSON5 whitespace. */
884
885/** Match a JSON number: [.-+0-9]. */
887 return !!(char_table1[c] & CHAR_TYPE_NUM);
888}
889
890/** Match an ASCII character in string: ["\‍], [0x00-0x1F, 0x80-0xFF]. */
894
895/** Match an ASCII character single-quoted: ['\‍], [0x00-0x1F, 0x80-0xFF]. */
899
900/** Match a trivia character: extended whitespace or comment. */
904
905/** Match a line end character: [\r\n]. */
907 return !!(char_table2[c] & CHAR_TYPE_EOL);
908}
909
910/** Match an extended line end character: [\r\n], JSON5 line terminator. */
914
915/** Match an identifier name start: [_$A-Za-z\‍], U+0080+. */
919
920/** Match an identifier name next: [_$A-Za-z0-9\‍], U+0080+. */
924
925/** Match an identifier name ASCII: [_$A-Za-z0-9]. */
929
930/** Match a sign: [+-] */
932 return !!(char_table3[d] & CHAR_TYPE_SIGN);
933}
934
935/** Match a non-zero digit: [1-9] */
939
940/** Match a digit: [0-9] */
942 return !!(char_table3[d] & CHAR_TYPE_DIGIT);
943}
944
945/** Match an exponent character: [eE]. */
947 return !!(char_table3[d] & CHAR_TYPE_EXP);
948}
949
950/** Match a floating point indicator: [.eE]. */
952 return !!(char_table3[d] & (CHAR_TYPE_DOT | CHAR_TYPE_EXP));
953}
954
955/** Match a digit or floating point indicator: [0-9.eE]. */
960
961/** Match a JSON container: `{` or `[`. */
963 return (c & 0xDF) == 0x5B; /* '[': 0x5B, '{': 0x7B */
964}
965
966/** Convert ASCII letter to lowercase; valid only for [A-Za-z]. */
968 return c | 0x20;
969}
970
971/** Match UTF-8 byte order mask. */
972static_inline bool is_utf8_bom(const u8 *cur) {
973 return byte_load_3(cur) == byte_load_3("\xEF\xBB\xBF");
974}
975
976/** Match UTF-16 byte order mask. */
977static_inline bool is_utf16_bom(const u8 *cur) {
978 return byte_load_2(cur) == byte_load_2("\xFE\xFF") ||
979 byte_load_2(cur) == byte_load_2("\xFF\xFE");
980}
981
982/** Match UTF-32 byte order mask, need length check to avoid zero padding. */
983static_inline bool is_utf32_bom(const u8 *cur) {
984 return byte_load_4(cur) == byte_load_4("\x00\x00\xFE\xFF") ||
985 byte_load_4(cur) == byte_load_4("\xFF\xFE\x00\x00");
986}
987
988/** Get the extended line end length. Used with `char_is_eol_ext`. */
990 if (cur[0] < 0x80) return 1;
991 if (cur[1] == 0x80 && (cur[2] == 0xA8 || cur[2] == 0xA9)) return 3;
992 return 0;
993}
994
995/** Get the extended whitespace length. Used with `char_is_space_ext`. */
997 if (cur[0] < 0x80) {
998 return 1;
999 } else if (byte_load_2(cur) == byte_load_2("\xC2\xA0")) {
1000 return 2;
1001 } else if (byte_load_2(cur) == byte_load_2("\xE2\x80")) {
1002 if (cur[2] >= 0x80 && cur[2] <= 0x8A) return 3;
1003 if (cur[2] == 0xA8 || cur[2] == 0xA9 || cur[2] == 0xAF) return 3;
1004 } else {
1005 u32 uni = byte_load_3(cur);
1006 if (uni == byte_load_3("\xE1\x9A\x80") ||
1007 uni == byte_load_3("\xE2\x81\x9F") ||
1008 uni == byte_load_3("\xE3\x80\x80") ||
1009 uni == byte_load_3("\xEF\xBB\xBF")) return 3;
1010 }
1011 return 0;
1012}
1013
1014
1015
1016/*==============================================================================
1017 * MARK: - Hex Character Reader (Private)
1018 * This function is used by JSON reader to read escaped characters.
1019 *============================================================================*/
1020
1021/**
1022 This table is used to convert a 4-hex-character sequence to a number.
1023 A valid hex character [0-9A-Fa-f] is mapped to its raw value [0x00, 0x0F];
1024 an invalid hex character is mapped to [0xF0].
1025 (generated with misc/make_tables.c)
1026 */
1027static const u8 hex_conv_table[256] = {
1028 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1029 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1030 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1031 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1032 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1033 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1034 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1035 0x08, 0x09, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1036 0xF0, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF0,
1037 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1038 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1039 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1040 0xF0, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF0,
1041 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1042 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1043 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1044 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1045 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1046 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1047 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1048 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1049 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1050 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1051 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1052 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1053 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1054 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1055 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1056 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1057 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1058 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
1059 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0
1060};
1061
1062/** Load 4 hex characters to `u16`, return true on valid input. */
1063static_inline bool hex_load_4(const u8 *src, u16 *dst) {
1064 u16 c0 = hex_conv_table[src[0]];
1065 u16 c1 = hex_conv_table[src[1]];
1066 u16 c2 = hex_conv_table[src[2]];
1067 u16 c3 = hex_conv_table[src[3]];
1068 u16 t0 = (u16)((c0 << 8) | c2);
1069 u16 t1 = (u16)((c1 << 8) | c3);
1070 *dst = (u16)((t0 << 4) | t1);
1071 return ((t0 | t1) & (u16)0xF0F0) == 0;
1072}
1073
1074/** Load 2 hex characters to `u8`, return true on valid input. */
1075static_inline bool hex_load_2(const u8 *src, u8 *dst) {
1076 u8 c0 = hex_conv_table[src[0]];
1077 u8 c1 = hex_conv_table[src[1]];
1078 *dst = (u8)((c0 << 4) | c1);
1079 return ((c0 | c1) & 0xF0) == 0;
1080}
1081
1082/** Match a hexadecimal numeric character: [0-9a-fA-F]. */
1084 return hex_conv_table[c] != 0xF0;
1085}
1086
1087
1088
1089/*==============================================================================
1090 * MARK: - UTF8 Validation (Private)
1091 * Each Unicode code point is encoded using 1 to 4 bytes in UTF-8.
1092 * Validation is performed using a 4-byte mask and pattern-based approach,
1093 * which requires the input data to be padded with four zero bytes at the end.
1094 *============================================================================*/
1095
1096/* Macro for concatenating four u8 into a u32 and keeping the byte order. */
1097#if YYJSON_ENDIAN == YYJSON_LITTLE_ENDIAN
1098# define utf8_seq_def(name, a, b, c, d) \
1099 static const u32 utf8_seq_##name = 0x##d##c##b##a##UL;
1100# define utf8_seq(name) utf8_seq_##name
1101#elif YYJSON_ENDIAN == YYJSON_BIG_ENDIAN
1102# define utf8_seq_def(name, a, b, c, d) \
1103 static const u32 utf8_seq_##name = 0x##a##b##c##d##UL;
1104# define utf8_seq(name) utf8_seq_##name
1105#else
1106# define utf8_seq_def(name, a, b, c, d) \
1107 static const v32_uni utf8_uni_##name = {{ 0x##a, 0x##b, 0x##c, 0x##d }};
1108# define utf8_seq(name) utf8_uni_##name.u
1109#endif
1110
1111/*
1112 1-byte sequence (U+0000 to U+007F)
1113 bit min [.......0] (U+0000)
1114 bit max [.1111111] (U+007F)
1115 bit mask [x.......] (80)
1116 bit pattern [0.......] (00)
1117 */
1118utf8_seq_def(b1_mask, 80, 00, 00, 00)
1119utf8_seq_def(b1_patt, 00, 00, 00, 00)
1120#define is_utf8_seq1(uni) ( \
1121 ((uni & utf8_seq(b1_mask)) == utf8_seq(b1_patt)) )
1122
1123/*
1124 2-byte sequence (U+0080 to U+07FF)
1125 bit min [......10 ..000000] (U+0080)
1126 bit max [...11111 ..111111] (U+07FF)
1127 bit mask [xxx..... xx......] (E0 C0)
1128 bit pattern [110..... 10......] (C0 80)
1129 bit require [...xxxx. ........] (1E 00)
1130 */
1131utf8_seq_def(b2_mask, E0, C0, 00, 00)
1132utf8_seq_def(b2_patt, C0, 80, 00, 00)
1133utf8_seq_def(b2_requ, 1E, 00, 00, 00)
1134#define is_utf8_seq2(uni) ( \
1135 ((uni & utf8_seq(b2_mask)) == utf8_seq(b2_patt)) && \
1136 ((uni & utf8_seq(b2_requ))) )
1137
1138/*
1139 3-byte sequence (U+0800 to U+FFFF)
1140 bit min [........ ..100000 ..000000] (U+0800)
1141 bit max [....1111 ..111111 ..111111] (U+FFFF)
1142 bit mask [xxxx.... xx...... xx......] (F0 C0 C0)
1143 bit pattern [1110.... 10...... 10......] (E0 80 80)
1144 bit require [....xxxx ..x..... ........] (0F 20 00)
1145
1146 3-byte invalid sequence, reserved for surrogate halves (U+D800 to U+DFFF)
1147 bit min [....1101 ..100000 ..000000] (U+D800)
1148 bit max [....1101 ..111111 ..111111] (U+DFFF)
1149 bit mask [....xxxx ..x..... ........] (0F 20 00)
1150 bit pattern [....1101 ..1..... ........] (0D 20 00)
1151 */
1152utf8_seq_def(b3_mask, F0, C0, C0, 00)
1153utf8_seq_def(b3_patt, E0, 80, 80, 00)
1154utf8_seq_def(b3_requ, 0F, 20, 00, 00)
1155utf8_seq_def(b3_erro, 0D, 20, 00, 00)
1156#define is_utf8_seq3(uni) ( \
1157 ((uni & utf8_seq(b3_mask)) == utf8_seq(b3_patt)) && \
1158 ((tmp = (uni & utf8_seq(b3_requ)))) && \
1159 ((tmp != utf8_seq(b3_erro))) )
1160
1161/*
1162 4-byte sequence (U+10000 to U+10FFFF)
1163 bit min [........ ...10000 ..000000 ..000000] (U+10000)
1164 bit max [.....100 ..001111 ..111111 ..111111] (U+10FFFF)
1165 bit mask [xxxxx... xx...... xx...... xx......] (F8 C0 C0 C0)
1166 bit pattern [11110... 10...... 10...... 10......] (F0 80 80 80)
1167 bit require [.....xxx ..xx.... ........ ........] (07 30 00 00)
1168 bit require 1 [.....x.. ........ ........ ........] (04 00 00 00)
1169 bit require 2 [......xx ..xx.... ........ ........] (03 30 00 00)
1170 */
1171utf8_seq_def(b4_mask, F8, C0, C0, C0)
1172utf8_seq_def(b4_patt, F0, 80, 80, 80)
1173utf8_seq_def(b4_requ, 07, 30, 00, 00)
1174utf8_seq_def(b4_req1, 04, 00, 00, 00)
1175utf8_seq_def(b4_req2, 03, 30, 00, 00)
1176#define is_utf8_seq4(uni) ( \
1177 ((uni & utf8_seq(b4_mask)) == utf8_seq(b4_patt)) && \
1178 ((tmp = (uni & utf8_seq(b4_requ)))) && \
1179 ((tmp & utf8_seq(b4_req1)) == 0 || (tmp & utf8_seq(b4_req2)) == 0) )
1180
1181
1182
1183/*==============================================================================
1184 * MARK: - Power10 Lookup Table (Private)
1185 * These data are used by the floating-point number reader and writer.
1186 *============================================================================*/
1187
1188#if !YYJSON_DISABLE_FAST_FP_CONV
1189
1190/** Maximum pow10 exponent that can be represented exactly as a float64. */
1191#define F64_POW10_MAX_EXACT_EXP 22
1192
1193#if YYJSON_DOUBLE_MATH_CORRECT
1194/** Cached pow10 table. */
1195static const f64 f64_pow10_table[F64_POW10_MAX_EXACT_EXP + 1] = {
1196 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12,
1197 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22
1198};
1199#endif
1200
1201/** Maximum pow10 exponent that can be represented exactly as a uint64. */
1202#define U64_POW10_MAX_EXACT_EXP 19
1203
1204/** Table: [ 10^0, ..., 10^19 ] (generated with misc/make_tables.c) */
1205static const u64 u64_pow10_table[U64_POW10_MAX_EXACT_EXP + 1] = {
1206 U64(0x00000000, 0x00000001), U64(0x00000000, 0x0000000A),
1207 U64(0x00000000, 0x00000064), U64(0x00000000, 0x000003E8),
1208 U64(0x00000000, 0x00002710), U64(0x00000000, 0x000186A0),
1209 U64(0x00000000, 0x000F4240), U64(0x00000000, 0x00989680),
1210 U64(0x00000000, 0x05F5E100), U64(0x00000000, 0x3B9ACA00),
1211 U64(0x00000002, 0x540BE400), U64(0x00000017, 0x4876E800),
1212 U64(0x000000E8, 0xD4A51000), U64(0x00000918, 0x4E72A000),
1213 U64(0x00005AF3, 0x107A4000), U64(0x00038D7E, 0xA4C68000),
1214 U64(0x002386F2, 0x6FC10000), U64(0x01634578, 0x5D8A0000),
1215 U64(0x0DE0B6B3, 0xA7640000), U64(0x8AC72304, 0x89E80000)
1216};
1217
1218/** Minimum decimal exponent in pow10_sig_table. */
1219#define POW10_SIG_TABLE_MIN_EXP -343
1220
1221/** Maximum decimal exponent in pow10_sig_table. */
1222#define POW10_SIG_TABLE_MAX_EXP 324
1223
1224/** Minimum exact decimal exponent in pow10_sig_table */
1225#define POW10_SIG_TABLE_MIN_EXACT_EXP 0
1226
1227/** Maximum exact decimal exponent in pow10_sig_table */
1228#define POW10_SIG_TABLE_MAX_EXACT_EXP 55
1229
1230/** Normalized significant 128 bits of pow10, not rounded up (size: 10.4KB).
1231 This lookup table is used by both the double number reader and writer.
1232 (generated with misc/make_tables.c) */
1233static const u64 pow10_sig_table[] = {
1234 U64(0xBF29DCAB, 0xA82FDEAE), U64(0x7432EE87, 0x3880FC33), /* ~= 10^-343 */
1235 U64(0xEEF453D6, 0x923BD65A), U64(0x113FAA29, 0x06A13B3F), /* ~= 10^-342 */
1236 U64(0x9558B466, 0x1B6565F8), U64(0x4AC7CA59, 0xA424C507), /* ~= 10^-341 */
1237 U64(0xBAAEE17F, 0xA23EBF76), U64(0x5D79BCF0, 0x0D2DF649), /* ~= 10^-340 */
1238 U64(0xE95A99DF, 0x8ACE6F53), U64(0xF4D82C2C, 0x107973DC), /* ~= 10^-339 */
1239 U64(0x91D8A02B, 0xB6C10594), U64(0x79071B9B, 0x8A4BE869), /* ~= 10^-338 */
1240 U64(0xB64EC836, 0xA47146F9), U64(0x9748E282, 0x6CDEE284), /* ~= 10^-337 */
1241 U64(0xE3E27A44, 0x4D8D98B7), U64(0xFD1B1B23, 0x08169B25), /* ~= 10^-336 */
1242 U64(0x8E6D8C6A, 0xB0787F72), U64(0xFE30F0F5, 0xE50E20F7), /* ~= 10^-335 */
1243 U64(0xB208EF85, 0x5C969F4F), U64(0xBDBD2D33, 0x5E51A935), /* ~= 10^-334 */
1244 U64(0xDE8B2B66, 0xB3BC4723), U64(0xAD2C7880, 0x35E61382), /* ~= 10^-333 */
1245 U64(0x8B16FB20, 0x3055AC76), U64(0x4C3BCB50, 0x21AFCC31), /* ~= 10^-332 */
1246 U64(0xADDCB9E8, 0x3C6B1793), U64(0xDF4ABE24, 0x2A1BBF3D), /* ~= 10^-331 */
1247 U64(0xD953E862, 0x4B85DD78), U64(0xD71D6DAD, 0x34A2AF0D), /* ~= 10^-330 */
1248 U64(0x87D4713D, 0x6F33AA6B), U64(0x8672648C, 0x40E5AD68), /* ~= 10^-329 */
1249 U64(0xA9C98D8C, 0xCB009506), U64(0x680EFDAF, 0x511F18C2), /* ~= 10^-328 */
1250 U64(0xD43BF0EF, 0xFDC0BA48), U64(0x0212BD1B, 0x2566DEF2), /* ~= 10^-327 */
1251 U64(0x84A57695, 0xFE98746D), U64(0x014BB630, 0xF7604B57), /* ~= 10^-326 */
1252 U64(0xA5CED43B, 0x7E3E9188), U64(0x419EA3BD, 0x35385E2D), /* ~= 10^-325 */
1253 U64(0xCF42894A, 0x5DCE35EA), U64(0x52064CAC, 0x828675B9), /* ~= 10^-324 */
1254 U64(0x818995CE, 0x7AA0E1B2), U64(0x7343EFEB, 0xD1940993), /* ~= 10^-323 */
1255 U64(0xA1EBFB42, 0x19491A1F), U64(0x1014EBE6, 0xC5F90BF8), /* ~= 10^-322 */
1256 U64(0xCA66FA12, 0x9F9B60A6), U64(0xD41A26E0, 0x77774EF6), /* ~= 10^-321 */
1257 U64(0xFD00B897, 0x478238D0), U64(0x8920B098, 0x955522B4), /* ~= 10^-320 */
1258 U64(0x9E20735E, 0x8CB16382), U64(0x55B46E5F, 0x5D5535B0), /* ~= 10^-319 */
1259 U64(0xC5A89036, 0x2FDDBC62), U64(0xEB2189F7, 0x34AA831D), /* ~= 10^-318 */
1260 U64(0xF712B443, 0xBBD52B7B), U64(0xA5E9EC75, 0x01D523E4), /* ~= 10^-317 */
1261 U64(0x9A6BB0AA, 0x55653B2D), U64(0x47B233C9, 0x2125366E), /* ~= 10^-316 */
1262 U64(0xC1069CD4, 0xEABE89F8), U64(0x999EC0BB, 0x696E840A), /* ~= 10^-315 */
1263 U64(0xF148440A, 0x256E2C76), U64(0xC00670EA, 0x43CA250D), /* ~= 10^-314 */
1264 U64(0x96CD2A86, 0x5764DBCA), U64(0x38040692, 0x6A5E5728), /* ~= 10^-313 */
1265 U64(0xBC807527, 0xED3E12BC), U64(0xC6050837, 0x04F5ECF2), /* ~= 10^-312 */
1266 U64(0xEBA09271, 0xE88D976B), U64(0xF7864A44, 0xC633682E), /* ~= 10^-311 */
1267 U64(0x93445B87, 0x31587EA3), U64(0x7AB3EE6A, 0xFBE0211D), /* ~= 10^-310 */
1268 U64(0xB8157268, 0xFDAE9E4C), U64(0x5960EA05, 0xBAD82964), /* ~= 10^-309 */
1269 U64(0xE61ACF03, 0x3D1A45DF), U64(0x6FB92487, 0x298E33BD), /* ~= 10^-308 */
1270 U64(0x8FD0C162, 0x06306BAB), U64(0xA5D3B6D4, 0x79F8E056), /* ~= 10^-307 */
1271 U64(0xB3C4F1BA, 0x87BC8696), U64(0x8F48A489, 0x9877186C), /* ~= 10^-306 */
1272 U64(0xE0B62E29, 0x29ABA83C), U64(0x331ACDAB, 0xFE94DE87), /* ~= 10^-305 */
1273 U64(0x8C71DCD9, 0xBA0B4925), U64(0x9FF0C08B, 0x7F1D0B14), /* ~= 10^-304 */
1274 U64(0xAF8E5410, 0x288E1B6F), U64(0x07ECF0AE, 0x5EE44DD9), /* ~= 10^-303 */
1275 U64(0xDB71E914, 0x32B1A24A), U64(0xC9E82CD9, 0xF69D6150), /* ~= 10^-302 */
1276 U64(0x892731AC, 0x9FAF056E), U64(0xBE311C08, 0x3A225CD2), /* ~= 10^-301 */
1277 U64(0xAB70FE17, 0xC79AC6CA), U64(0x6DBD630A, 0x48AAF406), /* ~= 10^-300 */
1278 U64(0xD64D3D9D, 0xB981787D), U64(0x092CBBCC, 0xDAD5B108), /* ~= 10^-299 */
1279 U64(0x85F04682, 0x93F0EB4E), U64(0x25BBF560, 0x08C58EA5), /* ~= 10^-298 */
1280 U64(0xA76C5823, 0x38ED2621), U64(0xAF2AF2B8, 0x0AF6F24E), /* ~= 10^-297 */
1281 U64(0xD1476E2C, 0x07286FAA), U64(0x1AF5AF66, 0x0DB4AEE1), /* ~= 10^-296 */
1282 U64(0x82CCA4DB, 0x847945CA), U64(0x50D98D9F, 0xC890ED4D), /* ~= 10^-295 */
1283 U64(0xA37FCE12, 0x6597973C), U64(0xE50FF107, 0xBAB528A0), /* ~= 10^-294 */
1284 U64(0xCC5FC196, 0xFEFD7D0C), U64(0x1E53ED49, 0xA96272C8), /* ~= 10^-293 */
1285 U64(0xFF77B1FC, 0xBEBCDC4F), U64(0x25E8E89C, 0x13BB0F7A), /* ~= 10^-292 */
1286 U64(0x9FAACF3D, 0xF73609B1), U64(0x77B19161, 0x8C54E9AC), /* ~= 10^-291 */
1287 U64(0xC795830D, 0x75038C1D), U64(0xD59DF5B9, 0xEF6A2417), /* ~= 10^-290 */
1288 U64(0xF97AE3D0, 0xD2446F25), U64(0x4B057328, 0x6B44AD1D), /* ~= 10^-289 */
1289 U64(0x9BECCE62, 0x836AC577), U64(0x4EE367F9, 0x430AEC32), /* ~= 10^-288 */
1290 U64(0xC2E801FB, 0x244576D5), U64(0x229C41F7, 0x93CDA73F), /* ~= 10^-287 */
1291 U64(0xF3A20279, 0xED56D48A), U64(0x6B435275, 0x78C1110F), /* ~= 10^-286 */
1292 U64(0x9845418C, 0x345644D6), U64(0x830A1389, 0x6B78AAA9), /* ~= 10^-285 */
1293 U64(0xBE5691EF, 0x416BD60C), U64(0x23CC986B, 0xC656D553), /* ~= 10^-284 */
1294 U64(0xEDEC366B, 0x11C6CB8F), U64(0x2CBFBE86, 0xB7EC8AA8), /* ~= 10^-283 */
1295 U64(0x94B3A202, 0xEB1C3F39), U64(0x7BF7D714, 0x32F3D6A9), /* ~= 10^-282 */
1296 U64(0xB9E08A83, 0xA5E34F07), U64(0xDAF5CCD9, 0x3FB0CC53), /* ~= 10^-281 */
1297 U64(0xE858AD24, 0x8F5C22C9), U64(0xD1B3400F, 0x8F9CFF68), /* ~= 10^-280 */
1298 U64(0x91376C36, 0xD99995BE), U64(0x23100809, 0xB9C21FA1), /* ~= 10^-279 */
1299 U64(0xB5854744, 0x8FFFFB2D), U64(0xABD40A0C, 0x2832A78A), /* ~= 10^-278 */
1300 U64(0xE2E69915, 0xB3FFF9F9), U64(0x16C90C8F, 0x323F516C), /* ~= 10^-277 */
1301 U64(0x8DD01FAD, 0x907FFC3B), U64(0xAE3DA7D9, 0x7F6792E3), /* ~= 10^-276 */
1302 U64(0xB1442798, 0xF49FFB4A), U64(0x99CD11CF, 0xDF41779C), /* ~= 10^-275 */
1303 U64(0xDD95317F, 0x31C7FA1D), U64(0x40405643, 0xD711D583), /* ~= 10^-274 */
1304 U64(0x8A7D3EEF, 0x7F1CFC52), U64(0x482835EA, 0x666B2572), /* ~= 10^-273 */
1305 U64(0xAD1C8EAB, 0x5EE43B66), U64(0xDA324365, 0x0005EECF), /* ~= 10^-272 */
1306 U64(0xD863B256, 0x369D4A40), U64(0x90BED43E, 0x40076A82), /* ~= 10^-271 */
1307 U64(0x873E4F75, 0xE2224E68), U64(0x5A7744A6, 0xE804A291), /* ~= 10^-270 */
1308 U64(0xA90DE353, 0x5AAAE202), U64(0x711515D0, 0xA205CB36), /* ~= 10^-269 */
1309 U64(0xD3515C28, 0x31559A83), U64(0x0D5A5B44, 0xCA873E03), /* ~= 10^-268 */
1310 U64(0x8412D999, 0x1ED58091), U64(0xE858790A, 0xFE9486C2), /* ~= 10^-267 */
1311 U64(0xA5178FFF, 0x668AE0B6), U64(0x626E974D, 0xBE39A872), /* ~= 10^-266 */
1312 U64(0xCE5D73FF, 0x402D98E3), U64(0xFB0A3D21, 0x2DC8128F), /* ~= 10^-265 */
1313 U64(0x80FA687F, 0x881C7F8E), U64(0x7CE66634, 0xBC9D0B99), /* ~= 10^-264 */
1314 U64(0xA139029F, 0x6A239F72), U64(0x1C1FFFC1, 0xEBC44E80), /* ~= 10^-263 */
1315 U64(0xC9874347, 0x44AC874E), U64(0xA327FFB2, 0x66B56220), /* ~= 10^-262 */
1316 U64(0xFBE91419, 0x15D7A922), U64(0x4BF1FF9F, 0x0062BAA8), /* ~= 10^-261 */
1317 U64(0x9D71AC8F, 0xADA6C9B5), U64(0x6F773FC3, 0x603DB4A9), /* ~= 10^-260 */
1318 U64(0xC4CE17B3, 0x99107C22), U64(0xCB550FB4, 0x384D21D3), /* ~= 10^-259 */
1319 U64(0xF6019DA0, 0x7F549B2B), U64(0x7E2A53A1, 0x46606A48), /* ~= 10^-258 */
1320 U64(0x99C10284, 0x4F94E0FB), U64(0x2EDA7444, 0xCBFC426D), /* ~= 10^-257 */
1321 U64(0xC0314325, 0x637A1939), U64(0xFA911155, 0xFEFB5308), /* ~= 10^-256 */
1322 U64(0xF03D93EE, 0xBC589F88), U64(0x793555AB, 0x7EBA27CA), /* ~= 10^-255 */
1323 U64(0x96267C75, 0x35B763B5), U64(0x4BC1558B, 0x2F3458DE), /* ~= 10^-254 */
1324 U64(0xBBB01B92, 0x83253CA2), U64(0x9EB1AAED, 0xFB016F16), /* ~= 10^-253 */
1325 U64(0xEA9C2277, 0x23EE8BCB), U64(0x465E15A9, 0x79C1CADC), /* ~= 10^-252 */
1326 U64(0x92A1958A, 0x7675175F), U64(0x0BFACD89, 0xEC191EC9), /* ~= 10^-251 */
1327 U64(0xB749FAED, 0x14125D36), U64(0xCEF980EC, 0x671F667B), /* ~= 10^-250 */
1328 U64(0xE51C79A8, 0x5916F484), U64(0x82B7E127, 0x80E7401A), /* ~= 10^-249 */
1329 U64(0x8F31CC09, 0x37AE58D2), U64(0xD1B2ECB8, 0xB0908810), /* ~= 10^-248 */
1330 U64(0xB2FE3F0B, 0x8599EF07), U64(0x861FA7E6, 0xDCB4AA15), /* ~= 10^-247 */
1331 U64(0xDFBDCECE, 0x67006AC9), U64(0x67A791E0, 0x93E1D49A), /* ~= 10^-246 */
1332 U64(0x8BD6A141, 0x006042BD), U64(0xE0C8BB2C, 0x5C6D24E0), /* ~= 10^-245 */
1333 U64(0xAECC4991, 0x4078536D), U64(0x58FAE9F7, 0x73886E18), /* ~= 10^-244 */
1334 U64(0xDA7F5BF5, 0x90966848), U64(0xAF39A475, 0x506A899E), /* ~= 10^-243 */
1335 U64(0x888F9979, 0x7A5E012D), U64(0x6D8406C9, 0x52429603), /* ~= 10^-242 */
1336 U64(0xAAB37FD7, 0xD8F58178), U64(0xC8E5087B, 0xA6D33B83), /* ~= 10^-241 */
1337 U64(0xD5605FCD, 0xCF32E1D6), U64(0xFB1E4A9A, 0x90880A64), /* ~= 10^-240 */
1338 U64(0x855C3BE0, 0xA17FCD26), U64(0x5CF2EEA0, 0x9A55067F), /* ~= 10^-239 */
1339 U64(0xA6B34AD8, 0xC9DFC06F), U64(0xF42FAA48, 0xC0EA481E), /* ~= 10^-238 */
1340 U64(0xD0601D8E, 0xFC57B08B), U64(0xF13B94DA, 0xF124DA26), /* ~= 10^-237 */
1341 U64(0x823C1279, 0x5DB6CE57), U64(0x76C53D08, 0xD6B70858), /* ~= 10^-236 */
1342 U64(0xA2CB1717, 0xB52481ED), U64(0x54768C4B, 0x0C64CA6E), /* ~= 10^-235 */
1343 U64(0xCB7DDCDD, 0xA26DA268), U64(0xA9942F5D, 0xCF7DFD09), /* ~= 10^-234 */
1344 U64(0xFE5D5415, 0x0B090B02), U64(0xD3F93B35, 0x435D7C4C), /* ~= 10^-233 */
1345 U64(0x9EFA548D, 0x26E5A6E1), U64(0xC47BC501, 0x4A1A6DAF), /* ~= 10^-232 */
1346 U64(0xC6B8E9B0, 0x709F109A), U64(0x359AB641, 0x9CA1091B), /* ~= 10^-231 */
1347 U64(0xF867241C, 0x8CC6D4C0), U64(0xC30163D2, 0x03C94B62), /* ~= 10^-230 */
1348 U64(0x9B407691, 0xD7FC44F8), U64(0x79E0DE63, 0x425DCF1D), /* ~= 10^-229 */
1349 U64(0xC2109436, 0x4DFB5636), U64(0x985915FC, 0x12F542E4), /* ~= 10^-228 */
1350 U64(0xF294B943, 0xE17A2BC4), U64(0x3E6F5B7B, 0x17B2939D), /* ~= 10^-227 */
1351 U64(0x979CF3CA, 0x6CEC5B5A), U64(0xA705992C, 0xEECF9C42), /* ~= 10^-226 */
1352 U64(0xBD8430BD, 0x08277231), U64(0x50C6FF78, 0x2A838353), /* ~= 10^-225 */
1353 U64(0xECE53CEC, 0x4A314EBD), U64(0xA4F8BF56, 0x35246428), /* ~= 10^-224 */
1354 U64(0x940F4613, 0xAE5ED136), U64(0x871B7795, 0xE136BE99), /* ~= 10^-223 */
1355 U64(0xB9131798, 0x99F68584), U64(0x28E2557B, 0x59846E3F), /* ~= 10^-222 */
1356 U64(0xE757DD7E, 0xC07426E5), U64(0x331AEADA, 0x2FE589CF), /* ~= 10^-221 */
1357 U64(0x9096EA6F, 0x3848984F), U64(0x3FF0D2C8, 0x5DEF7621), /* ~= 10^-220 */
1358 U64(0xB4BCA50B, 0x065ABE63), U64(0x0FED077A, 0x756B53A9), /* ~= 10^-219 */
1359 U64(0xE1EBCE4D, 0xC7F16DFB), U64(0xD3E84959, 0x12C62894), /* ~= 10^-218 */
1360 U64(0x8D3360F0, 0x9CF6E4BD), U64(0x64712DD7, 0xABBBD95C), /* ~= 10^-217 */
1361 U64(0xB080392C, 0xC4349DEC), U64(0xBD8D794D, 0x96AACFB3), /* ~= 10^-216 */
1362 U64(0xDCA04777, 0xF541C567), U64(0xECF0D7A0, 0xFC5583A0), /* ~= 10^-215 */
1363 U64(0x89E42CAA, 0xF9491B60), U64(0xF41686C4, 0x9DB57244), /* ~= 10^-214 */
1364 U64(0xAC5D37D5, 0xB79B6239), U64(0x311C2875, 0xC522CED5), /* ~= 10^-213 */
1365 U64(0xD77485CB, 0x25823AC7), U64(0x7D633293, 0x366B828B), /* ~= 10^-212 */
1366 U64(0x86A8D39E, 0xF77164BC), U64(0xAE5DFF9C, 0x02033197), /* ~= 10^-211 */
1367 U64(0xA8530886, 0xB54DBDEB), U64(0xD9F57F83, 0x0283FDFC), /* ~= 10^-210 */
1368 U64(0xD267CAA8, 0x62A12D66), U64(0xD072DF63, 0xC324FD7B), /* ~= 10^-209 */
1369 U64(0x8380DEA9, 0x3DA4BC60), U64(0x4247CB9E, 0x59F71E6D), /* ~= 10^-208 */
1370 U64(0xA4611653, 0x8D0DEB78), U64(0x52D9BE85, 0xF074E608), /* ~= 10^-207 */
1371 U64(0xCD795BE8, 0x70516656), U64(0x67902E27, 0x6C921F8B), /* ~= 10^-206 */
1372 U64(0x806BD971, 0x4632DFF6), U64(0x00BA1CD8, 0xA3DB53B6), /* ~= 10^-205 */
1373 U64(0xA086CFCD, 0x97BF97F3), U64(0x80E8A40E, 0xCCD228A4), /* ~= 10^-204 */
1374 U64(0xC8A883C0, 0xFDAF7DF0), U64(0x6122CD12, 0x8006B2CD), /* ~= 10^-203 */
1375 U64(0xFAD2A4B1, 0x3D1B5D6C), U64(0x796B8057, 0x20085F81), /* ~= 10^-202 */
1376 U64(0x9CC3A6EE, 0xC6311A63), U64(0xCBE33036, 0x74053BB0), /* ~= 10^-201 */
1377 U64(0xC3F490AA, 0x77BD60FC), U64(0xBEDBFC44, 0x11068A9C), /* ~= 10^-200 */
1378 U64(0xF4F1B4D5, 0x15ACB93B), U64(0xEE92FB55, 0x15482D44), /* ~= 10^-199 */
1379 U64(0x99171105, 0x2D8BF3C5), U64(0x751BDD15, 0x2D4D1C4A), /* ~= 10^-198 */
1380 U64(0xBF5CD546, 0x78EEF0B6), U64(0xD262D45A, 0x78A0635D), /* ~= 10^-197 */
1381 U64(0xEF340A98, 0x172AACE4), U64(0x86FB8971, 0x16C87C34), /* ~= 10^-196 */
1382 U64(0x9580869F, 0x0E7AAC0E), U64(0xD45D35E6, 0xAE3D4DA0), /* ~= 10^-195 */
1383 U64(0xBAE0A846, 0xD2195712), U64(0x89748360, 0x59CCA109), /* ~= 10^-194 */
1384 U64(0xE998D258, 0x869FACD7), U64(0x2BD1A438, 0x703FC94B), /* ~= 10^-193 */
1385 U64(0x91FF8377, 0x5423CC06), U64(0x7B6306A3, 0x4627DDCF), /* ~= 10^-192 */
1386 U64(0xB67F6455, 0x292CBF08), U64(0x1A3BC84C, 0x17B1D542), /* ~= 10^-191 */
1387 U64(0xE41F3D6A, 0x7377EECA), U64(0x20CABA5F, 0x1D9E4A93), /* ~= 10^-190 */
1388 U64(0x8E938662, 0x882AF53E), U64(0x547EB47B, 0x7282EE9C), /* ~= 10^-189 */
1389 U64(0xB23867FB, 0x2A35B28D), U64(0xE99E619A, 0x4F23AA43), /* ~= 10^-188 */
1390 U64(0xDEC681F9, 0xF4C31F31), U64(0x6405FA00, 0xE2EC94D4), /* ~= 10^-187 */
1391 U64(0x8B3C113C, 0x38F9F37E), U64(0xDE83BC40, 0x8DD3DD04), /* ~= 10^-186 */
1392 U64(0xAE0B158B, 0x4738705E), U64(0x9624AB50, 0xB148D445), /* ~= 10^-185 */
1393 U64(0xD98DDAEE, 0x19068C76), U64(0x3BADD624, 0xDD9B0957), /* ~= 10^-184 */
1394 U64(0x87F8A8D4, 0xCFA417C9), U64(0xE54CA5D7, 0x0A80E5D6), /* ~= 10^-183 */
1395 U64(0xA9F6D30A, 0x038D1DBC), U64(0x5E9FCF4C, 0xCD211F4C), /* ~= 10^-182 */
1396 U64(0xD47487CC, 0x8470652B), U64(0x7647C320, 0x0069671F), /* ~= 10^-181 */
1397 U64(0x84C8D4DF, 0xD2C63F3B), U64(0x29ECD9F4, 0x0041E073), /* ~= 10^-180 */
1398 U64(0xA5FB0A17, 0xC777CF09), U64(0xF4681071, 0x00525890), /* ~= 10^-179 */
1399 U64(0xCF79CC9D, 0xB955C2CC), U64(0x7182148D, 0x4066EEB4), /* ~= 10^-178 */
1400 U64(0x81AC1FE2, 0x93D599BF), U64(0xC6F14CD8, 0x48405530), /* ~= 10^-177 */
1401 U64(0xA21727DB, 0x38CB002F), U64(0xB8ADA00E, 0x5A506A7C), /* ~= 10^-176 */
1402 U64(0xCA9CF1D2, 0x06FDC03B), U64(0xA6D90811, 0xF0E4851C), /* ~= 10^-175 */
1403 U64(0xFD442E46, 0x88BD304A), U64(0x908F4A16, 0x6D1DA663), /* ~= 10^-174 */
1404 U64(0x9E4A9CEC, 0x15763E2E), U64(0x9A598E4E, 0x043287FE), /* ~= 10^-173 */
1405 U64(0xC5DD4427, 0x1AD3CDBA), U64(0x40EFF1E1, 0x853F29FD), /* ~= 10^-172 */
1406 U64(0xF7549530, 0xE188C128), U64(0xD12BEE59, 0xE68EF47C), /* ~= 10^-171 */
1407 U64(0x9A94DD3E, 0x8CF578B9), U64(0x82BB74F8, 0x301958CE), /* ~= 10^-170 */
1408 U64(0xC13A148E, 0x3032D6E7), U64(0xE36A5236, 0x3C1FAF01), /* ~= 10^-169 */
1409 U64(0xF18899B1, 0xBC3F8CA1), U64(0xDC44E6C3, 0xCB279AC1), /* ~= 10^-168 */
1410 U64(0x96F5600F, 0x15A7B7E5), U64(0x29AB103A, 0x5EF8C0B9), /* ~= 10^-167 */
1411 U64(0xBCB2B812, 0xDB11A5DE), U64(0x7415D448, 0xF6B6F0E7), /* ~= 10^-166 */
1412 U64(0xEBDF6617, 0x91D60F56), U64(0x111B495B, 0x3464AD21), /* ~= 10^-165 */
1413 U64(0x936B9FCE, 0xBB25C995), U64(0xCAB10DD9, 0x00BEEC34), /* ~= 10^-164 */
1414 U64(0xB84687C2, 0x69EF3BFB), U64(0x3D5D514F, 0x40EEA742), /* ~= 10^-163 */
1415 U64(0xE65829B3, 0x046B0AFA), U64(0x0CB4A5A3, 0x112A5112), /* ~= 10^-162 */
1416 U64(0x8FF71A0F, 0xE2C2E6DC), U64(0x47F0E785, 0xEABA72AB), /* ~= 10^-161 */
1417 U64(0xB3F4E093, 0xDB73A093), U64(0x59ED2167, 0x65690F56), /* ~= 10^-160 */
1418 U64(0xE0F218B8, 0xD25088B8), U64(0x306869C1, 0x3EC3532C), /* ~= 10^-159 */
1419 U64(0x8C974F73, 0x83725573), U64(0x1E414218, 0xC73A13FB), /* ~= 10^-158 */
1420 U64(0xAFBD2350, 0x644EEACF), U64(0xE5D1929E, 0xF90898FA), /* ~= 10^-157 */
1421 U64(0xDBAC6C24, 0x7D62A583), U64(0xDF45F746, 0xB74ABF39), /* ~= 10^-156 */
1422 U64(0x894BC396, 0xCE5DA772), U64(0x6B8BBA8C, 0x328EB783), /* ~= 10^-155 */
1423 U64(0xAB9EB47C, 0x81F5114F), U64(0x066EA92F, 0x3F326564), /* ~= 10^-154 */
1424 U64(0xD686619B, 0xA27255A2), U64(0xC80A537B, 0x0EFEFEBD), /* ~= 10^-153 */
1425 U64(0x8613FD01, 0x45877585), U64(0xBD06742C, 0xE95F5F36), /* ~= 10^-152 */
1426 U64(0xA798FC41, 0x96E952E7), U64(0x2C481138, 0x23B73704), /* ~= 10^-151 */
1427 U64(0xD17F3B51, 0xFCA3A7A0), U64(0xF75A1586, 0x2CA504C5), /* ~= 10^-150 */
1428 U64(0x82EF8513, 0x3DE648C4), U64(0x9A984D73, 0xDBE722FB), /* ~= 10^-149 */
1429 U64(0xA3AB6658, 0x0D5FDAF5), U64(0xC13E60D0, 0xD2E0EBBA), /* ~= 10^-148 */
1430 U64(0xCC963FEE, 0x10B7D1B3), U64(0x318DF905, 0x079926A8), /* ~= 10^-147 */
1431 U64(0xFFBBCFE9, 0x94E5C61F), U64(0xFDF17746, 0x497F7052), /* ~= 10^-146 */
1432 U64(0x9FD561F1, 0xFD0F9BD3), U64(0xFEB6EA8B, 0xEDEFA633), /* ~= 10^-145 */
1433 U64(0xC7CABA6E, 0x7C5382C8), U64(0xFE64A52E, 0xE96B8FC0), /* ~= 10^-144 */
1434 U64(0xF9BD690A, 0x1B68637B), U64(0x3DFDCE7A, 0xA3C673B0), /* ~= 10^-143 */
1435 U64(0x9C1661A6, 0x51213E2D), U64(0x06BEA10C, 0xA65C084E), /* ~= 10^-142 */
1436 U64(0xC31BFA0F, 0xE5698DB8), U64(0x486E494F, 0xCFF30A62), /* ~= 10^-141 */
1437 U64(0xF3E2F893, 0xDEC3F126), U64(0x5A89DBA3, 0xC3EFCCFA), /* ~= 10^-140 */
1438 U64(0x986DDB5C, 0x6B3A76B7), U64(0xF8962946, 0x5A75E01C), /* ~= 10^-139 */
1439 U64(0xBE895233, 0x86091465), U64(0xF6BBB397, 0xF1135823), /* ~= 10^-138 */
1440 U64(0xEE2BA6C0, 0x678B597F), U64(0x746AA07D, 0xED582E2C), /* ~= 10^-137 */
1441 U64(0x94DB4838, 0x40B717EF), U64(0xA8C2A44E, 0xB4571CDC), /* ~= 10^-136 */
1442 U64(0xBA121A46, 0x50E4DDEB), U64(0x92F34D62, 0x616CE413), /* ~= 10^-135 */
1443 U64(0xE896A0D7, 0xE51E1566), U64(0x77B020BA, 0xF9C81D17), /* ~= 10^-134 */
1444 U64(0x915E2486, 0xEF32CD60), U64(0x0ACE1474, 0xDC1D122E), /* ~= 10^-133 */
1445 U64(0xB5B5ADA8, 0xAAFF80B8), U64(0x0D819992, 0x132456BA), /* ~= 10^-132 */
1446 U64(0xE3231912, 0xD5BF60E6), U64(0x10E1FFF6, 0x97ED6C69), /* ~= 10^-131 */
1447 U64(0x8DF5EFAB, 0xC5979C8F), U64(0xCA8D3FFA, 0x1EF463C1), /* ~= 10^-130 */
1448 U64(0xB1736B96, 0xB6FD83B3), U64(0xBD308FF8, 0xA6B17CB2), /* ~= 10^-129 */
1449 U64(0xDDD0467C, 0x64BCE4A0), U64(0xAC7CB3F6, 0xD05DDBDE), /* ~= 10^-128 */
1450 U64(0x8AA22C0D, 0xBEF60EE4), U64(0x6BCDF07A, 0x423AA96B), /* ~= 10^-127 */
1451 U64(0xAD4AB711, 0x2EB3929D), U64(0x86C16C98, 0xD2C953C6), /* ~= 10^-126 */
1452 U64(0xD89D64D5, 0x7A607744), U64(0xE871C7BF, 0x077BA8B7), /* ~= 10^-125 */
1453 U64(0x87625F05, 0x6C7C4A8B), U64(0x11471CD7, 0x64AD4972), /* ~= 10^-124 */
1454 U64(0xA93AF6C6, 0xC79B5D2D), U64(0xD598E40D, 0x3DD89BCF), /* ~= 10^-123 */
1455 U64(0xD389B478, 0x79823479), U64(0x4AFF1D10, 0x8D4EC2C3), /* ~= 10^-122 */
1456 U64(0x843610CB, 0x4BF160CB), U64(0xCEDF722A, 0x585139BA), /* ~= 10^-121 */
1457 U64(0xA54394FE, 0x1EEDB8FE), U64(0xC2974EB4, 0xEE658828), /* ~= 10^-120 */
1458 U64(0xCE947A3D, 0xA6A9273E), U64(0x733D2262, 0x29FEEA32), /* ~= 10^-119 */
1459 U64(0x811CCC66, 0x8829B887), U64(0x0806357D, 0x5A3F525F), /* ~= 10^-118 */
1460 U64(0xA163FF80, 0x2A3426A8), U64(0xCA07C2DC, 0xB0CF26F7), /* ~= 10^-117 */
1461 U64(0xC9BCFF60, 0x34C13052), U64(0xFC89B393, 0xDD02F0B5), /* ~= 10^-116 */
1462 U64(0xFC2C3F38, 0x41F17C67), U64(0xBBAC2078, 0xD443ACE2), /* ~= 10^-115 */
1463 U64(0x9D9BA783, 0x2936EDC0), U64(0xD54B944B, 0x84AA4C0D), /* ~= 10^-114 */
1464 U64(0xC5029163, 0xF384A931), U64(0x0A9E795E, 0x65D4DF11), /* ~= 10^-113 */
1465 U64(0xF64335BC, 0xF065D37D), U64(0x4D4617B5, 0xFF4A16D5), /* ~= 10^-112 */
1466 U64(0x99EA0196, 0x163FA42E), U64(0x504BCED1, 0xBF8E4E45), /* ~= 10^-111 */
1467 U64(0xC06481FB, 0x9BCF8D39), U64(0xE45EC286, 0x2F71E1D6), /* ~= 10^-110 */
1468 U64(0xF07DA27A, 0x82C37088), U64(0x5D767327, 0xBB4E5A4C), /* ~= 10^-109 */
1469 U64(0x964E858C, 0x91BA2655), U64(0x3A6A07F8, 0xD510F86F), /* ~= 10^-108 */
1470 U64(0xBBE226EF, 0xB628AFEA), U64(0x890489F7, 0x0A55368B), /* ~= 10^-107 */
1471 U64(0xEADAB0AB, 0xA3B2DBE5), U64(0x2B45AC74, 0xCCEA842E), /* ~= 10^-106 */
1472 U64(0x92C8AE6B, 0x464FC96F), U64(0x3B0B8BC9, 0x0012929D), /* ~= 10^-105 */
1473 U64(0xB77ADA06, 0x17E3BBCB), U64(0x09CE6EBB, 0x40173744), /* ~= 10^-104 */
1474 U64(0xE5599087, 0x9DDCAABD), U64(0xCC420A6A, 0x101D0515), /* ~= 10^-103 */
1475 U64(0x8F57FA54, 0xC2A9EAB6), U64(0x9FA94682, 0x4A12232D), /* ~= 10^-102 */
1476 U64(0xB32DF8E9, 0xF3546564), U64(0x47939822, 0xDC96ABF9), /* ~= 10^-101 */
1477 U64(0xDFF97724, 0x70297EBD), U64(0x59787E2B, 0x93BC56F7), /* ~= 10^-100 */
1478 U64(0x8BFBEA76, 0xC619EF36), U64(0x57EB4EDB, 0x3C55B65A), /* ~= 10^-99 */
1479 U64(0xAEFAE514, 0x77A06B03), U64(0xEDE62292, 0x0B6B23F1), /* ~= 10^-98 */
1480 U64(0xDAB99E59, 0x958885C4), U64(0xE95FAB36, 0x8E45ECED), /* ~= 10^-97 */
1481 U64(0x88B402F7, 0xFD75539B), U64(0x11DBCB02, 0x18EBB414), /* ~= 10^-96 */
1482 U64(0xAAE103B5, 0xFCD2A881), U64(0xD652BDC2, 0x9F26A119), /* ~= 10^-95 */
1483 U64(0xD59944A3, 0x7C0752A2), U64(0x4BE76D33, 0x46F0495F), /* ~= 10^-94 */
1484 U64(0x857FCAE6, 0x2D8493A5), U64(0x6F70A440, 0x0C562DDB), /* ~= 10^-93 */
1485 U64(0xA6DFBD9F, 0xB8E5B88E), U64(0xCB4CCD50, 0x0F6BB952), /* ~= 10^-92 */
1486 U64(0xD097AD07, 0xA71F26B2), U64(0x7E2000A4, 0x1346A7A7), /* ~= 10^-91 */
1487 U64(0x825ECC24, 0xC873782F), U64(0x8ED40066, 0x8C0C28C8), /* ~= 10^-90 */
1488 U64(0xA2F67F2D, 0xFA90563B), U64(0x72890080, 0x2F0F32FA), /* ~= 10^-89 */
1489 U64(0xCBB41EF9, 0x79346BCA), U64(0x4F2B40A0, 0x3AD2FFB9), /* ~= 10^-88 */
1490 U64(0xFEA126B7, 0xD78186BC), U64(0xE2F610C8, 0x4987BFA8), /* ~= 10^-87 */
1491 U64(0x9F24B832, 0xE6B0F436), U64(0x0DD9CA7D, 0x2DF4D7C9), /* ~= 10^-86 */
1492 U64(0xC6EDE63F, 0xA05D3143), U64(0x91503D1C, 0x79720DBB), /* ~= 10^-85 */
1493 U64(0xF8A95FCF, 0x88747D94), U64(0x75A44C63, 0x97CE912A), /* ~= 10^-84 */
1494 U64(0x9B69DBE1, 0xB548CE7C), U64(0xC986AFBE, 0x3EE11ABA), /* ~= 10^-83 */
1495 U64(0xC24452DA, 0x229B021B), U64(0xFBE85BAD, 0xCE996168), /* ~= 10^-82 */
1496 U64(0xF2D56790, 0xAB41C2A2), U64(0xFAE27299, 0x423FB9C3), /* ~= 10^-81 */
1497 U64(0x97C560BA, 0x6B0919A5), U64(0xDCCD879F, 0xC967D41A), /* ~= 10^-80 */
1498 U64(0xBDB6B8E9, 0x05CB600F), U64(0x5400E987, 0xBBC1C920), /* ~= 10^-79 */
1499 U64(0xED246723, 0x473E3813), U64(0x290123E9, 0xAAB23B68), /* ~= 10^-78 */
1500 U64(0x9436C076, 0x0C86E30B), U64(0xF9A0B672, 0x0AAF6521), /* ~= 10^-77 */
1501 U64(0xB9447093, 0x8FA89BCE), U64(0xF808E40E, 0x8D5B3E69), /* ~= 10^-76 */
1502 U64(0xE7958CB8, 0x7392C2C2), U64(0xB60B1D12, 0x30B20E04), /* ~= 10^-75 */
1503 U64(0x90BD77F3, 0x483BB9B9), U64(0xB1C6F22B, 0x5E6F48C2), /* ~= 10^-74 */
1504 U64(0xB4ECD5F0, 0x1A4AA828), U64(0x1E38AEB6, 0x360B1AF3), /* ~= 10^-73 */
1505 U64(0xE2280B6C, 0x20DD5232), U64(0x25C6DA63, 0xC38DE1B0), /* ~= 10^-72 */
1506 U64(0x8D590723, 0x948A535F), U64(0x579C487E, 0x5A38AD0E), /* ~= 10^-71 */
1507 U64(0xB0AF48EC, 0x79ACE837), U64(0x2D835A9D, 0xF0C6D851), /* ~= 10^-70 */
1508 U64(0xDCDB1B27, 0x98182244), U64(0xF8E43145, 0x6CF88E65), /* ~= 10^-69 */
1509 U64(0x8A08F0F8, 0xBF0F156B), U64(0x1B8E9ECB, 0x641B58FF), /* ~= 10^-68 */
1510 U64(0xAC8B2D36, 0xEED2DAC5), U64(0xE272467E, 0x3D222F3F), /* ~= 10^-67 */
1511 U64(0xD7ADF884, 0xAA879177), U64(0x5B0ED81D, 0xCC6ABB0F), /* ~= 10^-66 */
1512 U64(0x86CCBB52, 0xEA94BAEA), U64(0x98E94712, 0x9FC2B4E9), /* ~= 10^-65 */
1513 U64(0xA87FEA27, 0xA539E9A5), U64(0x3F2398D7, 0x47B36224), /* ~= 10^-64 */
1514 U64(0xD29FE4B1, 0x8E88640E), U64(0x8EEC7F0D, 0x19A03AAD), /* ~= 10^-63 */
1515 U64(0x83A3EEEE, 0xF9153E89), U64(0x1953CF68, 0x300424AC), /* ~= 10^-62 */
1516 U64(0xA48CEAAA, 0xB75A8E2B), U64(0x5FA8C342, 0x3C052DD7), /* ~= 10^-61 */
1517 U64(0xCDB02555, 0x653131B6), U64(0x3792F412, 0xCB06794D), /* ~= 10^-60 */
1518 U64(0x808E1755, 0x5F3EBF11), U64(0xE2BBD88B, 0xBEE40BD0), /* ~= 10^-59 */
1519 U64(0xA0B19D2A, 0xB70E6ED6), U64(0x5B6ACEAE, 0xAE9D0EC4), /* ~= 10^-58 */
1520 U64(0xC8DE0475, 0x64D20A8B), U64(0xF245825A, 0x5A445275), /* ~= 10^-57 */
1521 U64(0xFB158592, 0xBE068D2E), U64(0xEED6E2F0, 0xF0D56712), /* ~= 10^-56 */
1522 U64(0x9CED737B, 0xB6C4183D), U64(0x55464DD6, 0x9685606B), /* ~= 10^-55 */
1523 U64(0xC428D05A, 0xA4751E4C), U64(0xAA97E14C, 0x3C26B886), /* ~= 10^-54 */
1524 U64(0xF5330471, 0x4D9265DF), U64(0xD53DD99F, 0x4B3066A8), /* ~= 10^-53 */
1525 U64(0x993FE2C6, 0xD07B7FAB), U64(0xE546A803, 0x8EFE4029), /* ~= 10^-52 */
1526 U64(0xBF8FDB78, 0x849A5F96), U64(0xDE985204, 0x72BDD033), /* ~= 10^-51 */
1527 U64(0xEF73D256, 0xA5C0F77C), U64(0x963E6685, 0x8F6D4440), /* ~= 10^-50 */
1528 U64(0x95A86376, 0x27989AAD), U64(0xDDE70013, 0x79A44AA8), /* ~= 10^-49 */
1529 U64(0xBB127C53, 0xB17EC159), U64(0x5560C018, 0x580D5D52), /* ~= 10^-48 */
1530 U64(0xE9D71B68, 0x9DDE71AF), U64(0xAAB8F01E, 0x6E10B4A6), /* ~= 10^-47 */
1531 U64(0x92267121, 0x62AB070D), U64(0xCAB39613, 0x04CA70E8), /* ~= 10^-46 */
1532 U64(0xB6B00D69, 0xBB55C8D1), U64(0x3D607B97, 0xC5FD0D22), /* ~= 10^-45 */
1533 U64(0xE45C10C4, 0x2A2B3B05), U64(0x8CB89A7D, 0xB77C506A), /* ~= 10^-44 */
1534 U64(0x8EB98A7A, 0x9A5B04E3), U64(0x77F3608E, 0x92ADB242), /* ~= 10^-43 */
1535 U64(0xB267ED19, 0x40F1C61C), U64(0x55F038B2, 0x37591ED3), /* ~= 10^-42 */
1536 U64(0xDF01E85F, 0x912E37A3), U64(0x6B6C46DE, 0xC52F6688), /* ~= 10^-41 */
1537 U64(0x8B61313B, 0xBABCE2C6), U64(0x2323AC4B, 0x3B3DA015), /* ~= 10^-40 */
1538 U64(0xAE397D8A, 0xA96C1B77), U64(0xABEC975E, 0x0A0D081A), /* ~= 10^-39 */
1539 U64(0xD9C7DCED, 0x53C72255), U64(0x96E7BD35, 0x8C904A21), /* ~= 10^-38 */
1540 U64(0x881CEA14, 0x545C7575), U64(0x7E50D641, 0x77DA2E54), /* ~= 10^-37 */
1541 U64(0xAA242499, 0x697392D2), U64(0xDDE50BD1, 0xD5D0B9E9), /* ~= 10^-36 */
1542 U64(0xD4AD2DBF, 0xC3D07787), U64(0x955E4EC6, 0x4B44E864), /* ~= 10^-35 */
1543 U64(0x84EC3C97, 0xDA624AB4), U64(0xBD5AF13B, 0xEF0B113E), /* ~= 10^-34 */
1544 U64(0xA6274BBD, 0xD0FADD61), U64(0xECB1AD8A, 0xEACDD58E), /* ~= 10^-33 */
1545 U64(0xCFB11EAD, 0x453994BA), U64(0x67DE18ED, 0xA5814AF2), /* ~= 10^-32 */
1546 U64(0x81CEB32C, 0x4B43FCF4), U64(0x80EACF94, 0x8770CED7), /* ~= 10^-31 */
1547 U64(0xA2425FF7, 0x5E14FC31), U64(0xA1258379, 0xA94D028D), /* ~= 10^-30 */
1548 U64(0xCAD2F7F5, 0x359A3B3E), U64(0x096EE458, 0x13A04330), /* ~= 10^-29 */
1549 U64(0xFD87B5F2, 0x8300CA0D), U64(0x8BCA9D6E, 0x188853FC), /* ~= 10^-28 */
1550 U64(0x9E74D1B7, 0x91E07E48), U64(0x775EA264, 0xCF55347D), /* ~= 10^-27 */
1551 U64(0xC6120625, 0x76589DDA), U64(0x95364AFE, 0x032A819D), /* ~= 10^-26 */
1552 U64(0xF79687AE, 0xD3EEC551), U64(0x3A83DDBD, 0x83F52204), /* ~= 10^-25 */
1553 U64(0x9ABE14CD, 0x44753B52), U64(0xC4926A96, 0x72793542), /* ~= 10^-24 */
1554 U64(0xC16D9A00, 0x95928A27), U64(0x75B7053C, 0x0F178293), /* ~= 10^-23 */
1555 U64(0xF1C90080, 0xBAF72CB1), U64(0x5324C68B, 0x12DD6338), /* ~= 10^-22 */
1556 U64(0x971DA050, 0x74DA7BEE), U64(0xD3F6FC16, 0xEBCA5E03), /* ~= 10^-21 */
1557 U64(0xBCE50864, 0x92111AEA), U64(0x88F4BB1C, 0xA6BCF584), /* ~= 10^-20 */
1558 U64(0xEC1E4A7D, 0xB69561A5), U64(0x2B31E9E3, 0xD06C32E5), /* ~= 10^-19 */
1559 U64(0x9392EE8E, 0x921D5D07), U64(0x3AFF322E, 0x62439FCF), /* ~= 10^-18 */
1560 U64(0xB877AA32, 0x36A4B449), U64(0x09BEFEB9, 0xFAD487C2), /* ~= 10^-17 */
1561 U64(0xE69594BE, 0xC44DE15B), U64(0x4C2EBE68, 0x7989A9B3), /* ~= 10^-16 */
1562 U64(0x901D7CF7, 0x3AB0ACD9), U64(0x0F9D3701, 0x4BF60A10), /* ~= 10^-15 */
1563 U64(0xB424DC35, 0x095CD80F), U64(0x538484C1, 0x9EF38C94), /* ~= 10^-14 */
1564 U64(0xE12E1342, 0x4BB40E13), U64(0x2865A5F2, 0x06B06FB9), /* ~= 10^-13 */
1565 U64(0x8CBCCC09, 0x6F5088CB), U64(0xF93F87B7, 0x442E45D3), /* ~= 10^-12 */
1566 U64(0xAFEBFF0B, 0xCB24AAFE), U64(0xF78F69A5, 0x1539D748), /* ~= 10^-11 */
1567 U64(0xDBE6FECE, 0xBDEDD5BE), U64(0xB573440E, 0x5A884D1B), /* ~= 10^-10 */
1568 U64(0x89705F41, 0x36B4A597), U64(0x31680A88, 0xF8953030), /* ~= 10^-9 */
1569 U64(0xABCC7711, 0x8461CEFC), U64(0xFDC20D2B, 0x36BA7C3D), /* ~= 10^-8 */
1570 U64(0xD6BF94D5, 0xE57A42BC), U64(0x3D329076, 0x04691B4C), /* ~= 10^-7 */
1571 U64(0x8637BD05, 0xAF6C69B5), U64(0xA63F9A49, 0xC2C1B10F), /* ~= 10^-6 */
1572 U64(0xA7C5AC47, 0x1B478423), U64(0x0FCF80DC, 0x33721D53), /* ~= 10^-5 */
1573 U64(0xD1B71758, 0xE219652B), U64(0xD3C36113, 0x404EA4A8), /* ~= 10^-4 */
1574 U64(0x83126E97, 0x8D4FDF3B), U64(0x645A1CAC, 0x083126E9), /* ~= 10^-3 */
1575 U64(0xA3D70A3D, 0x70A3D70A), U64(0x3D70A3D7, 0x0A3D70A3), /* ~= 10^-2 */
1576 U64(0xCCCCCCCC, 0xCCCCCCCC), U64(0xCCCCCCCC, 0xCCCCCCCC), /* ~= 10^-1 */
1577 U64(0x80000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^0 */
1578 U64(0xA0000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^1 */
1579 U64(0xC8000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^2 */
1580 U64(0xFA000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^3 */
1581 U64(0x9C400000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^4 */
1582 U64(0xC3500000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^5 */
1583 U64(0xF4240000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^6 */
1584 U64(0x98968000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^7 */
1585 U64(0xBEBC2000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^8 */
1586 U64(0xEE6B2800, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^9 */
1587 U64(0x9502F900, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^10 */
1588 U64(0xBA43B740, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^11 */
1589 U64(0xE8D4A510, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^12 */
1590 U64(0x9184E72A, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^13 */
1591 U64(0xB5E620F4, 0x80000000), U64(0x00000000, 0x00000000), /* == 10^14 */
1592 U64(0xE35FA931, 0xA0000000), U64(0x00000000, 0x00000000), /* == 10^15 */
1593 U64(0x8E1BC9BF, 0x04000000), U64(0x00000000, 0x00000000), /* == 10^16 */
1594 U64(0xB1A2BC2E, 0xC5000000), U64(0x00000000, 0x00000000), /* == 10^17 */
1595 U64(0xDE0B6B3A, 0x76400000), U64(0x00000000, 0x00000000), /* == 10^18 */
1596 U64(0x8AC72304, 0x89E80000), U64(0x00000000, 0x00000000), /* == 10^19 */
1597 U64(0xAD78EBC5, 0xAC620000), U64(0x00000000, 0x00000000), /* == 10^20 */
1598 U64(0xD8D726B7, 0x177A8000), U64(0x00000000, 0x00000000), /* == 10^21 */
1599 U64(0x87867832, 0x6EAC9000), U64(0x00000000, 0x00000000), /* == 10^22 */
1600 U64(0xA968163F, 0x0A57B400), U64(0x00000000, 0x00000000), /* == 10^23 */
1601 U64(0xD3C21BCE, 0xCCEDA100), U64(0x00000000, 0x00000000), /* == 10^24 */
1602 U64(0x84595161, 0x401484A0), U64(0x00000000, 0x00000000), /* == 10^25 */
1603 U64(0xA56FA5B9, 0x9019A5C8), U64(0x00000000, 0x00000000), /* == 10^26 */
1604 U64(0xCECB8F27, 0xF4200F3A), U64(0x00000000, 0x00000000), /* == 10^27 */
1605 U64(0x813F3978, 0xF8940984), U64(0x40000000, 0x00000000), /* == 10^28 */
1606 U64(0xA18F07D7, 0x36B90BE5), U64(0x50000000, 0x00000000), /* == 10^29 */
1607 U64(0xC9F2C9CD, 0x04674EDE), U64(0xA4000000, 0x00000000), /* == 10^30 */
1608 U64(0xFC6F7C40, 0x45812296), U64(0x4D000000, 0x00000000), /* == 10^31 */
1609 U64(0x9DC5ADA8, 0x2B70B59D), U64(0xF0200000, 0x00000000), /* == 10^32 */
1610 U64(0xC5371912, 0x364CE305), U64(0x6C280000, 0x00000000), /* == 10^33 */
1611 U64(0xF684DF56, 0xC3E01BC6), U64(0xC7320000, 0x00000000), /* == 10^34 */
1612 U64(0x9A130B96, 0x3A6C115C), U64(0x3C7F4000, 0x00000000), /* == 10^35 */
1613 U64(0xC097CE7B, 0xC90715B3), U64(0x4B9F1000, 0x00000000), /* == 10^36 */
1614 U64(0xF0BDC21A, 0xBB48DB20), U64(0x1E86D400, 0x00000000), /* == 10^37 */
1615 U64(0x96769950, 0xB50D88F4), U64(0x13144480, 0x00000000), /* == 10^38 */
1616 U64(0xBC143FA4, 0xE250EB31), U64(0x17D955A0, 0x00000000), /* == 10^39 */
1617 U64(0xEB194F8E, 0x1AE525FD), U64(0x5DCFAB08, 0x00000000), /* == 10^40 */
1618 U64(0x92EFD1B8, 0xD0CF37BE), U64(0x5AA1CAE5, 0x00000000), /* == 10^41 */
1619 U64(0xB7ABC627, 0x050305AD), U64(0xF14A3D9E, 0x40000000), /* == 10^42 */
1620 U64(0xE596B7B0, 0xC643C719), U64(0x6D9CCD05, 0xD0000000), /* == 10^43 */
1621 U64(0x8F7E32CE, 0x7BEA5C6F), U64(0xE4820023, 0xA2000000), /* == 10^44 */
1622 U64(0xB35DBF82, 0x1AE4F38B), U64(0xDDA2802C, 0x8A800000), /* == 10^45 */
1623 U64(0xE0352F62, 0xA19E306E), U64(0xD50B2037, 0xAD200000), /* == 10^46 */
1624 U64(0x8C213D9D, 0xA502DE45), U64(0x4526F422, 0xCC340000), /* == 10^47 */
1625 U64(0xAF298D05, 0x0E4395D6), U64(0x9670B12B, 0x7F410000), /* == 10^48 */
1626 U64(0xDAF3F046, 0x51D47B4C), U64(0x3C0CDD76, 0x5F114000), /* == 10^49 */
1627 U64(0x88D8762B, 0xF324CD0F), U64(0xA5880A69, 0xFB6AC800), /* == 10^50 */
1628 U64(0xAB0E93B6, 0xEFEE0053), U64(0x8EEA0D04, 0x7A457A00), /* == 10^51 */
1629 U64(0xD5D238A4, 0xABE98068), U64(0x72A49045, 0x98D6D880), /* == 10^52 */
1630 U64(0x85A36366, 0xEB71F041), U64(0x47A6DA2B, 0x7F864750), /* == 10^53 */
1631 U64(0xA70C3C40, 0xA64E6C51), U64(0x999090B6, 0x5F67D924), /* == 10^54 */
1632 U64(0xD0CF4B50, 0xCFE20765), U64(0xFFF4B4E3, 0xF741CF6D), /* == 10^55 */
1633 U64(0x82818F12, 0x81ED449F), U64(0xBFF8F10E, 0x7A8921A4), /* ~= 10^56 */
1634 U64(0xA321F2D7, 0x226895C7), U64(0xAFF72D52, 0x192B6A0D), /* ~= 10^57 */
1635 U64(0xCBEA6F8C, 0xEB02BB39), U64(0x9BF4F8A6, 0x9F764490), /* ~= 10^58 */
1636 U64(0xFEE50B70, 0x25C36A08), U64(0x02F236D0, 0x4753D5B4), /* ~= 10^59 */
1637 U64(0x9F4F2726, 0x179A2245), U64(0x01D76242, 0x2C946590), /* ~= 10^60 */
1638 U64(0xC722F0EF, 0x9D80AAD6), U64(0x424D3AD2, 0xB7B97EF5), /* ~= 10^61 */
1639 U64(0xF8EBAD2B, 0x84E0D58B), U64(0xD2E08987, 0x65A7DEB2), /* ~= 10^62 */
1640 U64(0x9B934C3B, 0x330C8577), U64(0x63CC55F4, 0x9F88EB2F), /* ~= 10^63 */
1641 U64(0xC2781F49, 0xFFCFA6D5), U64(0x3CBF6B71, 0xC76B25FB), /* ~= 10^64 */
1642 U64(0xF316271C, 0x7FC3908A), U64(0x8BEF464E, 0x3945EF7A), /* ~= 10^65 */
1643 U64(0x97EDD871, 0xCFDA3A56), U64(0x97758BF0, 0xE3CBB5AC), /* ~= 10^66 */
1644 U64(0xBDE94E8E, 0x43D0C8EC), U64(0x3D52EEED, 0x1CBEA317), /* ~= 10^67 */
1645 U64(0xED63A231, 0xD4C4FB27), U64(0x4CA7AAA8, 0x63EE4BDD), /* ~= 10^68 */
1646 U64(0x945E455F, 0x24FB1CF8), U64(0x8FE8CAA9, 0x3E74EF6A), /* ~= 10^69 */
1647 U64(0xB975D6B6, 0xEE39E436), U64(0xB3E2FD53, 0x8E122B44), /* ~= 10^70 */
1648 U64(0xE7D34C64, 0xA9C85D44), U64(0x60DBBCA8, 0x7196B616), /* ~= 10^71 */
1649 U64(0x90E40FBE, 0xEA1D3A4A), U64(0xBC8955E9, 0x46FE31CD), /* ~= 10^72 */
1650 U64(0xB51D13AE, 0xA4A488DD), U64(0x6BABAB63, 0x98BDBE41), /* ~= 10^73 */
1651 U64(0xE264589A, 0x4DCDAB14), U64(0xC696963C, 0x7EED2DD1), /* ~= 10^74 */
1652 U64(0x8D7EB760, 0x70A08AEC), U64(0xFC1E1DE5, 0xCF543CA2), /* ~= 10^75 */
1653 U64(0xB0DE6538, 0x8CC8ADA8), U64(0x3B25A55F, 0x43294BCB), /* ~= 10^76 */
1654 U64(0xDD15FE86, 0xAFFAD912), U64(0x49EF0EB7, 0x13F39EBE), /* ~= 10^77 */
1655 U64(0x8A2DBF14, 0x2DFCC7AB), U64(0x6E356932, 0x6C784337), /* ~= 10^78 */
1656 U64(0xACB92ED9, 0x397BF996), U64(0x49C2C37F, 0x07965404), /* ~= 10^79 */
1657 U64(0xD7E77A8F, 0x87DAF7FB), U64(0xDC33745E, 0xC97BE906), /* ~= 10^80 */
1658 U64(0x86F0AC99, 0xB4E8DAFD), U64(0x69A028BB, 0x3DED71A3), /* ~= 10^81 */
1659 U64(0xA8ACD7C0, 0x222311BC), U64(0xC40832EA, 0x0D68CE0C), /* ~= 10^82 */
1660 U64(0xD2D80DB0, 0x2AABD62B), U64(0xF50A3FA4, 0x90C30190), /* ~= 10^83 */
1661 U64(0x83C7088E, 0x1AAB65DB), U64(0x792667C6, 0xDA79E0FA), /* ~= 10^84 */
1662 U64(0xA4B8CAB1, 0xA1563F52), U64(0x577001B8, 0x91185938), /* ~= 10^85 */
1663 U64(0xCDE6FD5E, 0x09ABCF26), U64(0xED4C0226, 0xB55E6F86), /* ~= 10^86 */
1664 U64(0x80B05E5A, 0xC60B6178), U64(0x544F8158, 0x315B05B4), /* ~= 10^87 */
1665 U64(0xA0DC75F1, 0x778E39D6), U64(0x696361AE, 0x3DB1C721), /* ~= 10^88 */
1666 U64(0xC913936D, 0xD571C84C), U64(0x03BC3A19, 0xCD1E38E9), /* ~= 10^89 */
1667 U64(0xFB587849, 0x4ACE3A5F), U64(0x04AB48A0, 0x4065C723), /* ~= 10^90 */
1668 U64(0x9D174B2D, 0xCEC0E47B), U64(0x62EB0D64, 0x283F9C76), /* ~= 10^91 */
1669 U64(0xC45D1DF9, 0x42711D9A), U64(0x3BA5D0BD, 0x324F8394), /* ~= 10^92 */
1670 U64(0xF5746577, 0x930D6500), U64(0xCA8F44EC, 0x7EE36479), /* ~= 10^93 */
1671 U64(0x9968BF6A, 0xBBE85F20), U64(0x7E998B13, 0xCF4E1ECB), /* ~= 10^94 */
1672 U64(0xBFC2EF45, 0x6AE276E8), U64(0x9E3FEDD8, 0xC321A67E), /* ~= 10^95 */
1673 U64(0xEFB3AB16, 0xC59B14A2), U64(0xC5CFE94E, 0xF3EA101E), /* ~= 10^96 */
1674 U64(0x95D04AEE, 0x3B80ECE5), U64(0xBBA1F1D1, 0x58724A12), /* ~= 10^97 */
1675 U64(0xBB445DA9, 0xCA61281F), U64(0x2A8A6E45, 0xAE8EDC97), /* ~= 10^98 */
1676 U64(0xEA157514, 0x3CF97226), U64(0xF52D09D7, 0x1A3293BD), /* ~= 10^99 */
1677 U64(0x924D692C, 0xA61BE758), U64(0x593C2626, 0x705F9C56), /* ~= 10^100 */
1678 U64(0xB6E0C377, 0xCFA2E12E), U64(0x6F8B2FB0, 0x0C77836C), /* ~= 10^101 */
1679 U64(0xE498F455, 0xC38B997A), U64(0x0B6DFB9C, 0x0F956447), /* ~= 10^102 */
1680 U64(0x8EDF98B5, 0x9A373FEC), U64(0x4724BD41, 0x89BD5EAC), /* ~= 10^103 */
1681 U64(0xB2977EE3, 0x00C50FE7), U64(0x58EDEC91, 0xEC2CB657), /* ~= 10^104 */
1682 U64(0xDF3D5E9B, 0xC0F653E1), U64(0x2F2967B6, 0x6737E3ED), /* ~= 10^105 */
1683 U64(0x8B865B21, 0x5899F46C), U64(0xBD79E0D2, 0x0082EE74), /* ~= 10^106 */
1684 U64(0xAE67F1E9, 0xAEC07187), U64(0xECD85906, 0x80A3AA11), /* ~= 10^107 */
1685 U64(0xDA01EE64, 0x1A708DE9), U64(0xE80E6F48, 0x20CC9495), /* ~= 10^108 */
1686 U64(0x884134FE, 0x908658B2), U64(0x3109058D, 0x147FDCDD), /* ~= 10^109 */
1687 U64(0xAA51823E, 0x34A7EEDE), U64(0xBD4B46F0, 0x599FD415), /* ~= 10^110 */
1688 U64(0xD4E5E2CD, 0xC1D1EA96), U64(0x6C9E18AC, 0x7007C91A), /* ~= 10^111 */
1689 U64(0x850FADC0, 0x9923329E), U64(0x03E2CF6B, 0xC604DDB0), /* ~= 10^112 */
1690 U64(0xA6539930, 0xBF6BFF45), U64(0x84DB8346, 0xB786151C), /* ~= 10^113 */
1691 U64(0xCFE87F7C, 0xEF46FF16), U64(0xE6126418, 0x65679A63), /* ~= 10^114 */
1692 U64(0x81F14FAE, 0x158C5F6E), U64(0x4FCB7E8F, 0x3F60C07E), /* ~= 10^115 */
1693 U64(0xA26DA399, 0x9AEF7749), U64(0xE3BE5E33, 0x0F38F09D), /* ~= 10^116 */
1694 U64(0xCB090C80, 0x01AB551C), U64(0x5CADF5BF, 0xD3072CC5), /* ~= 10^117 */
1695 U64(0xFDCB4FA0, 0x02162A63), U64(0x73D9732F, 0xC7C8F7F6), /* ~= 10^118 */
1696 U64(0x9E9F11C4, 0x014DDA7E), U64(0x2867E7FD, 0xDCDD9AFA), /* ~= 10^119 */
1697 U64(0xC646D635, 0x01A1511D), U64(0xB281E1FD, 0x541501B8), /* ~= 10^120 */
1698 U64(0xF7D88BC2, 0x4209A565), U64(0x1F225A7C, 0xA91A4226), /* ~= 10^121 */
1699 U64(0x9AE75759, 0x6946075F), U64(0x3375788D, 0xE9B06958), /* ~= 10^122 */
1700 U64(0xC1A12D2F, 0xC3978937), U64(0x0052D6B1, 0x641C83AE), /* ~= 10^123 */
1701 U64(0xF209787B, 0xB47D6B84), U64(0xC0678C5D, 0xBD23A49A), /* ~= 10^124 */
1702 U64(0x9745EB4D, 0x50CE6332), U64(0xF840B7BA, 0x963646E0), /* ~= 10^125 */
1703 U64(0xBD176620, 0xA501FBFF), U64(0xB650E5A9, 0x3BC3D898), /* ~= 10^126 */
1704 U64(0xEC5D3FA8, 0xCE427AFF), U64(0xA3E51F13, 0x8AB4CEBE), /* ~= 10^127 */
1705 U64(0x93BA47C9, 0x80E98CDF), U64(0xC66F336C, 0x36B10137), /* ~= 10^128 */
1706 U64(0xB8A8D9BB, 0xE123F017), U64(0xB80B0047, 0x445D4184), /* ~= 10^129 */
1707 U64(0xE6D3102A, 0xD96CEC1D), U64(0xA60DC059, 0x157491E5), /* ~= 10^130 */
1708 U64(0x9043EA1A, 0xC7E41392), U64(0x87C89837, 0xAD68DB2F), /* ~= 10^131 */
1709 U64(0xB454E4A1, 0x79DD1877), U64(0x29BABE45, 0x98C311FB), /* ~= 10^132 */
1710 U64(0xE16A1DC9, 0xD8545E94), U64(0xF4296DD6, 0xFEF3D67A), /* ~= 10^133 */
1711 U64(0x8CE2529E, 0x2734BB1D), U64(0x1899E4A6, 0x5F58660C), /* ~= 10^134 */
1712 U64(0xB01AE745, 0xB101E9E4), U64(0x5EC05DCF, 0xF72E7F8F), /* ~= 10^135 */
1713 U64(0xDC21A117, 0x1D42645D), U64(0x76707543, 0xF4FA1F73), /* ~= 10^136 */
1714 U64(0x899504AE, 0x72497EBA), U64(0x6A06494A, 0x791C53A8), /* ~= 10^137 */
1715 U64(0xABFA45DA, 0x0EDBDE69), U64(0x0487DB9D, 0x17636892), /* ~= 10^138 */
1716 U64(0xD6F8D750, 0x9292D603), U64(0x45A9D284, 0x5D3C42B6), /* ~= 10^139 */
1717 U64(0x865B8692, 0x5B9BC5C2), U64(0x0B8A2392, 0xBA45A9B2), /* ~= 10^140 */
1718 U64(0xA7F26836, 0xF282B732), U64(0x8E6CAC77, 0x68D7141E), /* ~= 10^141 */
1719 U64(0xD1EF0244, 0xAF2364FF), U64(0x3207D795, 0x430CD926), /* ~= 10^142 */
1720 U64(0x8335616A, 0xED761F1F), U64(0x7F44E6BD, 0x49E807B8), /* ~= 10^143 */
1721 U64(0xA402B9C5, 0xA8D3A6E7), U64(0x5F16206C, 0x9C6209A6), /* ~= 10^144 */
1722 U64(0xCD036837, 0x130890A1), U64(0x36DBA887, 0xC37A8C0F), /* ~= 10^145 */
1723 U64(0x80222122, 0x6BE55A64), U64(0xC2494954, 0xDA2C9789), /* ~= 10^146 */
1724 U64(0xA02AA96B, 0x06DEB0FD), U64(0xF2DB9BAA, 0x10B7BD6C), /* ~= 10^147 */
1725 U64(0xC83553C5, 0xC8965D3D), U64(0x6F928294, 0x94E5ACC7), /* ~= 10^148 */
1726 U64(0xFA42A8B7, 0x3ABBF48C), U64(0xCB772339, 0xBA1F17F9), /* ~= 10^149 */
1727 U64(0x9C69A972, 0x84B578D7), U64(0xFF2A7604, 0x14536EFB), /* ~= 10^150 */
1728 U64(0xC38413CF, 0x25E2D70D), U64(0xFEF51385, 0x19684ABA), /* ~= 10^151 */
1729 U64(0xF46518C2, 0xEF5B8CD1), U64(0x7EB25866, 0x5FC25D69), /* ~= 10^152 */
1730 U64(0x98BF2F79, 0xD5993802), U64(0xEF2F773F, 0xFBD97A61), /* ~= 10^153 */
1731 U64(0xBEEEFB58, 0x4AFF8603), U64(0xAAFB550F, 0xFACFD8FA), /* ~= 10^154 */
1732 U64(0xEEAABA2E, 0x5DBF6784), U64(0x95BA2A53, 0xF983CF38), /* ~= 10^155 */
1733 U64(0x952AB45C, 0xFA97A0B2), U64(0xDD945A74, 0x7BF26183), /* ~= 10^156 */
1734 U64(0xBA756174, 0x393D88DF), U64(0x94F97111, 0x9AEEF9E4), /* ~= 10^157 */
1735 U64(0xE912B9D1, 0x478CEB17), U64(0x7A37CD56, 0x01AAB85D), /* ~= 10^158 */
1736 U64(0x91ABB422, 0xCCB812EE), U64(0xAC62E055, 0xC10AB33A), /* ~= 10^159 */
1737 U64(0xB616A12B, 0x7FE617AA), U64(0x577B986B, 0x314D6009), /* ~= 10^160 */
1738 U64(0xE39C4976, 0x5FDF9D94), U64(0xED5A7E85, 0xFDA0B80B), /* ~= 10^161 */
1739 U64(0x8E41ADE9, 0xFBEBC27D), U64(0x14588F13, 0xBE847307), /* ~= 10^162 */
1740 U64(0xB1D21964, 0x7AE6B31C), U64(0x596EB2D8, 0xAE258FC8), /* ~= 10^163 */
1741 U64(0xDE469FBD, 0x99A05FE3), U64(0x6FCA5F8E, 0xD9AEF3BB), /* ~= 10^164 */
1742 U64(0x8AEC23D6, 0x80043BEE), U64(0x25DE7BB9, 0x480D5854), /* ~= 10^165 */
1743 U64(0xADA72CCC, 0x20054AE9), U64(0xAF561AA7, 0x9A10AE6A), /* ~= 10^166 */
1744 U64(0xD910F7FF, 0x28069DA4), U64(0x1B2BA151, 0x8094DA04), /* ~= 10^167 */
1745 U64(0x87AA9AFF, 0x79042286), U64(0x90FB44D2, 0xF05D0842), /* ~= 10^168 */
1746 U64(0xA99541BF, 0x57452B28), U64(0x353A1607, 0xAC744A53), /* ~= 10^169 */
1747 U64(0xD3FA922F, 0x2D1675F2), U64(0x42889B89, 0x97915CE8), /* ~= 10^170 */
1748 U64(0x847C9B5D, 0x7C2E09B7), U64(0x69956135, 0xFEBADA11), /* ~= 10^171 */
1749 U64(0xA59BC234, 0xDB398C25), U64(0x43FAB983, 0x7E699095), /* ~= 10^172 */
1750 U64(0xCF02B2C2, 0x1207EF2E), U64(0x94F967E4, 0x5E03F4BB), /* ~= 10^173 */
1751 U64(0x8161AFB9, 0x4B44F57D), U64(0x1D1BE0EE, 0xBAC278F5), /* ~= 10^174 */
1752 U64(0xA1BA1BA7, 0x9E1632DC), U64(0x6462D92A, 0x69731732), /* ~= 10^175 */
1753 U64(0xCA28A291, 0x859BBF93), U64(0x7D7B8F75, 0x03CFDCFE), /* ~= 10^176 */
1754 U64(0xFCB2CB35, 0xE702AF78), U64(0x5CDA7352, 0x44C3D43E), /* ~= 10^177 */
1755 U64(0x9DEFBF01, 0xB061ADAB), U64(0x3A088813, 0x6AFA64A7), /* ~= 10^178 */
1756 U64(0xC56BAEC2, 0x1C7A1916), U64(0x088AAA18, 0x45B8FDD0), /* ~= 10^179 */
1757 U64(0xF6C69A72, 0xA3989F5B), U64(0x8AAD549E, 0x57273D45), /* ~= 10^180 */
1758 U64(0x9A3C2087, 0xA63F6399), U64(0x36AC54E2, 0xF678864B), /* ~= 10^181 */
1759 U64(0xC0CB28A9, 0x8FCF3C7F), U64(0x84576A1B, 0xB416A7DD), /* ~= 10^182 */
1760 U64(0xF0FDF2D3, 0xF3C30B9F), U64(0x656D44A2, 0xA11C51D5), /* ~= 10^183 */
1761 U64(0x969EB7C4, 0x7859E743), U64(0x9F644AE5, 0xA4B1B325), /* ~= 10^184 */
1762 U64(0xBC4665B5, 0x96706114), U64(0x873D5D9F, 0x0DDE1FEE), /* ~= 10^185 */
1763 U64(0xEB57FF22, 0xFC0C7959), U64(0xA90CB506, 0xD155A7EA), /* ~= 10^186 */
1764 U64(0x9316FF75, 0xDD87CBD8), U64(0x09A7F124, 0x42D588F2), /* ~= 10^187 */
1765 U64(0xB7DCBF53, 0x54E9BECE), U64(0x0C11ED6D, 0x538AEB2F), /* ~= 10^188 */
1766 U64(0xE5D3EF28, 0x2A242E81), U64(0x8F1668C8, 0xA86DA5FA), /* ~= 10^189 */
1767 U64(0x8FA47579, 0x1A569D10), U64(0xF96E017D, 0x694487BC), /* ~= 10^190 */
1768 U64(0xB38D92D7, 0x60EC4455), U64(0x37C981DC, 0xC395A9AC), /* ~= 10^191 */
1769 U64(0xE070F78D, 0x3927556A), U64(0x85BBE253, 0xF47B1417), /* ~= 10^192 */
1770 U64(0x8C469AB8, 0x43B89562), U64(0x93956D74, 0x78CCEC8E), /* ~= 10^193 */
1771 U64(0xAF584166, 0x54A6BABB), U64(0x387AC8D1, 0x970027B2), /* ~= 10^194 */
1772 U64(0xDB2E51BF, 0xE9D0696A), U64(0x06997B05, 0xFCC0319E), /* ~= 10^195 */
1773 U64(0x88FCF317, 0xF22241E2), U64(0x441FECE3, 0xBDF81F03), /* ~= 10^196 */
1774 U64(0xAB3C2FDD, 0xEEAAD25A), U64(0xD527E81C, 0xAD7626C3), /* ~= 10^197 */
1775 U64(0xD60B3BD5, 0x6A5586F1), U64(0x8A71E223, 0xD8D3B074), /* ~= 10^198 */
1776 U64(0x85C70565, 0x62757456), U64(0xF6872D56, 0x67844E49), /* ~= 10^199 */
1777 U64(0xA738C6BE, 0xBB12D16C), U64(0xB428F8AC, 0x016561DB), /* ~= 10^200 */
1778 U64(0xD106F86E, 0x69D785C7), U64(0xE13336D7, 0x01BEBA52), /* ~= 10^201 */
1779 U64(0x82A45B45, 0x0226B39C), U64(0xECC00246, 0x61173473), /* ~= 10^202 */
1780 U64(0xA34D7216, 0x42B06084), U64(0x27F002D7, 0xF95D0190), /* ~= 10^203 */
1781 U64(0xCC20CE9B, 0xD35C78A5), U64(0x31EC038D, 0xF7B441F4), /* ~= 10^204 */
1782 U64(0xFF290242, 0xC83396CE), U64(0x7E670471, 0x75A15271), /* ~= 10^205 */
1783 U64(0x9F79A169, 0xBD203E41), U64(0x0F0062C6, 0xE984D386), /* ~= 10^206 */
1784 U64(0xC75809C4, 0x2C684DD1), U64(0x52C07B78, 0xA3E60868), /* ~= 10^207 */
1785 U64(0xF92E0C35, 0x37826145), U64(0xA7709A56, 0xCCDF8A82), /* ~= 10^208 */
1786 U64(0x9BBCC7A1, 0x42B17CCB), U64(0x88A66076, 0x400BB691), /* ~= 10^209 */
1787 U64(0xC2ABF989, 0x935DDBFE), U64(0x6ACFF893, 0xD00EA435), /* ~= 10^210 */
1788 U64(0xF356F7EB, 0xF83552FE), U64(0x0583F6B8, 0xC4124D43), /* ~= 10^211 */
1789 U64(0x98165AF3, 0x7B2153DE), U64(0xC3727A33, 0x7A8B704A), /* ~= 10^212 */
1790 U64(0xBE1BF1B0, 0x59E9A8D6), U64(0x744F18C0, 0x592E4C5C), /* ~= 10^213 */
1791 U64(0xEDA2EE1C, 0x7064130C), U64(0x1162DEF0, 0x6F79DF73), /* ~= 10^214 */
1792 U64(0x9485D4D1, 0xC63E8BE7), U64(0x8ADDCB56, 0x45AC2BA8), /* ~= 10^215 */
1793 U64(0xB9A74A06, 0x37CE2EE1), U64(0x6D953E2B, 0xD7173692), /* ~= 10^216 */
1794 U64(0xE8111C87, 0xC5C1BA99), U64(0xC8FA8DB6, 0xCCDD0437), /* ~= 10^217 */
1795 U64(0x910AB1D4, 0xDB9914A0), U64(0x1D9C9892, 0x400A22A2), /* ~= 10^218 */
1796 U64(0xB54D5E4A, 0x127F59C8), U64(0x2503BEB6, 0xD00CAB4B), /* ~= 10^219 */
1797 U64(0xE2A0B5DC, 0x971F303A), U64(0x2E44AE64, 0x840FD61D), /* ~= 10^220 */
1798 U64(0x8DA471A9, 0xDE737E24), U64(0x5CEAECFE, 0xD289E5D2), /* ~= 10^221 */
1799 U64(0xB10D8E14, 0x56105DAD), U64(0x7425A83E, 0x872C5F47), /* ~= 10^222 */
1800 U64(0xDD50F199, 0x6B947518), U64(0xD12F124E, 0x28F77719), /* ~= 10^223 */
1801 U64(0x8A5296FF, 0xE33CC92F), U64(0x82BD6B70, 0xD99AAA6F), /* ~= 10^224 */
1802 U64(0xACE73CBF, 0xDC0BFB7B), U64(0x636CC64D, 0x1001550B), /* ~= 10^225 */
1803 U64(0xD8210BEF, 0xD30EFA5A), U64(0x3C47F7E0, 0x5401AA4E), /* ~= 10^226 */
1804 U64(0x8714A775, 0xE3E95C78), U64(0x65ACFAEC, 0x34810A71), /* ~= 10^227 */
1805 U64(0xA8D9D153, 0x5CE3B396), U64(0x7F1839A7, 0x41A14D0D), /* ~= 10^228 */
1806 U64(0xD31045A8, 0x341CA07C), U64(0x1EDE4811, 0x1209A050), /* ~= 10^229 */
1807 U64(0x83EA2B89, 0x2091E44D), U64(0x934AED0A, 0xAB460432), /* ~= 10^230 */
1808 U64(0xA4E4B66B, 0x68B65D60), U64(0xF81DA84D, 0x5617853F), /* ~= 10^231 */
1809 U64(0xCE1DE406, 0x42E3F4B9), U64(0x36251260, 0xAB9D668E), /* ~= 10^232 */
1810 U64(0x80D2AE83, 0xE9CE78F3), U64(0xC1D72B7C, 0x6B426019), /* ~= 10^233 */
1811 U64(0xA1075A24, 0xE4421730), U64(0xB24CF65B, 0x8612F81F), /* ~= 10^234 */
1812 U64(0xC94930AE, 0x1D529CFC), U64(0xDEE033F2, 0x6797B627), /* ~= 10^235 */
1813 U64(0xFB9B7CD9, 0xA4A7443C), U64(0x169840EF, 0x017DA3B1), /* ~= 10^236 */
1814 U64(0x9D412E08, 0x06E88AA5), U64(0x8E1F2895, 0x60EE864E), /* ~= 10^237 */
1815 U64(0xC491798A, 0x08A2AD4E), U64(0xF1A6F2BA, 0xB92A27E2), /* ~= 10^238 */
1816 U64(0xF5B5D7EC, 0x8ACB58A2), U64(0xAE10AF69, 0x6774B1DB), /* ~= 10^239 */
1817 U64(0x9991A6F3, 0xD6BF1765), U64(0xACCA6DA1, 0xE0A8EF29), /* ~= 10^240 */
1818 U64(0xBFF610B0, 0xCC6EDD3F), U64(0x17FD090A, 0x58D32AF3), /* ~= 10^241 */
1819 U64(0xEFF394DC, 0xFF8A948E), U64(0xDDFC4B4C, 0xEF07F5B0), /* ~= 10^242 */
1820 U64(0x95F83D0A, 0x1FB69CD9), U64(0x4ABDAF10, 0x1564F98E), /* ~= 10^243 */
1821 U64(0xBB764C4C, 0xA7A4440F), U64(0x9D6D1AD4, 0x1ABE37F1), /* ~= 10^244 */
1822 U64(0xEA53DF5F, 0xD18D5513), U64(0x84C86189, 0x216DC5ED), /* ~= 10^245 */
1823 U64(0x92746B9B, 0xE2F8552C), U64(0x32FD3CF5, 0xB4E49BB4), /* ~= 10^246 */
1824 U64(0xB7118682, 0xDBB66A77), U64(0x3FBC8C33, 0x221DC2A1), /* ~= 10^247 */
1825 U64(0xE4D5E823, 0x92A40515), U64(0x0FABAF3F, 0xEAA5334A), /* ~= 10^248 */
1826 U64(0x8F05B116, 0x3BA6832D), U64(0x29CB4D87, 0xF2A7400E), /* ~= 10^249 */
1827 U64(0xB2C71D5B, 0xCA9023F8), U64(0x743E20E9, 0xEF511012), /* ~= 10^250 */
1828 U64(0xDF78E4B2, 0xBD342CF6), U64(0x914DA924, 0x6B255416), /* ~= 10^251 */
1829 U64(0x8BAB8EEF, 0xB6409C1A), U64(0x1AD089B6, 0xC2F7548E), /* ~= 10^252 */
1830 U64(0xAE9672AB, 0xA3D0C320), U64(0xA184AC24, 0x73B529B1), /* ~= 10^253 */
1831 U64(0xDA3C0F56, 0x8CC4F3E8), U64(0xC9E5D72D, 0x90A2741E), /* ~= 10^254 */
1832 U64(0x88658996, 0x17FB1871), U64(0x7E2FA67C, 0x7A658892), /* ~= 10^255 */
1833 U64(0xAA7EEBFB, 0x9DF9DE8D), U64(0xDDBB901B, 0x98FEEAB7), /* ~= 10^256 */
1834 U64(0xD51EA6FA, 0x85785631), U64(0x552A7422, 0x7F3EA565), /* ~= 10^257 */
1835 U64(0x8533285C, 0x936B35DE), U64(0xD53A8895, 0x8F87275F), /* ~= 10^258 */
1836 U64(0xA67FF273, 0xB8460356), U64(0x8A892ABA, 0xF368F137), /* ~= 10^259 */
1837 U64(0xD01FEF10, 0xA657842C), U64(0x2D2B7569, 0xB0432D85), /* ~= 10^260 */
1838 U64(0x8213F56A, 0x67F6B29B), U64(0x9C3B2962, 0x0E29FC73), /* ~= 10^261 */
1839 U64(0xA298F2C5, 0x01F45F42), U64(0x8349F3BA, 0x91B47B8F), /* ~= 10^262 */
1840 U64(0xCB3F2F76, 0x42717713), U64(0x241C70A9, 0x36219A73), /* ~= 10^263 */
1841 U64(0xFE0EFB53, 0xD30DD4D7), U64(0xED238CD3, 0x83AA0110), /* ~= 10^264 */
1842 U64(0x9EC95D14, 0x63E8A506), U64(0xF4363804, 0x324A40AA), /* ~= 10^265 */
1843 U64(0xC67BB459, 0x7CE2CE48), U64(0xB143C605, 0x3EDCD0D5), /* ~= 10^266 */
1844 U64(0xF81AA16F, 0xDC1B81DA), U64(0xDD94B786, 0x8E94050A), /* ~= 10^267 */
1845 U64(0x9B10A4E5, 0xE9913128), U64(0xCA7CF2B4, 0x191C8326), /* ~= 10^268 */
1846 U64(0xC1D4CE1F, 0x63F57D72), U64(0xFD1C2F61, 0x1F63A3F0), /* ~= 10^269 */
1847 U64(0xF24A01A7, 0x3CF2DCCF), U64(0xBC633B39, 0x673C8CEC), /* ~= 10^270 */
1848 U64(0x976E4108, 0x8617CA01), U64(0xD5BE0503, 0xE085D813), /* ~= 10^271 */
1849 U64(0xBD49D14A, 0xA79DBC82), U64(0x4B2D8644, 0xD8A74E18), /* ~= 10^272 */
1850 U64(0xEC9C459D, 0x51852BA2), U64(0xDDF8E7D6, 0x0ED1219E), /* ~= 10^273 */
1851 U64(0x93E1AB82, 0x52F33B45), U64(0xCABB90E5, 0xC942B503), /* ~= 10^274 */
1852 U64(0xB8DA1662, 0xE7B00A17), U64(0x3D6A751F, 0x3B936243), /* ~= 10^275 */
1853 U64(0xE7109BFB, 0xA19C0C9D), U64(0x0CC51267, 0x0A783AD4), /* ~= 10^276 */
1854 U64(0x906A617D, 0x450187E2), U64(0x27FB2B80, 0x668B24C5), /* ~= 10^277 */
1855 U64(0xB484F9DC, 0x9641E9DA), U64(0xB1F9F660, 0x802DEDF6), /* ~= 10^278 */
1856 U64(0xE1A63853, 0xBBD26451), U64(0x5E7873F8, 0xA0396973), /* ~= 10^279 */
1857 U64(0x8D07E334, 0x55637EB2), U64(0xDB0B487B, 0x6423E1E8), /* ~= 10^280 */
1858 U64(0xB049DC01, 0x6ABC5E5F), U64(0x91CE1A9A, 0x3D2CDA62), /* ~= 10^281 */
1859 U64(0xDC5C5301, 0xC56B75F7), U64(0x7641A140, 0xCC7810FB), /* ~= 10^282 */
1860 U64(0x89B9B3E1, 0x1B6329BA), U64(0xA9E904C8, 0x7FCB0A9D), /* ~= 10^283 */
1861 U64(0xAC2820D9, 0x623BF429), U64(0x546345FA, 0x9FBDCD44), /* ~= 10^284 */
1862 U64(0xD732290F, 0xBACAF133), U64(0xA97C1779, 0x47AD4095), /* ~= 10^285 */
1863 U64(0x867F59A9, 0xD4BED6C0), U64(0x49ED8EAB, 0xCCCC485D), /* ~= 10^286 */
1864 U64(0xA81F3014, 0x49EE8C70), U64(0x5C68F256, 0xBFFF5A74), /* ~= 10^287 */
1865 U64(0xD226FC19, 0x5C6A2F8C), U64(0x73832EEC, 0x6FFF3111), /* ~= 10^288 */
1866 U64(0x83585D8F, 0xD9C25DB7), U64(0xC831FD53, 0xC5FF7EAB), /* ~= 10^289 */
1867 U64(0xA42E74F3, 0xD032F525), U64(0xBA3E7CA8, 0xB77F5E55), /* ~= 10^290 */
1868 U64(0xCD3A1230, 0xC43FB26F), U64(0x28CE1BD2, 0xE55F35EB), /* ~= 10^291 */
1869 U64(0x80444B5E, 0x7AA7CF85), U64(0x7980D163, 0xCF5B81B3), /* ~= 10^292 */
1870 U64(0xA0555E36, 0x1951C366), U64(0xD7E105BC, 0xC332621F), /* ~= 10^293 */
1871 U64(0xC86AB5C3, 0x9FA63440), U64(0x8DD9472B, 0xF3FEFAA7), /* ~= 10^294 */
1872 U64(0xFA856334, 0x878FC150), U64(0xB14F98F6, 0xF0FEB951), /* ~= 10^295 */
1873 U64(0x9C935E00, 0xD4B9D8D2), U64(0x6ED1BF9A, 0x569F33D3), /* ~= 10^296 */
1874 U64(0xC3B83581, 0x09E84F07), U64(0x0A862F80, 0xEC4700C8), /* ~= 10^297 */
1875 U64(0xF4A642E1, 0x4C6262C8), U64(0xCD27BB61, 0x2758C0FA), /* ~= 10^298 */
1876 U64(0x98E7E9CC, 0xCFBD7DBD), U64(0x8038D51C, 0xB897789C), /* ~= 10^299 */
1877 U64(0xBF21E440, 0x03ACDD2C), U64(0xE0470A63, 0xE6BD56C3), /* ~= 10^300 */
1878 U64(0xEEEA5D50, 0x04981478), U64(0x1858CCFC, 0xE06CAC74), /* ~= 10^301 */
1879 U64(0x95527A52, 0x02DF0CCB), U64(0x0F37801E, 0x0C43EBC8), /* ~= 10^302 */
1880 U64(0xBAA718E6, 0x8396CFFD), U64(0xD3056025, 0x8F54E6BA), /* ~= 10^303 */
1881 U64(0xE950DF20, 0x247C83FD), U64(0x47C6B82E, 0xF32A2069), /* ~= 10^304 */
1882 U64(0x91D28B74, 0x16CDD27E), U64(0x4CDC331D, 0x57FA5441), /* ~= 10^305 */
1883 U64(0xB6472E51, 0x1C81471D), U64(0xE0133FE4, 0xADF8E952), /* ~= 10^306 */
1884 U64(0xE3D8F9E5, 0x63A198E5), U64(0x58180FDD, 0xD97723A6), /* ~= 10^307 */
1885 U64(0x8E679C2F, 0x5E44FF8F), U64(0x570F09EA, 0xA7EA7648), /* ~= 10^308 */
1886 U64(0xB201833B, 0x35D63F73), U64(0x2CD2CC65, 0x51E513DA), /* ~= 10^309 */
1887 U64(0xDE81E40A, 0x034BCF4F), U64(0xF8077F7E, 0xA65E58D1), /* ~= 10^310 */
1888 U64(0x8B112E86, 0x420F6191), U64(0xFB04AFAF, 0x27FAF782), /* ~= 10^311 */
1889 U64(0xADD57A27, 0xD29339F6), U64(0x79C5DB9A, 0xF1F9B563), /* ~= 10^312 */
1890 U64(0xD94AD8B1, 0xC7380874), U64(0x18375281, 0xAE7822BC), /* ~= 10^313 */
1891 U64(0x87CEC76F, 0x1C830548), U64(0x8F229391, 0x0D0B15B5), /* ~= 10^314 */
1892 U64(0xA9C2794A, 0xE3A3C69A), U64(0xB2EB3875, 0x504DDB22), /* ~= 10^315 */
1893 U64(0xD433179D, 0x9C8CB841), U64(0x5FA60692, 0xA46151EB), /* ~= 10^316 */
1894 U64(0x849FEEC2, 0x81D7F328), U64(0xDBC7C41B, 0xA6BCD333), /* ~= 10^317 */
1895 U64(0xA5C7EA73, 0x224DEFF3), U64(0x12B9B522, 0x906C0800), /* ~= 10^318 */
1896 U64(0xCF39E50F, 0xEAE16BEF), U64(0xD768226B, 0x34870A00), /* ~= 10^319 */
1897 U64(0x81842F29, 0xF2CCE375), U64(0xE6A11583, 0x00D46640), /* ~= 10^320 */
1898 U64(0xA1E53AF4, 0x6F801C53), U64(0x60495AE3, 0xC1097FD0), /* ~= 10^321 */
1899 U64(0xCA5E89B1, 0x8B602368), U64(0x385BB19C, 0xB14BDFC4), /* ~= 10^322 */
1900 U64(0xFCF62C1D, 0xEE382C42), U64(0x46729E03, 0xDD9ED7B5), /* ~= 10^323 */
1901 U64(0x9E19DB92, 0xB4E31BA9), U64(0x6C07A2C2, 0x6A8346D1) /* ~= 10^324 */
1902};
1903
1904/**
1905 Get the cached pow10 value from `pow10_sig_table`.
1906 @param exp10 The exponent of pow(10, e). This value must be in the range
1907 `POW10_SIG_TABLE_MIN_EXP` to `POW10_SIG_TABLE_MAX_EXP`.
1908 @param hi The highest 64 bits of pow(10, e).
1909 @param lo The lower 64 bits after `hi`.
1910 */
1911static_inline void pow10_table_get_sig(i32 exp10, u64 *hi, u64 *lo) {
1912 i32 idx = exp10 - (POW10_SIG_TABLE_MIN_EXP);
1913 *hi = pow10_sig_table[idx * 2];
1914 *lo = pow10_sig_table[idx * 2 + 1];
1915}
1916
1917/**
1918 Get the exponent (base 2) for the highest 64-bit significand in
1919 `pow10_sig_table`.
1920 */
1921static_inline void pow10_table_get_exp(i32 exp10, i32 *exp2) {
1922 /* e2 = floor(log2(pow(10, e))) - 64 + 1 */
1923 /* = floor(e * log2(10) - 63) */
1924 *exp2 = (exp10 * 217706 - 4128768) >> 16;
1925}
1926
1927#endif
1928
1929
1930
1931/*==============================================================================
1932 * MARK: - Number and Bit Utils (Private)
1933 *============================================================================*/
1934
1935/** Convert bits to double. */
1936static_inline f64 f64_from_bits(u64 u) {
1937 f64 f;
1938 memcpy(&f, &u, sizeof(u));
1939 return f;
1940}
1941
1942/** Convert double to bits. */
1944 u64 u;
1945 memcpy(&u, &f, sizeof(u));
1946 return u;
1947}
1948
1949/** Convert float to bits. */
1951 u32 u;
1952 memcpy(&u, &f, sizeof(u));
1953 return u;
1954}
1955
1956/** Get 'infinity' bits with sign. */
1958#if YYJSON_HAS_IEEE_754
1959 return F64_BITS_INF | ((u64)sign << 63);
1960#else
1961 return f64_to_bits(sign ? (f64)-INFINITY : (f64)INFINITY);
1962#endif
1963}
1964
1965/** Returns whether the double value is infinity (not NaN). */
1967#if YYJSON_HAS_IEEE_754
1968 return (f64_to_bits(val) & F64_EXP_MASK) == F64_BITS_INF;
1969#else
1970 return val >= (f64)INFINITY || val <= (f64)-INFINITY;
1971#endif
1972}
1973
1974/** Get 'nan' bits with sign. */
1976#if YYJSON_HAS_IEEE_754
1977 return F64_BITS_NAN | ((u64)sign << 63);
1978#else
1979 return f64_to_bits(sign ? (f64)-NAN : (f64)NAN);
1980#endif
1981}
1982
1983/** Casting double to float, allow overflow. */
1984#if yyjson_has_attribute(no_sanitize)
1985__attribute__((no_sanitize("undefined")))
1986#elif yyjson_gcc_available(4, 9, 0)
1987__attribute__((__no_sanitize_undefined__))
1988#endif
1990 return (f32)val;
1991}
1992
1993/** Returns the number of leading 0-bits in value (input should not be 0). */
1995#if GCC_HAS_CLZLL
1996 return (u32)__builtin_clzll(v);
1997#elif MSC_HAS_BIT_SCAN_64
1998 unsigned long r;
1999 _BitScanReverse64(&r, v);
2000 return (u32)63 - (u32)r;
2001#elif MSC_HAS_BIT_SCAN
2002 unsigned long hi, lo;
2003 bool hi_set = _BitScanReverse(&hi, (u32)(v >> 32)) != 0;
2004 _BitScanReverse(&lo, (u32)v);
2005 hi |= 32;
2006 return (u32)63 - (u32)(hi_set ? hi : lo);
2007#else
2008 /* branchless, use De Bruijn sequence */
2009 /* see: https://www.chessprogramming.org/BitScan */
2010 const u8 table[64] = {
2011 63, 16, 62, 7, 15, 36, 61, 3, 6, 14, 22, 26, 35, 47, 60, 2,
2012 9, 5, 28, 11, 13, 21, 42, 19, 25, 31, 34, 40, 46, 52, 59, 1,
2013 17, 8, 37, 4, 23, 27, 48, 10, 29, 12, 43, 20, 32, 41, 53, 18,
2014 38, 24, 49, 30, 44, 33, 54, 39, 50, 45, 55, 51, 56, 57, 58, 0
2015 };
2016 v |= v >> 1;
2017 v |= v >> 2;
2018 v |= v >> 4;
2019 v |= v >> 8;
2020 v |= v >> 16;
2021 v |= v >> 32;
2022 return table[(v * U64(0x03F79D71, 0xB4CB0A89)) >> 58];
2023#endif
2024}
2025
2026/** Returns the number of trailing 0-bits in value (input should not be 0). */
2028#if GCC_HAS_CTZLL
2029 return (u32)__builtin_ctzll(v);
2030#elif MSC_HAS_BIT_SCAN_64
2031 unsigned long r;
2032 _BitScanForward64(&r, v);
2033 return (u32)r;
2034#elif MSC_HAS_BIT_SCAN
2035 unsigned long lo, hi;
2036 bool lo_set = _BitScanForward(&lo, (u32)(v)) != 0;
2037 _BitScanForward(&hi, (u32)(v >> 32));
2038 hi += 32;
2039 return lo_set ? lo : hi;
2040#else
2041 /* branchless, use De Bruijn sequence */
2042 /* see: https://www.chessprogramming.org/BitScan */
2043 const u8 table[64] = {
2044 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28,
2045 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11,
2046 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
2047 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12
2048 };
2049 return table[((v & (~v + 1)) * U64(0x022FDD63, 0xCC95386D)) >> 58];
2050#endif
2051}
2052
2053/** Multiplies two 64-bit unsigned integers (a * b),
2054 returns the 128-bit result as 'hi' and 'lo'. */
2055static_inline void u128_mul(u64 a, u64 b, u64 *hi, u64 *lo) {
2056#if YYJSON_HAS_INT128
2057 u128 m = (u128)a * b;
2058 *hi = (u64)(m >> 64);
2059 *lo = (u64)(m);
2060#elif MSC_HAS_UMUL128
2061 *lo = _umul128(a, b, hi);
2062#else
2063 u32 a0 = (u32)(a), a1 = (u32)(a >> 32);
2064 u32 b0 = (u32)(b), b1 = (u32)(b >> 32);
2065 u64 p00 = (u64)a0 * b0, p01 = (u64)a0 * b1;
2066 u64 p10 = (u64)a1 * b0, p11 = (u64)a1 * b1;
2067 u64 m0 = p01 + (p00 >> 32);
2068 u32 m00 = (u32)(m0), m01 = (u32)(m0 >> 32);
2069 u64 m1 = p10 + m00;
2070 u32 m10 = (u32)(m1), m11 = (u32)(m1 >> 32);
2071 *hi = p11 + m01 + m11;
2072 *lo = ((u64)m10 << 32) | (u32)p00;
2073#endif
2074}
2075
2076/** Multiplies two 64-bit unsigned integers and add a value (a * b + c),
2077 returns the 128-bit result as 'hi' and 'lo'. */
2078static_inline void u128_mul_add(u64 a, u64 b, u64 c, u64 *hi, u64 *lo) {
2079#if YYJSON_HAS_INT128
2080 u128 m = (u128)a * b + c;
2081 *hi = (u64)(m >> 64);
2082 *lo = (u64)(m);
2083#else
2084 u64 h, l, t;
2085 u128_mul(a, b, &h, &l);
2086 t = l + c;
2087 h += (u64)(((t < l) | (t < c)));
2088 *hi = h;
2089 *lo = t;
2090#endif
2091}
2092
2093
2094
2095/*==============================================================================
2096 * MARK: - File Utils (Private)
2097 * These functions are used to read and write JSON files.
2098 *============================================================================*/
2099
2100#if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE
2101
2102#define YYJSON_FOPEN_E
2103#if !defined(_MSC_VER) && defined(__GLIBC__) && defined(__GLIBC_PREREQ)
2104# if __GLIBC_PREREQ(2, 7)
2105# undef YYJSON_FOPEN_E
2106# define YYJSON_FOPEN_E "e" /* glibc extension to enable O_CLOEXEC */
2107# endif
2108#endif
2109
2110static_inline FILE *fopen_safe(const char *path, const char *mode) {
2111#if YYJSON_MSC_VER >= 1400
2112 FILE *file = NULL;
2113 if (fopen_s(&file, path, mode) != 0) return NULL;
2114 return file;
2115#else
2116 return fopen(path, mode);
2117#endif
2118}
2119
2120static_inline FILE *fopen_readonly(const char *path) {
2121 return fopen_safe(path, "rb" YYJSON_FOPEN_E);
2122}
2123
2124static_inline FILE *fopen_writeonly(const char *path) {
2125 return fopen_safe(path, "wb" YYJSON_FOPEN_E);
2126}
2127
2128static_inline usize fread_safe(void *buf, usize size, FILE *file) {
2129#if YYJSON_MSC_VER >= 1400
2130 return fread_s(buf, size, 1, size, file);
2131#else
2132 return fread(buf, 1, size, file);
2133#endif
2134}
2135
2136#endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */
2137
2138
2139
2140/*==============================================================================
2141 * MARK: - Size Utils (Private)
2142 * These functions are used for memory allocation.
2143 *============================================================================*/
2144
2145/** Returns whether the size is overflow after increment. */
2147 return size > (size + add);
2148}
2149
2150/** Returns whether the size is power of 2 (size should not be 0). */
2152 return (size & (size - 1)) == 0;
2153}
2154
2155/** Align size upwards (may overflow). */
2157 if (size_is_pow2(align)) {
2158 return (size + (align - 1)) & ~(align - 1);
2159 } else {
2160 return size + align - (size + align - 1) % align - 1;
2161 }
2162}
2163
2164/** Align size downwards. */
2166 if (size_is_pow2(align)) {
2167 return size & ~(align - 1);
2168 } else {
2169 return size - (size % align);
2170 }
2171}
2172
2173/** Align address upwards (may overflow). */
2174static_inline void *mem_align_up(void *mem, usize align) {
2175 usize size;
2176 memcpy(&size, &mem, sizeof(usize));
2177 size = size_align_up(size, align);
2178 memcpy(&mem, &size, sizeof(usize));
2179 return mem;
2180}
2181
2182
2183
2184/*==============================================================================
2185 * MARK: - Null Memory Allocator (Private)
2186 * This allocator is just a placeholder to ensure that the internal
2187 * malloc/realloc/free function pointers are not null.
2188 *============================================================================*/
2189
2190static void *null_malloc(void *ctx, usize size) {
2191 return NULL;
2192}
2193
2194static void *null_realloc(void *ctx, void *ptr, usize old_size, usize size) {
2195 return NULL;
2196}
2197
2198static void null_free(void *ctx, void *ptr) {
2199 return;
2200}
2201
2204};
2205
2206
2207
2208/*==============================================================================
2209 * MARK: - Default Memory Allocator (Private)
2210 * This is a simple libc memory allocator wrapper.
2211 *============================================================================*/
2212
2213#if defined(YYJSON_CUSTOM_ALC)
2214
2215/* user-provided via macro */
2216extern const yyjson_alc YYJSON_CUSTOM_ALC;
2217#define YYJSON_DEFAULT_ALC YYJSON_CUSTOM_ALC
2218
2219#elif YYJSON_FREESTANDING
2220
2221/* null allocator */
2222static const yyjson_alc YYJSON_DEFAULT_ALC = {
2224};
2225
2226#else /* YYJSON_FREESTANDING */
2227
2228/* default libc allocator */
2229static void *default_malloc(void *ctx, usize size) {
2230 return malloc(size);
2231}
2232static void *default_realloc(void *ctx, void *ptr, usize old_size, usize size) {
2233 return realloc(ptr, size);
2234}
2235static void default_free(void *ctx, void *ptr) {
2236 free(ptr);
2237}
2241
2242#endif /* YYJSON_FREESTANDING */
2243
2244
2245
2246/*==============================================================================
2247 * MARK: - Pool Memory Allocator (Public)
2248 * This allocator is initialized with a fixed-size buffer.
2249 * The buffer is split into multiple memory chunks for memory allocation.
2250 *============================================================================*/
2251
2252/** memory chunk header */
2253typedef struct pool_chunk {
2254 usize size; /* chunk memory size, including chunk header */
2255 struct pool_chunk *next; /* linked list, nullable */
2256 /* char mem[]; flexible array member */
2258
2259/** allocator ctx header */
2260typedef struct pool_ctx {
2261 usize size; /* total memory size, including ctx header */
2262 pool_chunk *free_list; /* linked list, nullable */
2263 /* pool_chunk chunks[]; flexible array member */
2265
2266/** align up the input size to chunk size */
2268 *size = size_align_up(*size, sizeof(pool_chunk)) + sizeof(pool_chunk);
2269}
2270
2271static void *pool_malloc(void *ctx_ptr, usize size) {
2272 /* assert(size != 0) */
2273 pool_ctx *ctx = (pool_ctx *)ctx_ptr;
2274 pool_chunk *next, *prev = NULL, *cur = ctx->free_list;
2275
2276 if (unlikely(size >= ctx->size)) return NULL;
2277 pool_size_align(&size);
2278
2279 while (cur) {
2280 if (cur->size < size) {
2281 /* not enough space, try next chunk */
2282 prev = cur;
2283 cur = cur->next;
2284 continue;
2285 }
2286 if (cur->size >= size + sizeof(pool_chunk) * 2) {
2287 /* too much space, split this chunk */
2288 next = (pool_chunk *)(void *)((u8 *)cur + size);
2289 next->size = cur->size - size;
2290 next->next = cur->next;
2291 cur->size = size;
2292 } else {
2293 /* just enough space, use whole chunk */
2294 next = cur->next;
2295 }
2296 if (prev) prev->next = next;
2297 else ctx->free_list = next;
2298 return (void *)(cur + 1);
2299 }
2300 return NULL;
2301}
2302
2303static void pool_free(void *ctx_ptr, void *ptr) {
2304 /* assert(ptr != NULL) */
2305 pool_ctx *ctx = (pool_ctx *)ctx_ptr;
2306 pool_chunk *cur = ((pool_chunk *)ptr) - 1;
2307 pool_chunk *prev = NULL, *next = ctx->free_list;
2308
2309 while (next && next < cur) {
2310 prev = next;
2311 next = next->next;
2312 }
2313 if (prev) prev->next = cur;
2314 else ctx->free_list = cur;
2315 cur->next = next;
2316
2317 if (next && ((u8 *)cur + cur->size) == (u8 *)next) {
2318 /* merge cur to higher chunk */
2319 cur->size += next->size;
2320 cur->next = next->next;
2321 }
2322 if (prev && ((u8 *)prev + prev->size) == (u8 *)cur) {
2323 /* merge cur to lower chunk */
2324 prev->size += cur->size;
2325 prev->next = cur->next;
2326 }
2327}
2328
2329static void *pool_realloc(void *ctx_ptr, void *ptr,
2330 usize old_size, usize size) {
2331 /* assert(ptr != NULL && size != 0 && old_size < size) */
2332 pool_ctx *ctx = (pool_ctx *)ctx_ptr;
2333 pool_chunk *cur = ((pool_chunk *)ptr) - 1, *prev, *next, *tmp;
2334
2335 /* check size */
2336 if (unlikely(size >= ctx->size)) return NULL;
2337 pool_size_align(&old_size);
2338 pool_size_align(&size);
2339 if (unlikely(old_size == size)) return ptr;
2340
2341 /* find next and prev chunk */
2342 prev = NULL;
2343 next = ctx->free_list;
2344 while (next && next < cur) {
2345 prev = next;
2346 next = next->next;
2347 }
2348
2349 if ((u8 *)cur + cur->size == (u8 *)next && cur->size + next->size >= size) {
2350 /* merge to higher chunk if they are contiguous */
2351 usize free_size = cur->size + next->size - size;
2352 if (free_size > sizeof(pool_chunk) * 2) {
2353 tmp = (pool_chunk *)(void *)((u8 *)cur + size);
2354 if (prev) prev->next = tmp;
2355 else ctx->free_list = tmp;
2356 tmp->next = next->next;
2357 tmp->size = free_size;
2358 cur->size = size;
2359 } else {
2360 if (prev) prev->next = next->next;
2361 else ctx->free_list = next->next;
2362 cur->size += next->size;
2363 }
2364 return ptr;
2365 } else {
2366 /* fallback to malloc and memcpy */
2367 void *new_ptr = pool_malloc(ctx_ptr, size - sizeof(pool_chunk));
2368 if (new_ptr) {
2369 memcpy(new_ptr, ptr, cur->size - sizeof(pool_chunk));
2370 pool_free(ctx_ptr, ptr);
2371 }
2372 return new_ptr;
2373 }
2374}
2375
2376bool yyjson_alc_pool_init(yyjson_alc *alc, void *buf, usize size) {
2377 pool_chunk *chunk;
2378 pool_ctx *ctx;
2379
2380 if (unlikely(!alc)) return false;
2381 *alc = YYJSON_NULL_ALC;
2382 if (size < sizeof(pool_ctx) * 4) return false;
2383 ctx = (pool_ctx *)mem_align_up(buf, sizeof(pool_ctx));
2384 if (unlikely(!ctx)) return false;
2385 size -= (usize)((u8 *)ctx - (u8 *)buf);
2386 size = size_align_down(size, sizeof(pool_ctx));
2387
2388 chunk = (pool_chunk *)(ctx + 1);
2389 chunk->size = size - sizeof(pool_ctx);
2390 chunk->next = NULL;
2391 ctx->size = size;
2392 ctx->free_list = chunk;
2393
2394 alc->malloc = pool_malloc;
2395 alc->realloc = pool_realloc;
2396 alc->free = pool_free;
2397 alc->ctx = (void *)ctx;
2398 return true;
2399}
2400
2401
2402
2403/*==============================================================================
2404 * MARK: - Dynamic Memory Allocator (Public)
2405 * This allocator allocates memory on demand and does not immediately release
2406 * unused memory. Instead, it places the unused memory into a freelist for
2407 * potential reuse in the future. It is only when the entire allocator is
2408 * destroyed that all previously allocated memory is released at once.
2409 *============================================================================*/
2410
2411/** memory chunk header */
2412typedef struct dyn_chunk {
2413 usize size; /* chunk size, including header */
2415 /* char mem[]; flexible array member */
2417
2418/** allocator ctx header */
2419typedef struct {
2420 dyn_chunk free_list; /* dummy header, sorted from small to large */
2421 dyn_chunk used_list; /* dummy header */
2422} dyn_ctx;
2423
2424/** align up the input size to chunk size */
2426 usize alc_size = *size + sizeof(dyn_chunk);
2427 alc_size = size_align_up(alc_size, YYJSON_ALC_DYN_MIN_SIZE);
2428 if (unlikely(alc_size < *size)) return false; /* overflow */
2429 *size = alc_size;
2430 return true;
2431}
2432
2433/** remove a chunk from list (the chunk must already be in the list) */
2435 dyn_chunk *prev = list, *cur;
2436 for (cur = prev->next; cur; cur = cur->next) {
2437 if (cur == chunk) {
2438 prev->next = cur->next;
2439 cur->next = NULL;
2440 return;
2441 }
2442 prev = cur;
2443 }
2444}
2445
2446/** add a chunk to list header (the chunk must not be in the list) */
2448 chunk->next = list->next;
2449 list->next = chunk;
2450}
2451
2452static void *dyn_malloc(void *ctx_ptr, usize size) {
2453 /* assert(size != 0) */
2454 const yyjson_alc def = YYJSON_DEFAULT_ALC;
2455 dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
2456 dyn_chunk *chunk, *prev;
2457 if (unlikely(!dyn_size_align(&size))) return NULL;
2458
2459 /* freelist is empty, create new chunk */
2460 if (!ctx->free_list.next) {
2461 chunk = (dyn_chunk *)def.malloc(def.ctx, size);
2462 if (unlikely(!chunk)) return NULL;
2463 chunk->size = size;
2464 chunk->next = NULL;
2465 dyn_chunk_list_add(&ctx->used_list, chunk);
2466 return (void *)(chunk + 1);
2467 }
2468
2469 /* find a large enough chunk, or resize the largest chunk */
2470 prev = &ctx->free_list;
2471 while (true) {
2472 chunk = prev->next;
2473 if (chunk->size >= size) { /* enough size, reuse this chunk */
2474 prev->next = chunk->next;
2475 dyn_chunk_list_add(&ctx->used_list, chunk);
2476 return (void *)(chunk + 1);
2477 }
2478 if (!chunk->next) { /* resize the largest chunk */
2479 chunk = (dyn_chunk *)def.realloc(def.ctx, chunk, chunk->size, size);
2480 if (unlikely(!chunk)) return NULL;
2481 prev->next = NULL;
2482 chunk->size = size;
2483 dyn_chunk_list_add(&ctx->used_list, chunk);
2484 return (void *)(chunk + 1);
2485 }
2486 prev = chunk;
2487 }
2488}
2489
2490static void *dyn_realloc(void *ctx_ptr, void *ptr,
2491 usize old_size, usize size) {
2492 /* assert(ptr != NULL && size != 0 && old_size < size) */
2493 const yyjson_alc def = YYJSON_DEFAULT_ALC;
2494 dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
2495 dyn_chunk *new_chunk, *chunk = (dyn_chunk *)ptr - 1;
2496 if (unlikely(!dyn_size_align(&size))) return NULL;
2497 if (chunk->size >= size) return ptr;
2498
2499 dyn_chunk_list_remove(&ctx->used_list, chunk);
2500 new_chunk = (dyn_chunk *)def.realloc(def.ctx, chunk, chunk->size, size);
2501 if (likely(new_chunk)) {
2502 new_chunk->size = size;
2503 chunk = new_chunk;
2504 }
2505 dyn_chunk_list_add(&ctx->used_list, chunk);
2506 return new_chunk ? (void *)(new_chunk + 1) : NULL;
2507}
2508
2509static void dyn_free(void *ctx_ptr, void *ptr) {
2510 /* assert(ptr != NULL) */
2511 dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
2512 dyn_chunk *chunk = (dyn_chunk *)ptr - 1, *prev;
2513
2514 dyn_chunk_list_remove(&ctx->used_list, chunk);
2515 for (prev = &ctx->free_list; prev; prev = prev->next) {
2516 if (!prev->next || prev->next->size >= chunk->size) {
2517 chunk->next = prev->next;
2518 prev->next = chunk;
2519 break;
2520 }
2521 }
2522}
2523
2525 const yyjson_alc def = YYJSON_DEFAULT_ALC;
2526 usize hdr_len = sizeof(yyjson_alc) + sizeof(dyn_ctx);
2527 yyjson_alc *alc;
2528 dyn_ctx *ctx;
2529 alc = (yyjson_alc *)def.malloc(def.ctx, hdr_len);
2530 if (unlikely(!alc)) return NULL;
2531 ctx = (dyn_ctx *)(void *)(alc + 1);
2532 alc->malloc = dyn_malloc;
2533 alc->realloc = dyn_realloc;
2534 alc->free = dyn_free;
2535 alc->ctx = alc + 1;
2536 memset(ctx, 0, sizeof(*ctx));
2537 return alc;
2538}
2539
2541 const yyjson_alc def = YYJSON_DEFAULT_ALC;
2542 dyn_ctx *ctx;
2543 dyn_chunk *chunk, *next;
2544 if (unlikely(!alc)) return;
2545 ctx = (dyn_ctx *)(void *)(alc + 1);
2546 for (chunk = ctx->free_list.next; chunk; chunk = next) {
2547 next = chunk->next;
2548 def.free(def.ctx, chunk);
2549 }
2550 for (chunk = ctx->used_list.next; chunk; chunk = next) {
2551 next = chunk->next;
2552 def.free(def.ctx, chunk);
2553 }
2554 def.free(def.ctx, alc);
2555}
2556
2557
2558
2559/*==============================================================================
2560 * MARK: - JSON Struct Utils (Public)
2561 * These functions are used for creating, copying, releasing, and comparing
2562 * JSON documents and values. They are widely used throughout this library.
2563 *============================================================================*/
2564
2566 yyjson_alc *alc) {
2567 yyjson_str_chunk *chunk = pool->chunks, *next;
2568 while (chunk) {
2569 next = chunk->next;
2570 alc->free(alc->ctx, chunk);
2571 chunk = next;
2572 }
2573}
2574
2576 yyjson_alc *alc) {
2577 yyjson_val_chunk *chunk = pool->chunks, *next;
2578 while (chunk) {
2579 next = chunk->next;
2580 alc->free(alc->ctx, chunk);
2581 chunk = next;
2582 }
2583}
2584
2586 const yyjson_alc *alc, usize len) {
2587 yyjson_str_chunk *chunk;
2588 usize size, max_len;
2589
2590 /* create a new chunk */
2591 max_len = USIZE_MAX - sizeof(yyjson_str_chunk);
2592 if (unlikely(len > max_len)) return false;
2593 size = len + sizeof(yyjson_str_chunk);
2594 size = yyjson_max(pool->chunk_size, size);
2595 chunk = (yyjson_str_chunk *)alc->malloc(alc->ctx, size);
2596 if (unlikely(!chunk)) return false;
2597
2598 /* insert the new chunk as the head of the linked list */
2599 chunk->next = pool->chunks;
2600 chunk->chunk_size = size;
2601 pool->chunks = chunk;
2602 pool->cur = (char *)chunk + sizeof(yyjson_str_chunk);
2603 pool->end = (char *)chunk + size;
2604
2605 /* the next chunk is twice the size of the current one */
2606 size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max);
2607 if (size < pool->chunk_size) size = pool->chunk_size_max; /* overflow */
2608 pool->chunk_size = size;
2609 return true;
2610}
2611
2613 const yyjson_alc *alc, usize count) {
2614 yyjson_val_chunk *chunk;
2615 usize size, max_count;
2616
2617 /* create a new chunk */
2618 max_count = USIZE_MAX / sizeof(yyjson_mut_val) - 1;
2619 if (unlikely(count > max_count)) return false;
2620 size = (count + 1) * sizeof(yyjson_mut_val);
2621 size = yyjson_max(pool->chunk_size, size);
2622 chunk = (yyjson_val_chunk *)alc->malloc(alc->ctx, size);
2623 if (unlikely(!chunk)) return false;
2624
2625 /* insert the new chunk as the head of the linked list */
2626 chunk->next = pool->chunks;
2627 chunk->chunk_size = size;
2628 pool->chunks = chunk;
2629 pool->cur = (yyjson_mut_val *)(void *)((u8 *)chunk) + 1;
2630 pool->end = (yyjson_mut_val *)(void *)((u8 *)chunk + size);
2631
2632 /* the next chunk is twice the size of the current one */
2633 size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max);
2634 if (size < pool->chunk_size) size = pool->chunk_size_max; /* overflow */
2635 pool->chunk_size = size;
2636 return true;
2637}
2638
2640 usize max_size = USIZE_MAX - sizeof(yyjson_str_chunk);
2641 if (!doc || !len || len > max_size) return false;
2642 doc->str_pool.chunk_size = len + sizeof(yyjson_str_chunk);
2643 return true;
2644}
2645
2647 usize max_count = USIZE_MAX / sizeof(yyjson_mut_val) - 1;
2648 if (!doc || !count || count > max_count) return false;
2649 doc->val_pool.chunk_size = (count + 1) * sizeof(yyjson_mut_val);
2650 return true;
2651}
2652
2654 if (doc) {
2655 yyjson_alc alc = doc->alc;
2656 memset(&doc->alc, 0, sizeof(alc));
2659 alc.free(alc.ctx, doc);
2660 }
2661}
2662
2664 yyjson_mut_doc *doc;
2665 if (!alc) alc = &YYJSON_DEFAULT_ALC;
2666 doc = (yyjson_mut_doc *)alc->malloc(alc->ctx, sizeof(yyjson_mut_doc));
2667 if (!doc) return NULL;
2668 memset(doc, 0, sizeof(yyjson_mut_doc));
2669
2670 doc->alc = *alc;
2675 return doc;
2676}
2677
2679 const yyjson_alc *alc) {
2680 yyjson_mut_doc *m_doc;
2681 yyjson_mut_val *m_val;
2682
2683 if (!doc || !doc->root) return NULL;
2684 m_doc = yyjson_mut_doc_new(alc);
2685 if (!m_doc) return NULL;
2686 m_val = yyjson_val_mut_copy(m_doc, doc->root);
2687 if (!m_val) {
2688 yyjson_mut_doc_free(m_doc);
2689 return NULL;
2690 }
2691 yyjson_mut_doc_set_root(m_doc, m_val);
2692 return m_doc;
2693}
2694
2696 const yyjson_alc *alc) {
2697 yyjson_mut_doc *m_doc;
2698 yyjson_mut_val *m_val;
2699
2700 if (!doc) return NULL;
2701 if (!doc->root) return yyjson_mut_doc_new(alc);
2702
2703 m_doc = yyjson_mut_doc_new(alc);
2704 if (!m_doc) return NULL;
2705 m_val = yyjson_mut_val_mut_copy(m_doc, doc->root);
2706 if (!m_val) {
2707 yyjson_mut_doc_free(m_doc);
2708 return NULL;
2709 }
2710 yyjson_mut_doc_set_root(m_doc, m_val);
2711 return m_doc;
2712}
2713
2715 const yyjson_val *i_vals) {
2716 /*
2717 The immutable object or array stores all sub-values in a contiguous memory,
2718 We copy them to another contiguous memory as mutable values,
2719 then reconnect the mutable values with the original relationship.
2720 */
2721 usize i_vals_len;
2722 yyjson_mut_val *m_vals, *m_val;
2723 yyjson_val *i_val, *i_end;
2724
2725 if (!m_doc || !i_vals) return NULL;
2726 i_end = unsafe_yyjson_get_next(i_vals);
2727 i_vals_len = (usize)(unsafe_yyjson_get_next(i_vals) - i_vals);
2728 m_vals = unsafe_yyjson_mut_val(m_doc, i_vals_len);
2729 if (!m_vals) return NULL;
2730 i_val = constcast(yyjson_val *)i_vals;
2731 m_val = m_vals;
2732
2733 for (; i_val < i_end; i_val++, m_val++) {
2734 yyjson_type type = unsafe_yyjson_get_type(i_val);
2735 m_val->tag = i_val->tag;
2736 m_val->uni.u64 = i_val->uni.u64;
2737 if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
2738 const char *str = i_val->uni.str;
2739 usize str_len = unsafe_yyjson_get_len(i_val);
2740 m_val->uni.str = unsafe_yyjson_mut_strncpy(m_doc, str, str_len);
2741 if (!m_val->uni.str) return NULL;
2742 } else if (type == YYJSON_TYPE_ARR) {
2744 if (len > 0) {
2745 yyjson_val *ii_val = i_val + 1, *ii_next;
2746 yyjson_mut_val *mm_val = m_val + 1, *mm_ctn = m_val, *mm_next;
2747 while (len-- > 1) {
2748 ii_next = unsafe_yyjson_get_next(ii_val);
2749 mm_next = mm_val + (ii_next - ii_val);
2750 mm_val->next = mm_next;
2751 ii_val = ii_next;
2752 mm_val = mm_next;
2753 }
2754 mm_val->next = mm_ctn + 1;
2755 mm_ctn->uni.ptr = mm_val;
2756 }
2757 } else if (type == YYJSON_TYPE_OBJ) {
2759 if (len > 0) {
2760 yyjson_val *ii_key = i_val + 1, *ii_nextkey;
2761 yyjson_mut_val *mm_key = m_val + 1, *mm_ctn = m_val;
2762 yyjson_mut_val *mm_nextkey;
2763 while (len-- > 1) {
2764 ii_nextkey = unsafe_yyjson_get_next(ii_key + 1);
2765 mm_nextkey = mm_key + (ii_nextkey - ii_key);
2766 mm_key->next = mm_key + 1;
2767 mm_key->next->next = mm_nextkey;
2768 ii_key = ii_nextkey;
2769 mm_key = mm_nextkey;
2770 }
2771 mm_key->next = mm_key + 1;
2772 mm_key->next->next = mm_ctn + 1;
2773 mm_ctn->uni.ptr = mm_key;
2774 }
2775 }
2776 }
2777 return m_vals;
2778}
2779
2781 yyjson_mut_doc *m_doc, const yyjson_mut_val *m_vals) {
2782 /*
2783 The mutable object or array stores all sub-values in a circular linked
2784 list, so we can traverse them in the same loop. The traversal starts from
2785 the last item, continues with the first item in a list, and ends with the
2786 second to last item, which needs to be linked to the last item to close the
2787 circle.
2788 */
2789 yyjson_mut_val *m_val = unsafe_yyjson_mut_val(m_doc, 1);
2790 if (unlikely(!m_val)) return NULL;
2791 m_val->tag = m_vals->tag;
2792
2793 switch (unsafe_yyjson_get_type(m_vals)) {
2794 case YYJSON_TYPE_OBJ:
2795 case YYJSON_TYPE_ARR:
2796 if (unsafe_yyjson_get_len(m_vals) > 0) {
2797 yyjson_mut_val *last = (yyjson_mut_val *)m_vals->uni.ptr;
2798 yyjson_mut_val *next = last->next, *prev;
2799 prev = unsafe_yyjson_mut_val_mut_copy(m_doc, last);
2800 if (!prev) return NULL;
2801 m_val->uni.ptr = (void *)prev;
2802 while (next != last) {
2803 prev->next = unsafe_yyjson_mut_val_mut_copy(m_doc, next);
2804 if (!prev->next) return NULL;
2805 prev = prev->next;
2806 next = next->next;
2807 }
2808 prev->next = (yyjson_mut_val *)m_val->uni.ptr;
2809 }
2810 break;
2811 case YYJSON_TYPE_RAW:
2812 case YYJSON_TYPE_STR: {
2813 const char *str = m_vals->uni.str;
2814 usize str_len = unsafe_yyjson_get_len(m_vals);
2815 m_val->uni.str = unsafe_yyjson_mut_strncpy(m_doc, str, str_len);
2816 if (!m_val->uni.str) return NULL;
2817 break;
2818 }
2819 default:
2820 m_val->uni = m_vals->uni;
2821 break;
2822 }
2823 return m_val;
2824}
2825
2827 const yyjson_mut_val *val) {
2828 if (doc && val) return unsafe_yyjson_mut_val_mut_copy(doc, val);
2829 return NULL;
2830}
2831
2832/* Count the number of values and the total length of the strings. */
2833static void yyjson_mut_stat(const yyjson_mut_val *val,
2834 usize *val_sum, usize *str_sum) {
2836 *val_sum += 1;
2837 if (type == YYJSON_TYPE_ARR || type == YYJSON_TYPE_OBJ) {
2838 yyjson_mut_val *child = (yyjson_mut_val *)val->uni.ptr;
2840 len <<= (u8)(type == YYJSON_TYPE_OBJ);
2841 *val_sum += len;
2842 for (i = 0; i < len; i++) {
2843 yyjson_type stype = unsafe_yyjson_get_type(child);
2844 if (stype == YYJSON_TYPE_STR || stype == YYJSON_TYPE_RAW) {
2845 *str_sum += unsafe_yyjson_get_len(child) + 1;
2846 } else if (stype == YYJSON_TYPE_ARR || stype == YYJSON_TYPE_OBJ) {
2847 yyjson_mut_stat(child, val_sum, str_sum);
2848 *val_sum -= 1;
2849 }
2850 child = child->next;
2851 }
2852 } else if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
2853 *str_sum += unsafe_yyjson_get_len(val) + 1;
2854 }
2855}
2856
2857/* Copy mutable values to immutable value pool. */
2858static usize yyjson_imut_copy(yyjson_val **val_ptr, char **buf_ptr,
2859 const yyjson_mut_val *mval) {
2860 yyjson_val *val = *val_ptr;
2862 if (type == YYJSON_TYPE_ARR || type == YYJSON_TYPE_OBJ) {
2863 yyjson_mut_val *child = (yyjson_mut_val *)mval->uni.ptr;
2864 usize len = unsafe_yyjson_get_len(mval), i;
2865 usize val_sum = 1;
2866 if (type == YYJSON_TYPE_OBJ) {
2867 if (len) child = child->next->next;
2868 len <<= 1;
2869 } else {
2870 if (len) child = child->next;
2871 }
2872 *val_ptr = val + 1;
2873 for (i = 0; i < len; i++) {
2874 val_sum += yyjson_imut_copy(val_ptr, buf_ptr, child);
2875 child = child->next;
2876 }
2877 val->tag = mval->tag;
2878 val->uni.ofs = val_sum * sizeof(yyjson_val);
2879 return val_sum;
2880 } else if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
2881 char *buf = *buf_ptr;
2883 memcpy((void *)buf, (const void *)mval->uni.str, len);
2884 buf[len] = '\0';
2885 val->tag = mval->tag;
2886 val->uni.str = buf;
2887 *val_ptr = val + 1;
2888 *buf_ptr = buf + len + 1;
2889 return 1;
2890 } else {
2891 val->tag = mval->tag;
2892 val->uni = mval->uni;
2893 *val_ptr = val + 1;
2894 return 1;
2895 }
2896}
2897
2899 const yyjson_alc *alc) {
2900 if (!mdoc) return NULL;
2901 return yyjson_mut_val_imut_copy(mdoc->root, alc);
2902}
2903
2905 const yyjson_alc *alc) {
2906 usize val_num = 0, str_sum = 0, hdr_size, buf_size;
2907 yyjson_doc *doc = NULL;
2908 yyjson_val *val_hdr = NULL;
2909
2910 /* This value should be NULL here. Setting a non-null value suppresses
2911 warning from the clang analyzer. */
2912 char *str_hdr = (char *)(void *)&str_sum;
2913 if (!mval) return NULL;
2914 if (!alc) alc = &YYJSON_DEFAULT_ALC;
2915
2916 /* traverse the input value to get pool size */
2917 yyjson_mut_stat(mval, &val_num, &str_sum);
2918
2919 /* create doc and val pool */
2920 hdr_size = size_align_up(sizeof(yyjson_doc), sizeof(yyjson_val));
2921 buf_size = hdr_size + val_num * sizeof(yyjson_val);
2922 doc = (yyjson_doc *)alc->malloc(alc->ctx, buf_size);
2923 if (!doc) return NULL;
2924 memset(doc, 0, sizeof(yyjson_doc));
2925 val_hdr = (yyjson_val *)(void *)((char *)(void *)doc + hdr_size);
2926 doc->root = val_hdr;
2927 doc->alc = *alc;
2928
2929 /* create str pool */
2930 if (str_sum > 0) {
2931 str_hdr = (char *)alc->malloc(alc->ctx, str_sum);
2932 doc->str_pool = str_hdr;
2933 if (!str_hdr) {
2934 alc->free(alc->ctx, (void *)doc);
2935 return NULL;
2936 }
2937 }
2938
2939 /* copy vals and strs */
2940 doc->val_read = yyjson_imut_copy(&val_hdr, &str_hdr, mval);
2941 doc->dat_read = str_sum + 1;
2942 return doc;
2943}
2944
2945static_inline bool unsafe_yyjson_num_equals(const void *lhs, const void *rhs) {
2946 const yyjson_val_uni *luni = &((const yyjson_val *)lhs)->uni;
2947 const yyjson_val_uni *runi = &((const yyjson_val *)rhs)->uni;
2950 if (lt == rt) return luni->u64 == runi->u64;
2951 if (lt == YYJSON_SUBTYPE_SINT && rt == YYJSON_SUBTYPE_UINT) {
2952 return luni->i64 >= 0 && luni->u64 == runi->u64;
2953 }
2954 if (lt == YYJSON_SUBTYPE_UINT && rt == YYJSON_SUBTYPE_SINT) {
2955 return runi->i64 >= 0 && luni->u64 == runi->u64;
2956 }
2957 return false;
2958}
2959
2960static_inline bool unsafe_yyjson_str_equals(const void *lhs, const void *rhs) {
2962 if (len != unsafe_yyjson_get_len(rhs)) return false;
2963 return !memcmp(unsafe_yyjson_get_str(lhs),
2965}
2966
2967bool unsafe_yyjson_equals(const yyjson_val *lhs, const yyjson_val *rhs) {
2969 if (type != unsafe_yyjson_get_type(rhs)) return false;
2970
2971 switch (type) {
2972 case YYJSON_TYPE_OBJ: {
2974 if (len != unsafe_yyjson_get_len(rhs)) return false;
2975 if (len > 0) {
2976 yyjson_obj_iter iter;
2977 yyjson_obj_iter_init(rhs, &iter);
2978 lhs = unsafe_yyjson_get_first(lhs);
2979 while (len-- > 0) {
2980 rhs = yyjson_obj_iter_getn(&iter, lhs->uni.str,
2982 if (!rhs) return false;
2983 if (!unsafe_yyjson_equals(lhs + 1, rhs)) return false;
2984 lhs = unsafe_yyjson_get_next(lhs + 1);
2985 }
2986 }
2987 /* yyjson allows duplicate keys, so the check may be inaccurate */
2988 return true;
2989 }
2990
2991 case YYJSON_TYPE_ARR: {
2993 if (len != unsafe_yyjson_get_len(rhs)) return false;
2994 if (len > 0) {
2995 lhs = unsafe_yyjson_get_first(lhs);
2996 rhs = unsafe_yyjson_get_first(rhs);
2997 while (len-- > 0) {
2998 if (!unsafe_yyjson_equals(lhs, rhs)) return false;
2999 lhs = unsafe_yyjson_get_next(lhs);
3000 rhs = unsafe_yyjson_get_next(rhs);
3001 }
3002 }
3003 return true;
3004 }
3005
3006 case YYJSON_TYPE_NUM:
3007 return unsafe_yyjson_num_equals(lhs, rhs);
3008
3009 case YYJSON_TYPE_RAW:
3010 case YYJSON_TYPE_STR:
3011 return unsafe_yyjson_str_equals(lhs, rhs);
3012
3013 case YYJSON_TYPE_NULL:
3014 case YYJSON_TYPE_BOOL:
3015 return lhs->tag == rhs->tag;
3016
3017 default:
3018 return false;
3019 }
3020}
3021
3023 const yyjson_mut_val *rhs) {
3025 if (type != unsafe_yyjson_get_type(rhs)) return false;
3026
3027 switch (type) {
3028 case YYJSON_TYPE_OBJ: {
3030 if (len != unsafe_yyjson_get_len(rhs)) return false;
3031 if (len > 0) {
3034 lhs = (yyjson_mut_val *)lhs->uni.ptr;
3035 while (len-- > 0) {
3036 rhs = yyjson_mut_obj_iter_getn(&iter, lhs->uni.str,
3038 if (!rhs) return false;
3039 if (!unsafe_yyjson_mut_equals(lhs->next, rhs)) return false;
3040 lhs = lhs->next->next;
3041 }
3042 }
3043 /* yyjson allows duplicate keys, so the check may be inaccurate */
3044 return true;
3045 }
3046
3047 case YYJSON_TYPE_ARR: {
3049 if (len != unsafe_yyjson_get_len(rhs)) return false;
3050 if (len > 0) {
3051 lhs = (yyjson_mut_val *)lhs->uni.ptr;
3052 rhs = (yyjson_mut_val *)rhs->uni.ptr;
3053 while (len-- > 0) {
3054 if (!unsafe_yyjson_mut_equals(lhs, rhs)) return false;
3055 lhs = lhs->next;
3056 rhs = rhs->next;
3057 }
3058 }
3059 return true;
3060 }
3061
3062 case YYJSON_TYPE_NUM:
3063 return unsafe_yyjson_num_equals(lhs, rhs);
3064
3065 case YYJSON_TYPE_RAW:
3066 case YYJSON_TYPE_STR:
3067 return unsafe_yyjson_str_equals(lhs, rhs);
3068
3069 case YYJSON_TYPE_NULL:
3070 case YYJSON_TYPE_BOOL:
3071 return lhs->tag == rhs->tag;
3072
3073 default:
3074 return false;
3075 }
3076}
3077
3078bool yyjson_locate_pos(const char *str, size_t len, size_t pos,
3079 size_t *line, size_t *col, size_t *chr) {
3080 usize line_sum = 0, line_pos = 0, chr_sum = 0;
3081 const u8 *cur = (const u8 *)str;
3082 const u8 *end = cur + pos;
3083
3084 if (!str || pos > len) {
3085 if (line) *line = 0;
3086 if (col) *col = 0;
3087 if (chr) *chr = 0;
3088 return false;
3089 }
3090
3091 if (pos >= 3 && is_utf8_bom(cur)) cur += 3; /* don't count BOM */
3092 while (cur < end) {
3093 u8 c = *cur;
3094 chr_sum += 1;
3095 if (likely(c < 0x80)) { /* 0xxxxxxx (0x00-0x7F) ASCII */
3096 if (c == '\n') {
3097 line_sum += 1;
3098 line_pos = chr_sum;
3099 }
3100 cur += 1;
3101 }
3102 else if (c < 0xC0) cur += 1; /* 10xxxxxx (0x80-0xBF) Invalid */
3103 else if (c < 0xE0) cur += 2; /* 110xxxxx (0xC0-0xDF) 2-byte UTF-8 */
3104 else if (c < 0xF0) cur += 3; /* 1110xxxx (0xE0-0xEF) 3-byte UTF-8 */
3105 else if (c < 0xF8) cur += 4; /* 11110xxx (0xF0-0xF7) 4-byte UTF-8 */
3106 else cur += 1; /* 11111xxx (0xF8-0xFF) Invalid */
3107 }
3108 if (line) *line = line_sum + 1;
3109 if (col) *col = chr_sum - line_pos + 1;
3110 if (chr) *chr = chr_sum;
3111 return true;
3112}
3113
3114
3115
3116#if !YYJSON_DISABLE_READER /* reader begin */
3117
3118/* Check read flag, avoids `always false` warning when disabled. */
3119#define has_flg(_flg) unlikely(has_rflag(flg, YYJSON_READ_##_flg, 0))
3120#define has_allow(_flg) unlikely(has_rflag(flg, YYJSON_READ_ALLOW_##_flg, 1))
3121#define YYJSON_READ_ALLOW_TRIVIA (YYJSON_READ_ALLOW_COMMENTS | \
3122 YYJSON_READ_ALLOW_EXT_WHITESPACE)
3124 bool non_standard) {
3125#if YYJSON_DISABLE_NON_STANDARD
3126 if (non_standard) return false;
3127#endif
3128 return (flg & chk) != 0;
3129}
3130
3131
3132
3133/*==============================================================================
3134 * MARK: - JSON Reader Utils (Private)
3135 * These functions are used by JSON reader to read literals and comments.
3136 *============================================================================*/
3137
3138/** Read `true` literal, `*ptr[0]` should be `t`. */
3140 u8 *cur = *ptr;
3141 if (likely(byte_match_4(cur, "true"))) {
3143 *ptr = cur + 4;
3144 return true;
3145 }
3146 return false;
3147}
3148
3149/** Read `false` literal, `*ptr[0]` should be `f`. */
3151 u8 *cur = *ptr;
3152 if (likely(byte_match_4(cur + 1, "alse"))) {
3154 *ptr = cur + 5;
3155 return true;
3156 }
3157 return false;
3158}
3159
3160/** Read `null` literal, `*ptr[0]` should be `n`. */
3162 u8 *cur = *ptr;
3163 if (likely(byte_match_4(cur, "null"))) {
3164 val->tag = YYJSON_TYPE_NULL;
3165 *ptr = cur + 4;
3166 return true;
3167 }
3168 return false;
3169}
3170
3171/** Read `Inf` or `Infinity` literal (ignoring case). */
3173 yyjson_read_flag flg, yyjson_val *val) {
3174 u8 *hdr = *ptr;
3175 u8 *cur = *ptr;
3176 u8 **end = ptr;
3177 bool sign = (*cur == '-');
3178 if (*cur == '+' && !has_allow(EXT_NUMBER)) return false;
3179 cur += char_is_sign(*cur);
3180 if (char_to_lower(cur[0]) == 'i' &&
3181 char_to_lower(cur[1]) == 'n' &&
3182 char_to_lower(cur[2]) == 'f') {
3183 if (char_to_lower(cur[3]) == 'i') {
3184 if (char_to_lower(cur[4]) == 'n' &&
3185 char_to_lower(cur[5]) == 'i' &&
3186 char_to_lower(cur[6]) == 't' &&
3187 char_to_lower(cur[7]) == 'y') {
3188 cur += 8;
3189 } else {
3190 return false;
3191 }
3192 } else {
3193 cur += 3;
3194 }
3195 *end = cur;
3196 if (has_flg(NUMBER_AS_RAW)) {
3197 **pre = '\0'; /* add null-terminator for previous raw string */
3198 *pre = cur; /* save end position for current raw string */
3199 val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
3200 val->uni.str = (const char *)hdr;
3201 } else {
3203 val->uni.u64 = f64_bits_inf(sign);
3204 }
3205 return true;
3206 }
3207 return false;
3208}
3209
3210/** Read `NaN` literal (ignoring case). */
3212 yyjson_read_flag flg, yyjson_val *val) {
3213 u8 *hdr = *ptr;
3214 u8 *cur = *ptr;
3215 u8 **end = ptr;
3216 bool sign = (*cur == '-');
3217 if (*cur == '+' && !has_allow(EXT_NUMBER)) return false;
3218 cur += char_is_sign(*cur);
3219 if (char_to_lower(cur[0]) == 'n' &&
3220 char_to_lower(cur[1]) == 'a' &&
3221 char_to_lower(cur[2]) == 'n') {
3222 cur += 3;
3223 *end = cur;
3224 if (has_flg(NUMBER_AS_RAW)) {
3225 **pre = '\0'; /* add null-terminator for previous raw string */
3226 *pre = cur; /* save end position for current raw string */
3227 val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
3228 val->uni.str = (const char *)hdr;
3229 } else {
3231 val->uni.u64 = f64_bits_nan(sign);
3232 }
3233 return true;
3234 }
3235 return false;
3236}
3237
3238/** Read `Inf`, `Infinity` or `NaN` literal (ignoring case). */
3240 yyjson_read_flag flg, yyjson_val *val) {
3241 if (read_inf(ptr, pre, flg, val)) return true;
3242 if (read_nan(ptr, pre, flg, val)) return true;
3243 return false;
3244}
3245
3246/** Read a JSON number as raw string. */
3248 yyjson_val *val, const char **msg) {
3249#define return_err(_pos, _msg) do { \
3250 *msg = _msg; *end = _pos; return false; \
3251} while (false)
3252
3253#define return_raw() do { \
3254 val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
3255 val->uni.str = (const char *)hdr; \
3256 **pre = '\0'; *pre = cur; *end = cur; return true; \
3257} while (false)
3258
3259 u8 *hdr = *ptr;
3260 u8 *cur = *ptr;
3261 u8 **end = ptr;
3262
3263 /* skip sign */
3264 cur += (*cur == '-');
3265
3266 /* read first digit, check leading zero */
3267 while (unlikely(!char_is_digit(*cur))) {
3268 if (has_allow(EXT_NUMBER)) {
3269 if (*cur == '+' && cur == hdr) { /* leading `+` sign */
3270 cur++;
3271 continue;
3272 }
3273 if (*cur == '.' && char_is_digit(cur[1])) { /* e.g. '.123' */
3274 goto read_double;
3275 }
3276 }
3277 if (has_allow(INF_AND_NAN)) {
3278 if (read_inf_or_nan(ptr, pre, flg, val)) return true;
3279 }
3280 return_err(cur, "no digit after sign");
3281 }
3282
3283 /* read integral part */
3284 if (*cur == '0') {
3285 cur++;
3286 if (unlikely(char_is_digit(*cur))) {
3287 return_err(cur - 1, "number with leading zero is not allowed");
3288 }
3289 if (!char_is_fp(*cur)) {
3290 if (has_allow(EXT_NUMBER) && char_to_lower(*cur) == 'x') { /* hex */
3291 if (!char_is_hex(*++cur)) return_err(cur, "invalid hex number");
3292 while(char_is_hex(*cur)) cur++;
3293 }
3294 return_raw();
3295 }
3296 } else {
3297 while (char_is_digit(*cur)) cur++;
3298 if (!char_is_fp(*cur)) return_raw();
3299 }
3300
3301read_double:
3302 /* read fraction part */
3303 if (*cur == '.') {
3304 cur++;
3305 if (!char_is_digit(*cur)) {
3306 if (has_allow(EXT_NUMBER)) {
3307 if (!char_is_exp(*cur)) return_raw();
3308 } else {
3309 return_err(cur, "no digit after decimal point");
3310 }
3311 }
3312 while (char_is_digit(*cur)) cur++;
3313 }
3314
3315 /* read exponent part */
3316 if (char_is_exp(*cur)) {
3317 cur += 1 + char_is_sign(cur[1]);
3318 if (!char_is_digit(*cur++)) {
3319 return_err(cur, "no digit after exponent sign");
3320 }
3321 while (char_is_digit(*cur)) cur++;
3322 }
3323
3324 return_raw();
3325
3326#undef return_err
3327#undef return_raw
3328}
3329
3330/** Read a hex number. */
3332 yyjson_val *val, const char **msg) {
3333 u8 *hdr = *ptr;
3334 u8 *cur = *ptr;
3335 u8 **end = ptr;
3336 u64 sig = 0, i = 0;
3337 bool sign;
3338
3339 /* skip sign and '0x' */
3340 sign = (*cur == '-');
3341 cur += (*cur == '-' || *cur == '+') + 2;
3342
3343 /* read hex */
3344 for(; i < 16; i++) {
3345 u8 c = hex_conv_table[cur[i]];
3346 if (c == 0xF0) break;
3347 sig <<= 4;
3348 sig |= c;
3349 }
3350
3351 /* check error */
3352 if (unlikely(i == 0)) {
3353 *msg = "invalid hex number";
3354 return false;
3355 }
3356
3357 /* check overflow */
3358 if (unlikely(i == 16)) {
3359 if (char_is_hex(cur[16]) || (sign && sig > ((u64)1 << 63))) {
3360 if (!has_flg(BIGNUM_AS_RAW)) {
3361 *msg = "hex number overflow";
3362 return false;
3363 }
3364 cur += 16;
3365 while (char_is_hex(*cur)) cur++;
3366 **pre = '\0';
3367 val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
3368 val->uni.str = (const char *)hdr;
3369 *pre = cur; *end = cur;
3370 return true;
3371 }
3372 }
3373
3374 val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3);
3375 val->uni.u64 = (u64)(sign ? (u64)(~(sig) + 1) : (u64)(sig));
3376 *end = cur + i;
3377 return true;
3378}
3379
3380/**
3381 Skip trivia (whitespace and comments).
3382 This function should be used only when `char_is_trivia()` returns true.
3383 @param ptr (inout) Input current position, output end position.
3384 @param eof JSON end position.
3385 @param flg JSON read flags.
3386 @return true if at least one character was skipped.
3387 false if no characters were skipped,
3388 or if a multi-line comment is unterminated;
3389 in the latter case, `ptr` will be set to `eof`.
3390 */
3392 u8 *hdr = *ptr, *cur = *ptr;
3393 usize len;
3394
3395 while (cur < eof) {
3396 u8 *loop_begin = cur;
3397
3398 /* skip standard whitespace */
3399 while(char_is_space(*cur)) cur++;
3400
3401 /* skip extended whitespace */
3402 if (has_allow(EXT_WHITESPACE)) {
3403 while (char_is_space_ext(*cur)) {
3404 cur += (len = ext_space_len(cur));
3405 if (!len) break;
3406 }
3407 }
3408
3409 /* skip comment, do not validate encoding */
3410 if (has_allow(COMMENTS) && cur[0] == '/') {
3411 if (cur[1] == '/') { /* single-line comment */
3412 cur += 2;
3413 if (has_allow(EXT_WHITESPACE)) {
3414 while (cur < eof) {
3415 if (char_is_eol_ext(*cur)) {
3416 cur += (len = ext_eol_len(cur));
3417 if (len) break;
3418 }
3419 cur++;
3420 }
3421 } else {
3422 while (cur < eof && !char_is_eol(*cur)) cur++;
3423 }
3424 } else if (cur[1] == '*') { /* multi-line comment */
3425 cur += 2;
3426 while (!byte_match_2(cur, "*/") && cur < eof) cur++;
3427 if (cur == eof) {
3428 *ptr = eof;
3429 return false; /* unclosed comment */
3430 }
3431 cur += 2;
3432 }
3433 }
3434 if (cur == loop_begin) break;
3435 }
3436 *ptr = cur;
3437 return cur > hdr;
3438}
3439
3440/**
3441 Check truncated UTF-8 character.
3442 Return true if `cur` starts a valid UTF-8 sequence that is truncated.
3443 */
3444static bool is_truncated_utf8(u8 *cur, u8 *eof) {
3445 u8 c0, c1, c2;
3446 usize len = (usize)(eof - cur);
3447 if (cur >= eof || len >= 4) return false;
3448 c0 = cur[0]; c1 = cur[1]; c2 = cur[2];
3449 /* 1-byte UTF-8, not truncated */
3450 if (c0 < 0x80) return false;
3451 if (len == 1) {
3452 /* 2-byte UTF-8, truncated */
3453 if ((c0 & 0xE0) == 0xC0 && (c0 & 0x1E) != 0x00) return true;
3454 /* 3-byte UTF-8, truncated */
3455 if ((c0 & 0xF0) == 0xE0) return true;
3456 /* 4-byte UTF-8, truncated */
3457 if ((c0 & 0xF8) == 0xF0 && (c0 & 0x07) <= 0x04) return true;
3458 } else if (len == 2) {
3459 /* 3-byte UTF-8, truncated */
3460 if ((c0 & 0xF0) == 0xE0 && (c1 & 0xC0) == 0x80) {
3461 u8 t = (u8)(((c0 & 0x0F) << 1) | ((c1 & 0x20) >> 5));
3462 return 0x01 <= t && t != 0x1B;
3463 }
3464 /* 4-byte UTF-8, truncated */
3465 if ((c0 & 0xF8) == 0xF0 && (c1 & 0xC0) == 0x80) {
3466 u8 t = (u8)(((c0 & 0x07) << 2) | ((c1 & 0x30) >> 4));
3467 return 0x01 <= t && t <= 0x10;
3468 }
3469 } else if (len == 3) {
3470 /* 4 bytes UTF-8, truncated */
3471 if ((c0 & 0xF8) == 0xF0 && (c1 & 0xC0) == 0x80 && (c2 & 0xC0) == 0x80) {
3472 u8 t = (u8)(((c0 & 0x07) << 2) | ((c1 & 0x30) >> 4));
3473 return 0x01 <= t && t <= 0x10;
3474 }
3475 }
3476 return false;
3477}
3478
3479/**
3480 Check truncated string.
3481 Returns true if `cur` match `str` but is truncated.
3482 The `str` should be lowercase ASCII letters.
3483 */
3484static bool is_truncated_str(u8 *cur, u8 *eof, const char *str,
3485 bool case_sensitive) {
3486 usize len = strlen(str);
3487 if (cur + len <= eof || eof <= cur) return false;
3488 if (case_sensitive) {
3489 return memcmp(cur, str, (usize)(eof - cur)) == 0;
3490 }
3491 for (; cur < eof; cur++, str++) {
3492 if (char_to_lower(*cur) != *(const u8 *)str) return false;
3493 }
3494 return true;
3495}
3496
3497/**
3498 Check truncated JSON on parsing errors.
3499 Returns true if the input is valid but truncated.
3500 */
3502 yyjson_read_code code,
3503 yyjson_read_flag flg) {
3504 if (cur >= eof) return true;
3505 if (code == YYJSON_READ_ERROR_LITERAL) {
3506 if (is_truncated_str(cur, eof, "true", true) ||
3507 is_truncated_str(cur, eof, "false", true) ||
3508 is_truncated_str(cur, eof, "null", true)) {
3509 return true;
3510 }
3511 }
3514 code == YYJSON_READ_ERROR_LITERAL) {
3515 if (has_allow(INF_AND_NAN)) {
3516 if (*cur == '-') cur++;
3517 if (is_truncated_str(cur, eof, "infinity", false) ||
3518 is_truncated_str(cur, eof, "nan", false)) {
3519 return true;
3520 }
3521 }
3522 }
3524 if (has_allow(INF_AND_NAN)) {
3525 if (hdr + 3 <= cur &&
3526 is_truncated_str(cur - 3, eof, "infinity", false)) {
3527 return true; /* e.g. infin would be read as inf + in */
3528 }
3529 }
3530 }
3532 usize len = (usize)(eof - cur);
3533
3534 /* unicode escape sequence */
3535 if (*cur == '\\') {
3536 if (len == 1) return true;
3537 if (len <= 5) {
3538 if (*++cur != 'u') return false;
3539 for (++cur; cur < eof; cur++) {
3540 if (!char_is_hex(*cur)) return false;
3541 }
3542 return true;
3543 } else if (len <= 11) {
3544 /* incomplete surrogate pair? */
3545 u16 hi;
3546 if (*++cur != 'u') return false;
3547 if (!hex_load_4(++cur, &hi)) return false;
3548 if ((hi & 0xF800) != 0xD800) return false;
3549 cur += 4;
3550 if (cur >= eof) return true;
3551 /* valid low surrogate is DC00...DFFF */
3552 if (*cur != '\\') return false;
3553 if (++cur >= eof) return true;
3554 if (*cur != 'u') return false;
3555 if (++cur >= eof) return true;
3556 if (*cur != 'd' && *cur != 'D') return false;
3557 if (++cur >= eof) return true;
3558 if ((*cur < 'c' || *cur > 'f') && (*cur < 'C' || *cur > 'F'))
3559 return false;
3560 if (++cur >= eof) return true;
3561 if (!char_is_hex(*cur)) return false;
3562 return true;
3563 }
3564 return false;
3565 }
3566
3567 /* 2 to 4 bytes UTF-8 */
3568 if (is_truncated_utf8(cur, eof)) {
3569 return true;
3570 }
3571 }
3572 if (has_allow(COMMENTS)) {
3574 /* unclosed multiline comment */
3575 return true;
3576 }
3578 *cur == '/' && cur + 1 == eof) {
3579 /* truncated beginning of comment */
3580 return true;
3581 }
3582 }
3584 has_allow(BOM)) {
3585 /* truncated UTF-8 BOM */
3586 usize len = (usize)(eof - cur);
3587 if (cur == hdr && len < 3 && !memcmp(hdr, "\xEF\xBB\xBF", len)) {
3588 return true;
3589 }
3590 }
3591 return false;
3592}
3593
3594
3595
3596#if !YYJSON_DISABLE_FAST_FP_CONV /* FP_READER */
3597
3598/*==============================================================================
3599 * MARK: - BigInt For Floating Point Number Reader (Private)
3600 *
3601 * The bigint algorithm is used by floating-point number reader to get correctly
3602 * rounded result for numbers with lots of digits. This part of code is rarely
3603 * used for common numbers.
3604 *============================================================================*/
3605
3606/** Unsigned arbitrarily large integer */
3607typedef struct bigint {
3608 u32 used; /* used chunks count, should not be 0 */
3609 u64 bits[64]; /* chunks (58 is enough here) */
3610} bigint;
3611
3612/**
3613 Evaluate 'big += val'.
3614 @param big A big number (can be 0).
3615 @param val An unsigned integer (can be 0).
3616 */
3617static_inline void bigint_add_u64(bigint *big, u64 val) {
3618 u32 idx, max;
3619 u64 num = big->bits[0];
3620 u64 add = num + val;
3621 big->bits[0] = add;
3622 if (likely((add >= num) || (add >= val))) return;
3623 for ((void)(idx = 1), max = big->used; idx < max; idx++) {
3624 if (likely(big->bits[idx] != U64_MAX)) {
3625 big->bits[idx] += 1;
3626 return;
3627 }
3628 big->bits[idx] = 0;
3629 }
3630 big->bits[big->used++] = 1;
3631}
3632
3633/**
3634 Evaluate 'big *= val'.
3635 @param big A big number (can be 0).
3636 @param val An unsigned integer (cannot be 0).
3637 */
3638static_inline void bigint_mul_u64(bigint *big, u64 val) {
3639 u32 idx = 0, max = big->used;
3640 u64 hi, lo, carry = 0;
3641 for (; idx < max; idx++) {
3642 if (big->bits[idx]) break;
3643 }
3644 for (; idx < max; idx++) {
3645 u128_mul_add(big->bits[idx], val, carry, &hi, &lo);
3646 big->bits[idx] = lo;
3647 carry = hi;
3648 }
3649 if (carry) big->bits[big->used++] = carry;
3650}
3651
3652/**
3653 Evaluate 'big *= 2^exp'.
3654 @param big A big number (can be 0).
3655 @param exp An exponent integer (can be 0).
3656 */
3657static_inline void bigint_mul_pow2(bigint *big, u32 exp) {
3658 u32 shft = exp % 64;
3659 u32 move = exp / 64;
3660 u32 idx = big->used;
3661 if (unlikely(shft == 0)) {
3662 for (; idx > 0; idx--) {
3663 big->bits[idx + move - 1] = big->bits[idx - 1];
3664 }
3665 big->used += move;
3666 while (move) big->bits[--move] = 0;
3667 } else {
3668 big->bits[idx] = 0;
3669 for (; idx > 0; idx--) {
3670 u64 num = big->bits[idx] << shft;
3671 num |= big->bits[idx - 1] >> (64 - shft);
3672 big->bits[idx + move] = num;
3673 }
3674 big->bits[move] = big->bits[0] << shft;
3675 big->used += move + (big->bits[big->used + move] > 0);
3676 while (move) big->bits[--move] = 0;
3677 }
3678}
3679
3680/**
3681 Evaluate 'big *= 10^exp'.
3682 @param big A big number (can be 0).
3683 @param exp An exponent integer (cannot be 0).
3684 */
3685static_inline void bigint_mul_pow10(bigint *big, i32 exp) {
3686 for (; exp >= U64_POW10_MAX_EXACT_EXP; exp -= U64_POW10_MAX_EXACT_EXP) {
3687 bigint_mul_u64(big, u64_pow10_table[U64_POW10_MAX_EXACT_EXP]);
3688 }
3689 if (exp) {
3690 bigint_mul_u64(big, u64_pow10_table[exp]);
3691 }
3692}
3693
3694/**
3695 Compare two bigint.
3696 @return -1 if 'a < b', +1 if 'a > b', 0 if 'a == b'.
3697 */
3698static_inline i32 bigint_cmp(bigint *a, bigint *b) {
3699 u32 idx = a->used;
3700 if (a->used < b->used) return -1;
3701 if (a->used > b->used) return +1;
3702 while (idx-- > 0) {
3703 u64 av = a->bits[idx];
3704 u64 bv = b->bits[idx];
3705 if (av < bv) return -1;
3706 if (av > bv) return +1;
3707 }
3708 return 0;
3709}
3710
3711/**
3712 Evaluate 'big = val'.
3713 @param big A big number (can be 0).
3714 @param val An unsigned integer (can be 0).
3715 */
3716static_inline void bigint_set_u64(bigint *big, u64 val) {
3717 big->used = 1;
3718 big->bits[0] = val;
3719}
3720
3721/** Set a bigint with floating point number string. */
3722static_noinline void bigint_set_buf(bigint *big, u64 sig, i32 *exp,
3723 u8 *sig_cut, u8 *sig_end, u8 *dot_pos) {
3724
3725 if (unlikely(!sig_cut)) {
3726 /* no digit cut, set significant part only */
3727 bigint_set_u64(big, sig);
3728 return;
3729
3730 } else {
3731 /* some digits were cut, read them from 'sig_cut' to 'sig_end' */
3732 u8 *hdr = sig_cut;
3733 u8 *cur = hdr;
3734 u32 len = 0;
3735 u64 val = 0;
3736 bool dig_big_cut = false;
3737 bool has_dot = (hdr < dot_pos) & (dot_pos < sig_end);
3738 u32 dig_len_total = U64_SAFE_DIG + (u32)(sig_end - hdr) - has_dot;
3739
3740 sig -= (*sig_cut >= '5'); /* sig was rounded before */
3741 if (dig_len_total > F64_MAX_DEC_DIG) {
3742 dig_big_cut = true;
3743 sig_end -= dig_len_total - (F64_MAX_DEC_DIG + 1);
3744 sig_end -= (dot_pos + 1 == sig_end);
3745 dig_len_total = (F64_MAX_DEC_DIG + 1);
3746 }
3747 *exp -= (i32)dig_len_total - U64_SAFE_DIG;
3748
3749 big->used = 1;
3750 big->bits[0] = sig;
3751 while (cur < sig_end) {
3752 if (likely(cur != dot_pos)) {
3753 val = val * 10 + (u8)(*cur++ - '0');
3754 len++;
3755 if (unlikely(cur == sig_end && dig_big_cut)) {
3756 /* The last digit must be non-zero, */
3757 /* set it to '1' for correct rounding. */
3758 val = val - (val % 10) + 1;
3759 }
3760 if (len == U64_SAFE_DIG || cur == sig_end) {
3761 bigint_mul_pow10(big, (i32)len);
3762 bigint_add_u64(big, val);
3763 val = 0;
3764 len = 0;
3765 }
3766 } else {
3767 cur++;
3768 }
3769 }
3770 }
3771}
3772
3773
3774
3775/*==============================================================================
3776 * MARK: - Diy Floating Point (Private)
3777 *============================================================================*/
3778
3779/** "Do It Yourself Floating Point" struct. */
3780typedef struct diy_fp {
3781 u64 sig; /* significand */
3782 i32 exp; /* exponent, base 2 */
3783 i32 pad; /* padding, useless */
3784} diy_fp;
3785
3786/** Get cached rounded diy_fp for pow(10, e). The input value must be in the
3787 range [POW10_SIG_TABLE_MIN_EXP, POW10_SIG_TABLE_MAX_EXP]. */
3788static_inline diy_fp diy_fp_get_cached_pow10(i32 exp10) {
3789 diy_fp fp;
3790 u64 sig_ext;
3791 pow10_table_get_sig(exp10, &fp.sig, &sig_ext);
3792 pow10_table_get_exp(exp10, &fp.exp);
3793 fp.sig += (sig_ext >> 63);
3794 return fp;
3795}
3796
3797/** Returns fp * fp2. */
3798static_inline diy_fp diy_fp_mul(diy_fp fp, diy_fp fp2) {
3799 u64 hi, lo;
3800 u128_mul(fp.sig, fp2.sig, &hi, &lo);
3801 fp.sig = hi + (lo >> 63);
3802 fp.exp += fp2.exp + 64;
3803 return fp;
3804}
3805
3806/** Convert diy_fp to IEEE-754 raw value. */
3807static_inline u64 diy_fp_to_ieee_raw(diy_fp fp) {
3808 u64 sig = fp.sig;
3809 i32 exp = fp.exp;
3810 u32 lz_bits;
3811 if (unlikely(fp.sig == 0)) return 0;
3812
3813 lz_bits = u64_lz_bits(sig);
3814 sig <<= lz_bits;
3815 sig >>= F64_BITS - F64_SIG_FULL_BITS;
3816 exp -= (i32)lz_bits;
3817 exp += F64_BITS - F64_SIG_FULL_BITS;
3818 exp += F64_SIG_BITS;
3819
3820 if (unlikely(exp >= F64_MAX_BIN_EXP)) {
3821 /* overflow */
3822 return F64_BITS_INF;
3823 } else if (likely(exp >= F64_MIN_BIN_EXP - 1)) {
3824 /* normal */
3825 exp += F64_EXP_BIAS;
3826 return ((u64)exp << F64_SIG_BITS) | (sig & F64_SIG_MASK);
3827 } else if (likely(exp >= F64_MIN_BIN_EXP - F64_SIG_FULL_BITS)) {
3828 /* subnormal */
3829 return sig >> (F64_MIN_BIN_EXP - exp - 1);
3830 } else {
3831 /* underflow */
3832 return 0;
3833 }
3834}
3835
3836
3837
3838/*==============================================================================
3839 * MARK: - Number Reader (Private)
3840 *============================================================================*/
3841
3842/**
3843 Read a JSON number.
3844
3845 1. This function assume that the floating-point number is in IEEE-754 format.
3846 2. This function support uint64/int64/double number. If an integer number
3847 cannot fit in uint64/int64, it will returns as a double number. If a double
3848 number is infinite, the return value is based on flag.
3849 3. This function (with inline attribute) may generate a lot of instructions.
3850 */
3851static_inline bool read_num(u8 **ptr, u8 **pre, yyjson_read_flag flg,
3852 yyjson_val *val, const char **msg) {
3853#define return_err(_pos, _msg) do { \
3854 *msg = _msg; \
3855 *end = _pos; \
3856 return false; \
3857} while (false)
3858
3859#define return_0() do { \
3860 val->tag = YYJSON_TYPE_NUM | (u8)((u8)sign << 3); \
3861 val->uni.u64 = 0; \
3862 *end = cur; return true; \
3863} while (false)
3864
3865#define return_i64(_v) do { \
3866 val->tag = YYJSON_TYPE_NUM | (u8)((u8)sign << 3); \
3867 val->uni.u64 = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \
3868 *end = cur; return true; \
3869} while (false)
3870
3871#define return_f64(_v) do { \
3872 val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
3873 val->uni.f64 = sign ? -(f64)(_v) : (f64)(_v); \
3874 *end = cur; return true; \
3875} while (false)
3876
3877#define return_f64_bin(_v) do { \
3878 val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
3879 val->uni.u64 = ((u64)sign << 63) | (u64)(_v); \
3880 *end = cur; return true; \
3881} while (false)
3882
3883#define return_inf() do { \
3884 if (has_flg(BIGNUM_AS_RAW)) return_raw(); \
3885 if (has_allow(INF_AND_NAN)) return_f64_bin(F64_BITS_INF); \
3886 else return_err(hdr, "number is infinity when parsed as double"); \
3887} while (false)
3888
3889#define return_raw() do { \
3890 **pre = '\0'; /* add null-terminator for previous raw string */ \
3891 val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
3892 val->uni.str = (const char *)hdr; \
3893 *pre = cur; *end = cur; return true; \
3894} while (false)
3895
3896 u8 *sig_cut = NULL; /* significant part cutting position for long number */
3897 u8 *sig_end = NULL; /* significant part ending position */
3898 u8 *dot_pos = NULL; /* decimal point position */
3899
3900 u64 sig = 0; /* significant part of the number */
3901 i32 exp = 0; /* exponent part of the number */
3902
3903 bool exp_sign; /* temporary exponent sign from literal part */
3904 i64 exp_sig = 0; /* temporary exponent number from significant part */
3905 i64 exp_lit = 0; /* temporary exponent number from exponent literal part */
3906 u64 num; /* temporary number for reading */
3907 u8 *tmp; /* temporary cursor for reading */
3908
3909 u8 *hdr = *ptr;
3910 u8 *cur = *ptr;
3911 u8 **end = ptr;
3912 bool sign;
3913
3914 /* read number as raw string if has `YYJSON_READ_NUMBER_AS_RAW` flag */
3915 if (has_flg(NUMBER_AS_RAW)) {
3916 return read_num_raw(ptr, pre, flg, val, msg);
3917 }
3918
3919 sign = (*hdr == '-');
3920 cur += sign;
3921
3922 /* begin with a leading zero or non-digit */
3923 while (unlikely(!char_is_nonzero(*cur))) { /* 0 or non-digit char */
3924 if (unlikely(*cur != '0')) { /* non-digit char */
3925 if (has_allow(EXT_NUMBER)) {
3926 if (*cur == '+' && cur == hdr) { /* leading `+` sign */
3927 cur++;
3928 continue;
3929 }
3930 if (*cur == '.' && char_is_digit(cur[1])) { /* e.g. '.123' */
3931 goto leading_dot;
3932 }
3933 }
3934 if (has_allow(INF_AND_NAN)) {
3935 if (read_inf_or_nan(ptr, pre, flg, val)) return true;
3936 }
3937 return_err(cur, "no digit after sign");
3938 }
3939 /* begin with 0 */
3940 if (likely(!char_is_digit_or_fp(*++cur))) {
3941 if (has_allow(EXT_NUMBER) && char_to_lower(*cur) == 'x') { /* hex */
3942 return read_num_hex(ptr, pre, flg, val, msg);
3943 }
3944 return_0();
3945 }
3946 if (likely(*cur == '.')) {
3947leading_dot:
3948 dot_pos = cur++;
3949 if (unlikely(!char_is_digit(*cur))) {
3950 if (has_allow(EXT_NUMBER)) {
3951 if (char_is_exp(*cur)) {
3952 goto digi_exp_more;
3953 } else {
3954 return_f64_bin(0);
3955 }
3956 }
3957 return_err(cur, "no digit after decimal point");
3958 }
3959 while (unlikely(*cur == '0')) cur++;
3960 if (likely(char_is_digit(*cur))) {
3961 /* first non-zero digit after decimal point */
3962 sig = (u64)(*cur - '0'); /* read first digit */
3963 cur--;
3964 goto digi_frac_1; /* continue read fraction part */
3965 }
3966 }
3967 if (unlikely(char_is_digit(*cur))) {
3968 return_err(cur - 1, "number with leading zero is not allowed");
3969 }
3970 if (unlikely(char_is_exp(*cur))) { /* 0 with any exponent is still 0 */
3971 cur += (usize)1 + char_is_sign(cur[1]);
3972 if (unlikely(!char_is_digit(*cur))) {
3973 return_err(cur, "no digit after exponent sign");
3974 }
3975 while (char_is_digit(*++cur));
3976 }
3977 return_f64_bin(0);
3978 }
3979
3980 /* begin with non-zero digit */
3981 sig = (u64)(*cur - '0');
3982
3983 /*
3984 Read integral part, same as the following code.
3985
3986 for (int i = 1; i <= 18; i++) {
3987 num = cur[i] - '0';
3988 if (num <= 9) sig = num + sig * 10;
3989 else goto digi_sepr_i;
3990 }
3991 */
3992#define expr_intg(i) \
3993 if (likely((num = (u64)(cur[i] - (u8)'0')) <= 9)) sig = num + sig * 10; \
3994 else { goto digi_sepr_##i; }
3996#undef expr_intg
3997
3998
3999 cur += 19; /* skip continuous 19 digits */
4000 if (!char_is_digit_or_fp(*cur)) {
4001 /* this number is an integer consisting of 19 digits */
4002 if (sign && (sig > ((u64)1 << 63))) { /* overflow */
4003 if (has_flg(BIGNUM_AS_RAW)) return_raw();
4005 }
4006 return_i64(sig);
4007 }
4008 goto digi_intg_more; /* read more digits in integral part */
4009
4010
4011 /* process first non-digit character */
4012#define expr_sepr(i) \
4013 digi_sepr_##i: \
4014 if (likely(!char_is_fp(cur[i]))) { cur += i; return_i64(sig); } \
4015 dot_pos = cur + i; \
4016 if (likely(cur[i] == '.')) goto digi_frac_##i; \
4017 cur += i; sig_end = cur; goto digi_exp_more;
4018 repeat_in_1_18(expr_sepr)
4019#undef expr_sepr
4020
4021
4022 /* read fraction part */
4023#define expr_frac(i) \
4024 digi_frac_##i: \
4025 if (likely((num = (u64)(cur[i + 1] - (u8)'0')) <= 9)) \
4026 sig = num + sig * 10; \
4027 else { goto digi_stop_##i; }
4028 repeat_in_1_18(expr_frac)
4029#undef expr_frac
4030
4031 cur += 20; /* skip 19 digits and 1 decimal point */
4032 if (!char_is_digit(*cur)) goto digi_frac_end; /* fraction part end */
4033 goto digi_frac_more; /* read more digits in fraction part */
4034
4035
4036 /* significant part end */
4037#define expr_stop(i) \
4038 digi_stop_##i: \
4039 cur += i + 1; \
4040 goto digi_frac_end;
4042#undef expr_stop
4043
4044
4045 /* read more digits in integral part */
4046digi_intg_more:
4047 if (char_is_digit(*cur)) {
4048 if (!char_is_digit_or_fp(cur[1])) {
4049 /* this number is an integer consisting of 20 digits */
4050 num = (u64)(*cur - '0');
4051 if ((sig < (U64_MAX / 10)) ||
4052 (sig == (U64_MAX / 10) && num <= (U64_MAX % 10))) {
4053 sig = num + sig * 10;
4054 cur++;
4055 /* convert to double if overflow */
4056 if (sign) {
4057 if (has_flg(BIGNUM_AS_RAW)) return_raw();
4059 }
4060 return_i64(sig);
4061 }
4062 }
4063 }
4064
4065 if (char_is_exp(*cur)) {
4066 dot_pos = cur;
4067 goto digi_exp_more;
4068 }
4069
4070 if (*cur == '.') {
4071 dot_pos = cur++;
4072 if (unlikely(!char_is_digit(*cur))) {
4073 if (has_allow(EXT_NUMBER)) {
4074 goto digi_frac_end;
4075 }
4076 return_err(cur, "no digit after decimal point");
4077 }
4078 }
4079
4080
4081 /* read more digits in fraction part */
4082digi_frac_more:
4083 sig_cut = cur; /* too large to fit in u64, excess digits need to be cut */
4084 sig += (*cur >= '5'); /* round */
4085 while (char_is_digit(*++cur));
4086 if (!dot_pos) {
4087 if (!char_is_fp(*cur) && has_flg(BIGNUM_AS_RAW)) {
4088 return_raw(); /* it's a large integer */
4089 }
4090 dot_pos = cur;
4091 if (*cur == '.') {
4092 if (unlikely(!char_is_digit(*++cur))) {
4093 if (!has_allow(EXT_NUMBER)) {
4094 return_err(cur, "no digit after decimal point");
4095 }
4096 }
4097 while (char_is_digit(*cur)) cur++;
4098 }
4099 }
4100 exp_sig = (i64)(dot_pos - sig_cut);
4101 exp_sig += (dot_pos < sig_cut);
4102
4103 /* ignore trailing zeros */
4104 tmp = cur - 1;
4105 while ((*tmp == '0' || *tmp == '.') && tmp > hdr) tmp--;
4106 if (tmp < sig_cut) {
4107 sig_cut = NULL;
4108 } else {
4109 sig_end = cur;
4110 }
4111
4112 if (char_is_exp(*cur)) goto digi_exp_more;
4113 goto digi_exp_finish;
4114
4115
4116 /* fraction part end */
4117digi_frac_end:
4118 if (unlikely(dot_pos + 1 == cur)) {
4119 if (!has_allow(EXT_NUMBER)) {
4120 return_err(cur, "no digit after decimal point");
4121 }
4122 }
4123 sig_end = cur;
4124 exp_sig = -(i64)((u64)(cur - dot_pos) - 1);
4125 if (likely(!char_is_exp(*cur))) {
4126 if (unlikely(exp_sig < F64_MIN_DEC_EXP - 19)) {
4127 return_f64_bin(0); /* underflow */
4128 }
4129 exp = (i32)exp_sig;
4130 goto digi_finish;
4131 } else {
4132 goto digi_exp_more;
4133 }
4134
4135
4136 /* read exponent part */
4137digi_exp_more:
4138 exp_sign = (*++cur == '-');
4139 cur += char_is_sign(*cur);
4140 if (unlikely(!char_is_digit(*cur))) {
4141 return_err(cur, "no digit after exponent sign");
4142 }
4143 while (*cur == '0') cur++;
4144
4145 /* read exponent literal */
4146 tmp = cur;
4147 while (char_is_digit(*cur)) {
4148 exp_lit = (i64)((u8)(*cur++ - '0') + (u64)exp_lit * 10);
4149 }
4150 if (unlikely(cur - tmp >= U64_SAFE_DIG)) {
4151 if (exp_sign) {
4152 return_f64_bin(0); /* underflow */
4153 } else {
4154 return_inf(); /* overflow */
4155 }
4156 }
4157 exp_sig += exp_sign ? -exp_lit : exp_lit;
4158
4159
4160 /* validate exponent value */
4161digi_exp_finish:
4162 if (unlikely(exp_sig < F64_MIN_DEC_EXP - 19)) {
4163 return_f64_bin(0); /* underflow */
4164 }
4165 if (unlikely(exp_sig > F64_MAX_DEC_EXP)) {
4166 return_inf(); /* overflow */
4167 }
4168 exp = (i32)exp_sig;
4169
4170
4171 /* all digit read finished */
4172digi_finish:
4173
4174 /*
4175 Fast path 1:
4176
4177 1. The floating-point number calculation should be accurate, see the
4178 comments of macro `YYJSON_DOUBLE_MATH_CORRECT`.
4179 2. Correct rounding should be performed (fegetround() == FE_TONEAREST).
4180 3. The input to floating-point calculations does not lose precision,
4181 which means: 64 - leading_zero(input) - trailing_zero(input) < 53.
4182
4183 We don't check all available inputs here, because that would make the code
4184 more complicated, and not friendly to branch predictor.
4185 */
4186#if YYJSON_DOUBLE_MATH_CORRECT
4187 if (sig < ((u64)1 << 53) &&
4188 exp >= -F64_POW10_MAX_EXACT_EXP &&
4189 exp <= +F64_POW10_MAX_EXACT_EXP) {
4190 f64 dbl = (f64)sig;
4191 if (exp < 0) {
4192 dbl /= f64_pow10_table[-exp];
4193 } else {
4194 dbl *= f64_pow10_table[+exp];
4195 }
4196 return_f64(dbl);
4197 }
4198#endif
4199 if (unlikely(sig == 0)) return_f64_bin(0);
4200
4201 /*
4202 Fast path 2:
4203
4204 To keep it simple, we only accept normal number here,
4205 let the slow path handle subnormal and infinite numbers.
4206 */
4207 if (likely(!sig_cut &&
4208 exp > -F64_MAX_DEC_EXP + 1 &&
4209 exp < +F64_MAX_DEC_EXP - 20)) {
4210 /*
4211 The result value is exactly equal to (sig * 10^exp),
4212 the exponent part (10^exp) can be converted to (sig2 * 2^exp2).
4213
4214 The sig2 can be an infinite length number, only the highest 128 bits
4215 is cached in the pow10_sig_table.
4216
4217 Now we have these bits:
4218 sig1 (normalized 64bit) : aaaaaaaa
4219 sig2 (higher 64bit) : bbbbbbbb
4220 sig2_ext (lower 64bit) : cccccccc
4221 sig2_cut (extra unknown bits) : dddddddddddd....
4222
4223 And the calculation process is:
4224 ----------------------------------------
4225 aaaaaaaa *
4226 bbbbbbbbccccccccdddddddddddd....
4227 ----------------------------------------
4228 abababababababab +
4229 acacacacacacacac +
4230 adadadadadadadadadad....
4231 ----------------------------------------
4232 [hi____][lo____] +
4233 [hi2___][lo2___] +
4234 [unknown___________....]
4235 ----------------------------------------
4236
4237 The addition with carry may affect higher bits, but if there is a 0
4238 in higher bits, the bits higher than 0 will not be affected.
4239
4240 `lo2` + `unknown` may get a carry bit and may affect `hi2`, the max
4241 value of `hi2` is 0xFFFFFFFFFFFFFFFE, so `hi2` will not overflow.
4242
4243 `lo` + `hi2` may also get a carry bit and may affect `hi`, but only
4244 the highest significant 53 bits of `hi` is needed. If there is a 0
4245 in the lower bits of `hi`, then all the following bits can be dropped.
4246
4247 To convert the result to IEEE-754 double number, we need to perform
4248 correct rounding:
4249 1. if bit 54 is 0, round down,
4250 2. if bit 54 is 1 and any bit beyond bit 54 is 1, round up,
4251 3. if bit 54 is 1 and all bits beyond bit 54 are 0, round to even,
4252 as the extra bits is unknown, this case will not be handled here.
4253 */
4254
4255 u64 raw;
4256 u64 sig1, sig2, sig2_ext, hi, lo, hi2, lo2, add, bits;
4257 i32 exp2;
4258 u32 lz;
4259 bool exact = false, carry, round_up;
4260
4261 /* convert (10^exp) to (sig2 * 2^exp2) */
4262 pow10_table_get_sig(exp, &sig2, &sig2_ext);
4263 pow10_table_get_exp(exp, &exp2);
4264
4265 /* normalize and multiply */
4266 lz = u64_lz_bits(sig);
4267 sig1 = sig << lz;
4268 exp2 -= (i32)lz;
4269 u128_mul(sig1, sig2, &hi, &lo);
4270
4271 /*
4272 The `hi` is in range [0x4000000000000000, 0xFFFFFFFFFFFFFFFE],
4273 To get normalized value, `hi` should be shifted to the left by 0 or 1.
4274
4275 The highest significant 53 bits is used by IEEE-754 double number,
4276 and the bit 54 is used to detect rounding direction.
4277
4278 The lowest (64 - 54 - 1) bits is used to check whether it contains 0.
4279 */
4280 bits = hi & (((u64)1 << (64 - 54 - 1)) - 1);
4281 if (bits - 1 < (((u64)1 << (64 - 54 - 1)) - 2)) {
4282 /*
4283 (bits != 0 && bits != 0x1FF) => (bits - 1 < 0x1FF - 1)
4284 The `bits` is not zero, so we don't need to check `round to even`
4285 case. The `bits` contains bit `0`, so we can drop the extra bits
4286 after `0`.
4287 */
4288 exact = true;
4289
4290 } else {
4291 /*
4292 (bits == 0 || bits == 0x1FF)
4293 The `bits` is filled with all `0` or all `1`, so we need to check
4294 lower bits with another 64-bit multiplication.
4295 */
4296 u128_mul(sig1, sig2_ext, &hi2, &lo2);
4297
4298 add = lo + hi2;
4299 if (add + 1 > (u64)1) {
4300 /*
4301 (add != 0 && add != U64_MAX) => (add + 1 > 1)
4302 The `add` is not zero, so we don't need to check `round to
4303 even` case. The `add` contains bit `0`, so we can drop the
4304 extra bits after `0`. The `hi` cannot be U64_MAX, so it will
4305 not overflow.
4306 */
4307 carry = add < lo || add < hi2;
4308 hi += carry;
4309 exact = true;
4310 }
4311 }
4312
4313 if (exact) {
4314 /* normalize */
4315 lz = hi < ((u64)1 << 63);
4316 hi <<= lz;
4317 exp2 -= (i32)lz;
4318 exp2 += 64;
4319
4320 /* test the bit 54 and get rounding direction */
4321 round_up = (hi & ((u64)1 << (64 - 54))) > (u64)0;
4322 hi += (round_up ? ((u64)1 << (64 - 54)) : (u64)0);
4323
4324 /* test overflow */
4325 if (hi < ((u64)1 << (64 - 54))) {
4326 hi = ((u64)1 << 63);
4327 exp2 += 1;
4328 }
4329
4330 /* This is a normal number, convert it to IEEE-754 format. */
4331 hi >>= F64_BITS - F64_SIG_FULL_BITS;
4333 exp2 += F64_EXP_BIAS;
4334 raw = ((u64)exp2 << F64_SIG_BITS) | (hi & F64_SIG_MASK);
4335 return_f64_bin(raw);
4336 }
4337 }
4338
4339 /*
4340 Slow path: read double number exactly with diyfp.
4341 1. Use cached diyfp to get an approximation value.
4342 2. Use bigcomp to check the approximation value if needed.
4343
4344 This algorithm refers to google's double-conversion project:
4345 https://github.com/google/double-conversion
4346 */
4347 {
4348 const i32 ERR_ULP_LOG = 3;
4349 const i32 ERR_ULP = 1 << ERR_ULP_LOG;
4350 const i32 ERR_CACHED_POW = ERR_ULP / 2;
4351 const i32 ERR_MUL_FIXED = ERR_ULP / 2;
4352 const i32 DIY_SIG_BITS = 64;
4353 const i32 EXP_BIAS = F64_EXP_BIAS + F64_SIG_BITS;
4354 const i32 EXP_SUBNORMAL = -EXP_BIAS + 1;
4355
4356 u64 fp_err;
4357 u32 bits;
4358 i32 order_of_magnitude;
4359 i32 effective_significand_size;
4360 i32 precision_digits_count;
4361 u64 precision_bits;
4362 u64 half_way;
4363
4364 u64 raw;
4365 diy_fp fp, fp_upper;
4366 bigint big_full, big_comp;
4367 i32 cmp;
4368
4369 fp.sig = sig;
4370 fp.exp = 0;
4371 fp_err = sig_cut ? (u64)(ERR_ULP / 2) : (u64)0;
4372
4373 /* normalize */
4374 bits = u64_lz_bits(fp.sig);
4375 fp.sig <<= bits;
4376 fp.exp -= (i32)bits;
4377 fp_err <<= bits;
4378
4379 /* multiply and add error */
4380 fp = diy_fp_mul(fp, diy_fp_get_cached_pow10(exp));
4381 fp_err += (u64)ERR_CACHED_POW + (fp_err != 0) + (u64)ERR_MUL_FIXED;
4382
4383 /* normalize */
4384 bits = u64_lz_bits(fp.sig);
4385 fp.sig <<= bits;
4386 fp.exp -= (i32)bits;
4387 fp_err <<= bits;
4388
4389 /* effective significand */
4390 order_of_magnitude = DIY_SIG_BITS + fp.exp;
4391 if (likely(order_of_magnitude >= EXP_SUBNORMAL + F64_SIG_FULL_BITS)) {
4392 effective_significand_size = F64_SIG_FULL_BITS;
4393 } else if (order_of_magnitude <= EXP_SUBNORMAL) {
4394 effective_significand_size = 0;
4395 } else {
4396 effective_significand_size = order_of_magnitude - EXP_SUBNORMAL;
4397 }
4398
4399 /* precision digits count */
4400 precision_digits_count = DIY_SIG_BITS - effective_significand_size;
4401 if (unlikely(precision_digits_count + ERR_ULP_LOG >= DIY_SIG_BITS)) {
4402 i32 shr = (precision_digits_count + ERR_ULP_LOG) - DIY_SIG_BITS + 1;
4403 fp.sig >>= shr;
4404 fp.exp += shr;
4405 fp_err = (fp_err >> shr) + 1 + (u32)ERR_ULP;
4406 precision_digits_count -= shr;
4407 }
4408
4409 /* half way */
4410 precision_bits = fp.sig & (((u64)1 << precision_digits_count) - 1);
4411 precision_bits *= (u32)ERR_ULP;
4412 half_way = (u64)1 << (precision_digits_count - 1);
4413 half_way *= (u32)ERR_ULP;
4414
4415 /* rounding */
4416 fp.sig >>= precision_digits_count;
4417 fp.sig += (precision_bits >= half_way + fp_err);
4418 fp.exp += precision_digits_count;
4419
4420 /* get IEEE double raw value */
4421 raw = diy_fp_to_ieee_raw(fp);
4422 if (unlikely(raw == F64_BITS_INF)) return_inf();
4423 if (likely(precision_bits <= half_way - fp_err ||
4424 precision_bits >= half_way + fp_err)) {
4425 return_f64_bin(raw); /* number is accurate */
4426 }
4427 /* now the number is the correct value, or the next lower value */
4428
4429 /* upper boundary */
4430 if (raw & F64_EXP_MASK) {
4431 fp_upper.sig = (raw & F64_SIG_MASK) + ((u64)1 << F64_SIG_BITS);
4432 fp_upper.exp = (i32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
4433 } else {
4434 fp_upper.sig = (raw & F64_SIG_MASK);
4435 fp_upper.exp = 1;
4436 }
4437 fp_upper.exp -= F64_EXP_BIAS + F64_SIG_BITS;
4438 fp_upper.sig <<= 1;
4439 fp_upper.exp -= 1;
4440 fp_upper.sig += 1; /* add half ulp */
4441
4442 /* compare with bigint */
4443 bigint_set_buf(&big_full, sig, &exp, sig_cut, sig_end, dot_pos);
4444 bigint_set_u64(&big_comp, fp_upper.sig);
4445 if (exp >= 0) {
4446 bigint_mul_pow10(&big_full, +exp);
4447 } else {
4448 bigint_mul_pow10(&big_comp, -exp);
4449 }
4450 if (fp_upper.exp > 0) {
4451 bigint_mul_pow2(&big_comp, (u32)+fp_upper.exp);
4452 } else {
4453 bigint_mul_pow2(&big_full, (u32)-fp_upper.exp);
4454 }
4455 cmp = bigint_cmp(&big_full, &big_comp);
4456 if (likely(cmp != 0)) {
4457 /* round down or round up */
4458 raw += (cmp > 0);
4459 } else {
4460 /* falls midway, round to even */
4461 raw += (raw & 1);
4462 }
4463
4464 if (unlikely(raw == F64_BITS_INF)) return_inf();
4465 return_f64_bin(raw);
4466 }
4467
4468#undef return_err
4469#undef return_inf
4470#undef return_0
4471#undef return_i64
4472#undef return_f64
4473#undef return_f64_bin
4474#undef return_raw
4475}
4476
4477
4478
4479#else /* FP_READER */
4480
4481/**
4482 Read a JSON number.
4483 This is a fallback function if the custom number reader is disabled.
4484 This function use libc's strtod() to read floating-point number.
4485 */
4487 yyjson_val *val, const char **msg) {
4488#define return_err(_pos, _msg) do { \
4489 *msg = _msg; \
4490 *end = _pos; \
4491 return false; \
4492} while (false)
4493
4494#define return_0() do { \
4495 val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); \
4496 val->uni.u64 = 0; \
4497 *end = cur; return true; \
4498} while (false)
4499
4500#define return_i64(_v) do { \
4501 val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); \
4502 val->uni.u64 = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \
4503 *end = cur; return true; \
4504} while (false)
4505
4506#define return_f64(_v) do { \
4507 val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
4508 val->uni.f64 = sign ? -(f64)(_v) : (f64)(_v); \
4509 *end = cur; return true; \
4510} while (false)
4511
4512#define return_f64_bin(_v) do { \
4513 val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
4514 val->uni.u64 = ((u64)sign << 63) | (u64)(_v); \
4515 *end = cur; return true; \
4516} while (false)
4517
4518#define return_inf() do { \
4519 if (has_flg(BIGNUM_AS_RAW)) return_raw(); \
4520 if (has_allow(INF_AND_NAN)) return_f64_bin(F64_BITS_INF); \
4521 else return_err(hdr, "number is infinity when parsed as double"); \
4522} while (false)
4523
4524#define return_raw() do { \
4525 val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
4526 val->uni.str = (const char *)hdr; \
4527 **pre = '\0'; *pre = cur; *end = cur; return true; \
4528} while (false)
4529
4530 u64 sig, num;
4531 u8 *hdr = *ptr;
4532 u8 *cur = *ptr;
4533 u8 **end = ptr;
4534 u8 *dot = NULL;
4535 u8 *f64_end = NULL;
4536 bool sign;
4537
4538 /* read number as raw string if has `YYJSON_READ_NUMBER_AS_RAW` flag */
4539 if (has_flg(NUMBER_AS_RAW)) {
4540 return read_num_raw(ptr, pre, flg, val, msg);
4541 }
4542
4543 sign = (*hdr == '-');
4544 cur += sign;
4545 sig = (u8)(*cur - '0');
4546
4547 /* read first digit, check leading zero */
4548 while (unlikely(!char_is_digit(*cur))) {
4549 if (has_allow(EXT_NUMBER)) {
4550 if (*cur == '+' && cur == hdr) { /* leading `+` sign */
4551 cur++;
4552 sig = (u8)(*cur - '0');
4553 continue;
4554 }
4555 if (*cur == '.' && char_is_num(cur[1])) { /* no integer part */
4556 goto read_double; /* e.g. '.123' */
4557 }
4558 }
4559 if (has_allow(INF_AND_NAN)) {
4560 if (read_inf_or_nan(ptr, pre, flg, val)) return true;
4561 }
4562 return_err(cur, "no digit after sign");
4563 }
4564 if (*cur == '0') {
4565 cur++;
4566 if (unlikely(char_is_digit(*cur))) {
4567 return_err(cur - 1, "number with leading zero is not allowed");
4568 }
4569 if (!char_is_fp(*cur)) {
4570 if (has_allow(EXT_NUMBER) &&
4571 (*cur == 'x' || *cur == 'X')) { /* hex integer */
4572 return read_num_hex(ptr, pre, flg, val, msg);
4573 }
4574 return_0();
4575 }
4576 goto read_double;
4577 }
4578
4579 /* read continuous digits, up to 19 characters */
4580#define expr_intg(i) \
4581 if (likely((num = (u64)(cur[i] - (u8)'0')) <= 9)) sig = num + sig * 10; \
4582 else { cur += i; goto intg_end; }
4584#undef expr_intg
4585
4586 /* here are 19 continuous digits, skip them */
4587 cur += 19;
4588 if (char_is_digit(cur[0]) && !char_is_digit_or_fp(cur[1])) {
4589 /* this number is an integer consisting of 20 digits */
4590 num = (u8)(*cur - '0');
4591 if ((sig < (U64_MAX / 10)) ||
4592 (sig == (U64_MAX / 10) && num <= (U64_MAX % 10))) {
4593 sig = num + sig * 10;
4594 cur++;
4595 if (sign) {
4596 if (has_flg(BIGNUM_AS_RAW)) return_raw();
4598 }
4599 return_i64(sig);
4600 }
4601 }
4602
4603intg_end:
4604 /* continuous digits ended */
4605 if (!char_is_digit_or_fp(*cur)) {
4606 /* this number is an integer consisting of 1 to 19 digits */
4607 if (sign && (sig > ((u64)1 << 63))) {
4608 if (has_flg(BIGNUM_AS_RAW)) return_raw();
4610 }
4611 return_i64(sig);
4612 }
4613
4614read_double:
4615 /* this number should be read as double */
4616 while (char_is_digit(*cur)) cur++;
4617 if (!char_is_fp(*cur) && has_flg(BIGNUM_AS_RAW)) {
4618 return_raw(); /* it's a large integer */
4619 }
4620 while (*cur == '.') {
4621 /* skip fraction part */
4622 dot = cur;
4623 cur++;
4624 if (!char_is_digit(*cur)) {
4625 if (has_allow(EXT_NUMBER)) {
4626 break;
4627 } else {
4628 return_err(cur, "no digit after decimal point");
4629 }
4630 }
4631 cur++;
4632 while (char_is_digit(*cur)) cur++;
4633 break;
4634 }
4635 if (char_is_exp(*cur)) {
4636 /* skip exponent part */
4637 cur += 1 + char_is_sign(cur[1]);
4638 if (!char_is_digit(*cur)) {
4639 return_err(cur, "no digit after exponent sign");
4640 }
4641 cur++;
4642 while (char_is_digit(*cur)) cur++;
4643 }
4644
4645 /*
4646 libc's strtod() is used to parse the floating-point number.
4647
4648 Note that the decimal point character used by strtod() is locale-dependent,
4649 and the rounding direction may affected by fesetround().
4650
4651 For currently known locales, (en, zh, ja, ko, am, he, hi) use '.' as the
4652 decimal point, while other locales use ',' as the decimal point.
4653
4654 Here strtod() is called twice for different locales, but if another thread
4655 happens calls setlocale() between two strtod(), parsing may still fail.
4656 */
4657 val->uni.f64 = strtod((const char *)hdr, (char **)&f64_end);
4658 if (unlikely(f64_end != cur)) {
4659 /* replace '.' with ',' for locale */
4660 bool cut = (*cur == ',');
4661 if (cut) *cur = ' ';
4662 if (dot) *dot = ',';
4663 val->uni.f64 = strtod((const char *)hdr, (char **)&f64_end);
4664 /* restore ',' to '.' */
4665 if (cut) *cur = ',';
4666 if (dot) *dot = '.';
4667 if (unlikely(f64_end != cur)) {
4668 return_err(hdr, "strtod() failed to parse the number");
4669 }
4670 }
4671 if (unlikely(f64_is_inf(val->uni.f64))) {
4672 return_inf();
4673 }
4675 *end = cur;
4676 return true;
4677
4678#undef return_err
4679#undef return_0
4680#undef return_i64
4681#undef return_f64
4682#undef return_f64_bin
4683#undef return_inf
4684#undef return_raw
4685}
4686
4687#endif /* FP_READER */
4688
4689
4690
4691/*==============================================================================
4692 * MARK: - String Reader (Private)
4693 *============================================================================*/
4694
4695/** Read unicode escape sequence. */
4696static_inline bool read_uni_esc(u8 **src_ptr, u8 **dst_ptr, const char **msg) {
4697#define return_err(_end, _msg) *msg = _msg; *src_ptr = _end; return false
4698
4699 u8 *src = *src_ptr;
4700 u8 *dst = *dst_ptr;
4701 u16 hi, lo;
4702 u32 uni;
4703
4704 src += 2; /* skip `\u` */
4705 if (unlikely(!hex_load_4(src, &hi))) {
4706 return_err(src - 2, "invalid escaped sequence in string");
4707 }
4708 src += 4; /* skip hex */
4709 if (likely((hi & 0xF800) != 0xD800)) {
4710 /* a BMP character */
4711 if (hi >= 0x800) {
4712 *dst++ = (u8)(0xE0 | (hi >> 12));
4713 *dst++ = (u8)(0x80 | ((hi >> 6) & 0x3F));
4714 *dst++ = (u8)(0x80 | (hi & 0x3F));
4715 } else if (hi >= 0x80) {
4716 *dst++ = (u8)(0xC0 | (hi >> 6));
4717 *dst++ = (u8)(0x80 | (hi & 0x3F));
4718 } else {
4719 *dst++ = (u8)hi;
4720 }
4721 } else {
4722 /* a non-BMP character, represented as a surrogate pair */
4723 if (unlikely((hi & 0xFC00) != 0xD800)) {
4724 return_err(src - 6, "invalid high surrogate in string");
4725 }
4726 if (unlikely(!byte_match_2(src, "\\u"))) {
4727 return_err(src - 6, "no low surrogate in string");
4728 }
4729 if (unlikely(!hex_load_4(src + 2, &lo))) {
4730 return_err(src - 6, "invalid escape in string");
4731 }
4732 if (unlikely((lo & 0xFC00) != 0xDC00)) {
4733 return_err(src - 6, "invalid low surrogate in string");
4734 }
4735 uni = ((((u32)hi - 0xD800) << 10) |
4736 ((u32)lo - 0xDC00)) + 0x10000;
4737 *dst++ = (u8)(0xF0 | (uni >> 18));
4738 *dst++ = (u8)(0x80 | ((uni >> 12) & 0x3F));
4739 *dst++ = (u8)(0x80 | ((uni >> 6) & 0x3F));
4740 *dst++ = (u8)(0x80 | (uni & 0x3F));
4741 src += 6;
4742 }
4743 *src_ptr = src;
4744 *dst_ptr = dst;
4745 return true;
4746#undef return_err
4747}
4748
4749/**
4750 Read a JSON string.
4751 @param quo The quote character (single quote or double quote).
4752 @param ptr The head pointer of string before quote (inout).
4753 @param eof JSON end position.
4754 @param flg JSON read flag.
4755 @param val The string value to be written.
4756 @param msg The error message pointer.
4757 @param con Continuation for incremental parsing.
4758 @return Whether success.
4759 */
4761 yyjson_val *val, const char **msg, u8 *con[2]) {
4762 /*
4763 GCC may sometimes load variables into registers too early, causing
4764 unnecessary instructions and performance degradation. This inline assembly
4765 serves as a hint to GCC: 'This variable will be modified, so avoid loading
4766 it too early.' Other compilers like MSVC, Clang, and ICC can generate the
4767 expected instructions without needing this hint.
4768
4769 Check out this example: https://godbolt.org/z/YG6a5W5Ec
4770 */
4771#define return_err(_end, _msg) do { \
4772 *msg = _msg; \
4773 *end = _end; \
4774 if (con) { con[0] = _end; con[1] = dst; } \
4775 return false; \
4776} while (false)
4777
4778 u8 *hdr = *ptr + 1;
4779 u8 **end = ptr;
4780 u8 *src = hdr, *dst = NULL, *pos;
4781 u32 uni, tmp;
4782
4783 /* Resume incremental parsing. */
4784 if (con && unlikely(con[0])) {
4785 src = con[0];
4786 dst = con[1];
4787 if (dst) goto copy_ascii;
4788 }
4789
4790skip_ascii:
4791 /*
4792 Most strings have no escaped characters, so we can jump them quickly.
4793
4794 We want to make loop unrolling, as shown in the following code. Some
4795 compiler may not generate instructions as expected, so we rewrite it with
4796 explicit goto statements. We hope the compiler can generate instructions
4797 like this: https://godbolt.org/z/8vjsYq
4798
4799 while (true) repeat16({
4800 if (likely((char_is_ascii_skip(*src)))) src++;
4801 else break;
4802 })
4803 */
4804 if (quo == '"') {
4805#define expr_jump(i) \
4806 if (likely(char_is_ascii_skip(src[i]))) {} \
4807 else goto skip_ascii_stop##i;
4808
4809#define expr_stop(i) \
4810 skip_ascii_stop##i: \
4811 src += i; \
4812 goto skip_ascii_end;
4813
4815 src += 16;
4816 goto skip_ascii;
4818
4819#undef expr_jump
4820#undef expr_stop
4821 } else {
4822#define expr_jump(i) \
4823 if (likely(char_is_ascii_skip_sq(src[i]))) {} \
4824 else goto skip_ascii_stop_sq##i;
4825
4826#define expr_stop(i) \
4827 skip_ascii_stop_sq##i: \
4828 src += i; \
4829 goto skip_ascii_end;
4830
4832 src += 16;
4833 goto skip_ascii;
4835
4836#undef expr_jump
4837#undef expr_stop
4838 }
4839
4840skip_ascii_end:
4841 gcc_store_barrier(*src);
4842 if (likely(*src == quo)) {
4843 val->tag = ((u64)(src - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR |
4844 (quo == '"' ? YYJSON_SUBTYPE_NOESC : 0);
4845 val->uni.str = (const char *)hdr;
4846 *src = '\0';
4847 *end = src + 1;
4848 if (con) con[0] = con[1] = NULL;
4849 return true;
4850 }
4851
4852skip_utf8:
4853 if (*src & 0x80) { /* non-ASCII character */
4854 /*
4855 Non-ASCII character appears here, which means that the text is likely
4856 to be written in non-English or emoticons. According to some common
4857 data set statistics, byte sequences of the same length may appear
4858 consecutively. We process the byte sequences of the same length in each
4859 loop, which is more friendly to branch prediction.
4860 */
4861 pos = src;
4862#if YYJSON_DISABLE_UTF8_VALIDATION
4863 while (true) repeat8({
4864 if (likely((*src & 0xF0) == 0xE0)) src += 3;
4865 else break;
4866 })
4867 if (*src < 0x80) goto skip_ascii;
4868 while (true) repeat8({
4869 if (likely((*src & 0xE0) == 0xC0)) src += 2;
4870 else break;
4871 })
4872 while (true) repeat8({
4873 if (likely((*src & 0xF8) == 0xF0)) src += 4;
4874 else break;
4875 })
4876#else
4877 uni = byte_load_4(src);
4878 while (is_utf8_seq3(uni)) {
4879 src += 3;
4880 uni = byte_load_4(src);
4881 }
4882 if (is_utf8_seq1(uni)) goto skip_ascii;
4883 while (is_utf8_seq2(uni)) {
4884 src += 2;
4885 uni = byte_load_4(src);
4886 }
4887 while (is_utf8_seq4(uni)) {
4888 src += 4;
4889 uni = byte_load_4(src);
4890 }
4891#endif
4892 if (unlikely(pos == src)) {
4893 if (has_allow(INVALID_UNICODE)) ++src;
4894 else return_err(src, "invalid UTF-8 encoding in string");
4895 }
4896 goto skip_ascii;
4897 }
4898
4899 /* The escape character appears, we need to copy it. */
4900 dst = src;
4901copy_escape:
4902 if (likely(*src == '\\')) {
4903 switch (*++src) {
4904 case '"': *dst++ = '"'; src++; break;
4905 case '\\': *dst++ = '\\'; src++; break;
4906 case '/': *dst++ = '/'; src++; break;
4907 case 'b': *dst++ = '\b'; src++; break;
4908 case 'f': *dst++ = '\f'; src++; break;
4909 case 'n': *dst++ = '\n'; src++; break;
4910 case 'r': *dst++ = '\r'; src++; break;
4911 case 't': *dst++ = '\t'; src++; break;
4912 case 'u':
4913 src--;
4914 if (!read_uni_esc(&src, &dst, msg)) return_err(src, *msg);
4915 break;
4916 default: {
4917 if (has_allow(EXT_ESCAPE)) {
4918 /* read extended escape (non-standard) */
4919 switch (*src) {
4920 case '\'': *dst++ = '\''; src++; break;
4921 case 'a': *dst++ = '\a'; src++; break;
4922 case 'v': *dst++ = '\v'; src++; break;
4923 case '?': *dst++ = '\?'; src++; break;
4924 case 'e': *dst++ = 0x1B; src++; break;
4925 case '0':
4926 if (!char_is_digit(src[1])) {
4927 *dst++ = '\0'; src++; break;
4928 }
4929 return_err(src - 1, "octal escape is not allowed");
4930 case '1': case '2': case '3': case '4':
4931 case '5': case '6': case '7': case '8': case '9':
4932 return_err(src - 1, "invalid number escape");
4933 case 'x': {
4934 u8 c;
4935 if (hex_load_2(src + 1, &c)) {
4936 src += 3;
4937 if (c <= 0x7F) { /* 1-byte ASCII */
4938 *dst++ = c;
4939 } else { /* 2-byte UTF-8 */
4940 *dst++ = (u8)(0xC0 | (c >> 6));
4941 *dst++ = (u8)(0x80 | (c & 0x3F));
4942 }
4943 break;
4944 }
4945 return_err(src - 1, "invalid hex escape");
4946 }
4947 case '\n': src++; break;
4948 case '\r': src++; src += (*src == '\n'); break;
4949 case 0xE2: /* Line terminator: U+2028, U+2029 */
4950 if ((src[1] == 0x80 && src[2] == 0xA8) ||
4951 (src[1] == 0x80 && src[2] == 0xA9)) {
4952 src += 3;
4953 }
4954 break;
4955 default:
4956 break; /* skip */
4957 }
4958 } else if (quo == '\'' && *src == '\'') {
4959 *dst++ = '\''; src++; break;
4960 } else {
4961 return_err(src - 1, "invalid escaped sequence in string");
4962 }
4963 }
4964 }
4965 } else if (likely(*src == quo)) {
4966 val->tag = ((u64)(dst - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR;
4967 val->uni.str = (const char *)hdr;
4968 *dst = '\0';
4969 *end = src + 1;
4970 if (con) con[0] = con[1] = NULL;
4971 return true;
4972 } else {
4973 if (!has_allow(INVALID_UNICODE)) {
4974 return_err(src, "unexpected control character in string");
4975 }
4976 if (src >= eof) return_err(src, "unclosed string");
4977 *dst++ = *src++;
4978 }
4979
4980copy_ascii:
4981 /*
4982 Copy continuous ASCII, loop unrolling, same as the following code:
4983
4984 while (true) repeat16({
4985 if (char_is_ascii_skip(*src)) *dst++ = *src++;
4986 else break;
4987 })
4988 */
4989 if (quo == '"') {
4990#define expr_jump(i) \
4991 if (likely((char_is_ascii_skip(src[i])))) {} \
4992 else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; }
4994#undef expr_jump
4995 } else {
4996#define expr_jump(i) \
4997 if (likely((char_is_ascii_skip_sq(src[i])))) {} \
4998 else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; }
5000#undef expr_jump
5001 }
5002
5003 byte_move_16(dst, src);
5004 dst += 16; src += 16;
5005 goto copy_ascii;
5006
5007 /*
5008 The memory is copied forward since `dst < src`.
5009 So it's safe to move one extra byte to reduce instruction count.
5010 */
5011#define expr_jump(i) \
5012 copy_ascii_stop_##i: \
5013 byte_move_forward(dst, src, i); \
5014 dst += i; src += i; \
5015 goto copy_utf8;
5017#undef expr_jump
5018
5019copy_utf8:
5020 if (*src & 0x80) { /* non-ASCII character */
5021 pos = src;
5022 uni = byte_load_4(src);
5023#if YYJSON_DISABLE_UTF8_VALIDATION
5024 while (true) repeat4({
5025 if ((uni & utf8_seq(b3_mask)) == utf8_seq(b3_patt)) {
5026 byte_copy_4(dst, &uni);
5027 dst += 3; src += 3;
5028 uni = byte_load_4(src);
5029 } else break;
5030 })
5031 if ((uni & utf8_seq(b1_mask)) == utf8_seq(b1_patt)) goto copy_ascii;
5032 while (true) repeat4({
5033 if ((uni & utf8_seq(b2_mask)) == utf8_seq(b2_patt)) {
5034 byte_copy_2(dst, &uni);
5035 dst += 2; src += 2;
5036 uni = byte_load_4(src);
5037 } else break;
5038 })
5039 while (true) repeat4({
5040 if ((uni & utf8_seq(b4_mask)) == utf8_seq(b4_patt)) {
5041 byte_copy_4(dst, &uni);
5042 dst += 4; src += 4;
5043 uni = byte_load_4(src);
5044 } else break;
5045 })
5046#else
5047 while (is_utf8_seq3(uni)) {
5048 byte_copy_4(dst, &uni);
5049 dst += 3; src += 3;
5050 uni = byte_load_4(src);
5051 }
5052 if (is_utf8_seq1(uni)) goto copy_ascii;
5053 while (is_utf8_seq2(uni)) {
5054 byte_copy_2(dst, &uni);
5055 dst += 2; src += 2;
5056 uni = byte_load_4(src);
5057 }
5058 while (is_utf8_seq4(uni)) {
5059 byte_copy_4(dst, &uni);
5060 dst += 4; src += 4;
5061 uni = byte_load_4(src);
5062 }
5063#endif
5064 if (unlikely(pos == src)) {
5065 if (!has_allow(INVALID_UNICODE)) {
5067 }
5068 goto copy_ascii_stop_1;
5069 }
5070 goto copy_ascii;
5071 }
5072 goto copy_escape;
5073
5074#undef return_err
5075}
5076
5078 yyjson_val *val, const char **msg) {
5079 return read_str_opt('\"', ptr, eof, flg, val, msg, NULL);
5080}
5081
5083 yyjson_val *val, const char **msg, u8 **con) {
5084 return read_str_opt('\"', ptr, eof, flg, val, msg, con);
5085}
5086
5088 yyjson_val *val, const char **msg) {
5089 return read_str_opt('\'', ptr, eof, flg, val, msg, NULL);
5090}
5091
5092/** Read unquoted key (identifier name). */
5094 u8 **pre, yyjson_val *val, const char **msg) {
5095#define return_err(_end, _msg) do { \
5096 *msg = _msg; \
5097 *end = _end; \
5098 return false; \
5099} while (false)
5100
5101#define return_suc(_str_end, _cur_end) do { \
5102 val->tag = ((u64)(_str_end - hdr) << YYJSON_TAG_BIT) | \
5103 (u64)(YYJSON_TYPE_STR); \
5104 val->uni.str = (const char *)hdr; \
5105 *pre = _str_end; *end = _cur_end; \
5106 return true; \
5107} while (false)
5108
5109 u8 *hdr = *ptr;
5110 u8 **end = ptr;
5111 u8 *src = hdr, *dst = NULL;
5112 u32 uni, tmp;
5113
5114 /* add null-terminator for previous raw string */
5115 **pre = '\0';
5116
5117skip_ascii:
5118#define expr_jump(i) \
5119 if (likely(char_is_id_ascii(src[i]))) {} \
5120 else goto skip_ascii_stop##i;
5121
5122#define expr_stop(i) \
5123 skip_ascii_stop##i: \
5124 src += i; \
5125 goto skip_ascii_end;
5126
5128 src += 16;
5129 goto skip_ascii;
5131
5132#undef expr_jump
5133#undef expr_stop
5134
5135skip_ascii_end:
5136 gcc_store_barrier(*src);
5137 if (likely(!char_is_id_next(*src))) {
5138 return_suc(src, src);
5139 }
5140
5141skip_utf8:
5142 while (*src >= 0x80) {
5143 if (has_allow(EXT_WHITESPACE)) {
5144 if (char_is_space_ext(*src) && ext_space_len(src)) {
5145 return_suc(src, src);
5146 }
5147 }
5148 uni = byte_load_4(src);
5149 if (is_utf8_seq2(uni)) {
5150 src += 2;
5151 } else if (is_utf8_seq3(uni)) {
5152 src += 3;
5153 } else if (is_utf8_seq4(uni)) {
5154 src += 4;
5155 } else {
5156#if !YYJSON_DISABLE_UTF8_VALIDATION
5157 if (!has_allow(INVALID_UNICODE)) return_err(src, MSG_ERR_UTF8);
5158#endif
5159 src += 1;
5160 }
5161 }
5162 if (char_is_id_ascii(*src)) goto skip_ascii;
5163
5164 /* The escape character appears, we need to copy it. */
5165 dst = src;
5166copy_escape:
5167 if (byte_match_2(src, "\\u")) {
5168 if (!read_uni_esc(&src, &dst, msg)) return_err(src, *msg);
5169 } else {
5170 if (!char_is_id_next(*src)) return_suc(dst, src);
5171 return_err(src, "unexpected character in key");
5172 }
5173
5174copy_ascii:
5175 /*
5176 Copy continuous ASCII, loop unrolling, same as the following code:
5177
5178 while (true) repeat16({
5179 if (char_is_ascii_skip(*src)) *dst++ = *src++;
5180 else break;
5181 })
5182 */
5183#define expr_jump(i) \
5184 if (likely((char_is_id_ascii(src[i])))) {} \
5185 else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; }
5187#undef expr_jump
5188
5189 byte_move_16(dst, src);
5190 dst += 16; src += 16;
5191 goto copy_ascii;
5192
5193#define expr_jump(i) \
5194 copy_ascii_stop_##i: \
5195 byte_move_forward(dst, src, i); \
5196 dst += i; src += i; \
5197 goto copy_utf8;
5199#undef expr_jump
5200
5201copy_utf8:
5202 while (*src >= 0x80) { /* non-ASCII character */
5203 if (has_allow(EXT_WHITESPACE)) {
5204 if (char_is_space_ext(*src) && ext_space_len(src)) {
5205 return_suc(dst, src);
5206 }
5207 }
5208 uni = byte_load_4(src);
5209 if (is_utf8_seq2(uni)) {
5210 byte_copy_2(dst, &uni);
5211 dst += 2; src += 2;
5212 } else if (is_utf8_seq3(uni)) {
5213 byte_copy_4(dst, &uni);
5214 dst += 3; src += 3;
5215 } else if (is_utf8_seq4(uni)) {
5216 byte_copy_4(dst, &uni);
5217 dst += 4; src += 4;
5218 } else {
5219#if !YYJSON_DISABLE_UTF8_VALIDATION
5220 if (!has_allow(INVALID_UNICODE)) return_err(src, MSG_ERR_UTF8);
5221#endif
5222 *dst = *src;
5223 dst += 1; src += 1;
5224 }
5225 }
5226 if (char_is_id_ascii(*src)) goto copy_ascii;
5227 goto copy_escape;
5228
5229#undef return_err
5230#undef return_suc
5231}
5232
5233
5234
5235/*==============================================================================
5236 * MARK: - JSON Reader Implementation (Private)
5237 *
5238 * We use goto statements to build the finite state machine (FSM).
5239 * The FSM's state was held by program counter (PC) and the 'goto' make the
5240 * state transitions.
5241 *============================================================================*/
5242
5243/** Read single value JSON document. */
5245 yyjson_alc alc,
5246 yyjson_read_flag flg,
5247 yyjson_read_err *err) {
5248#define return_err(_pos, _code, _msg) do { \
5249 if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \
5250 err->pos = (usize)(eof - hdr); \
5251 err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
5252 err->msg = MSG_NOT_END; \
5253 } else { \
5254 err->pos = (usize)(_pos - hdr); \
5255 err->code = YYJSON_READ_ERROR_##_code; \
5256 err->msg = _msg; \
5257 } \
5258 if (val_hdr) alc.free(alc.ctx, val_hdr); \
5259 return NULL; \
5260} while (false)
5261
5262 usize hdr_len; /* value count used by doc */
5263 usize alc_num; /* value count capacity */
5264 yyjson_val *val_hdr; /* the head of allocated values */
5265 yyjson_val *val; /* current value */
5266 yyjson_doc *doc; /* the JSON document, equals to val_hdr */
5267 const char *msg; /* error message */
5268
5269 u8 raw_end[1]; /* raw end for null-terminator */
5270 u8 *raw_ptr = raw_end;
5271 u8 **pre = &raw_ptr; /* previous raw end pointer */
5272
5273 hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
5274 hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
5275 alc_num = hdr_len + 1; /* single value */
5276
5277 val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_num * sizeof(yyjson_val));
5278 if (unlikely(!val_hdr)) goto fail_alloc;
5279 val = val_hdr + hdr_len;
5280
5281 if (char_is_num(*cur)) {
5282 if (likely(read_num(&cur, pre, flg, val, &msg))) goto doc_end;
5283 goto fail_number;
5284 }
5285 if (*cur == '"') {
5286 if (likely(read_str(&cur, eof, flg, val, &msg))) goto doc_end;
5287 goto fail_string;
5288 }
5289 if (*cur == 't') {
5290 if (likely(read_true(&cur, val))) goto doc_end;
5291 goto fail_literal_true;
5292 }
5293 if (*cur == 'f') {
5294 if (likely(read_false(&cur, val))) goto doc_end;
5295 goto fail_literal_false;
5296 }
5297 if (*cur == 'n') {
5298 if (likely(read_null(&cur, val))) goto doc_end;
5299 if (has_allow(INF_AND_NAN)) {
5300 if (read_nan(&cur, pre, flg, val)) goto doc_end;
5301 }
5302 goto fail_literal_null;
5303 }
5304 if (has_allow(INF_AND_NAN)) {
5305 if (read_inf_or_nan(&cur, pre, flg, val)) goto doc_end;
5306 }
5307 if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
5308 if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto doc_end;
5309 goto fail_string;
5310 }
5311 goto fail_character;
5312
5313doc_end:
5314 /* check invalid contents after json document */
5315 if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) {
5316 while (char_is_space(*cur)) cur++;
5317 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5318 if (!skip_trivia(&cur, eof, flg) && cur == eof) {
5319 goto fail_comment;
5320 }
5321 }
5322 if (unlikely(cur < eof)) goto fail_garbage;
5323 }
5324
5325 **pre = '\0';
5326 doc = (yyjson_doc *)val_hdr;
5327 doc->root = val_hdr + hdr_len;
5328 doc->alc = alc;
5329 doc->dat_read = (usize)(cur - hdr);
5330 doc->val_read = 1;
5331 doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
5332 return doc;
5333
5334fail_string: return_err(cur, INVALID_STRING, msg);
5335fail_number: return_err(cur, INVALID_NUMBER, msg);
5336fail_alloc: return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
5337fail_literal_true: return_err(cur, LITERAL, MSG_CHAR_T);
5338fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F);
5339fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N);
5340fail_character: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
5341fail_comment: return_err(cur, INVALID_COMMENT, MSG_COMMENT);
5342fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
5343fail_depth: return_err(cur, DEPTH, MSG_DEPTH);
5344
5345#undef return_err
5346}
5347
5348/** Read JSON document (accept all style, but optimized for minify). */
5350 yyjson_alc alc,
5351 yyjson_read_flag flg,
5352 yyjson_read_err *err) {
5353#define return_err(_pos, _code, _msg) do { \
5354 if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \
5355 err->pos = (usize)(eof - hdr); \
5356 err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
5357 err->msg = MSG_NOT_END; \
5358 } else { \
5359 err->pos = (usize)(_pos - hdr); \
5360 err->code = YYJSON_READ_ERROR_##_code; \
5361 err->msg = _msg; \
5362 } \
5363 if (val_hdr) alc.free(alc.ctx, val_hdr); \
5364 return NULL; \
5365} while (false)
5366
5367#define val_incr() do { \
5368 val++; \
5369 if (unlikely(val >= val_end)) { \
5370 usize alc_old = alc_len; \
5371 usize val_ofs = (usize)(val - val_hdr); \
5372 usize ctn_ofs = (usize)(ctn - val_hdr); \
5373 alc_len += alc_len / 2; \
5374 if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \
5375 val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
5376 alc_old * sizeof(yyjson_val), \
5377 alc_len * sizeof(yyjson_val)); \
5378 if ((!val_tmp)) goto fail_alloc; \
5379 val = val_tmp + val_ofs; \
5380 ctn = val_tmp + ctn_ofs; \
5381 val_hdr = val_tmp; \
5382 val_end = val_tmp + (alc_len - 2); \
5383 } \
5384} while (false)
5385
5386 usize dat_len; /* data length in bytes, hint for allocator */
5387 usize hdr_len; /* value count used by yyjson_doc */
5388 usize alc_len; /* value count allocated */
5389 usize alc_max; /* maximum value count for allocator */
5390 usize ctn_len; /* the number of elements in current container */
5391 yyjson_val *val_hdr; /* the head of allocated values */
5392 yyjson_val *val_end; /* the end of allocated values */
5393 yyjson_val *val_tmp; /* temporary pointer for realloc */
5394 yyjson_val *val; /* current JSON value */
5395 yyjson_val *ctn; /* current container */
5396 yyjson_val *ctn_parent; /* parent of current container */
5397 yyjson_doc *doc; /* the JSON document, equals to val_hdr */
5398 const char *msg; /* error message */
5399
5400 u8 raw_end[1]; /* raw end for null-terminator */
5401 u8 *raw_ptr = raw_end;
5402 u8 **pre = &raw_ptr; /* previous raw end pointer */
5403
5404#if YYJSON_READER_DEPTH_LIMIT
5405 u32 container_depth = 0; /* current array/object depth */
5406#endif
5407
5408 dat_len = has_flg(STOP_WHEN_DONE) ? 256 : (usize)(eof - cur);
5409 hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
5410 hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
5411 alc_max = USIZE_MAX / sizeof(yyjson_val);
5412 alc_len = hdr_len + (dat_len / YYJSON_READER_ESTIMATED_MINIFY_RATIO) + 4;
5413 alc_len = yyjson_min(alc_len, alc_max);
5414
5415 val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_len * sizeof(yyjson_val));
5416 if (unlikely(!val_hdr)) goto fail_alloc;
5417 val_end = val_hdr + (alc_len - 2); /* padding for key-value pair reading */
5418 val = val_hdr + hdr_len;
5419 ctn = val;
5420 ctn_len = 0;
5421
5422 if (*cur++ == '{') {
5423 ctn->tag = YYJSON_TYPE_OBJ;
5424 ctn->uni.ofs = 0;
5425 goto obj_key_begin;
5426 } else {
5427 ctn->tag = YYJSON_TYPE_ARR;
5428 ctn->uni.ofs = 0;
5429 goto arr_val_begin;
5430 }
5431
5432arr_begin:
5433#if YYJSON_READER_DEPTH_LIMIT
5434 container_depth++;
5435 if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) {
5436 goto fail_depth;
5437 }
5438#endif
5439 /* save current container */
5440 ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
5441 (ctn->tag & YYJSON_TAG_MASK);
5442
5443 /* create a new array value, save parent container offset */
5444 val_incr();
5445 val->tag = YYJSON_TYPE_ARR;
5446 val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
5447
5448 /* push the new array value as current container */
5449 ctn = val;
5450 ctn_len = 0;
5451
5452arr_val_begin:
5453 if (*cur == '{') {
5454 cur++;
5455 goto obj_begin;
5456 }
5457 if (*cur == '[') {
5458 cur++;
5459 goto arr_begin;
5460 }
5461 if (char_is_num(*cur)) {
5462 val_incr();
5463 ctn_len++;
5464 if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_end;
5465 goto fail_number;
5466 }
5467 if (*cur == '"') {
5468 val_incr();
5469 ctn_len++;
5470 if (likely(read_str(&cur, eof, flg, val, &msg))) goto arr_val_end;
5471 goto fail_string;
5472 }
5473 if (*cur == 't') {
5474 val_incr();
5475 ctn_len++;
5476 if (likely(read_true(&cur, val))) goto arr_val_end;
5477 goto fail_literal_true;
5478 }
5479 if (*cur == 'f') {
5480 val_incr();
5481 ctn_len++;
5482 if (likely(read_false(&cur, val))) goto arr_val_end;
5483 goto fail_literal_false;
5484 }
5485 if (*cur == 'n') {
5486 val_incr();
5487 ctn_len++;
5488 if (likely(read_null(&cur, val))) goto arr_val_end;
5489 if (has_allow(INF_AND_NAN)) {
5490 if (read_nan(&cur, pre, flg, val)) goto arr_val_end;
5491 }
5492 goto fail_literal_null;
5493 }
5494 if (*cur == ']') {
5495 cur++;
5496 if (likely(ctn_len == 0)) goto arr_end;
5497 if (has_allow(TRAILING_COMMAS)) goto arr_end;
5498 do { cur--; } while (*cur != ',');
5499 goto fail_trailing_comma;
5500 }
5501 if (char_is_space(*cur)) {
5502 while (char_is_space(*++cur));
5503 goto arr_val_begin;
5504 }
5505 if (has_allow(INF_AND_NAN) &&
5506 (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
5507 val_incr();
5508 ctn_len++;
5509 if (read_inf_or_nan(&cur, pre, flg, val)) goto arr_val_end;
5510 goto fail_character_val;
5511 }
5512 if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
5513 val_incr();
5514 ctn_len++;
5515 if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto arr_val_end;
5516 goto fail_string;
5517 }
5518 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5519 if (skip_trivia(&cur, eof, flg)) goto arr_val_begin;
5520 if (cur == eof) goto fail_comment;
5521 }
5522 goto fail_character_val;
5523
5524arr_val_end:
5525 if (*cur == ',') {
5526 cur++;
5527 goto arr_val_begin;
5528 }
5529 if (*cur == ']') {
5530 cur++;
5531 goto arr_end;
5532 }
5533 if (char_is_space(*cur)) {
5534 while (char_is_space(*++cur));
5535 goto arr_val_end;
5536 }
5537 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5538 if (skip_trivia(&cur, eof, flg)) goto arr_val_end;
5539 if (cur == eof) goto fail_comment;
5540 }
5541 goto fail_character_arr_end;
5542
5543arr_end:
5544#if YYJSON_READER_DEPTH_LIMIT
5545 container_depth--;
5546#endif
5547 /* get parent container */
5548 ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
5549
5550 /* save the next sibling value offset */
5551 ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
5552 ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
5553 if (unlikely(ctn == ctn_parent)) goto doc_end;
5554
5555 /* pop parent as current container */
5556 ctn = ctn_parent;
5557 ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
5558 if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
5559 goto obj_val_end;
5560 } else {
5561 goto arr_val_end;
5562 }
5563
5564obj_begin:
5565#if YYJSON_READER_DEPTH_LIMIT
5566 container_depth++;
5567 if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) {
5568 goto fail_depth;
5569 }
5570#endif
5571 /* push container */
5572 ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
5573 (ctn->tag & YYJSON_TAG_MASK);
5574 val_incr();
5575 val->tag = YYJSON_TYPE_OBJ;
5576 /* offset to the parent */
5577 val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
5578 ctn = val;
5579 ctn_len = 0;
5580
5581obj_key_begin:
5582 if (likely(*cur == '"')) {
5583 val_incr();
5584 ctn_len++;
5585 if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_key_end;
5586 goto fail_string;
5587 }
5588 if (likely(*cur == '}')) {
5589 cur++;
5590 if (likely(ctn_len == 0)) goto obj_end;
5591 if (has_allow(TRAILING_COMMAS)) goto obj_end;
5592 do { cur--; } while (*cur != ',');
5593 goto fail_trailing_comma;
5594 }
5595 if (char_is_space(*cur)) {
5596 while (char_is_space(*++cur));
5597 goto obj_key_begin;
5598 }
5599 if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
5600 val_incr();
5601 ctn_len++;
5602 if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_key_end;
5603 goto fail_string;
5604 }
5605 if (has_allow(UNQUOTED_KEY) && char_is_id_start(*cur)) {
5606 val_incr();
5607 ctn_len++;
5608 if (read_str_id(&cur, eof, flg, pre, val, &msg)) goto obj_key_end;
5609 goto fail_string;
5610 }
5611 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5612 if (skip_trivia(&cur, eof, flg)) goto obj_key_begin;
5613 if (cur == eof) goto fail_comment;
5614 }
5615 goto fail_character_obj_key;
5616
5617obj_key_end:
5618 if (*cur == ':') {
5619 cur++;
5620 goto obj_val_begin;
5621 }
5622 if (char_is_space(*cur)) {
5623 while (char_is_space(*++cur));
5624 goto obj_key_end;
5625 }
5626 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5627 if (skip_trivia(&cur, eof, flg)) goto obj_key_end;
5628 if (cur == eof) goto fail_comment;
5629 }
5630 goto fail_character_obj_sep;
5631
5632obj_val_begin:
5633 if (*cur == '"') {
5634 val++;
5635 ctn_len++;
5636 if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_val_end;
5637 goto fail_string;
5638 }
5639 if (char_is_num(*cur)) {
5640 val++;
5641 ctn_len++;
5642 if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_end;
5643 goto fail_number;
5644 }
5645 if (*cur == '{') {
5646 cur++;
5647 goto obj_begin;
5648 }
5649 if (*cur == '[') {
5650 cur++;
5651 goto arr_begin;
5652 }
5653 if (*cur == 't') {
5654 val++;
5655 ctn_len++;
5656 if (likely(read_true(&cur, val))) goto obj_val_end;
5657 goto fail_literal_true;
5658 }
5659 if (*cur == 'f') {
5660 val++;
5661 ctn_len++;
5662 if (likely(read_false(&cur, val))) goto obj_val_end;
5663 goto fail_literal_false;
5664 }
5665 if (*cur == 'n') {
5666 val++;
5667 ctn_len++;
5668 if (likely(read_null(&cur, val))) goto obj_val_end;
5669 if (has_allow(INF_AND_NAN)) {
5670 if (read_nan(&cur, pre, flg, val)) goto obj_val_end;
5671 }
5672 goto fail_literal_null;
5673 }
5674 if (char_is_space(*cur)) {
5675 while (char_is_space(*++cur));
5676 goto obj_val_begin;
5677 }
5678 if (has_allow(INF_AND_NAN) &&
5679 (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
5680 val++;
5681 ctn_len++;
5682 if (read_inf_or_nan(&cur, pre, flg, val)) goto obj_val_end;
5683 goto fail_character_val;
5684 }
5685 if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
5686 val++;
5687 ctn_len++;
5688 if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_val_end;
5689 goto fail_string;
5690 }
5691 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5692 if (skip_trivia(&cur, eof, flg)) goto obj_val_begin;
5693 if (cur == eof) goto fail_comment;
5694 }
5695 goto fail_character_val;
5696
5697obj_val_end:
5698 if (likely(*cur == ',')) {
5699 cur++;
5700 goto obj_key_begin;
5701 }
5702 if (likely(*cur == '}')) {
5703 cur++;
5704 goto obj_end;
5705 }
5706 if (char_is_space(*cur)) {
5707 while (char_is_space(*++cur));
5708 goto obj_val_end;
5709 }
5710 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5711 if (skip_trivia(&cur, eof, flg)) goto obj_val_end;
5712 if (cur == eof) goto fail_comment;
5713 }
5714 goto fail_character_obj_end;
5715
5716obj_end:
5717#if YYJSON_READER_DEPTH_LIMIT
5718 container_depth--;
5719#endif
5720 /* pop container */
5721 ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
5722 /* point to the next value */
5723 ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
5724 ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
5725 if (unlikely(ctn == ctn_parent)) goto doc_end;
5726 ctn = ctn_parent;
5727 ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
5728 if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
5729 goto obj_val_end;
5730 } else {
5731 goto arr_val_end;
5732 }
5733
5734doc_end:
5735 /* check invalid contents after json document */
5736 if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) {
5737 while (char_is_space(*cur)) cur++;
5738 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5739 if (!skip_trivia(&cur, eof, flg) && cur == eof) {
5740 goto fail_comment;
5741 }
5742 }
5743 if (unlikely(cur < eof)) goto fail_garbage;
5744 }
5745
5746 **pre = '\0';
5747 doc = (yyjson_doc *)val_hdr;
5748 doc->root = val_hdr + hdr_len;
5749 doc->alc = alc;
5750 doc->dat_read = (usize)(cur - hdr);
5751 doc->val_read = (usize)((val - doc->root) + 1);
5752 doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
5753 return doc;
5754
5755fail_string: return_err(cur, INVALID_STRING, msg);
5756fail_number: return_err(cur, INVALID_NUMBER, msg);
5757fail_alloc: return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
5758fail_trailing_comma: return_err(cur, JSON_STRUCTURE, MSG_COMMA);
5759fail_literal_true: return_err(cur, LITERAL, MSG_CHAR_T);
5760fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F);
5761fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N);
5762fail_character_val: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
5763fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END);
5764fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY);
5765fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
5766fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
5767fail_comment: return_err(cur, INVALID_COMMENT, MSG_COMMENT);
5768fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
5769fail_depth: return_err(cur, DEPTH, MSG_DEPTH);
5770
5771#undef val_incr
5772#undef return_err
5773}
5774
5775/** Read JSON document (accept all style, but optimized for pretty). */
5777 yyjson_alc alc,
5778 yyjson_read_flag flg,
5779 yyjson_read_err *err) {
5780#define return_err(_pos, _code, _msg) do { \
5781 if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \
5782 err->pos = (usize)(eof - hdr); \
5783 err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
5784 err->msg = MSG_NOT_END; \
5785 } else { \
5786 err->pos = (usize)(_pos - hdr); \
5787 err->code = YYJSON_READ_ERROR_##_code; \
5788 err->msg = _msg; \
5789 } \
5790 if (val_hdr) alc.free(alc.ctx, val_hdr); \
5791 return NULL; \
5792} while (false)
5793
5794#define val_incr() do { \
5795 val++; \
5796 if (unlikely(val >= val_end)) { \
5797 usize alc_old = alc_len; \
5798 usize val_ofs = (usize)(val - val_hdr); \
5799 usize ctn_ofs = (usize)(ctn - val_hdr); \
5800 alc_len += alc_len / 2; \
5801 if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \
5802 val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
5803 alc_old * sizeof(yyjson_val), \
5804 alc_len * sizeof(yyjson_val)); \
5805 if ((!val_tmp)) goto fail_alloc; \
5806 val = val_tmp + val_ofs; \
5807 ctn = val_tmp + ctn_ofs; \
5808 val_hdr = val_tmp; \
5809 val_end = val_tmp + (alc_len - 2); \
5810 } \
5811} while (false)
5812
5813 usize dat_len; /* data length in bytes, hint for allocator */
5814 usize hdr_len; /* value count used by yyjson_doc */
5815 usize alc_len; /* value count allocated */
5816 usize alc_max; /* maximum value count for allocator */
5817 usize ctn_len; /* the number of elements in current container */
5818 yyjson_val *val_hdr; /* the head of allocated values */
5819 yyjson_val *val_end; /* the end of allocated values */
5820 yyjson_val *val_tmp; /* temporary pointer for realloc */
5821 yyjson_val *val; /* current JSON value */
5822 yyjson_val *ctn; /* current container */
5823 yyjson_val *ctn_parent; /* parent of current container */
5824 yyjson_doc *doc; /* the JSON document, equals to val_hdr */
5825 const char *msg; /* error message */
5826
5827 u8 raw_end[1]; /* raw end for null-terminator */
5828 u8 *raw_ptr = raw_end;
5829 u8 **pre = &raw_ptr; /* previous raw end pointer */
5830#if YYJSON_READER_DEPTH_LIMIT
5831 u32 container_depth = 0; /* current array/object depth */
5832#endif
5833
5834 dat_len = has_flg(STOP_WHEN_DONE) ? 256 : (usize)(eof - cur);
5835 hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
5836 hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
5837 alc_max = USIZE_MAX / sizeof(yyjson_val);
5838 alc_len = hdr_len + (dat_len / YYJSON_READER_ESTIMATED_PRETTY_RATIO) + 4;
5839 alc_len = yyjson_min(alc_len, alc_max);
5840
5841 val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_len * sizeof(yyjson_val));
5842 if (unlikely(!val_hdr)) goto fail_alloc;
5843 val_end = val_hdr + (alc_len - 2); /* padding for key-value pair reading */
5844 val = val_hdr + hdr_len;
5845 ctn = val;
5846 ctn_len = 0;
5847
5848 if (*cur++ == '{') {
5849 ctn->tag = YYJSON_TYPE_OBJ;
5850 ctn->uni.ofs = 0;
5851 if (*cur == '\n') cur++;
5852 goto obj_key_begin;
5853 } else {
5854 ctn->tag = YYJSON_TYPE_ARR;
5855 ctn->uni.ofs = 0;
5856 if (*cur == '\n') cur++;
5857 goto arr_val_begin;
5858 }
5859
5860arr_begin:
5861#if YYJSON_READER_DEPTH_LIMIT
5862 container_depth++;
5863 if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) {
5864 goto fail_depth;
5865 }
5866#endif
5867
5868 /* save current container */
5869 ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
5870 (ctn->tag & YYJSON_TAG_MASK);
5871
5872 /* create a new array value, save parent container offset */
5873 val_incr();
5874 val->tag = YYJSON_TYPE_ARR;
5875 val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
5876
5877 /* push the new array value as current container */
5878 ctn = val;
5879 ctn_len = 0;
5880 if (*cur == '\n') cur++;
5881
5882arr_val_begin:
5883#if YYJSON_IS_REAL_GCC
5884 while (true) repeat16({
5885 if (byte_match_2(cur, " ")) cur += 2;
5886 else break;
5887 })
5888#else
5889 while (true) repeat16({
5890 if (likely(byte_match_2(cur, " "))) cur += 2;
5891 else break;
5892 })
5893#endif
5894
5895 if (*cur == '{') {
5896 cur++;
5897 goto obj_begin;
5898 }
5899 if (*cur == '[') {
5900 cur++;
5901 goto arr_begin;
5902 }
5903 if (char_is_num(*cur)) {
5904 val_incr();
5905 ctn_len++;
5906 if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_end;
5907 goto fail_number;
5908 }
5909 if (*cur == '"') {
5910 val_incr();
5911 ctn_len++;
5912 if (likely(read_str(&cur, eof, flg, val, &msg))) goto arr_val_end;
5913 goto fail_string;
5914 }
5915 if (*cur == 't') {
5916 val_incr();
5917 ctn_len++;
5918 if (likely(read_true(&cur, val))) goto arr_val_end;
5919 goto fail_literal_true;
5920 }
5921 if (*cur == 'f') {
5922 val_incr();
5923 ctn_len++;
5924 if (likely(read_false(&cur, val))) goto arr_val_end;
5925 goto fail_literal_false;
5926 }
5927 if (*cur == 'n') {
5928 val_incr();
5929 ctn_len++;
5930 if (likely(read_null(&cur, val))) goto arr_val_end;
5931 if (has_allow(INF_AND_NAN)) {
5932 if (read_nan(&cur, pre, flg, val)) goto arr_val_end;
5933 }
5934 goto fail_literal_null;
5935 }
5936 if (*cur == ']') {
5937 cur++;
5938 if (likely(ctn_len == 0)) goto arr_end;
5939 if (has_allow(TRAILING_COMMAS)) goto arr_end;
5940 do { cur--; } while (*cur != ',');
5941 goto fail_trailing_comma;
5942 }
5943 if (char_is_space(*cur)) {
5944 while (char_is_space(*++cur));
5945 goto arr_val_begin;
5946 }
5947 if (has_allow(INF_AND_NAN) &&
5948 (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
5949 val_incr();
5950 ctn_len++;
5951 if (read_inf_or_nan(&cur, pre, flg, val)) goto arr_val_end;
5952 goto fail_character_val;
5953 }
5954 if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
5955 val_incr();
5956 ctn_len++;
5957 if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto arr_val_end;
5958 goto fail_string;
5959 }
5960 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5961 if (skip_trivia(&cur, eof, flg)) goto arr_val_begin;
5962 if (cur == eof) goto fail_comment;
5963 }
5964 goto fail_character_val;
5965
5966arr_val_end:
5967 if (byte_match_2(cur, ",\n")) {
5968 cur += 2;
5969 goto arr_val_begin;
5970 }
5971 if (*cur == ',') {
5972 cur++;
5973 goto arr_val_begin;
5974 }
5975 if (*cur == ']') {
5976 cur++;
5977 goto arr_end;
5978 }
5979 if (char_is_space(*cur)) {
5980 while (char_is_space(*++cur));
5981 goto arr_val_end;
5982 }
5983 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
5984 if (skip_trivia(&cur, eof, flg)) goto arr_val_end;
5985 if (cur == eof) goto fail_comment;
5986 }
5987 goto fail_character_arr_end;
5988
5989arr_end:
5990#if YYJSON_READER_DEPTH_LIMIT
5991 container_depth--;
5992#endif
5993 /* get parent container */
5994 ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
5995
5996 /* save the next sibling value offset */
5997 ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
5998 ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
5999 if (unlikely(ctn == ctn_parent)) goto doc_end;
6000
6001 /* pop parent as current container */
6002 ctn = ctn_parent;
6003 ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
6004 if (*cur == '\n') cur++;
6005 if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
6006 goto obj_val_end;
6007 } else {
6008 goto arr_val_end;
6009 }
6010
6011obj_begin:
6012#if YYJSON_READER_DEPTH_LIMIT
6013 container_depth++;
6014 if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) {
6015 goto fail_depth;
6016 }
6017#endif
6018
6019 /* push container */
6020 ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
6021 (ctn->tag & YYJSON_TAG_MASK);
6022 val_incr();
6023 val->tag = YYJSON_TYPE_OBJ;
6024 /* offset to the parent */
6025 val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
6026 ctn = val;
6027 ctn_len = 0;
6028 if (*cur == '\n') cur++;
6029
6030obj_key_begin:
6031#if YYJSON_IS_REAL_GCC
6032 while (true) repeat16({
6033 if (byte_match_2(cur, " ")) cur += 2;
6034 else break;
6035 })
6036#else
6037 while (true) repeat16({
6038 if (likely(byte_match_2(cur, " "))) cur += 2;
6039 else break;
6040 })
6041#endif
6042 if (likely(*cur == '"')) {
6043 val_incr();
6044 ctn_len++;
6045 if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_key_end;
6046 goto fail_string;
6047 }
6048 if (likely(*cur == '}')) {
6049 cur++;
6050 if (likely(ctn_len == 0)) goto obj_end;
6051 if (has_allow(TRAILING_COMMAS)) goto obj_end;
6052 do { cur--; } while (*cur != ',');
6053 goto fail_trailing_comma;
6054 }
6055 if (char_is_space(*cur)) {
6056 while (char_is_space(*++cur));
6057 goto obj_key_begin;
6058 }
6059 if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
6060 val_incr();
6061 ctn_len++;
6062 if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_key_end;
6063 goto fail_string;
6064 }
6065 if (has_allow(UNQUOTED_KEY) && char_is_id_start(*cur)) {
6066 val_incr();
6067 ctn_len++;
6068 if (read_str_id(&cur, eof, flg, pre, val, &msg)) goto obj_key_end;
6069 goto fail_string;
6070 }
6071 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
6072 if (skip_trivia(&cur, eof, flg)) goto obj_key_begin;
6073 if (cur == eof) goto fail_comment;
6074 }
6075 goto fail_character_obj_key;
6076
6077obj_key_end:
6078 if (byte_match_2(cur, ": ")) {
6079 cur += 2;
6080 goto obj_val_begin;
6081 }
6082 if (*cur == ':') {
6083 cur++;
6084 goto obj_val_begin;
6085 }
6086 if (char_is_space(*cur)) {
6087 while (char_is_space(*++cur));
6088 goto obj_key_end;
6089 }
6090 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
6091 if (skip_trivia(&cur, eof, flg)) goto obj_key_end;
6092 if (cur == eof) goto fail_comment;
6093 }
6094 goto fail_character_obj_sep;
6095
6096obj_val_begin:
6097 if (*cur == '"') {
6098 val++;
6099 ctn_len++;
6100 if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_val_end;
6101 goto fail_string;
6102 }
6103 if (char_is_num(*cur)) {
6104 val++;
6105 ctn_len++;
6106 if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_end;
6107 goto fail_number;
6108 }
6109 if (*cur == '{') {
6110 cur++;
6111 goto obj_begin;
6112 }
6113 if (*cur == '[') {
6114 cur++;
6115 goto arr_begin;
6116 }
6117 if (*cur == 't') {
6118 val++;
6119 ctn_len++;
6120 if (likely(read_true(&cur, val))) goto obj_val_end;
6121 goto fail_literal_true;
6122 }
6123 if (*cur == 'f') {
6124 val++;
6125 ctn_len++;
6126 if (likely(read_false(&cur, val))) goto obj_val_end;
6127 goto fail_literal_false;
6128 }
6129 if (*cur == 'n') {
6130 val++;
6131 ctn_len++;
6132 if (likely(read_null(&cur, val))) goto obj_val_end;
6133 if (has_allow(INF_AND_NAN)) {
6134 if (read_nan(&cur, pre, flg, val)) goto obj_val_end;
6135 }
6136 goto fail_literal_null;
6137 }
6138 if (char_is_space(*cur)) {
6139 while (char_is_space(*++cur));
6140 goto obj_val_begin;
6141 }
6142 if (has_allow(INF_AND_NAN) &&
6143 (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
6144 val++;
6145 ctn_len++;
6146 if (read_inf_or_nan(&cur, pre, flg, val)) goto obj_val_end;
6147 goto fail_character_val;
6148 }
6149 if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
6150 val++;
6151 ctn_len++;
6152 if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_val_end;
6153 goto fail_string;
6154 }
6155 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
6156 if (skip_trivia(&cur, eof, flg)) goto obj_val_begin;
6157 if (cur == eof) goto fail_comment;
6158 }
6159 goto fail_character_val;
6160
6161obj_val_end:
6162 if (byte_match_2(cur, ",\n")) {
6163 cur += 2;
6164 goto obj_key_begin;
6165 }
6166 if (likely(*cur == ',')) {
6167 cur++;
6168 goto obj_key_begin;
6169 }
6170 if (likely(*cur == '}')) {
6171 cur++;
6172 goto obj_end;
6173 }
6174 if (char_is_space(*cur)) {
6175 while (char_is_space(*++cur));
6176 goto obj_val_end;
6177 }
6178 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
6179 if (skip_trivia(&cur, eof, flg)) goto obj_val_end;
6180 if (cur == eof) goto fail_comment;
6181 }
6182 goto fail_character_obj_end;
6183
6184obj_end:
6185#if YYJSON_READER_DEPTH_LIMIT
6186 container_depth--;
6187#endif
6188
6189 /* pop container */
6190 ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
6191 /* point to the next value */
6192 ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
6193 ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
6194 if (unlikely(ctn == ctn_parent)) goto doc_end;
6195 ctn = ctn_parent;
6196 ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
6197 if (*cur == '\n') cur++;
6198 if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
6199 goto obj_val_end;
6200 } else {
6201 goto arr_val_end;
6202 }
6203
6204doc_end:
6205 /* check invalid contents after json document */
6206 if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) {
6207 while (char_is_space(*cur)) cur++;
6208 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
6209 if (!skip_trivia(&cur, eof, flg) && cur == eof) {
6210 goto fail_comment;
6211 }
6212 }
6213 if (unlikely(cur < eof)) goto fail_garbage;
6214 }
6215
6216 **pre = '\0';
6217 doc = (yyjson_doc *)val_hdr;
6218 doc->root = val_hdr + hdr_len;
6219 doc->alc = alc;
6220 doc->dat_read = (usize)(cur - hdr);
6221 doc->val_read = (usize)((val - doc->root) + 1);
6222 doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
6223 return doc;
6224
6225fail_string: return_err(cur, INVALID_STRING, msg);
6226fail_number: return_err(cur, INVALID_NUMBER, msg);
6227fail_alloc: return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
6228fail_trailing_comma: return_err(cur, JSON_STRUCTURE, MSG_COMMA);
6229fail_literal_true: return_err(cur, LITERAL, MSG_CHAR_T);
6230fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F);
6231fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N);
6232fail_character_val: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
6233fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END);
6234fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY);
6235fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
6236fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
6237fail_comment: return_err(cur, INVALID_COMMENT, MSG_COMMENT);
6238fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
6239fail_depth: return_err(cur, DEPTH, MSG_DEPTH);
6240
6241#undef val_incr
6242#undef return_err
6243}
6244
6245
6246
6247/*==============================================================================
6248 * MARK: - JSON Reader (Public)
6249 *============================================================================*/
6250
6252 yyjson_read_flag flg,
6253 const yyjson_alc *alc_ptr,
6254 yyjson_read_err *err) {
6255#define return_err(_pos, _code, _msg) do { \
6256 err->pos = (usize)(_pos); \
6257 err->msg = _msg; \
6258 err->code = YYJSON_READ_ERROR_##_code; \
6259 if (!has_flg(INSITU) && hdr) alc.free(alc.ctx, (void *)hdr); \
6260 return NULL; \
6261} while (false)
6262
6263 yyjson_read_err tmp_err;
6264 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
6265 yyjson_doc *doc;
6266 u8 *hdr = NULL, *eof, *cur;
6267
6268 /* validate input parameters */
6269 if (!err) err = &tmp_err;
6270 if (unlikely(!dat)) return_err(0, INVALID_PARAMETER, "input data is NULL");
6271 if (unlikely(!len)) return_err(0, INVALID_PARAMETER, "input length is 0");
6272
6273 /* add 4-byte zero padding for input data if necessary */
6274 if (has_flg(INSITU)) {
6275 hdr = (u8 *)dat;
6276 eof = (u8 *)dat + len;
6277 cur = (u8 *)dat;
6278 } else {
6280 return_err(0, MEMORY_ALLOCATION, MSG_MALLOC);
6281 }
6282 hdr = (u8 *)alc.malloc(alc.ctx, len + YYJSON_PADDING_SIZE);
6283 if (unlikely(!hdr)) {
6284 return_err(0, MEMORY_ALLOCATION, MSG_MALLOC);
6285 }
6286 eof = hdr + len;
6287 cur = hdr;
6288 memcpy(hdr, dat, len);
6289 }
6290 memset(eof, 0, YYJSON_PADDING_SIZE);
6291
6292 if (has_allow(BOM)) {
6293 if (len >= 3 && is_utf8_bom(cur)) cur += 3;
6294 }
6295
6296 /* skip empty contents before json document */
6297 if (unlikely(!char_is_ctn(*cur))) {
6298 while (char_is_space(*cur)) cur++;
6299 if (unlikely(!char_is_ctn(*cur))) {
6300 if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
6301 if (!skip_trivia(&cur, eof, flg) && cur == eof) {
6302 return_err(cur - hdr, INVALID_COMMENT, MSG_COMMENT);
6303 }
6304 }
6305 }
6306 if (unlikely(cur >= eof)) {
6307 return_err(0, EMPTY_CONTENT, "input data is empty");
6308 }
6309 }
6310
6311 /* read json document */
6312 if (likely(char_is_ctn(*cur))) {
6313 if (char_is_space(cur[1]) && char_is_space(cur[2])) {
6314 doc = read_root_pretty(hdr, cur, eof, alc, flg, err);
6315 } else {
6316 doc = read_root_minify(hdr, cur, eof, alc, flg, err);
6317 }
6318 } else {
6319 doc = read_root_single(hdr, cur, eof, alc, flg, err);
6320 }
6321
6322 /* check result */
6323 if (likely(doc)) {
6324 memset(err, 0, sizeof(yyjson_read_err));
6325 } else {
6326 /* RFC 8259: JSON text MUST be encoded using UTF-8 */
6327 if (err->pos == 0 && err->code != YYJSON_READ_ERROR_MEMORY_ALLOCATION) {
6328 if (is_utf8_bom(hdr)) err->msg = MSG_ERR_BOM;
6329 else if (len >= 4 && is_utf32_bom(hdr)) err->msg = MSG_ERR_UTF32;
6330 else if (len >= 2 && is_utf16_bom(hdr)) err->msg = MSG_ERR_UTF16;
6331 }
6332 if (!has_flg(INSITU)) alc.free(alc.ctx, hdr);
6333 }
6334 return doc;
6335
6336#undef return_err
6337}
6338
6339#if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE
6340
6342 yyjson_read_flag flg,
6343 const yyjson_alc *alc_ptr,
6344 yyjson_read_err *err) {
6345#define return_err(_code, _msg) do { \
6346 err->pos = 0; \
6347 err->msg = _msg; \
6348 err->code = YYJSON_READ_ERROR_##_code; \
6349 return NULL; \
6350} while (false)
6351
6352 yyjson_read_err tmp_err;
6353 yyjson_doc *doc;
6354 FILE *file;
6355
6356 if (!err) err = &tmp_err;
6357 if (unlikely(!path)) return_err(INVALID_PARAMETER, "input path is NULL");
6358
6359 file = fopen_readonly(path);
6360 if (unlikely(!file)) return_err(FILE_OPEN, MSG_FREAD);
6361
6362 doc = yyjson_read_fp(file, flg, alc_ptr, err);
6363 fclose(file);
6364 return doc;
6365
6366#undef return_err
6367}
6368
6370 yyjson_read_flag flg,
6371 const yyjson_alc *alc_ptr,
6372 yyjson_read_err *err) {
6373#define return_err(_code, _msg) do { \
6374 err->pos = 0; \
6375 err->msg = _msg; \
6376 err->code = YYJSON_READ_ERROR_##_code; \
6377 if (buf) alc.free(alc.ctx, buf); \
6378 return NULL; \
6379} while (false)
6380
6381 yyjson_read_err tmp_err;
6382 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
6383 yyjson_doc *doc;
6384
6385 long file_size = 0, file_pos;
6386 void *buf = NULL;
6387 usize buf_size = 0;
6388 usize dat_size = 0;
6389
6390 /* validate input parameters */
6391 if (!err) err = &tmp_err;
6392 if (unlikely(!file)) return_err(INVALID_PARAMETER, "input file is NULL");
6393
6394 /* get current position */
6395 file_pos = ftell(file);
6396 if (file_pos != -1) {
6397 /* get total file size, may fail */
6398 if (fseek(file, 0, SEEK_END) == 0) {
6399 file_size = ftell(file);
6400 if (file_size == -1) file_size = 0;
6401 }
6402 /* reset to original position, may fail */
6403 if (fseek(file, file_pos, SEEK_SET) != 0) file_size = 0;
6404 /* get file size from current position to end */
6405 if (file_size > 0) file_size -= file_pos;
6406 }
6407
6408 /* read file */
6409 if (file_size > 0) {
6410 /* read the entire file in one call */
6411 dat_size = (usize)file_size;
6412 buf_size = dat_size + YYJSON_PADDING_SIZE;
6413 buf = alc.malloc(alc.ctx, buf_size);
6414 if (buf == NULL) {
6415 return_err(MEMORY_ALLOCATION, MSG_MALLOC);
6416 }
6417 if (fread_safe(buf, dat_size, file) != dat_size) {
6418 return_err(FILE_READ, MSG_FREAD);
6419 }
6420 } else {
6421 /* failed to get file size, read it as a stream */
6422 usize chunk_min = (usize)64;
6423 usize chunk_max = (usize)512 * 1024 * 1024;
6424 usize chunk_now = chunk_min;
6425 usize read_size;
6426 void *tmp;
6427
6428 buf_size = YYJSON_PADDING_SIZE;
6429 while (true) {
6430 if (buf_size + chunk_now < buf_size) { /* overflow */
6431 return_err(MEMORY_ALLOCATION, MSG_MALLOC);
6432 }
6433 buf_size += chunk_now;
6434 if (!buf) {
6435 buf = alc.malloc(alc.ctx, buf_size);
6436 if (!buf) return_err(MEMORY_ALLOCATION, MSG_MALLOC);
6437 } else {
6438 tmp = alc.realloc(alc.ctx, buf, buf_size - chunk_now, buf_size);
6439 if (!tmp) return_err(MEMORY_ALLOCATION, MSG_MALLOC);
6440 buf = tmp;
6441 }
6442 tmp = ((u8 *)buf) + buf_size - YYJSON_PADDING_SIZE - chunk_now;
6443 read_size = fread_safe(tmp, chunk_now, file);
6444 dat_size += read_size;
6445 if (read_size != chunk_now) break;
6446
6447 chunk_now *= 2;
6448 if (chunk_now > chunk_max) chunk_now = chunk_max;
6449 }
6450 }
6451
6452 /* read JSON */
6453 memset((u8 *)buf + dat_size, 0, YYJSON_PADDING_SIZE);
6454 flg |= YYJSON_READ_INSITU;
6455 doc = yyjson_read_opts((char *)buf, dat_size, flg, &alc, err);
6456 if (doc) {
6457 doc->str_pool = (char *)buf;
6458 return doc;
6459 } else {
6460 alc.free(alc.ctx, buf);
6461 return NULL;
6462 }
6463
6464#undef return_err
6465}
6466
6467#endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */
6468
6469const char *yyjson_read_number(const char *dat,
6470 yyjson_val *val,
6471 yyjson_read_flag flg,
6472 const yyjson_alc *alc,
6473 yyjson_read_err *err) {
6474#define return_err(_pos, _code, _msg) do { \
6475 err->pos = _pos > hdr ? (usize)(_pos - hdr) : 0; \
6476 err->msg = _msg; \
6477 err->code = YYJSON_READ_ERROR_##_code; \
6478 return NULL; \
6479} while (false)
6480
6481 u8 *hdr = constcast(u8 *)dat, *cur = hdr;
6482 u8 raw_end[1]; /* raw end for null-terminator */
6483 u8 *raw_ptr = raw_end;
6484 u8 **pre = &raw_ptr; /* previous raw end pointer */
6485 const char *msg;
6486 yyjson_read_err tmp_err;
6487
6488#if YYJSON_DISABLE_FAST_FP_CONV
6489 u8 buf[128];
6490 usize dat_len;
6491#endif
6492
6493 if (!err) err = &tmp_err;
6494 if (unlikely(!dat)) {
6495 return_err(cur, INVALID_PARAMETER, "input data is NULL");
6496 }
6497 if (unlikely(!val)) {
6498 return_err(cur, INVALID_PARAMETER, "output value is NULL");
6499 }
6500
6501#if YYJSON_DISABLE_FAST_FP_CONV
6502 if (!alc) alc = &YYJSON_DEFAULT_ALC;
6503 dat_len = strlen(dat);
6504 if (dat_len < sizeof(buf)) {
6505 memcpy(buf, dat, dat_len + 1);
6506 hdr = buf;
6507 cur = hdr;
6508 } else {
6509 hdr = (u8 *)alc->malloc(alc->ctx, dat_len + 1);
6510 cur = hdr;
6511 if (unlikely(!hdr)) {
6512 return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
6513 }
6514 memcpy(hdr, dat, dat_len + 1);
6515 }
6516 hdr[dat_len] = 0;
6517#endif
6518
6519#if YYJSON_DISABLE_FAST_FP_CONV
6520 if (!read_num(&cur, pre, flg, val, &msg)) {
6521 if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr);
6522 return_err(cur, INVALID_NUMBER, msg);
6523 }
6524 if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr);
6525 if (yyjson_is_raw(val)) val->uni.str = dat;
6526 return dat + (cur - hdr);
6527#else
6528 if (!read_num(&cur, pre, flg, val, &msg)) {
6529 return_err(cur, INVALID_NUMBER, msg);
6530 }
6531 return (const char *)cur;
6532#endif
6533
6534#undef return_err
6535}
6536
6537
6538
6539/*==============================================================================
6540 * MARK: - Incremental JSON Reader (Public)
6541 *============================================================================*/
6542
6543#if !YYJSON_DISABLE_INCR_READER
6544
6545/* labels within yyjson_incr_read() to resume incremental parsing */
6546#define LABEL_doc_begin 0
6547#define LABEL_arr_val_begin 1
6548#define LABEL_arr_val_end 2
6549#define LABEL_obj_key_begin 3
6550#define LABEL_obj_key_end 4
6551#define LABEL_obj_val_begin 5
6552#define LABEL_obj_val_end 6
6553#define LABEL_doc_end 7
6554
6555/** State for incremental JSON reader, opaque in the API. */
6557 u32 label; /* current parser goto label */
6558 yyjson_alc alc; /* allocator */
6559 yyjson_read_flag flg; /* read flags */
6560 u8 *hdr; /* JSON data header */
6561 u8 *cur; /* current position in JSON data */
6562 usize buf_len; /* total buffer length (without padding) */
6563 usize hdr_len; /* value count used by yyjson_doc */
6564 usize alc_len; /* value count allocated */
6565 usize ctn_len; /* the number of elements in current container */
6566 yyjson_val *val_hdr; /* the head of allocated values */
6567 yyjson_val *val_end; /* the end of allocated values */
6568 yyjson_val *val; /* current JSON value */
6569 yyjson_val *ctn; /* current container */
6570 u8 *str_con[2]; /* string parser incremental state */
6571 u8 *raw_ptr; /* pending position for a deferred raw null-terminator */
6572 u8 raw_end[1]; /* dummy target for the first deferred null-terminator */
6573};
6574
6575yyjson_incr_state *yyjson_incr_new(char *buf, size_t buf_len,
6576 yyjson_read_flag flg,
6577 const yyjson_alc *alc_ptr) {
6578 yyjson_incr_state *state = NULL;
6579 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
6580
6581 /* remove non-standard flags */
6582 flg &= ~YYJSON_READ_JSON5;
6585
6586 if (unlikely(!buf)) return NULL;
6587 if (unlikely(buf_len >= USIZE_MAX - YYJSON_PADDING_SIZE)) return NULL;
6588 state = (yyjson_incr_state *)alc.malloc(alc.ctx, sizeof(*state));
6589 if (!state) return NULL;
6590 memset(state, 0, sizeof(yyjson_incr_state));
6591 state->alc = alc;
6592 state->flg = flg;
6593 state->buf_len = buf_len;
6594
6595 /* add 4-byte zero padding for input data if necessary */
6596 if (has_flg(INSITU)) {
6597 state->hdr = (u8 *)buf;
6598 } else {
6599 state->hdr = (u8 *)alc.malloc(alc.ctx, buf_len + YYJSON_PADDING_SIZE);
6600 if (unlikely(!state->hdr)) {
6601 alc.free(alc.ctx, state);
6602 return NULL;
6603 }
6604 memcpy(state->hdr, buf, buf_len);
6605 }
6606 memset(state->hdr + buf_len, 0, YYJSON_PADDING_SIZE);
6607 state->cur = state->hdr;
6608 state->raw_ptr = state->raw_end;
6609 state->label = LABEL_doc_begin;
6610 return state;
6611}
6612
6614 if (state) {
6615 yyjson_alc alc = state->alc;
6616 memset(&state->alc, 0, sizeof(alc));
6617 if (state->val_hdr) {
6618 alc.free(alc.ctx, (void *)state->val_hdr);
6619 }
6620 if (state->hdr && !(state->flg & YYJSON_READ_INSITU)) {
6621 alc.free(alc.ctx, state->hdr);
6622 }
6623 alc.free(alc.ctx, state);
6624 }
6625}
6626
6628 yyjson_read_err *err) {
6629#define return_err_inv_param(_msg) do { \
6630 err->pos = 0; \
6631 err->msg = _msg; \
6632 err->code = YYJSON_READ_ERROR_INVALID_PARAMETER; \
6633 return NULL; \
6634} while (false)
6635
6636#define return_err(_pos, _code, _msg) do { \
6637 if (is_truncated_end(hdr, _pos, end, YYJSON_READ_ERROR_##_code, flg)) { \
6638 goto unexpected_end; \
6639 } else { \
6640 err->pos = (usize)(_pos - hdr); \
6641 err->code = YYJSON_READ_ERROR_##_code; \
6642 err->msg = _msg; \
6643 } \
6644 return NULL; \
6645} while (false)
6646
6647#define val_incr() do { \
6648 val++; \
6649 if (unlikely(val >= val_end)) { \
6650 usize alc_old = alc_len; \
6651 alc_len += alc_len / 2; \
6652 if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \
6653 val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
6654 alc_old * sizeof(yyjson_val), \
6655 alc_len * sizeof(yyjson_val)); \
6656 if ((!val_tmp)) goto fail_alloc; \
6657 val = val_tmp + (usize)(val - val_hdr); \
6658 ctn = val_tmp + (usize)(ctn - val_hdr); \
6659 state->val = val_tmp + (usize)(state->val - val_hdr); \
6660 state->val_hdr = val_hdr = val_tmp; \
6661 val_end = val_tmp + (alc_len - 2); \
6662 state->val_end = val_end; \
6663 } \
6664} while (false)
6665
6666 /* save position where it's possible to resume incremental parsing */
6667#define save_incr_state(_label) do { \
6668 state->label = LABEL_##_label; \
6669 state->cur = cur; \
6670 state->val = val; \
6671 state->ctn_len = ctn_len; \
6672 state->hdr_len = hdr_len; \
6673 state->raw_ptr = raw_ptr; \
6674 if (unlikely(cur >= end)) goto unexpected_end; \
6675} while (false)
6676
6677#define check_maybe_truncated_number() do { \
6678 if (unlikely(cur >= end)) { \
6679 if (unlikely(cur > state->cur + INCR_NUM_MAX_LEN)) { \
6680 msg = "number too long"; \
6681 goto fail_number; \
6682 } \
6683 goto unexpected_end; \
6684 } \
6685} while (false)
6686
6687 u8 *hdr = NULL, *end = NULL, *cur = NULL;
6688 yyjson_read_flag flg;
6689 yyjson_alc alc;
6690 usize dat_len; /* data length in bytes, hint for allocator */
6691 usize hdr_len; /* value count used by yyjson_doc */
6692 usize alc_len; /* value count allocated */
6693 usize alc_max; /* maximum value count for allocator */
6694 usize ctn_len; /* the number of elements in current container */
6695 yyjson_val *val_hdr; /* the head of allocated values */
6696 yyjson_val *val_end; /* the end of allocated values */
6697 yyjson_val *val_tmp; /* temporary pointer for realloc */
6698 yyjson_val *val; /* current JSON value */
6699 yyjson_val *ctn; /* current container */
6700 yyjson_val *ctn_parent; /* parent of current container */
6701 yyjson_doc *doc; /* the JSON document, equals to val_hdr */
6702 const char *msg; /* error message */
6703
6704 yyjson_read_err tmp_err;
6705 u8 *raw_ptr; /* deferred raw null-terminator position, committed at save */
6706 u8 **pre = &raw_ptr; /* previous raw end pointer */
6707 u8 **con = NULL; /* for incremental string parsing */
6708 u8 saved_end = '\0'; /* saved end char */
6709
6710#if YYJSON_READER_DEPTH_LIMIT
6711 u32 container_depth = 0; /* current array/object depth */
6712#endif
6713
6714 /* validate input parameters */
6715 if (!err) err = &tmp_err;
6716 if (unlikely(!state)) {
6717 return_err_inv_param("input state is NULL");
6718 }
6719 if (unlikely(!len)) {
6720 return_err_inv_param("input length is 0");
6721 }
6722 if (unlikely(len > state->buf_len)) {
6723 return_err_inv_param("length is greater than total input length");
6724 }
6725
6726 /* restore state saved from the previous call */
6727 hdr = state->hdr;
6728 end = state->hdr + len;
6729 cur = state->cur;
6730 flg = state->flg;
6731 alc = state->alc;
6732 ctn_len = state->ctn_len;
6733 hdr_len = state->hdr_len;
6734 alc_len = state->alc_len;
6735 val = state->val;
6736 val_hdr = state->val_hdr;
6737 val_end = state->val_end;
6738 ctn = state->ctn;
6739 con = state->str_con;
6740 raw_ptr = state->raw_ptr;
6741 alc_max = USIZE_MAX / sizeof(yyjson_val);
6742
6743 /* insert null terminator to make us stop at the specified end, even if
6744 the data contains more valid JSON */
6745 saved_end = *end;
6746 *end = '\0';
6747
6748 /* resume parsing from the last save point */
6749 switch (state->label) {
6750 case LABEL_doc_begin: goto doc_begin;
6751 case LABEL_arr_val_begin: goto arr_val_begin;
6752 case LABEL_arr_val_end: goto arr_val_end;
6753 case LABEL_obj_key_begin: goto obj_key_begin;
6754 case LABEL_obj_key_end: goto obj_key_end;
6755 case LABEL_obj_val_begin: goto obj_val_begin;
6756 case LABEL_obj_val_end: goto obj_val_end;
6757 case LABEL_doc_end: goto doc_end;
6758 default: return_err_inv_param("invalid incremental state");
6759 }
6760
6761doc_begin:
6762 /* skip empty contents before json document */
6763 if (unlikely(!char_is_ctn(*cur))) {
6764 while (char_is_space(*cur)) cur++;
6765 if (unlikely(cur >= end)) goto unexpected_end; /* input data is empty */
6766 }
6767
6768 /* allocate memory for document */
6769 if (!val_hdr) {
6770 hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
6771 hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
6772 if (likely(char_is_ctn(*cur))) {
6773 dat_len = has_flg(STOP_WHEN_DONE) ? 256 : state->buf_len;
6774 alc_len = hdr_len +
6776 alc_len = yyjson_min(alc_len, alc_max);
6777 } else {
6778 alc_len = hdr_len + 1; /* single value */
6779 }
6780 val_hdr = (yyjson_val *)alc.malloc(alc.ctx,
6781 alc_len * sizeof(yyjson_val));
6782 if (unlikely(!val_hdr)) goto fail_alloc;
6783 val_end = val_hdr + (alc_len - 2); /* padding for kv pair reading */
6784 val = val_hdr + hdr_len;
6785 ctn = val;
6786 ctn_len = 0;
6787 state->val_hdr = val_hdr;
6788 state->val_end = val_end;
6789 save_incr_state(doc_begin);
6790 }
6791
6792 /* read json document */
6793 if (*cur == '{') {
6794 cur++;
6795 ctn->tag = YYJSON_TYPE_OBJ;
6796 ctn->uni.ofs = 0;
6797 goto obj_key_begin;
6798 }
6799 if (*cur == '[') {
6800 cur++;
6801 ctn->tag = YYJSON_TYPE_ARR;
6802 ctn->uni.ofs = 0;
6803 goto arr_val_begin;
6804 }
6805 if (char_is_num(*cur)) {
6806 if (likely(read_num(&cur, pre, flg, val, &msg))) {
6807 /* a root number may continue with more digits in a later chunk */
6809 goto doc_end;
6810 }
6811 goto fail_number;
6812 }
6813 if (*cur == '"') {
6814 if (likely(read_str_con(&cur, end, flg, val, &msg, con))) goto doc_end;
6815 goto fail_string;
6816 }
6817 if (*cur == 't') {
6818 if (likely(read_true(&cur, val))) goto doc_end;
6819 goto fail_literal_true;
6820 }
6821 if (*cur == 'f') {
6822 if (likely(read_false(&cur, val))) goto doc_end;
6823 goto fail_literal_false;
6824 }
6825 if (*cur == 'n') {
6826 if (likely(read_null(&cur, val))) goto doc_end;
6827 goto fail_literal_null;
6828 }
6829
6830 msg = "unexpected character, expected a valid root value";
6831 if (cur == hdr) {
6832 /* RFC 8259: JSON text MUST be encoded using UTF-8 */
6833 if (is_utf8_bom(hdr)) msg = MSG_ERR_BOM;
6834 else if (len >= 4 && is_utf32_bom(hdr)) msg = MSG_ERR_UTF32;
6835 else if (len >= 2 && is_utf16_bom(hdr)) msg = MSG_ERR_UTF16;
6836 }
6837 return_err(cur, UNEXPECTED_CHARACTER, msg);
6838
6839arr_begin:
6840#if YYJSON_READER_DEPTH_LIMIT
6841 container_depth++;
6842 if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) {
6843 goto fail_depth;
6844 }
6845#endif
6846
6847 /* save current container */
6848 ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
6849 (ctn->tag & YYJSON_TAG_MASK);
6850
6851 /* create a new array value, save parent container offset */
6852 val_incr();
6853 val->tag = YYJSON_TYPE_ARR;
6854 val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
6855
6856 /* push the new array value as current container */
6857 ctn = val;
6858 ctn_len = 0;
6859
6860arr_val_begin:
6861 save_incr_state(arr_val_begin);
6862arr_val_continue:
6863 if (*cur == '{') {
6864 cur++;
6865 goto obj_begin;
6866 }
6867 if (*cur == '[') {
6868 cur++;
6869 goto arr_begin;
6870 }
6871 if (char_is_num(*cur)) {
6872 val_incr();
6873 ctn_len++;
6874 if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_maybe_end;
6875 goto fail_number;
6876 }
6877 if (*cur == '"') {
6878 val_incr();
6879 ctn_len++;
6880 if (likely(read_str_con(&cur, end, flg, val, &msg, con)))
6881 goto arr_val_end;
6882 goto fail_string;
6883 }
6884 if (*cur == 't') {
6885 val_incr();
6886 ctn_len++;
6887 if (likely(read_true(&cur, val))) goto arr_val_end;
6888 goto fail_literal_true;
6889 }
6890 if (*cur == 'f') {
6891 val_incr();
6892 ctn_len++;
6893 if (likely(read_false(&cur, val))) goto arr_val_end;
6894 goto fail_literal_false;
6895 }
6896 if (*cur == 'n') {
6897 val_incr();
6898 ctn_len++;
6899 if (likely(read_null(&cur, val))) goto arr_val_end;
6900 goto fail_literal_null;
6901 }
6902 if (*cur == ']') {
6903 cur++;
6904 if (likely(ctn_len == 0)) goto arr_end;
6905 do { cur--; } while (*cur != ',');
6906 goto fail_trailing_comma;
6907 }
6908 if (char_is_space(*cur)) {
6909 while (char_is_space(*++cur));
6910 goto arr_val_continue;
6911 }
6912 goto fail_character_val;
6913
6914arr_val_maybe_end:
6915 /* if incremental parsing stops in the middle of a number, it may continue
6916 with more digits, so arr val maybe didn't end yet */
6918
6919arr_val_end:
6920 save_incr_state(arr_val_end);
6921 if (*cur == ',') {
6922 cur++;
6923 goto arr_val_begin;
6924 }
6925 if (*cur == ']') {
6926 cur++;
6927 goto arr_end;
6928 }
6929 if (char_is_space(*cur)) {
6930 while (char_is_space(*++cur));
6931 goto arr_val_end;
6932 }
6933 goto fail_character_arr_end;
6934
6935arr_end:
6936#if YYJSON_READER_DEPTH_LIMIT
6937 container_depth--;
6938#endif
6939 /* get parent container */
6940 ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
6941
6942 /* save the next sibling value offset */
6943 ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
6944 ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
6945 if (unlikely(ctn == ctn_parent)) goto doc_end;
6946
6947 /* pop parent as current container */
6948 ctn = ctn_parent;
6949 ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
6950 if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
6951 goto obj_val_end;
6952 } else {
6953 goto arr_val_end;
6954 }
6955
6956obj_begin:
6957#if YYJSON_READER_DEPTH_LIMIT
6958 container_depth++;
6959 if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) {
6960 goto fail_depth;
6961 }
6962#endif
6963
6964 /* push container */
6965 ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
6966 (ctn->tag & YYJSON_TAG_MASK);
6967 val_incr();
6968 val->tag = YYJSON_TYPE_OBJ;
6969 /* offset to the parent */
6970 val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
6971 ctn = val;
6972 ctn_len = 0;
6973
6974obj_key_begin:
6975 save_incr_state(obj_key_begin);
6976obj_key_continue:
6977 if (likely(*cur == '"')) {
6978 val_incr();
6979 ctn_len++;
6980 if (likely(read_str_con(&cur, end, flg, val, &msg, con)))
6981 goto obj_key_end;
6982 goto fail_string;
6983 }
6984 if (likely(*cur == '}')) {
6985 cur++;
6986 if (likely(ctn_len == 0)) goto obj_end;
6987 do { cur--; } while (*cur != ',');
6988 goto fail_trailing_comma;
6989 }
6990 if (char_is_space(*cur)) {
6991 while (char_is_space(*++cur));
6992 goto obj_key_continue;
6993 }
6994 goto fail_character_obj_key;
6995
6996obj_key_end:
6997 save_incr_state(obj_key_end);
6998 if (*cur == ':') {
6999 cur++;
7000 goto obj_val_begin;
7001 }
7002 if (char_is_space(*cur)) {
7003 while (char_is_space(*++cur));
7004 goto obj_key_end;
7005 }
7006 goto fail_character_obj_sep;
7007
7008obj_val_begin:
7009 save_incr_state(obj_val_begin);
7010obj_val_continue:
7011 if (*cur == '"') {
7012 val++;
7013 ctn_len++;
7014 if (likely(read_str_con(&cur, end, flg, val, &msg, con)))
7015 goto obj_val_end;
7016 goto fail_string;
7017 }
7018 if (char_is_num(*cur)) {
7019 val++;
7020 ctn_len++;
7021 if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_maybe_end;
7022 goto fail_number;
7023 }
7024 if (*cur == '{') {
7025 cur++;
7026 goto obj_begin;
7027 }
7028 if (*cur == '[') {
7029 cur++;
7030 goto arr_begin;
7031 }
7032 if (*cur == 't') {
7033 val++;
7034 ctn_len++;
7035 if (likely(read_true(&cur, val))) goto obj_val_end;
7036 goto fail_literal_true;
7037 }
7038 if (*cur == 'f') {
7039 val++;
7040 ctn_len++;
7041 if (likely(read_false(&cur, val))) goto obj_val_end;
7042 goto fail_literal_false;
7043 }
7044 if (*cur == 'n') {
7045 val++;
7046 ctn_len++;
7047 if (likely(read_null(&cur, val))) goto obj_val_end;
7048 goto fail_literal_null;
7049 }
7050 if (char_is_space(*cur)) {
7051 while (char_is_space(*++cur));
7052 goto obj_val_continue;
7053 }
7054 goto fail_character_val;
7055
7056obj_val_maybe_end:
7057 /* if incremental parsing stops in the middle of a number, it may continue
7058 with more digits, so obj val maybe didn't end yet */
7060
7061obj_val_end:
7062 save_incr_state(obj_val_end);
7063 if (likely(*cur == ',')) {
7064 cur++;
7065 goto obj_key_begin;
7066 }
7067 if (likely(*cur == '}')) {
7068 cur++;
7069 goto obj_end;
7070 }
7071 if (char_is_space(*cur)) {
7072 while (char_is_space(*++cur));
7073 goto obj_val_end;
7074 }
7075 goto fail_character_obj_end;
7076
7077obj_end:
7078#if YYJSON_READER_DEPTH_LIMIT
7079 container_depth--;
7080#endif
7081
7082 /* pop container */
7083 ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
7084 /* point to the next value */
7085 ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
7086 ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
7087 if (unlikely(ctn == ctn_parent)) goto doc_end;
7088 ctn = ctn_parent;
7089 ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
7090 if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
7091 goto obj_val_end;
7092 } else {
7093 goto arr_val_end;
7094 }
7095
7096doc_end:
7097 /* check invalid contents after json document */
7098 if (unlikely(cur < end || len < state->buf_len) &&
7099 !has_flg(STOP_WHEN_DONE)) {
7100 save_incr_state(doc_end);
7101 while (char_is_space(*cur)) cur++;
7102 if (unlikely(cur < end)) goto fail_garbage;
7103 /* the document is complete for the bytes seen so far, but more input
7104 is still pending; it may hold trailing content that has to be
7105 rejected, so request the remaining data before finalizing */
7106 if (unlikely(len < state->buf_len)) goto unexpected_end;
7107 }
7108
7109 **pre = '\0';
7110 doc = (yyjson_doc *)val_hdr;
7111 doc->root = val_hdr + hdr_len;
7112 doc->alc = alc;
7113 doc->dat_read = (usize)(cur - hdr);
7114 doc->val_read = (usize)((val - doc->root) + 1);
7115 doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
7116 state->hdr = NULL;
7117 state->val_hdr = NULL;
7118 memset(err, 0, sizeof(yyjson_read_err));
7119 return doc;
7120
7121unexpected_end:
7122 err->pos = len;
7123 /* if no more data, stop the incr read */
7124 if (unlikely(len >= state->buf_len)) {
7126 err->msg = MSG_NOT_END;
7127 return NULL;
7128 }
7129 /* save parser state in extended error struct, in addition to what was
7130 * stored in the last save_incr_state */
7132 err->msg = "need more data";
7133 state->val_end = val_end;
7134 state->ctn = ctn;
7135 state->alc_len = alc_len;
7136 /* restore the end where we've inserted a null terminator */
7137 *end = saved_end;
7138 return NULL;
7139
7140fail_string: return_err(cur, INVALID_STRING, msg);
7141fail_number: return_err(cur, INVALID_NUMBER, msg);
7142fail_alloc: return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
7143fail_trailing_comma: return_err(cur, JSON_STRUCTURE, MSG_COMMA);
7144fail_literal_true: return_err(cur, LITERAL, MSG_CHAR_T);
7145fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F);
7146fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N);
7147fail_character_val: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
7148fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END);
7149fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY);
7150fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
7151fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
7152fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
7153fail_depth: return_err(cur, DEPTH, MSG_DEPTH);
7154
7155#undef val_incr
7156#undef return_err
7157#undef return_err_inv_param
7158#undef save_incr_state
7159#undef check_maybe_truncated_number
7160}
7161
7162#endif /* YYJSON_DISABLE_INCR_READER */
7163
7164#undef has_flg
7165#undef has_allow
7166#endif /* YYJSON_DISABLE_READER */
7167
7168
7169
7170#if !YYJSON_DISABLE_WRITER /* writer begin */
7171
7172/* Check write flag, avoids `always false` warning when disabled. */
7173#define has_flg(_flg) unlikely(has_wflag(flg, YYJSON_WRITE_##_flg, 0))
7174#define has_allow(_flg) unlikely(has_wflag(flg, YYJSON_WRITE_ALLOW_##_flg, 1))
7176 bool non_standard) {
7177#if YYJSON_DISABLE_NON_STANDARD
7178 if (non_standard) return false;
7179#endif
7180 return (flg & chk) != 0;
7181}
7182
7183/*==============================================================================
7184 * MARK: - Integer Writer (Private)
7185 *
7186 * The maximum value of uint32_t is 4294967295 (10 digits),
7187 * these digits are named as 'aabbccddee' here.
7188 *
7189 * Although most compilers may convert the "division by constant value" into
7190 * "multiply and shift", manual conversion can still help some compilers
7191 * generate fewer and better instructions.
7192 *
7193 * Reference:
7194 * Division by Invariant Integers using Multiplication, 1994.
7195 * https://gmplib.org/~tege/divcnst-pldi94.pdf
7196 * Improved division by invariant integers, 2011.
7197 * https://gmplib.org/~tege/division-paper.pdf
7198 *============================================================================*/
7199
7200/** Digit table from 00 to 99. */
7202static const char digit_table[200] = {
7203 '0', '0', '0', '1', '0', '2', '0', '3', '0', '4',
7204 '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
7205 '1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
7206 '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
7207 '2', '0', '2', '1', '2', '2', '2', '3', '2', '4',
7208 '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
7209 '3', '0', '3', '1', '3', '2', '3', '3', '3', '4',
7210 '3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
7211 '4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
7212 '4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
7213 '5', '0', '5', '1', '5', '2', '5', '3', '5', '4',
7214 '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
7215 '6', '0', '6', '1', '6', '2', '6', '3', '6', '4',
7216 '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
7217 '7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
7218 '7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
7219 '8', '0', '8', '1', '8', '2', '8', '3', '8', '4',
7220 '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
7221 '9', '0', '9', '1', '9', '2', '9', '3', '9', '4',
7222 '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'
7223};
7224
7226 u32 aa, bb, cc, dd, aabb, ccdd; /* 8 digits: aabbccdd */
7227 aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
7228 ccdd = val - aabb * 10000; /* (val % 10000) */
7229 aa = (aabb * 5243) >> 19; /* (aabb / 100) */
7230 cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */
7231 bb = aabb - aa * 100; /* (aabb % 100) */
7232 dd = ccdd - cc * 100; /* (ccdd % 100) */
7233 byte_copy_2(buf + 0, digit_table + aa * 2);
7234 byte_copy_2(buf + 2, digit_table + bb * 2);
7235 byte_copy_2(buf + 4, digit_table + cc * 2);
7236 byte_copy_2(buf + 6, digit_table + dd * 2);
7237 return buf + 8;
7238}
7239
7241 u32 aa, bb; /* 4 digits: aabb */
7242 aa = (val * 5243) >> 19; /* (val / 100) */
7243 bb = val - aa * 100; /* (val % 100) */
7244 byte_copy_2(buf + 0, digit_table + aa * 2);
7245 byte_copy_2(buf + 2, digit_table + bb * 2);
7246 return buf + 4;
7247}
7248
7250 u32 aa, bb, cc, dd, aabb, bbcc, ccdd, lz;
7251
7252 if (val < 100) { /* 1-2 digits: aa */
7253 lz = val < 10; /* leading zero: 0 or 1 */
7254 byte_copy_2(buf + 0, digit_table + val * 2 + lz);
7255 buf -= lz;
7256 return buf + 2;
7257
7258 } else if (val < 10000) { /* 3-4 digits: aabb */
7259 aa = (val * 5243) >> 19; /* (val / 100) */
7260 bb = val - aa * 100; /* (val % 100) */
7261 lz = aa < 10; /* leading zero: 0 or 1 */
7262 byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7263 buf -= lz;
7264 byte_copy_2(buf + 2, digit_table + bb * 2);
7265 return buf + 4;
7266
7267 } else if (val < 1000000) { /* 5-6 digits: aabbcc */
7268 aa = (u32)(((u64)val * 429497) >> 32); /* (val / 10000) */
7269 bbcc = val - aa * 10000; /* (val % 10000) */
7270 bb = (bbcc * 5243) >> 19; /* (bbcc / 100) */
7271 cc = bbcc - bb * 100; /* (bbcc % 100) */
7272 lz = aa < 10; /* leading zero: 0 or 1 */
7273 byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7274 buf -= lz;
7275 byte_copy_2(buf + 2, digit_table + bb * 2);
7276 byte_copy_2(buf + 4, digit_table + cc * 2);
7277 return buf + 6;
7278
7279 } else { /* 7-8 digits: aabbccdd */
7280 aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
7281 ccdd = val - aabb * 10000; /* (val % 10000) */
7282 aa = (aabb * 5243) >> 19; /* (aabb / 100) */
7283 cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */
7284 bb = aabb - aa * 100; /* (aabb % 100) */
7285 dd = ccdd - cc * 100; /* (ccdd % 100) */
7286 lz = aa < 10; /* leading zero: 0 or 1 */
7287 byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7288 buf -= lz;
7289 byte_copy_2(buf + 2, digit_table + bb * 2);
7290 byte_copy_2(buf + 4, digit_table + cc * 2);
7291 byte_copy_2(buf + 6, digit_table + dd * 2);
7292 return buf + 8;
7293 }
7294}
7295
7297 u32 aa, bb, cc, dd, aabb, bbcc, ccdd, lz;
7298
7299 if (val < 1000000) { /* 5-6 digits: aabbcc */
7300 aa = (u32)(((u64)val * 429497) >> 32); /* (val / 10000) */
7301 bbcc = val - aa * 10000; /* (val % 10000) */
7302 bb = (bbcc * 5243) >> 19; /* (bbcc / 100) */
7303 cc = bbcc - bb * 100; /* (bbcc % 100) */
7304 lz = aa < 10; /* leading zero: 0 or 1 */
7305 byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7306 buf -= lz;
7307 byte_copy_2(buf + 2, digit_table + bb * 2);
7308 byte_copy_2(buf + 4, digit_table + cc * 2);
7309 return buf + 6;
7310
7311 } else { /* 7-8 digits: aabbccdd */
7312 aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
7313 ccdd = val - aabb * 10000; /* (val % 10000) */
7314 aa = (aabb * 5243) >> 19; /* (aabb / 100) */
7315 cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */
7316 bb = aabb - aa * 100; /* (aabb % 100) */
7317 dd = ccdd - cc * 100; /* (ccdd % 100) */
7318 lz = aa < 10; /* leading zero: 0 or 1 */
7319 byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
7320 buf -= lz;
7321 byte_copy_2(buf + 2, digit_table + bb * 2);
7322 byte_copy_2(buf + 4, digit_table + cc * 2);
7323 byte_copy_2(buf + 6, digit_table + dd * 2);
7324 return buf + 8;
7325 }
7326}
7327
7329 u64 tmp, hgh;
7330 u32 mid, low;
7331
7332 if (val < 100000000) { /* 1-8 digits */
7333 buf = write_u32_len_1_to_8((u32)val, buf);
7334 return buf;
7335
7336 } else if (val < (u64)100000000 * 100000000) { /* 9-16 digits */
7337 hgh = val / 100000000; /* (val / 100000000) */
7338 low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
7339 buf = write_u32_len_1_to_8((u32)hgh, buf);
7340 buf = write_u32_len_8(low, buf);
7341 return buf;
7342
7343 } else { /* 17-20 digits */
7344 tmp = val / 100000000; /* (val / 100000000) */
7345 low = (u32)(val - tmp * 100000000); /* (val % 100000000) */
7346 hgh = (u32)(tmp / 10000); /* (tmp / 10000) */
7347 mid = (u32)(tmp - hgh * 10000); /* (tmp % 10000) */
7348 buf = write_u32_len_5_to_8((u32)hgh, buf);
7349 buf = write_u32_len_4(mid, buf);
7350 buf = write_u32_len_8(low, buf);
7351 return buf;
7352 }
7353}
7354
7355
7356
7357/*==============================================================================
7358 * MARK: - Number Writer (Private)
7359 *============================================================================*/
7360
7361#if !YYJSON_DISABLE_FAST_FP_CONV /* FP_WRITER */
7362
7363/** Trailing zero count table for number 0 to 99.
7364 (generated with misc/make_tables.c) */
7365static const u8 dec_trailing_zero_table[] = {
7366 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7367 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7368 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7369 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7370 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7371 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7372 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7373 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7374 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7375 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
7376};
7377
7378static_inline u8 *write_u64_len_1_to_16(u64 val, u8 *buf) {
7379 u64 hgh;
7380 u32 low;
7381 if (val < 100000000) { /* 1-8 digits */
7382 buf = write_u32_len_1_to_8((u32)val, buf);
7383 return buf;
7384 } else { /* 9-16 digits */
7385 hgh = val / 100000000; /* (val / 100000000) */
7386 low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
7387 buf = write_u32_len_1_to_8((u32)hgh, buf);
7388 buf = write_u32_len_8(low, buf);
7389 return buf;
7390 }
7391}
7392
7393static_inline u8 *write_u64_len_1_to_17(u64 val, u8 *buf) {
7394 u64 hgh;
7395 u32 mid, low, one;
7396 if (val >= (u64)100000000 * 10000000) { /* len: 16 to 17 */
7397 hgh = val / 100000000; /* (val / 100000000) */
7398 low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
7399 one = (u32)(hgh / 100000000); /* (hgh / 100000000) */
7400 mid = (u32)(hgh - (u64)one * 100000000); /* (hgh % 100000000) */
7401 *buf = (u8)((u8)one + (u8)'0');
7402 buf += one > 0;
7403 buf = write_u32_len_8(mid, buf);
7404 buf = write_u32_len_8(low, buf);
7405 return buf;
7406 } else if (val >= (u64)100000000){ /* len: 9 to 15 */
7407 hgh = val / 100000000; /* (val / 100000000) */
7408 low = (u32)(val - hgh * 100000000); /* (val % 100000000) */
7409 buf = write_u32_len_1_to_8((u32)hgh, buf);
7410 buf = write_u32_len_8(low, buf);
7411 return buf;
7412 } else { /* len: 1 to 8 */
7413 buf = write_u32_len_1_to_8((u32)val, buf);
7414 return buf;
7415 }
7416}
7417
7418/**
7419 Write an unsigned integer with a length of 7 to 9 with trailing zero trimmed.
7420 These digits are named as "abbccddee" here.
7421 For example, input 123456000, output "123456".
7422 */
7423static_inline u8 *write_u32_len_7_to_9_trim(u32 val, u8 *buf) {
7424 bool lz;
7425 u32 tz, tz1, tz2;
7426
7427 u32 abbcc = val / 10000; /* (abbccddee / 10000) */
7428 u32 ddee = val - abbcc * 10000; /* (abbccddee % 10000) */
7429 u32 abb = (u32)(((u64)abbcc * 167773) >> 24); /* (abbcc / 100) */
7430 u32 a = (abb * 41) >> 12; /* (abb / 100) */
7431 u32 bb = abb - a * 100; /* (abb % 100) */
7432 u32 cc = abbcc - abb * 100; /* (abbcc % 100) */
7433
7434 /* write abbcc */
7435 buf[0] = (u8)(a + '0');
7436 buf += a > 0;
7437 lz = bb < 10 && a == 0;
7438 byte_copy_2(buf + 0, digit_table + bb * 2 + lz);
7439 buf -= lz;
7440 byte_copy_2(buf + 2, digit_table + cc * 2);
7441
7442 if (ddee) {
7443 u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */
7444 u32 ee = ddee - dd * 100; /* (ddee % 100) */
7445 byte_copy_2(buf + 4, digit_table + dd * 2);
7446 byte_copy_2(buf + 6, digit_table + ee * 2);
7447 tz1 = dec_trailing_zero_table[dd];
7448 tz2 = dec_trailing_zero_table[ee];
7449 tz = ee ? tz2 : (tz1 + 2);
7450 buf += 8 - tz;
7451 return buf;
7452 } else {
7453 tz1 = dec_trailing_zero_table[bb];
7454 tz2 = dec_trailing_zero_table[cc];
7455 tz = cc ? tz2 : (tz1 + tz2);
7456 buf += 4 - tz;
7457 return buf;
7458 }
7459}
7460
7461/**
7462 Write an unsigned integer with a length of 16 or 17 with trailing zero trimmed.
7463 These digits are named as "abbccddeeffgghhii" here.
7464 For example, input 1234567890123000, output "1234567890123".
7465 */
7466static_inline u8 *write_u64_len_16_to_17_trim(u64 val, u8 *buf) {
7467 u32 tz, tz1, tz2;
7468
7469 u32 abbccddee = (u32)(val / 100000000);
7470 u32 ffgghhii = (u32)(val - (u64)abbccddee * 100000000);
7471 u32 abbcc = abbccddee / 10000;
7472 u32 ddee = abbccddee - abbcc * 10000;
7473 u32 abb = (u32)(((u64)abbcc * 167773) >> 24); /* (abbcc / 100) */
7474 u32 a = (abb * 41) >> 12; /* (abb / 100) */
7475 u32 bb = abb - a * 100; /* (abb % 100) */
7476 u32 cc = abbcc - abb * 100; /* (abbcc % 100) */
7477 buf[0] = (u8)(a + '0');
7478 buf += a > 0;
7479 byte_copy_2(buf + 0, digit_table + bb * 2);
7480 byte_copy_2(buf + 2, digit_table + cc * 2);
7481
7482 if (ffgghhii) {
7483 u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */
7484 u32 ee = ddee - dd * 100; /* (ddee % 100) */
7485 u32 ffgg = (u32)(((u64)ffgghhii * 109951163) >> 40); /* (val / 10000) */
7486 u32 hhii = ffgghhii - ffgg * 10000; /* (val % 10000) */
7487 u32 ff = (ffgg * 5243) >> 19; /* (aabb / 100) */
7488 u32 gg = ffgg - ff * 100; /* (aabb % 100) */
7489 byte_copy_2(buf + 4, digit_table + dd * 2);
7490 byte_copy_2(buf + 6, digit_table + ee * 2);
7491 byte_copy_2(buf + 8, digit_table + ff * 2);
7492 byte_copy_2(buf + 10, digit_table + gg * 2);
7493 if (hhii) {
7494 u32 hh = (hhii * 5243) >> 19; /* (ccdd / 100) */
7495 u32 ii = hhii - hh * 100; /* (ccdd % 100) */
7496 byte_copy_2(buf + 12, digit_table + hh * 2);
7497 byte_copy_2(buf + 14, digit_table + ii * 2);
7498 tz1 = dec_trailing_zero_table[hh];
7499 tz2 = dec_trailing_zero_table[ii];
7500 tz = ii ? tz2 : (tz1 + 2);
7501 return buf + 16 - tz;
7502 } else {
7503 tz1 = dec_trailing_zero_table[ff];
7504 tz2 = dec_trailing_zero_table[gg];
7505 tz = gg ? tz2 : (tz1 + 2);
7506 return buf + 12 - tz;
7507 }
7508 } else {
7509 if (ddee) {
7510 u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */
7511 u32 ee = ddee - dd * 100; /* (ddee % 100) */
7512 byte_copy_2(buf + 4, digit_table + dd * 2);
7513 byte_copy_2(buf + 6, digit_table + ee * 2);
7514 tz1 = dec_trailing_zero_table[dd];
7515 tz2 = dec_trailing_zero_table[ee];
7516 tz = ee ? tz2 : (tz1 + 2);
7517 return buf + 8 - tz;
7518 } else {
7519 tz1 = dec_trailing_zero_table[bb];
7520 tz2 = dec_trailing_zero_table[cc];
7521 tz = cc ? tz2 : (tz1 + tz2);
7522 return buf + 4 - tz;
7523 }
7524 }
7525}
7526
7527/** Write exponent part in range `e-45` to `e38`. */
7528static_inline u8 *write_f32_exp(i32 exp, u8 *buf) {
7529 bool lz;
7530 byte_copy_2(buf, "e-");
7531 buf += 2 - (exp >= 0);
7532 exp = exp < 0 ? -exp : exp;
7533 lz = exp < 10;
7534 byte_copy_2(buf + 0, digit_table + (u32)exp * 2 + lz);
7535 return buf + 2 - lz;
7536}
7537
7538/** Write exponent part in range `e-324` to `e308`. */
7539static_inline u8 *write_f64_exp(i32 exp, u8 *buf) {
7540 byte_copy_2(buf, "e-");
7541 buf += 2 - (exp >= 0);
7542 exp = exp < 0 ? -exp : exp;
7543 if (exp < 100) {
7544 bool lz = exp < 10;
7545 byte_copy_2(buf + 0, digit_table + (u32)exp * 2 + lz);
7546 return buf + 2 - lz;
7547 } else {
7548 u32 hi = ((u32)exp * 656) >> 16; /* exp / 100 */
7549 u32 lo = (u32)exp - hi * 100; /* exp % 100 */
7550 buf[0] = (u8)((u8)hi + (u8)'0');
7551 byte_copy_2(buf + 1, digit_table + lo * 2);
7552 return buf + 3;
7553 }
7554}
7555
7556/** Magic number for fast `divide by power of 10`. */
7557typedef struct {
7558 u64 p10, mul;
7559 u32 shr1, shr2;
7560} div_pow10_magic;
7561
7562/** Generated with llvm, see https://github.com/llvm/llvm-project/
7563 blob/main/llvm/lib/Support/DivisionByConstantInfo.cpp */
7564static const div_pow10_magic div_pow10_table[] = {
7565 { U64(0x00000000, 0x00000001), U64(0x00000000, 0x00000000), 0, 0 },
7566 { U64(0x00000000, 0x0000000A), U64(0xCCCCCCCC, 0xCCCCCCCD), 0, 3 },
7567 { U64(0x00000000, 0x00000064), U64(0x28F5C28F, 0x5C28F5C3), 2, 2 },
7568 { U64(0x00000000, 0x000003E8), U64(0x20C49BA5, 0xE353F7CF), 3, 4 },
7569 { U64(0x00000000, 0x00002710), U64(0x346DC5D6, 0x3886594B), 0, 11 },
7570 { U64(0x00000000, 0x000186A0), U64(0x0A7C5AC4, 0x71B47843), 5, 7 },
7571 { U64(0x00000000, 0x000F4240), U64(0x431BDE82, 0xD7B634DB), 0, 18 },
7572 { U64(0x00000000, 0x00989680), U64(0xD6BF94D5, 0xE57A42BD), 0, 23 },
7573 { U64(0x00000000, 0x05F5E100), U64(0xABCC7711, 0x8461CEFD), 0, 26 },
7574 { U64(0x00000000, 0x3B9ACA00), U64(0x0044B82F, 0xA09B5A53), 9, 11 },
7575 { U64(0x00000002, 0x540BE400), U64(0xDBE6FECE, 0xBDEDD5BF), 0, 33 },
7576 { U64(0x00000017, 0x4876E800), U64(0xAFEBFF0B, 0xCB24AAFF), 0, 36 },
7577 { U64(0x000000E8, 0xD4A51000), U64(0x232F3302, 0x5BD42233), 0, 37 },
7578 { U64(0x00000918, 0x4E72A000), U64(0x384B84D0, 0x92ED0385), 0, 41 },
7579 { U64(0x00005AF3, 0x107A4000), U64(0x0B424DC3, 0x5095CD81), 0, 42 },
7580 { U64(0x00038D7E, 0xA4C68000), U64(0x00024075, 0xF3DCEAC3), 15, 20 },
7581 { U64(0x002386F2, 0x6FC10000), U64(0x39A5652F, 0xB1137857), 0, 51 },
7582 { U64(0x01634578, 0x5D8A0000), U64(0x00005C3B, 0xD5191B53), 17, 22 },
7583 { U64(0x0DE0B6B3, 0xA7640000), U64(0x000049C9, 0x7747490F), 18, 24 },
7584 { U64(0x8AC72304, 0x89E80000), U64(0x760F253E, 0xDB4AB0d3), 0, 62 },
7585};
7586
7587/** Divide a number by power of 10. */
7588static_inline void div_pow10(u64 num, u32 exp, u64 *div, u64 *mod, u64 *p10) {
7589 u64 hi, lo;
7590 div_pow10_magic m = div_pow10_table[exp];
7591 u128_mul(num >> m.shr1, m.mul, &hi, &lo);
7592 *div = hi >> m.shr2;
7593 *mod = num - (*div * m.p10);
7594 *p10 = m.p10;
7595}
7596
7597/** Multiplies 64-bit integer and returns highest 64-bit rounded value. */
7598static_inline u32 u64_round_to_odd(u64 u, u32 cp) {
7599 u64 hi, lo;
7600 u32 y_hi, y_lo;
7601 u128_mul(cp, u, &hi, &lo);
7602 y_hi = (u32)hi;
7603 y_lo = (u32)(lo >> 32);
7604 return y_hi | (y_lo > 1);
7605}
7606
7607/** Multiplies 128-bit integer and returns highest 64-bit rounded value. */
7608static_inline u64 u128_round_to_odd(u64 hi, u64 lo, u64 cp) {
7609 u64 x_hi, x_lo, y_hi, y_lo;
7610 u128_mul(cp, lo, &x_hi, &x_lo);
7611 u128_mul_add(cp, hi, x_hi, &y_hi, &y_lo);
7612 return y_hi | (y_lo > 1);
7613}
7614
7615/** Convert f32 from binary to decimal (shortest but may have trailing zeros).
7616 The input should not be 0, inf or nan. */
7617static_inline void f32_bin_to_dec(u32 sig_raw, u32 exp_raw,
7618 u32 sig_bin, i32 exp_bin,
7619 u32 *sig_dec, i32 *exp_dec) {
7620
7621 bool is_even, irregular, round_up, trim;
7622 bool u0_inside, u1_inside, w0_inside, w1_inside;
7623 u64 p10_hi, p10_lo, hi, lo;
7624 u32 s, sp, cb, cbl, cbr, vb, vbl, vbr, upper, lower, mid;
7625 i32 k, h;
7626
7627 /* Fast path, see f64_bin_to_dec(). */
7628 while (likely(sig_raw)) {
7629 u32 mod, dec, add_1, add_10, s_hi, s_lo;
7630 u32 c, half_ulp, t0, t1;
7631
7632 /* k = floor(exp_bin * log10(2)); */
7633 /* h = exp_bin + floor(log2(10) * -k); (h = 0/1/2/3) */
7634 k = (i32)(exp_bin * 315653) >> 20;
7635 h = exp_bin + ((-k * 217707) >> 16);
7636 pow10_table_get_sig(-k, &p10_hi, &p10_lo);
7637
7638 /* sig_bin << (1/2/3/4) */
7639 cb = sig_bin << (h + 1);
7640 u128_mul(cb, p10_hi, &hi, &lo);
7641 s_hi = (u32)(hi);
7642 s_lo = (u32)(lo >> 32);
7643 mod = s_hi % 10;
7644 dec = s_hi - mod;
7645
7646 /* right shift 4 to fit in u32 */
7647 c = (mod << (32 - 4)) | (s_lo >> 4);
7648 half_ulp = (u32)(p10_hi >> (32 + 4 - h));
7649
7650 /* check w1, u0, w0 range */
7651 w1_inside = (s_lo >= ((u32)1 << 31));
7652 if (unlikely(s_lo == ((u32)1 << 31))) break;
7653 u0_inside = (half_ulp >= c);
7654 if (unlikely(half_ulp == c)) break;
7655 t0 = (u32)10 << (32 - 4);
7656 t1 = c + half_ulp;
7657 w0_inside = (t1 >= t0);
7658 if (unlikely(t0 - t1 <= (u32)1)) break;
7659
7660 trim = (u0_inside | w0_inside);
7661 add_10 = (w0_inside ? 10 : 0);
7662 add_1 = mod + w1_inside;
7663 *sig_dec = dec + (trim ? add_10 : add_1);
7664 *exp_dec = k;
7665 return;
7666 }
7667
7668 /* Schubfach algorithm, see f64_bin_to_dec(). */
7669 irregular = (sig_raw == 0 && exp_raw > 1);
7670 is_even = !(sig_bin & 1);
7671 cbl = 4 * sig_bin - 2 + irregular;
7672 cb = 4 * sig_bin;
7673 cbr = 4 * sig_bin + 2;
7674
7675 /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */
7676 /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */
7677 k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20;
7678 h = exp_bin + ((-k * 217707) >> 16) + 1;
7679 pow10_table_get_sig(-k, &p10_hi, &p10_lo);
7680 p10_hi += 1;
7681
7682 vbl = u64_round_to_odd(p10_hi, cbl << h);
7683 vb = u64_round_to_odd(p10_hi, cb << h);
7684 vbr = u64_round_to_odd(p10_hi, cbr << h);
7685 lower = vbl + !is_even;
7686 upper = vbr - !is_even;
7687
7688 s = vb / 4;
7689 if (s >= 10) {
7690 sp = s / 10;
7691 u0_inside = (lower <= 40 * sp);
7692 w0_inside = (upper >= 40 * sp + 40);
7693 if (u0_inside != w0_inside) {
7694 *sig_dec = sp * 10 + (w0_inside ? 10 : 0);
7695 *exp_dec = k;
7696 return;
7697 }
7698 }
7699 u1_inside = (lower <= 4 * s);
7700 w1_inside = (upper >= 4 * s + 4);
7701 mid = 4 * s + 2;
7702 round_up = (vb > mid) || (vb == mid && (s & 1) != 0);
7703 *sig_dec = s + ((u1_inside != w1_inside) ? w1_inside : round_up);
7704 *exp_dec = k;
7705}
7706
7707/** Convert f64 from binary to decimal (shortest but may have trailing zeros).
7708 The input should not be 0, inf or nan. */
7709static_inline void f64_bin_to_dec(u64 sig_raw, u32 exp_raw,
7710 u64 sig_bin, i32 exp_bin,
7711 u64 *sig_dec, i32 *exp_dec) {
7712
7713 bool is_even, irregular, round_up, trim;
7714 bool u0_inside, u1_inside, w0_inside, w1_inside;
7715 u64 s, sp, cb, cbl, cbr, vb, vbl, vbr, p10_hi, p10_lo, upper, lower, mid;
7716 i32 k, h;
7717
7718 /*
7719 Fast path:
7720 For regular spacing significand 'c', there are 4 candidates:
7721
7722 u0 u1 c w1 w0
7723 ----|----|----|----|----|-*--|----|----|----|----|----|----|----|----
7724 9 0 1 2 3 4 5 6 7 8 9 0 1
7725 |___________________|___________________|
7726 1ulp
7727
7728 The `1ulp` is in the range [1.0, 10.0).
7729 If (c - 0.5ulp < u0), trim the last digit and round down.
7730 If (c + 0.5ulp > w0), trim the last digit and round up.
7731 If (c - 0.5ulp < u1), round down.
7732 If (c + 0.5ulp > w1), round up.
7733 */
7734 while (likely(sig_raw)) {
7735 u64 mod, dec, add_1, add_10, s_hi, s_lo;
7736 u64 c, half_ulp, t0, t1;
7737
7738 /* k = floor(exp_bin * log10(2)); */
7739 /* h = exp_bin + floor(log2(10) * -k); (h = 0/1/2/3) */
7740 k = (i32)(exp_bin * 315653) >> 20;
7741 h = exp_bin + ((-k * 217707) >> 16);
7742 pow10_table_get_sig(-k, &p10_hi, &p10_lo);
7743
7744 /* sig_bin << (1/2/3/4) */
7745 cb = sig_bin << (h + 1);
7746 u128_mul(cb, p10_lo, &s_hi, &s_lo);
7747 u128_mul_add(cb, p10_hi, s_hi, &s_hi, &s_lo);
7748 mod = s_hi % 10;
7749 dec = s_hi - mod;
7750
7751 /* right shift 4 to fit in u64 */
7752 c = (mod << (64 - 4)) | (s_lo >> 4);
7753 half_ulp = p10_hi >> (4 - h);
7754
7755 /* check w1, u0, w0 range */
7756 w1_inside = (s_lo >= ((u64)1 << 63));
7757 if (unlikely(s_lo == ((u64)1 << 63))) break;
7758 u0_inside = (half_ulp >= c);
7759 if (unlikely(half_ulp == c)) break;
7760 t0 = ((u64)10 << (64 - 4));
7761 t1 = c + half_ulp;
7762 w0_inside = (t1 >= t0);
7763 if (unlikely(t0 - t1 <= (u64)1)) break;
7764
7765 trim = (u0_inside | w0_inside);
7766 add_10 = (w0_inside ? 10 : 0);
7767 add_1 = mod + w1_inside;
7768 *sig_dec = dec + (trim ? add_10 : add_1);
7769 *exp_dec = k;
7770 return;
7771 }
7772
7773 /*
7774 Schubfach algorithm:
7775 Raffaello Giulietti, The Schubfach way to render doubles, 2022.
7776 https://drive.google.com/file/d/1gp5xv4CAa78SVgCeWfGqqI4FfYYYuNFb (Paper)
7777 https://github.com/openjdk/jdk/pull/3402 (Java implementation)
7778 https://github.com/abolz/Drachennest (C++ implementation)
7779 */
7780 irregular = (sig_raw == 0 && exp_raw > 1);
7781 is_even = !(sig_bin & 1);
7782 cbl = 4 * sig_bin - 2 + irregular;
7783 cb = 4 * sig_bin;
7784 cbr = 4 * sig_bin + 2;
7785
7786 /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */
7787 /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */
7788 k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20;
7789 h = exp_bin + ((-k * 217707) >> 16) + 1;
7790 pow10_table_get_sig(-k, &p10_hi, &p10_lo);
7791 p10_lo += 1;
7792
7793 vbl = u128_round_to_odd(p10_hi, p10_lo, cbl << h);
7794 vb = u128_round_to_odd(p10_hi, p10_lo, cb << h);
7795 vbr = u128_round_to_odd(p10_hi, p10_lo, cbr << h);
7796 lower = vbl + !is_even;
7797 upper = vbr - !is_even;
7798
7799 s = vb / 4;
7800 if (s >= 10) {
7801 sp = s / 10;
7802 u0_inside = (lower <= 40 * sp);
7803 w0_inside = (upper >= 40 * sp + 40);
7804 if (u0_inside != w0_inside) {
7805 *sig_dec = sp * 10 + (w0_inside ? 10 : 0);
7806 *exp_dec = k;
7807 return;
7808 }
7809 }
7810 u1_inside = (lower <= 4 * s);
7811 w1_inside = (upper >= 4 * s + 4);
7812 mid = 4 * s + 2;
7813 round_up = (vb > mid) || (vb == mid && (s & 1) != 0);
7814 *sig_dec = s + ((u1_inside != w1_inside) ? w1_inside : round_up);
7815 *exp_dec = k;
7816}
7817
7818/** Convert f64 from binary to decimal (fast but not the shortest).
7819 The input should not be 0, inf, nan. */
7820static_inline void f64_bin_to_dec_fast(u64 sig_raw, u32 exp_raw,
7821 u64 sig_bin, i32 exp_bin,
7822 u64 *sig_dec, i32 *exp_dec,
7823 bool *round_up) {
7824 u64 cb, p10_hi, p10_lo, s_hi, s_lo;
7825 i32 k, h;
7826 bool irregular, u;
7827
7828 irregular = (sig_raw == 0 && exp_raw > 1);
7829
7830 /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */
7831 /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */
7832 k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20;
7833 h = exp_bin + ((-k * 217707) >> 16);
7834 pow10_table_get_sig(-k, &p10_hi, &p10_lo);
7835
7836 /* sig_bin << (1/2/3/4) */
7837 cb = sig_bin << (h + 1);
7838 u128_mul(cb, p10_lo, &s_hi, &s_lo);
7839 u128_mul_add(cb, p10_hi, s_hi, &s_hi, &s_lo);
7840
7841 /* round up */
7842 u = s_lo >= (irregular ? U64(0x55555555, 0x55555555) : ((u64)1 << 63));
7843
7844 *sig_dec = s_hi + u;
7845 *exp_dec = k;
7846 *round_up = u;
7847 return;
7848}
7849
7850/** Write inf/nan if allowed. */
7851static_inline u8 *write_inf_or_nan(u8 *buf, yyjson_write_flag flg,
7852 u64 sig_raw, bool sign) {
7853 if (has_flg(INF_AND_NAN_AS_NULL)) {
7854 byte_copy_4(buf, "null");
7855 return buf + 4;
7856 }
7857 if (has_allow(INF_AND_NAN)) {
7858 if (sig_raw == 0) {
7859 buf[0] = '-';
7860 buf += sign;
7861 byte_copy_8(buf, "Infinity");
7862 return buf + 8;
7863 } else {
7864 byte_copy_4(buf, "NaN");
7865 return buf + 3;
7866 }
7867 }
7868 return NULL;
7869}
7870
7871/**
7872 Write a float number (requires 40 bytes buffer).
7873 We follow the ECMAScript specification for printing floating-point numbers,
7874 similar to `Number.prototype.toString()`, but with the following changes:
7875 1. Keep the negative sign of `-0.0` to preserve input information.
7876 2. Keep the decimal point to indicate that the number is floating-point.
7877 3. Remove positive sign in the exponent part.
7878 */
7879static_noinline u8 *write_f32_raw(u8 *buf, u64 raw_f64,
7880 yyjson_write_flag flg) {
7881 u32 sig_bin, sig_dec, sig_raw;
7882 i32 exp_bin, exp_dec, sig_len, dot_ofs;
7883 u32 exp_raw, raw;
7884 u8 *end;
7885 bool sign;
7886
7887 /* cast double to float */
7888 raw = f32_to_bits(f64_to_f32(f64_from_bits(raw_f64)));
7889
7890 /* decode raw bytes from IEEE-754 double format. */
7891 sign = (bool)(raw >> (F32_BITS - 1));
7892 sig_raw = raw & F32_SIG_MASK;
7893 exp_raw = (raw & F32_EXP_MASK) >> F32_SIG_BITS;
7894
7895 /* return inf or nan */
7896 if (unlikely(exp_raw == ((u32)1 << F32_EXP_BITS) - 1)) {
7897 return write_inf_or_nan(buf, flg, sig_raw, sign);
7898 }
7899
7900 /* add sign for all finite number */
7901 buf[0] = '-';
7902 buf += sign;
7903
7904 /* return zero */
7905 if ((raw << 1) == 0) {
7906 byte_copy_4(buf, "0.0");
7907 return buf + 3;
7908 }
7909
7910 if (likely(exp_raw != 0)) {
7911 /* normal number */
7912 sig_bin = sig_raw | ((u32)1 << F32_SIG_BITS);
7913 exp_bin = (i32)exp_raw - F32_EXP_BIAS - F32_SIG_BITS;
7914
7915 /* fast path for small integer number without fraction */
7916 if ((-F32_SIG_BITS <= exp_bin && exp_bin <= 0) &&
7917 (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) {
7918 sig_dec = sig_bin >> -exp_bin; /* range: [1, 0xFFFFFF] */
7919 buf = write_u32_len_1_to_8(sig_dec, buf);
7920 byte_copy_2(buf, ".0");
7921 return buf + 2;
7922 }
7923
7924 /* binary to decimal */
7925 f32_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
7926
7927 /* the sig length is 7 or 9 */
7928 sig_len = 7 + (sig_dec >= (u32)10000000) + (sig_dec >= (u32)100000000);
7929
7930 /* the decimal point offset relative to the first digit */
7931 dot_ofs = sig_len + exp_dec;
7932
7933 if (-6 < dot_ofs && dot_ofs <= 21) {
7934 i32 num_sep_pos, dot_set_pos, pre_ofs;
7935 u8 *num_hdr, *num_end, *num_sep, *dot_end;
7936 bool no_pre_zero;
7937
7938 /* fill zeros */
7939 memset(buf, '0', 32);
7940
7941 /* not prefixed with zero, e.g. 1.234, 1234.0 */
7942 no_pre_zero = (dot_ofs > 0);
7943
7944 /* write the number as digits */
7945 pre_ofs = no_pre_zero ? 0 : (2 - dot_ofs);
7946 num_hdr = buf + pre_ofs;
7947 num_end = write_u32_len_7_to_9_trim(sig_dec, num_hdr);
7948
7949 /* separate these digits to leave a space for dot */
7950 num_sep_pos = no_pre_zero ? dot_ofs : 0;
7951 num_sep = num_hdr + num_sep_pos;
7952 byte_move_8(num_sep + no_pre_zero, num_sep);
7953 num_end += no_pre_zero;
7954
7955 /* write the dot */
7956 dot_set_pos = yyjson_max(dot_ofs, 1);
7957 buf[dot_set_pos] = '.';
7958
7959 /* return the ending */
7960 dot_end = buf + dot_ofs + 2;
7961 return yyjson_max(dot_end, num_end);
7962
7963 } else {
7964 /* write with scientific notation, e.g. 1.234e56 */
7965 end = write_u32_len_7_to_9_trim(sig_dec, buf + 1);
7966 end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */
7967 exp_dec += sig_len - 1;
7968 buf[0] = buf[1];
7969 buf[1] = '.';
7970 return write_f32_exp(exp_dec, end);
7971 }
7972
7973 } else {
7974 /* subnormal number */
7975 sig_bin = sig_raw;
7976 exp_bin = 1 - F32_EXP_BIAS - F32_SIG_BITS;
7977
7978 /* binary to decimal */
7979 f32_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
7980
7981 /* write significand part */
7982 end = write_u32_len_1_to_8(sig_dec, buf + 1);
7983 buf[0] = buf[1];
7984 buf[1] = '.';
7985 exp_dec += (i32)(end - buf) - 2;
7986
7987 /* trim trailing zeros */
7988 end -= *(end - 1) == '0'; /* branchless for last zero */
7989 end -= *(end - 1) == '0'; /* branchless for second last zero */
7990 while (*(end - 1) == '0') end--; /* for unlikely more zeros */
7991 end -= *(end - 1) == '.'; /* remove dot, e.g. 2.e-321 -> 2e-321 */
7992
7993 /* write exponent part */
7994 return write_f32_exp(exp_dec, end);
7995 }
7996}
7997
7998/**
7999 Write a double number (requires 40 bytes buffer).
8000 We follow the ECMAScript specification for printing floating-point numbers,
8001 similar to `Number.prototype.toString()`, but with the following changes:
8002 1. Keep the negative sign of `-0.0` to preserve input information.
8003 2. Keep the decimal point to indicate that the number is floating-point.
8004 3. Remove positive sign in the exponent part.
8005 */
8007 u64 sig_bin, sig_dec, sig_raw;
8008 i32 exp_bin, exp_dec, sig_len, dot_ofs;
8009 u32 exp_raw;
8010 u8 *end;
8011 bool sign;
8012
8013 /* decode raw bytes from IEEE-754 double format. */
8014 sign = (bool)(raw >> (F64_BITS - 1));
8015 sig_raw = raw & F64_SIG_MASK;
8016 exp_raw = (u32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
8017
8018 /* return inf or nan */
8019 if (unlikely(exp_raw == ((u32)1 << F64_EXP_BITS) - 1)) {
8020 return write_inf_or_nan(buf, flg, sig_raw, sign);
8021 }
8022
8023 /* add sign for all finite number */
8024 buf[0] = '-';
8025 buf += sign;
8026
8027 /* return zero */
8028 if ((raw << 1) == 0) {
8029 byte_copy_4(buf, "0.0");
8030 return buf + 3;
8031 }
8032
8033 if (likely(exp_raw != 0)) {
8034 /* normal number */
8035 sig_bin = sig_raw | ((u64)1 << F64_SIG_BITS);
8036 exp_bin = (i32)exp_raw - F64_EXP_BIAS - F64_SIG_BITS;
8037
8038 /* fast path for small integer number without fraction */
8039 if ((-F64_SIG_BITS <= exp_bin && exp_bin <= 0) &&
8040 (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) {
8041 sig_dec = sig_bin >> -exp_bin; /* range: [1, 0x1FFFFFFFFFFFFF] */
8042 buf = write_u64_len_1_to_16(sig_dec, buf);
8043 byte_copy_2(buf, ".0");
8044 return buf + 2;
8045 }
8046
8047 /* binary to decimal */
8048 f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
8049
8050 /* the sig length is 16 or 17 */
8051 sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
8052
8053 /* the decimal point offset relative to the first digit */
8054 dot_ofs = sig_len + exp_dec;
8055
8056 if (-6 < dot_ofs && dot_ofs <= 21) {
8057 i32 num_sep_pos, dot_set_pos, pre_ofs;
8058 u8 *num_hdr, *num_end, *num_sep, *dot_end;
8059 bool no_pre_zero;
8060
8061 /* fill zeros */
8062 memset(buf, '0', 32);
8063
8064 /* not prefixed with zero, e.g. 1.234, 1234.0 */
8065 no_pre_zero = (dot_ofs > 0);
8066
8067 /* write the number as digits */
8068 pre_ofs = no_pre_zero ? 0 : (2 - dot_ofs);
8069 num_hdr = buf + pre_ofs;
8070 num_end = write_u64_len_16_to_17_trim(sig_dec, num_hdr);
8071
8072 /* separate these digits to leave a space for dot */
8073 num_sep_pos = no_pre_zero ? dot_ofs : 0;
8074 num_sep = num_hdr + num_sep_pos;
8075 byte_move_16(num_sep + no_pre_zero, num_sep);
8076 num_end += no_pre_zero;
8077
8078 /* write the dot */
8079 dot_set_pos = yyjson_max(dot_ofs, 1);
8080 buf[dot_set_pos] = '.';
8081
8082 /* return the ending */
8083 dot_end = buf + dot_ofs + 2;
8084 return yyjson_max(dot_end, num_end);
8085
8086 } else {
8087 /* write with scientific notation, e.g. 1.234e56 */
8088 end = write_u64_len_16_to_17_trim(sig_dec, buf + 1);
8089 end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */
8090 exp_dec += sig_len - 1;
8091 buf[0] = buf[1];
8092 buf[1] = '.';
8093 return write_f64_exp(exp_dec, end);
8094 }
8095
8096 } else {
8097 /* subnormal number */
8098 sig_bin = sig_raw;
8099 exp_bin = 1 - F64_EXP_BIAS - F64_SIG_BITS;
8100
8101 /* binary to decimal */
8102 f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
8103
8104 /* write significand part */
8105 end = write_u64_len_1_to_17(sig_dec, buf + 1);
8106 buf[0] = buf[1];
8107 buf[1] = '.';
8108 exp_dec += (i32)(end - buf) - 2;
8109
8110 /* trim trailing zeros */
8111 end -= *(end - 1) == '0'; /* branchless for last zero */
8112 end -= *(end - 1) == '0'; /* branchless for second last zero */
8113 while (*(end - 1) == '0') end--; /* for unlikely more zeros */
8114 end -= *(end - 1) == '.'; /* remove dot, e.g. 2.e-321 -> 2e-321 */
8115
8116 /* write exponent part */
8117 return write_f64_exp(exp_dec, end);
8118 }
8119}
8120
8121/**
8122 Write a double number using fixed-point notation (requires 40 bytes buffer).
8123
8124 We follow the ECMAScript specification for printing floating-point numbers,
8125 similar to `Number.prototype.toFixed(prec)`, but with the following changes:
8126 1. Keep the negative sign of `-0.0` to preserve input information.
8127 2. Keep the decimal point to indicate that the number is floating-point.
8128 3. Remove positive sign in the exponent part.
8129 4. Remove trailing zeros and reduce unnecessary precision.
8130 */
8132 u32 prec) {
8133 u64 sig_bin, sig_dec, sig_raw;
8134 i32 exp_bin, exp_dec, sig_len, dot_ofs;
8135 u32 exp_raw;
8136 u8 *end;
8137 bool sign;
8138
8139 /* decode raw bytes from IEEE-754 double format. */
8140 sign = (bool)(raw >> (F64_BITS - 1));
8141 sig_raw = raw & F64_SIG_MASK;
8142 exp_raw = (u32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
8143
8144 /* return inf or nan */
8145 if (unlikely(exp_raw == ((u32)1 << F64_EXP_BITS) - 1)) {
8146 return write_inf_or_nan(buf, flg, sig_raw, sign);
8147 }
8148
8149 /* add sign for all finite number */
8150 buf[0] = '-';
8151 buf += sign;
8152
8153 /* return zero */
8154 if ((raw << 1) == 0) {
8155 byte_copy_4(buf, "0.0");
8156 return buf + 3;
8157 }
8158
8159 if (likely(exp_raw != 0)) {
8160 /* normal number */
8161 sig_bin = sig_raw | ((u64)1 << F64_SIG_BITS);
8162 exp_bin = (i32)exp_raw - F64_EXP_BIAS - F64_SIG_BITS;
8163
8164 /* fast path for small integer number without fraction */
8165 if ((-F64_SIG_BITS <= exp_bin && exp_bin <= 0) &&
8166 (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) {
8167 sig_dec = sig_bin >> -exp_bin; /* range: [1, 0x1FFFFFFFFFFFFF] */
8168 buf = write_u64_len_1_to_16(sig_dec, buf);
8169 byte_copy_2(buf, ".0");
8170 return buf + 2;
8171 }
8172
8173 /* only `fabs(num) < 1e21` are processed here. */
8174 if ((raw << 1) < (U64(0x444B1AE4, 0xD6E2EF50) << 1)) {
8175 i32 num_sep_pos, dot_set_pos, pre_ofs;
8176 u8 *num_hdr, *num_end, *num_sep;
8177 bool round_up, no_pre_zero;
8178
8179 /* binary to decimal */
8180 f64_bin_to_dec_fast(sig_raw, exp_raw, sig_bin, exp_bin,
8181 &sig_dec, &exp_dec, &round_up);
8182
8183 /* the sig length is 16 or 17 */
8184 sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
8185
8186 /* limit the length of digits after the decimal point */
8187 if (exp_dec < -1) {
8188 i32 sig_len_cut = -exp_dec - (i32)prec;
8189 if (sig_len_cut > sig_len) {
8190 byte_copy_4(buf, "0.0");
8191 return buf + 3;
8192 }
8193 if (sig_len_cut > 0) {
8194 u64 div, mod, p10;
8195
8196 /* remove round up */
8197 sig_dec -= round_up;
8198 sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
8199
8200 /* cut off some digits */
8201 div_pow10(sig_dec, (u32)sig_len_cut, &div, &mod, &p10);
8202
8203 /* add round up */
8204 sig_dec = div + (mod >= p10 / 2);
8205
8206 /* update exp and sig length */
8207 exp_dec += sig_len_cut;
8208 sig_len -= sig_len_cut;
8209 sig_len += (sig_len >= 0) &&
8210 (sig_dec >= div_pow10_table[sig_len].p10);
8211 }
8212 if (sig_len <= 0) {
8213 byte_copy_4(buf, "0.0");
8214 return buf + 3;
8215 }
8216 }
8217
8218 /* fill zeros */
8219 memset(buf, '0', 32);
8220
8221 /* the decimal point offset relative to the first digit */
8222 dot_ofs = sig_len + exp_dec;
8223
8224 /* not prefixed with zero, e.g. 1.234, 1234.0 */
8225 no_pre_zero = (dot_ofs > 0);
8226
8227 /* write the number as digits */
8228 pre_ofs = no_pre_zero ? 0 : (1 - dot_ofs);
8229 num_hdr = buf + pre_ofs;
8230 num_end = write_u64_len_1_to_17(sig_dec, num_hdr);
8231
8232 /* separate these digits to leave a space for dot */
8233 num_sep_pos = no_pre_zero ? dot_ofs : -dot_ofs;
8234 num_sep = buf + num_sep_pos;
8235 byte_move_16(num_sep + 1, num_sep);
8236 num_end += (exp_dec < 0);
8237
8238 /* write the dot */
8239 dot_set_pos = yyjson_max(dot_ofs, 1);
8240 buf[dot_set_pos] = '.';
8241
8242 /* remove trailing zeros */
8243 buf += dot_set_pos + 2;
8244 buf = yyjson_max(buf, num_end);
8245 buf -= *(buf - 1) == '0'; /* branchless for last zero */
8246 buf -= *(buf - 1) == '0'; /* branchless for second last zero */
8247 while (*(buf - 1) == '0') buf--; /* for unlikely more zeros */
8248 buf += *(buf - 1) == '.'; /* keep a zero after dot */
8249 return buf;
8250
8251 } else {
8252 /* binary to decimal */
8253 f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin,
8254 &sig_dec, &exp_dec);
8255
8256 /* the sig length is 16 or 17 */
8257 sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
8258
8259 /* write with scientific notation, e.g. 1.234e56 */
8260 end = write_u64_len_16_to_17_trim(sig_dec, buf + 1);
8261 end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */
8262 exp_dec += sig_len - 1;
8263 buf[0] = buf[1];
8264 buf[1] = '.';
8265 return write_f64_exp(exp_dec, end);
8266 }
8267 } else {
8268 /* subnormal number */
8269 byte_copy_4(buf, "0.0");
8270 return buf + 3;
8271 }
8272}
8273
8274#else /* FP_WRITER */
8275
8276#if YYJSON_MSC_VER >= 1400
8277#define snprintf_num(buf, len, fmt, dig, val) \
8278 sprintf_s((char *)buf, len, fmt, dig, val)
8279#elif defined(snprintf) || (YYJSON_STDC_VER >= 199901L)
8280#define snprintf_num(buf, len, fmt, dig, val) \
8281 snprintf((char *)buf, len, fmt, dig, val)
8282#else
8283#define snprintf_num(buf, len, fmt, dig, val) \
8284 sprintf((char *)buf, fmt, dig, val)
8285#endif
8286
8288 yyjson_write_flag flg, bool fixed) {
8289 u8 *cur = buf;
8290 if (unlikely(len < 1)) return NULL;
8291 cur += (*cur == '-');
8292 if (unlikely(!char_is_digit(*cur))) {
8293 /* nan, inf, or bad output */
8294 if (has_flg(INF_AND_NAN_AS_NULL)) {
8295 byte_copy_4(buf, "null");
8296 return buf + 4;
8297 } else if (has_allow(INF_AND_NAN)) {
8298 if (*cur == 'i') {
8299 byte_copy_8(cur, "Infinity");
8300 return cur + 8;
8301 } else if (*cur == 'n') {
8302 byte_copy_4(buf, "NaN");
8303 return buf + 3;
8304 }
8305 }
8306 return NULL;
8307 } else {
8308 /* finite number */
8309 u8 *end = buf + len, *dot = NULL, *exp = NULL;
8310
8311 /*
8312 The snprintf() function is locale-dependent. For currently known
8313 locales, (en, zh, ja, ko, am, he, hi) use '.' as the decimal point,
8314 while other locales use ',' as the decimal point. we need to replace
8315 ',' with '.' to avoid the locale setting.
8316 */
8317 for (; cur < end; cur++) {
8318 switch (*cur) {
8319 case ',': *cur = '.'; /* fallthrough */
8320 case '.': dot = cur; break;
8321 case 'e': exp = cur; break;
8322 default: break;
8323 }
8324 }
8325 if (fixed) {
8326 /* remove trailing zeros */
8327 while (*(end - 1) == '0') end--;
8328 end += *(end - 1) == '.';
8329 } else {
8330 if (!dot && !exp) {
8331 /* add decimal point, e.g. 123 -> 123.0 */
8332 byte_copy_2(end, ".0");
8333 end += 2;
8334 } else if (exp) {
8335 cur = exp + 1;
8336 /* remove positive sign in the exponent part */
8337 if (*cur == '+') {
8338 memmove(cur, cur + 1, (usize)(end - cur - 1));
8339 end--;
8340 }
8341 cur += (*cur == '-');
8342 /* remove leading zeros in the exponent part */
8343 if (*cur == '0') {
8344 u8 *hdr = cur++;
8345 while (*cur == '0') cur++;
8346 memmove(hdr, cur, (usize)(end - cur));
8347 end -= (usize)(cur - hdr);
8348 }
8349 }
8350 }
8351 return end;
8352 }
8353}
8354
8355/** Write a double number (requires 40 bytes buffer). */
8357#if defined(DBL_DECIMAL_DIG) && DBL_DECIMAL_DIG < F64_DEC_DIG
8358 int dig = DBL_DECIMAL_DIG;
8359#else
8360 int dig = F64_DEC_DIG;
8361#endif
8362 f64 val = f64_from_bits(raw);
8363 int len = snprintf_num(buf, FP_BUF_LEN, "%.*g", dig, val);
8364 return write_fp_reformat(buf, len, flg, false);
8365}
8366
8367/** Write a double number (requires 40 bytes buffer). */
8369#if defined(FLT_DECIMAL_DIG) && FLT_DECIMAL_DIG < F32_DEC_DIG
8370 int dig = FLT_DECIMAL_DIG;
8371#else
8372 int dig = F32_DEC_DIG;
8373#endif
8374 f64 val = (f64)f64_to_f32(f64_from_bits(raw));
8375 int len = snprintf_num(buf, FP_BUF_LEN, "%.*g", dig, val);
8376 return write_fp_reformat(buf, len, flg, false);
8377}
8378
8379/** Write a double number (requires 40 bytes buffer). */
8381 yyjson_write_flag flg, u32 prec) {
8382 f64 val = (f64)f64_from_bits(raw);
8383 if (-1e21 < val && val < 1e21) {
8384 int len = snprintf_num(buf, FP_BUF_LEN, "%.*f", (int)prec, val);
8385 return write_fp_reformat(buf, len, flg, true);
8386 } else {
8387 return write_f64_raw(buf, raw, flg);
8388 }
8389}
8390
8391#endif /* FP_WRITER */
8392
8393/** Write a JSON number (requires 40 bytes buffer). */
8395 if (!(val->tag & YYJSON_SUBTYPE_REAL)) {
8396 u64 pos = val->uni.u64;
8397 u64 neg = ~pos + 1;
8398 usize sign = ((val->tag & YYJSON_SUBTYPE_SINT) > 0) & ((i64)pos < 0);
8399 *cur = '-';
8400 return write_u64(sign ? neg : pos, cur + sign);
8401 } else {
8402 u64 raw = val->uni.u64;
8403 u32 val_fmt = (u32)(val->tag >> 32);
8404 u32 all_fmt = flg;
8405 u32 fmt = val_fmt | all_fmt;
8406 if (likely(!(fmt >> (32 - YYJSON_WRITE_FP_FLAG_BITS)))) {
8407 /* double to shortest */
8408 return write_f64_raw(cur, raw, flg);
8409 } else if (fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS)) {
8410 /* double to fixed */
8411 u32 val_prec = val_fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS);
8412 u32 all_prec = all_fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS);
8413 u32 prec = val_prec ? val_prec : all_prec;
8414 return write_f64_raw_fixed(cur, raw, flg, prec);
8415 } else {
8416 if (fmt & YYJSON_WRITE_FP_TO_FLOAT) {
8417 /* float to shortest */
8418 return write_f32_raw(cur, raw, flg);
8419 } else {
8420 /* double to shortest */
8421 return write_f64_raw(cur, raw, flg);
8422 }
8423 }
8424 }
8425}
8426
8427char *yyjson_write_number(const yyjson_val *val, char *buf) {
8428 if (unlikely(!val || !buf)) return NULL;
8429 switch (val->tag & YYJSON_TAG_MASK) {
8431 buf = (char *)write_u64(val->uni.u64, (u8 *)buf);
8432 *buf = '\0';
8433 return buf;
8434 }
8436 u64 pos = val->uni.u64;
8437 u64 neg = ~pos + 1;
8438 usize sign = ((i64)pos < 0);
8439 *buf = '-';
8440 buf = (char *)write_u64(sign ? neg : pos, (u8 *)buf + sign);
8441 *buf = '\0';
8442 return buf;
8443 }
8445 u64 raw = val->uni.u64;
8446 u32 fmt = (u32)(val->tag >> 32);
8448 if (likely(!(fmt >> (32 - YYJSON_WRITE_FP_FLAG_BITS)))) {
8449 buf = (char *)write_f64_raw((u8 *)buf, raw, flg);
8450 } else if (fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS)) {
8451 u32 prec = fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS);
8452 buf = (char *)write_f64_raw_fixed((u8 *)buf, raw, flg, prec);
8453 } else {
8454 if (fmt & YYJSON_WRITE_FP_TO_FLOAT) {
8455 buf = (char *)write_f32_raw((u8 *)buf, raw, flg);
8456 } else {
8457 buf = (char *)write_f64_raw((u8 *)buf, raw, flg);
8458 }
8459 }
8460 if (buf) *buf = '\0';
8461 return buf;
8462 }
8463 default: return NULL;
8464 }
8465}
8466
8467
8468
8469/*==============================================================================
8470 * MARK: - String Writer (Private)
8471 *============================================================================*/
8472
8473/** Character encode type, if (type > CHAR_ENC_ERR_1) bytes = type / 2; */
8475#define CHAR_ENC_CPY_1 0 /* 1-byte UTF-8, copy. */
8476#define CHAR_ENC_ERR_1 1 /* 1-byte UTF-8, error. */
8477#define CHAR_ENC_ESC_A 2 /* 1-byte ASCII, escaped as '\x'. */
8478#define CHAR_ENC_ESC_1 3 /* 1-byte UTF-8, escaped as '\uXXXX'. */
8479#define CHAR_ENC_CPY_2 4 /* 2-byte UTF-8, copy. */
8480#define CHAR_ENC_ESC_2 5 /* 2-byte UTF-8, escaped as '\uXXXX'. */
8481#define CHAR_ENC_CPY_3 6 /* 3-byte UTF-8, copy. */
8482#define CHAR_ENC_ESC_3 7 /* 3-byte UTF-8, escaped as '\uXXXX'. */
8483#define CHAR_ENC_CPY_4 8 /* 4-byte UTF-8, copy. */
8484#define CHAR_ENC_ESC_4 9 /* 4-byte UTF-8, escaped as '\uXXXX\uXXXX'. */
8485
8486/** Character encode type table: don't escape unicode, don't escape '/'.
8487 (generated with misc/make_tables.c) */
8488static const char_enc_type enc_table_cpy[256] = {
8489 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
8490 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
8491 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8492 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8493 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8494 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
8495 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8496 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8497 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8498 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8499 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8500 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8501 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
8502 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
8503 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
8504 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1
8505};
8506
8507/** Character encode type table: don't escape unicode, escape '/'.
8508 (generated with misc/make_tables.c) */
8510 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
8511 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
8512 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
8513 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8514 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8515 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
8516 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8517 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8518 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8519 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8520 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8521 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8522 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
8523 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
8524 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
8525 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1
8526};
8527
8528/** Character encode type table: escape unicode, don't escape '/'.
8529 (generated with misc/make_tables.c) */
8530static const char_enc_type enc_table_esc[256] = {
8531 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
8532 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
8533 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8534 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8535 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8536 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
8537 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8538 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8539 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8540 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8541 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8542 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8543 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
8544 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
8545 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
8546 9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1
8547};
8548
8549/** Character encode type table: escape unicode, escape '/'.
8550 (generated with misc/make_tables.c) */
8552 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
8553 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
8554 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
8555 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8556 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8557 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
8558 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8559 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8560 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8561 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8562 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8563 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8564 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
8565 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
8566 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
8567 9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1
8568};
8569
8570/** Escaped hex character table: ["00" "01" "02" ... "FD" "FE" "FF"].
8571 (generated with misc/make_tables.c) */
8572yyjson_align(2)
8573static const u8 esc_hex_char_table[512] = {
8574 '0', '0', '0', '1', '0', '2', '0', '3',
8575 '0', '4', '0', '5', '0', '6', '0', '7',
8576 '0', '8', '0', '9', '0', 'A', '0', 'B',
8577 '0', 'C', '0', 'D', '0', 'E', '0', 'F',
8578 '1', '0', '1', '1', '1', '2', '1', '3',
8579 '1', '4', '1', '5', '1', '6', '1', '7',
8580 '1', '8', '1', '9', '1', 'A', '1', 'B',
8581 '1', 'C', '1', 'D', '1', 'E', '1', 'F',
8582 '2', '0', '2', '1', '2', '2', '2', '3',
8583 '2', '4', '2', '5', '2', '6', '2', '7',
8584 '2', '8', '2', '9', '2', 'A', '2', 'B',
8585 '2', 'C', '2', 'D', '2', 'E', '2', 'F',
8586 '3', '0', '3', '1', '3', '2', '3', '3',
8587 '3', '4', '3', '5', '3', '6', '3', '7',
8588 '3', '8', '3', '9', '3', 'A', '3', 'B',
8589 '3', 'C', '3', 'D', '3', 'E', '3', 'F',
8590 '4', '0', '4', '1', '4', '2', '4', '3',
8591 '4', '4', '4', '5', '4', '6', '4', '7',
8592 '4', '8', '4', '9', '4', 'A', '4', 'B',
8593 '4', 'C', '4', 'D', '4', 'E', '4', 'F',
8594 '5', '0', '5', '1', '5', '2', '5', '3',
8595 '5', '4', '5', '5', '5', '6', '5', '7',
8596 '5', '8', '5', '9', '5', 'A', '5', 'B',
8597 '5', 'C', '5', 'D', '5', 'E', '5', 'F',
8598 '6', '0', '6', '1', '6', '2', '6', '3',
8599 '6', '4', '6', '5', '6', '6', '6', '7',
8600 '6', '8', '6', '9', '6', 'A', '6', 'B',
8601 '6', 'C', '6', 'D', '6', 'E', '6', 'F',
8602 '7', '0', '7', '1', '7', '2', '7', '3',
8603 '7', '4', '7', '5', '7', '6', '7', '7',
8604 '7', '8', '7', '9', '7', 'A', '7', 'B',
8605 '7', 'C', '7', 'D', '7', 'E', '7', 'F',
8606 '8', '0', '8', '1', '8', '2', '8', '3',
8607 '8', '4', '8', '5', '8', '6', '8', '7',
8608 '8', '8', '8', '9', '8', 'A', '8', 'B',
8609 '8', 'C', '8', 'D', '8', 'E', '8', 'F',
8610 '9', '0', '9', '1', '9', '2', '9', '3',
8611 '9', '4', '9', '5', '9', '6', '9', '7',
8612 '9', '8', '9', '9', '9', 'A', '9', 'B',
8613 '9', 'C', '9', 'D', '9', 'E', '9', 'F',
8614 'A', '0', 'A', '1', 'A', '2', 'A', '3',
8615 'A', '4', 'A', '5', 'A', '6', 'A', '7',
8616 'A', '8', 'A', '9', 'A', 'A', 'A', 'B',
8617 'A', 'C', 'A', 'D', 'A', 'E', 'A', 'F',
8618 'B', '0', 'B', '1', 'B', '2', 'B', '3',
8619 'B', '4', 'B', '5', 'B', '6', 'B', '7',
8620 'B', '8', 'B', '9', 'B', 'A', 'B', 'B',
8621 'B', 'C', 'B', 'D', 'B', 'E', 'B', 'F',
8622 'C', '0', 'C', '1', 'C', '2', 'C', '3',
8623 'C', '4', 'C', '5', 'C', '6', 'C', '7',
8624 'C', '8', 'C', '9', 'C', 'A', 'C', 'B',
8625 'C', 'C', 'C', 'D', 'C', 'E', 'C', 'F',
8626 'D', '0', 'D', '1', 'D', '2', 'D', '3',
8627 'D', '4', 'D', '5', 'D', '6', 'D', '7',
8628 'D', '8', 'D', '9', 'D', 'A', 'D', 'B',
8629 'D', 'C', 'D', 'D', 'D', 'E', 'D', 'F',
8630 'E', '0', 'E', '1', 'E', '2', 'E', '3',
8631 'E', '4', 'E', '5', 'E', '6', 'E', '7',
8632 'E', '8', 'E', '9', 'E', 'A', 'E', 'B',
8633 'E', 'C', 'E', 'D', 'E', 'E', 'E', 'F',
8634 'F', '0', 'F', '1', 'F', '2', 'F', '3',
8635 'F', '4', 'F', '5', 'F', '6', 'F', '7',
8636 'F', '8', 'F', '9', 'F', 'A', 'F', 'B',
8637 'F', 'C', 'F', 'D', 'F', 'E', 'F', 'F'
8638};
8639
8640/** Lowercase variant of esc_hex_char_table. */
8641yyjson_align(2)
8642static const u8 esc_hex_char_table_lower[512] = {
8643 '0', '0', '0', '1', '0', '2', '0', '3',
8644 '0', '4', '0', '5', '0', '6', '0', '7',
8645 '0', '8', '0', '9', '0', 'a', '0', 'b',
8646 '0', 'c', '0', 'd', '0', 'e', '0', 'f',
8647 '1', '0', '1', '1', '1', '2', '1', '3',
8648 '1', '4', '1', '5', '1', '6', '1', '7',
8649 '1', '8', '1', '9', '1', 'a', '1', 'b',
8650 '1', 'c', '1', 'd', '1', 'e', '1', 'f',
8651 '2', '0', '2', '1', '2', '2', '2', '3',
8652 '2', '4', '2', '5', '2', '6', '2', '7',
8653 '2', '8', '2', '9', '2', 'a', '2', 'b',
8654 '2', 'c', '2', 'd', '2', 'e', '2', 'f',
8655 '3', '0', '3', '1', '3', '2', '3', '3',
8656 '3', '4', '3', '5', '3', '6', '3', '7',
8657 '3', '8', '3', '9', '3', 'a', '3', 'b',
8658 '3', 'c', '3', 'd', '3', 'e', '3', 'f',
8659 '4', '0', '4', '1', '4', '2', '4', '3',
8660 '4', '4', '4', '5', '4', '6', '4', '7',
8661 '4', '8', '4', '9', '4', 'a', '4', 'b',
8662 '4', 'c', '4', 'd', '4', 'e', '4', 'f',
8663 '5', '0', '5', '1', '5', '2', '5', '3',
8664 '5', '4', '5', '5', '5', '6', '5', '7',
8665 '5', '8', '5', '9', '5', 'a', '5', 'b',
8666 '5', 'c', '5', 'd', '5', 'e', '5', 'f',
8667 '6', '0', '6', '1', '6', '2', '6', '3',
8668 '6', '4', '6', '5', '6', '6', '6', '7',
8669 '6', '8', '6', '9', '6', 'a', '6', 'b',
8670 '6', 'c', '6', 'd', '6', 'e', '6', 'f',
8671 '7', '0', '7', '1', '7', '2', '7', '3',
8672 '7', '4', '7', '5', '7', '6', '7', '7',
8673 '7', '8', '7', '9', '7', 'a', '7', 'b',
8674 '7', 'c', '7', 'd', '7', 'e', '7', 'f',
8675 '8', '0', '8', '1', '8', '2', '8', '3',
8676 '8', '4', '8', '5', '8', '6', '8', '7',
8677 '8', '8', '8', '9', '8', 'a', '8', 'b',
8678 '8', 'c', '8', 'd', '8', 'e', '8', 'f',
8679 '9', '0', '9', '1', '9', '2', '9', '3',
8680 '9', '4', '9', '5', '9', '6', '9', '7',
8681 '9', '8', '9', '9', '9', 'a', '9', 'b',
8682 '9', 'c', '9', 'd', '9', 'e', '9', 'f',
8683 'a', '0', 'a', '1', 'a', '2', 'a', '3',
8684 'a', '4', 'a', '5', 'a', '6', 'a', '7',
8685 'a', '8', 'a', '9', 'a', 'a', 'a', 'b',
8686 'a', 'c', 'a', 'd', 'a', 'e', 'a', 'f',
8687 'b', '0', 'b', '1', 'b', '2', 'b', '3',
8688 'b', '4', 'b', '5', 'b', '6', 'b', '7',
8689 'b', '8', 'b', '9', 'b', 'a', 'b', 'b',
8690 'b', 'c', 'b', 'd', 'b', 'e', 'b', 'f',
8691 'c', '0', 'c', '1', 'c', '2', 'c', '3',
8692 'c', '4', 'c', '5', 'c', '6', 'c', '7',
8693 'c', '8', 'c', '9', 'c', 'a', 'c', 'b',
8694 'c', 'c', 'c', 'd', 'c', 'e', 'c', 'f',
8695 'd', '0', 'd', '1', 'd', '2', 'd', '3',
8696 'd', '4', 'd', '5', 'd', '6', 'd', '7',
8697 'd', '8', 'd', '9', 'd', 'a', 'd', 'b',
8698 'd', 'c', 'd', 'd', 'd', 'e', 'd', 'f',
8699 'e', '0', 'e', '1', 'e', '2', 'e', '3',
8700 'e', '4', 'e', '5', 'e', '6', 'e', '7',
8701 'e', '8', 'e', '9', 'e', 'a', 'e', 'b',
8702 'e', 'c', 'e', 'd', 'e', 'e', 'e', 'f',
8703 'f', '0', 'f', '1', 'f', '2', 'f', '3',
8704 'f', '4', 'f', '5', 'f', '6', 'f', '7',
8705 'f', '8', 'f', '9', 'f', 'a', 'f', 'b',
8706 'f', 'c', 'f', 'd', 'f', 'e', 'f', 'f'
8707};
8708
8709/** Escaped single character table. (generated with misc/make_tables.c) */
8710yyjson_align(2)
8711static const u8 esc_single_char_table[512] = {
8712 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8713 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8714 '\\', 'b', '\\', 't', '\\', 'n', ' ', ' ',
8715 '\\', 'f', '\\', 'r', ' ', ' ', ' ', ' ',
8716 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8717 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8718 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8719 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8720 ' ', ' ', ' ', ' ', '\\', '"', ' ', ' ',
8721 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8722 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8723 ' ', ' ', ' ', ' ', ' ', ' ', '\\', '/',
8724 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8725 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8726 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8727 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8728 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8729 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8730 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8731 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8732 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8733 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8734 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8735 '\\', '\\', ' ', ' ', ' ', ' ', ' ', ' ',
8736 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8737 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8738 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8739 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8740 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8741 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8742 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8743 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8744 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8745 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8746 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8747 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8748 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8749 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8750 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8751 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8752 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8753 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8754 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8755 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8756 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8757 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8758 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8759 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8760 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8761 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8762 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8763 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8764 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8765 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8766 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8767 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8768 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8769 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8770 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8771 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8772 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8773 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8774 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8775 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
8776};
8777
8778/** Returns the hex digit table to use for \uXXXX escapes. */
8780 return has_flg(LOWERCASE_HEX)
8781 ? esc_hex_char_table_lower
8782 : esc_hex_char_table;
8783}
8784
8785/** Returns the encode table with options. */
8787 yyjson_write_flag flg) {
8788 if (has_flg(ESCAPE_UNICODE)) {
8789 if (has_flg(ESCAPE_SLASHES)) {
8790 return enc_table_esc_slash;
8791 } else {
8792 return enc_table_esc;
8793 }
8794 } else {
8795 if (has_flg(ESCAPE_SLASHES)) {
8796 return enc_table_cpy_slash;
8797 } else {
8798 return enc_table_cpy;
8799 }
8800 }
8801}
8802
8803/** Write raw string. */
8804static_inline u8 *write_raw(u8 *cur, const u8 *raw, usize raw_len) {
8805 memcpy(cur, raw, raw_len);
8806 return cur + raw_len;
8807}
8808
8809/**
8810 Write string no-escape.
8811 @param cur Buffer cursor.
8812 @param str A UTF-8 string, null-terminator is not required.
8813 @param str_len Length of string in bytes.
8814 @return The buffer cursor after string.
8815 */
8816static_inline u8 *write_str_noesc(u8 *cur, const u8 *str, usize str_len) {
8817 *cur++ = '"';
8818 while (str_len >= 16) {
8819 byte_copy_16(cur, str);
8820 cur += 16;
8821 str += 16;
8822 str_len -= 16;
8823 }
8824 while (str_len >= 4) {
8825 byte_copy_4(cur, str);
8826 cur += 4;
8827 str += 4;
8828 str_len -= 4;
8829 }
8830 while (str_len) {
8831 *cur++ = *str++;
8832 str_len -= 1;
8833 }
8834 *cur++ = '"';
8835 return cur;
8836}
8837
8838/**
8839 Write UTF-8 string (requires len * 6 + 2 bytes buffer).
8840 @param cur Buffer cursor.
8841 @param esc Escape unicode.
8842 @param inv Allow invalid unicode.
8843 @param str A UTF-8 string, null-terminator is not required.
8844 @param str_len Length of string in bytes.
8845 @param enc_table Encode type table for character.
8846 @return The buffer cursor after string, or NULL on invalid unicode.
8847 */
8848static_inline u8 *write_str(u8 *cur, bool esc, bool inv,
8849 const u8 *str, usize str_len,
8850 const char_enc_type *enc_table,
8851 const u8 *hex_table) {
8852 /* The replacement character U+FFFD, used to indicate invalid character.
8853 Looked up via hex_table so that LOWERCASE_HEX produces "fffd" while
8854 the default produces "FFFD". */
8855 const v32 pre = {{ '\\', 'u', '0', '0' }};
8856
8857 const u8 *src = str;
8858 const u8 *end = str + str_len;
8859 *cur++ = '"';
8860
8861copy_ascii:
8862 /*
8863 Copy continuous ASCII, loop unrolling, same as the following code:
8864
8865 while (end > src) (
8866 if (unlikely(enc_table[*src])) break;
8867 *cur++ = *src++;
8868 );
8869 */
8870#define expr_jump(i) \
8871 if (unlikely(enc_table[src[i]])) goto stop_char_##i;
8872
8873#define expr_stop(i) \
8874 stop_char_##i: \
8875 memcpy(cur, src, i); \
8876 cur += i; src += i; goto copy_utf8;
8877
8878 while (end - src >= 16) {
8880 byte_copy_16(cur, src);
8881 cur += 16; src += 16;
8882 }
8883
8884 while (end - src >= 4) {
8886 byte_copy_4(cur, src);
8887 cur += 4; src += 4;
8888 }
8889
8890 while (end > src) {
8891 expr_jump(0)
8892 *cur++ = *src++;
8893 }
8894
8895 *cur++ = '"';
8896 return cur;
8897
8899
8900#undef expr_jump
8901#undef expr_stop
8902
8903copy_utf8:
8904 if (unlikely(src + 4 > end)) {
8905 if (end == src) goto copy_end;
8906 if (end - src < enc_table[*src] / 2) goto err_one;
8907 }
8908 switch (enc_table[*src]) {
8909 case CHAR_ENC_CPY_1: {
8910 *cur++ = *src++;
8911 goto copy_ascii;
8912 }
8913 case CHAR_ENC_CPY_2: {
8914#if YYJSON_DISABLE_UTF8_VALIDATION
8915 byte_copy_2(cur, src);
8916#else
8917 u32 uni = 0;
8918 byte_copy_2(&uni, src);
8919 if (unlikely(!is_utf8_seq2(uni))) goto err_cpy;
8920 byte_copy_2(cur, &uni);
8921#endif
8922 cur += 2;
8923 src += 2;
8924 goto copy_utf8;
8925 }
8926 case CHAR_ENC_CPY_3: {
8927#if YYJSON_DISABLE_UTF8_VALIDATION
8928 if (likely(src + 4 <= end)) {
8929 byte_copy_4(cur, src);
8930 } else {
8931 byte_copy_2(cur, src);
8932 cur[2] = src[2];
8933 }
8934#else
8935 u32 uni, tmp;
8936 if (likely(src + 4 <= end)) {
8937 uni = byte_load_4(src);
8938 if (unlikely(!is_utf8_seq3(uni))) goto err_cpy;
8939 byte_copy_4(cur, src);
8940 } else {
8941 uni = byte_load_3(src);
8942 if (unlikely(!is_utf8_seq3(uni))) goto err_cpy;
8943 byte_copy_4(cur, &uni);
8944 }
8945#endif
8946 cur += 3;
8947 src += 3;
8948 goto copy_utf8;
8949 }
8950 case CHAR_ENC_CPY_4: {
8951#if YYJSON_DISABLE_UTF8_VALIDATION
8952 byte_copy_4(cur, src);
8953#else
8954 u32 uni, tmp;
8955 uni = byte_load_4(src);
8956 if (unlikely(!is_utf8_seq4(uni))) goto err_cpy;
8957 byte_copy_4(cur, src);
8958#endif
8959 cur += 4;
8960 src += 4;
8961 goto copy_utf8;
8962 }
8963 case CHAR_ENC_ESC_A: {
8964 byte_copy_2(cur, &esc_single_char_table[*src * 2]);
8965 cur += 2;
8966 src += 1;
8967 goto copy_utf8;
8968 }
8969 case CHAR_ENC_ESC_1: {
8970 byte_copy_4(cur + 0, &pre);
8971 byte_copy_2(cur + 4, &hex_table[*src * 2]);
8972 cur += 6;
8973 src += 1;
8974 goto copy_utf8;
8975 }
8976 case CHAR_ENC_ESC_2: {
8977 u16 u;
8978#if !YYJSON_DISABLE_UTF8_VALIDATION
8979 u32 v4 = 0;
8980 u16 v2 = byte_load_2(src);
8981 byte_copy_2(&v4, &v2);
8982 if (unlikely(!is_utf8_seq2(v4))) goto err_esc;
8983#endif
8984 u = (u16)(((u16)(src[0] & 0x1F) << 6) |
8985 ((u16)(src[1] & 0x3F) << 0));
8986 byte_copy_2(cur + 0, &pre);
8987 byte_copy_2(cur + 2, &hex_table[(u >> 8) * 2]);
8988 byte_copy_2(cur + 4, &hex_table[(u & 0xFF) * 2]);
8989 cur += 6;
8990 src += 2;
8991 goto copy_utf8;
8992 }
8993 case CHAR_ENC_ESC_3: {
8994 u16 u;
8995 u32 v, tmp;
8996#if !YYJSON_DISABLE_UTF8_VALIDATION
8997 v = byte_load_3(src);
8998 if (unlikely(!is_utf8_seq3(v))) goto err_esc;
8999#endif
9000 u = (u16)(((u16)(src[0] & 0x0F) << 12) |
9001 ((u16)(src[1] & 0x3F) << 6) |
9002 ((u16)(src[2] & 0x3F) << 0));
9003 byte_copy_2(cur + 0, &pre);
9004 byte_copy_2(cur + 2, &hex_table[(u >> 8) * 2]);
9005 byte_copy_2(cur + 4, &hex_table[(u & 0xFF) * 2]);
9006 cur += 6;
9007 src += 3;
9008 goto copy_utf8;
9009 }
9010 case CHAR_ENC_ESC_4: {
9011 u32 hi, lo, u, v, tmp;
9012#if !YYJSON_DISABLE_UTF8_VALIDATION
9013 v = byte_load_4(src);
9014 if (unlikely(!is_utf8_seq4(v))) goto err_esc;
9015#endif
9016 u = ((u32)(src[0] & 0x07) << 18) |
9017 ((u32)(src[1] & 0x3F) << 12) |
9018 ((u32)(src[2] & 0x3F) << 6) |
9019 ((u32)(src[3] & 0x3F) << 0);
9020 u -= 0x10000;
9021 hi = (u >> 10) + 0xD800;
9022 lo = (u & 0x3FF) + 0xDC00;
9023 byte_copy_2(cur + 0, &pre);
9024 byte_copy_2(cur + 2, &hex_table[(hi >> 8) * 2]);
9025 byte_copy_2(cur + 4, &hex_table[(hi & 0xFF) * 2]);
9026 byte_copy_2(cur + 6, &pre);
9027 byte_copy_2(cur + 8, &hex_table[(lo >> 8) * 2]);
9028 byte_copy_2(cur + 10, &hex_table[(lo & 0xFF) * 2]);
9029 cur += 12;
9030 src += 4;
9031 goto copy_utf8;
9032 }
9033 case CHAR_ENC_ERR_1: {
9034 goto err_one;
9035 }
9036 default: break; /* unreachable */
9037 }
9038
9039copy_end:
9040 *cur++ = '"';
9041 return cur;
9042
9043err_one:
9044 if (esc) goto err_esc;
9045 else goto err_cpy;
9046
9047err_cpy:
9048 if (!inv) return NULL;
9049 *cur++ = *src++;
9050 goto copy_utf8;
9051
9052err_esc:
9053 if (!inv) return NULL;
9054 byte_copy_2(cur + 0, &pre);
9055 /* U+FFFD = 0xFFFD, written as two pairs from hex_table so that
9056 LOWERCASE_HEX produces "fffd". Replaces a single byte_copy_4
9057 from a hardcoded uppercase "FFFD" v32; same total output, one
9058 extra load on the (rare) invalid-UTF-8-with-ALLOW path. */
9059 byte_copy_2(cur + 2, &hex_table[0xFF * 2]);
9060 byte_copy_2(cur + 4, &hex_table[0xFD * 2]);
9061 cur += 6;
9062 src += 1;
9063 goto copy_utf8;
9064}
9065
9066
9067
9068/*==============================================================================
9069 * MARK: - JSON Writer Utilities (Private)
9070 *============================================================================*/
9071
9072/** Write null (requires 8 bytes buffer). */
9074 v64 v = {{ 'n', 'u', 'l', 'l', ',', '\n', 0, 0 }};
9075 byte_copy_8(cur, &v);
9076 return cur + 4;
9077}
9078
9079/** Write bool (requires 8 bytes buffer). */
9080static_inline u8 *write_bool(u8 *cur, bool val) {
9081 v64 v0 = {{ 'f', 'a', 'l', 's', 'e', ',', '\n', 0 }};
9082 v64 v1 = {{ 't', 'r', 'u', 'e', ',', '\n', 0, 0 }};
9083 if (val) {
9084 byte_copy_8(cur, &v1);
9085 } else {
9086 byte_copy_8(cur, &v0);
9087 }
9088 return cur + 5 - val;
9089}
9090
9091/** Write indent (requires level x 4 bytes buffer).
9092 Param spaces should not larger than 4. */
9094 while (level-- > 0) {
9095 byte_copy_4(cur, " ");
9096 cur += spaces;
9097 }
9098 return cur;
9099}
9100
9101#if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE
9102
9103/** Write data to file pointer. */
9104static bool write_dat_to_fp(FILE *fp, u8 *dat, usize len,
9105 yyjson_write_err *err) {
9106 if (fwrite(dat, 1, len, fp) != len) {
9107 err->msg = "file writing failed";
9109 return false;
9110 }
9111 return true;
9112}
9113
9114/** Write data to file. */
9115static bool write_dat_to_file(const char *path, u8 *dat, usize len,
9116 yyjson_write_err *err) {
9117#define return_err(_code, _msg) do { \
9118 err->msg = _msg; \
9119 err->code = YYJSON_WRITE_ERROR_##_code; \
9120 if (file) fclose(file); \
9121 return false; \
9122} while (false)
9123
9124 FILE *file = fopen_writeonly(path);
9125 if (file == NULL) {
9126 return_err(FILE_OPEN, MSG_FOPEN);
9127 }
9128 if (fwrite(dat, 1, len, file) != len) {
9129 return_err(FILE_WRITE, MSG_FWRITE);
9130 }
9131 if (fclose(file) != 0) {
9132 file = NULL;
9133 return_err(FILE_WRITE, MSG_FCLOSE);
9134 }
9135 return true;
9136
9137#undef return_err
9138}
9139
9140#endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */
9141
9142
9143
9144/*==============================================================================
9145 * MARK: - JSON Writer Implementation (Private)
9146 *============================================================================*/
9147
9151
9153 usize size, bool is_obj) {
9154 ctx->tag = (size << 1) | (usize)is_obj;
9155}
9156
9158 usize *size, bool *is_obj) {
9159 usize tag = ctx->tag;
9160 *size = tag >> 1;
9161 *is_obj = (bool)(tag & 1);
9162}
9163
9164/** Write single JSON value. */
9167 yyjson_alc alc,
9168 char *buf, usize *dat_len,
9169 yyjson_write_err *err) {
9170#define return_err(_code, _msg) do { \
9171 if (hdr) alc.free(alc.ctx, (void *)hdr); \
9172 *dat_len = 0; \
9173 err->code = YYJSON_WRITE_ERROR_##_code; \
9174 err->msg = _msg; \
9175 return NULL; \
9176} while (false)
9177
9178#define incr_len(_len) do { \
9179 if (buf) hdr = *dat_len >= _len ? (u8 *)buf : (u8 *)NULL; \
9180 else hdr = (u8 *)alc.malloc(alc.ctx, _len); \
9181 if (!hdr) goto fail_alloc; \
9182 cur = hdr; \
9183} while (false)
9184
9185#define check_str_len(_len) do { \
9186 if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
9187 goto fail_alloc; \
9188} while (false)
9189
9190 u8 *hdr = NULL, *cur;
9191 usize str_len;
9192 const u8 *str_ptr;
9193 const char_enc_type *enc_table = get_enc_table_with_flag(flg);
9194 const u8 *hex_table = get_hex_table_with_flag(flg);
9195 bool cpy = (enc_table == enc_table_cpy);
9196 bool esc = has_flg(ESCAPE_UNICODE) != 0;
9197 bool inv = has_allow(INVALID_UNICODE) != 0;
9198 bool newline = has_flg(NEWLINE_AT_END) != 0;
9199 const usize end_len = 2; /* '\n' and '\0' */
9200
9201 switch (unsafe_yyjson_get_type(val)) {
9202 case YYJSON_TYPE_RAW:
9203 str_len = unsafe_yyjson_get_len(val);
9204 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9205 check_str_len(str_len);
9206 incr_len(str_len + end_len);
9207 cur = write_raw(cur, str_ptr, str_len);
9208 break;
9209
9210 case YYJSON_TYPE_STR:
9211 str_len = unsafe_yyjson_get_len(val);
9212 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9213 check_str_len(str_len);
9214 incr_len(str_len * 6 + 2 + end_len);
9215 if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
9216 cur = write_str_noesc(cur, str_ptr, str_len);
9217 } else {
9218 cur = write_str(cur, esc, inv, str_ptr, str_len,
9219 enc_table, hex_table);
9220 if (unlikely(!cur)) goto fail_str;
9221 }
9222 break;
9223
9224 case YYJSON_TYPE_NUM:
9225 incr_len(FP_BUF_LEN + end_len);
9226 cur = write_num(cur, val, flg);
9227 if (unlikely(!cur)) goto fail_num;
9228 break;
9229
9230 case YYJSON_TYPE_BOOL:
9231 incr_len(8);
9232 cur = write_bool(cur, unsafe_yyjson_get_bool(val));
9233 break;
9234
9235 case YYJSON_TYPE_NULL:
9236 incr_len(8);
9237 cur = write_null(cur);
9238 break;
9239
9240 case YYJSON_TYPE_ARR:
9241 incr_len(2 + end_len);
9242 byte_copy_2(cur, "[]");
9243 cur += 2;
9244 break;
9245
9246 case YYJSON_TYPE_OBJ:
9247 incr_len(2 + end_len);
9248 byte_copy_2(cur, "{}");
9249 cur += 2;
9250 break;
9251
9252 default:
9253 goto fail_type;
9254 }
9255
9256 if (newline) *cur++ = '\n';
9257 *cur = '\0';
9258 *dat_len = (usize)(cur - hdr);
9259 memset(err, 0, sizeof(yyjson_write_err));
9260 return hdr;
9261
9262fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
9263fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
9264fail_num: return_err(NAN_OR_INF, MSG_NAN_INF);
9265fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8);
9266
9267#undef return_err
9268#undef check_str_len
9269#undef incr_len
9270}
9271
9272/** Write JSON document minify.
9273 The root of this document should be a non-empty container. */
9275 const yyjson_write_flag flg,
9276 const yyjson_alc alc,
9277 char *buf, usize *dat_len,
9278 yyjson_write_err *err) {
9279#define return_err(_code, _msg) do { \
9280 *dat_len = 0; \
9281 err->code = YYJSON_WRITE_ERROR_##_code; \
9282 err->msg = _msg; \
9283 if (hdr) alc.free(alc.ctx, hdr); \
9284 return NULL; \
9285} while (false)
9286
9287#define incr_len(_len) do { \
9288 ext_len = (usize)(_len); \
9289 if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
9290 usize ctx_pos = (usize)((u8 *)ctx - hdr); \
9291 usize cur_pos = (usize)(cur - hdr); \
9292 yyjson_assume((u8 *)ctx <= (u8 *)end); \
9293 ctx_len = (usize)((u8 *)end - (u8 *)ctx); \
9294 alc_inc = yyjson_max(alc_len / 2, ext_len); \
9295 alc_inc = size_align_up(alc_inc, sizeof(yyjson_write_ctx)); \
9296 if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
9297 goto fail_alloc; \
9298 alc_len += alc_inc; \
9299 tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
9300 if (unlikely(!tmp)) goto fail_alloc; \
9301 ctx_tmp = (yyjson_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
9302 memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
9303 ctx = ctx_tmp; \
9304 cur = tmp + cur_pos; \
9305 end = tmp + alc_len; \
9306 hdr = tmp; \
9307 } \
9308} while (false)
9309
9310#define check_str_len(_len) do { \
9311 if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
9312 goto fail_alloc; \
9313} while (false)
9314
9315 yyjson_val *val;
9316 yyjson_type val_type;
9317 usize ctn_len, ctn_len_tmp;
9318 bool ctn_obj, ctn_obj_tmp, is_key;
9319 u8 *hdr, *cur, *end, *tmp;
9320 yyjson_write_ctx *ctx, *ctx_tmp;
9321 usize alc_len, alc_inc, ctx_len, ext_len, str_len;
9322 const u8 *str_ptr;
9323 const char_enc_type *enc_table = get_enc_table_with_flag(flg);
9324 const u8 *hex_table = get_hex_table_with_flag(flg);
9325 bool cpy = (enc_table == enc_table_cpy);
9326 bool esc = has_flg(ESCAPE_UNICODE) != 0;
9327 bool inv = has_allow(INVALID_UNICODE) != 0;
9328 bool newline = has_flg(NEWLINE_AT_END) != 0;
9329
9330 if (buf) {
9331 hdr = (u8 *)buf;
9332 alc_len = *dat_len;
9333 alc_len = size_align_down(alc_len, sizeof(yyjson_write_ctx));
9334 if (alc_len <= sizeof(yyjson_write_ctx)) goto fail_alloc;
9335 } else {
9336 alc_len = root->uni.ofs / sizeof(yyjson_val);
9337 alc_len = alc_len * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64;
9338 alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx));
9339 hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
9340 if (!hdr) goto fail_alloc;
9341 }
9342 cur = hdr;
9343 end = hdr + alc_len;
9344 ctx = (yyjson_write_ctx *)(void *)end;
9345
9346doc_begin:
9347 val = constcast(yyjson_val *)root;
9348 val_type = unsafe_yyjson_get_type(val);
9349 ctn_obj = (val_type == YYJSON_TYPE_OBJ);
9350 ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
9351 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9352 val++;
9353
9354val_begin:
9355 val_type = unsafe_yyjson_get_type(val);
9356 if (val_type == YYJSON_TYPE_STR) {
9357 is_key = ((u8)ctn_obj & (u8)~ctn_len);
9358 str_len = unsafe_yyjson_get_len(val);
9359 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9360 check_str_len(str_len);
9361 incr_len(str_len * 6 + 16);
9362 if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
9363 cur = write_str_noesc(cur, str_ptr, str_len);
9364 } else {
9365 cur = write_str(cur, esc, inv, str_ptr, str_len,
9366 enc_table, hex_table);
9367 if (unlikely(!cur)) goto fail_str;
9368 }
9369 *cur++ = is_key ? ':' : ',';
9370 goto val_end;
9371 }
9372 if (val_type == YYJSON_TYPE_NUM) {
9374 cur = write_num(cur, val, flg);
9375 if (unlikely(!cur)) goto fail_num;
9376 *cur++ = ',';
9377 goto val_end;
9378 }
9379 if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
9381 ctn_len_tmp = unsafe_yyjson_get_len(val);
9382 ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
9383 incr_len(2 * sizeof(*ctx));
9384 if (unlikely(ctn_len_tmp == 0)) {
9385 /* write empty container */
9386 *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
9387 *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
9388 *cur++ = ',';
9389 goto val_end;
9390 } else {
9391 /* push context, setup new container */
9392 yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj);
9393 ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
9394 ctn_obj = ctn_obj_tmp;
9395 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9396 val++;
9397 goto val_begin;
9398 }
9399 }
9400 if (val_type == YYJSON_TYPE_BOOL) {
9401 incr_len(16);
9402 cur = write_bool(cur, unsafe_yyjson_get_bool(val));
9403 cur++;
9404 goto val_end;
9405 }
9406 if (val_type == YYJSON_TYPE_NULL) {
9407 incr_len(16);
9408 cur = write_null(cur);
9409 cur++;
9410 goto val_end;
9411 }
9412 if (val_type == YYJSON_TYPE_RAW) {
9413 str_len = unsafe_yyjson_get_len(val);
9414 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9415 check_str_len(str_len);
9416 incr_len(str_len + 2);
9417 cur = write_raw(cur, str_ptr, str_len);
9418 *cur++ = ',';
9419 goto val_end;
9420 }
9421 goto fail_type;
9422
9423val_end:
9424 val++;
9425 ctn_len--;
9426 if (unlikely(ctn_len == 0)) goto ctn_end;
9427 goto val_begin;
9428
9429ctn_end:
9430 cur--;
9431 *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
9432 *cur++ = ',';
9433 if (unlikely((u8 *)ctx >= end)) goto doc_end;
9434 yyjson_write_ctx_get(ctx++, &ctn_len, &ctn_obj);
9435 ctn_len--;
9436 if (likely(ctn_len > 0)) {
9437 goto val_begin;
9438 } else {
9439 goto ctn_end;
9440 }
9441
9442doc_end:
9443 if (newline) {
9444 incr_len(2);
9445 *(cur - 1) = '\n';
9446 cur++;
9447 }
9448 *--cur = '\0';
9449 *dat_len = (usize)(cur - hdr);
9450 memset(err, 0, sizeof(yyjson_write_err));
9451 return hdr;
9452
9453fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
9454fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
9455fail_num: return_err(NAN_OR_INF, MSG_NAN_INF);
9456fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8);
9457
9458#undef return_err
9459#undef incr_len
9460#undef check_str_len
9461}
9462
9463/** Write JSON document pretty.
9464 The root of this document should be a non-empty container. */
9466 const yyjson_write_flag flg,
9467 const yyjson_alc alc,
9468 char *buf, usize *dat_len,
9469 yyjson_write_err *err) {
9470#define return_err(_code, _msg) do { \
9471 *dat_len = 0; \
9472 err->code = YYJSON_WRITE_ERROR_##_code; \
9473 err->msg = _msg; \
9474 if (hdr) alc.free(alc.ctx, hdr); \
9475 return NULL; \
9476} while (false)
9477
9478#define incr_len(_len) do { \
9479 ext_len = (usize)(_len); \
9480 if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
9481 usize ctx_pos = (usize)((u8 *)ctx - hdr); \
9482 usize cur_pos = (usize)(cur - hdr); \
9483 yyjson_assume((u8 *)ctx <= (u8 *)end); \
9484 ctx_len = (usize)((u8 *)end - (u8 *)ctx); \
9485 alc_inc = yyjson_max(alc_len / 2, ext_len); \
9486 alc_inc = size_align_up(alc_inc, sizeof(yyjson_write_ctx)); \
9487 if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
9488 goto fail_alloc; \
9489 alc_len += alc_inc; \
9490 tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
9491 if (unlikely(!tmp)) goto fail_alloc; \
9492 ctx_tmp = (yyjson_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
9493 memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
9494 ctx = ctx_tmp; \
9495 cur = tmp + cur_pos; \
9496 end = tmp + alc_len; \
9497 hdr = tmp; \
9498 } \
9499} while (false)
9500
9501#define check_str_len(_len) do { \
9502 if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
9503 goto fail_alloc; \
9504} while (false)
9505
9506 yyjson_val *val;
9507 yyjson_type val_type;
9508 usize ctn_len, ctn_len_tmp;
9509 bool ctn_obj, ctn_obj_tmp, is_key, no_indent;
9510 u8 *hdr, *cur, *end, *tmp;
9511 yyjson_write_ctx *ctx, *ctx_tmp;
9512 usize alc_len, alc_inc, ctx_len, ext_len, str_len, level;
9513 const u8 *str_ptr;
9514 const char_enc_type *enc_table = get_enc_table_with_flag(flg);
9515 const u8 *hex_table = get_hex_table_with_flag(flg);
9516 bool cpy = (enc_table == enc_table_cpy);
9517 bool esc = has_flg(ESCAPE_UNICODE) != 0;
9518 bool inv = has_allow(INVALID_UNICODE) != 0;
9519 usize spaces = has_flg(PRETTY_TWO_SPACES) ? 2 : 4;
9520 bool newline = has_flg(NEWLINE_AT_END) != 0;
9521
9522 if (buf) {
9523 hdr = (u8 *)buf;
9524 alc_len = *dat_len;
9525 alc_len = size_align_down(alc_len, sizeof(yyjson_write_ctx));
9526 if (alc_len <= sizeof(yyjson_write_ctx)) goto fail_alloc;
9527 } else {
9528 alc_len = root->uni.ofs / sizeof(yyjson_val);
9529 alc_len = alc_len * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64;
9530 alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx));
9531 hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
9532 if (!hdr) goto fail_alloc;
9533 }
9534 cur = hdr;
9535 end = hdr + alc_len;
9536 ctx = (yyjson_write_ctx *)(void *)end;
9537
9538doc_begin:
9539 val = constcast(yyjson_val *)root;
9540 val_type = unsafe_yyjson_get_type(val);
9541 ctn_obj = (val_type == YYJSON_TYPE_OBJ);
9542 ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
9543 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9544 *cur++ = '\n';
9545 val++;
9546 level = 1;
9547
9548val_begin:
9549 val_type = unsafe_yyjson_get_type(val);
9550 if (val_type == YYJSON_TYPE_STR) {
9551 is_key = (bool)((u8)ctn_obj & (u8)~ctn_len);
9552 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9553 str_len = unsafe_yyjson_get_len(val);
9554 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9555 check_str_len(str_len);
9556 if ((sizeof(usize) < 8) && !no_indent &&
9557 level > (USIZE_MAX - 16 - str_len * 6) / 4) goto fail_alloc;
9558 incr_len(str_len * 6 + 16 + (no_indent ? 0 : level * 4));
9559 cur = write_indent(cur, no_indent ? 0 : level, spaces);
9560 if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
9561 cur = write_str_noesc(cur, str_ptr, str_len);
9562 } else {
9563 cur = write_str(cur, esc, inv, str_ptr, str_len,
9564 enc_table, hex_table);
9565 if (unlikely(!cur)) goto fail_str;
9566 }
9567 *cur++ = is_key ? ':' : ',';
9568 *cur++ = is_key ? ' ' : '\n';
9569 goto val_end;
9570 }
9571 if (val_type == YYJSON_TYPE_NUM) {
9572 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9573 incr_len(FP_BUF_LEN + (no_indent ? 0 : level * 4));
9574 cur = write_indent(cur, no_indent ? 0 : level, spaces);
9575 cur = write_num(cur, val, flg);
9576 if (unlikely(!cur)) goto fail_num;
9577 *cur++ = ',';
9578 *cur++ = '\n';
9579 goto val_end;
9580 }
9581 if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
9583 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9584 ctn_len_tmp = unsafe_yyjson_get_len(val);
9585 ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
9586 incr_len(2 * sizeof(*ctx) + (no_indent ? 0 : level * 4));
9587 if (unlikely(ctn_len_tmp == 0)) {
9588 /* write empty container */
9589 cur = write_indent(cur, no_indent ? 0 : level, spaces);
9590 *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
9591 *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
9592 *cur++ = ',';
9593 *cur++ = '\n';
9594 goto val_end;
9595 } else {
9596 /* push context, setup new container */
9597 yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj);
9598 ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
9599 ctn_obj = ctn_obj_tmp;
9600 cur = write_indent(cur, no_indent ? 0 : level, spaces);
9601 level++;
9602 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9603 *cur++ = '\n';
9604 val++;
9605 goto val_begin;
9606 }
9607 }
9608 if (val_type == YYJSON_TYPE_BOOL) {
9609 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9610 incr_len(16 + (no_indent ? 0 : level * 4));
9611 cur = write_indent(cur, no_indent ? 0 : level, spaces);
9612 cur = write_bool(cur, unsafe_yyjson_get_bool(val));
9613 cur += 2;
9614 goto val_end;
9615 }
9616 if (val_type == YYJSON_TYPE_NULL) {
9617 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9618 incr_len(16 + (no_indent ? 0 : level * 4));
9619 cur = write_indent(cur, no_indent ? 0 : level, spaces);
9620 cur = write_null(cur);
9621 cur += 2;
9622 goto val_end;
9623 }
9624 if (val_type == YYJSON_TYPE_RAW) {
9625 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
9626 str_len = unsafe_yyjson_get_len(val);
9627 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9628 check_str_len(str_len);
9629 incr_len(str_len + 3 + (no_indent ? 0 : level * 4));
9630 cur = write_indent(cur, no_indent ? 0 : level, spaces);
9631 cur = write_raw(cur, str_ptr, str_len);
9632 *cur++ = ',';
9633 *cur++ = '\n';
9634 goto val_end;
9635 }
9636 goto fail_type;
9637
9638val_end:
9639 val++;
9640 ctn_len--;
9641 if (unlikely(ctn_len == 0)) goto ctn_end;
9642 goto val_begin;
9643
9644ctn_end:
9645 cur -= 2;
9646 *cur++ = '\n';
9647 incr_len(level * 4);
9648 cur = write_indent(cur, --level, spaces);
9649 *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
9650 if (unlikely((u8 *)ctx >= end)) goto doc_end;
9651 yyjson_write_ctx_get(ctx++, &ctn_len, &ctn_obj);
9652 ctn_len--;
9653 *cur++ = ',';
9654 *cur++ = '\n';
9655 if (likely(ctn_len > 0)) {
9656 goto val_begin;
9657 } else {
9658 goto ctn_end;
9659 }
9660
9661doc_end:
9662 if (newline) {
9663 incr_len(2);
9664 *cur++ = '\n';
9665 }
9666 *cur = '\0';
9667 *dat_len = (usize)(cur - hdr);
9668 memset(err, 0, sizeof(yyjson_write_err));
9669 return hdr;
9670
9671fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
9672fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
9673fail_num: return_err(NAN_OR_INF, MSG_NAN_INF);
9674fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8);
9675
9676#undef return_err
9677#undef incr_len
9678#undef check_str_len
9679}
9680
9681static char *write_root(const yyjson_val *val,
9683 const yyjson_alc *alc_ptr,
9684 char *buf, usize *dat_len,
9685 yyjson_write_err *err) {
9686 yyjson_write_err tmp_err;
9687 usize tmp_dat_len;
9688 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
9689 yyjson_val *root = constcast(yyjson_val *)val;
9690
9691 if (!err) err = &tmp_err;
9692 if (!dat_len) dat_len = &tmp_dat_len;
9693
9694 if (unlikely(!root)) {
9695 *dat_len = 0;
9696 err->msg = "input JSON is NULL";
9698 return NULL;
9699 }
9700
9701 if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) {
9702 return (char *)write_root_single(root, flg, alc, buf, dat_len, err);
9704 return (char *)write_root_pretty(root, flg, alc, buf, dat_len, err);
9705 } else {
9706 return (char *)write_root_minify(root, flg, alc, buf, dat_len, err);
9707 }
9708}
9709
9710
9711
9712/*==============================================================================
9713 * MARK: - JSON Writer (Public)
9714 *============================================================================*/
9715
9718 const yyjson_alc *alc_ptr,
9719 usize *dat_len,
9720 yyjson_write_err *err) {
9721 return write_root(val, flg, alc_ptr, NULL, dat_len, err);
9722}
9723
9726 const yyjson_alc *alc_ptr,
9727 usize *dat_len,
9728 yyjson_write_err *err) {
9729 yyjson_val *root = doc ? doc->root : NULL;
9730 return write_root(root, flg, alc_ptr, NULL, dat_len, err);
9731}
9732
9733#if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE
9734
9735bool yyjson_val_write_file(const char *path,
9736 const yyjson_val *val,
9738 const yyjson_alc *alc_ptr,
9739 yyjson_write_err *err) {
9740 yyjson_write_err tmp_err;
9741 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
9742 u8 *dat;
9743 usize dat_len = 0;
9744 yyjson_val *root = constcast(yyjson_val *)val;
9745 bool suc;
9746
9747 if (!err) err = &tmp_err;
9748 if (unlikely(!path || !*path)) {
9749 err->msg = "input path is invalid";
9751 return false;
9752 }
9753
9754 dat = (u8 *)write_root(root, flg, &alc, NULL, &dat_len, err);
9755 if (unlikely(!dat)) return false;
9756 suc = write_dat_to_file(path, dat, dat_len, err);
9757 alc.free(alc.ctx, dat);
9758 return suc;
9759}
9760
9762 const yyjson_val *val,
9764 const yyjson_alc *alc_ptr,
9765 yyjson_write_err *err) {
9766 yyjson_write_err tmp_err;
9767 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
9768 u8 *dat;
9769 usize dat_len = 0;
9770 yyjson_val *root = constcast(yyjson_val *)val;
9771 bool suc;
9772
9773 if (!err) err = &tmp_err;
9774 if (unlikely(!fp)) {
9775 err->msg = "input fp is invalid";
9777 return false;
9778 }
9779
9780 dat = (u8 *)write_root(root, flg, &alc, NULL, &dat_len, err);
9781 if (unlikely(!dat)) return false;
9782 suc = write_dat_to_fp(fp, dat, dat_len, err);
9783 alc.free(alc.ctx, dat);
9784 return suc;
9785}
9786
9787bool yyjson_write_file(const char *path,
9788 const yyjson_doc *doc,
9790 const yyjson_alc *alc_ptr,
9791 yyjson_write_err *err) {
9792 yyjson_val *root = doc ? doc->root : NULL;
9793 return yyjson_val_write_file(path, root, flg, alc_ptr, err);
9794}
9795
9796bool yyjson_write_fp(FILE *fp,
9797 const yyjson_doc *doc,
9799 const yyjson_alc *alc_ptr,
9800 yyjson_write_err *err) {
9801 yyjson_val *root = doc ? doc->root : NULL;
9802 return yyjson_val_write_fp(fp, root, flg, alc_ptr, err);
9803}
9804
9805#endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */
9806
9807size_t yyjson_val_write_buf(char *buf, size_t buf_len,
9808 const yyjson_val *val,
9810 yyjson_write_err *err) {
9811 if (unlikely(!buf || !buf_len)) {
9813 if (err) err->msg = "input buf or buf_len is invalid";
9814 return 0;
9815 } else {
9816 write_root(val, flg, &YYJSON_NULL_ALC, buf, &buf_len, err);
9817 return buf_len;
9818 }
9819}
9820
9821size_t yyjson_write_buf(char *buf, size_t buf_len,
9822 const yyjson_doc *doc,
9824 yyjson_write_err *err) {
9825 yyjson_val *root = doc ? doc->root : NULL;
9826 return yyjson_val_write_buf(buf, buf_len, root, flg, err);
9827}
9828
9829
9830
9831/*==============================================================================
9832 * MARK: - Mutable JSON Writer Implementation (Private)
9833 *============================================================================*/
9834
9839
9841 yyjson_mut_val *ctn,
9842 usize size, bool is_obj) {
9843 ctx->tag = (size << 1) | (usize)is_obj;
9844 ctx->ctn = ctn;
9845}
9846
9848 yyjson_mut_val **ctn,
9849 usize *size, bool *is_obj) {
9850 usize tag = ctx->tag;
9851 *size = tag >> 1;
9852 *is_obj = (bool)(tag & 1);
9853 *ctn = ctx->ctn;
9854}
9855
9856/** Get the estimated number of values for the mutable JSON document. */
9858 const yyjson_mut_doc *doc) {
9859 usize sum = 0;
9860 yyjson_val_chunk *chunk = doc->val_pool.chunks;
9861 while (chunk) {
9862 sum += chunk->chunk_size / sizeof(yyjson_mut_val) - 1;
9863 if (chunk == doc->val_pool.chunks) {
9864 sum -= (usize)(doc->val_pool.end - doc->val_pool.cur);
9865 }
9866 chunk = chunk->next;
9867 }
9868 return sum;
9869}
9870
9871/** Write single JSON value. */
9874 yyjson_alc alc,
9875 char *buf, usize *dat_len,
9876 yyjson_write_err *err) {
9877 return write_root_single((yyjson_val *)val, flg, alc, buf, dat_len, err);
9878}
9879
9880/** Write JSON document minify.
9881 The root of this document should be a non-empty container. */
9883 usize estimated_val_num,
9885 yyjson_alc alc,
9886 char *buf, usize *dat_len,
9887 yyjson_write_err *err) {
9888#define return_err(_code, _msg) do { \
9889 *dat_len = 0; \
9890 err->code = YYJSON_WRITE_ERROR_##_code; \
9891 err->msg = _msg; \
9892 if (hdr) alc.free(alc.ctx, hdr); \
9893 return NULL; \
9894} while (false)
9895
9896#define incr_len(_len) do { \
9897 ext_len = (usize)(_len); \
9898 if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
9899 usize ctx_pos = (usize)((u8 *)ctx - hdr); \
9900 usize cur_pos = (usize)(cur - hdr); \
9901 yyjson_assume((u8 *)ctx <= (u8 *)end); \
9902 ctx_len = (usize)((u8 *)end - (u8 *)ctx); \
9903 alc_inc = yyjson_max(alc_len / 2, ext_len); \
9904 alc_inc = size_align_up(alc_inc, sizeof(yyjson_mut_write_ctx)); \
9905 if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
9906 goto fail_alloc; \
9907 alc_len += alc_inc; \
9908 tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
9909 if (unlikely(!tmp)) goto fail_alloc; \
9910 ctx_tmp = (yyjson_mut_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
9911 memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
9912 ctx = ctx_tmp; \
9913 cur = tmp + cur_pos; \
9914 end = tmp + alc_len; \
9915 hdr = tmp; \
9916 } \
9917} while (false)
9918
9919#define check_str_len(_len) do { \
9920 if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
9921 goto fail_alloc; \
9922} while (false)
9923
9924 yyjson_mut_val *val, *ctn;
9925 yyjson_type val_type;
9926 usize ctn_len, ctn_len_tmp;
9927 bool ctn_obj, ctn_obj_tmp, is_key;
9928 u8 *hdr, *cur, *end, *tmp;
9929 yyjson_mut_write_ctx *ctx, *ctx_tmp;
9930 usize alc_len, alc_inc, ctx_len, ext_len, str_len;
9931 const u8 *str_ptr;
9932 const char_enc_type *enc_table = get_enc_table_with_flag(flg);
9933 const u8 *hex_table = get_hex_table_with_flag(flg);
9934 bool cpy = (enc_table == enc_table_cpy);
9935 bool esc = has_flg(ESCAPE_UNICODE) != 0;
9936 bool inv = has_allow(INVALID_UNICODE) != 0;
9937 bool newline = has_flg(NEWLINE_AT_END) != 0;
9938
9939 if (buf) {
9940 hdr = (u8 *)buf;
9941 alc_len = *dat_len;
9942 alc_len = size_align_down(alc_len, sizeof(yyjson_mut_write_ctx));
9943 if (alc_len <= sizeof(yyjson_mut_write_ctx)) goto fail_alloc;
9944 } else {
9945 alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64;
9946 alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx));
9947 hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
9948 if (!hdr) goto fail_alloc;
9949 }
9950 cur = hdr;
9951 end = hdr + alc_len;
9952 ctx = (yyjson_mut_write_ctx *)(void *)end;
9953
9954doc_begin:
9955 val = constcast(yyjson_mut_val *)root;
9956 val_type = unsafe_yyjson_get_type(val);
9957 ctn_obj = (val_type == YYJSON_TYPE_OBJ);
9958 ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
9959 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
9960 ctn = val;
9961 val = (yyjson_mut_val *)val->uni.ptr; /* tail */
9962 val = ctn_obj ? val->next->next : val->next;
9963
9964val_begin:
9965 val_type = unsafe_yyjson_get_type(val);
9966 if (val_type == YYJSON_TYPE_STR) {
9967 is_key = ((u8)ctn_obj & (u8)~ctn_len);
9968 str_len = unsafe_yyjson_get_len(val);
9969 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
9970 check_str_len(str_len);
9971 incr_len(str_len * 6 + 16);
9972 if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
9973 cur = write_str_noesc(cur, str_ptr, str_len);
9974 } else {
9975 cur = write_str(cur, esc, inv, str_ptr, str_len,
9976 enc_table, hex_table);
9977 if (unlikely(!cur)) goto fail_str;
9978 }
9979 *cur++ = is_key ? ':' : ',';
9980 goto val_end;
9981 }
9982 if (val_type == YYJSON_TYPE_NUM) {
9984 cur = write_num(cur, (yyjson_val *)val, flg);
9985 if (unlikely(!cur)) goto fail_num;
9986 *cur++ = ',';
9987 goto val_end;
9988 }
9989 if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
9991 ctn_len_tmp = unsafe_yyjson_get_len(val);
9992 ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
9993 incr_len(2 * sizeof(*ctx));
9994 if (unlikely(ctn_len_tmp == 0)) {
9995 /* write empty container */
9996 *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
9997 *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
9998 *cur++ = ',';
9999 goto val_end;
10000 } else {
10001 /* push context, setup new container */
10002 yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj);
10003 ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
10004 ctn_obj = ctn_obj_tmp;
10005 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
10006 ctn = val;
10007 val = (yyjson_mut_val *)ctn->uni.ptr; /* tail */
10008 val = ctn_obj ? val->next->next : val->next;
10009 goto val_begin;
10010 }
10011 }
10012 if (val_type == YYJSON_TYPE_BOOL) {
10013 incr_len(16);
10014 cur = write_bool(cur, unsafe_yyjson_get_bool(val));
10015 cur++;
10016 goto val_end;
10017 }
10018 if (val_type == YYJSON_TYPE_NULL) {
10019 incr_len(16);
10020 cur = write_null(cur);
10021 cur++;
10022 goto val_end;
10023 }
10024 if (val_type == YYJSON_TYPE_RAW) {
10025 str_len = unsafe_yyjson_get_len(val);
10026 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
10027 check_str_len(str_len);
10028 incr_len(str_len + 2);
10029 cur = write_raw(cur, str_ptr, str_len);
10030 *cur++ = ',';
10031 goto val_end;
10032 }
10033 goto fail_type;
10034
10035val_end:
10036 ctn_len--;
10037 if (unlikely(ctn_len == 0)) goto ctn_end;
10038 val = val->next;
10039 goto val_begin;
10040
10041ctn_end:
10042 cur--;
10043 *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
10044 *cur++ = ',';
10045 if (unlikely((u8 *)ctx >= end)) goto doc_end;
10046 val = ctn->next;
10047 yyjson_mut_write_ctx_get(ctx++, &ctn, &ctn_len, &ctn_obj);
10048 ctn_len--;
10049 if (likely(ctn_len > 0)) {
10050 goto val_begin;
10051 } else {
10052 goto ctn_end;
10053 }
10054
10055doc_end:
10056 if (newline) {
10057 incr_len(2);
10058 *(cur - 1) = '\n';
10059 cur++;
10060 }
10061 *--cur = '\0';
10062 *dat_len = (usize)(cur - hdr);
10064 err->msg = NULL;
10065 return hdr;
10066
10067fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
10068fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
10069fail_num: return_err(NAN_OR_INF, MSG_NAN_INF);
10070fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8);
10071
10072#undef return_err
10073#undef incr_len
10074#undef check_str_len
10075}
10076
10077/** Write JSON document pretty.
10078 The root of this document should be a non-empty container. */
10080 usize estimated_val_num,
10082 yyjson_alc alc,
10083 char *buf, usize *dat_len,
10084 yyjson_write_err *err) {
10085#define return_err(_code, _msg) do { \
10086 *dat_len = 0; \
10087 err->code = YYJSON_WRITE_ERROR_##_code; \
10088 err->msg = _msg; \
10089 if (hdr) alc.free(alc.ctx, hdr); \
10090 return NULL; \
10091} while (false)
10092
10093#define incr_len(_len) do { \
10094 ext_len = (usize)(_len); \
10095 if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
10096 usize ctx_pos = (usize)((u8 *)ctx - hdr); \
10097 usize cur_pos = (usize)(cur - hdr); \
10098 yyjson_assume((u8 *)ctx <= (u8 *)end); \
10099 ctx_len = (usize)((u8 *)end - (u8 *)ctx); \
10100 alc_inc = yyjson_max(alc_len / 2, ext_len); \
10101 alc_inc = size_align_up(alc_inc, sizeof(yyjson_mut_write_ctx)); \
10102 if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
10103 goto fail_alloc; \
10104 alc_len += alc_inc; \
10105 tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
10106 if (unlikely(!tmp)) goto fail_alloc; \
10107 ctx_tmp = (yyjson_mut_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
10108 memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
10109 ctx = ctx_tmp; \
10110 cur = tmp + cur_pos; \
10111 end = tmp + alc_len; \
10112 hdr = tmp; \
10113 } \
10114} while (false)
10115
10116#define check_str_len(_len) do { \
10117 if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
10118 goto fail_alloc; \
10119} while (false)
10120
10121 yyjson_mut_val *val, *ctn;
10122 yyjson_type val_type;
10123 usize ctn_len, ctn_len_tmp;
10124 bool ctn_obj, ctn_obj_tmp, is_key, no_indent;
10125 u8 *hdr, *cur, *end, *tmp;
10126 yyjson_mut_write_ctx *ctx, *ctx_tmp;
10127 usize alc_len, alc_inc, ctx_len, ext_len, str_len, level;
10128 const u8 *str_ptr;
10129 const char_enc_type *enc_table = get_enc_table_with_flag(flg);
10130 const u8 *hex_table = get_hex_table_with_flag(flg);
10131 bool cpy = (enc_table == enc_table_cpy);
10132 bool esc = has_flg(ESCAPE_UNICODE) != 0;
10133 bool inv = has_allow(INVALID_UNICODE) != 0;
10134 usize spaces = has_flg(PRETTY_TWO_SPACES) ? 2 : 4;
10135 bool newline = has_flg(NEWLINE_AT_END) != 0;
10136
10137 if (buf) {
10138 hdr = (u8 *)buf;
10139 alc_len = *dat_len;
10140 alc_len = size_align_down(alc_len, sizeof(yyjson_mut_write_ctx));
10141 if (alc_len <= sizeof(yyjson_mut_write_ctx)) goto fail_alloc;
10142 } else {
10143 alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64;
10144 alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx));
10145 hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
10146 if (!hdr) goto fail_alloc;
10147 }
10148 cur = hdr;
10149 end = hdr + alc_len;
10150 ctx = (yyjson_mut_write_ctx *)(void *)end;
10151
10152doc_begin:
10153 val = constcast(yyjson_mut_val *)root;
10154 val_type = unsafe_yyjson_get_type(val);
10155 ctn_obj = (val_type == YYJSON_TYPE_OBJ);
10156 ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
10157 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
10158 *cur++ = '\n';
10159 ctn = val;
10160 val = (yyjson_mut_val *)val->uni.ptr; /* tail */
10161 val = ctn_obj ? val->next->next : val->next;
10162 level = 1;
10163
10164val_begin:
10165 val_type = unsafe_yyjson_get_type(val);
10166 if (val_type == YYJSON_TYPE_STR) {
10167 is_key = (bool)((u8)ctn_obj & (u8)~ctn_len);
10168 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10169 str_len = unsafe_yyjson_get_len(val);
10170 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
10171 check_str_len(str_len);
10172 if ((sizeof(usize) < 8) && !no_indent &&
10173 level > (USIZE_MAX - 16 - str_len * 6) / 4) goto fail_alloc;
10174 incr_len(str_len * 6 + 16 + (no_indent ? 0 : level * 4));
10175 cur = write_indent(cur, no_indent ? 0 : level, spaces);
10176 if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
10177 cur = write_str_noesc(cur, str_ptr, str_len);
10178 } else {
10179 cur = write_str(cur, esc, inv, str_ptr, str_len,
10180 enc_table, hex_table);
10181 if (unlikely(!cur)) goto fail_str;
10182 }
10183 *cur++ = is_key ? ':' : ',';
10184 *cur++ = is_key ? ' ' : '\n';
10185 goto val_end;
10186 }
10187 if (val_type == YYJSON_TYPE_NUM) {
10188 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10189 incr_len(FP_BUF_LEN + (no_indent ? 0 : level * 4));
10190 cur = write_indent(cur, no_indent ? 0 : level, spaces);
10191 cur = write_num(cur, (yyjson_val *)val, flg);
10192 if (unlikely(!cur)) goto fail_num;
10193 *cur++ = ',';
10194 *cur++ = '\n';
10195 goto val_end;
10196 }
10197 if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
10199 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10200 ctn_len_tmp = unsafe_yyjson_get_len(val);
10201 ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
10202 incr_len(2 * sizeof(*ctx) + (no_indent ? 0 : level * 4));
10203 if (unlikely(ctn_len_tmp == 0)) {
10204 /* write empty container */
10205 cur = write_indent(cur, no_indent ? 0 : level, spaces);
10206 *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
10207 *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
10208 *cur++ = ',';
10209 *cur++ = '\n';
10210 goto val_end;
10211 } else {
10212 /* push context, setup new container */
10213 yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj);
10214 ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
10215 ctn_obj = ctn_obj_tmp;
10216 cur = write_indent(cur, no_indent ? 0 : level, spaces);
10217 level++;
10218 *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
10219 *cur++ = '\n';
10220 ctn = val;
10221 val = (yyjson_mut_val *)ctn->uni.ptr; /* tail */
10222 val = ctn_obj ? val->next->next : val->next;
10223 goto val_begin;
10224 }
10225 }
10226 if (val_type == YYJSON_TYPE_BOOL) {
10227 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10228 incr_len(16 + (no_indent ? 0 : level * 4));
10229 cur = write_indent(cur, no_indent ? 0 : level, spaces);
10230 cur = write_bool(cur, unsafe_yyjson_get_bool(val));
10231 cur += 2;
10232 goto val_end;
10233 }
10234 if (val_type == YYJSON_TYPE_NULL) {
10235 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10236 incr_len(16 + (no_indent ? 0 : level * 4));
10237 cur = write_indent(cur, no_indent ? 0 : level, spaces);
10238 cur = write_null(cur);
10239 cur += 2;
10240 goto val_end;
10241 }
10242 if (val_type == YYJSON_TYPE_RAW) {
10243 no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10244 str_len = unsafe_yyjson_get_len(val);
10245 str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
10246 check_str_len(str_len);
10247 incr_len(str_len + 3 + (no_indent ? 0 : level * 4));
10248 cur = write_indent(cur, no_indent ? 0 : level, spaces);
10249 cur = write_raw(cur, str_ptr, str_len);
10250 *cur++ = ',';
10251 *cur++ = '\n';
10252 goto val_end;
10253 }
10254 goto fail_type;
10255
10256val_end:
10257 ctn_len--;
10258 if (unlikely(ctn_len == 0)) goto ctn_end;
10259 val = val->next;
10260 goto val_begin;
10261
10262ctn_end:
10263 cur -= 2;
10264 *cur++ = '\n';
10265 incr_len(level * 4);
10266 cur = write_indent(cur, --level, spaces);
10267 *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
10268 if (unlikely((u8 *)ctx >= end)) goto doc_end;
10269 val = ctn->next;
10270 yyjson_mut_write_ctx_get(ctx++, &ctn, &ctn_len, &ctn_obj);
10271 ctn_len--;
10272 *cur++ = ',';
10273 *cur++ = '\n';
10274 if (likely(ctn_len > 0)) {
10275 goto val_begin;
10276 } else {
10277 goto ctn_end;
10278 }
10279
10280doc_end:
10281 if (newline) {
10282 incr_len(2);
10283 *cur++ = '\n';
10284 }
10285 *cur = '\0';
10286 *dat_len = (usize)(cur - hdr);
10288 err->msg = NULL;
10289 return hdr;
10290
10291fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
10292fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
10293fail_num: return_err(NAN_OR_INF, MSG_NAN_INF);
10294fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8);
10295
10296#undef return_err
10297#undef incr_len
10298#undef check_str_len
10299}
10300
10301static char *mut_write_root(const yyjson_mut_val *val,
10302 usize estimated_val_num,
10304 const yyjson_alc *alc_ptr,
10305 char *buf, usize *dat_len,
10306 yyjson_write_err *err) {
10307 yyjson_write_err tmp_err;
10308 usize tmp_dat_len;
10309 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
10311
10312 if (!err) err = &tmp_err;
10313 if (!dat_len) dat_len = &tmp_dat_len;
10314
10315 if (unlikely(!root)) {
10316 *dat_len = 0;
10317 err->msg = "input JSON is NULL";
10319 return NULL;
10320 }
10321
10322 if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) {
10323 return (char *)mut_write_root_single(root, flg, alc, buf, dat_len, err);
10325 return (char *)mut_write_root_pretty(root, estimated_val_num,
10326 flg, alc, buf, dat_len, err);
10327 } else {
10328 return (char *)mut_write_root_minify(root, estimated_val_num,
10329 flg, alc, buf, dat_len, err);
10330 }
10331}
10332
10333
10334
10335/*==============================================================================
10336 * MARK: - Mutable JSON Writer (Public)
10337 *============================================================================*/
10338
10341 const yyjson_alc *alc_ptr,
10342 usize *dat_len,
10343 yyjson_write_err *err) {
10344 return mut_write_root(val, 0, flg, alc_ptr, NULL, dat_len, err);
10345}
10346
10349 const yyjson_alc *alc_ptr,
10350 usize *dat_len,
10351 yyjson_write_err *err) {
10352 yyjson_mut_val *root;
10353 usize estimated_val_num;
10354 if (likely(doc)) {
10355 root = doc->root;
10356 estimated_val_num = yyjson_mut_doc_estimated_val_num(doc);
10357 } else {
10358 root = NULL;
10359 estimated_val_num = 0;
10360 }
10361 return mut_write_root(root, estimated_val_num,
10362 flg, alc_ptr, NULL, dat_len, err);
10363}
10364
10365size_t yyjson_mut_val_write_buf(char *buf, size_t buf_len,
10366 const yyjson_mut_val *val,
10368 yyjson_write_err *err) {
10369 if (unlikely(!buf || !buf_len)) {
10371 if (err) err->msg = "input buf or buf_len is invalid";
10372 return 0;
10373 } else {
10374 mut_write_root(val, 0, flg, &YYJSON_NULL_ALC, buf, &buf_len, err);
10375 return buf_len;
10376 }
10377}
10378
10379size_t yyjson_mut_write_buf(char *buf, size_t buf_len,
10380 const yyjson_mut_doc *doc,
10382 yyjson_write_err *err) {
10383 yyjson_mut_val *root = doc ? doc->root : NULL;
10384 return yyjson_mut_val_write_buf(buf, buf_len, root, flg, err);
10385}
10386
10387#if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE
10388
10389bool yyjson_mut_val_write_file(const char *path,
10390 const yyjson_mut_val *val,
10392 const yyjson_alc *alc_ptr,
10393 yyjson_write_err *err) {
10394 yyjson_write_err tmp_err;
10395 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
10396 u8 *dat;
10397 usize dat_len = 0;
10399 bool suc;
10400
10401 if (!err) err = &tmp_err;
10402 if (unlikely(!path || !*path)) {
10403 err->msg = "input path is invalid";
10405 return false;
10406 }
10407
10408 dat = (u8 *)yyjson_mut_val_write_opts(root, flg, &alc, &dat_len, err);
10409 if (unlikely(!dat)) return false;
10410 suc = write_dat_to_file(path, dat, dat_len, err);
10411 alc.free(alc.ctx, dat);
10412 return suc;
10413}
10414
10416 const yyjson_mut_val *val,
10418 const yyjson_alc *alc_ptr,
10419 yyjson_write_err *err) {
10420 yyjson_write_err tmp_err;
10421 yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
10422 u8 *dat;
10423 usize dat_len = 0;
10425 bool suc;
10426
10427 if (!err) err = &tmp_err;
10428 if (unlikely(!fp)) {
10429 err->msg = "input fp is invalid";
10431 return false;
10432 }
10433
10434 dat = (u8 *)yyjson_mut_val_write_opts(root, flg, &alc, &dat_len, err);
10435 if (unlikely(!dat)) return false;
10436 suc = write_dat_to_fp(fp, dat, dat_len, err);
10437 alc.free(alc.ctx, dat);
10438 return suc;
10439}
10440
10441bool yyjson_mut_write_file(const char *path,
10442 const yyjson_mut_doc *doc,
10444 const yyjson_alc *alc_ptr,
10445 yyjson_write_err *err) {
10446 yyjson_mut_val *root = doc ? doc->root : NULL;
10447 return yyjson_mut_val_write_file(path, root, flg, alc_ptr, err);
10448}
10449
10451 const yyjson_mut_doc *doc,
10453 const yyjson_alc *alc_ptr,
10454 yyjson_write_err *err) {
10455 yyjson_mut_val *root = doc ? doc->root : NULL;
10456 return yyjson_mut_val_write_fp(fp, root, flg, alc_ptr, err);
10457}
10458
10459#endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */
10460
10461#undef has_flg
10462#undef has_allow
10463#endif /* YYJSON_DISABLE_WRITER */
10464
10465
10466
10467#if !YYJSON_DISABLE_UTILS
10468
10469/*==============================================================================
10470 * MARK: - JSON Pointer API (RFC 6901) (Public)
10471 *============================================================================*/
10472
10473/**
10474 Get a token from JSON pointer string.
10475 @param ptr [in] string that points to current token prefix `/`
10476 [out] string that points to next token prefix `/`, or string end
10477 @param end [in] end of the entire JSON Pointer string
10478 @param len [out] unescaped token length
10479 @param esc [out] number of escaped characters in this token
10480 @return head of the token, or NULL if syntax error
10481 */
10482static_inline const char *ptr_next_token(const char **ptr, const char *end,
10483 usize *len, usize *esc) {
10484 const char *hdr = *ptr + 1;
10485 const char *cur = hdr;
10486 /* skip unescaped characters */
10487 while (cur < end && *cur != '/' && *cur != '~') cur++;
10488 if (likely(cur == end || *cur != '~')) {
10489 /* no escaped characters, return */
10490 *ptr = cur;
10491 *len = (usize)(cur - hdr);
10492 *esc = 0;
10493 return hdr;
10494 } else {
10495 /* handle escaped characters */
10496 usize esc_num = 0;
10497 while (cur < end && *cur != '/') {
10498 if (*cur++ == '~') {
10499 if (cur == end || (*cur != '0' && *cur != '1')) {
10500 *ptr = cur - 1;
10501 return NULL;
10502 }
10503 esc_num++;
10504 }
10505 }
10506 *ptr = cur;
10507 *len = (usize)(cur - hdr) - esc_num;
10508 *esc = esc_num;
10509 return hdr;
10510 }
10511}
10512
10513/**
10514 Convert token string to index.
10515 @param cur [in] token head
10516 @param len [in] token length
10517 @param idx [out] the index number, or USIZE_MAX if token is '-'
10518 @return true if token is a valid array index
10519 */
10520static_inline bool ptr_token_to_idx(const char *cur, usize len, usize *idx) {
10521 const char *end = cur + len;
10522 usize num = 0, add;
10523 if (unlikely(len == 0 || len > USIZE_SAFE_DIG)) return false;
10524 if (*cur == '0') {
10525 if (unlikely(len > 1)) return false;
10526 *idx = 0;
10527 return true;
10528 }
10529 if (*cur == '-') {
10530 if (unlikely(len > 1)) return false;
10531 *idx = USIZE_MAX;
10532 return true;
10533 }
10534 for (; cur < end && (add = (usize)((u8)*cur - (u8)'0')) <= 9; cur++) {
10535 num = num * 10 + add;
10536 }
10537 if (unlikely(num == 0 || cur < end)) return false;
10538 *idx = num;
10539 return true;
10540}
10541
10542/**
10543 Compare JSON key with token.
10544 @param key a string key (yyjson_val or yyjson_mut_val)
10545 @param token a JSON pointer token
10546 @param len unescaped token length
10547 @param esc number of escaped characters in this token
10548 @return true if `str` is equal to `token`
10549 */
10551 const char *token, usize len, usize esc) {
10552 yyjson_val *val = (yyjson_val *)key;
10553 if (unsafe_yyjson_get_len(val) != len) return false;
10554 if (likely(!esc)) {
10555 return memcmp(val->uni.str, token, len) == 0;
10556 } else {
10557 const char *str = val->uni.str;
10558 for (; len-- > 0; token++, str++) {
10559 if (*token == '~') {
10560 if (*str != (*++token == '0' ? '~' : '/')) return false;
10561 } else {
10562 if (*str != *token) return false;
10563 }
10564 }
10565 return true;
10566 }
10567}
10568
10569/**
10570 Get a value from array by token.
10571 @param arr an array, should not be NULL or non-array type
10572 @param token a JSON pointer token
10573 @param len unescaped token length
10574 @param esc number of escaped characters in this token
10575 @return value at index, or NULL if token is not index or index is out of range
10576 */
10577static_inline yyjson_val *ptr_arr_get(const yyjson_val *arr, const char *token,
10578 usize len, usize esc) {
10580 usize num = unsafe_yyjson_get_len(arr), idx = 0;
10581 if (unlikely(num == 0)) return NULL;
10582 if (unlikely(!ptr_token_to_idx(token, len, &idx))) return NULL;
10583 if (unlikely(idx >= num)) return NULL;
10584 if (unsafe_yyjson_arr_is_flat(arr)) {
10585 return val + idx;
10586 } else {
10587 while (idx-- > 0) val = unsafe_yyjson_get_next(val);
10588 return val;
10589 }
10590}
10591
10592/**
10593 Get a value from object by token.
10594 @param obj [in] an object, should not be NULL or non-object type
10595 @param token [in] a JSON pointer token
10596 @param len [in] unescaped token length
10597 @param esc [in] number of escaped characters in this token
10598 @return value associated with the token, or NULL if no value
10599 */
10600static_inline yyjson_val *ptr_obj_get(const yyjson_val *obj, const char *token,
10601 usize len, usize esc) {
10603 usize num = unsafe_yyjson_get_len(obj);
10604 if (unlikely(num == 0)) return NULL;
10605 for (; num > 0; num--, key = unsafe_yyjson_get_next(key + 1)) {
10606 if (ptr_token_eq(key, token, len, esc)) return key + 1;
10607 }
10608 return NULL;
10609}
10610
10611/**
10612 Get a value from array by token.
10613 @param arr [in] an array, should not be NULL or non-array type
10614 @param token [in] a JSON pointer token
10615 @param len [in] unescaped token length
10616 @param esc [in] number of escaped characters in this token
10617 @param pre [out] previous (sibling) value of the returned value
10618 @param last [out] whether index is last
10619 @return value at index, or NULL if token is not index or index is out of range
10620 */
10622 const char *token,
10623 usize len, usize esc,
10624 yyjson_mut_val **pre,
10625 bool *last) {
10626 yyjson_mut_val *val = (yyjson_mut_val *)arr->uni.ptr; /* last (tail) */
10627 usize num = unsafe_yyjson_get_len(arr), idx;
10628 if (last) *last = false;
10629 if (pre) *pre = NULL;
10630 if (unlikely(num == 0)) {
10631 if (last && len == 1 && (*token == '0' || *token == '-')) *last = true;
10632 return NULL;
10633 }
10634 if (unlikely(!ptr_token_to_idx(token, len, &idx))) return NULL;
10635 if (last) *last = (idx == num || idx == USIZE_MAX);
10636 if (unlikely(idx >= num)) return NULL;
10637 while (idx-- > 0) val = val->next;
10638 if (pre) *pre = val;
10639 return val->next;
10640}
10641
10642/**
10643 Get a value from object by token.
10644 @param obj [in] an object, should not be NULL or non-object type
10645 @param token [in] a JSON pointer token
10646 @param len [in] unescaped token length
10647 @param esc [in] number of escaped characters in this token
10648 @param pre [out] previous (sibling) key of the returned value's key
10649 @return value associated with the token, or NULL if no value
10650 */
10652 const char *token,
10653 usize len, usize esc,
10654 yyjson_mut_val **pre) {
10655 yyjson_mut_val *pre_key = (yyjson_mut_val *)obj->uni.ptr, *key;
10656 usize num = unsafe_yyjson_get_len(obj);
10657 if (pre) *pre = NULL;
10658 if (unlikely(num == 0)) return NULL;
10659 for (; num > 0; num--, pre_key = key) {
10660 key = pre_key->next->next;
10661 if (ptr_token_eq(key, token, len, esc)) {
10662 if (pre) *pre = pre_key;
10663 return key->next;
10664 }
10665 }
10666 return NULL;
10667}
10668
10669/**
10670 Create a string value with JSON pointer token.
10671 @param token [in] a JSON pointer token
10672 @param len [in] unescaped token length
10673 @param esc [in] number of escaped characters in this token
10674 @param doc [in] used for memory allocation when creating value
10675 @return new string value, or NULL if memory allocation failed
10676 */
10678 usize len, usize esc,
10679 yyjson_mut_doc *doc) {
10680 const char *src = token;
10681 if (likely(!esc)) {
10682 return yyjson_mut_strncpy(doc, src, len);
10683 } else {
10684 const char *end = src + len + esc;
10685 char *dst = unsafe_yyjson_mut_str_alc(doc, len + esc);
10686 char *str = dst;
10687 if (unlikely(!dst)) return NULL;
10688 for (; src < end; src++, dst++) {
10689 if (*src != '~') *dst = *src;
10690 else *dst = (*++src == '0' ? '~' : '/');
10691 }
10692 *dst = '\0';
10693 return yyjson_mut_strn(doc, str, len);
10694 }
10695}
10696
10697/* macros for yyjson_ptr */
10698#define return_err(_ret, _code, _pos, _msg) do { \
10699 if (err) { \
10700 err->code = YYJSON_PTR_ERR_##_code; \
10701 err->msg = _msg; \
10702 err->pos = (usize)(_pos); \
10703 } \
10704 return _ret; \
10705} while (false)
10706
10707#define return_err_resolve(_ret, _pos) \
10708 return_err(_ret, RESOLVE, _pos, "JSON pointer cannot be resolved")
10709#define return_err_syntax(_ret, _pos) \
10710 return_err(_ret, SYNTAX, _pos, "invalid escaped character")
10711#define return_err_alloc(_ret) \
10712 return_err(_ret, MEMORY_ALLOCATION, 0, "failed to create value")
10713
10715 const char *ptr, size_t ptr_len,
10716 yyjson_ptr_err *err) {
10717
10718 const char *hdr = ptr, *end = ptr + ptr_len, *token;
10719 usize len, esc;
10720 yyjson_type type;
10721
10722 while (true) {
10723 token = ptr_next_token(&ptr, end, &len, &esc);
10724 if (unlikely(!token)) return_err_syntax(NULL, ptr - hdr);
10725 type = unsafe_yyjson_get_type(val);
10726 if (type == YYJSON_TYPE_OBJ) {
10727 val = ptr_obj_get(val, token, len, esc);
10728 } else if (type == YYJSON_TYPE_ARR) {
10729 val = ptr_arr_get(val, token, len, esc);
10730 } else {
10731 val = NULL;
10732 }
10733 if (!val) return_err_resolve(NULL, token - hdr);
10734 if (ptr == end) return constcast(yyjson_val *)val;
10735 }
10736}
10737
10739 const yyjson_mut_val *val, const char *ptr, size_t ptr_len,
10740 yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
10741
10742 const char *hdr = ptr, *end = ptr + ptr_len, *token;
10743 usize len, esc;
10744 yyjson_mut_val *ctn, *pre = NULL;
10745 yyjson_type type;
10746 bool idx_is_last = false;
10747
10748 while (true) {
10749 token = ptr_next_token(&ptr, end, &len, &esc);
10750 if (unlikely(!token)) return_err_syntax(NULL, ptr - hdr);
10751 ctn = constcast(yyjson_mut_val *)val;
10752 type = unsafe_yyjson_get_type(val);
10753 if (type == YYJSON_TYPE_OBJ) {
10754 val = ptr_mut_obj_get(val, token, len, esc, &pre);
10755 } else if (type == YYJSON_TYPE_ARR) {
10756 val = ptr_mut_arr_get(val, token, len, esc, &pre, &idx_is_last);
10757 } else {
10758 val = NULL;
10759 }
10760 if (ctx && (ptr == end)) {
10761 if (type == YYJSON_TYPE_OBJ ||
10762 (type == YYJSON_TYPE_ARR && (val || idx_is_last))) {
10763 ctx->ctn = ctn;
10764 ctx->pre = pre;
10765 }
10766 }
10767 if (!val) return_err_resolve(NULL, token - hdr);
10768 if (ptr == end) return constcast(yyjson_mut_val *)val;
10769 }
10770}
10771
10773 yyjson_mut_val *val, const char *ptr, size_t ptr_len,
10774 yyjson_mut_val *new_val, yyjson_mut_doc *doc, bool create_parent,
10775 bool insert_new, yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
10776
10777 const char *hdr = ptr, *end = ptr + ptr_len, *token;
10778 usize token_len, esc, ctn_len;
10779 yyjson_mut_val *ctn, *key, *pre = NULL;
10780 yyjson_mut_val *sep_ctn = NULL, *sep_key = NULL, *sep_val = NULL;
10781 yyjson_type ctn_type;
10782 bool idx_is_last = false;
10783
10784 /* skip exist parent nodes */
10785 while (true) {
10786 token = ptr_next_token(&ptr, end, &token_len, &esc);
10787 if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
10788 ctn = val;
10789 ctn_type = unsafe_yyjson_get_type(ctn);
10790 if (ctn_type == YYJSON_TYPE_OBJ) {
10791 val = ptr_mut_obj_get(ctn, token, token_len, esc, &pre);
10792 } else if (ctn_type == YYJSON_TYPE_ARR) {
10793 val = ptr_mut_arr_get(ctn, token, token_len, esc, &pre,
10794 &idx_is_last);
10795 } else return_err_resolve(false, token - hdr);
10796 if (!val) break;
10797 if (ptr == end) break; /* is last token */
10798 }
10799
10800 /* create parent nodes if not exist */
10801 if (unlikely(ptr != end)) { /* not last token */
10802 if (!create_parent) return_err_resolve(false, token - hdr);
10803
10804 /* add value at last index if container is array */
10805 if (ctn_type == YYJSON_TYPE_ARR) {
10806 if (!idx_is_last || !insert_new) {
10807 return_err_resolve(false, token - hdr);
10808 }
10809 val = yyjson_mut_obj(doc);
10810 if (!val) return_err_alloc(false);
10811
10812 /* delay attaching until all operations are completed */
10813 sep_ctn = ctn;
10814 sep_key = NULL;
10815 sep_val = val;
10816
10817 /* move to next token */
10818 ctn = val;
10819 val = NULL;
10820 ctn_type = YYJSON_TYPE_OBJ;
10821 token = ptr_next_token(&ptr, end, &token_len, &esc);
10822 if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
10823 }
10824
10825 /* container is object, create parent nodes */
10826 while (ptr != end) { /* not last token */
10827 key = ptr_new_key(token, token_len, esc, doc);
10828 if (!key) return_err_alloc(false);
10829 val = yyjson_mut_obj(doc);
10830 if (!val) return_err_alloc(false);
10831
10832 /* delay attaching until all operations are completed */
10833 if (!sep_ctn) {
10834 sep_ctn = ctn;
10835 sep_key = key;
10836 sep_val = val;
10837 } else {
10838 yyjson_mut_obj_add(ctn, key, val);
10839 }
10840
10841 /* move to next token */
10842 ctn = val;
10843 val = NULL;
10844 token = ptr_next_token(&ptr, end, &token_len, &esc);
10845 if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
10846 }
10847 }
10848
10849 /* JSON pointer is resolved, insert or replace target value */
10850 ctn_len = unsafe_yyjson_get_len(ctn);
10851 if (ctn_type == YYJSON_TYPE_OBJ) {
10852 if (ctx) ctx->ctn = ctn;
10853 if (!val || insert_new) {
10854 /* insert new key-value pair */
10855 key = ptr_new_key(token, token_len, esc, doc);
10856 if (unlikely(!key)) return_err_alloc(false);
10857 if (ctx) ctx->pre = ctn_len ? (yyjson_mut_val *)ctn->uni.ptr : key;
10858 unsafe_yyjson_mut_obj_add(ctn, key, new_val, ctn_len);
10859 } else {
10860 /* replace exist value */
10861 key = pre->next->next;
10862 if (ctx) ctx->pre = pre;
10863 if (ctx) ctx->old = val;
10864 yyjson_mut_obj_put(ctn, key, new_val);
10865 }
10866 } else {
10867 /* array */
10868 if (ctx && (val || idx_is_last)) ctx->ctn = ctn;
10869 if (insert_new) {
10870 /* append new value */
10871 if (val) {
10872 pre->next = new_val;
10873 new_val->next = val;
10874 if (ctx) ctx->pre = pre;
10875 unsafe_yyjson_set_len(ctn, ctn_len + 1);
10876 } else if (idx_is_last) {
10877 if (ctx) ctx->pre = ctn_len ?
10878 (yyjson_mut_val *)ctn->uni.ptr : new_val;
10879 yyjson_mut_arr_append(ctn, new_val);
10880 } else {
10881 return_err_resolve(false, token - hdr);
10882 }
10883 } else {
10884 /* replace exist value */
10885 if (!val) return_err_resolve(false, token - hdr);
10886 if (ctn_len > 1) {
10887 new_val->next = val->next;
10888 pre->next = new_val;
10889 if (ctn->uni.ptr == val) ctn->uni.ptr = new_val;
10890 } else {
10891 new_val->next = new_val;
10892 ctn->uni.ptr = new_val;
10893 pre = new_val;
10894 }
10895 if (ctx) ctx->pre = pre;
10896 if (ctx) ctx->old = val;
10897 }
10898 }
10899
10900 /* all operations are completed, attach the new components to the target */
10901 if (unlikely(sep_ctn)) {
10902 if (sep_key) yyjson_mut_obj_add(sep_ctn, sep_key, sep_val);
10903 else yyjson_mut_arr_append(sep_ctn, sep_val);
10904 }
10905 return true;
10906}
10907
10909 yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val,
10910 yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
10911
10912 yyjson_mut_val *cur_val;
10913 yyjson_ptr_ctx cur_ctx;
10914 memset(&cur_ctx, 0, sizeof(cur_ctx));
10915 if (!ctx) ctx = &cur_ctx;
10916 cur_val = unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err);
10917 if (!cur_val) return NULL;
10918
10919 if (yyjson_mut_is_obj(ctx->ctn)) {
10920 yyjson_mut_val *key = ctx->pre->next->next;
10921 yyjson_mut_obj_put(ctx->ctn, key, new_val);
10922 } else {
10923 yyjson_ptr_ctx_replace(ctx, new_val);
10924 }
10925 ctx->old = cur_val;
10926 return cur_val;
10927}
10928
10930 yyjson_mut_val *val, const char *ptr, size_t len,
10931 yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
10932
10933 yyjson_mut_val *cur_val;
10934 yyjson_ptr_ctx cur_ctx;
10935 memset(&cur_ctx, 0, sizeof(cur_ctx));
10936 if (!ctx) ctx = &cur_ctx;
10937 cur_val = unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err);
10938 if (cur_val) {
10939 if (yyjson_mut_is_obj(ctx->ctn)) {
10940 yyjson_mut_val *key = ctx->pre->next->next;
10941 yyjson_mut_obj_put(ctx->ctn, key, NULL);
10942 } else {
10944 }
10945 ctx->pre = NULL;
10946 ctx->old = cur_val;
10947 }
10948 return cur_val;
10949}
10950
10951/* macros for yyjson_ptr */
10952#undef return_err
10953#undef return_err_resolve
10954#undef return_err_syntax
10955#undef return_err_alloc
10956
10957
10958
10959/*==============================================================================
10960 * MARK: - JSON Patch API (RFC 6902) (Public)
10961 *============================================================================*/
10962
10963/* JSON Patch operation */
10964typedef enum patch_op {
10965 PATCH_OP_ADD, /* path, value */
10967 PATCH_OP_REPLACE, /* path, value */
10968 PATCH_OP_MOVE, /* from, path */
10969 PATCH_OP_COPY, /* from, path */
10970 PATCH_OP_TEST, /* path, value */
10971 PATCH_OP_NONE /* invalid */
10973
10975 const char *str = op->uni.str;
10976 switch (unsafe_yyjson_get_len(op)) {
10977 case 3:
10978 if (!memcmp(str, "add", 3)) return PATCH_OP_ADD;
10979 return PATCH_OP_NONE;
10980 case 4:
10981 if (!memcmp(str, "move", 4)) return PATCH_OP_MOVE;
10982 if (!memcmp(str, "copy", 4)) return PATCH_OP_COPY;
10983 if (!memcmp(str, "test", 4)) return PATCH_OP_TEST;
10984 return PATCH_OP_NONE;
10985 case 6:
10986 if (!memcmp(str, "remove", 6)) return PATCH_OP_REMOVE;
10987 return PATCH_OP_NONE;
10988 case 7:
10989 if (!memcmp(str, "replace", 7)) return PATCH_OP_REPLACE;
10990 return PATCH_OP_NONE;
10991 default:
10992 return PATCH_OP_NONE;
10993 }
10994}
10995
10996/* macros for yyjson_patch */
10997#define return_err(_code, _msg) do { \
10998 if (err->ptr.code == YYJSON_PTR_ERR_MEMORY_ALLOCATION) { \
10999 err->code = YYJSON_PATCH_ERROR_MEMORY_ALLOCATION; \
11000 err->msg = _msg; \
11001 memset(&err->ptr, 0, sizeof(yyjson_ptr_err)); \
11002 } else { \
11003 err->code = YYJSON_PATCH_ERROR_##_code; \
11004 err->msg = _msg; \
11005 err->idx = iter.idx ? iter.idx - 1 : 0; \
11006 } \
11007 return NULL; \
11008} while (false)
11009
11010#define return_err_copy() \
11011 return_err(MEMORY_ALLOCATION, "failed to copy value")
11012#define return_err_key(_key) \
11013 return_err(MISSING_KEY, "missing key " _key)
11014#define return_err_val(_key) \
11015 return_err(INVALID_MEMBER, "invalid member " _key)
11016
11017#define ptr_get(_ptr) yyjson_mut_ptr_getx( \
11018 root, _ptr->uni.str, _ptr##_len, NULL, &err->ptr)
11019#define ptr_add(_ptr, _val) yyjson_mut_ptr_addx( \
11020 root, _ptr->uni.str, _ptr##_len, _val, doc, false, NULL, &err->ptr)
11021#define ptr_remove(_ptr) yyjson_mut_ptr_removex( \
11022 root, _ptr->uni.str, _ptr##_len, NULL, &err->ptr)
11023#define ptr_replace(_ptr, _val)yyjson_mut_ptr_replacex( \
11024 root, _ptr->uni.str, _ptr##_len, _val, NULL, &err->ptr)
11025
11027 const yyjson_val *orig,
11028 const yyjson_val *patch,
11029 yyjson_patch_err *err) {
11030
11031 yyjson_mut_val *root;
11032 yyjson_val *obj;
11033 yyjson_arr_iter iter;
11034 yyjson_patch_err err_tmp;
11035 if (!err) err = &err_tmp;
11036 memset(err, 0, sizeof(*err));
11037 memset(&iter, 0, sizeof(iter));
11038
11039 if (unlikely(!doc || !orig || !patch)) {
11040 return_err(INVALID_PARAMETER, "input parameter is NULL");
11041 }
11042 if (unlikely(!yyjson_is_arr(patch))) {
11043 return_err(INVALID_PARAMETER, "input patch is not array");
11044 }
11045 root = yyjson_val_mut_copy(doc, orig);
11046 if (unlikely(!root)) return_err_copy();
11047
11048 /* iterate through the patch array */
11049 yyjson_arr_iter_init(patch, &iter);
11050 while ((obj = yyjson_arr_iter_next(&iter))) {
11051 patch_op op_enum;
11052 yyjson_val *op, *path, *from = NULL, *value;
11053 yyjson_mut_val *val = NULL, *test;
11054 usize path_len, from_len = 0;
11055 if (unlikely(!unsafe_yyjson_is_obj(obj))) {
11056 return_err(INVALID_OPERATION, "JSON patch operation is not object");
11057 }
11058
11059 /* get required member: op */
11060 op = yyjson_obj_get(obj, "op");
11061 if (unlikely(!op)) return_err_key("`op`");
11062 if (unlikely(!yyjson_is_str(op))) return_err_val("`op`");
11063 op_enum = patch_op_get(op);
11064
11065 /* get required member: path */
11066 path = yyjson_obj_get(obj, "path");
11067 if (unlikely(!path)) return_err_key("`path`");
11068 if (unlikely(!yyjson_is_str(path))) return_err_val("`path`");
11069 path_len = unsafe_yyjson_get_len(path);
11070
11071 /* get required member: value, from */
11072 switch ((int)op_enum) {
11074 value = yyjson_obj_get(obj, "value");
11075 if (unlikely(!value)) return_err_key("`value`");
11076 val = yyjson_val_mut_copy(doc, value);
11077 if (unlikely(!val)) return_err_copy();
11078 break;
11079 case PATCH_OP_MOVE: case PATCH_OP_COPY:
11080 from = yyjson_obj_get(obj, "from");
11081 if (unlikely(!from)) return_err_key("`from`");
11082 if (unlikely(!yyjson_is_str(from))) return_err_val("`from`");
11083 from_len = unsafe_yyjson_get_len(from);
11084 break;
11085 default:
11086 break;
11087 }
11088
11089 /* perform an operation */
11090 switch ((int)op_enum) {
11091 case PATCH_OP_ADD: /* add(path, val) */
11092 if (unlikely(path_len == 0)) { root = val; break; }
11093 if (unlikely(!ptr_add(path, val))) {
11094 return_err(POINTER, "failed to add `path`");
11095 }
11096 break;
11097 case PATCH_OP_REMOVE: /* remove(path) */
11098 if (unlikely(!ptr_remove(path))) {
11099 return_err(POINTER, "failed to remove `path`");
11100 }
11101 break;
11102 case PATCH_OP_REPLACE: /* replace(path, val) */
11103 if (unlikely(path_len == 0)) { root = val; break; }
11104 if (unlikely(!ptr_replace(path, val))) {
11105 return_err(POINTER, "failed to replace `path`");
11106 }
11107 break;
11108 case PATCH_OP_MOVE: /* val = remove(from), add(path, val) */
11109 if (unlikely(from_len == 0 && path_len == 0)) break;
11110 val = ptr_remove(from);
11111 if (unlikely(!val)) {
11112 return_err(POINTER, "failed to remove `from`");
11113 }
11114 if (unlikely(path_len == 0)) { root = val; break; }
11115 if (unlikely(!ptr_add(path, val))) {
11116 return_err(POINTER, "failed to add `path`");
11117 }
11118 break;
11119 case PATCH_OP_COPY: /* val = get(from).copy, add(path, val) */
11120 val = ptr_get(from);
11121 if (unlikely(!val)) {
11122 return_err(POINTER, "failed to get `from`");
11123 }
11124 if (unlikely(path_len == 0)) { root = val; break; }
11125 val = yyjson_mut_val_mut_copy(doc, val);
11126 if (unlikely(!val)) return_err_copy();
11127 if (unlikely(!ptr_add(path, val))) {
11128 return_err(POINTER, "failed to add `path`");
11129 }
11130 break;
11131 case PATCH_OP_TEST: /* test = get(path), test.eq(val) */
11132 test = ptr_get(path);
11133 if (unlikely(!test)) {
11134 return_err(POINTER, "failed to get `path`");
11135 }
11136 if (unlikely(!yyjson_mut_equals(val, test))) {
11137 return_err(EQUAL, "failed to test equal");
11138 }
11139 break;
11140 default:
11141 return_err(INVALID_MEMBER, "unsupported `op`");
11142 }
11143 }
11144 return root;
11145}
11146
11148 const yyjson_mut_val *orig,
11149 const yyjson_mut_val *patch,
11150 yyjson_patch_err *err) {
11151 yyjson_mut_val *root, *obj;
11153 yyjson_patch_err err_tmp;
11154 if (!err) err = &err_tmp;
11155 memset(err, 0, sizeof(*err));
11156 memset(&iter, 0, sizeof(iter));
11157
11158 if (unlikely(!doc || !orig || !patch)) {
11159 return_err(INVALID_PARAMETER, "input parameter is NULL");
11160 }
11161 if (unlikely(!yyjson_mut_is_arr(patch))) {
11162 return_err(INVALID_PARAMETER, "input patch is not array");
11163 }
11164 root = yyjson_mut_val_mut_copy(doc, orig);
11165 if (unlikely(!root)) return_err_copy();
11166
11167 /* iterate through the patch array */
11169 while ((obj = yyjson_mut_arr_iter_next(&iter))) {
11170 patch_op op_enum;
11171 yyjson_mut_val *op, *path, *from = NULL, *value;
11172 yyjson_mut_val *val = NULL, *test;
11173 usize path_len, from_len = 0;
11174 if (!unsafe_yyjson_is_obj(obj)) {
11175 return_err(INVALID_OPERATION, "JSON patch operation is not object");
11176 }
11177
11178 /* get required member: op */
11179 op = yyjson_mut_obj_get(obj, "op");
11180 if (unlikely(!op)) return_err_key("`op`");
11181 if (unlikely(!yyjson_mut_is_str(op))) return_err_val("`op`");
11182 op_enum = patch_op_get((yyjson_val *)(void *)op);
11183
11184 /* get required member: path */
11185 path = yyjson_mut_obj_get(obj, "path");
11186 if (unlikely(!path)) return_err_key("`path`");
11187 if (unlikely(!yyjson_mut_is_str(path))) return_err_val("`path`");
11188 path_len = unsafe_yyjson_get_len(path);
11189
11190 /* get required member: value, from */
11191 switch ((int)op_enum) {
11193 value = yyjson_mut_obj_get(obj, "value");
11194 if (unlikely(!value)) return_err_key("`value`");
11195 val = yyjson_mut_val_mut_copy(doc, value);
11196 if (unlikely(!val)) return_err_copy();
11197 break;
11198 case PATCH_OP_MOVE: case PATCH_OP_COPY:
11199 from = yyjson_mut_obj_get(obj, "from");
11200 if (unlikely(!from)) return_err_key("`from`");
11201 if (unlikely(!yyjson_mut_is_str(from))) {
11202 return_err_val("`from`");
11203 }
11204 from_len = unsafe_yyjson_get_len(from);
11205 break;
11206 default:
11207 break;
11208 }
11209
11210 /* perform an operation */
11211 switch ((int)op_enum) {
11212 case PATCH_OP_ADD: /* add(path, val) */
11213 if (unlikely(path_len == 0)) { root = val; break; }
11214 if (unlikely(!ptr_add(path, val))) {
11215 return_err(POINTER, "failed to add `path`");
11216 }
11217 break;
11218 case PATCH_OP_REMOVE: /* remove(path) */
11219 if (unlikely(!ptr_remove(path))) {
11220 return_err(POINTER, "failed to remove `path`");
11221 }
11222 break;
11223 case PATCH_OP_REPLACE: /* replace(path, val) */
11224 if (unlikely(path_len == 0)) { root = val; break; }
11225 if (unlikely(!ptr_replace(path, val))) {
11226 return_err(POINTER, "failed to replace `path`");
11227 }
11228 break;
11229 case PATCH_OP_MOVE: /* val = remove(from), add(path, val) */
11230 if (unlikely(from_len == 0 && path_len == 0)) break;
11231 val = ptr_remove(from);
11232 if (unlikely(!val)) {
11233 return_err(POINTER, "failed to remove `from`");
11234 }
11235 if (unlikely(path_len == 0)) { root = val; break; }
11236 if (unlikely(!ptr_add(path, val))) {
11237 return_err(POINTER, "failed to add `path`");
11238 }
11239 break;
11240 case PATCH_OP_COPY: /* val = get(from).copy, add(path, val) */
11241 val = ptr_get(from);
11242 if (unlikely(!val)) {
11243 return_err(POINTER, "failed to get `from`");
11244 }
11245 if (unlikely(path_len == 0)) { root = val; break; }
11246 val = yyjson_mut_val_mut_copy(doc, val);
11247 if (unlikely(!val)) return_err_copy();
11248 if (unlikely(!ptr_add(path, val))) {
11249 return_err(POINTER, "failed to add `path`");
11250 }
11251 break;
11252 case PATCH_OP_TEST: /* test = get(path), test.eq(val) */
11253 test = ptr_get(path);
11254 if (unlikely(!test)) {
11255 return_err(POINTER, "failed to get `path`");
11256 }
11257 if (unlikely(!yyjson_mut_equals(val, test))) {
11258 return_err(EQUAL, "failed to test equal");
11259 }
11260 break;
11261 default:
11262 return_err(INVALID_MEMBER, "unsupported `op`");
11263 }
11264 }
11265 return root;
11266}
11267
11268/* macros for yyjson_patch */
11269#undef return_err
11270#undef return_err_copy
11271#undef return_err_key
11272#undef return_err_val
11273#undef ptr_get
11274#undef ptr_add
11275#undef ptr_remove
11276#undef ptr_replace
11277
11278
11279
11280/*==============================================================================
11281 * MARK: - JSON Merge-Patch API (RFC 7386) (Public)
11282 *============================================================================*/
11283
11285 const yyjson_val *orig,
11286 const yyjson_val *patch) {
11287 usize idx, max;
11288 yyjson_val *key, *orig_val, *patch_val, local_orig;
11289 yyjson_mut_val *builder, *mut_key, *mut_val, *merged_val;
11290
11291 if (unlikely(!yyjson_is_obj(patch))) {
11292 return yyjson_val_mut_copy(doc, patch);
11293 }
11294
11295 builder = yyjson_mut_obj(doc);
11296 if (unlikely(!builder)) return NULL;
11297
11298 memset(&local_orig, 0, sizeof(local_orig));
11299 if (!yyjson_is_obj(orig)) {
11300 local_orig.tag = builder->tag;
11301 local_orig.uni = builder->uni;
11302 orig = &local_orig;
11303 }
11304
11305 /* If orig is contributing, copy any items not modified by the patch */
11306 if (orig != &local_orig) {
11307 yyjson_obj_foreach(orig, idx, max, key, orig_val) {
11308 patch_val = yyjson_obj_getn(patch,
11311 if (!patch_val) {
11312 mut_key = yyjson_val_mut_copy(doc, key);
11313 mut_val = yyjson_val_mut_copy(doc, orig_val);
11314 if (!yyjson_mut_obj_add(builder, mut_key, mut_val)) return NULL;
11315 }
11316 }
11317 }
11318
11319 /* Merge items modified by the patch. */
11320 yyjson_obj_foreach(patch, idx, max, key, patch_val) {
11321 /* null indicates the field is removed. */
11322 if (unsafe_yyjson_is_null(patch_val)) {
11323 continue;
11324 }
11325 mut_key = yyjson_val_mut_copy(doc, key);
11326 orig_val = yyjson_obj_getn(orig,
11329 merged_val = yyjson_merge_patch(doc, orig_val, patch_val);
11330 if (!yyjson_mut_obj_add(builder, mut_key, merged_val)) return NULL;
11331 }
11332
11333 return builder;
11334}
11335
11337 const yyjson_mut_val *orig,
11338 const yyjson_mut_val *patch) {
11339 usize idx, max;
11340 yyjson_mut_val *key, *orig_val, *patch_val, local_orig;
11341 yyjson_mut_val *builder, *mut_key, *mut_val, *merged_val;
11342
11343 if (unlikely(!yyjson_mut_is_obj(patch))) {
11344 return yyjson_mut_val_mut_copy(doc, patch);
11345 }
11346
11347 builder = yyjson_mut_obj(doc);
11348 if (unlikely(!builder)) return NULL;
11349
11350 memset(&local_orig, 0, sizeof(local_orig));
11351 if (!yyjson_mut_is_obj(orig)) {
11352 local_orig.tag = builder->tag;
11353 local_orig.uni = builder->uni;
11354 orig = &local_orig;
11355 }
11356
11357 /* If orig is contributing, copy any items not modified by the patch */
11358 if (orig != &local_orig) {
11359 yyjson_mut_obj_foreach(orig, idx, max, key, orig_val) {
11360 patch_val = yyjson_mut_obj_getn(patch,
11363 if (!patch_val) {
11364 mut_key = yyjson_mut_val_mut_copy(doc, key);
11365 mut_val = yyjson_mut_val_mut_copy(doc, orig_val);
11366 if (!yyjson_mut_obj_add(builder, mut_key, mut_val)) return NULL;
11367 }
11368 }
11369 }
11370
11371 /* Merge items modified by the patch. */
11372 yyjson_mut_obj_foreach(patch, idx, max, key, patch_val) {
11373 /* null indicates the field is removed. */
11374 if (unsafe_yyjson_is_null(patch_val)) {
11375 continue;
11376 }
11377 mut_key = yyjson_mut_val_mut_copy(doc, key);
11378 orig_val = yyjson_mut_obj_getn(orig,
11381 merged_val = yyjson_mut_merge_patch(doc, orig_val, patch_val);
11382 if (!yyjson_mut_obj_add(builder, mut_key, merged_val)) return NULL;
11383 }
11384
11385 return builder;
11386}
11387
11388#endif /* YYJSON_DISABLE_UTILS */
struct dyn_chunk * next
Definition yyjson.c:2414
usize size
Definition yyjson.c:2413
dyn_chunk used_list
Definition yyjson.c:2421
dyn_chunk free_list
Definition yyjson.c:2420
usize size
Definition yyjson.c:2254
struct pool_chunk * next
Definition yyjson.c:2255
pool_chunk * free_list
Definition yyjson.c:2262
usize size
Definition yyjson.c:2261
Definition yyjson.c:550
char c[2]
Definition yyjson.c:550
Definition yyjson.c:551
char c[4]
Definition yyjson.c:551
Definition yyjson.c:552
char c[8]
Definition yyjson.c:552
void(* free)(void *ctx, void *ptr)
Definition yyjson.h:668
void *(* malloc)(void *ctx, size_t size)
Definition yyjson.h:664
void * ctx
Definition yyjson.h:670
void *(* realloc)(void *ctx, void *ptr, size_t old_size, size_t size)
Definition yyjson.h:666
size_t dat_read
Definition yyjson.h:4979
char * str_pool
Definition yyjson.h:4983
yyjson_alc alc
Definition yyjson.h:4977
size_t val_read
Definition yyjson.h:4981
yyjson_val * root
Definition yyjson.h:4975
yyjson_val * val
Definition yyjson.c:6568
yyjson_val * val_end
Definition yyjson.c:6567
yyjson_val * ctn
Definition yyjson.c:6569
yyjson_val * val_hdr
Definition yyjson.c:6566
yyjson_alc alc
Definition yyjson.c:6558
u8 * str_con[2]
Definition yyjson.c:6570
yyjson_read_flag flg
Definition yyjson.c:6559
yyjson_str_pool str_pool
Definition yyjson.h:5851
yyjson_mut_val * root
Definition yyjson.h:5849
yyjson_alc alc
Definition yyjson.h:5850
yyjson_val_pool val_pool
Definition yyjson.h:5852
yyjson_mut_val * next
Definition yyjson.h:5803
yyjson_val_uni uni
Definition yyjson.h:5802
uint64_t tag
Definition yyjson.h:5801
yyjson_mut_val * ctn
Definition yyjson.c:9837
yyjson_mut_val * old
Definition yyjson.h:4348
yyjson_mut_val * ctn
Definition yyjson.h:4334
yyjson_mut_val * pre
Definition yyjson.h:4343
yyjson_read_code code
Definition yyjson.h:960
const char * msg
Definition yyjson.h:962
size_t chunk_size
Definition yyjson.h:5811
struct yyjson_str_chunk * next
Definition yyjson.h:5810
yyjson_str_chunk * chunks
Definition yyjson.h:5823
size_t chunk_size_max
Definition yyjson.h:5822
size_t chunk_size
Definition yyjson.h:5821
size_t chunk_size
Definition yyjson.h:5832
struct yyjson_val_chunk * next
Definition yyjson.h:5831
yyjson_mut_val * end
Definition yyjson.h:5842
size_t chunk_size
Definition yyjson.h:5843
yyjson_val_chunk * chunks
Definition yyjson.h:5845
yyjson_mut_val * cur
Definition yyjson.h:5841
size_t chunk_size_max
Definition yyjson.h:5844
yyjson_val_uni uni
Definition yyjson.h:4970
uint64_t tag
Definition yyjson.h:4969
const char * msg
Definition yyjson.h:1338
yyjson_write_code code
Definition yyjson.h:1336
v16 v
Definition yyjson.c:555
u16 u
Definition yyjson.c:555
v32 v
Definition yyjson.c:556
u32 u
Definition yyjson.c:556
v64 v
Definition yyjson.c:557
u64 u
Definition yyjson.c:557
uint64_t u64
Definition yyjson.h:4957
const char * str
Definition yyjson.h:4960
int64_t i64
Definition yyjson.h:4958
static void yyjson_mut_stat(const yyjson_mut_val *val, usize *val_sum, usize *str_sum)
Definition yyjson.c:2833
#define return_err_syntax(_ret, _pos)
Definition yyjson.c:10709
static_inline bool hex_load_4(const u8 *src, u16 *dst)
Definition yyjson.c:1063
#define repeat4(x)
Definition yyjson.c:352
static_inline bool char_is_sign(u8 d)
Definition yyjson.c:931
#define val_incr()
#define is_utf8_seq3(uni)
static_inline void byte_copy_8(void *dst, const void *src)
Definition yyjson.c:588
#define is_utf8_seq4(uni)
#define check_str_len(_len)
static_inline bool read_inf(u8 **ptr, u8 **pre, yyjson_read_flag flg, yyjson_val *val)
Definition yyjson.c:3172
#define CHAR_ENC_ESC_2
Definition yyjson.c:8480
#define CHAR_TYPE_ID_START
Definition yyjson.c:759
#define repeat4_incr(x)
Definition yyjson.c:357
static const yyjson_alc YYJSON_DEFAULT_ALC
Definition yyjson.c:2238
#define CHAR_TYPE_NONZERO
Definition yyjson.c:766
static void * pool_realloc(void *ctx_ptr, void *ptr, usize old_size, usize size)
Definition yyjson.c:2329
static_inline yyjson_mut_val * ptr_new_key(const char *token, usize len, usize esc, yyjson_mut_doc *doc)
Definition yyjson.c:10677
static_inline bool read_null(u8 **ptr, yyjson_val *val)
Definition yyjson.c:3161
u8 char_enc_type
Definition yyjson.c:8474
static_inline bool char_is_id_start(u8 c)
Definition yyjson.c:916
const char * yyjson_read_number(const char *dat, yyjson_val *val, yyjson_read_flag flg, const yyjson_alc *alc, yyjson_read_err *err)
Definition yyjson.c:6469
bool unsafe_yyjson_mut_ptr_putx(yyjson_mut_val *val, const char *ptr, size_t ptr_len, yyjson_mut_val *new_val, yyjson_mut_doc *doc, bool create_parent, bool insert_new, yyjson_ptr_ctx *ctx, yyjson_ptr_err *err)
Definition yyjson.c:10772
#define CHAR_ENC_CPY_2
Definition yyjson.c:8479
#define CHAR_TYPE_EOL_EXT
Definition yyjson.c:758
static_inline u32 u64_lz_bits(u64 v)
Definition yyjson.c:1994
static_inline u32 u64_tz_bits(u64 v)
Definition yyjson.c:2027
static_inline bool hex_load_2(const u8 *src, u8 *dst)
Definition yyjson.c:1075
static_inline bool char_is_trivia(u8 c)
Definition yyjson.c:901
static_inline void byte_move_16(void *dst, const void *src)
Definition yyjson.c:645
static_inline usize size_align_down(usize size, usize align)
Definition yyjson.c:2165
static_inline u8 * write_num(u8 *cur, yyjson_val *val, yyjson_write_flag flg)
Definition yyjson.c:8394
#define F32_EXP_BIAS
Definition yyjson.c:511
static_inline yyjson_doc * read_root_minify(u8 *hdr, u8 *cur, u8 *eof, yyjson_alc alc, yyjson_read_flag flg, yyjson_read_err *err)
Definition yyjson.c:5349
static_inline void byte_copy_16(void *dst, const void *src)
Definition yyjson.c:597
#define F64_MIN_BIN_EXP
Definition yyjson.c:484
yyjson_mut_val * unsafe_yyjson_mut_ptr_replacex(yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val, yyjson_ptr_ctx *ctx, yyjson_ptr_err *err)
Definition yyjson.c:10908
static void default_free(void *ctx, void *ptr)
Definition yyjson.c:2235
#define F64_EXP_BIAS
Definition yyjson.c:512
#define F64_BITS
Definition yyjson.c:488
#define has_allow(_flg)
Definition yyjson.c:3120
#define USIZE_SAFE_DIG
Definition yyjson.c:459
void yyjson_alc_dyn_free(yyjson_alc *alc)
Definition yyjson.c:2540
static_inline bool is_utf16_bom(const u8 *cur)
Definition yyjson.c:977
#define MSG_DEPTH
Definition yyjson.c:443
#define YYJSON_FOPEN_E
Definition yyjson.c:2102
#define YYJSON_MUT_DOC_STR_POOL_INIT_SIZE
Definition yyjson.c:332
yyjson_doc * yyjson_mut_val_imut_copy(const yyjson_mut_val *mval, const yyjson_alc *alc)
Definition yyjson.c:2904
bool yyjson_val_write_file(const char *path, const yyjson_val *val, yyjson_write_flag flg, const yyjson_alc *alc_ptr, yyjson_write_err *err)
Definition yyjson.c:9735
#define ptr_remove(_ptr)
Definition yyjson.c:11021
#define likely(x)
Definition yyjson.c:367
#define ptr_replace(_ptr, _val)
Definition yyjson.c:11023
static_noinline bool read_str_id(u8 **ptr, u8 *eof, yyjson_read_flag flg, u8 **pre, yyjson_val *val, const char **msg)
Definition yyjson.c:5093
static_inline u32 f32_to_bits(f32 f)
Definition yyjson.c:1950
static_inline bool char_is_exp(u8 d)
Definition yyjson.c:946
#define CHAR_TYPE_SPACE_EXT
Definition yyjson.c:752
#define return_raw()
yyjson_mut_doc * yyjson_mut_doc_mut_copy(const yyjson_mut_doc *doc, const yyjson_alc *alc)
Definition yyjson.c:2695
#define YYJSON_MUT_DOC_VAL_POOL_MAX_SIZE
Definition yyjson.c:335
static void * default_realloc(void *ctx, void *ptr, usize old_size, usize size)
Definition yyjson.c:2232
bool yyjson_write_fp(FILE *fp, const yyjson_doc *doc, yyjson_write_flag flg, const yyjson_alc *alc_ptr, yyjson_write_err *err)
Definition yyjson.c:9796
#define CHAR_ENC_CPY_4
Definition yyjson.c:8483
#define CHAR_TYPE_ID_NEXT
Definition yyjson.c:760
yyjson_mut_val * unsafe_yyjson_mut_ptr_getx(const yyjson_mut_val *val, const char *ptr, size_t ptr_len, yyjson_ptr_ctx *ctx, yyjson_ptr_err *err)
Definition yyjson.c:10738
#define F64_EXP_MASK
Definition yyjson.c:508
void yyjson_incr_free(yyjson_incr_state *state)
Definition yyjson.c:6613
#define check_maybe_truncated_number()
#define gcc_store_barrier(val)
Definition yyjson.c:409
static_inline u32 byte_load_3(const void *src)
Definition yyjson.c:712
#define MSG_ERR_BOM
Definition yyjson.c:439
static_inline bool char_is_eol_ext(u8 c)
Definition yyjson.c:911
static_inline bool char_is_ascii_skip_sq(u8 c)
Definition yyjson.c:896
static_noinline bool read_num_hex(u8 **ptr, u8 **pre, yyjson_read_flag flg, yyjson_val *val, const char **msg)
Definition yyjson.c:3331
bool yyjson_mut_doc_set_str_pool_size(yyjson_mut_doc *doc, size_t len)
Definition yyjson.c:2639
#define F64_BITS_INF
Definition yyjson.c:462
#define CHAR_TYPE_ID_ASCII
Definition yyjson.c:761
static_inline bool byte_match_4(void *buf, const char *pat)
Definition yyjson.c:685
yyjson_doc * yyjson_incr_read(yyjson_incr_state *state, size_t len, yyjson_read_err *err)
Definition yyjson.c:6627
static void * pool_malloc(void *ctx_ptr, usize size)
Definition yyjson.c:2271
static_inline bool unsafe_yyjson_str_equals(const void *lhs, const void *rhs)
Definition yyjson.c:2960
static_inline bool char_is_nonzero(u8 d)
Definition yyjson.c:936
static_inline void byte_move_8(void *dst, const void *src)
Definition yyjson.c:632
static const u8 char_table1[256]
Definition yyjson.c:770
#define F64_SIG_FULL_BITS
Definition yyjson.c:500
yyjson_mut_val * yyjson_merge_patch(yyjson_mut_doc *doc, const yyjson_val *orig, const yyjson_val *patch)
Definition yyjson.c:11284
#define MSG_OBJ_SEP
Definition yyjson.c:431
static_noinline u8 * write_f64_raw(u8 *buf, u64 raw, yyjson_write_flag flg)
Definition yyjson.c:8356
#define return_err_alloc(_ret)
Definition yyjson.c:10711
static_inline u64 f64_bits_nan(bool sign)
Definition yyjson.c:1975
static_inline bool byte_match_2(void *buf, const char *pat)
Definition yyjson.c:672
#define CHAR_TYPE_DOT
Definition yyjson.c:768
uint64_t u64
Definition yyjson.c:540
#define LABEL_obj_key_begin
Definition yyjson.c:6549
#define snprintf_num(buf, len, fmt, dig, val)
Definition yyjson.c:8283
#define YYJSON_MUT_DOC_STR_POOL_MAX_SIZE
Definition yyjson.c:333
yyjson_alc * yyjson_alc_dyn_new(void)
Definition yyjson.c:2524
static_inline u8 * write_root_single(yyjson_val *val, yyjson_write_flag flg, yyjson_alc alc, char *buf, usize *dat_len, yyjson_write_err *err)
Definition yyjson.c:9165
static_inline void unsafe_yyjson_val_pool_release(yyjson_val_pool *pool, yyjson_alc *alc)
Definition yyjson.c:2575
#define expr_stop(i)
char * yyjson_mut_write_opts(const yyjson_mut_doc *doc, yyjson_write_flag flg, const yyjson_alc *alc_ptr, usize *dat_len, yyjson_write_err *err)
Definition yyjson.c:10347
#define has_flg(_flg)
Definition yyjson.c:3119
static_inline void u128_mul_add(u64 a, u64 b, u64 c, u64 *hi, u64 *lo)
Definition yyjson.c:2078
static_inline bool unsafe_yyjson_num_equals(const void *lhs, const void *rhs)
Definition yyjson.c:2945
static_inline usize fread_safe(void *buf, usize size, FILE *file)
Definition yyjson.c:2128
void yyjson_mut_doc_free(yyjson_mut_doc *doc)
Definition yyjson.c:2653
#define CHAR_ENC_ESC_1
Definition yyjson.c:8478
#define yyjson_max(x, y)
Definition yyjson.c:381
#define CHAR_TYPE_SIGN
Definition yyjson.c:764
int32_t i32
Definition yyjson.c:537
bool unsafe_yyjson_val_pool_grow(yyjson_val_pool *pool, const yyjson_alc *alc, usize count)
Definition yyjson.c:2612
uint32_t yyjson_version(void)
Definition yyjson.c:58
static_inline bool size_add_is_overflow(usize size, usize add)
Definition yyjson.c:2146
static_inline const char_enc_type * get_enc_table_with_flag(yyjson_write_flag flg)
Definition yyjson.c:8786
static_inline void dyn_chunk_list_remove(dyn_chunk *list, dyn_chunk *chunk)
Definition yyjson.c:2434
static_inline bool char_is_space(u8 c)
Definition yyjson.c:876
static_inline yyjson_val * ptr_arr_get(const yyjson_val *arr, const char *token, usize len, usize esc)
Definition yyjson.c:10577
static_inline void yyjson_write_ctx_get(yyjson_write_ctx *ctx, usize *size, bool *is_obj)
Definition yyjson.c:9157
#define return_err_copy()
Definition yyjson.c:11010
static yyjson_mut_val * unsafe_yyjson_mut_val_mut_copy(yyjson_mut_doc *m_doc, const yyjson_mut_val *m_vals)
Definition yyjson.c:2780
bool unsafe_yyjson_equals(const yyjson_val *lhs, const yyjson_val *rhs)
Definition yyjson.c:2967
#define return_i64(_v)
static bool is_truncated_utf8(u8 *cur, u8 *eof)
Definition yyjson.c:3444
size_t usize
Definition yyjson.c:541
bool yyjson_locate_pos(const char *str, size_t len, size_t pos, size_t *line, size_t *col, size_t *chr)
Definition yyjson.c:3078
static_inline bool char_is_id_ascii(u8 c)
Definition yyjson.c:926
static_inline u64 f64_bits_inf(bool sign)
Definition yyjson.c:1957
static_inline bool is_utf8_bom(const u8 *cur)
Definition yyjson.c:972
static_inline bool read_uni_esc(u8 **src_ptr, u8 **dst_ptr, const char **msg)
Definition yyjson.c:4696
#define F64_SIG_MASK
Definition yyjson.c:504
#define F64_BITS_NAN
Definition yyjson.c:468
char * yyjson_write_number(const yyjson_val *val, char *buf)
Definition yyjson.c:8427
yyjson_doc * yyjson_read_opts(char *dat, usize len, yyjson_read_flag flg, const yyjson_alc *alc_ptr, yyjson_read_err *err)
Definition yyjson.c:6251
static_noinline bool read_str_sq(u8 **ptr, u8 *eof, yyjson_read_flag flg, yyjson_val *val, const char **msg)
Definition yyjson.c:5087
static_inline const u8 * get_hex_table_with_flag(yyjson_write_flag flg)
Definition yyjson.c:8779
static_inline u8 * write_raw(u8 *cur, const u8 *raw, usize raw_len)
Definition yyjson.c:8804
static bool is_truncated_str(u8 *cur, u8 *eof, const char *str, bool case_sensitive)
Definition yyjson.c:3484
size_t yyjson_mut_write_buf(char *buf, size_t buf_len, const yyjson_mut_doc *doc, yyjson_write_flag flg, yyjson_write_err *err)
Definition yyjson.c:10379
static_inline void * mem_align_up(void *mem, usize align)
Definition yyjson.c:2174
static_inline bool char_is_digit(u8 d)
Definition yyjson.c:941
#define MSG_NAN_INF
Definition yyjson.c:437
bool yyjson_val_write_fp(FILE *fp, const yyjson_val *val, yyjson_write_flag flg, const yyjson_alc *alc_ptr, yyjson_write_err *err)
Definition yyjson.c:9761
#define byte_move_src(x)
Definition yyjson.c:566
float f32
Definition yyjson.c:531
static bool write_dat_to_file(const char *path, u8 *dat, usize len, yyjson_write_err *err)
Definition yyjson.c:9115
#define MSG_COMMENT
Definition yyjson.c:435
#define U64(hi, lo)
Definition yyjson.c:385
static_inline bool char_is_space_ext(u8 c)
Definition yyjson.c:881
yyjson_doc * yyjson_read_fp(FILE *file, yyjson_read_flag flg, const yyjson_alc *alc_ptr, yyjson_read_err *err)
Definition yyjson.c:6369
static_inline bool char_is_ctn(u8 c)
Definition yyjson.c:962
static_inline const char * ptr_next_token(const char **ptr, const char *end, usize *len, usize *esc)
Definition yyjson.c:10482
static_inline bool char_is_ascii_skip(u8 c)
Definition yyjson.c:891
bool yyjson_alc_pool_init(yyjson_alc *alc, void *buf, usize size)
Definition yyjson.c:2376
#define CHAR_TYPE_EXP
Definition yyjson.c:767
static const char_enc_type enc_table_esc_slash[256]
Definition yyjson.c:8551
static_inline bool ptr_token_eq(void *key, const char *token, usize len, usize esc)
Definition yyjson.c:10550
static_inline u8 * write_root_pretty(const yyjson_val *root, const yyjson_write_flag flg, const yyjson_alc alc, char *buf, usize *dat_len, yyjson_write_err *err)
Definition yyjson.c:9465
static_inline void unsafe_yyjson_str_pool_release(yyjson_str_pool *pool, yyjson_alc *alc)
Definition yyjson.c:2565
static_noinline u8 * write_fp_reformat(u8 *buf, int len, yyjson_write_flag flg, bool fixed)
Definition yyjson.c:8287
size_t yyjson_write_buf(char *buf, size_t buf_len, const yyjson_doc *doc, yyjson_write_flag flg, yyjson_write_err *err)
Definition yyjson.c:9821
#define expr_intg(i)
static_noinline yyjson_doc * read_root_single(u8 *hdr, u8 *cur, u8 *eof, yyjson_alc alc, yyjson_read_flag flg, yyjson_read_err *err)
Definition yyjson.c:5244
#define CHAR_TYPE_ASCII_SQ
Definition yyjson.c:750
static_inline void yyjson_write_ctx_set(yyjson_write_ctx *ctx, usize size, bool is_obj)
Definition yyjson.c:9152
static_inline void u128_mul(u64 a, u64 b, u64 *hi, u64 *lo)
Definition yyjson.c:2055
static_inline u8 * mut_write_root_single(yyjson_mut_val *val, yyjson_write_flag flg, yyjson_alc alc, char *buf, usize *dat_len, yyjson_write_err *err)
Definition yyjson.c:9872
#define USIZE_MAX
Definition yyjson.c:451
#define repeat16_incr(x)
Definition yyjson.c:359
#define MSG_OBJ_END
Definition yyjson.c:432
static_inline u64 f64_to_bits(f64 f)
Definition yyjson.c:1943
#define LABEL_doc_begin
Definition yyjson.c:6546
#define LABEL_obj_val_end
Definition yyjson.c:6552
static_inline void yyjson_mut_write_ctx_get(yyjson_mut_write_ctx *ctx, yyjson_mut_val **ctn, usize *size, bool *is_obj)
Definition yyjson.c:9847
#define F32_BITS
Definition yyjson.c:487
#define repeat8_incr(x)
Definition yyjson.c:358
#define CHAR_ENC_ESC_4
Definition yyjson.c:8484
static_inline FILE * fopen_safe(const char *path, const char *mode)
Definition yyjson.c:2110
#define expr_jump(i)
#define CHAR_ENC_ESC_3
Definition yyjson.c:8482
static_noinline u8 * write_f32_raw(u8 *buf, u64 raw, yyjson_write_flag flg)
Definition yyjson.c:8368
#define ptr_get(_ptr)
Definition yyjson.c:11017
static_inline bool read_str_con(u8 **ptr, u8 *eof, yyjson_read_flag flg, yyjson_val *val, const char **msg, u8 **con)
Definition yyjson.c:5082
#define byte_move_dst(x)
Definition yyjson.c:567
yyjson_mut_val * unsafe_yyjson_mut_ptr_removex(yyjson_mut_val *val, const char *ptr, size_t len, yyjson_ptr_ctx *ctx, yyjson_ptr_err *err)
Definition yyjson.c:10929
static_inline bool is_utf32_bom(const u8 *cur)
Definition yyjson.c:983
#define is_utf8_seq2(uni)
#define MSG_GARBAGE
Definition yyjson.c:433
static_inline bool char_is_fp(u8 d)
Definition yyjson.c:951
#define F64_DEC_DIG
Definition yyjson.c:516
static_inline yyjson_mut_val * ptr_mut_arr_get(const yyjson_mut_val *arr, const char *token, usize len, usize esc, yyjson_mut_val **pre, bool *last)
Definition yyjson.c:10621
#define CHAR_TYPE_DIGIT
Definition yyjson.c:765
#define LABEL_obj_key_end
Definition yyjson.c:6550
#define YYJSON_MUT_DOC_VAL_POOL_INIT_SIZE
Definition yyjson.c:334
#define repeat2_incr(x)
Definition yyjson.c:356
bool yyjson_mut_val_write_fp(FILE *fp, const yyjson_mut_val *val, yyjson_write_flag flg, const yyjson_alc *alc_ptr, yyjson_write_err *err)
Definition yyjson.c:10415
static_inline bool read_false(u8 **ptr, yyjson_val *val)
Definition yyjson.c:3150
yyjson_val * unsafe_yyjson_ptr_getx(const yyjson_val *val, const char *ptr, size_t ptr_len, yyjson_ptr_err *err)
Definition yyjson.c:10714
#define F32_SIG_BITS
Definition yyjson.c:495
static const u8 char_table2[256]
Definition yyjson.c:805
int64_t i64
Definition yyjson.c:539
static void * default_malloc(void *ctx, usize size)
Definition yyjson.c:2229
static void dyn_free(void *ctx_ptr, void *ptr)
Definition yyjson.c:2509
static_inline u32 byte_load_4(const void *src)
Definition yyjson.c:728
bool unsafe_yyjson_str_pool_grow(yyjson_str_pool *pool, const yyjson_alc *alc, usize len)
Definition yyjson.c:2585
static_inline yyjson_doc * read_root_pretty(u8 *hdr, u8 *cur, u8 *eof, yyjson_alc alc, yyjson_read_flag flg, yyjson_read_err *err)
Definition yyjson.c:5776
static const yyjson_alc YYJSON_NULL_ALC
Definition yyjson.c:2202
#define yyjson_min(x, y)
Definition yyjson.c:379
#define return_err(_pos, _msg)
Definition yyjson.c:10698
#define F64_EXP_BITS
Definition yyjson.c:492
bool yyjson_mut_val_write_file(const char *path, const yyjson_mut_val *val, yyjson_write_flag flg, const yyjson_alc *alc_ptr, yyjson_write_err *err)
Definition yyjson.c:10389
#define NAN
Definition yyjson.c:154
#define CHAR_ENC_CPY_3
Definition yyjson.c:8481
static_inline usize ext_eol_len(const u8 *cur)
Definition yyjson.c:989
bool yyjson_write_file(const char *path, const yyjson_doc *doc, yyjson_write_flag flg, const yyjson_alc *alc_ptr, yyjson_write_err *err)
Definition yyjson.c:9787
patch_op
Definition yyjson.c:10964
@ PATCH_OP_TEST
Definition yyjson.c:10970
@ PATCH_OP_REPLACE
Definition yyjson.c:10967
@ PATCH_OP_COPY
Definition yyjson.c:10969
@ PATCH_OP_MOVE
Definition yyjson.c:10968
@ PATCH_OP_ADD
Definition yyjson.c:10965
@ PATCH_OP_REMOVE
Definition yyjson.c:10966
@ PATCH_OP_NONE
Definition yyjson.c:10971
#define constcast
Definition yyjson.c:390
yyjson_mut_val * yyjson_mut_patch(yyjson_mut_doc *doc, const yyjson_mut_val *orig, const yyjson_mut_val *patch, yyjson_patch_err *err)
Definition yyjson.c:11147
static_inline u8 * write_bool(u8 *cur, bool val)
Definition yyjson.c:9080
static void * dyn_malloc(void *ctx_ptr, usize size)
Definition yyjson.c:2452
#define repeat8(x)
Definition yyjson.c:353
#define U64_SAFE_DIG
Definition yyjson.c:457
static_inline FILE * fopen_readonly(const char *path)
Definition yyjson.c:2120
uint8_t u8
Definition yyjson.c:534
static_inline void byte_move_2(void *dst, const void *src)
Definition yyjson.c:606
yyjson_mut_doc * yyjson_mut_doc_new(const yyjson_alc *alc)
Definition yyjson.c:2663
double f64
Definition yyjson.c:532
#define INFINITY
Definition yyjson.c:148
static usize yyjson_imut_copy(yyjson_val **val_ptr, char **buf_ptr, const yyjson_mut_val *mval)
Definition yyjson.c:2858
#define is_utf8_seq1(uni)
char * yyjson_write_opts(const yyjson_doc *doc, yyjson_write_flag flg, const yyjson_alc *alc_ptr, usize *dat_len, yyjson_write_err *err)
Definition yyjson.c:9724
static_inline void byte_copy_4(void *dst, const void *src)
Definition yyjson.c:579
#define MSG_ARR_END
Definition yyjson.c:429
static_inline u8 * write_null(u8 *cur)
Definition yyjson.c:9073
static_inline bool size_is_pow2(usize size)
Definition yyjson.c:2151
#define return_err_resolve(_ret, _pos)
Definition yyjson.c:10707
#define save_incr_state(_label)
#define return_f64(_v)
#define MSG_CHAR_N
Definition yyjson.c:427
#define LABEL_doc_end
Definition yyjson.c:6553
static_inline u8 * mut_write_root_pretty(const yyjson_mut_val *root, usize estimated_val_num, yyjson_write_flag flg, yyjson_alc alc, char *buf, usize *dat_len, yyjson_write_err *err)
Definition yyjson.c:10079
static_inline u8 * write_u32_len_1_to_8(u32 val, u8 *buf)
Definition yyjson.c:7249
#define YYJSON_READER_ESTIMATED_MINIFY_RATIO
Definition yyjson.c:327
#define MSG_CHAR_T
Definition yyjson.c:425
static_inline u8 * write_u64(u64 val, u8 *buf)
Definition yyjson.c:7328
#define CHAR_TYPE_NUM
Definition yyjson.c:753
#define F64_SIG_BITS
Definition yyjson.c:496
#define MSG_ERR_TYPE
Definition yyjson.c:438
static_inline void pool_size_align(usize *size)
Definition yyjson.c:2267
static_inline void byte_move_4(void *dst, const void *src)
Definition yyjson.c:619
#define F32_DEC_DIG
Definition yyjson.c:515
char * yyjson_mut_val_write_opts(const yyjson_mut_val *val, yyjson_write_flag flg, const yyjson_alc *alc_ptr, usize *dat_len, yyjson_write_err *err)
Definition yyjson.c:10339
#define ptr_add(_ptr, _val)
Definition yyjson.c:11019
static_inline usize ext_space_len(const u8 *cur)
Definition yyjson.c:996
static_inline bool read_inf_or_nan(u8 **ptr, u8 **pre, yyjson_read_flag flg, yyjson_val *val)
Definition yyjson.c:3239
#define return_err_val(_key)
Definition yyjson.c:11014
#define LABEL_arr_val_begin
Definition yyjson.c:6547
static void * null_realloc(void *ctx, void *ptr, usize old_size, usize size)
Definition yyjson.c:2194
yyjson_doc * yyjson_read_file(const char *path, yyjson_read_flag flg, const yyjson_alc *alc_ptr, yyjson_read_err *err)
Definition yyjson.c:6341
static_inline void byte_move_forward(void *dst, void *src, usize n)
Definition yyjson.c:662
#define U64_MAX
Definition yyjson.c:447
static const char_enc_type enc_table_cpy_slash[256]
Definition yyjson.c:8509
bool yyjson_mut_write_file(const char *path, const yyjson_mut_doc *doc, yyjson_write_flag flg, const yyjson_alc *alc_ptr, yyjson_write_err *err)
Definition yyjson.c:10441
static_inline u8 * write_u32_len_8(u32 val, u8 *buf)
Definition yyjson.c:7225
#define MSG_FOPEN
Definition yyjson.c:420
static_inline f32 f64_to_f32(f64 val)
Definition yyjson.c:1989
bool yyjson_mut_write_fp(FILE *fp, const yyjson_mut_doc *doc, yyjson_write_flag flg, const yyjson_alc *alc_ptr, yyjson_write_err *err)
Definition yyjson.c:10450
static const u8 hex_conv_table[256]
Definition yyjson.c:1027
static_inline bool char_is_hex(u8 c)
Definition yyjson.c:1083
static const char_enc_type enc_table_esc[256]
Definition yyjson.c:8530
static_inline void dyn_chunk_list_add(dyn_chunk *list, dyn_chunk *chunk)
Definition yyjson.c:2447
#define MSG_OBJ_KEY
Definition yyjson.c:430
static void null_free(void *ctx, void *ptr)
Definition yyjson.c:2198
#define CHAR_ENC_ERR_1
Definition yyjson.c:8476
static_inline bool has_rflag(yyjson_read_flag flg, yyjson_read_flag chk, bool non_standard)
Definition yyjson.c:3123
#define CHAR_ENC_ESC_A
Definition yyjson.c:8477
static_noinline bool read_num_raw(u8 **ptr, u8 **pre, yyjson_read_flag flg, yyjson_val *val, const char **msg)
Definition yyjson.c:3247
static_inline FILE * fopen_writeonly(const char *path)
Definition yyjson.c:2124
#define utf8_seq(name)
Definition yyjson.c:1108
static_inline u16 byte_load_2(const void *src)
Definition yyjson.c:700
#define LABEL_obj_val_begin
Definition yyjson.c:6551
yyjson_mut_val * yyjson_mut_merge_patch(yyjson_mut_doc *doc, const yyjson_mut_val *orig, const yyjson_mut_val *patch)
Definition yyjson.c:11336
#define static_noinline
Definition yyjson.c:375
static_inline bool read_true(u8 **ptr, yyjson_val *val)
Definition yyjson.c:3139
size_t yyjson_mut_val_write_buf(char *buf, size_t buf_len, const yyjson_mut_val *val, yyjson_write_flag flg, yyjson_write_err *err)
Definition yyjson.c:10365
static_inline bool char_is_eol(u8 c)
Definition yyjson.c:906
#define return_err_key(_key)
Definition yyjson.c:11012
#define CHAR_ENC_CPY_1
Definition yyjson.c:8475
static_inline bool read_nan(u8 **ptr, u8 **pre, yyjson_read_flag flg, yyjson_val *val)
Definition yyjson.c:3211
#define FP_BUF_LEN
Definition yyjson.c:519
#define F32_EXP_MASK
Definition yyjson.c:507
static_inline void byte_copy_2(void *dst, const void *src)
Definition yyjson.c:570
#define unlikely(x)
Definition yyjson.c:369
bool yyjson_mut_doc_set_val_pool_size(yyjson_mut_doc *doc, size_t count)
Definition yyjson.c:2646
static_inline u8 char_to_lower(u8 c)
Definition yyjson.c:967
static_inline u8 * write_indent(u8 *cur, usize level, usize spaces)
Definition yyjson.c:9093
#define MSG_CHAR
Definition yyjson.c:428
static_inline usize yyjson_mut_doc_estimated_val_num(const yyjson_mut_doc *doc)
Definition yyjson.c:9857
static_inline yyjson_val * ptr_obj_get(const yyjson_val *obj, const char *token, usize len, usize esc)
Definition yyjson.c:10600
static_inline bool read_str(u8 **ptr, u8 *eof, yyjson_read_flag flg, yyjson_val *val, const char **msg)
Definition yyjson.c:5077
#define MSG_ERR_UTF8
Definition yyjson.c:440
static_inline bool char_is_id_next(u8 c)
Definition yyjson.c:921
#define YYJSON_WRITER_ESTIMATED_MINIFY_RATIO
Definition yyjson.c:329
#define MSG_ERR_UTF32
Definition yyjson.c:442
uint16_t u16
Definition yyjson.c:536
#define return_suc(_str_end, _cur_end)
#define MSG_MALLOC
Definition yyjson.c:424
static_inline u8 * write_u32_len_5_to_8(u32 val, u8 *buf)
Definition yyjson.c:7296
static_inline void yyjson_mut_write_ctx_set(yyjson_mut_write_ctx *ctx, yyjson_mut_val *ctn, usize size, bool is_obj)
Definition yyjson.c:9840
#define F64_MAX_DEC_DIG
Definition yyjson.c:472
int16_t i16
Definition yyjson.c:535
#define F64_MAX_DEC_EXP
Definition yyjson.c:475
char * yyjson_val_write_opts(const yyjson_val *val, yyjson_write_flag flg, const yyjson_alc *alc_ptr, usize *dat_len, yyjson_write_err *err)
Definition yyjson.c:9716
#define return_err_inv_param(_msg)
static_inline bool char_is_num(u8 c)
Definition yyjson.c:886
static_inline u8 * write_str_noesc(u8 *cur, const u8 *str, usize str_len)
Definition yyjson.c:8816
#define YYJSON_READER_ESTIMATED_PRETTY_RATIO
Definition yyjson.c:326
static_inline u8 * write_str(u8 *cur, bool esc, bool inv, const u8 *str, usize str_len, const char_enc_type *enc_table, const u8 *hex_table)
Definition yyjson.c:8848
static bool write_dat_to_fp(FILE *fp, u8 *dat, usize len, yyjson_write_err *err)
Definition yyjson.c:9104
static const char_enc_type enc_table_cpy[256]
Definition yyjson.c:8488
#define F64_MAX_BIN_EXP
Definition yyjson.c:481
#define F64_MIN_DEC_EXP
Definition yyjson.c:478
#define MSG_FREAD
Definition yyjson.c:421
static char * write_root(const yyjson_val *val, yyjson_write_flag flg, const yyjson_alc *alc_ptr, char *buf, usize *dat_len, yyjson_write_err *err)
Definition yyjson.c:9681
size_t yyjson_val_write_buf(char *buf, size_t buf_len, const yyjson_val *val, yyjson_write_flag flg, yyjson_write_err *err)
Definition yyjson.c:9807
static_inline bool f64_is_inf(f64 val)
Definition yyjson.c:1966
static void * dyn_realloc(void *ctx_ptr, void *ptr, usize old_size, usize size)
Definition yyjson.c:2490
#define MSG_NOT_END
Definition yyjson.c:434
static_inline bool read_num(u8 **ptr, u8 **pre, yyjson_read_flag flg, yyjson_val *val, const char **msg)
Definition yyjson.c:4486
#define return_0()
#define F32_EXP_BITS
Definition yyjson.c:491
#define YYJSON_WRITER_ESTIMATED_PRETTY_RATIO
Definition yyjson.c:328
#define return_f64_bin(_v)
int8_t i8
Definition yyjson.c:533
static const u8 char_table3[256]
Definition yyjson.c:840
#define CHAR_TYPE_COMMENT
Definition yyjson.c:754
#define MSG_FWRITE
Definition yyjson.c:422
static_inline bool ptr_token_to_idx(const char *cur, usize len, usize *idx)
Definition yyjson.c:10520
static char * mut_write_root(const yyjson_mut_val *val, usize estimated_val_num, yyjson_write_flag flg, const yyjson_alc *alc_ptr, char *buf, usize *dat_len, yyjson_write_err *err)
Definition yyjson.c:10301
static_inline u8 * write_u32_len_4(u32 val, u8 *buf)
Definition yyjson.c:7240
static_noinline u8 * write_f64_raw_fixed(u8 *buf, u64 raw, yyjson_write_flag flg, u32 prec)
Definition yyjson.c:8380
#define repeat16(x)
Definition yyjson.c:354
#define return_inf()
static_inline yyjson_mut_val * ptr_mut_obj_get(const yyjson_mut_val *obj, const char *token, usize len, usize esc, yyjson_mut_val **pre)
Definition yyjson.c:10651
yyjson_incr_state * yyjson_incr_new(char *buf, size_t buf_len, yyjson_read_flag flg, const yyjson_alc *alc_ptr)
Definition yyjson.c:6575
#define incr_len(_len)
#define LABEL_arr_val_end
Definition yyjson.c:6548
static_inline usize size_align_up(usize size, usize align)
Definition yyjson.c:2156
#define static_inline
Definition yyjson.c:373
#define MSG_FCLOSE
Definition yyjson.c:423
yyjson_mut_doc * yyjson_doc_mut_copy(const yyjson_doc *doc, const yyjson_alc *alc)
Definition yyjson.c:2678
static_inline bool char_is_digit_or_fp(u8 d)
Definition yyjson.c:956
#define repeat_in_1_18(x)
Definition yyjson.c:361
#define YYJSON_ALC_DYN_MIN_SIZE
Definition yyjson.c:338
#define MSG_CHAR_F
Definition yyjson.c:426
static_inline bool read_str_opt(u8 quo, u8 **ptr, u8 *eof, yyjson_read_flag flg, yyjson_val *val, const char **msg, u8 *con[2])
Definition yyjson.c:4760
bool unsafe_yyjson_mut_equals(const yyjson_mut_val *lhs, const yyjson_mut_val *rhs)
Definition yyjson.c:3022
static patch_op patch_op_get(yyjson_val *op)
Definition yyjson.c:10974
yyjson_mut_val * yyjson_mut_val_mut_copy(yyjson_mut_doc *doc, const yyjson_mut_val *val)
Definition yyjson.c:2826
yyjson_doc * yyjson_mut_doc_imut_copy(const yyjson_mut_doc *mdoc, const yyjson_alc *alc)
Definition yyjson.c:2898
static_noinline bool skip_trivia(u8 **ptr, u8 *eof, yyjson_read_flag flg)
Definition yyjson.c:3391
#define MSG_COMMA
Definition yyjson.c:436
static void pool_free(void *ctx_ptr, void *ptr)
Definition yyjson.c:2303
static_inline u8 * mut_write_root_minify(const yyjson_mut_val *root, usize estimated_val_num, yyjson_write_flag flg, yyjson_alc alc, char *buf, usize *dat_len, yyjson_write_err *err)
Definition yyjson.c:9882
#define MSG_ERR_UTF16
Definition yyjson.c:441
static_inline bool dyn_size_align(usize *size)
Definition yyjson.c:2425
#define byte_move_idx(x)
Definition yyjson.c:565
static_noinline bool is_truncated_end(u8 *hdr, u8 *cur, u8 *eof, yyjson_read_code code, yyjson_read_flag flg)
Definition yyjson.c:3501
static void * null_malloc(void *ctx, usize size)
Definition yyjson.c:2190
#define CHAR_TYPE_EOL
Definition yyjson.c:757
yyjson_mut_val * yyjson_patch(yyjson_mut_doc *doc, const yyjson_val *orig, const yyjson_val *patch, yyjson_patch_err *err)
Definition yyjson.c:11026
static_inline u8 * write_root_minify(const yyjson_val *root, const yyjson_write_flag flg, const yyjson_alc alc, char *buf, usize *dat_len, yyjson_write_err *err)
Definition yyjson.c:9274
#define CHAR_TYPE_ASCII
Definition yyjson.c:749
#define F32_SIG_MASK
Definition yyjson.c:503
uint32_t u32
Definition yyjson.c:538
#define CHAR_TYPE_SPACE
Definition yyjson.c:751
static_inline bool has_wflag(yyjson_write_flag flg, yyjson_write_flag chk, bool non_standard)
Definition yyjson.c:7175
#define utf8_seq_def(name, a, b, c, d)
Definition yyjson.c:1106
yyjson_mut_val * yyjson_val_mut_copy(yyjson_mut_doc *m_doc, const yyjson_val *i_vals)
Definition yyjson.c:2714
uint8_t yyjson_subtype
Definition yyjson.h:614
#define YYJSON_READER_DEPTH_LIMIT
Definition yyjson.h:115
uint32_t yyjson_read_code
Definition yyjson.h:907
yyjson_api_inline char * unsafe_yyjson_mut_str_alc(yyjson_mut_doc *doc, size_t len)
Definition yyjson.h:5866
yyjson_api_inline bool unsafe_yyjson_arr_is_flat(const yyjson_val *val)
Definition yyjson.h:5136
#define YYJSON_TYPE_BOOL
Definition yyjson.h:603
static const yyjson_read_code YYJSON_READ_ERROR_MEMORY_ALLOCATION
Definition yyjson.h:916
static const yyjson_read_code YYJSON_READ_ERROR_UNEXPECTED_CONTENT
Definition yyjson.h:922
yyjson_api_inline void unsafe_yyjson_set_len(void *val, size_t len)
Definition yyjson.h:5218
yyjson_api_inline const char * unsafe_yyjson_get_str(const void *val)
Definition yyjson.h:5179
yyjson_api_inline yyjson_mut_val * yyjson_mut_strn(yyjson_mut_doc *doc, const char *str, size_t len)
Definition yyjson.h:6276
yyjson_api_inline bool yyjson_is_str(const yyjson_val *val)
Definition yyjson.h:5390
yyjson_api_inline yyjson_mut_val * yyjson_mut_strncpy(yyjson_mut_doc *doc, const char *str, size_t len)
Definition yyjson.h:6295
yyjson_api_inline bool yyjson_is_obj(const yyjson_val *val)
Definition yyjson.h:5398
#define YYJSON_SUBTYPE_FALSE
Definition yyjson.h:618
static const yyjson_read_code YYJSON_READ_ERROR_LITERAL
Definition yyjson.h:943
#define YYJSON_SUBTYPE_REAL
Definition yyjson.h:626
static const yyjson_write_code YYJSON_WRITE_SUCCESS
Definition yyjson.h:1310
const char * ptr
Definition yyjson.h:8356
yyjson_api_inline yyjson_mut_val * yyjson_mut_obj_get(const yyjson_mut_val *obj, const char *key)
Definition yyjson.h:6970
#define yyjson_obj_foreach(obj, idx, max, key, val)
Definition yyjson.h:2419
uint32_t yyjson_read_flag
Definition yyjson.h:799
#define yyjson_align(x)
Definition yyjson.h:272
static const yyjson_write_flag YYJSON_WRITE_ALLOW_INF_AND_NAN
Definition yyjson.h:1257
#define YYJSON_TYPE_STR
Definition yyjson.h:607
#define YYJSON_TYPE_NULL
Definition yyjson.h:601
yyjson_api_inline yyjson_mut_val * yyjson_mut_obj_iter_getn(yyjson_mut_obj_iter *iter, const char *key, size_t key_len)
Definition yyjson.h:7059
yyjson_api_inline double unsafe_yyjson_u64_to_f64(uint64_t num)
Definition yyjson.h:5044
static const yyjson_read_code YYJSON_READ_ERROR_MORE
Definition yyjson.h:952
uint8_t yyjson_type
Definition yyjson.h:595
yyjson_api_inline yyjson_mut_val * unsafe_yyjson_mut_val(yyjson_mut_doc *doc, size_t count)
Definition yyjson.h:5894
#define YYJSON_TYPE_MASK
Definition yyjson.h:631
yyjson_api_inline yyjson_subtype unsafe_yyjson_get_subtype(const void *val)
Definition yyjson.h:5062
yyjson_api_inline bool unsafe_yyjson_is_ctn(const void *val)
Definition yyjson.h:5100
yyjson_api_inline bool unsafe_yyjson_is_null(const void *val)
Definition yyjson.h:5076
#define YYJSON_TYPE_ARR
Definition yyjson.h:609
yyjson_api_inline bool yyjson_is_arr(const yyjson_val *val)
Definition yyjson.h:5394
static const yyjson_read_code YYJSON_READ_ERROR_INVALID_COMMENT
Definition yyjson.h:934
#define YYJSON_TYPE_NUM
Definition yyjson.h:605
yyjson_api_inline yyjson_mut_val * yyjson_mut_obj(yyjson_mut_doc *doc)
Definition yyjson.h:7086
yyjson_api_inline yyjson_val * yyjson_obj_get(const yyjson_val *obj, const char *key)
Definition yyjson.h:5693
yyjson_api_inline yyjson_val * unsafe_yyjson_get_next(const yyjson_val *val)
Definition yyjson.h:5191
static const yyjson_write_code YYJSON_WRITE_ERROR_FILE_WRITE
Definition yyjson.h:1328
yyjson_api_inline yyjson_mut_val * yyjson_mut_arr_iter_next(yyjson_mut_arr_iter *iter)
Definition yyjson.h:6375
#define YYJSON_TYPE_OBJ
Definition yyjson.h:611
yyjson_api_inline yyjson_val * yyjson_obj_iter_getn(yyjson_obj_iter *iter, const char *key, size_t key_len)
Definition yyjson.h:5760
static const yyjson_write_flag YYJSON_WRITE_PRETTY_TWO_SPACES
Definition yyjson.h:1272
yyjson_api_inline yyjson_type unsafe_yyjson_get_type(const void *val)
Definition yyjson.h:5057
yyjson_api_inline bool yyjson_obj_iter_init(const yyjson_val *obj, yyjson_obj_iter *iter)
Definition yyjson.h:5718
static const yyjson_write_code YYJSON_WRITE_ERROR_INVALID_PARAMETER
Definition yyjson.h:1313
static const yyjson_read_code YYJSON_READ_ERROR_INVALID_PARAMETER
Definition yyjson.h:913
static const yyjson_read_flag YYJSON_READ_JSON5
Definition yyjson.h:894
#define YYJSON_WRITE_FP_FLAG_BITS
Definition yyjson.h:1286
yyjson_api_inline void yyjson_mut_doc_set_root(yyjson_mut_doc *doc, yyjson_mut_val *root)
Definition yyjson.h:5919
static const yyjson_read_code YYJSON_READ_ERROR_INVALID_NUMBER
Definition yyjson.h:937
yyjson_api_inline bool unsafe_yyjson_get_bool(const void *val)
Definition yyjson.h:5146
yyjson_api_inline bool yyjson_ptr_ctx_remove(yyjson_ptr_ctx *ctx)
Definition yyjson.h:8212
yyjson_api_inline bool yyjson_mut_is_obj(const yyjson_mut_val *val)
Definition yyjson.h:5978
static const yyjson_read_flag YYJSON_READ_INSITU
Definition yyjson.h:817
#define YYJSON_SUBTYPE_UINT
Definition yyjson.h:622
#define YYJSON_TAG_BIT
Definition yyjson.h:645
yyjson_api_inline bool yyjson_mut_equals(const yyjson_mut_val *lhs, const yyjson_mut_val *rhs)
Definition yyjson.h:6059
#define YYJSON_WRITE_FP_TO_FLOAT
Definition yyjson.h:1302
static const yyjson_read_code YYJSON_READ_ERROR_INVALID_STRING
Definition yyjson.h:940
#define YYJSON_SUBTYPE_SINT
Definition yyjson.h:624
yyjson_api_inline yyjson_val * yyjson_arr_iter_next(yyjson_arr_iter *iter)
Definition yyjson.h:5672
#define bool
Definition yyjson.h:522
#define YYJSON_PADDING_SIZE
Definition yyjson.h:648
static const yyjson_read_flag YYJSON_READ_ALLOW_INVALID_UNICODE
Definition yyjson.h:847
#define YYJSON_VERSION_HEX
Definition yyjson.h:580
yyjson_api_inline bool yyjson_mut_obj_add(yyjson_mut_val *obj, yyjson_mut_val *key, yyjson_mut_val *val)
Definition yyjson.h:7248
const char size_t len
Definition yyjson.h:8364
yyjson_api_inline yyjson_mut_val * yyjson_mut_obj_getn(const yyjson_mut_val *obj, const char *key, size_t key_len)
Definition yyjson.h:6975
yyjson_api_inline bool yyjson_ptr_ctx_replace(yyjson_ptr_ctx *ctx, yyjson_mut_val *val)
Definition yyjson.h:8180
yyjson_api_inline size_t unsafe_yyjson_get_len(const void *val)
Definition yyjson.h:5183
#define YYJSON_TAG_MASK
Definition yyjson.h:643
yyjson_api_inline bool yyjson_mut_obj_put(yyjson_mut_val *obj, yyjson_mut_val *key, yyjson_mut_val *val)
Definition yyjson.h:7259
yyjson_api_inline bool yyjson_mut_is_str(const yyjson_mut_val *val)
Definition yyjson.h:5970
yyjson_api_inline bool yyjson_mut_obj_iter_init(yyjson_mut_val *obj, yyjson_mut_obj_iter *iter)
Definition yyjson.h:6995
yyjson_api_inline yyjson_val * yyjson_obj_getn(const yyjson_val *obj, const char *key, size_t key_len)
Definition yyjson.h:5698
yyjson_api_inline char * unsafe_yyjson_mut_strncpy(yyjson_mut_doc *doc, const char *str, size_t len)
Definition yyjson.h:5885
yyjson_api_inline bool yyjson_mut_arr_iter_init(yyjson_mut_val *arr, yyjson_mut_arr_iter *iter)
Definition yyjson.h:6350
yyjson_api_inline bool unsafe_yyjson_is_obj(const void *val)
Definition yyjson.h:5096
yyjson_api_inline yyjson_val * unsafe_yyjson_get_first(const yyjson_val *ctn)
Definition yyjson.h:5187
yyjson_api_inline bool yyjson_is_raw(const yyjson_val *val)
Definition yyjson.h:5350
#define yyjson_mut_obj_foreach(obj, idx, max, key, val)
Definition yyjson.h:3859
#define YYJSON_TYPE_RAW
Definition yyjson.h:599
#define YYJSON_WRITE_FP_PREC_BITS
Definition yyjson.h:1289
#define YYJSON_SUBTYPE_TRUE
Definition yyjson.h:620
static const yyjson_read_code YYJSON_READ_ERROR_UNEXPECTED_END
Definition yyjson.h:925
yyjson_api_inline bool yyjson_mut_is_arr(const yyjson_mut_val *val)
Definition yyjson.h:5974
static const yyjson_write_flag YYJSON_WRITE_PRETTY
Definition yyjson.h:1248
static const yyjson_read_code YYJSON_READ_ERROR_UNEXPECTED_CHARACTER
Definition yyjson.h:928
yyjson_api_inline void unsafe_yyjson_mut_obj_add(yyjson_mut_val *obj, yyjson_mut_val *key, yyjson_mut_val *val, size_t len)
Definition yyjson.h:7174
yyjson_api_inline bool yyjson_mut_arr_append(yyjson_mut_val *arr, yyjson_mut_val *val)
Definition yyjson.h:6621
yyjson_api_inline bool yyjson_arr_iter_init(const yyjson_val *arr, yyjson_arr_iter *iter)
Definition yyjson.h:5650
static const yyjson_read_flag YYJSON_READ_ALLOW_BOM
Definition yyjson.h:856
#define YYJSON_SUBTYPE_NOESC
Definition yyjson.h:628
uint32_t yyjson_write_flag
Definition yyjson.h:1238