master ohmu/fastfetch-openbsd / src / 3rdparty / yyjson / yyjson.c
ohmu  ·  2026-10-15
    1/*==============================================================================
    2 Copyright (c) 2020 YaoYuan <ibireme@gmail.com>
    3
    4 Permission is hereby granted, free of charge, to any person obtaining a copy
    5 of this software and associated documentation files (the "Software"), to deal
    6 in the Software without restriction, including without limitation the rights
    7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    8 copies of the Software, and to permit persons to whom the Software is
    9 furnished to do so, subject to the following conditions:
   10
   11 The above copyright notice and this permission notice shall be included in all
   12 copies or substantial portions of the Software.
   13
   14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   20 SOFTWARE.
   21 *============================================================================*/
   22
   23#include "yyjson.h"
   24
   25
   26
   27/*==============================================================================
   28 * MARK: - Warning Suppress (Private)
   29 *============================================================================*/
   30
   31#if defined(__clang__)
   32#   pragma clang diagnostic ignored "-Wunused-function"
   33#   pragma clang diagnostic ignored "-Wunused-parameter"
   34#   pragma clang diagnostic ignored "-Wunused-label"
   35#   pragma clang diagnostic ignored "-Wunused-macros"
   36#   pragma clang diagnostic ignored "-Wunused-variable"
   37#elif YYJSON_IS_REAL_GCC && yyjson_gcc_available(4, 2, 0)
   38#   pragma GCC diagnostic ignored "-Wunused-function"
   39#   pragma GCC diagnostic ignored "-Wunused-parameter"
   40#   pragma GCC diagnostic ignored "-Wunused-label"
   41#   pragma GCC diagnostic ignored "-Wunused-macros"
   42#   pragma GCC diagnostic ignored "-Wunused-variable"
   43#elif defined(_MSC_VER)
   44#   pragma warning(disable:4100) /* unreferenced formal parameter */
   45#   pragma warning(disable:4101) /* unreferenced variable */
   46#   pragma warning(disable:4102) /* unreferenced label */
   47#   pragma warning(disable:4127) /* conditional expression is constant */
   48#   pragma warning(disable:4702) /* unreachable code */
   49#   pragma warning(disable:4706) /* assignment within conditional expression */
   50#endif
   51
   52
   53
   54/*==============================================================================
   55 * MARK: - Version (Public)
   56 *============================================================================*/
   57
   58uint32_t yyjson_version(void) {
   59    return YYJSON_VERSION_HEX;
   60}
   61
   62
   63
   64/*==============================================================================
   65 * MARK: - Flags (Private)
   66 *============================================================================*/
   67
   68/* msvc intrinsic */
   69#if YYJSON_MSC_VER >= 1400
   70#   include <intrin.h>
   71#   if defined(_M_AMD64) || defined(_M_ARM64)
   72#       define MSC_HAS_BIT_SCAN_64 1
   73#       pragma intrinsic(_BitScanForward64)
   74#       pragma intrinsic(_BitScanReverse64)
   75#   else
   76#       define MSC_HAS_BIT_SCAN_64 0
   77#   endif
   78#   if defined(_M_AMD64) || defined(_M_ARM64) || \
   79        defined(_M_IX86) || defined(_M_ARM)
   80#       define MSC_HAS_BIT_SCAN 1
   81#       pragma intrinsic(_BitScanForward)
   82#       pragma intrinsic(_BitScanReverse)
   83#   else
   84#       define MSC_HAS_BIT_SCAN 0
   85#   endif
   86#   if defined(_M_AMD64)
   87#       define MSC_HAS_UMUL128 1
   88#       pragma intrinsic(_umul128)
   89#   else
   90#       define MSC_HAS_UMUL128 0
   91#   endif
   92#else
   93#   define MSC_HAS_BIT_SCAN_64 0
   94#   define MSC_HAS_BIT_SCAN 0
   95#   define MSC_HAS_UMUL128 0
   96#endif
   97
   98/* gcc builtin */
   99#if yyjson_has_builtin(__builtin_clzll) || yyjson_gcc_available(3, 4, 0)
  100#   define GCC_HAS_CLZLL 1
  101#else
  102#   define GCC_HAS_CLZLL 0
  103#endif
  104
  105#if yyjson_has_builtin(__builtin_ctzll) || yyjson_gcc_available(3, 4, 0)
  106#   define GCC_HAS_CTZLL 1
  107#else
  108#   define GCC_HAS_CTZLL 0
  109#endif
  110
  111/* int128 type */
  112#ifndef YYJSON_HAS_INT128
  113#   if defined(__SIZEOF_INT128__) && (__SIZEOF_INT128__ == 16) && \
  114    (defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER)) && \
  115    (!defined(__EMSCRIPTEN__) && !defined(__wasm__))
  116#       define YYJSON_HAS_INT128 1
  117#   else
  118#       define YYJSON_HAS_INT128 0
  119#   endif
  120#endif
  121
  122/* IEEE 754 floating-point binary representation */
  123#ifndef YYJSON_HAS_IEEE_754
  124#   if defined(__STDC_IEC_559__) || defined(__STDC_IEC_60559_BFP__)
  125#       define YYJSON_HAS_IEEE_754 1
  126#   elif FLT_RADIX == 2 && \
  127    FLT_MANT_DIG == 24 && FLT_DIG == 6 && \
  128    FLT_MIN_EXP == -125 && FLT_MAX_EXP == 128 && \
  129    FLT_MIN_10_EXP == -37 && FLT_MAX_10_EXP == 38 && \
  130    DBL_MANT_DIG == 53 && DBL_DIG == 15 && \
  131    DBL_MIN_EXP == -1021 && DBL_MAX_EXP == 1024 && \
  132    DBL_MIN_10_EXP == -307 && DBL_MAX_10_EXP == 308
  133#       define YYJSON_HAS_IEEE_754 1
  134#   else
  135#       define YYJSON_HAS_IEEE_754 0
  136#       undef  YYJSON_DISABLE_FAST_FP_CONV
  137#       define YYJSON_DISABLE_FAST_FP_CONV 1
  138#   endif
  139#endif
  140
  141#if YYJSON_DISABLE_FAST_FP_CONV && YYJSON_FREESTANDING
  142#   error DISABLE_FAST_FP_CONV and FREESTANDING cannot be used together
  143#endif
  144
  145/* Inf and NaN */
  146#ifndef INFINITY
  147#    ifndef HUGE_VAL
  148#        define INFINITY ((double)(1.0 / 0.0))
  149#    else
  150#        define INFINITY HUGE_VAL
  151#    endif
  152#endif
  153#ifndef NAN
  154#    define NAN ((double)(0.0 / 0.0))
  155#endif
  156
  157/*
  158 Correct rounding in double number computations.
  159
  160 On the x86 architecture, some compilers may use x87 FPU instructions for
  161 floating-point arithmetic. The x87 FPU loads all floating-point numbers as
  162 80-bit double-extended precision internally, then rounds the result to the
  163 original precision, which may produce inaccurate results. For a more detailed
  164 explanation, see the paper: https://arxiv.org/abs/cs/0701192
  165
  166 Here are some examples of double precision calculation error:
  167
  168     2877.0 / 1e6   == 0.002877,  but x87 returns 0.0028770000000000002
  169     43683.0 * 1e21 == 4.3683e25, but x87 returns 4.3683000000000004e25
  170
  171 Here are some examples of compiler flags to generate x87 instructions on x86:
  172
  173     clang -m32 -mno-sse
  174     gcc/icc -m32 -mfpmath=387
  175     msvc /arch:SSE or /arch:IA32
  176
  177 If we are sure that there's no similar error described above, we can define the
  178 YYJSON_DOUBLE_MATH_CORRECT as 1 to enable the fast path calculation. This is
  179 not an accurate detection; it just tries to avoid the error at compile-time.
  180 An accurate detection can be done at run-time:
  181
  182     bool is_double_math_correct(void) {
  183         volatile double r = 43683.0;
  184         r *= 1e21;
  185         return r == 4.3683e25;
  186     }
  187
  188 See also: utils.h in https://github.com/google/double-conversion/
  189 */
  190#if !defined(FLT_EVAL_METHOD) && defined(__FLT_EVAL_METHOD__)
  191#    define FLT_EVAL_METHOD __FLT_EVAL_METHOD__
  192#endif
  193
  194#if defined(FLT_EVAL_METHOD) && FLT_EVAL_METHOD != 0 && FLT_EVAL_METHOD != 1
  195#    define YYJSON_DOUBLE_MATH_CORRECT 0
  196#elif defined(i386) || defined(__i386) || defined(__i386__) || \
  197    defined(_X86_) || defined(__X86__) || defined(_M_IX86) || \
  198    defined(__I86__) || defined(__IA32__) || defined(__THW_INTEL)
  199#   if (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP == 2) || \
  200        (defined(__SSE2_MATH__) && __SSE2_MATH__)
  201#       define YYJSON_DOUBLE_MATH_CORRECT 1
  202#   else
  203#       define YYJSON_DOUBLE_MATH_CORRECT 0
  204#   endif
  205#elif defined(__mc68000__) || defined(__pnacl__) || defined(__native_client__)
  206#   define YYJSON_DOUBLE_MATH_CORRECT 0
  207#else
  208#   define YYJSON_DOUBLE_MATH_CORRECT 1
  209#endif
  210
  211/*
  212 Detect the endianness at compile-time.
  213 YYJSON_ENDIAN == YYJSON_BIG_ENDIAN
  214 YYJSON_ENDIAN == YYJSON_LITTLE_ENDIAN
  215 */
  216#define YYJSON_BIG_ENDIAN       4321
  217#define YYJSON_LITTLE_ENDIAN    1234
  218
  219#if yyjson_has_include(<sys/types.h>)
  220#    include <sys/types.h> /* POSIX */
  221#endif
  222#if yyjson_has_include(<endian.h>)
  223#    include <endian.h> /* Linux */
  224#elif yyjson_has_include(<sys/endian.h>)
  225#    include <sys/endian.h> /* BSD, Android */
  226#elif yyjson_has_include(<machine/endian.h>)
  227#    include <machine/endian.h> /* BSD, Darwin */
  228#endif
  229
  230#if defined(BYTE_ORDER) && BYTE_ORDER
  231#   if defined(BIG_ENDIAN) && (BYTE_ORDER == BIG_ENDIAN)
  232#       define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
  233#   elif defined(LITTLE_ENDIAN) && (BYTE_ORDER == LITTLE_ENDIAN)
  234#       define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
  235#   endif
  236#elif defined(__BYTE_ORDER) && __BYTE_ORDER
  237#   if defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN)
  238#       define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
  239#   elif defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN)
  240#       define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
  241#   endif
  242#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__
  243#   if defined(__ORDER_BIG_ENDIAN__) && \
  244        (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
  245#       define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
  246#   elif defined(__ORDER_LITTLE_ENDIAN__) && \
  247        (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
  248#       define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
  249#   endif
  250#elif (defined(__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__ == 1) || \
  251    defined(__i386) || defined(__i386__) || \
  252    defined(_X86_) || defined(__X86__) || \
  253    defined(_M_IX86) || defined(__THW_INTEL__) || \
  254    defined(__x86_64) || defined(__x86_64__) || \
  255    defined(__amd64) || defined(__amd64__) || \
  256    defined(_M_AMD64) || defined(_M_X64) || \
  257    defined(_M_ARM) || defined(_M_ARM64) || \
  258    defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \
  259    defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || \
  260    defined(__EMSCRIPTEN__) || defined(__wasm__) || \
  261    defined(__loongarch__)
  262#   define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN
  263#elif (defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ == 1) || \
  264    defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \
  265    defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) || \
  266    defined(__or1k__) || defined(__OR1K__)
  267#   define YYJSON_ENDIAN YYJSON_BIG_ENDIAN
  268#else
  269#   define YYJSON_ENDIAN 0 /* unknown endian, detect at run-time */
  270#endif
  271
  272/*
  273 This macro controls how yyjson handles unaligned memory accesses.
  274
  275 By default, yyjson uses `memcpy()` for memory copying. This allows the compiler
  276 to optimize the code and emit unaligned memory access instructions when
  277 supported by the target architecture.
  278
  279 However, on some older compilers or architectures where `memcpy()` is not
  280 well-optimized and may result in unnecessary function calls, defining this
  281 macro as 1 may help. In such cases, yyjson switches to manual byte-by-byte
  282 access, which can potentially improve performance.
  283
  284 An example of the generated assembly code for ARM can be found here:
  285 https://godbolt.org/z/334jjhxPT
  286
  287 This flag is already enabled for common architectures in the following code,
  288 so manual configuration is usually unnecessary. If unsure, you can check the
  289 generated assembly or run benchmarks to make an informed decision.
  290 */
  291#ifndef YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
  292#   if defined(__ia64) || defined(_IA64) || defined(__IA64__) ||  \
  293        defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
  294#       define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* Itanium */
  295#   elif (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) && \
  296        (defined(__GNUC__) || defined(__clang__)) && \
  297        (!defined(__ARM_FEATURE_UNALIGNED) || !__ARM_FEATURE_UNALIGNED)
  298#       define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* ARM */
  299#   elif defined(__sparc) || defined(__sparc__)
  300#       define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* SPARC */
  301#   elif defined(__mips) || defined(__mips__) || defined(__MIPS__)
  302#       define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* MIPS */
  303#   elif defined(__m68k__) || defined(M68000)
  304#       define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* M68K */
  305#   else
  306#       define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 0
  307#   endif
  308#endif
  309
  310/*
  311 Estimated initial ratio of the JSON data (data_size / value_count).
  312 For example:
  313
  314    data:        {"id":12345678,"name":"Harry"}
  315    data_size:   30
  316    value_count: 5
  317    ratio:       6
  318
  319 yyjson uses dynamic memory with a growth factor of 1.5 when reading and writing
  320 JSON, the ratios below are used to determine the initial memory size.
  321
  322 A too large ratio will waste memory, and a too small ratio will cause multiple
  323 memory growths and degrade performance. Currently, these ratios are generated
  324 with some commonly used JSON datasets.
  325 */
  326#define YYJSON_READER_ESTIMATED_PRETTY_RATIO 16
  327#define YYJSON_READER_ESTIMATED_MINIFY_RATIO 6
  328#define YYJSON_WRITER_ESTIMATED_PRETTY_RATIO 32
  329#define YYJSON_WRITER_ESTIMATED_MINIFY_RATIO 18
  330
  331/* The initial and maximum size of the memory pool's chunk in yyjson_mut_doc. */
  332#define YYJSON_MUT_DOC_STR_POOL_INIT_SIZE   0x100
  333#define YYJSON_MUT_DOC_STR_POOL_MAX_SIZE    0x10000000
  334#define YYJSON_MUT_DOC_VAL_POOL_INIT_SIZE   (0x10 * sizeof(yyjson_mut_val))
  335#define YYJSON_MUT_DOC_VAL_POOL_MAX_SIZE    (0x1000000 * sizeof(yyjson_mut_val))
  336
  337/* The minimum size of the dynamic allocator's chunk. */
  338#define YYJSON_ALC_DYN_MIN_SIZE             0x1000
  339
  340/* Default value for compile-time options. */
  341
  342#ifndef YYJSON_READER_DEPTH_LIMIT
  343#define YYJSON_READER_DEPTH_LIMIT 0
  344#endif
  345
  346#ifndef YYJSON_WRITER_DEPTH_LIMIT
  347#define YYJSON_WRITER_DEPTH_LIMIT 0
  348#endif
  349
  350/*==============================================================================
  351 * MARK: - Macros (Private)
  352 *============================================================================*/
  353
  354/* Macros used for loop unrolling and other purposes. */
  355#define repeat2(x)  { x x }
  356#define repeat4(x)  { x x x x }
  357#define repeat8(x)  { x x x x x x x x }
  358#define repeat16(x) { x x x x x x x x x x x x x x x x }
  359
  360#define repeat2_incr(x)   { x(0)  x(1) }
  361#define repeat4_incr(x)   { x(0)  x(1)  x(2)  x(3) }
  362#define repeat8_incr(x)   { x(0)  x(1)  x(2)  x(3)  x(4)  x(5)  x(6)  x(7)  }
  363#define repeat16_incr(x)  { x(0)  x(1)  x(2)  x(3)  x(4)  x(5)  x(6)  x(7)  \
  364                            x(8)  x(9)  x(10) x(11) x(12) x(13) x(14) x(15) }
  365#define repeat_in_1_18(x) { x(1)  x(2)  x(3)  x(4)  x(5)  x(6)  x(7)  x(8)  \
  366                            x(9)  x(10) x(11) x(12) x(13) x(14) x(15) x(16) \
  367                            x(17) x(18) }
  368
  369/* Macros used to provide branch prediction information for compiler. */
  370#undef  likely
  371#define likely(x)       yyjson_likely(x)
  372#undef  unlikely
  373#define unlikely(x)     yyjson_unlikely(x)
  374
  375/* Macros used to provide inline information for compiler. */
  376#undef  static_inline
  377#define static_inline   static yyjson_inline
  378#undef  static_noinline
  379#define static_noinline static yyjson_noinline
  380
  381/* Macros for min and max. */
  382#undef  yyjson_min
  383#define yyjson_min(x, y) ((x) < (y) ? (x) : (y))
  384#undef  yyjson_max
  385#define yyjson_max(x, y) ((x) > (y) ? (x) : (y))
  386
  387/* Used to write u64 literal for C89 which doesn't support "ULL" suffix. */
  388#undef  U64
  389#define U64(hi, lo) ((((u64)hi##UL) << 32U) + lo##UL)
  390#undef  U32
  391#define U32(hi) ((u32)(hi##UL))
  392
  393/* Used to cast away (remove) const qualifier. */
  394#define constcast yyjson_constcast
  395
  396/*
  397 Compiler barriers for single variables.
  398
  399 These macros inform GCC that a read or write access to the given memory
  400 location will occur, preventing certain compiler optimizations or reordering
  401 around the access to 'val'. They do not emit any actual instructions.
  402
  403 This is useful when GCC's default optimization strategies are suboptimal and
  404 precise control over memory access patterns is required.
  405 These barriers are not needed when using Clang or MSVC.
  406 */
  407#if YYJSON_IS_REAL_GCC
  408#   define gcc_load_barrier(val)   __asm__ volatile(""::"m"(val))
  409#   define gcc_store_barrier(val)  __asm__ volatile("":"=m"(val))
  410#   define gcc_full_barrier(val)   __asm__ volatile("":"=m"(val):"m"(val))
  411#else
  412#   define gcc_load_barrier(val)
  413#   define gcc_store_barrier(val)
  414#   define gcc_full_barrier(val)
  415#endif
  416
  417
  418
  419/*==============================================================================
  420 * MARK: - Constants (Private)
  421 *============================================================================*/
  422
  423/* Common error messages. */
  424#define MSG_FOPEN       "failed to open file"
  425#define MSG_FREAD       "failed to read file"
  426#define MSG_FWRITE      "failed to write file"
  427#define MSG_FCLOSE      "failed to close file"
  428#define MSG_MALLOC      "failed to allocate memory"
  429#define MSG_CHAR_T      "invalid literal, expected 'true'"
  430#define MSG_CHAR_F      "invalid literal, expected 'false'"
  431#define MSG_CHAR_N      "invalid literal, expected 'null'"
  432#define MSG_CHAR        "unexpected character, expected a JSON value"
  433#define MSG_ARR_END     "unexpected character, expected ',' or ']'"
  434#define MSG_OBJ_KEY     "unexpected character, expected a string key"
  435#define MSG_OBJ_SEP     "unexpected character, expected ':' after key"
  436#define MSG_OBJ_END     "unexpected character, expected ',' or '}'"
  437#define MSG_GARBAGE     "unexpected content after document"
  438#define MSG_NOT_END     "unexpected end of data"
  439#define MSG_COMMENT     "unclosed multiline comment"
  440#define MSG_COMMA       "trailing comma is not allowed"
  441#define MSG_NAN_INF     "nan or inf number is not allowed"
  442#define MSG_ERR_TYPE    "invalid JSON value type"
  443#define MSG_ERR_BOM     "UTF-8 byte order mark (BOM) is not supported"
  444#define MSG_ERR_UTF8    "invalid utf-8 encoding in string"
  445#define MSG_ERR_UTF16   "UTF-16 encoding is not supported"
  446#define MSG_ERR_UTF32   "UTF-32 encoding is not supported"
  447#define MSG_DEPTH       "depth limit exceeded"
  448
  449/* U64 constant values */
  450#undef  U64_MAX
  451#define U64_MAX         U64(0xFFFFFFFF, 0xFFFFFFFF)
  452#undef  I64_MAX
  453#define I64_MAX         U64(0x7FFFFFFF, 0xFFFFFFFF)
  454#undef  USIZE_MAX
  455#define USIZE_MAX       ((usize)(~(usize)0))
  456
  457/* Maximum number of digits for reading u32/u64/usize safety (not overflow). */
  458#undef  U32_SAFE_DIG
  459#define U32_SAFE_DIG    9   /* u32 max is 4294967295, 10 digits */
  460#undef  U64_SAFE_DIG
  461#define U64_SAFE_DIG    19  /* u64 max is 18446744073709551615, 20 digits */
  462#undef  USIZE_SAFE_DIG
  463#define USIZE_SAFE_DIG  (sizeof(usize) == 8 ? U64_SAFE_DIG : U32_SAFE_DIG)
  464
  465/* Inf bits (positive) */
  466#define F64_BITS_INF U64(0x7FF00000, 0x00000000)
  467
  468/* NaN bits (quiet NaN, no payload, no sign) */
  469#if defined(__hppa__) || (defined(__mips__) && !defined(__mips_nan2008))
  470#define F64_BITS_NAN U64(0x7FF7FFFF, 0xFFFFFFFF)
  471#else
  472#define F64_BITS_NAN U64(0x7FF80000, 0x00000000)
  473#endif
  474
  475/* maximum significant digits count in decimal when reading double number */
  476#define F64_MAX_DEC_DIG 768
  477
  478/* maximum decimal power of double number (1.7976931348623157e308) */
  479#define F64_MAX_DEC_EXP 308
  480
  481/* minimum decimal power of double number (4.9406564584124654e-324) */
  482#define F64_MIN_DEC_EXP (-324)
  483
  484/* maximum binary power of double number */
  485#define F64_MAX_BIN_EXP 1024
  486
  487/* minimum binary power of double number */
  488#define F64_MIN_BIN_EXP (-1021)
  489
  490/* float/double number bits */
  491#define F32_BITS 32
  492#define F64_BITS 64
  493
  494/* float/double number exponent part bits */
  495#define F32_EXP_BITS 8
  496#define F64_EXP_BITS 11
  497
  498/* float/double number significand part bits */
  499#define F32_SIG_BITS 23
  500#define F64_SIG_BITS 52
  501
  502/* float/double number significand part bits (with 1 hidden bit) */
  503#define F32_SIG_FULL_BITS 24
  504#define F64_SIG_FULL_BITS 53
  505
  506/* float/double number significand bit mask */
  507#define F32_SIG_MASK U32(0x007FFFFF)
  508#define F64_SIG_MASK U64(0x000FFFFF, 0xFFFFFFFF)
  509
  510/* float/double number exponent bit mask */
  511#define F32_EXP_MASK U32(0x7F800000)
  512#define F64_EXP_MASK U64(0x7FF00000, 0x00000000)
  513
  514/* float/double number exponent bias */
  515#define F32_EXP_BIAS 127
  516#define F64_EXP_BIAS 1023
  517
  518/* float/double number significant digits count in decimal */
  519#define F32_DEC_DIG 9
  520#define F64_DEC_DIG 17
  521
  522/* buffer length required for float/double number writer */
  523#define FP_BUF_LEN 40
  524
  525/* maximum length of a number in incremental parsing */
  526#define INCR_NUM_MAX_LEN 1024
  527
  528
  529
  530/*==============================================================================
  531 * MARK: - Types (Private)
  532 *============================================================================*/
  533
  534/** Type aliases for primitive types. */
  535typedef float       f32;
  536typedef double      f64;
  537typedef int8_t      i8;
  538typedef uint8_t     u8;
  539typedef int16_t     i16;
  540typedef uint16_t    u16;
  541typedef int32_t     i32;
  542typedef uint32_t    u32;
  543typedef int64_t     i64;
  544typedef uint64_t    u64;
  545typedef size_t      usize;
  546
  547/** 128-bit integer, used by floating-point number reader and writer. */
  548#if YYJSON_HAS_INT128
  549__extension__ typedef __int128          i128;
  550__extension__ typedef unsigned __int128 u128;
  551#endif
  552
  553/** 16/32/64-bit vector */
  554typedef struct v16 { char c[2]; } v16;
  555typedef struct v32 { char c[4]; } v32;
  556typedef struct v64 { char c[8]; } v64;
  557
  558/** 16/32/64-bit vector union */
  559typedef union v16_uni { v16 v; u16 u; } v16_uni;
  560typedef union v32_uni { v32 v; u32 u; } v32_uni;
  561typedef union v64_uni { v64 v; u64 u; } v64_uni;
  562
  563
  564
  565/*==============================================================================
  566 * MARK: - Load/Store Utils (Private)
  567 *============================================================================*/
  568
  569#define byte_move_idx(x) ((char *)dst)[x] = ((const char *)src)[x];
  570#define byte_move_src(x) ((char *)tmp)[x] = ((const char *)src)[x];
  571#define byte_move_dst(x) ((char *)dst)[x] = ((const char *)tmp)[x];
  572
  573/** Same as `memcpy(dst, src, 2)`, no overlap. */
  574static_inline void byte_copy_2(void *dst, const void *src) {
  575#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
  576    memcpy(dst, src, 2);
  577#else
  578    repeat2_incr(byte_move_idx)
  579#endif
  580}
  581
  582/** Same as `memcpy(dst, src, 4)`, no overlap. */
  583static_inline void byte_copy_4(void *dst, const void *src) {
  584#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
  585    memcpy(dst, src, 4);
  586#else
  587    repeat4_incr(byte_move_idx)
  588#endif
  589}
  590
  591/** Same as `memcpy(dst, src, 8)`, no overlap. */
  592static_inline void byte_copy_8(void *dst, const void *src) {
  593#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
  594    memcpy(dst, src, 8);
  595#else
  596    repeat8_incr(byte_move_idx)
  597#endif
  598}
  599
  600/** Same as `memcpy(dst, src, 16)`, no overlap. */
  601static_inline void byte_copy_16(void *dst, const void *src) {
  602#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
  603    memcpy(dst, src, 16);
  604#else
  605    repeat16_incr(byte_move_idx)
  606#endif
  607}
  608
  609/** Same as `memmove(dst, src, 2)`, allows overlap. */
  610static_inline void byte_move_2(void *dst, const void *src) {
  611#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
  612    u16 tmp;
  613    memcpy(&tmp, src, 2);
  614    memcpy(dst, &tmp, 2);
  615#else
  616    char tmp[2];
  617    repeat2_incr(byte_move_src)
  618    repeat2_incr(byte_move_dst)
  619#endif
  620}
  621
  622/** Same as `memmove(dst, src, 4)`, allows overlap. */
  623static_inline void byte_move_4(void *dst, const void *src) {
  624#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
  625    u32 tmp;
  626    memcpy(&tmp, src, 4);
  627    memcpy(dst, &tmp, 4);
  628#else
  629    char tmp[4];
  630    repeat4_incr(byte_move_src)
  631    repeat4_incr(byte_move_dst)
  632#endif
  633}
  634
  635/** Same as `memmove(dst, src, 8)`, allows overlap. */
  636static_inline void byte_move_8(void *dst, const void *src) {
  637#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
  638    u64 tmp;
  639    memcpy(&tmp, src, 8);
  640    memcpy(dst, &tmp, 8);
  641#else
  642    char tmp[8];
  643    repeat8_incr(byte_move_src)
  644    repeat8_incr(byte_move_dst)
  645#endif
  646}
  647
  648/** Same as `memmove(dst, src, 16)`, allows overlap. */
  649static_inline void byte_move_16(void *dst, const void *src) {
  650#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
  651    char *pdst = (char *)dst;
  652    const char *psrc = (const char *)src;
  653    u64 tmp1, tmp2;
  654    memcpy(&tmp1, psrc, 8);
  655    memcpy(&tmp2, psrc + 8, 8);
  656    memcpy(pdst, &tmp1, 8);
  657    memcpy(pdst + 8, &tmp2, 8);
  658#else
  659    char tmp[16];
  660    repeat16_incr(byte_move_src)
  661    repeat16_incr(byte_move_dst)
  662#endif
  663}
  664
  665/** Same as `memmove(dst, src, n)`, but only `dst <= src` and `n <= 16`. */
  666static_inline void byte_move_forward(void *dst, void *src, usize n) {
  667    char *d = (char *)dst, *s = (char *)src;
  668    n += (n % 2); /* round up to even */
  669    if (n == 16) { byte_move_16(d, s); return; }
  670    if (n >= 8) { byte_move_8(d, s); n -= 8; d += 8; s += 8; }
  671    if (n >= 4) { byte_move_4(d, s); n -= 4; d += 4; s += 4; }
  672    if (n >= 2) { byte_move_2(d, s); }
  673}
  674
  675/** Same as `memcmp(buf, pat, 2) == 0`. */
  676static_inline bool byte_match_2(void *buf, const char *pat) {
  677#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
  678    v16_uni u1, u2;
  679    memcpy(&u1, buf, 2);
  680    memcpy(&u2, pat, 2);
  681    return u1.u == u2.u;
  682#else
  683    return ((char *)buf)[0] == ((const char *)pat)[0] &&
  684           ((char *)buf)[1] == ((const char *)pat)[1];
  685#endif
  686}
  687
  688/** Same as `memcmp(buf, pat, 4) == 0`. */
  689static_inline bool byte_match_4(void *buf, const char *pat) {
  690#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
  691    v32_uni u1, u2;
  692    memcpy(&u1, buf, 4);
  693    memcpy(&u2, pat, 4);
  694    return u1.u == u2.u;
  695#else
  696    return ((char *)buf)[0] == ((const char *)pat)[0] &&
  697           ((char *)buf)[1] == ((const char *)pat)[1] &&
  698           ((char *)buf)[2] == ((const char *)pat)[2] &&
  699           ((char *)buf)[3] == ((const char *)pat)[3];
  700#endif
  701}
  702
  703/** Loads 2 bytes from `src` as a u16 (native-endian). */
  704static_inline u16 byte_load_2(const void *src) {
  705    v16_uni uni;
  706#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
  707    memcpy(&uni, src, 2);
  708#else
  709    uni.v.c[0] = ((const char *)src)[0];
  710    uni.v.c[1] = ((const char *)src)[1];
  711#endif
  712    return uni.u;
  713}
  714
  715/** Loads 3 bytes from `src` as a u32 (native-endian). */
  716static_inline u32 byte_load_3(const void *src) {
  717    v32_uni uni;
  718#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
  719    memcpy(&uni, src, 2);
  720    uni.v.c[2] = ((const char *)src)[2];
  721    uni.v.c[3] = 0;
  722#else
  723    uni.v.c[0] = ((const char *)src)[0];
  724    uni.v.c[1] = ((const char *)src)[1];
  725    uni.v.c[2] = ((const char *)src)[2];
  726    uni.v.c[3] = 0;
  727#endif
  728    return uni.u;
  729}
  730
  731/** Loads 4 bytes from `src` as a u32 (native-endian). */
  732static_inline u32 byte_load_4(const void *src) {
  733    v32_uni uni;
  734#if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS
  735    memcpy(&uni, src, 4);
  736#else
  737    uni.v.c[0] = ((const char *)src)[0];
  738    uni.v.c[1] = ((const char *)src)[1];
  739    uni.v.c[2] = ((const char *)src)[2];
  740    uni.v.c[3] = ((const char *)src)[3];
  741#endif
  742    return uni.u;
  743}
  744
  745
  746
  747/*==============================================================================
  748 * MARK: - Character Utils (Private)
  749 * These lookup tables were generated by `misc/make_tables.c`.
  750 *============================================================================*/
  751
  752/* char_table1 */
  753#define CHAR_TYPE_ASCII     (1 << 0) /* Except: ["\], [0x00-0x1F, 0x80-0xFF] */
  754#define CHAR_TYPE_ASCII_SQ  (1 << 1) /* Except: ['\], [0x00-0x1F, 0x80-0xFF] */
  755#define CHAR_TYPE_SPACE     (1 << 2) /* Whitespace: [ \t\n\r] */
  756#define CHAR_TYPE_SPACE_EXT (1 << 3) /* Whitespace: [ \t\n\r\v\f], JSON5 */
  757#define CHAR_TYPE_NUM       (1 << 4) /* Number: [.-+0-9] */
  758#define CHAR_TYPE_COMMENT   (1 << 5) /* Comment: [/] */
  759
  760/* char_table2 */
  761#define CHAR_TYPE_EOL       (1 << 0) /* End of line: [\r\n] */
  762#define CHAR_TYPE_EOL_EXT   (1 << 1) /* End of line: [\r\n], JSON5 */
  763#define CHAR_TYPE_ID_START  (1 << 2) /* ID start: [_$A-Za-z\], U+0080+ */
  764#define CHAR_TYPE_ID_NEXT   (1 << 3) /* ID next: [_$A-Za-z0-9\], U+0080+ */
  765#define CHAR_TYPE_ID_ASCII  (1 << 4) /* ID next ASCII: [_$A-Za-z0-9] */
  766
  767/* char_table3 */
  768#define CHAR_TYPE_SIGN      (1 << 0) /* [-+] */
  769#define CHAR_TYPE_DIGIT     (1 << 1) /* [0-9] */
  770#define CHAR_TYPE_NONZERO   (1 << 2) /* [1-9] */
  771#define CHAR_TYPE_EXP       (1 << 3) /* [eE] */
  772#define CHAR_TYPE_DOT       (1 << 4) /* [.] */
  773
  774static const u8 char_table1[256] = {
  775    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  776    0x00, 0x0C, 0x0C, 0x08, 0x08, 0x0C, 0x00, 0x00,
  777    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  778    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  779    0x0F, 0x03, 0x02, 0x03, 0x03, 0x03, 0x03, 0x01,
  780    0x03, 0x03, 0x03, 0x13, 0x03, 0x13, 0x13, 0x23,
  781    0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
  782    0x13, 0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
  783    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
  784    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
  785    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
  786    0x03, 0x03, 0x03, 0x03, 0x00, 0x03, 0x03, 0x03,
  787    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
  788    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
  789    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
  790    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
  791    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  792    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  793    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  794    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  795    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  796    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  797    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  798    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  799    0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
  800    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  801    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  802    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  803    0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
  804    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
  805    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  806    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  807};
  808
  809static const u8 char_table2[256] = {
  810    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  811    0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
  812    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  813    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  814    0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
  815    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  816    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
  817    0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  818    0x00, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
  819    0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
  820    0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
  821    0x1C, 0x1C, 0x1C, 0x00, 0x0C, 0x00, 0x00, 0x1C,
  822    0x00, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
  823    0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
  824    0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
  825    0x1C, 0x1C, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00,
  826    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
  827    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
  828    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
  829    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
  830    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
  831    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
  832    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
  833    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
  834    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
  835    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
  836    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
  837    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
  838    0x0C, 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
  839    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
  840    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
  841    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C
  842};
  843
  844static const u8 char_table3[256] = {
  845    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  846    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  847    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  848    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  849    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  850    0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x10, 0x00,
  851    0x02, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
  852    0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  853    0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
  854    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  855    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  856    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  857    0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
  858    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  859    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  860    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  861    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  862    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  863    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  864    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  865    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  866    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  867    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  868    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  869    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  870    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  871    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  872    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  873    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  874    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  875    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  876    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  877};
  878
  879/** Match a whitespace: [ \t\n\r]. */
  880static_inline bool char_is_space(u8 c) {
  881    return !!(char_table1[c] & CHAR_TYPE_SPACE);
  882}
  883
  884/** Match an extended whitespace: [ \t\n\r\\v\\f], JSON5 whitespace. */
  885static_inline bool char_is_space_ext(u8 c) {
  886    return !!(char_table1[c] & CHAR_TYPE_SPACE_EXT);
  887}
  888
  889/** Match a JSON number: [.-+0-9]. */
  890static_inline bool char_is_num(u8 c) {
  891    return !!(char_table1[c] & CHAR_TYPE_NUM);
  892}
  893
  894/** Match an ASCII character in string: ["\], [0x00-0x1F, 0x80-0xFF]. */
  895static_inline bool char_is_ascii_skip(u8 c) {
  896    return !!(char_table1[c] & CHAR_TYPE_ASCII);
  897}
  898
  899/** Match an ASCII character single-quoted: ['\], [0x00-0x1F, 0x80-0xFF]. */
  900static_inline bool char_is_ascii_skip_sq(u8 c) {
  901    return !!(char_table1[c] & CHAR_TYPE_ASCII_SQ);
  902}
  903
  904/** Match a trivia character: extended whitespace or comment. */
  905static_inline bool char_is_trivia(u8 c) {
  906    return !!(char_table1[c] & (CHAR_TYPE_SPACE_EXT | CHAR_TYPE_COMMENT));
  907}
  908
  909/** Match a line end character: [\r\n]. */
  910static_inline bool char_is_eol(u8 c) {
  911    return !!(char_table2[c] & CHAR_TYPE_EOL);
  912}
  913
  914/** Match an extended line end character: [\r\n], JSON5 line terminator. */
  915static_inline bool char_is_eol_ext(u8 c) {
  916    return !!(char_table2[c] & CHAR_TYPE_EOL_EXT);
  917}
  918
  919/** Match an identifier name start: [_$A-Za-z\], U+0080+. */
  920static_inline bool char_is_id_start(u8 c) {
  921    return !!(char_table2[c] & CHAR_TYPE_ID_START);
  922}
  923
  924/** Match an identifier name next: [_$A-Za-z0-9\], U+0080+. */
  925static_inline bool char_is_id_next(u8 c) {
  926    return !!(char_table2[c] & CHAR_TYPE_ID_NEXT);
  927}
  928
  929/** Match an identifier name ASCII: [_$A-Za-z0-9]. */
  930static_inline bool char_is_id_ascii(u8 c) {
  931    return !!(char_table2[c] & CHAR_TYPE_ID_ASCII);
  932}
  933
  934/** Match a sign: [+-] */
  935static_inline bool char_is_sign(u8 d) {
  936    return !!(char_table3[d] & CHAR_TYPE_SIGN);
  937}
  938
  939/** Match a non-zero digit: [1-9] */
  940static_inline bool char_is_nonzero(u8 d) {
  941    return !!(char_table3[d] & CHAR_TYPE_NONZERO);
  942}
  943
  944/** Match a digit: [0-9] */
  945static_inline bool char_is_digit(u8 d) {
  946    return !!(char_table3[d] & CHAR_TYPE_DIGIT);
  947}
  948
  949/** Match an exponent character: [eE]. */
  950static_inline bool char_is_exp(u8 d) {
  951    return !!(char_table3[d] & CHAR_TYPE_EXP);
  952}
  953
  954/** Match a floating point indicator: [.eE]. */
  955static_inline bool char_is_fp(u8 d) {
  956    return !!(char_table3[d] & (CHAR_TYPE_DOT | CHAR_TYPE_EXP));
  957}
  958
  959/** Match a digit or floating point indicator: [0-9.eE]. */
  960static_inline bool char_is_digit_or_fp(u8 d) {
  961    return !!(char_table3[d] & (CHAR_TYPE_DIGIT | CHAR_TYPE_DOT |
  962                                CHAR_TYPE_EXP));
  963}
  964
  965/** Match a JSON container: `{` or `[`. */
  966static_inline bool char_is_ctn(u8 c) {
  967    return (c & 0xDF) == 0x5B; /* '[': 0x5B, '{': 0x7B */
  968}
  969
  970/** Convert ASCII letter to lowercase; valid only for [A-Za-z]. */
  971static_inline u8 char_to_lower(u8 c) {
  972    return c | 0x20;
  973}
  974
  975/** Match UTF-8 byte order mask. */
  976static_inline bool is_utf8_bom(const u8 *cur) {
  977    return byte_load_3(cur) == byte_load_3("\xEF\xBB\xBF");
  978}
  979
  980/** Match UTF-16 byte order mask. */
  981static_inline bool is_utf16_bom(const u8 *cur) {
  982    return byte_load_2(cur) == byte_load_2("\xFE\xFF") ||
  983           byte_load_2(cur) == byte_load_2("\xFF\xFE");
  984}
  985
  986/** Match UTF-32 byte order mask, need length check to avoid zero padding. */
  987static_inline bool is_utf32_bom(const u8 *cur) {
  988    return byte_load_4(cur) == byte_load_4("\x00\x00\xFE\xFF") ||
  989           byte_load_4(cur) == byte_load_4("\xFF\xFE\x00\x00");
  990}
  991
  992/** Get the extended line end length. Used with `char_is_eol_ext`. */
  993static_inline usize ext_eol_len(const u8 *cur) {
  994    if (cur[0] < 0x80) return 1;
  995    if (cur[1] == 0x80 && (cur[2] == 0xA8 || cur[2] == 0xA9)) return 3;
  996    return 0;
  997}
  998
  999/** Get the extended whitespace length. Used with `char_is_space_ext`. */
 1000static_inline usize ext_space_len(const u8 *cur) {
 1001    if (cur[0] < 0x80) {
 1002        return 1;
 1003    } else if (byte_load_2(cur) == byte_load_2("\xC2\xA0")) {
 1004        return 2;
 1005    } else if (byte_load_2(cur) == byte_load_2("\xE2\x80")) {
 1006        if (cur[2] >= 0x80 && cur[2] <= 0x8A) return 3;
 1007        if (cur[2] == 0xA8 || cur[2] == 0xA9 || cur[2] == 0xAF) return 3;
 1008    } else {
 1009        u32 uni = byte_load_3(cur);
 1010        if (uni == byte_load_3("\xE1\x9A\x80") ||
 1011            uni == byte_load_3("\xE2\x81\x9F") ||
 1012            uni == byte_load_3("\xE3\x80\x80") ||
 1013            uni == byte_load_3("\xEF\xBB\xBF")) return 3;
 1014    }
 1015    return 0;
 1016}
 1017
 1018
 1019
 1020/*==============================================================================
 1021 * MARK: - Hex Character Reader (Private)
 1022 * This function is used by JSON reader to read escaped characters.
 1023 *============================================================================*/
 1024
 1025/**
 1026 This table is used to convert a 4-hex-character sequence to a number.
 1027 A valid hex character [0-9A-Fa-f] is mapped to its raw value [0x00, 0x0F];
 1028 an invalid hex character is mapped to [0xF0].
 1029 (generated with misc/make_tables.c)
 1030 */
 1031static const u8 hex_conv_table[256] = {
 1032    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1033    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1034    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1035    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1036    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1037    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1038    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 1039    0x08, 0x09, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1040    0xF0, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF0,
 1041    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1042    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1043    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1044    0xF0, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF0,
 1045    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1046    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1047    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1048    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1049    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1050    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1051    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1052    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1053    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1054    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1055    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1056    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1057    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1058    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1059    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1060    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1061    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1062    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
 1063    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0
 1064};
 1065
 1066/** Load 4 hex characters to `u16`, return true on valid input. */
 1067static_inline bool hex_load_4(const u8 *src, u16 *dst) {
 1068    u16 c0 = hex_conv_table[src[0]];
 1069    u16 c1 = hex_conv_table[src[1]];
 1070    u16 c2 = hex_conv_table[src[2]];
 1071    u16 c3 = hex_conv_table[src[3]];
 1072    u16 t0 = (u16)((c0 << 8) | c2);
 1073    u16 t1 = (u16)((c1 << 8) | c3);
 1074    *dst = (u16)((t0 << 4) | t1);
 1075    return ((t0 | t1) & (u16)0xF0F0) == 0;
 1076}
 1077
 1078/** Load 2 hex characters to `u8`, return true on valid input. */
 1079static_inline bool hex_load_2(const u8 *src, u8 *dst) {
 1080    u8 c0 = hex_conv_table[src[0]];
 1081    u8 c1 = hex_conv_table[src[1]];
 1082    *dst = (u8)((c0 << 4) | c1);
 1083    return ((c0 | c1) & 0xF0) == 0;
 1084}
 1085
 1086/** Match a hexadecimal numeric character: [0-9a-fA-F]. */
 1087static_inline bool char_is_hex(u8 c) {
 1088    return hex_conv_table[c] != 0xF0;
 1089}
 1090
 1091
 1092
 1093/*==============================================================================
 1094 * MARK: - UTF8 Validation (Private)
 1095 * Each Unicode code point is encoded using 1 to 4 bytes in UTF-8.
 1096 * Validation is performed using a 4-byte mask and pattern-based approach,
 1097 * which requires the input data to be padded with four zero bytes at the end.
 1098 *============================================================================*/
 1099
 1100/* Macro for concatenating four u8 into a u32 and keeping the byte order. */
 1101#if YYJSON_ENDIAN == YYJSON_LITTLE_ENDIAN
 1102#   define utf8_seq_def(name, a, b, c, d) \
 1103        static const u32 utf8_seq_##name = 0x##d##c##b##a##UL;
 1104#   define utf8_seq(name) utf8_seq_##name
 1105#elif YYJSON_ENDIAN == YYJSON_BIG_ENDIAN
 1106#   define utf8_seq_def(name, a, b, c, d) \
 1107        static const u32 utf8_seq_##name = 0x##a##b##c##d##UL;
 1108#   define utf8_seq(name) utf8_seq_##name
 1109#else
 1110#   define utf8_seq_def(name, a, b, c, d) \
 1111        static const v32_uni utf8_uni_##name = {{ 0x##a, 0x##b, 0x##c, 0x##d }};
 1112#   define utf8_seq(name) utf8_uni_##name.u
 1113#endif
 1114
 1115/*
 1116 1-byte sequence (U+0000 to U+007F)
 1117 bit min        [.......0] (U+0000)
 1118 bit max        [.1111111] (U+007F)
 1119 bit mask       [x.......] (80)
 1120 bit pattern    [0.......] (00)
 1121 */
 1122utf8_seq_def(b1_mask, 80, 00, 00, 00)
 1123utf8_seq_def(b1_patt, 00, 00, 00, 00)
 1124#define is_utf8_seq1(uni) ( \
 1125    ((uni & utf8_seq(b1_mask)) == utf8_seq(b1_patt)) )
 1126
 1127/*
 1128 2-byte sequence (U+0080 to U+07FF)
 1129 bit min        [......10 ..000000] (U+0080)
 1130 bit max        [...11111 ..111111] (U+07FF)
 1131 bit mask       [xxx..... xx......] (E0 C0)
 1132 bit pattern    [110..... 10......] (C0 80)
 1133 bit require    [...xxxx. ........] (1E 00)
 1134 */
 1135utf8_seq_def(b2_mask, E0, C0, 00, 00)
 1136utf8_seq_def(b2_patt, C0, 80, 00, 00)
 1137utf8_seq_def(b2_requ, 1E, 00, 00, 00)
 1138#define is_utf8_seq2(uni) ( \
 1139    ((uni & utf8_seq(b2_mask)) == utf8_seq(b2_patt)) && \
 1140    ((uni & utf8_seq(b2_requ))) )
 1141
 1142/*
 1143 3-byte sequence (U+0800 to U+FFFF)
 1144 bit min        [........ ..100000 ..000000] (U+0800)
 1145 bit max        [....1111 ..111111 ..111111] (U+FFFF)
 1146 bit mask       [xxxx.... xx...... xx......] (F0 C0 C0)
 1147 bit pattern    [1110.... 10...... 10......] (E0 80 80)
 1148 bit require    [....xxxx ..x..... ........] (0F 20 00)
 1149
 1150 3-byte invalid sequence, reserved for surrogate halves (U+D800 to U+DFFF)
 1151 bit min        [....1101 ..100000 ..000000] (U+D800)
 1152 bit max        [....1101 ..111111 ..111111] (U+DFFF)
 1153 bit mask       [....xxxx ..x..... ........] (0F 20 00)
 1154 bit pattern    [....1101 ..1..... ........] (0D 20 00)
 1155 */
 1156utf8_seq_def(b3_mask, F0, C0, C0, 00)
 1157utf8_seq_def(b3_patt, E0, 80, 80, 00)
 1158utf8_seq_def(b3_requ, 0F, 20, 00, 00)
 1159utf8_seq_def(b3_erro, 0D, 20, 00, 00)
 1160#define is_utf8_seq3(uni) ( \
 1161    ((uni & utf8_seq(b3_mask)) == utf8_seq(b3_patt)) && \
 1162    ((tmp = (uni & utf8_seq(b3_requ)))) && \
 1163    ((tmp != utf8_seq(b3_erro))) )
 1164
 1165/*
 1166 4-byte sequence (U+10000 to U+10FFFF)
 1167 bit min        [........ ...10000 ..000000 ..000000] (U+10000)
 1168 bit max        [.....100 ..001111 ..111111 ..111111] (U+10FFFF)
 1169 bit mask       [xxxxx... xx...... xx...... xx......] (F8 C0 C0 C0)
 1170 bit pattern    [11110... 10...... 10...... 10......] (F0 80 80 80)
 1171 bit require    [.....xxx ..xx.... ........ ........] (07 30 00 00)
 1172 bit require 1  [.....x.. ........ ........ ........] (04 00 00 00)
 1173 bit require 2  [......xx ..xx.... ........ ........] (03 30 00 00)
 1174 */
 1175utf8_seq_def(b4_mask, F8, C0, C0, C0)
 1176utf8_seq_def(b4_patt, F0, 80, 80, 80)
 1177utf8_seq_def(b4_requ, 07, 30, 00, 00)
 1178utf8_seq_def(b4_req1, 04, 00, 00, 00)
 1179utf8_seq_def(b4_req2, 03, 30, 00, 00)
 1180#define is_utf8_seq4(uni) ( \
 1181    ((uni & utf8_seq(b4_mask)) == utf8_seq(b4_patt)) && \
 1182    ((tmp = (uni & utf8_seq(b4_requ)))) && \
 1183    ((tmp & utf8_seq(b4_req1)) == 0 || (tmp & utf8_seq(b4_req2)) == 0) )
 1184
 1185
 1186
 1187/*==============================================================================
 1188 * MARK: - Power10 Lookup Table (Private)
 1189 * These data are used by the floating-point number reader and writer.
 1190 *============================================================================*/
 1191
 1192#if !YYJSON_DISABLE_FAST_FP_CONV
 1193
 1194/** Maximum pow10 exponent that can be represented exactly as a float64. */
 1195#define F64_POW10_MAX_EXACT_EXP 22
 1196
 1197#if YYJSON_DOUBLE_MATH_CORRECT
 1198/** Cached pow10 table. */
 1199static const f64 f64_pow10_table[F64_POW10_MAX_EXACT_EXP + 1] = {
 1200    1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12,
 1201    1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22
 1202};
 1203#endif
 1204
 1205/** Maximum pow10 exponent that can be represented exactly as a uint64. */
 1206#define U64_POW10_MAX_EXACT_EXP 19
 1207
 1208/** Table: [ 10^0, ..., 10^19 ] (generated with misc/make_tables.c) */
 1209static const u64 u64_pow10_table[U64_POW10_MAX_EXACT_EXP + 1] = {
 1210    U64(0x00000000, 0x00000001), U64(0x00000000, 0x0000000A),
 1211    U64(0x00000000, 0x00000064), U64(0x00000000, 0x000003E8),
 1212    U64(0x00000000, 0x00002710), U64(0x00000000, 0x000186A0),
 1213    U64(0x00000000, 0x000F4240), U64(0x00000000, 0x00989680),
 1214    U64(0x00000000, 0x05F5E100), U64(0x00000000, 0x3B9ACA00),
 1215    U64(0x00000002, 0x540BE400), U64(0x00000017, 0x4876E800),
 1216    U64(0x000000E8, 0xD4A51000), U64(0x00000918, 0x4E72A000),
 1217    U64(0x00005AF3, 0x107A4000), U64(0x00038D7E, 0xA4C68000),
 1218    U64(0x002386F2, 0x6FC10000), U64(0x01634578, 0x5D8A0000),
 1219    U64(0x0DE0B6B3, 0xA7640000), U64(0x8AC72304, 0x89E80000)
 1220};
 1221
 1222/** Minimum decimal exponent in pow10_sig_table. */
 1223#define POW10_SIG_TABLE_MIN_EXP -343
 1224
 1225/** Maximum decimal exponent in pow10_sig_table. */
 1226#define POW10_SIG_TABLE_MAX_EXP 324
 1227
 1228/** Minimum exact decimal exponent in pow10_sig_table */
 1229#define POW10_SIG_TABLE_MIN_EXACT_EXP 0
 1230
 1231/** Maximum exact decimal exponent in pow10_sig_table */
 1232#define POW10_SIG_TABLE_MAX_EXACT_EXP 55
 1233
 1234/** Normalized significant 128 bits of pow10, not rounded up (size: 10.4KB).
 1235    This lookup table is used by both the double number reader and writer.
 1236    (generated with misc/make_tables.c) */
 1237static const u64 pow10_sig_table[] = {
 1238    U64(0xBF29DCAB, 0xA82FDEAE), U64(0x7432EE87, 0x3880FC33), /* ~= 10^-343 */
 1239    U64(0xEEF453D6, 0x923BD65A), U64(0x113FAA29, 0x06A13B3F), /* ~= 10^-342 */
 1240    U64(0x9558B466, 0x1B6565F8), U64(0x4AC7CA59, 0xA424C507), /* ~= 10^-341 */
 1241    U64(0xBAAEE17F, 0xA23EBF76), U64(0x5D79BCF0, 0x0D2DF649), /* ~= 10^-340 */
 1242    U64(0xE95A99DF, 0x8ACE6F53), U64(0xF4D82C2C, 0x107973DC), /* ~= 10^-339 */
 1243    U64(0x91D8A02B, 0xB6C10594), U64(0x79071B9B, 0x8A4BE869), /* ~= 10^-338 */
 1244    U64(0xB64EC836, 0xA47146F9), U64(0x9748E282, 0x6CDEE284), /* ~= 10^-337 */
 1245    U64(0xE3E27A44, 0x4D8D98B7), U64(0xFD1B1B23, 0x08169B25), /* ~= 10^-336 */
 1246    U64(0x8E6D8C6A, 0xB0787F72), U64(0xFE30F0F5, 0xE50E20F7), /* ~= 10^-335 */
 1247    U64(0xB208EF85, 0x5C969F4F), U64(0xBDBD2D33, 0x5E51A935), /* ~= 10^-334 */
 1248    U64(0xDE8B2B66, 0xB3BC4723), U64(0xAD2C7880, 0x35E61382), /* ~= 10^-333 */
 1249    U64(0x8B16FB20, 0x3055AC76), U64(0x4C3BCB50, 0x21AFCC31), /* ~= 10^-332 */
 1250    U64(0xADDCB9E8, 0x3C6B1793), U64(0xDF4ABE24, 0x2A1BBF3D), /* ~= 10^-331 */
 1251    U64(0xD953E862, 0x4B85DD78), U64(0xD71D6DAD, 0x34A2AF0D), /* ~= 10^-330 */
 1252    U64(0x87D4713D, 0x6F33AA6B), U64(0x8672648C, 0x40E5AD68), /* ~= 10^-329 */
 1253    U64(0xA9C98D8C, 0xCB009506), U64(0x680EFDAF, 0x511F18C2), /* ~= 10^-328 */
 1254    U64(0xD43BF0EF, 0xFDC0BA48), U64(0x0212BD1B, 0x2566DEF2), /* ~= 10^-327 */
 1255    U64(0x84A57695, 0xFE98746D), U64(0x014BB630, 0xF7604B57), /* ~= 10^-326 */
 1256    U64(0xA5CED43B, 0x7E3E9188), U64(0x419EA3BD, 0x35385E2D), /* ~= 10^-325 */
 1257    U64(0xCF42894A, 0x5DCE35EA), U64(0x52064CAC, 0x828675B9), /* ~= 10^-324 */
 1258    U64(0x818995CE, 0x7AA0E1B2), U64(0x7343EFEB, 0xD1940993), /* ~= 10^-323 */
 1259    U64(0xA1EBFB42, 0x19491A1F), U64(0x1014EBE6, 0xC5F90BF8), /* ~= 10^-322 */
 1260    U64(0xCA66FA12, 0x9F9B60A6), U64(0xD41A26E0, 0x77774EF6), /* ~= 10^-321 */
 1261    U64(0xFD00B897, 0x478238D0), U64(0x8920B098, 0x955522B4), /* ~= 10^-320 */
 1262    U64(0x9E20735E, 0x8CB16382), U64(0x55B46E5F, 0x5D5535B0), /* ~= 10^-319 */
 1263    U64(0xC5A89036, 0x2FDDBC62), U64(0xEB2189F7, 0x34AA831D), /* ~= 10^-318 */
 1264    U64(0xF712B443, 0xBBD52B7B), U64(0xA5E9EC75, 0x01D523E4), /* ~= 10^-317 */
 1265    U64(0x9A6BB0AA, 0x55653B2D), U64(0x47B233C9, 0x2125366E), /* ~= 10^-316 */
 1266    U64(0xC1069CD4, 0xEABE89F8), U64(0x999EC0BB, 0x696E840A), /* ~= 10^-315 */
 1267    U64(0xF148440A, 0x256E2C76), U64(0xC00670EA, 0x43CA250D), /* ~= 10^-314 */
 1268    U64(0x96CD2A86, 0x5764DBCA), U64(0x38040692, 0x6A5E5728), /* ~= 10^-313 */
 1269    U64(0xBC807527, 0xED3E12BC), U64(0xC6050837, 0x04F5ECF2), /* ~= 10^-312 */
 1270    U64(0xEBA09271, 0xE88D976B), U64(0xF7864A44, 0xC633682E), /* ~= 10^-311 */
 1271    U64(0x93445B87, 0x31587EA3), U64(0x7AB3EE6A, 0xFBE0211D), /* ~= 10^-310 */
 1272    U64(0xB8157268, 0xFDAE9E4C), U64(0x5960EA05, 0xBAD82964), /* ~= 10^-309 */
 1273    U64(0xE61ACF03, 0x3D1A45DF), U64(0x6FB92487, 0x298E33BD), /* ~= 10^-308 */
 1274    U64(0x8FD0C162, 0x06306BAB), U64(0xA5D3B6D4, 0x79F8E056), /* ~= 10^-307 */
 1275    U64(0xB3C4F1BA, 0x87BC8696), U64(0x8F48A489, 0x9877186C), /* ~= 10^-306 */
 1276    U64(0xE0B62E29, 0x29ABA83C), U64(0x331ACDAB, 0xFE94DE87), /* ~= 10^-305 */
 1277    U64(0x8C71DCD9, 0xBA0B4925), U64(0x9FF0C08B, 0x7F1D0B14), /* ~= 10^-304 */
 1278    U64(0xAF8E5410, 0x288E1B6F), U64(0x07ECF0AE, 0x5EE44DD9), /* ~= 10^-303 */
 1279    U64(0xDB71E914, 0x32B1A24A), U64(0xC9E82CD9, 0xF69D6150), /* ~= 10^-302 */
 1280    U64(0x892731AC, 0x9FAF056E), U64(0xBE311C08, 0x3A225CD2), /* ~= 10^-301 */
 1281    U64(0xAB70FE17, 0xC79AC6CA), U64(0x6DBD630A, 0x48AAF406), /* ~= 10^-300 */
 1282    U64(0xD64D3D9D, 0xB981787D), U64(0x092CBBCC, 0xDAD5B108), /* ~= 10^-299 */
 1283    U64(0x85F04682, 0x93F0EB4E), U64(0x25BBF560, 0x08C58EA5), /* ~= 10^-298 */
 1284    U64(0xA76C5823, 0x38ED2621), U64(0xAF2AF2B8, 0x0AF6F24E), /* ~= 10^-297 */
 1285    U64(0xD1476E2C, 0x07286FAA), U64(0x1AF5AF66, 0x0DB4AEE1), /* ~= 10^-296 */
 1286    U64(0x82CCA4DB, 0x847945CA), U64(0x50D98D9F, 0xC890ED4D), /* ~= 10^-295 */
 1287    U64(0xA37FCE12, 0x6597973C), U64(0xE50FF107, 0xBAB528A0), /* ~= 10^-294 */
 1288    U64(0xCC5FC196, 0xFEFD7D0C), U64(0x1E53ED49, 0xA96272C8), /* ~= 10^-293 */
 1289    U64(0xFF77B1FC, 0xBEBCDC4F), U64(0x25E8E89C, 0x13BB0F7A), /* ~= 10^-292 */
 1290    U64(0x9FAACF3D, 0xF73609B1), U64(0x77B19161, 0x8C54E9AC), /* ~= 10^-291 */
 1291    U64(0xC795830D, 0x75038C1D), U64(0xD59DF5B9, 0xEF6A2417), /* ~= 10^-290 */
 1292    U64(0xF97AE3D0, 0xD2446F25), U64(0x4B057328, 0x6B44AD1D), /* ~= 10^-289 */
 1293    U64(0x9BECCE62, 0x836AC577), U64(0x4EE367F9, 0x430AEC32), /* ~= 10^-288 */
 1294    U64(0xC2E801FB, 0x244576D5), U64(0x229C41F7, 0x93CDA73F), /* ~= 10^-287 */
 1295    U64(0xF3A20279, 0xED56D48A), U64(0x6B435275, 0x78C1110F), /* ~= 10^-286 */
 1296    U64(0x9845418C, 0x345644D6), U64(0x830A1389, 0x6B78AAA9), /* ~= 10^-285 */
 1297    U64(0xBE5691EF, 0x416BD60C), U64(0x23CC986B, 0xC656D553), /* ~= 10^-284 */
 1298    U64(0xEDEC366B, 0x11C6CB8F), U64(0x2CBFBE86, 0xB7EC8AA8), /* ~= 10^-283 */
 1299    U64(0x94B3A202, 0xEB1C3F39), U64(0x7BF7D714, 0x32F3D6A9), /* ~= 10^-282 */
 1300    U64(0xB9E08A83, 0xA5E34F07), U64(0xDAF5CCD9, 0x3FB0CC53), /* ~= 10^-281 */
 1301    U64(0xE858AD24, 0x8F5C22C9), U64(0xD1B3400F, 0x8F9CFF68), /* ~= 10^-280 */
 1302    U64(0x91376C36, 0xD99995BE), U64(0x23100809, 0xB9C21FA1), /* ~= 10^-279 */
 1303    U64(0xB5854744, 0x8FFFFB2D), U64(0xABD40A0C, 0x2832A78A), /* ~= 10^-278 */
 1304    U64(0xE2E69915, 0xB3FFF9F9), U64(0x16C90C8F, 0x323F516C), /* ~= 10^-277 */
 1305    U64(0x8DD01FAD, 0x907FFC3B), U64(0xAE3DA7D9, 0x7F6792E3), /* ~= 10^-276 */
 1306    U64(0xB1442798, 0xF49FFB4A), U64(0x99CD11CF, 0xDF41779C), /* ~= 10^-275 */
 1307    U64(0xDD95317F, 0x31C7FA1D), U64(0x40405643, 0xD711D583), /* ~= 10^-274 */
 1308    U64(0x8A7D3EEF, 0x7F1CFC52), U64(0x482835EA, 0x666B2572), /* ~= 10^-273 */
 1309    U64(0xAD1C8EAB, 0x5EE43B66), U64(0xDA324365, 0x0005EECF), /* ~= 10^-272 */
 1310    U64(0xD863B256, 0x369D4A40), U64(0x90BED43E, 0x40076A82), /* ~= 10^-271 */
 1311    U64(0x873E4F75, 0xE2224E68), U64(0x5A7744A6, 0xE804A291), /* ~= 10^-270 */
 1312    U64(0xA90DE353, 0x5AAAE202), U64(0x711515D0, 0xA205CB36), /* ~= 10^-269 */
 1313    U64(0xD3515C28, 0x31559A83), U64(0x0D5A5B44, 0xCA873E03), /* ~= 10^-268 */
 1314    U64(0x8412D999, 0x1ED58091), U64(0xE858790A, 0xFE9486C2), /* ~= 10^-267 */
 1315    U64(0xA5178FFF, 0x668AE0B6), U64(0x626E974D, 0xBE39A872), /* ~= 10^-266 */
 1316    U64(0xCE5D73FF, 0x402D98E3), U64(0xFB0A3D21, 0x2DC8128F), /* ~= 10^-265 */
 1317    U64(0x80FA687F, 0x881C7F8E), U64(0x7CE66634, 0xBC9D0B99), /* ~= 10^-264 */
 1318    U64(0xA139029F, 0x6A239F72), U64(0x1C1FFFC1, 0xEBC44E80), /* ~= 10^-263 */
 1319    U64(0xC9874347, 0x44AC874E), U64(0xA327FFB2, 0x66B56220), /* ~= 10^-262 */
 1320    U64(0xFBE91419, 0x15D7A922), U64(0x4BF1FF9F, 0x0062BAA8), /* ~= 10^-261 */
 1321    U64(0x9D71AC8F, 0xADA6C9B5), U64(0x6F773FC3, 0x603DB4A9), /* ~= 10^-260 */
 1322    U64(0xC4CE17B3, 0x99107C22), U64(0xCB550FB4, 0x384D21D3), /* ~= 10^-259 */
 1323    U64(0xF6019DA0, 0x7F549B2B), U64(0x7E2A53A1, 0x46606A48), /* ~= 10^-258 */
 1324    U64(0x99C10284, 0x4F94E0FB), U64(0x2EDA7444, 0xCBFC426D), /* ~= 10^-257 */
 1325    U64(0xC0314325, 0x637A1939), U64(0xFA911155, 0xFEFB5308), /* ~= 10^-256 */
 1326    U64(0xF03D93EE, 0xBC589F88), U64(0x793555AB, 0x7EBA27CA), /* ~= 10^-255 */
 1327    U64(0x96267C75, 0x35B763B5), U64(0x4BC1558B, 0x2F3458DE), /* ~= 10^-254 */
 1328    U64(0xBBB01B92, 0x83253CA2), U64(0x9EB1AAED, 0xFB016F16), /* ~= 10^-253 */
 1329    U64(0xEA9C2277, 0x23EE8BCB), U64(0x465E15A9, 0x79C1CADC), /* ~= 10^-252 */
 1330    U64(0x92A1958A, 0x7675175F), U64(0x0BFACD89, 0xEC191EC9), /* ~= 10^-251 */
 1331    U64(0xB749FAED, 0x14125D36), U64(0xCEF980EC, 0x671F667B), /* ~= 10^-250 */
 1332    U64(0xE51C79A8, 0x5916F484), U64(0x82B7E127, 0x80E7401A), /* ~= 10^-249 */
 1333    U64(0x8F31CC09, 0x37AE58D2), U64(0xD1B2ECB8, 0xB0908810), /* ~= 10^-248 */
 1334    U64(0xB2FE3F0B, 0x8599EF07), U64(0x861FA7E6, 0xDCB4AA15), /* ~= 10^-247 */
 1335    U64(0xDFBDCECE, 0x67006AC9), U64(0x67A791E0, 0x93E1D49A), /* ~= 10^-246 */
 1336    U64(0x8BD6A141, 0x006042BD), U64(0xE0C8BB2C, 0x5C6D24E0), /* ~= 10^-245 */
 1337    U64(0xAECC4991, 0x4078536D), U64(0x58FAE9F7, 0x73886E18), /* ~= 10^-244 */
 1338    U64(0xDA7F5BF5, 0x90966848), U64(0xAF39A475, 0x506A899E), /* ~= 10^-243 */
 1339    U64(0x888F9979, 0x7A5E012D), U64(0x6D8406C9, 0x52429603), /* ~= 10^-242 */
 1340    U64(0xAAB37FD7, 0xD8F58178), U64(0xC8E5087B, 0xA6D33B83), /* ~= 10^-241 */
 1341    U64(0xD5605FCD, 0xCF32E1D6), U64(0xFB1E4A9A, 0x90880A64), /* ~= 10^-240 */
 1342    U64(0x855C3BE0, 0xA17FCD26), U64(0x5CF2EEA0, 0x9A55067F), /* ~= 10^-239 */
 1343    U64(0xA6B34AD8, 0xC9DFC06F), U64(0xF42FAA48, 0xC0EA481E), /* ~= 10^-238 */
 1344    U64(0xD0601D8E, 0xFC57B08B), U64(0xF13B94DA, 0xF124DA26), /* ~= 10^-237 */
 1345    U64(0x823C1279, 0x5DB6CE57), U64(0x76C53D08, 0xD6B70858), /* ~= 10^-236 */
 1346    U64(0xA2CB1717, 0xB52481ED), U64(0x54768C4B, 0x0C64CA6E), /* ~= 10^-235 */
 1347    U64(0xCB7DDCDD, 0xA26DA268), U64(0xA9942F5D, 0xCF7DFD09), /* ~= 10^-234 */
 1348    U64(0xFE5D5415, 0x0B090B02), U64(0xD3F93B35, 0x435D7C4C), /* ~= 10^-233 */
 1349    U64(0x9EFA548D, 0x26E5A6E1), U64(0xC47BC501, 0x4A1A6DAF), /* ~= 10^-232 */
 1350    U64(0xC6B8E9B0, 0x709F109A), U64(0x359AB641, 0x9CA1091B), /* ~= 10^-231 */
 1351    U64(0xF867241C, 0x8CC6D4C0), U64(0xC30163D2, 0x03C94B62), /* ~= 10^-230 */
 1352    U64(0x9B407691, 0xD7FC44F8), U64(0x79E0DE63, 0x425DCF1D), /* ~= 10^-229 */
 1353    U64(0xC2109436, 0x4DFB5636), U64(0x985915FC, 0x12F542E4), /* ~= 10^-228 */
 1354    U64(0xF294B943, 0xE17A2BC4), U64(0x3E6F5B7B, 0x17B2939D), /* ~= 10^-227 */
 1355    U64(0x979CF3CA, 0x6CEC5B5A), U64(0xA705992C, 0xEECF9C42), /* ~= 10^-226 */
 1356    U64(0xBD8430BD, 0x08277231), U64(0x50C6FF78, 0x2A838353), /* ~= 10^-225 */
 1357    U64(0xECE53CEC, 0x4A314EBD), U64(0xA4F8BF56, 0x35246428), /* ~= 10^-224 */
 1358    U64(0x940F4613, 0xAE5ED136), U64(0x871B7795, 0xE136BE99), /* ~= 10^-223 */
 1359    U64(0xB9131798, 0x99F68584), U64(0x28E2557B, 0x59846E3F), /* ~= 10^-222 */
 1360    U64(0xE757DD7E, 0xC07426E5), U64(0x331AEADA, 0x2FE589CF), /* ~= 10^-221 */
 1361    U64(0x9096EA6F, 0x3848984F), U64(0x3FF0D2C8, 0x5DEF7621), /* ~= 10^-220 */
 1362    U64(0xB4BCA50B, 0x065ABE63), U64(0x0FED077A, 0x756B53A9), /* ~= 10^-219 */
 1363    U64(0xE1EBCE4D, 0xC7F16DFB), U64(0xD3E84959, 0x12C62894), /* ~= 10^-218 */
 1364    U64(0x8D3360F0, 0x9CF6E4BD), U64(0x64712DD7, 0xABBBD95C), /* ~= 10^-217 */
 1365    U64(0xB080392C, 0xC4349DEC), U64(0xBD8D794D, 0x96AACFB3), /* ~= 10^-216 */
 1366    U64(0xDCA04777, 0xF541C567), U64(0xECF0D7A0, 0xFC5583A0), /* ~= 10^-215 */
 1367    U64(0x89E42CAA, 0xF9491B60), U64(0xF41686C4, 0x9DB57244), /* ~= 10^-214 */
 1368    U64(0xAC5D37D5, 0xB79B6239), U64(0x311C2875, 0xC522CED5), /* ~= 10^-213 */
 1369    U64(0xD77485CB, 0x25823AC7), U64(0x7D633293, 0x366B828B), /* ~= 10^-212 */
 1370    U64(0x86A8D39E, 0xF77164BC), U64(0xAE5DFF9C, 0x02033197), /* ~= 10^-211 */
 1371    U64(0xA8530886, 0xB54DBDEB), U64(0xD9F57F83, 0x0283FDFC), /* ~= 10^-210 */
 1372    U64(0xD267CAA8, 0x62A12D66), U64(0xD072DF63, 0xC324FD7B), /* ~= 10^-209 */
 1373    U64(0x8380DEA9, 0x3DA4BC60), U64(0x4247CB9E, 0x59F71E6D), /* ~= 10^-208 */
 1374    U64(0xA4611653, 0x8D0DEB78), U64(0x52D9BE85, 0xF074E608), /* ~= 10^-207 */
 1375    U64(0xCD795BE8, 0x70516656), U64(0x67902E27, 0x6C921F8B), /* ~= 10^-206 */
 1376    U64(0x806BD971, 0x4632DFF6), U64(0x00BA1CD8, 0xA3DB53B6), /* ~= 10^-205 */
 1377    U64(0xA086CFCD, 0x97BF97F3), U64(0x80E8A40E, 0xCCD228A4), /* ~= 10^-204 */
 1378    U64(0xC8A883C0, 0xFDAF7DF0), U64(0x6122CD12, 0x8006B2CD), /* ~= 10^-203 */
 1379    U64(0xFAD2A4B1, 0x3D1B5D6C), U64(0x796B8057, 0x20085F81), /* ~= 10^-202 */
 1380    U64(0x9CC3A6EE, 0xC6311A63), U64(0xCBE33036, 0x74053BB0), /* ~= 10^-201 */
 1381    U64(0xC3F490AA, 0x77BD60FC), U64(0xBEDBFC44, 0x11068A9C), /* ~= 10^-200 */
 1382    U64(0xF4F1B4D5, 0x15ACB93B), U64(0xEE92FB55, 0x15482D44), /* ~= 10^-199 */
 1383    U64(0x99171105, 0x2D8BF3C5), U64(0x751BDD15, 0x2D4D1C4A), /* ~= 10^-198 */
 1384    U64(0xBF5CD546, 0x78EEF0B6), U64(0xD262D45A, 0x78A0635D), /* ~= 10^-197 */
 1385    U64(0xEF340A98, 0x172AACE4), U64(0x86FB8971, 0x16C87C34), /* ~= 10^-196 */
 1386    U64(0x9580869F, 0x0E7AAC0E), U64(0xD45D35E6, 0xAE3D4DA0), /* ~= 10^-195 */
 1387    U64(0xBAE0A846, 0xD2195712), U64(0x89748360, 0x59CCA109), /* ~= 10^-194 */
 1388    U64(0xE998D258, 0x869FACD7), U64(0x2BD1A438, 0x703FC94B), /* ~= 10^-193 */
 1389    U64(0x91FF8377, 0x5423CC06), U64(0x7B6306A3, 0x4627DDCF), /* ~= 10^-192 */
 1390    U64(0xB67F6455, 0x292CBF08), U64(0x1A3BC84C, 0x17B1D542), /* ~= 10^-191 */
 1391    U64(0xE41F3D6A, 0x7377EECA), U64(0x20CABA5F, 0x1D9E4A93), /* ~= 10^-190 */
 1392    U64(0x8E938662, 0x882AF53E), U64(0x547EB47B, 0x7282EE9C), /* ~= 10^-189 */
 1393    U64(0xB23867FB, 0x2A35B28D), U64(0xE99E619A, 0x4F23AA43), /* ~= 10^-188 */
 1394    U64(0xDEC681F9, 0xF4C31F31), U64(0x6405FA00, 0xE2EC94D4), /* ~= 10^-187 */
 1395    U64(0x8B3C113C, 0x38F9F37E), U64(0xDE83BC40, 0x8DD3DD04), /* ~= 10^-186 */
 1396    U64(0xAE0B158B, 0x4738705E), U64(0x9624AB50, 0xB148D445), /* ~= 10^-185 */
 1397    U64(0xD98DDAEE, 0x19068C76), U64(0x3BADD624, 0xDD9B0957), /* ~= 10^-184 */
 1398    U64(0x87F8A8D4, 0xCFA417C9), U64(0xE54CA5D7, 0x0A80E5D6), /* ~= 10^-183 */
 1399    U64(0xA9F6D30A, 0x038D1DBC), U64(0x5E9FCF4C, 0xCD211F4C), /* ~= 10^-182 */
 1400    U64(0xD47487CC, 0x8470652B), U64(0x7647C320, 0x0069671F), /* ~= 10^-181 */
 1401    U64(0x84C8D4DF, 0xD2C63F3B), U64(0x29ECD9F4, 0x0041E073), /* ~= 10^-180 */
 1402    U64(0xA5FB0A17, 0xC777CF09), U64(0xF4681071, 0x00525890), /* ~= 10^-179 */
 1403    U64(0xCF79CC9D, 0xB955C2CC), U64(0x7182148D, 0x4066EEB4), /* ~= 10^-178 */
 1404    U64(0x81AC1FE2, 0x93D599BF), U64(0xC6F14CD8, 0x48405530), /* ~= 10^-177 */
 1405    U64(0xA21727DB, 0x38CB002F), U64(0xB8ADA00E, 0x5A506A7C), /* ~= 10^-176 */
 1406    U64(0xCA9CF1D2, 0x06FDC03B), U64(0xA6D90811, 0xF0E4851C), /* ~= 10^-175 */
 1407    U64(0xFD442E46, 0x88BD304A), U64(0x908F4A16, 0x6D1DA663), /* ~= 10^-174 */
 1408    U64(0x9E4A9CEC, 0x15763E2E), U64(0x9A598E4E, 0x043287FE), /* ~= 10^-173 */
 1409    U64(0xC5DD4427, 0x1AD3CDBA), U64(0x40EFF1E1, 0x853F29FD), /* ~= 10^-172 */
 1410    U64(0xF7549530, 0xE188C128), U64(0xD12BEE59, 0xE68EF47C), /* ~= 10^-171 */
 1411    U64(0x9A94DD3E, 0x8CF578B9), U64(0x82BB74F8, 0x301958CE), /* ~= 10^-170 */
 1412    U64(0xC13A148E, 0x3032D6E7), U64(0xE36A5236, 0x3C1FAF01), /* ~= 10^-169 */
 1413    U64(0xF18899B1, 0xBC3F8CA1), U64(0xDC44E6C3, 0xCB279AC1), /* ~= 10^-168 */
 1414    U64(0x96F5600F, 0x15A7B7E5), U64(0x29AB103A, 0x5EF8C0B9), /* ~= 10^-167 */
 1415    U64(0xBCB2B812, 0xDB11A5DE), U64(0x7415D448, 0xF6B6F0E7), /* ~= 10^-166 */
 1416    U64(0xEBDF6617, 0x91D60F56), U64(0x111B495B, 0x3464AD21), /* ~= 10^-165 */
 1417    U64(0x936B9FCE, 0xBB25C995), U64(0xCAB10DD9, 0x00BEEC34), /* ~= 10^-164 */
 1418    U64(0xB84687C2, 0x69EF3BFB), U64(0x3D5D514F, 0x40EEA742), /* ~= 10^-163 */
 1419    U64(0xE65829B3, 0x046B0AFA), U64(0x0CB4A5A3, 0x112A5112), /* ~= 10^-162 */
 1420    U64(0x8FF71A0F, 0xE2C2E6DC), U64(0x47F0E785, 0xEABA72AB), /* ~= 10^-161 */
 1421    U64(0xB3F4E093, 0xDB73A093), U64(0x59ED2167, 0x65690F56), /* ~= 10^-160 */
 1422    U64(0xE0F218B8, 0xD25088B8), U64(0x306869C1, 0x3EC3532C), /* ~= 10^-159 */
 1423    U64(0x8C974F73, 0x83725573), U64(0x1E414218, 0xC73A13FB), /* ~= 10^-158 */
 1424    U64(0xAFBD2350, 0x644EEACF), U64(0xE5D1929E, 0xF90898FA), /* ~= 10^-157 */
 1425    U64(0xDBAC6C24, 0x7D62A583), U64(0xDF45F746, 0xB74ABF39), /* ~= 10^-156 */
 1426    U64(0x894BC396, 0xCE5DA772), U64(0x6B8BBA8C, 0x328EB783), /* ~= 10^-155 */
 1427    U64(0xAB9EB47C, 0x81F5114F), U64(0x066EA92F, 0x3F326564), /* ~= 10^-154 */
 1428    U64(0xD686619B, 0xA27255A2), U64(0xC80A537B, 0x0EFEFEBD), /* ~= 10^-153 */
 1429    U64(0x8613FD01, 0x45877585), U64(0xBD06742C, 0xE95F5F36), /* ~= 10^-152 */
 1430    U64(0xA798FC41, 0x96E952E7), U64(0x2C481138, 0x23B73704), /* ~= 10^-151 */
 1431    U64(0xD17F3B51, 0xFCA3A7A0), U64(0xF75A1586, 0x2CA504C5), /* ~= 10^-150 */
 1432    U64(0x82EF8513, 0x3DE648C4), U64(0x9A984D73, 0xDBE722FB), /* ~= 10^-149 */
 1433    U64(0xA3AB6658, 0x0D5FDAF5), U64(0xC13E60D0, 0xD2E0EBBA), /* ~= 10^-148 */
 1434    U64(0xCC963FEE, 0x10B7D1B3), U64(0x318DF905, 0x079926A8), /* ~= 10^-147 */
 1435    U64(0xFFBBCFE9, 0x94E5C61F), U64(0xFDF17746, 0x497F7052), /* ~= 10^-146 */
 1436    U64(0x9FD561F1, 0xFD0F9BD3), U64(0xFEB6EA8B, 0xEDEFA633), /* ~= 10^-145 */
 1437    U64(0xC7CABA6E, 0x7C5382C8), U64(0xFE64A52E, 0xE96B8FC0), /* ~= 10^-144 */
 1438    U64(0xF9BD690A, 0x1B68637B), U64(0x3DFDCE7A, 0xA3C673B0), /* ~= 10^-143 */
 1439    U64(0x9C1661A6, 0x51213E2D), U64(0x06BEA10C, 0xA65C084E), /* ~= 10^-142 */
 1440    U64(0xC31BFA0F, 0xE5698DB8), U64(0x486E494F, 0xCFF30A62), /* ~= 10^-141 */
 1441    U64(0xF3E2F893, 0xDEC3F126), U64(0x5A89DBA3, 0xC3EFCCFA), /* ~= 10^-140 */
 1442    U64(0x986DDB5C, 0x6B3A76B7), U64(0xF8962946, 0x5A75E01C), /* ~= 10^-139 */
 1443    U64(0xBE895233, 0x86091465), U64(0xF6BBB397, 0xF1135823), /* ~= 10^-138 */
 1444    U64(0xEE2BA6C0, 0x678B597F), U64(0x746AA07D, 0xED582E2C), /* ~= 10^-137 */
 1445    U64(0x94DB4838, 0x40B717EF), U64(0xA8C2A44E, 0xB4571CDC), /* ~= 10^-136 */
 1446    U64(0xBA121A46, 0x50E4DDEB), U64(0x92F34D62, 0x616CE413), /* ~= 10^-135 */
 1447    U64(0xE896A0D7, 0xE51E1566), U64(0x77B020BA, 0xF9C81D17), /* ~= 10^-134 */
 1448    U64(0x915E2486, 0xEF32CD60), U64(0x0ACE1474, 0xDC1D122E), /* ~= 10^-133 */
 1449    U64(0xB5B5ADA8, 0xAAFF80B8), U64(0x0D819992, 0x132456BA), /* ~= 10^-132 */
 1450    U64(0xE3231912, 0xD5BF60E6), U64(0x10E1FFF6, 0x97ED6C69), /* ~= 10^-131 */
 1451    U64(0x8DF5EFAB, 0xC5979C8F), U64(0xCA8D3FFA, 0x1EF463C1), /* ~= 10^-130 */
 1452    U64(0xB1736B96, 0xB6FD83B3), U64(0xBD308FF8, 0xA6B17CB2), /* ~= 10^-129 */
 1453    U64(0xDDD0467C, 0x64BCE4A0), U64(0xAC7CB3F6, 0xD05DDBDE), /* ~= 10^-128 */
 1454    U64(0x8AA22C0D, 0xBEF60EE4), U64(0x6BCDF07A, 0x423AA96B), /* ~= 10^-127 */
 1455    U64(0xAD4AB711, 0x2EB3929D), U64(0x86C16C98, 0xD2C953C6), /* ~= 10^-126 */
 1456    U64(0xD89D64D5, 0x7A607744), U64(0xE871C7BF, 0x077BA8B7), /* ~= 10^-125 */
 1457    U64(0x87625F05, 0x6C7C4A8B), U64(0x11471CD7, 0x64AD4972), /* ~= 10^-124 */
 1458    U64(0xA93AF6C6, 0xC79B5D2D), U64(0xD598E40D, 0x3DD89BCF), /* ~= 10^-123 */
 1459    U64(0xD389B478, 0x79823479), U64(0x4AFF1D10, 0x8D4EC2C3), /* ~= 10^-122 */
 1460    U64(0x843610CB, 0x4BF160CB), U64(0xCEDF722A, 0x585139BA), /* ~= 10^-121 */
 1461    U64(0xA54394FE, 0x1EEDB8FE), U64(0xC2974EB4, 0xEE658828), /* ~= 10^-120 */
 1462    U64(0xCE947A3D, 0xA6A9273E), U64(0x733D2262, 0x29FEEA32), /* ~= 10^-119 */
 1463    U64(0x811CCC66, 0x8829B887), U64(0x0806357D, 0x5A3F525F), /* ~= 10^-118 */
 1464    U64(0xA163FF80, 0x2A3426A8), U64(0xCA07C2DC, 0xB0CF26F7), /* ~= 10^-117 */
 1465    U64(0xC9BCFF60, 0x34C13052), U64(0xFC89B393, 0xDD02F0B5), /* ~= 10^-116 */
 1466    U64(0xFC2C3F38, 0x41F17C67), U64(0xBBAC2078, 0xD443ACE2), /* ~= 10^-115 */
 1467    U64(0x9D9BA783, 0x2936EDC0), U64(0xD54B944B, 0x84AA4C0D), /* ~= 10^-114 */
 1468    U64(0xC5029163, 0xF384A931), U64(0x0A9E795E, 0x65D4DF11), /* ~= 10^-113 */
 1469    U64(0xF64335BC, 0xF065D37D), U64(0x4D4617B5, 0xFF4A16D5), /* ~= 10^-112 */
 1470    U64(0x99EA0196, 0x163FA42E), U64(0x504BCED1, 0xBF8E4E45), /* ~= 10^-111 */
 1471    U64(0xC06481FB, 0x9BCF8D39), U64(0xE45EC286, 0x2F71E1D6), /* ~= 10^-110 */
 1472    U64(0xF07DA27A, 0x82C37088), U64(0x5D767327, 0xBB4E5A4C), /* ~= 10^-109 */
 1473    U64(0x964E858C, 0x91BA2655), U64(0x3A6A07F8, 0xD510F86F), /* ~= 10^-108 */
 1474    U64(0xBBE226EF, 0xB628AFEA), U64(0x890489F7, 0x0A55368B), /* ~= 10^-107 */
 1475    U64(0xEADAB0AB, 0xA3B2DBE5), U64(0x2B45AC74, 0xCCEA842E), /* ~= 10^-106 */
 1476    U64(0x92C8AE6B, 0x464FC96F), U64(0x3B0B8BC9, 0x0012929D), /* ~= 10^-105 */
 1477    U64(0xB77ADA06, 0x17E3BBCB), U64(0x09CE6EBB, 0x40173744), /* ~= 10^-104 */
 1478    U64(0xE5599087, 0x9DDCAABD), U64(0xCC420A6A, 0x101D0515), /* ~= 10^-103 */
 1479    U64(0x8F57FA54, 0xC2A9EAB6), U64(0x9FA94682, 0x4A12232D), /* ~= 10^-102 */
 1480    U64(0xB32DF8E9, 0xF3546564), U64(0x47939822, 0xDC96ABF9), /* ~= 10^-101 */
 1481    U64(0xDFF97724, 0x70297EBD), U64(0x59787E2B, 0x93BC56F7), /* ~= 10^-100 */
 1482    U64(0x8BFBEA76, 0xC619EF36), U64(0x57EB4EDB, 0x3C55B65A), /* ~= 10^-99 */
 1483    U64(0xAEFAE514, 0x77A06B03), U64(0xEDE62292, 0x0B6B23F1), /* ~= 10^-98 */
 1484    U64(0xDAB99E59, 0x958885C4), U64(0xE95FAB36, 0x8E45ECED), /* ~= 10^-97 */
 1485    U64(0x88B402F7, 0xFD75539B), U64(0x11DBCB02, 0x18EBB414), /* ~= 10^-96 */
 1486    U64(0xAAE103B5, 0xFCD2A881), U64(0xD652BDC2, 0x9F26A119), /* ~= 10^-95 */
 1487    U64(0xD59944A3, 0x7C0752A2), U64(0x4BE76D33, 0x46F0495F), /* ~= 10^-94 */
 1488    U64(0x857FCAE6, 0x2D8493A5), U64(0x6F70A440, 0x0C562DDB), /* ~= 10^-93 */
 1489    U64(0xA6DFBD9F, 0xB8E5B88E), U64(0xCB4CCD50, 0x0F6BB952), /* ~= 10^-92 */
 1490    U64(0xD097AD07, 0xA71F26B2), U64(0x7E2000A4, 0x1346A7A7), /* ~= 10^-91 */
 1491    U64(0x825ECC24, 0xC873782F), U64(0x8ED40066, 0x8C0C28C8), /* ~= 10^-90 */
 1492    U64(0xA2F67F2D, 0xFA90563B), U64(0x72890080, 0x2F0F32FA), /* ~= 10^-89 */
 1493    U64(0xCBB41EF9, 0x79346BCA), U64(0x4F2B40A0, 0x3AD2FFB9), /* ~= 10^-88 */
 1494    U64(0xFEA126B7, 0xD78186BC), U64(0xE2F610C8, 0x4987BFA8), /* ~= 10^-87 */
 1495    U64(0x9F24B832, 0xE6B0F436), U64(0x0DD9CA7D, 0x2DF4D7C9), /* ~= 10^-86 */
 1496    U64(0xC6EDE63F, 0xA05D3143), U64(0x91503D1C, 0x79720DBB), /* ~= 10^-85 */
 1497    U64(0xF8A95FCF, 0x88747D94), U64(0x75A44C63, 0x97CE912A), /* ~= 10^-84 */
 1498    U64(0x9B69DBE1, 0xB548CE7C), U64(0xC986AFBE, 0x3EE11ABA), /* ~= 10^-83 */
 1499    U64(0xC24452DA, 0x229B021B), U64(0xFBE85BAD, 0xCE996168), /* ~= 10^-82 */
 1500    U64(0xF2D56790, 0xAB41C2A2), U64(0xFAE27299, 0x423FB9C3), /* ~= 10^-81 */
 1501    U64(0x97C560BA, 0x6B0919A5), U64(0xDCCD879F, 0xC967D41A), /* ~= 10^-80 */
 1502    U64(0xBDB6B8E9, 0x05CB600F), U64(0x5400E987, 0xBBC1C920), /* ~= 10^-79 */
 1503    U64(0xED246723, 0x473E3813), U64(0x290123E9, 0xAAB23B68), /* ~= 10^-78 */
 1504    U64(0x9436C076, 0x0C86E30B), U64(0xF9A0B672, 0x0AAF6521), /* ~= 10^-77 */
 1505    U64(0xB9447093, 0x8FA89BCE), U64(0xF808E40E, 0x8D5B3E69), /* ~= 10^-76 */
 1506    U64(0xE7958CB8, 0x7392C2C2), U64(0xB60B1D12, 0x30B20E04), /* ~= 10^-75 */
 1507    U64(0x90BD77F3, 0x483BB9B9), U64(0xB1C6F22B, 0x5E6F48C2), /* ~= 10^-74 */
 1508    U64(0xB4ECD5F0, 0x1A4AA828), U64(0x1E38AEB6, 0x360B1AF3), /* ~= 10^-73 */
 1509    U64(0xE2280B6C, 0x20DD5232), U64(0x25C6DA63, 0xC38DE1B0), /* ~= 10^-72 */
 1510    U64(0x8D590723, 0x948A535F), U64(0x579C487E, 0x5A38AD0E), /* ~= 10^-71 */
 1511    U64(0xB0AF48EC, 0x79ACE837), U64(0x2D835A9D, 0xF0C6D851), /* ~= 10^-70 */
 1512    U64(0xDCDB1B27, 0x98182244), U64(0xF8E43145, 0x6CF88E65), /* ~= 10^-69 */
 1513    U64(0x8A08F0F8, 0xBF0F156B), U64(0x1B8E9ECB, 0x641B58FF), /* ~= 10^-68 */
 1514    U64(0xAC8B2D36, 0xEED2DAC5), U64(0xE272467E, 0x3D222F3F), /* ~= 10^-67 */
 1515    U64(0xD7ADF884, 0xAA879177), U64(0x5B0ED81D, 0xCC6ABB0F), /* ~= 10^-66 */
 1516    U64(0x86CCBB52, 0xEA94BAEA), U64(0x98E94712, 0x9FC2B4E9), /* ~= 10^-65 */
 1517    U64(0xA87FEA27, 0xA539E9A5), U64(0x3F2398D7, 0x47B36224), /* ~= 10^-64 */
 1518    U64(0xD29FE4B1, 0x8E88640E), U64(0x8EEC7F0D, 0x19A03AAD), /* ~= 10^-63 */
 1519    U64(0x83A3EEEE, 0xF9153E89), U64(0x1953CF68, 0x300424AC), /* ~= 10^-62 */
 1520    U64(0xA48CEAAA, 0xB75A8E2B), U64(0x5FA8C342, 0x3C052DD7), /* ~= 10^-61 */
 1521    U64(0xCDB02555, 0x653131B6), U64(0x3792F412, 0xCB06794D), /* ~= 10^-60 */
 1522    U64(0x808E1755, 0x5F3EBF11), U64(0xE2BBD88B, 0xBEE40BD0), /* ~= 10^-59 */
 1523    U64(0xA0B19D2A, 0xB70E6ED6), U64(0x5B6ACEAE, 0xAE9D0EC4), /* ~= 10^-58 */
 1524    U64(0xC8DE0475, 0x64D20A8B), U64(0xF245825A, 0x5A445275), /* ~= 10^-57 */
 1525    U64(0xFB158592, 0xBE068D2E), U64(0xEED6E2F0, 0xF0D56712), /* ~= 10^-56 */
 1526    U64(0x9CED737B, 0xB6C4183D), U64(0x55464DD6, 0x9685606B), /* ~= 10^-55 */
 1527    U64(0xC428D05A, 0xA4751E4C), U64(0xAA97E14C, 0x3C26B886), /* ~= 10^-54 */
 1528    U64(0xF5330471, 0x4D9265DF), U64(0xD53DD99F, 0x4B3066A8), /* ~= 10^-53 */
 1529    U64(0x993FE2C6, 0xD07B7FAB), U64(0xE546A803, 0x8EFE4029), /* ~= 10^-52 */
 1530    U64(0xBF8FDB78, 0x849A5F96), U64(0xDE985204, 0x72BDD033), /* ~= 10^-51 */
 1531    U64(0xEF73D256, 0xA5C0F77C), U64(0x963E6685, 0x8F6D4440), /* ~= 10^-50 */
 1532    U64(0x95A86376, 0x27989AAD), U64(0xDDE70013, 0x79A44AA8), /* ~= 10^-49 */
 1533    U64(0xBB127C53, 0xB17EC159), U64(0x5560C018, 0x580D5D52), /* ~= 10^-48 */
 1534    U64(0xE9D71B68, 0x9DDE71AF), U64(0xAAB8F01E, 0x6E10B4A6), /* ~= 10^-47 */
 1535    U64(0x92267121, 0x62AB070D), U64(0xCAB39613, 0x04CA70E8), /* ~= 10^-46 */
 1536    U64(0xB6B00D69, 0xBB55C8D1), U64(0x3D607B97, 0xC5FD0D22), /* ~= 10^-45 */
 1537    U64(0xE45C10C4, 0x2A2B3B05), U64(0x8CB89A7D, 0xB77C506A), /* ~= 10^-44 */
 1538    U64(0x8EB98A7A, 0x9A5B04E3), U64(0x77F3608E, 0x92ADB242), /* ~= 10^-43 */
 1539    U64(0xB267ED19, 0x40F1C61C), U64(0x55F038B2, 0x37591ED3), /* ~= 10^-42 */
 1540    U64(0xDF01E85F, 0x912E37A3), U64(0x6B6C46DE, 0xC52F6688), /* ~= 10^-41 */
 1541    U64(0x8B61313B, 0xBABCE2C6), U64(0x2323AC4B, 0x3B3DA015), /* ~= 10^-40 */
 1542    U64(0xAE397D8A, 0xA96C1B77), U64(0xABEC975E, 0x0A0D081A), /* ~= 10^-39 */
 1543    U64(0xD9C7DCED, 0x53C72255), U64(0x96E7BD35, 0x8C904A21), /* ~= 10^-38 */
 1544    U64(0x881CEA14, 0x545C7575), U64(0x7E50D641, 0x77DA2E54), /* ~= 10^-37 */
 1545    U64(0xAA242499, 0x697392D2), U64(0xDDE50BD1, 0xD5D0B9E9), /* ~= 10^-36 */
 1546    U64(0xD4AD2DBF, 0xC3D07787), U64(0x955E4EC6, 0x4B44E864), /* ~= 10^-35 */
 1547    U64(0x84EC3C97, 0xDA624AB4), U64(0xBD5AF13B, 0xEF0B113E), /* ~= 10^-34 */
 1548    U64(0xA6274BBD, 0xD0FADD61), U64(0xECB1AD8A, 0xEACDD58E), /* ~= 10^-33 */
 1549    U64(0xCFB11EAD, 0x453994BA), U64(0x67DE18ED, 0xA5814AF2), /* ~= 10^-32 */
 1550    U64(0x81CEB32C, 0x4B43FCF4), U64(0x80EACF94, 0x8770CED7), /* ~= 10^-31 */
 1551    U64(0xA2425FF7, 0x5E14FC31), U64(0xA1258379, 0xA94D028D), /* ~= 10^-30 */
 1552    U64(0xCAD2F7F5, 0x359A3B3E), U64(0x096EE458, 0x13A04330), /* ~= 10^-29 */
 1553    U64(0xFD87B5F2, 0x8300CA0D), U64(0x8BCA9D6E, 0x188853FC), /* ~= 10^-28 */
 1554    U64(0x9E74D1B7, 0x91E07E48), U64(0x775EA264, 0xCF55347D), /* ~= 10^-27 */
 1555    U64(0xC6120625, 0x76589DDA), U64(0x95364AFE, 0x032A819D), /* ~= 10^-26 */
 1556    U64(0xF79687AE, 0xD3EEC551), U64(0x3A83DDBD, 0x83F52204), /* ~= 10^-25 */
 1557    U64(0x9ABE14CD, 0x44753B52), U64(0xC4926A96, 0x72793542), /* ~= 10^-24 */
 1558    U64(0xC16D9A00, 0x95928A27), U64(0x75B7053C, 0x0F178293), /* ~= 10^-23 */
 1559    U64(0xF1C90080, 0xBAF72CB1), U64(0x5324C68B, 0x12DD6338), /* ~= 10^-22 */
 1560    U64(0x971DA050, 0x74DA7BEE), U64(0xD3F6FC16, 0xEBCA5E03), /* ~= 10^-21 */
 1561    U64(0xBCE50864, 0x92111AEA), U64(0x88F4BB1C, 0xA6BCF584), /* ~= 10^-20 */
 1562    U64(0xEC1E4A7D, 0xB69561A5), U64(0x2B31E9E3, 0xD06C32E5), /* ~= 10^-19 */
 1563    U64(0x9392EE8E, 0x921D5D07), U64(0x3AFF322E, 0x62439FCF), /* ~= 10^-18 */
 1564    U64(0xB877AA32, 0x36A4B449), U64(0x09BEFEB9, 0xFAD487C2), /* ~= 10^-17 */
 1565    U64(0xE69594BE, 0xC44DE15B), U64(0x4C2EBE68, 0x7989A9B3), /* ~= 10^-16 */
 1566    U64(0x901D7CF7, 0x3AB0ACD9), U64(0x0F9D3701, 0x4BF60A10), /* ~= 10^-15 */
 1567    U64(0xB424DC35, 0x095CD80F), U64(0x538484C1, 0x9EF38C94), /* ~= 10^-14 */
 1568    U64(0xE12E1342, 0x4BB40E13), U64(0x2865A5F2, 0x06B06FB9), /* ~= 10^-13 */
 1569    U64(0x8CBCCC09, 0x6F5088CB), U64(0xF93F87B7, 0x442E45D3), /* ~= 10^-12 */
 1570    U64(0xAFEBFF0B, 0xCB24AAFE), U64(0xF78F69A5, 0x1539D748), /* ~= 10^-11 */
 1571    U64(0xDBE6FECE, 0xBDEDD5BE), U64(0xB573440E, 0x5A884D1B), /* ~= 10^-10 */
 1572    U64(0x89705F41, 0x36B4A597), U64(0x31680A88, 0xF8953030), /* ~= 10^-9 */
 1573    U64(0xABCC7711, 0x8461CEFC), U64(0xFDC20D2B, 0x36BA7C3D), /* ~= 10^-8 */
 1574    U64(0xD6BF94D5, 0xE57A42BC), U64(0x3D329076, 0x04691B4C), /* ~= 10^-7 */
 1575    U64(0x8637BD05, 0xAF6C69B5), U64(0xA63F9A49, 0xC2C1B10F), /* ~= 10^-6 */
 1576    U64(0xA7C5AC47, 0x1B478423), U64(0x0FCF80DC, 0x33721D53), /* ~= 10^-5 */
 1577    U64(0xD1B71758, 0xE219652B), U64(0xD3C36113, 0x404EA4A8), /* ~= 10^-4 */
 1578    U64(0x83126E97, 0x8D4FDF3B), U64(0x645A1CAC, 0x083126E9), /* ~= 10^-3 */
 1579    U64(0xA3D70A3D, 0x70A3D70A), U64(0x3D70A3D7, 0x0A3D70A3), /* ~= 10^-2 */
 1580    U64(0xCCCCCCCC, 0xCCCCCCCC), U64(0xCCCCCCCC, 0xCCCCCCCC), /* ~= 10^-1 */
 1581    U64(0x80000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^0 */
 1582    U64(0xA0000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^1 */
 1583    U64(0xC8000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^2 */
 1584    U64(0xFA000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^3 */
 1585    U64(0x9C400000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^4 */
 1586    U64(0xC3500000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^5 */
 1587    U64(0xF4240000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^6 */
 1588    U64(0x98968000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^7 */
 1589    U64(0xBEBC2000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^8 */
 1590    U64(0xEE6B2800, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^9 */
 1591    U64(0x9502F900, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^10 */
 1592    U64(0xBA43B740, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^11 */
 1593    U64(0xE8D4A510, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^12 */
 1594    U64(0x9184E72A, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^13 */
 1595    U64(0xB5E620F4, 0x80000000), U64(0x00000000, 0x00000000), /* == 10^14 */
 1596    U64(0xE35FA931, 0xA0000000), U64(0x00000000, 0x00000000), /* == 10^15 */
 1597    U64(0x8E1BC9BF, 0x04000000), U64(0x00000000, 0x00000000), /* == 10^16 */
 1598    U64(0xB1A2BC2E, 0xC5000000), U64(0x00000000, 0x00000000), /* == 10^17 */
 1599    U64(0xDE0B6B3A, 0x76400000), U64(0x00000000, 0x00000000), /* == 10^18 */
 1600    U64(0x8AC72304, 0x89E80000), U64(0x00000000, 0x00000000), /* == 10^19 */
 1601    U64(0xAD78EBC5, 0xAC620000), U64(0x00000000, 0x00000000), /* == 10^20 */
 1602    U64(0xD8D726B7, 0x177A8000), U64(0x00000000, 0x00000000), /* == 10^21 */
 1603    U64(0x87867832, 0x6EAC9000), U64(0x00000000, 0x00000000), /* == 10^22 */
 1604    U64(0xA968163F, 0x0A57B400), U64(0x00000000, 0x00000000), /* == 10^23 */
 1605    U64(0xD3C21BCE, 0xCCEDA100), U64(0x00000000, 0x00000000), /* == 10^24 */
 1606    U64(0x84595161, 0x401484A0), U64(0x00000000, 0x00000000), /* == 10^25 */
 1607    U64(0xA56FA5B9, 0x9019A5C8), U64(0x00000000, 0x00000000), /* == 10^26 */
 1608    U64(0xCECB8F27, 0xF4200F3A), U64(0x00000000, 0x00000000), /* == 10^27 */
 1609    U64(0x813F3978, 0xF8940984), U64(0x40000000, 0x00000000), /* == 10^28 */
 1610    U64(0xA18F07D7, 0x36B90BE5), U64(0x50000000, 0x00000000), /* == 10^29 */
 1611    U64(0xC9F2C9CD, 0x04674EDE), U64(0xA4000000, 0x00000000), /* == 10^30 */
 1612    U64(0xFC6F7C40, 0x45812296), U64(0x4D000000, 0x00000000), /* == 10^31 */
 1613    U64(0x9DC5ADA8, 0x2B70B59D), U64(0xF0200000, 0x00000000), /* == 10^32 */
 1614    U64(0xC5371912, 0x364CE305), U64(0x6C280000, 0x00000000), /* == 10^33 */
 1615    U64(0xF684DF56, 0xC3E01BC6), U64(0xC7320000, 0x00000000), /* == 10^34 */
 1616    U64(0x9A130B96, 0x3A6C115C), U64(0x3C7F4000, 0x00000000), /* == 10^35 */
 1617    U64(0xC097CE7B, 0xC90715B3), U64(0x4B9F1000, 0x00000000), /* == 10^36 */
 1618    U64(0xF0BDC21A, 0xBB48DB20), U64(0x1E86D400, 0x00000000), /* == 10^37 */
 1619    U64(0x96769950, 0xB50D88F4), U64(0x13144480, 0x00000000), /* == 10^38 */
 1620    U64(0xBC143FA4, 0xE250EB31), U64(0x17D955A0, 0x00000000), /* == 10^39 */
 1621    U64(0xEB194F8E, 0x1AE525FD), U64(0x5DCFAB08, 0x00000000), /* == 10^40 */
 1622    U64(0x92EFD1B8, 0xD0CF37BE), U64(0x5AA1CAE5, 0x00000000), /* == 10^41 */
 1623    U64(0xB7ABC627, 0x050305AD), U64(0xF14A3D9E, 0x40000000), /* == 10^42 */
 1624    U64(0xE596B7B0, 0xC643C719), U64(0x6D9CCD05, 0xD0000000), /* == 10^43 */
 1625    U64(0x8F7E32CE, 0x7BEA5C6F), U64(0xE4820023, 0xA2000000), /* == 10^44 */
 1626    U64(0xB35DBF82, 0x1AE4F38B), U64(0xDDA2802C, 0x8A800000), /* == 10^45 */
 1627    U64(0xE0352F62, 0xA19E306E), U64(0xD50B2037, 0xAD200000), /* == 10^46 */
 1628    U64(0x8C213D9D, 0xA502DE45), U64(0x4526F422, 0xCC340000), /* == 10^47 */
 1629    U64(0xAF298D05, 0x0E4395D6), U64(0x9670B12B, 0x7F410000), /* == 10^48 */
 1630    U64(0xDAF3F046, 0x51D47B4C), U64(0x3C0CDD76, 0x5F114000), /* == 10^49 */
 1631    U64(0x88D8762B, 0xF324CD0F), U64(0xA5880A69, 0xFB6AC800), /* == 10^50 */
 1632    U64(0xAB0E93B6, 0xEFEE0053), U64(0x8EEA0D04, 0x7A457A00), /* == 10^51 */
 1633    U64(0xD5D238A4, 0xABE98068), U64(0x72A49045, 0x98D6D880), /* == 10^52 */
 1634    U64(0x85A36366, 0xEB71F041), U64(0x47A6DA2B, 0x7F864750), /* == 10^53 */
 1635    U64(0xA70C3C40, 0xA64E6C51), U64(0x999090B6, 0x5F67D924), /* == 10^54 */
 1636    U64(0xD0CF4B50, 0xCFE20765), U64(0xFFF4B4E3, 0xF741CF6D), /* == 10^55 */
 1637    U64(0x82818F12, 0x81ED449F), U64(0xBFF8F10E, 0x7A8921A4), /* ~= 10^56 */
 1638    U64(0xA321F2D7, 0x226895C7), U64(0xAFF72D52, 0x192B6A0D), /* ~= 10^57 */
 1639    U64(0xCBEA6F8C, 0xEB02BB39), U64(0x9BF4F8A6, 0x9F764490), /* ~= 10^58 */
 1640    U64(0xFEE50B70, 0x25C36A08), U64(0x02F236D0, 0x4753D5B4), /* ~= 10^59 */
 1641    U64(0x9F4F2726, 0x179A2245), U64(0x01D76242, 0x2C946590), /* ~= 10^60 */
 1642    U64(0xC722F0EF, 0x9D80AAD6), U64(0x424D3AD2, 0xB7B97EF5), /* ~= 10^61 */
 1643    U64(0xF8EBAD2B, 0x84E0D58B), U64(0xD2E08987, 0x65A7DEB2), /* ~= 10^62 */
 1644    U64(0x9B934C3B, 0x330C8577), U64(0x63CC55F4, 0x9F88EB2F), /* ~= 10^63 */
 1645    U64(0xC2781F49, 0xFFCFA6D5), U64(0x3CBF6B71, 0xC76B25FB), /* ~= 10^64 */
 1646    U64(0xF316271C, 0x7FC3908A), U64(0x8BEF464E, 0x3945EF7A), /* ~= 10^65 */
 1647    U64(0x97EDD871, 0xCFDA3A56), U64(0x97758BF0, 0xE3CBB5AC), /* ~= 10^66 */
 1648    U64(0xBDE94E8E, 0x43D0C8EC), U64(0x3D52EEED, 0x1CBEA317), /* ~= 10^67 */
 1649    U64(0xED63A231, 0xD4C4FB27), U64(0x4CA7AAA8, 0x63EE4BDD), /* ~= 10^68 */
 1650    U64(0x945E455F, 0x24FB1CF8), U64(0x8FE8CAA9, 0x3E74EF6A), /* ~= 10^69 */
 1651    U64(0xB975D6B6, 0xEE39E436), U64(0xB3E2FD53, 0x8E122B44), /* ~= 10^70 */
 1652    U64(0xE7D34C64, 0xA9C85D44), U64(0x60DBBCA8, 0x7196B616), /* ~= 10^71 */
 1653    U64(0x90E40FBE, 0xEA1D3A4A), U64(0xBC8955E9, 0x46FE31CD), /* ~= 10^72 */
 1654    U64(0xB51D13AE, 0xA4A488DD), U64(0x6BABAB63, 0x98BDBE41), /* ~= 10^73 */
 1655    U64(0xE264589A, 0x4DCDAB14), U64(0xC696963C, 0x7EED2DD1), /* ~= 10^74 */
 1656    U64(0x8D7EB760, 0x70A08AEC), U64(0xFC1E1DE5, 0xCF543CA2), /* ~= 10^75 */
 1657    U64(0xB0DE6538, 0x8CC8ADA8), U64(0x3B25A55F, 0x43294BCB), /* ~= 10^76 */
 1658    U64(0xDD15FE86, 0xAFFAD912), U64(0x49EF0EB7, 0x13F39EBE), /* ~= 10^77 */
 1659    U64(0x8A2DBF14, 0x2DFCC7AB), U64(0x6E356932, 0x6C784337), /* ~= 10^78 */
 1660    U64(0xACB92ED9, 0x397BF996), U64(0x49C2C37F, 0x07965404), /* ~= 10^79 */
 1661    U64(0xD7E77A8F, 0x87DAF7FB), U64(0xDC33745E, 0xC97BE906), /* ~= 10^80 */
 1662    U64(0x86F0AC99, 0xB4E8DAFD), U64(0x69A028BB, 0x3DED71A3), /* ~= 10^81 */
 1663    U64(0xA8ACD7C0, 0x222311BC), U64(0xC40832EA, 0x0D68CE0C), /* ~= 10^82 */
 1664    U64(0xD2D80DB0, 0x2AABD62B), U64(0xF50A3FA4, 0x90C30190), /* ~= 10^83 */
 1665    U64(0x83C7088E, 0x1AAB65DB), U64(0x792667C6, 0xDA79E0FA), /* ~= 10^84 */
 1666    U64(0xA4B8CAB1, 0xA1563F52), U64(0x577001B8, 0x91185938), /* ~= 10^85 */
 1667    U64(0xCDE6FD5E, 0x09ABCF26), U64(0xED4C0226, 0xB55E6F86), /* ~= 10^86 */
 1668    U64(0x80B05E5A, 0xC60B6178), U64(0x544F8158, 0x315B05B4), /* ~= 10^87 */
 1669    U64(0xA0DC75F1, 0x778E39D6), U64(0x696361AE, 0x3DB1C721), /* ~= 10^88 */
 1670    U64(0xC913936D, 0xD571C84C), U64(0x03BC3A19, 0xCD1E38E9), /* ~= 10^89 */
 1671    U64(0xFB587849, 0x4ACE3A5F), U64(0x04AB48A0, 0x4065C723), /* ~= 10^90 */
 1672    U64(0x9D174B2D, 0xCEC0E47B), U64(0x62EB0D64, 0x283F9C76), /* ~= 10^91 */
 1673    U64(0xC45D1DF9, 0x42711D9A), U64(0x3BA5D0BD, 0x324F8394), /* ~= 10^92 */
 1674    U64(0xF5746577, 0x930D6500), U64(0xCA8F44EC, 0x7EE36479), /* ~= 10^93 */
 1675    U64(0x9968BF6A, 0xBBE85F20), U64(0x7E998B13, 0xCF4E1ECB), /* ~= 10^94 */
 1676    U64(0xBFC2EF45, 0x6AE276E8), U64(0x9E3FEDD8, 0xC321A67E), /* ~= 10^95 */
 1677    U64(0xEFB3AB16, 0xC59B14A2), U64(0xC5CFE94E, 0xF3EA101E), /* ~= 10^96 */
 1678    U64(0x95D04AEE, 0x3B80ECE5), U64(0xBBA1F1D1, 0x58724A12), /* ~= 10^97 */
 1679    U64(0xBB445DA9, 0xCA61281F), U64(0x2A8A6E45, 0xAE8EDC97), /* ~= 10^98 */
 1680    U64(0xEA157514, 0x3CF97226), U64(0xF52D09D7, 0x1A3293BD), /* ~= 10^99 */
 1681    U64(0x924D692C, 0xA61BE758), U64(0x593C2626, 0x705F9C56), /* ~= 10^100 */
 1682    U64(0xB6E0C377, 0xCFA2E12E), U64(0x6F8B2FB0, 0x0C77836C), /* ~= 10^101 */
 1683    U64(0xE498F455, 0xC38B997A), U64(0x0B6DFB9C, 0x0F956447), /* ~= 10^102 */
 1684    U64(0x8EDF98B5, 0x9A373FEC), U64(0x4724BD41, 0x89BD5EAC), /* ~= 10^103 */
 1685    U64(0xB2977EE3, 0x00C50FE7), U64(0x58EDEC91, 0xEC2CB657), /* ~= 10^104 */
 1686    U64(0xDF3D5E9B, 0xC0F653E1), U64(0x2F2967B6, 0x6737E3ED), /* ~= 10^105 */
 1687    U64(0x8B865B21, 0x5899F46C), U64(0xBD79E0D2, 0x0082EE74), /* ~= 10^106 */
 1688    U64(0xAE67F1E9, 0xAEC07187), U64(0xECD85906, 0x80A3AA11), /* ~= 10^107 */
 1689    U64(0xDA01EE64, 0x1A708DE9), U64(0xE80E6F48, 0x20CC9495), /* ~= 10^108 */
 1690    U64(0x884134FE, 0x908658B2), U64(0x3109058D, 0x147FDCDD), /* ~= 10^109 */
 1691    U64(0xAA51823E, 0x34A7EEDE), U64(0xBD4B46F0, 0x599FD415), /* ~= 10^110 */
 1692    U64(0xD4E5E2CD, 0xC1D1EA96), U64(0x6C9E18AC, 0x7007C91A), /* ~= 10^111 */
 1693    U64(0x850FADC0, 0x9923329E), U64(0x03E2CF6B, 0xC604DDB0), /* ~= 10^112 */
 1694    U64(0xA6539930, 0xBF6BFF45), U64(0x84DB8346, 0xB786151C), /* ~= 10^113 */
 1695    U64(0xCFE87F7C, 0xEF46FF16), U64(0xE6126418, 0x65679A63), /* ~= 10^114 */
 1696    U64(0x81F14FAE, 0x158C5F6E), U64(0x4FCB7E8F, 0x3F60C07E), /* ~= 10^115 */
 1697    U64(0xA26DA399, 0x9AEF7749), U64(0xE3BE5E33, 0x0F38F09D), /* ~= 10^116 */
 1698    U64(0xCB090C80, 0x01AB551C), U64(0x5CADF5BF, 0xD3072CC5), /* ~= 10^117 */
 1699    U64(0xFDCB4FA0, 0x02162A63), U64(0x73D9732F, 0xC7C8F7F6), /* ~= 10^118 */
 1700    U64(0x9E9F11C4, 0x014DDA7E), U64(0x2867E7FD, 0xDCDD9AFA), /* ~= 10^119 */
 1701    U64(0xC646D635, 0x01A1511D), U64(0xB281E1FD, 0x541501B8), /* ~= 10^120 */
 1702    U64(0xF7D88BC2, 0x4209A565), U64(0x1F225A7C, 0xA91A4226), /* ~= 10^121 */
 1703    U64(0x9AE75759, 0x6946075F), U64(0x3375788D, 0xE9B06958), /* ~= 10^122 */
 1704    U64(0xC1A12D2F, 0xC3978937), U64(0x0052D6B1, 0x641C83AE), /* ~= 10^123 */
 1705    U64(0xF209787B, 0xB47D6B84), U64(0xC0678C5D, 0xBD23A49A), /* ~= 10^124 */
 1706    U64(0x9745EB4D, 0x50CE6332), U64(0xF840B7BA, 0x963646E0), /* ~= 10^125 */
 1707    U64(0xBD176620, 0xA501FBFF), U64(0xB650E5A9, 0x3BC3D898), /* ~= 10^126 */
 1708    U64(0xEC5D3FA8, 0xCE427AFF), U64(0xA3E51F13, 0x8AB4CEBE), /* ~= 10^127 */
 1709    U64(0x93BA47C9, 0x80E98CDF), U64(0xC66F336C, 0x36B10137), /* ~= 10^128 */
 1710    U64(0xB8A8D9BB, 0xE123F017), U64(0xB80B0047, 0x445D4184), /* ~= 10^129 */
 1711    U64(0xE6D3102A, 0xD96CEC1D), U64(0xA60DC059, 0x157491E5), /* ~= 10^130 */
 1712    U64(0x9043EA1A, 0xC7E41392), U64(0x87C89837, 0xAD68DB2F), /* ~= 10^131 */
 1713    U64(0xB454E4A1, 0x79DD1877), U64(0x29BABE45, 0x98C311FB), /* ~= 10^132 */
 1714    U64(0xE16A1DC9, 0xD8545E94), U64(0xF4296DD6, 0xFEF3D67A), /* ~= 10^133 */
 1715    U64(0x8CE2529E, 0x2734BB1D), U64(0x1899E4A6, 0x5F58660C), /* ~= 10^134 */
 1716    U64(0xB01AE745, 0xB101E9E4), U64(0x5EC05DCF, 0xF72E7F8F), /* ~= 10^135 */
 1717    U64(0xDC21A117, 0x1D42645D), U64(0x76707543, 0xF4FA1F73), /* ~= 10^136 */
 1718    U64(0x899504AE, 0x72497EBA), U64(0x6A06494A, 0x791C53A8), /* ~= 10^137 */
 1719    U64(0xABFA45DA, 0x0EDBDE69), U64(0x0487DB9D, 0x17636892), /* ~= 10^138 */
 1720    U64(0xD6F8D750, 0x9292D603), U64(0x45A9D284, 0x5D3C42B6), /* ~= 10^139 */
 1721    U64(0x865B8692, 0x5B9BC5C2), U64(0x0B8A2392, 0xBA45A9B2), /* ~= 10^140 */
 1722    U64(0xA7F26836, 0xF282B732), U64(0x8E6CAC77, 0x68D7141E), /* ~= 10^141 */
 1723    U64(0xD1EF0244, 0xAF2364FF), U64(0x3207D795, 0x430CD926), /* ~= 10^142 */
 1724    U64(0x8335616A, 0xED761F1F), U64(0x7F44E6BD, 0x49E807B8), /* ~= 10^143 */
 1725    U64(0xA402B9C5, 0xA8D3A6E7), U64(0x5F16206C, 0x9C6209A6), /* ~= 10^144 */
 1726    U64(0xCD036837, 0x130890A1), U64(0x36DBA887, 0xC37A8C0F), /* ~= 10^145 */
 1727    U64(0x80222122, 0x6BE55A64), U64(0xC2494954, 0xDA2C9789), /* ~= 10^146 */
 1728    U64(0xA02AA96B, 0x06DEB0FD), U64(0xF2DB9BAA, 0x10B7BD6C), /* ~= 10^147 */
 1729    U64(0xC83553C5, 0xC8965D3D), U64(0x6F928294, 0x94E5ACC7), /* ~= 10^148 */
 1730    U64(0xFA42A8B7, 0x3ABBF48C), U64(0xCB772339, 0xBA1F17F9), /* ~= 10^149 */
 1731    U64(0x9C69A972, 0x84B578D7), U64(0xFF2A7604, 0x14536EFB), /* ~= 10^150 */
 1732    U64(0xC38413CF, 0x25E2D70D), U64(0xFEF51385, 0x19684ABA), /* ~= 10^151 */
 1733    U64(0xF46518C2, 0xEF5B8CD1), U64(0x7EB25866, 0x5FC25D69), /* ~= 10^152 */
 1734    U64(0x98BF2F79, 0xD5993802), U64(0xEF2F773F, 0xFBD97A61), /* ~= 10^153 */
 1735    U64(0xBEEEFB58, 0x4AFF8603), U64(0xAAFB550F, 0xFACFD8FA), /* ~= 10^154 */
 1736    U64(0xEEAABA2E, 0x5DBF6784), U64(0x95BA2A53, 0xF983CF38), /* ~= 10^155 */
 1737    U64(0x952AB45C, 0xFA97A0B2), U64(0xDD945A74, 0x7BF26183), /* ~= 10^156 */
 1738    U64(0xBA756174, 0x393D88DF), U64(0x94F97111, 0x9AEEF9E4), /* ~= 10^157 */
 1739    U64(0xE912B9D1, 0x478CEB17), U64(0x7A37CD56, 0x01AAB85D), /* ~= 10^158 */
 1740    U64(0x91ABB422, 0xCCB812EE), U64(0xAC62E055, 0xC10AB33A), /* ~= 10^159 */
 1741    U64(0xB616A12B, 0x7FE617AA), U64(0x577B986B, 0x314D6009), /* ~= 10^160 */
 1742    U64(0xE39C4976, 0x5FDF9D94), U64(0xED5A7E85, 0xFDA0B80B), /* ~= 10^161 */
 1743    U64(0x8E41ADE9, 0xFBEBC27D), U64(0x14588F13, 0xBE847307), /* ~= 10^162 */
 1744    U64(0xB1D21964, 0x7AE6B31C), U64(0x596EB2D8, 0xAE258FC8), /* ~= 10^163 */
 1745    U64(0xDE469FBD, 0x99A05FE3), U64(0x6FCA5F8E, 0xD9AEF3BB), /* ~= 10^164 */
 1746    U64(0x8AEC23D6, 0x80043BEE), U64(0x25DE7BB9, 0x480D5854), /* ~= 10^165 */
 1747    U64(0xADA72CCC, 0x20054AE9), U64(0xAF561AA7, 0x9A10AE6A), /* ~= 10^166 */
 1748    U64(0xD910F7FF, 0x28069DA4), U64(0x1B2BA151, 0x8094DA04), /* ~= 10^167 */
 1749    U64(0x87AA9AFF, 0x79042286), U64(0x90FB44D2, 0xF05D0842), /* ~= 10^168 */
 1750    U64(0xA99541BF, 0x57452B28), U64(0x353A1607, 0xAC744A53), /* ~= 10^169 */
 1751    U64(0xD3FA922F, 0x2D1675F2), U64(0x42889B89, 0x97915CE8), /* ~= 10^170 */
 1752    U64(0x847C9B5D, 0x7C2E09B7), U64(0x69956135, 0xFEBADA11), /* ~= 10^171 */
 1753    U64(0xA59BC234, 0xDB398C25), U64(0x43FAB983, 0x7E699095), /* ~= 10^172 */
 1754    U64(0xCF02B2C2, 0x1207EF2E), U64(0x94F967E4, 0x5E03F4BB), /* ~= 10^173 */
 1755    U64(0x8161AFB9, 0x4B44F57D), U64(0x1D1BE0EE, 0xBAC278F5), /* ~= 10^174 */
 1756    U64(0xA1BA1BA7, 0x9E1632DC), U64(0x6462D92A, 0x69731732), /* ~= 10^175 */
 1757    U64(0xCA28A291, 0x859BBF93), U64(0x7D7B8F75, 0x03CFDCFE), /* ~= 10^176 */
 1758    U64(0xFCB2CB35, 0xE702AF78), U64(0x5CDA7352, 0x44C3D43E), /* ~= 10^177 */
 1759    U64(0x9DEFBF01, 0xB061ADAB), U64(0x3A088813, 0x6AFA64A7), /* ~= 10^178 */
 1760    U64(0xC56BAEC2, 0x1C7A1916), U64(0x088AAA18, 0x45B8FDD0), /* ~= 10^179 */
 1761    U64(0xF6C69A72, 0xA3989F5B), U64(0x8AAD549E, 0x57273D45), /* ~= 10^180 */
 1762    U64(0x9A3C2087, 0xA63F6399), U64(0x36AC54E2, 0xF678864B), /* ~= 10^181 */
 1763    U64(0xC0CB28A9, 0x8FCF3C7F), U64(0x84576A1B, 0xB416A7DD), /* ~= 10^182 */
 1764    U64(0xF0FDF2D3, 0xF3C30B9F), U64(0x656D44A2, 0xA11C51D5), /* ~= 10^183 */
 1765    U64(0x969EB7C4, 0x7859E743), U64(0x9F644AE5, 0xA4B1B325), /* ~= 10^184 */
 1766    U64(0xBC4665B5, 0x96706114), U64(0x873D5D9F, 0x0DDE1FEE), /* ~= 10^185 */
 1767    U64(0xEB57FF22, 0xFC0C7959), U64(0xA90CB506, 0xD155A7EA), /* ~= 10^186 */
 1768    U64(0x9316FF75, 0xDD87CBD8), U64(0x09A7F124, 0x42D588F2), /* ~= 10^187 */
 1769    U64(0xB7DCBF53, 0x54E9BECE), U64(0x0C11ED6D, 0x538AEB2F), /* ~= 10^188 */
 1770    U64(0xE5D3EF28, 0x2A242E81), U64(0x8F1668C8, 0xA86DA5FA), /* ~= 10^189 */
 1771    U64(0x8FA47579, 0x1A569D10), U64(0xF96E017D, 0x694487BC), /* ~= 10^190 */
 1772    U64(0xB38D92D7, 0x60EC4455), U64(0x37C981DC, 0xC395A9AC), /* ~= 10^191 */
 1773    U64(0xE070F78D, 0x3927556A), U64(0x85BBE253, 0xF47B1417), /* ~= 10^192 */
 1774    U64(0x8C469AB8, 0x43B89562), U64(0x93956D74, 0x78CCEC8E), /* ~= 10^193 */
 1775    U64(0xAF584166, 0x54A6BABB), U64(0x387AC8D1, 0x970027B2), /* ~= 10^194 */
 1776    U64(0xDB2E51BF, 0xE9D0696A), U64(0x06997B05, 0xFCC0319E), /* ~= 10^195 */
 1777    U64(0x88FCF317, 0xF22241E2), U64(0x441FECE3, 0xBDF81F03), /* ~= 10^196 */
 1778    U64(0xAB3C2FDD, 0xEEAAD25A), U64(0xD527E81C, 0xAD7626C3), /* ~= 10^197 */
 1779    U64(0xD60B3BD5, 0x6A5586F1), U64(0x8A71E223, 0xD8D3B074), /* ~= 10^198 */
 1780    U64(0x85C70565, 0x62757456), U64(0xF6872D56, 0x67844E49), /* ~= 10^199 */
 1781    U64(0xA738C6BE, 0xBB12D16C), U64(0xB428F8AC, 0x016561DB), /* ~= 10^200 */
 1782    U64(0xD106F86E, 0x69D785C7), U64(0xE13336D7, 0x01BEBA52), /* ~= 10^201 */
 1783    U64(0x82A45B45, 0x0226B39C), U64(0xECC00246, 0x61173473), /* ~= 10^202 */
 1784    U64(0xA34D7216, 0x42B06084), U64(0x27F002D7, 0xF95D0190), /* ~= 10^203 */
 1785    U64(0xCC20CE9B, 0xD35C78A5), U64(0x31EC038D, 0xF7B441F4), /* ~= 10^204 */
 1786    U64(0xFF290242, 0xC83396CE), U64(0x7E670471, 0x75A15271), /* ~= 10^205 */
 1787    U64(0x9F79A169, 0xBD203E41), U64(0x0F0062C6, 0xE984D386), /* ~= 10^206 */
 1788    U64(0xC75809C4, 0x2C684DD1), U64(0x52C07B78, 0xA3E60868), /* ~= 10^207 */
 1789    U64(0xF92E0C35, 0x37826145), U64(0xA7709A56, 0xCCDF8A82), /* ~= 10^208 */
 1790    U64(0x9BBCC7A1, 0x42B17CCB), U64(0x88A66076, 0x400BB691), /* ~= 10^209 */
 1791    U64(0xC2ABF989, 0x935DDBFE), U64(0x6ACFF893, 0xD00EA435), /* ~= 10^210 */
 1792    U64(0xF356F7EB, 0xF83552FE), U64(0x0583F6B8, 0xC4124D43), /* ~= 10^211 */
 1793    U64(0x98165AF3, 0x7B2153DE), U64(0xC3727A33, 0x7A8B704A), /* ~= 10^212 */
 1794    U64(0xBE1BF1B0, 0x59E9A8D6), U64(0x744F18C0, 0x592E4C5C), /* ~= 10^213 */
 1795    U64(0xEDA2EE1C, 0x7064130C), U64(0x1162DEF0, 0x6F79DF73), /* ~= 10^214 */
 1796    U64(0x9485D4D1, 0xC63E8BE7), U64(0x8ADDCB56, 0x45AC2BA8), /* ~= 10^215 */
 1797    U64(0xB9A74A06, 0x37CE2EE1), U64(0x6D953E2B, 0xD7173692), /* ~= 10^216 */
 1798    U64(0xE8111C87, 0xC5C1BA99), U64(0xC8FA8DB6, 0xCCDD0437), /* ~= 10^217 */
 1799    U64(0x910AB1D4, 0xDB9914A0), U64(0x1D9C9892, 0x400A22A2), /* ~= 10^218 */
 1800    U64(0xB54D5E4A, 0x127F59C8), U64(0x2503BEB6, 0xD00CAB4B), /* ~= 10^219 */
 1801    U64(0xE2A0B5DC, 0x971F303A), U64(0x2E44AE64, 0x840FD61D), /* ~= 10^220 */
 1802    U64(0x8DA471A9, 0xDE737E24), U64(0x5CEAECFE, 0xD289E5D2), /* ~= 10^221 */
 1803    U64(0xB10D8E14, 0x56105DAD), U64(0x7425A83E, 0x872C5F47), /* ~= 10^222 */
 1804    U64(0xDD50F199, 0x6B947518), U64(0xD12F124E, 0x28F77719), /* ~= 10^223 */
 1805    U64(0x8A5296FF, 0xE33CC92F), U64(0x82BD6B70, 0xD99AAA6F), /* ~= 10^224 */
 1806    U64(0xACE73CBF, 0xDC0BFB7B), U64(0x636CC64D, 0x1001550B), /* ~= 10^225 */
 1807    U64(0xD8210BEF, 0xD30EFA5A), U64(0x3C47F7E0, 0x5401AA4E), /* ~= 10^226 */
 1808    U64(0x8714A775, 0xE3E95C78), U64(0x65ACFAEC, 0x34810A71), /* ~= 10^227 */
 1809    U64(0xA8D9D153, 0x5CE3B396), U64(0x7F1839A7, 0x41A14D0D), /* ~= 10^228 */
 1810    U64(0xD31045A8, 0x341CA07C), U64(0x1EDE4811, 0x1209A050), /* ~= 10^229 */
 1811    U64(0x83EA2B89, 0x2091E44D), U64(0x934AED0A, 0xAB460432), /* ~= 10^230 */
 1812    U64(0xA4E4B66B, 0x68B65D60), U64(0xF81DA84D, 0x5617853F), /* ~= 10^231 */
 1813    U64(0xCE1DE406, 0x42E3F4B9), U64(0x36251260, 0xAB9D668E), /* ~= 10^232 */
 1814    U64(0x80D2AE83, 0xE9CE78F3), U64(0xC1D72B7C, 0x6B426019), /* ~= 10^233 */
 1815    U64(0xA1075A24, 0xE4421730), U64(0xB24CF65B, 0x8612F81F), /* ~= 10^234 */
 1816    U64(0xC94930AE, 0x1D529CFC), U64(0xDEE033F2, 0x6797B627), /* ~= 10^235 */
 1817    U64(0xFB9B7CD9, 0xA4A7443C), U64(0x169840EF, 0x017DA3B1), /* ~= 10^236 */
 1818    U64(0x9D412E08, 0x06E88AA5), U64(0x8E1F2895, 0x60EE864E), /* ~= 10^237 */
 1819    U64(0xC491798A, 0x08A2AD4E), U64(0xF1A6F2BA, 0xB92A27E2), /* ~= 10^238 */
 1820    U64(0xF5B5D7EC, 0x8ACB58A2), U64(0xAE10AF69, 0x6774B1DB), /* ~= 10^239 */
 1821    U64(0x9991A6F3, 0xD6BF1765), U64(0xACCA6DA1, 0xE0A8EF29), /* ~= 10^240 */
 1822    U64(0xBFF610B0, 0xCC6EDD3F), U64(0x17FD090A, 0x58D32AF3), /* ~= 10^241 */
 1823    U64(0xEFF394DC, 0xFF8A948E), U64(0xDDFC4B4C, 0xEF07F5B0), /* ~= 10^242 */
 1824    U64(0x95F83D0A, 0x1FB69CD9), U64(0x4ABDAF10, 0x1564F98E), /* ~= 10^243 */
 1825    U64(0xBB764C4C, 0xA7A4440F), U64(0x9D6D1AD4, 0x1ABE37F1), /* ~= 10^244 */
 1826    U64(0xEA53DF5F, 0xD18D5513), U64(0x84C86189, 0x216DC5ED), /* ~= 10^245 */
 1827    U64(0x92746B9B, 0xE2F8552C), U64(0x32FD3CF5, 0xB4E49BB4), /* ~= 10^246 */
 1828    U64(0xB7118682, 0xDBB66A77), U64(0x3FBC8C33, 0x221DC2A1), /* ~= 10^247 */
 1829    U64(0xE4D5E823, 0x92A40515), U64(0x0FABAF3F, 0xEAA5334A), /* ~= 10^248 */
 1830    U64(0x8F05B116, 0x3BA6832D), U64(0x29CB4D87, 0xF2A7400E), /* ~= 10^249 */
 1831    U64(0xB2C71D5B, 0xCA9023F8), U64(0x743E20E9, 0xEF511012), /* ~= 10^250 */
 1832    U64(0xDF78E4B2, 0xBD342CF6), U64(0x914DA924, 0x6B255416), /* ~= 10^251 */
 1833    U64(0x8BAB8EEF, 0xB6409C1A), U64(0x1AD089B6, 0xC2F7548E), /* ~= 10^252 */
 1834    U64(0xAE9672AB, 0xA3D0C320), U64(0xA184AC24, 0x73B529B1), /* ~= 10^253 */
 1835    U64(0xDA3C0F56, 0x8CC4F3E8), U64(0xC9E5D72D, 0x90A2741E), /* ~= 10^254 */
 1836    U64(0x88658996, 0x17FB1871), U64(0x7E2FA67C, 0x7A658892), /* ~= 10^255 */
 1837    U64(0xAA7EEBFB, 0x9DF9DE8D), U64(0xDDBB901B, 0x98FEEAB7), /* ~= 10^256 */
 1838    U64(0xD51EA6FA, 0x85785631), U64(0x552A7422, 0x7F3EA565), /* ~= 10^257 */
 1839    U64(0x8533285C, 0x936B35DE), U64(0xD53A8895, 0x8F87275F), /* ~= 10^258 */
 1840    U64(0xA67FF273, 0xB8460356), U64(0x8A892ABA, 0xF368F137), /* ~= 10^259 */
 1841    U64(0xD01FEF10, 0xA657842C), U64(0x2D2B7569, 0xB0432D85), /* ~= 10^260 */
 1842    U64(0x8213F56A, 0x67F6B29B), U64(0x9C3B2962, 0x0E29FC73), /* ~= 10^261 */
 1843    U64(0xA298F2C5, 0x01F45F42), U64(0x8349F3BA, 0x91B47B8F), /* ~= 10^262 */
 1844    U64(0xCB3F2F76, 0x42717713), U64(0x241C70A9, 0x36219A73), /* ~= 10^263 */
 1845    U64(0xFE0EFB53, 0xD30DD4D7), U64(0xED238CD3, 0x83AA0110), /* ~= 10^264 */
 1846    U64(0x9EC95D14, 0x63E8A506), U64(0xF4363804, 0x324A40AA), /* ~= 10^265 */
 1847    U64(0xC67BB459, 0x7CE2CE48), U64(0xB143C605, 0x3EDCD0D5), /* ~= 10^266 */
 1848    U64(0xF81AA16F, 0xDC1B81DA), U64(0xDD94B786, 0x8E94050A), /* ~= 10^267 */
 1849    U64(0x9B10A4E5, 0xE9913128), U64(0xCA7CF2B4, 0x191C8326), /* ~= 10^268 */
 1850    U64(0xC1D4CE1F, 0x63F57D72), U64(0xFD1C2F61, 0x1F63A3F0), /* ~= 10^269 */
 1851    U64(0xF24A01A7, 0x3CF2DCCF), U64(0xBC633B39, 0x673C8CEC), /* ~= 10^270 */
 1852    U64(0x976E4108, 0x8617CA01), U64(0xD5BE0503, 0xE085D813), /* ~= 10^271 */
 1853    U64(0xBD49D14A, 0xA79DBC82), U64(0x4B2D8644, 0xD8A74E18), /* ~= 10^272 */
 1854    U64(0xEC9C459D, 0x51852BA2), U64(0xDDF8E7D6, 0x0ED1219E), /* ~= 10^273 */
 1855    U64(0x93E1AB82, 0x52F33B45), U64(0xCABB90E5, 0xC942B503), /* ~= 10^274 */
 1856    U64(0xB8DA1662, 0xE7B00A17), U64(0x3D6A751F, 0x3B936243), /* ~= 10^275 */
 1857    U64(0xE7109BFB, 0xA19C0C9D), U64(0x0CC51267, 0x0A783AD4), /* ~= 10^276 */
 1858    U64(0x906A617D, 0x450187E2), U64(0x27FB2B80, 0x668B24C5), /* ~= 10^277 */
 1859    U64(0xB484F9DC, 0x9641E9DA), U64(0xB1F9F660, 0x802DEDF6), /* ~= 10^278 */
 1860    U64(0xE1A63853, 0xBBD26451), U64(0x5E7873F8, 0xA0396973), /* ~= 10^279 */
 1861    U64(0x8D07E334, 0x55637EB2), U64(0xDB0B487B, 0x6423E1E8), /* ~= 10^280 */
 1862    U64(0xB049DC01, 0x6ABC5E5F), U64(0x91CE1A9A, 0x3D2CDA62), /* ~= 10^281 */
 1863    U64(0xDC5C5301, 0xC56B75F7), U64(0x7641A140, 0xCC7810FB), /* ~= 10^282 */
 1864    U64(0x89B9B3E1, 0x1B6329BA), U64(0xA9E904C8, 0x7FCB0A9D), /* ~= 10^283 */
 1865    U64(0xAC2820D9, 0x623BF429), U64(0x546345FA, 0x9FBDCD44), /* ~= 10^284 */
 1866    U64(0xD732290F, 0xBACAF133), U64(0xA97C1779, 0x47AD4095), /* ~= 10^285 */
 1867    U64(0x867F59A9, 0xD4BED6C0), U64(0x49ED8EAB, 0xCCCC485D), /* ~= 10^286 */
 1868    U64(0xA81F3014, 0x49EE8C70), U64(0x5C68F256, 0xBFFF5A74), /* ~= 10^287 */
 1869    U64(0xD226FC19, 0x5C6A2F8C), U64(0x73832EEC, 0x6FFF3111), /* ~= 10^288 */
 1870    U64(0x83585D8F, 0xD9C25DB7), U64(0xC831FD53, 0xC5FF7EAB), /* ~= 10^289 */
 1871    U64(0xA42E74F3, 0xD032F525), U64(0xBA3E7CA8, 0xB77F5E55), /* ~= 10^290 */
 1872    U64(0xCD3A1230, 0xC43FB26F), U64(0x28CE1BD2, 0xE55F35EB), /* ~= 10^291 */
 1873    U64(0x80444B5E, 0x7AA7CF85), U64(0x7980D163, 0xCF5B81B3), /* ~= 10^292 */
 1874    U64(0xA0555E36, 0x1951C366), U64(0xD7E105BC, 0xC332621F), /* ~= 10^293 */
 1875    U64(0xC86AB5C3, 0x9FA63440), U64(0x8DD9472B, 0xF3FEFAA7), /* ~= 10^294 */
 1876    U64(0xFA856334, 0x878FC150), U64(0xB14F98F6, 0xF0FEB951), /* ~= 10^295 */
 1877    U64(0x9C935E00, 0xD4B9D8D2), U64(0x6ED1BF9A, 0x569F33D3), /* ~= 10^296 */
 1878    U64(0xC3B83581, 0x09E84F07), U64(0x0A862F80, 0xEC4700C8), /* ~= 10^297 */
 1879    U64(0xF4A642E1, 0x4C6262C8), U64(0xCD27BB61, 0x2758C0FA), /* ~= 10^298 */
 1880    U64(0x98E7E9CC, 0xCFBD7DBD), U64(0x8038D51C, 0xB897789C), /* ~= 10^299 */
 1881    U64(0xBF21E440, 0x03ACDD2C), U64(0xE0470A63, 0xE6BD56C3), /* ~= 10^300 */
 1882    U64(0xEEEA5D50, 0x04981478), U64(0x1858CCFC, 0xE06CAC74), /* ~= 10^301 */
 1883    U64(0x95527A52, 0x02DF0CCB), U64(0x0F37801E, 0x0C43EBC8), /* ~= 10^302 */
 1884    U64(0xBAA718E6, 0x8396CFFD), U64(0xD3056025, 0x8F54E6BA), /* ~= 10^303 */
 1885    U64(0xE950DF20, 0x247C83FD), U64(0x47C6B82E, 0xF32A2069), /* ~= 10^304 */
 1886    U64(0x91D28B74, 0x16CDD27E), U64(0x4CDC331D, 0x57FA5441), /* ~= 10^305 */
 1887    U64(0xB6472E51, 0x1C81471D), U64(0xE0133FE4, 0xADF8E952), /* ~= 10^306 */
 1888    U64(0xE3D8F9E5, 0x63A198E5), U64(0x58180FDD, 0xD97723A6), /* ~= 10^307 */
 1889    U64(0x8E679C2F, 0x5E44FF8F), U64(0x570F09EA, 0xA7EA7648), /* ~= 10^308 */
 1890    U64(0xB201833B, 0x35D63F73), U64(0x2CD2CC65, 0x51E513DA), /* ~= 10^309 */
 1891    U64(0xDE81E40A, 0x034BCF4F), U64(0xF8077F7E, 0xA65E58D1), /* ~= 10^310 */
 1892    U64(0x8B112E86, 0x420F6191), U64(0xFB04AFAF, 0x27FAF782), /* ~= 10^311 */
 1893    U64(0xADD57A27, 0xD29339F6), U64(0x79C5DB9A, 0xF1F9B563), /* ~= 10^312 */
 1894    U64(0xD94AD8B1, 0xC7380874), U64(0x18375281, 0xAE7822BC), /* ~= 10^313 */
 1895    U64(0x87CEC76F, 0x1C830548), U64(0x8F229391, 0x0D0B15B5), /* ~= 10^314 */
 1896    U64(0xA9C2794A, 0xE3A3C69A), U64(0xB2EB3875, 0x504DDB22), /* ~= 10^315 */
 1897    U64(0xD433179D, 0x9C8CB841), U64(0x5FA60692, 0xA46151EB), /* ~= 10^316 */
 1898    U64(0x849FEEC2, 0x81D7F328), U64(0xDBC7C41B, 0xA6BCD333), /* ~= 10^317 */
 1899    U64(0xA5C7EA73, 0x224DEFF3), U64(0x12B9B522, 0x906C0800), /* ~= 10^318 */
 1900    U64(0xCF39E50F, 0xEAE16BEF), U64(0xD768226B, 0x34870A00), /* ~= 10^319 */
 1901    U64(0x81842F29, 0xF2CCE375), U64(0xE6A11583, 0x00D46640), /* ~= 10^320 */
 1902    U64(0xA1E53AF4, 0x6F801C53), U64(0x60495AE3, 0xC1097FD0), /* ~= 10^321 */
 1903    U64(0xCA5E89B1, 0x8B602368), U64(0x385BB19C, 0xB14BDFC4), /* ~= 10^322 */
 1904    U64(0xFCF62C1D, 0xEE382C42), U64(0x46729E03, 0xDD9ED7B5), /* ~= 10^323 */
 1905    U64(0x9E19DB92, 0xB4E31BA9), U64(0x6C07A2C2, 0x6A8346D1)  /* ~= 10^324 */
 1906};
 1907
 1908/**
 1909 Get the cached pow10 value from `pow10_sig_table`.
 1910 @param exp10 The exponent of pow(10, e). This value must be in the range
 1911              `POW10_SIG_TABLE_MIN_EXP` to `POW10_SIG_TABLE_MAX_EXP`.
 1912 @param hi    The highest 64 bits of pow(10, e).
 1913 @param lo    The lower 64 bits after `hi`.
 1914 */
 1915static_inline void pow10_table_get_sig(i32 exp10, u64 *hi, u64 *lo) {
 1916    i32 idx = exp10 - (POW10_SIG_TABLE_MIN_EXP);
 1917    *hi = pow10_sig_table[idx * 2];
 1918    *lo = pow10_sig_table[idx * 2 + 1];
 1919}
 1920
 1921/**
 1922 Get the exponent (base 2) for the highest 64-bit significand in
 1923 `pow10_sig_table`.
 1924 */
 1925static_inline void pow10_table_get_exp(i32 exp10, i32 *exp2) {
 1926    /* e2 = floor(log2(pow(10, e))) - 64 + 1 */
 1927    /*    = floor(e * log2(10) - 63)         */
 1928    *exp2 = (exp10 * 217706 - 4128768) >> 16;
 1929}
 1930
 1931#endif
 1932
 1933
 1934
 1935/*==============================================================================
 1936 * MARK: - Number and Bit Utils (Private)
 1937 *============================================================================*/
 1938
 1939/** Convert bits to double. */
 1940static_inline f64 f64_from_bits(u64 u) {
 1941    f64 f;
 1942    memcpy(&f, &u, sizeof(u));
 1943    return f;
 1944}
 1945
 1946/** Convert double to bits. */
 1947static_inline u64 f64_to_bits(f64 f) {
 1948    u64 u;
 1949    memcpy(&u, &f, sizeof(u));
 1950    return u;
 1951}
 1952
 1953/** Convert float to bits. */
 1954static_inline u32 f32_to_bits(f32 f) {
 1955    u32 u;
 1956    memcpy(&u, &f, sizeof(u));
 1957    return u;
 1958}
 1959
 1960/** Get 'infinity' bits with sign. */
 1961static_inline u64 f64_bits_inf(bool sign) {
 1962#if YYJSON_HAS_IEEE_754
 1963    return F64_BITS_INF | ((u64)sign << 63);
 1964#else
 1965    return f64_to_bits(sign ? (f64)-INFINITY : (f64)INFINITY);
 1966#endif
 1967}
 1968
 1969/** Returns whether the double value is infinity (not NaN). */
 1970static_inline bool f64_is_inf(f64 val) {
 1971#if YYJSON_HAS_IEEE_754
 1972    return (f64_to_bits(val) & F64_EXP_MASK) == F64_BITS_INF;
 1973#else
 1974    return val >= (f64)INFINITY || val <= (f64)-INFINITY;
 1975#endif
 1976}
 1977
 1978/** Get 'nan' bits with sign. */
 1979static_inline u64 f64_bits_nan(bool sign) {
 1980#if YYJSON_HAS_IEEE_754
 1981    return F64_BITS_NAN | ((u64)sign << 63);
 1982#else
 1983    return f64_to_bits(sign ? (f64)-NAN : (f64)NAN);
 1984#endif
 1985}
 1986
 1987/** Casting double to float, allow overflow. */
 1988#if yyjson_has_attribute(no_sanitize)
 1989__attribute__((no_sanitize("undefined")))
 1990#elif yyjson_gcc_available(4, 9, 0)
 1991__attribute__((__no_sanitize_undefined__))
 1992#endif
 1993static_inline f32 f64_to_f32(f64 val) {
 1994    return (f32)val;
 1995}
 1996
 1997/** Returns the number of leading 0-bits in value (input should not be 0). */
 1998static_inline u32 u64_lz_bits(u64 v) {
 1999#if GCC_HAS_CLZLL
 2000    return (u32)__builtin_clzll(v);
 2001#elif MSC_HAS_BIT_SCAN_64
 2002    unsigned long r;
 2003    _BitScanReverse64(&r, v);
 2004    return (u32)63 - (u32)r;
 2005#elif MSC_HAS_BIT_SCAN
 2006    unsigned long hi, lo;
 2007    bool hi_set = _BitScanReverse(&hi, (u32)(v >> 32)) != 0;
 2008    _BitScanReverse(&lo, (u32)v);
 2009    hi |= 32;
 2010    return (u32)63 - (u32)(hi_set ? hi : lo);
 2011#else
 2012    /* branchless, use De Bruijn sequence */
 2013    /* see: https://www.chessprogramming.org/BitScan */
 2014    const u8 table[64] = {
 2015        63, 16, 62,  7, 15, 36, 61,  3,  6, 14, 22, 26, 35, 47, 60,  2,
 2016         9,  5, 28, 11, 13, 21, 42, 19, 25, 31, 34, 40, 46, 52, 59,  1,
 2017        17,  8, 37,  4, 23, 27, 48, 10, 29, 12, 43, 20, 32, 41, 53, 18,
 2018        38, 24, 49, 30, 44, 33, 54, 39, 50, 45, 55, 51, 56, 57, 58,  0
 2019    };
 2020    v |= v >> 1;
 2021    v |= v >> 2;
 2022    v |= v >> 4;
 2023    v |= v >> 8;
 2024    v |= v >> 16;
 2025    v |= v >> 32;
 2026    return table[(v * U64(0x03F79D71, 0xB4CB0A89)) >> 58];
 2027#endif
 2028}
 2029
 2030/** Returns the number of trailing 0-bits in value (input should not be 0). */
 2031static_inline u32 u64_tz_bits(u64 v) {
 2032#if GCC_HAS_CTZLL
 2033    return (u32)__builtin_ctzll(v);
 2034#elif MSC_HAS_BIT_SCAN_64
 2035    unsigned long r;
 2036    _BitScanForward64(&r, v);
 2037    return (u32)r;
 2038#elif MSC_HAS_BIT_SCAN
 2039    unsigned long lo, hi;
 2040    bool lo_set = _BitScanForward(&lo, (u32)(v)) != 0;
 2041    _BitScanForward(&hi, (u32)(v >> 32));
 2042    hi += 32;
 2043    return lo_set ? lo : hi;
 2044#else
 2045    /* branchless, use De Bruijn sequence */
 2046    /* see: https://www.chessprogramming.org/BitScan */
 2047    const u8 table[64] = {
 2048         0,  1,  2, 53,  3,  7, 54, 27,  4, 38, 41,  8, 34, 55, 48, 28,
 2049        62,  5, 39, 46, 44, 42, 22,  9, 24, 35, 59, 56, 49, 18, 29, 11,
 2050        63, 52,  6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
 2051        51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12
 2052    };
 2053    return table[((v & (~v + 1)) * U64(0x022FDD63, 0xCC95386D)) >> 58];
 2054#endif
 2055}
 2056
 2057/** Multiplies two 64-bit unsigned integers (a * b),
 2058    returns the 128-bit result as 'hi' and 'lo'. */
 2059static_inline void u128_mul(u64 a, u64 b, u64 *hi, u64 *lo) {
 2060#if YYJSON_HAS_INT128
 2061    u128 m = (u128)a * b;
 2062    *hi = (u64)(m >> 64);
 2063    *lo = (u64)(m);
 2064#elif MSC_HAS_UMUL128
 2065    *lo = _umul128(a, b, hi);
 2066#else
 2067    u32 a0 = (u32)(a), a1 = (u32)(a >> 32);
 2068    u32 b0 = (u32)(b), b1 = (u32)(b >> 32);
 2069    u64 p00 = (u64)a0 * b0, p01 = (u64)a0 * b1;
 2070    u64 p10 = (u64)a1 * b0, p11 = (u64)a1 * b1;
 2071    u64 m0 = p01 + (p00 >> 32);
 2072    u32 m00 = (u32)(m0), m01 = (u32)(m0 >> 32);
 2073    u64 m1 = p10 + m00;
 2074    u32 m10 = (u32)(m1), m11 = (u32)(m1 >> 32);
 2075    *hi = p11 + m01 + m11;
 2076    *lo = ((u64)m10 << 32) | (u32)p00;
 2077#endif
 2078}
 2079
 2080/** Multiplies two 64-bit unsigned integers and add a value (a * b + c),
 2081    returns the 128-bit result as 'hi' and 'lo'. */
 2082static_inline void u128_mul_add(u64 a, u64 b, u64 c, u64 *hi, u64 *lo) {
 2083#if YYJSON_HAS_INT128
 2084    u128 m = (u128)a * b + c;
 2085    *hi = (u64)(m >> 64);
 2086    *lo = (u64)(m);
 2087#else
 2088    u64 h, l, t;
 2089    u128_mul(a, b, &h, &l);
 2090    t = l + c;
 2091    h += (u64)(((t < l) | (t < c)));
 2092    *hi = h;
 2093    *lo = t;
 2094#endif
 2095}
 2096
 2097
 2098
 2099/*==============================================================================
 2100 * MARK: - File Utils (Private)
 2101 * These functions are used to read and write JSON files.
 2102 *============================================================================*/
 2103
 2104#if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE
 2105
 2106#define YYJSON_FOPEN_E
 2107#if !defined(_MSC_VER) && defined(__GLIBC__) && defined(__GLIBC_PREREQ)
 2108#   if __GLIBC_PREREQ(2, 7)
 2109#       undef YYJSON_FOPEN_E
 2110#       define YYJSON_FOPEN_E "e" /* glibc extension to enable O_CLOEXEC */
 2111#   endif
 2112#endif
 2113
 2114static_inline FILE *fopen_safe(const char *path, const char *mode) {
 2115#if YYJSON_MSC_VER >= 1400
 2116    FILE *file = NULL;
 2117    if (fopen_s(&file, path, mode) != 0) return NULL;
 2118    return file;
 2119#else
 2120    return fopen(path, mode);
 2121#endif
 2122}
 2123
 2124static_inline FILE *fopen_readonly(const char *path) {
 2125    return fopen_safe(path, "rb" YYJSON_FOPEN_E);
 2126}
 2127
 2128static_inline FILE *fopen_writeonly(const char *path) {
 2129    return fopen_safe(path, "wb" YYJSON_FOPEN_E);
 2130}
 2131
 2132static_inline usize fread_safe(void *buf, usize size, FILE *file) {
 2133#if YYJSON_MSC_VER >= 1400
 2134    return fread_s(buf, size, 1, size, file);
 2135#else
 2136    return fread(buf, 1, size, file);
 2137#endif
 2138}
 2139
 2140#endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */
 2141
 2142
 2143
 2144/*==============================================================================
 2145 * MARK: - Size Utils (Private)
 2146 * These functions are used for memory allocation.
 2147 *============================================================================*/
 2148
 2149/** Returns whether the size is overflow after increment. */
 2150static_inline bool size_add_is_overflow(usize size, usize add) {
 2151    return size > (size + add);
 2152}
 2153
 2154/** Returns whether the size is power of 2 (size should not be 0). */
 2155static_inline bool size_is_pow2(usize size) {
 2156    return (size & (size - 1)) == 0;
 2157}
 2158
 2159/** Align size upwards (may overflow). */
 2160static_inline usize size_align_up(usize size, usize align) {
 2161    if (size_is_pow2(align)) {
 2162        return (size + (align - 1)) & ~(align - 1);
 2163    } else {
 2164        return size + align - (size + align - 1) % align - 1;
 2165    }
 2166}
 2167
 2168/** Align size downwards. */
 2169static_inline usize size_align_down(usize size, usize align) {
 2170    if (size_is_pow2(align)) {
 2171        return size & ~(align - 1);
 2172    } else {
 2173        return size - (size % align);
 2174    }
 2175}
 2176
 2177/** Align address upwards (may overflow). */
 2178static_inline void *mem_align_up(void *mem, usize align) {
 2179    usize size;
 2180    memcpy(&size, &mem, sizeof(usize));
 2181    size = size_align_up(size, align);
 2182    memcpy(&mem, &size, sizeof(usize));
 2183    return mem;
 2184}
 2185
 2186
 2187
 2188/*==============================================================================
 2189 * MARK: - Null Memory Allocator (Private)
 2190 * This allocator is just a placeholder to ensure that the internal
 2191 * malloc/realloc/free function pointers are not null.
 2192 *============================================================================*/
 2193
 2194static void *null_malloc(void *ctx, usize size) {
 2195    return NULL;
 2196}
 2197
 2198static void *null_realloc(void *ctx, void *ptr, usize old_size, usize size) {
 2199    return NULL;
 2200}
 2201
 2202static void null_free(void *ctx, void *ptr) {
 2203    return;
 2204}
 2205
 2206static const yyjson_alc YYJSON_NULL_ALC = {
 2207    null_malloc, null_realloc, null_free, NULL
 2208};
 2209
 2210
 2211
 2212/*==============================================================================
 2213 * MARK: - Default Memory Allocator (Private)
 2214 * This is a simple libc memory allocator wrapper.
 2215 *============================================================================*/
 2216
 2217#if defined(YYJSON_CUSTOM_ALC)
 2218
 2219/* user-provided via macro */
 2220extern const yyjson_alc YYJSON_CUSTOM_ALC;
 2221#define YYJSON_DEFAULT_ALC YYJSON_CUSTOM_ALC
 2222
 2223#elif YYJSON_FREESTANDING
 2224
 2225/* null allocator */
 2226static const yyjson_alc YYJSON_DEFAULT_ALC = {
 2227    null_malloc, null_realloc, null_free, NULL
 2228};
 2229
 2230#else /* YYJSON_FREESTANDING */
 2231
 2232/* default libc allocator */
 2233static void *default_malloc(void *ctx, usize size) {
 2234    return malloc(size);
 2235}
 2236static void *default_realloc(void *ctx, void *ptr, usize old_size, usize size) {
 2237    return realloc(ptr, size);
 2238}
 2239static void default_free(void *ctx, void *ptr) {
 2240    free(ptr);
 2241}
 2242static const yyjson_alc YYJSON_DEFAULT_ALC = {
 2243    default_malloc, default_realloc, default_free, NULL
 2244};
 2245
 2246#endif /* YYJSON_FREESTANDING */
 2247
 2248
 2249
 2250/*==============================================================================
 2251 * MARK: - Pool Memory Allocator (Public)
 2252 * This allocator is initialized with a fixed-size buffer.
 2253 * The buffer is split into multiple memory chunks for memory allocation.
 2254 *============================================================================*/
 2255
 2256/** memory chunk header */
 2257typedef struct pool_chunk {
 2258    usize size; /* chunk memory size, including chunk header */
 2259    struct pool_chunk *next; /* linked list, nullable */
 2260    /* char mem[]; flexible array member */
 2261} pool_chunk;
 2262
 2263/** allocator ctx header */
 2264typedef struct pool_ctx {
 2265    usize size; /* total memory size, including ctx header */
 2266    pool_chunk *free_list; /* linked list, nullable */
 2267    /* pool_chunk chunks[]; flexible array member */
 2268} pool_ctx;
 2269
 2270/** align up the input size to chunk size */
 2271static_inline void pool_size_align(usize *size) {
 2272    *size = size_align_up(*size, sizeof(pool_chunk)) + sizeof(pool_chunk);
 2273}
 2274
 2275static void *pool_malloc(void *ctx_ptr, usize size) {
 2276    /* assert(size != 0) */
 2277    pool_ctx *ctx = (pool_ctx *)ctx_ptr;
 2278    pool_chunk *next, *prev = NULL, *cur = ctx->free_list;
 2279
 2280    if (unlikely(size >= ctx->size)) return NULL;
 2281    pool_size_align(&size);
 2282
 2283    while (cur) {
 2284        if (cur->size < size) {
 2285            /* not enough space, try next chunk */
 2286            prev = cur;
 2287            cur = cur->next;
 2288            continue;
 2289        }
 2290        if (cur->size >= size + sizeof(pool_chunk) * 2) {
 2291            /* too much space, split this chunk */
 2292            next = (pool_chunk *)(void *)((u8 *)cur + size);
 2293            next->size = cur->size - size;
 2294            next->next = cur->next;
 2295            cur->size = size;
 2296        } else {
 2297            /* just enough space, use whole chunk */
 2298            next = cur->next;
 2299        }
 2300        if (prev) prev->next = next;
 2301        else ctx->free_list = next;
 2302        return (void *)(cur + 1);
 2303    }
 2304    return NULL;
 2305}
 2306
 2307static void pool_free(void *ctx_ptr, void *ptr) {
 2308    /* assert(ptr != NULL) */
 2309    pool_ctx *ctx = (pool_ctx *)ctx_ptr;
 2310    pool_chunk *cur = ((pool_chunk *)ptr) - 1;
 2311    pool_chunk *prev = NULL, *next = ctx->free_list;
 2312
 2313    while (next && next < cur) {
 2314        prev = next;
 2315        next = next->next;
 2316    }
 2317    if (prev) prev->next = cur;
 2318    else ctx->free_list = cur;
 2319    cur->next = next;
 2320
 2321    if (next && ((u8 *)cur + cur->size) == (u8 *)next) {
 2322        /* merge cur to higher chunk */
 2323        cur->size += next->size;
 2324        cur->next = next->next;
 2325    }
 2326    if (prev && ((u8 *)prev + prev->size) == (u8 *)cur) {
 2327        /* merge cur to lower chunk */
 2328        prev->size += cur->size;
 2329        prev->next = cur->next;
 2330    }
 2331}
 2332
 2333static void *pool_realloc(void *ctx_ptr, void *ptr,
 2334                          usize old_size, usize size) {
 2335    /* assert(ptr != NULL && size != 0 && old_size < size) */
 2336    pool_ctx *ctx = (pool_ctx *)ctx_ptr;
 2337    pool_chunk *cur = ((pool_chunk *)ptr) - 1, *prev, *next, *tmp;
 2338
 2339    /* check size */
 2340    if (unlikely(size >= ctx->size)) return NULL;
 2341    pool_size_align(&old_size);
 2342    pool_size_align(&size);
 2343    if (unlikely(old_size == size)) return ptr;
 2344
 2345    /* find next and prev chunk */
 2346    prev = NULL;
 2347    next = ctx->free_list;
 2348    while (next && next < cur) {
 2349        prev = next;
 2350        next = next->next;
 2351    }
 2352
 2353    if ((u8 *)cur + cur->size == (u8 *)next && cur->size + next->size >= size) {
 2354        /* merge to higher chunk if they are contiguous */
 2355        usize free_size = cur->size + next->size - size;
 2356        if (free_size > sizeof(pool_chunk) * 2) {
 2357            tmp = (pool_chunk *)(void *)((u8 *)cur + size);
 2358            if (prev) prev->next = tmp;
 2359            else ctx->free_list = tmp;
 2360            tmp->next = next->next;
 2361            tmp->size = free_size;
 2362            cur->size = size;
 2363        } else {
 2364            if (prev) prev->next = next->next;
 2365            else ctx->free_list = next->next;
 2366            cur->size += next->size;
 2367        }
 2368        return ptr;
 2369    } else {
 2370        /* fallback to malloc and memcpy */
 2371        void *new_ptr = pool_malloc(ctx_ptr, size - sizeof(pool_chunk));
 2372        if (new_ptr) {
 2373            memcpy(new_ptr, ptr, cur->size - sizeof(pool_chunk));
 2374            pool_free(ctx_ptr, ptr);
 2375        }
 2376        return new_ptr;
 2377    }
 2378}
 2379
 2380bool yyjson_alc_pool_init(yyjson_alc *alc, void *buf, usize size) {
 2381    pool_chunk *chunk;
 2382    pool_ctx *ctx;
 2383
 2384    if (unlikely(!alc)) return false;
 2385    *alc = YYJSON_NULL_ALC;
 2386    if (size < sizeof(pool_ctx) * 4) return false;
 2387    ctx = (pool_ctx *)mem_align_up(buf, sizeof(pool_ctx));
 2388    if (unlikely(!ctx)) return false;
 2389    size -= (usize)((u8 *)ctx - (u8 *)buf);
 2390    size = size_align_down(size, sizeof(pool_ctx));
 2391
 2392    chunk = (pool_chunk *)(ctx + 1);
 2393    chunk->size = size - sizeof(pool_ctx);
 2394    chunk->next = NULL;
 2395    ctx->size = size;
 2396    ctx->free_list = chunk;
 2397
 2398    alc->malloc = pool_malloc;
 2399    alc->realloc = pool_realloc;
 2400    alc->free = pool_free;
 2401    alc->ctx = (void *)ctx;
 2402    return true;
 2403}
 2404
 2405
 2406
 2407/*==============================================================================
 2408 * MARK: - Dynamic Memory Allocator (Public)
 2409 * This allocator allocates memory on demand and does not immediately release
 2410 * unused memory. Instead, it places the unused memory into a freelist for
 2411 * potential reuse in the future. It is only when the entire allocator is
 2412 * destroyed that all previously allocated memory is released at once.
 2413 *============================================================================*/
 2414
 2415/** memory chunk header */
 2416typedef struct dyn_chunk {
 2417    usize size; /* chunk size, including header */
 2418    struct dyn_chunk *next;
 2419    /* char mem[]; flexible array member */
 2420} dyn_chunk;
 2421
 2422/** allocator ctx header */
 2423typedef struct {
 2424    dyn_chunk free_list; /* dummy header, sorted from small to large */
 2425    dyn_chunk used_list; /* dummy header */
 2426} dyn_ctx;
 2427
 2428/** align up the input size to chunk size */
 2429static_inline bool dyn_size_align(usize *size) {
 2430    usize alc_size = *size + sizeof(dyn_chunk);
 2431    alc_size = size_align_up(alc_size, YYJSON_ALC_DYN_MIN_SIZE);
 2432    if (unlikely(alc_size < *size)) return false; /* overflow */
 2433    *size = alc_size;
 2434    return true;
 2435}
 2436
 2437/** remove a chunk from list (the chunk must already be in the list) */
 2438static_inline void dyn_chunk_list_remove(dyn_chunk *list, dyn_chunk *chunk) {
 2439    dyn_chunk *prev = list, *cur;
 2440    for (cur = prev->next; cur; cur = cur->next) {
 2441        if (cur == chunk) {
 2442            prev->next = cur->next;
 2443            cur->next = NULL;
 2444            return;
 2445        }
 2446        prev = cur;
 2447    }
 2448}
 2449
 2450/** add a chunk to list header (the chunk must not be in the list) */
 2451static_inline void dyn_chunk_list_add(dyn_chunk *list, dyn_chunk *chunk) {
 2452    chunk->next = list->next;
 2453    list->next = chunk;
 2454}
 2455
 2456static void *dyn_malloc(void *ctx_ptr, usize size) {
 2457    /* assert(size != 0) */
 2458    const yyjson_alc def = YYJSON_DEFAULT_ALC;
 2459    dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
 2460    dyn_chunk *chunk, *prev;
 2461    if (unlikely(!dyn_size_align(&size))) return NULL;
 2462
 2463    /* freelist is empty, create new chunk */
 2464    if (!ctx->free_list.next) {
 2465        chunk = (dyn_chunk *)def.malloc(def.ctx, size);
 2466        if (unlikely(!chunk)) return NULL;
 2467        chunk->size = size;
 2468        chunk->next = NULL;
 2469        dyn_chunk_list_add(&ctx->used_list, chunk);
 2470        return (void *)(chunk + 1);
 2471    }
 2472
 2473    /* find a large enough chunk, or resize the largest chunk */
 2474    prev = &ctx->free_list;
 2475    while (true) {
 2476        chunk = prev->next;
 2477        if (chunk->size >= size) { /* enough size, reuse this chunk */
 2478            prev->next = chunk->next;
 2479            dyn_chunk_list_add(&ctx->used_list, chunk);
 2480            return (void *)(chunk + 1);
 2481        }
 2482        if (!chunk->next) { /* resize the largest chunk */
 2483            chunk = (dyn_chunk *)def.realloc(def.ctx, chunk, chunk->size, size);
 2484            if (unlikely(!chunk)) return NULL;
 2485            prev->next = NULL;
 2486            chunk->size = size;
 2487            dyn_chunk_list_add(&ctx->used_list, chunk);
 2488            return (void *)(chunk + 1);
 2489        }
 2490        prev = chunk;
 2491    }
 2492}
 2493
 2494static void *dyn_realloc(void *ctx_ptr, void *ptr,
 2495                          usize old_size, usize size) {
 2496    /* assert(ptr != NULL && size != 0 && old_size < size) */
 2497    const yyjson_alc def = YYJSON_DEFAULT_ALC;
 2498    dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
 2499    dyn_chunk *new_chunk, *chunk = (dyn_chunk *)ptr - 1;
 2500    if (unlikely(!dyn_size_align(&size))) return NULL;
 2501    if (chunk->size >= size) return ptr;
 2502
 2503    dyn_chunk_list_remove(&ctx->used_list, chunk);
 2504    new_chunk = (dyn_chunk *)def.realloc(def.ctx, chunk, chunk->size, size);
 2505    if (likely(new_chunk)) {
 2506        new_chunk->size = size;
 2507        chunk = new_chunk;
 2508    }
 2509    dyn_chunk_list_add(&ctx->used_list, chunk);
 2510    return new_chunk ? (void *)(new_chunk + 1) : NULL;
 2511}
 2512
 2513static void dyn_free(void *ctx_ptr, void *ptr) {
 2514    /* assert(ptr != NULL) */
 2515    dyn_ctx *ctx = (dyn_ctx *)ctx_ptr;
 2516    dyn_chunk *chunk = (dyn_chunk *)ptr - 1, *prev;
 2517
 2518    dyn_chunk_list_remove(&ctx->used_list, chunk);
 2519    for (prev = &ctx->free_list; prev; prev = prev->next) {
 2520        if (!prev->next || prev->next->size >= chunk->size) {
 2521            chunk->next = prev->next;
 2522            prev->next = chunk;
 2523            break;
 2524        }
 2525    }
 2526}
 2527
 2528yyjson_alc *yyjson_alc_dyn_new(void) {
 2529    const yyjson_alc def = YYJSON_DEFAULT_ALC;
 2530    usize hdr_len = sizeof(yyjson_alc) + sizeof(dyn_ctx);
 2531    yyjson_alc *alc;
 2532    dyn_ctx *ctx;
 2533    alc = (yyjson_alc *)def.malloc(def.ctx, hdr_len);
 2534    if (unlikely(!alc)) return NULL;
 2535    ctx = (dyn_ctx *)(void *)(alc + 1);
 2536    alc->malloc = dyn_malloc;
 2537    alc->realloc = dyn_realloc;
 2538    alc->free = dyn_free;
 2539    alc->ctx = alc + 1;
 2540    memset(ctx, 0, sizeof(*ctx));
 2541    return alc;
 2542}
 2543
 2544void yyjson_alc_dyn_free(yyjson_alc *alc) {
 2545    const yyjson_alc def = YYJSON_DEFAULT_ALC;
 2546    dyn_ctx *ctx;
 2547    dyn_chunk *chunk, *next;
 2548    if (unlikely(!alc)) return;
 2549    ctx = (dyn_ctx *)(void *)(alc + 1);
 2550    for (chunk = ctx->free_list.next; chunk; chunk = next) {
 2551        next = chunk->next;
 2552        def.free(def.ctx, chunk);
 2553    }
 2554    for (chunk = ctx->used_list.next; chunk; chunk = next) {
 2555        next = chunk->next;
 2556        def.free(def.ctx, chunk);
 2557    }
 2558    def.free(def.ctx, alc);
 2559}
 2560
 2561
 2562
 2563/*==============================================================================
 2564 * MARK: - JSON Struct Utils (Public)
 2565 * These functions are used for creating, copying, releasing, and comparing
 2566 * JSON documents and values. They are widely used throughout this library.
 2567 *============================================================================*/
 2568
 2569static_inline void unsafe_yyjson_str_pool_release(yyjson_str_pool *pool,
 2570                                                  yyjson_alc *alc) {
 2571    yyjson_str_chunk *chunk = pool->chunks, *next;
 2572    while (chunk) {
 2573        next = chunk->next;
 2574        alc->free(alc->ctx, chunk);
 2575        chunk = next;
 2576    }
 2577}
 2578
 2579static_inline void unsafe_yyjson_val_pool_release(yyjson_val_pool *pool,
 2580                                                  yyjson_alc *alc) {
 2581    yyjson_val_chunk *chunk = pool->chunks, *next;
 2582    while (chunk) {
 2583        next = chunk->next;
 2584        alc->free(alc->ctx, chunk);
 2585        chunk = next;
 2586    }
 2587}
 2588
 2589bool unsafe_yyjson_str_pool_grow(yyjson_str_pool *pool,
 2590                                 const yyjson_alc *alc, usize len) {
 2591    yyjson_str_chunk *chunk;
 2592    usize size, max_len;
 2593
 2594    /* create a new chunk */
 2595    max_len = USIZE_MAX - sizeof(yyjson_str_chunk);
 2596    if (unlikely(len > max_len)) return false;
 2597    size = len + sizeof(yyjson_str_chunk);
 2598    size = yyjson_max(pool->chunk_size, size);
 2599    chunk = (yyjson_str_chunk *)alc->malloc(alc->ctx, size);
 2600    if (unlikely(!chunk)) return false;
 2601
 2602    /* insert the new chunk as the head of the linked list */
 2603    chunk->next = pool->chunks;
 2604    chunk->chunk_size = size;
 2605    pool->chunks = chunk;
 2606    pool->cur = (char *)chunk + sizeof(yyjson_str_chunk);
 2607    pool->end = (char *)chunk + size;
 2608
 2609    /* the next chunk is twice the size of the current one */
 2610    size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max);
 2611    if (size < pool->chunk_size) size = pool->chunk_size_max; /* overflow */
 2612    pool->chunk_size = size;
 2613    return true;
 2614}
 2615
 2616bool unsafe_yyjson_val_pool_grow(yyjson_val_pool *pool,
 2617                                 const yyjson_alc *alc, usize count) {
 2618    yyjson_val_chunk *chunk;
 2619    usize size, max_count;
 2620
 2621    /* create a new chunk */
 2622    max_count = USIZE_MAX / sizeof(yyjson_mut_val) - 1;
 2623    if (unlikely(count > max_count)) return false;
 2624    size = (count + 1) * sizeof(yyjson_mut_val);
 2625    size = yyjson_max(pool->chunk_size, size);
 2626    chunk = (yyjson_val_chunk *)alc->malloc(alc->ctx, size);
 2627    if (unlikely(!chunk)) return false;
 2628
 2629    /* insert the new chunk as the head of the linked list */
 2630    chunk->next = pool->chunks;
 2631    chunk->chunk_size = size;
 2632    pool->chunks = chunk;
 2633    pool->cur = (yyjson_mut_val *)(void *)((u8 *)chunk) + 1;
 2634    pool->end = (yyjson_mut_val *)(void *)((u8 *)chunk + size);
 2635
 2636    /* the next chunk is twice the size of the current one */
 2637    size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max);
 2638    if (size < pool->chunk_size) size = pool->chunk_size_max; /* overflow */
 2639    pool->chunk_size = size;
 2640    return true;
 2641}
 2642
 2643bool yyjson_mut_doc_set_str_pool_size(yyjson_mut_doc *doc, size_t len) {
 2644    usize max_size = USIZE_MAX - sizeof(yyjson_str_chunk);
 2645    if (!doc || !len || len > max_size) return false;
 2646    doc->str_pool.chunk_size = len + sizeof(yyjson_str_chunk);
 2647    return true;
 2648}
 2649
 2650bool yyjson_mut_doc_set_val_pool_size(yyjson_mut_doc *doc, size_t count) {
 2651    usize max_count = USIZE_MAX / sizeof(yyjson_mut_val) - 1;
 2652    if (!doc || !count || count > max_count) return false;
 2653    doc->val_pool.chunk_size = (count + 1) * sizeof(yyjson_mut_val);
 2654    return true;
 2655}
 2656
 2657void yyjson_mut_doc_free(yyjson_mut_doc *doc) {
 2658    if (doc) {
 2659        yyjson_alc alc = doc->alc;
 2660        memset(&doc->alc, 0, sizeof(alc));
 2661        unsafe_yyjson_str_pool_release(&doc->str_pool, &alc);
 2662        unsafe_yyjson_val_pool_release(&doc->val_pool, &alc);
 2663        alc.free(alc.ctx, doc);
 2664    }
 2665}
 2666
 2667yyjson_mut_doc *yyjson_mut_doc_new(const yyjson_alc *alc) {
 2668    yyjson_mut_doc *doc;
 2669    if (!alc) alc = &YYJSON_DEFAULT_ALC;
 2670    doc = (yyjson_mut_doc *)alc->malloc(alc->ctx, sizeof(yyjson_mut_doc));
 2671    if (!doc) return NULL;
 2672    memset(doc, 0, sizeof(yyjson_mut_doc));
 2673
 2674    doc->alc = *alc;
 2675    doc->str_pool.chunk_size = YYJSON_MUT_DOC_STR_POOL_INIT_SIZE;
 2676    doc->str_pool.chunk_size_max = YYJSON_MUT_DOC_STR_POOL_MAX_SIZE;
 2677    doc->val_pool.chunk_size = YYJSON_MUT_DOC_VAL_POOL_INIT_SIZE;
 2678    doc->val_pool.chunk_size_max = YYJSON_MUT_DOC_VAL_POOL_MAX_SIZE;
 2679    return doc;
 2680}
 2681
 2682yyjson_mut_doc *yyjson_doc_mut_copy(const yyjson_doc *doc,
 2683                                    const yyjson_alc *alc) {
 2684    yyjson_mut_doc *m_doc;
 2685    yyjson_mut_val *m_val;
 2686
 2687    if (!doc || !doc->root) return NULL;
 2688    m_doc = yyjson_mut_doc_new(alc);
 2689    if (!m_doc) return NULL;
 2690    m_val = yyjson_val_mut_copy(m_doc, doc->root);
 2691    if (!m_val) {
 2692        yyjson_mut_doc_free(m_doc);
 2693        return NULL;
 2694    }
 2695    yyjson_mut_doc_set_root(m_doc, m_val);
 2696    return m_doc;
 2697}
 2698
 2699yyjson_mut_doc *yyjson_mut_doc_mut_copy(const yyjson_mut_doc *doc,
 2700                                        const yyjson_alc *alc) {
 2701    yyjson_mut_doc *m_doc;
 2702    yyjson_mut_val *m_val;
 2703
 2704    if (!doc) return NULL;
 2705    if (!doc->root) return yyjson_mut_doc_new(alc);
 2706
 2707    m_doc = yyjson_mut_doc_new(alc);
 2708    if (!m_doc) return NULL;
 2709    m_val = yyjson_mut_val_mut_copy(m_doc, doc->root);
 2710    if (!m_val) {
 2711        yyjson_mut_doc_free(m_doc);
 2712        return NULL;
 2713    }
 2714    yyjson_mut_doc_set_root(m_doc, m_val);
 2715    return m_doc;
 2716}
 2717
 2718yyjson_mut_val *yyjson_val_mut_copy(yyjson_mut_doc *m_doc,
 2719                                    const yyjson_val *i_vals) {
 2720    /*
 2721     The immutable object or array stores all sub-values in a contiguous memory,
 2722     We copy them to another contiguous memory as mutable values,
 2723     then reconnect the mutable values with the original relationship.
 2724     */
 2725    usize i_vals_len;
 2726    yyjson_mut_val *m_vals, *m_val;
 2727    yyjson_val *i_val, *i_end;
 2728
 2729    if (!m_doc || !i_vals) return NULL;
 2730    i_end = unsafe_yyjson_get_next(i_vals);
 2731    i_vals_len = (usize)(unsafe_yyjson_get_next(i_vals) - i_vals);
 2732    m_vals = unsafe_yyjson_mut_val(m_doc, i_vals_len);
 2733    if (!m_vals) return NULL;
 2734    i_val = constcast(yyjson_val *)i_vals;
 2735    m_val = m_vals;
 2736
 2737    for (; i_val < i_end; i_val++, m_val++) {
 2738        yyjson_type type = unsafe_yyjson_get_type(i_val);
 2739        m_val->tag = i_val->tag;
 2740        m_val->uni.u64 = i_val->uni.u64;
 2741        if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
 2742            const char *str = i_val->uni.str;
 2743            usize str_len = unsafe_yyjson_get_len(i_val);
 2744            m_val->uni.str = unsafe_yyjson_mut_strncpy(m_doc, str, str_len);
 2745            if (!m_val->uni.str) return NULL;
 2746        } else if (type == YYJSON_TYPE_ARR) {
 2747            usize len = unsafe_yyjson_get_len(i_val);
 2748            if (len > 0) {
 2749                yyjson_val *ii_val = i_val + 1, *ii_next;
 2750                yyjson_mut_val *mm_val = m_val + 1, *mm_ctn = m_val, *mm_next;
 2751                while (len-- > 1) {
 2752                    ii_next = unsafe_yyjson_get_next(ii_val);
 2753                    mm_next = mm_val + (ii_next - ii_val);
 2754                    mm_val->next = mm_next;
 2755                    ii_val = ii_next;
 2756                    mm_val = mm_next;
 2757                }
 2758                mm_val->next = mm_ctn + 1;
 2759                mm_ctn->uni.ptr = mm_val;
 2760            }
 2761        } else if (type == YYJSON_TYPE_OBJ) {
 2762            usize len = unsafe_yyjson_get_len(i_val);
 2763            if (len > 0) {
 2764                yyjson_val *ii_key = i_val + 1, *ii_nextkey;
 2765                yyjson_mut_val *mm_key = m_val + 1, *mm_ctn = m_val;
 2766                yyjson_mut_val *mm_nextkey;
 2767                while (len-- > 1) {
 2768                    ii_nextkey = unsafe_yyjson_get_next(ii_key + 1);
 2769                    mm_nextkey = mm_key + (ii_nextkey - ii_key);
 2770                    mm_key->next = mm_key + 1;
 2771                    mm_key->next->next = mm_nextkey;
 2772                    ii_key = ii_nextkey;
 2773                    mm_key = mm_nextkey;
 2774                }
 2775                mm_key->next = mm_key + 1;
 2776                mm_key->next->next = mm_ctn + 1;
 2777                mm_ctn->uni.ptr = mm_key;
 2778            }
 2779        }
 2780    }
 2781    return m_vals;
 2782}
 2783
 2784static yyjson_mut_val *unsafe_yyjson_mut_val_mut_copy(
 2785    yyjson_mut_doc *m_doc, const yyjson_mut_val *m_vals) {
 2786    /*
 2787     The mutable object or array stores all sub-values in a circular linked
 2788     list, so we can traverse them in the same loop. The traversal starts from
 2789     the last item, continues with the first item in a list, and ends with the
 2790     second to last item, which needs to be linked to the last item to close the
 2791     circle.
 2792     */
 2793    yyjson_mut_val *m_val = unsafe_yyjson_mut_val(m_doc, 1);
 2794    if (unlikely(!m_val)) return NULL;
 2795    m_val->tag = m_vals->tag;
 2796
 2797    switch (unsafe_yyjson_get_type(m_vals)) {
 2798        case YYJSON_TYPE_OBJ:
 2799        case YYJSON_TYPE_ARR:
 2800            if (unsafe_yyjson_get_len(m_vals) > 0) {
 2801                yyjson_mut_val *last = (yyjson_mut_val *)m_vals->uni.ptr;
 2802                yyjson_mut_val *next = last->next, *prev;
 2803                prev = unsafe_yyjson_mut_val_mut_copy(m_doc, last);
 2804                if (!prev) return NULL;
 2805                m_val->uni.ptr = (void *)prev;
 2806                while (next != last) {
 2807                    prev->next = unsafe_yyjson_mut_val_mut_copy(m_doc, next);
 2808                    if (!prev->next) return NULL;
 2809                    prev = prev->next;
 2810                    next = next->next;
 2811                }
 2812                prev->next = (yyjson_mut_val *)m_val->uni.ptr;
 2813            }
 2814            break;
 2815        case YYJSON_TYPE_RAW:
 2816        case YYJSON_TYPE_STR: {
 2817            const char *str = m_vals->uni.str;
 2818            usize str_len = unsafe_yyjson_get_len(m_vals);
 2819            m_val->uni.str = unsafe_yyjson_mut_strncpy(m_doc, str, str_len);
 2820            if (!m_val->uni.str) return NULL;
 2821            break;
 2822        }
 2823        default:
 2824            m_val->uni = m_vals->uni;
 2825            break;
 2826    }
 2827    return m_val;
 2828}
 2829
 2830yyjson_mut_val *yyjson_mut_val_mut_copy(yyjson_mut_doc *doc,
 2831                                        const yyjson_mut_val *val) {
 2832    if (doc && val) return unsafe_yyjson_mut_val_mut_copy(doc, val);
 2833    return NULL;
 2834}
 2835
 2836/* Count the number of values and the total length of the strings. */
 2837static void yyjson_mut_stat(const yyjson_mut_val *val,
 2838                            usize *val_sum, usize *str_sum) {
 2839    yyjson_type type = unsafe_yyjson_get_type(val);
 2840    *val_sum += 1;
 2841    if (type == YYJSON_TYPE_ARR || type == YYJSON_TYPE_OBJ) {
 2842        yyjson_mut_val *child = (yyjson_mut_val *)val->uni.ptr;
 2843        usize len = unsafe_yyjson_get_len(val), i;
 2844        len <<= (u8)(type == YYJSON_TYPE_OBJ);
 2845        *val_sum += len;
 2846        for (i = 0; i < len; i++) {
 2847            yyjson_type stype = unsafe_yyjson_get_type(child);
 2848            if (stype == YYJSON_TYPE_STR || stype == YYJSON_TYPE_RAW) {
 2849                *str_sum += unsafe_yyjson_get_len(child) + 1;
 2850            } else if (stype == YYJSON_TYPE_ARR || stype == YYJSON_TYPE_OBJ) {
 2851                yyjson_mut_stat(child, val_sum, str_sum);
 2852                *val_sum -= 1;
 2853            }
 2854            child = child->next;
 2855        }
 2856    } else if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
 2857        *str_sum += unsafe_yyjson_get_len(val) + 1;
 2858    }
 2859}
 2860
 2861/* Copy mutable values to immutable value pool. */
 2862static usize yyjson_imut_copy(yyjson_val **val_ptr, char **buf_ptr,
 2863                              const yyjson_mut_val *mval) {
 2864    yyjson_val *val = *val_ptr;
 2865    yyjson_type type = unsafe_yyjson_get_type(mval);
 2866    if (type == YYJSON_TYPE_ARR || type == YYJSON_TYPE_OBJ) {
 2867        yyjson_mut_val *child = (yyjson_mut_val *)mval->uni.ptr;
 2868        usize len = unsafe_yyjson_get_len(mval), i;
 2869        usize val_sum = 1;
 2870        if (type == YYJSON_TYPE_OBJ) {
 2871            if (len) child = child->next->next;
 2872            len <<= 1;
 2873        } else {
 2874            if (len) child = child->next;
 2875        }
 2876        *val_ptr = val + 1;
 2877        for (i = 0; i < len; i++) {
 2878            val_sum += yyjson_imut_copy(val_ptr, buf_ptr, child);
 2879            child = child->next;
 2880        }
 2881        val->tag = mval->tag;
 2882        val->uni.ofs = val_sum * sizeof(yyjson_val);
 2883        return val_sum;
 2884    } else if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) {
 2885        char *buf = *buf_ptr;
 2886        usize len = unsafe_yyjson_get_len(mval);
 2887        memcpy((void *)buf, (const void *)mval->uni.str, len);
 2888        buf[len] = '\0';
 2889        val->tag = mval->tag;
 2890        val->uni.str = buf;
 2891        *val_ptr = val + 1;
 2892        *buf_ptr = buf + len + 1;
 2893        return 1;
 2894    } else {
 2895        val->tag = mval->tag;
 2896        val->uni = mval->uni;
 2897        *val_ptr = val + 1;
 2898        return 1;
 2899    }
 2900}
 2901
 2902yyjson_doc *yyjson_mut_doc_imut_copy(const yyjson_mut_doc *mdoc,
 2903                                     const yyjson_alc *alc) {
 2904    if (!mdoc) return NULL;
 2905    return yyjson_mut_val_imut_copy(mdoc->root, alc);
 2906}
 2907
 2908yyjson_doc *yyjson_mut_val_imut_copy(const yyjson_mut_val *mval,
 2909                                     const yyjson_alc *alc) {
 2910    usize val_num = 0, str_sum = 0, hdr_size, buf_size;
 2911    yyjson_doc *doc = NULL;
 2912    yyjson_val *val_hdr = NULL;
 2913
 2914    /* This value should be NULL here. Setting a non-null value suppresses
 2915       warning from the clang analyzer. */
 2916    char *str_hdr = (char *)(void *)&str_sum;
 2917    if (!mval) return NULL;
 2918    if (!alc) alc = &YYJSON_DEFAULT_ALC;
 2919
 2920    /* traverse the input value to get pool size */
 2921    yyjson_mut_stat(mval, &val_num, &str_sum);
 2922
 2923    /* create doc and val pool */
 2924    hdr_size = size_align_up(sizeof(yyjson_doc), sizeof(yyjson_val));
 2925    buf_size = hdr_size + val_num * sizeof(yyjson_val);
 2926    doc = (yyjson_doc *)alc->malloc(alc->ctx, buf_size);
 2927    if (!doc) return NULL;
 2928    memset(doc, 0, sizeof(yyjson_doc));
 2929    val_hdr = (yyjson_val *)(void *)((char *)(void *)doc + hdr_size);
 2930    doc->root = val_hdr;
 2931    doc->alc = *alc;
 2932
 2933    /* create str pool */
 2934    if (str_sum > 0) {
 2935        str_hdr = (char *)alc->malloc(alc->ctx, str_sum);
 2936        doc->str_pool = str_hdr;
 2937        if (!str_hdr) {
 2938            alc->free(alc->ctx, (void *)doc);
 2939            return NULL;
 2940        }
 2941    }
 2942
 2943    /* copy vals and strs */
 2944    doc->val_read = yyjson_imut_copy(&val_hdr, &str_hdr, mval);
 2945    doc->dat_read = str_sum + 1;
 2946    return doc;
 2947}
 2948
 2949static_inline bool unsafe_yyjson_num_equals(const void *lhs, const void *rhs) {
 2950    const yyjson_val_uni *luni = &((const yyjson_val *)lhs)->uni;
 2951    const yyjson_val_uni *runi = &((const yyjson_val *)rhs)->uni;
 2952    yyjson_subtype lt = unsafe_yyjson_get_subtype(lhs);
 2953    yyjson_subtype rt = unsafe_yyjson_get_subtype(rhs);
 2954    if (lt == rt) return luni->u64 == runi->u64;
 2955    if (lt == YYJSON_SUBTYPE_SINT && rt == YYJSON_SUBTYPE_UINT) {
 2956        return luni->i64 >= 0 && luni->u64 == runi->u64;
 2957    }
 2958    if (lt == YYJSON_SUBTYPE_UINT && rt == YYJSON_SUBTYPE_SINT) {
 2959        return runi->i64 >= 0 && luni->u64 == runi->u64;
 2960    }
 2961    return false;
 2962}
 2963
 2964static_inline bool unsafe_yyjson_str_equals(const void *lhs, const void *rhs) {
 2965    usize len = unsafe_yyjson_get_len(lhs);
 2966    if (len != unsafe_yyjson_get_len(rhs)) return false;
 2967    return !memcmp(unsafe_yyjson_get_str(lhs),
 2968                   unsafe_yyjson_get_str(rhs), len);
 2969}
 2970
 2971bool unsafe_yyjson_equals(const yyjson_val *lhs, const yyjson_val *rhs) {
 2972    yyjson_type type = unsafe_yyjson_get_type(lhs);
 2973    if (type != unsafe_yyjson_get_type(rhs)) return false;
 2974
 2975    switch (type) {
 2976        case YYJSON_TYPE_OBJ: {
 2977            usize len = unsafe_yyjson_get_len(lhs);
 2978            if (len != unsafe_yyjson_get_len(rhs)) return false;
 2979            if (len > 0) {
 2980                yyjson_obj_iter iter;
 2981                yyjson_obj_iter_init(rhs, &iter);
 2982                lhs = unsafe_yyjson_get_first(lhs);
 2983                while (len-- > 0) {
 2984                    rhs = yyjson_obj_iter_getn(&iter, lhs->uni.str,
 2985                                               unsafe_yyjson_get_len(lhs));
 2986                    if (!rhs) return false;
 2987                    if (!unsafe_yyjson_equals(lhs + 1, rhs)) return false;
 2988                    lhs = unsafe_yyjson_get_next(lhs + 1);
 2989                }
 2990            }
 2991            /* yyjson allows duplicate keys, so the check may be inaccurate */
 2992            return true;
 2993        }
 2994
 2995        case YYJSON_TYPE_ARR: {
 2996            usize len = unsafe_yyjson_get_len(lhs);
 2997            if (len != unsafe_yyjson_get_len(rhs)) return false;
 2998            if (len > 0) {
 2999                lhs = unsafe_yyjson_get_first(lhs);
 3000                rhs = unsafe_yyjson_get_first(rhs);
 3001                while (len-- > 0) {
 3002                    if (!unsafe_yyjson_equals(lhs, rhs)) return false;
 3003                    lhs = unsafe_yyjson_get_next(lhs);
 3004                    rhs = unsafe_yyjson_get_next(rhs);
 3005                }
 3006            }
 3007            return true;
 3008        }
 3009
 3010        case YYJSON_TYPE_NUM:
 3011            return unsafe_yyjson_num_equals(lhs, rhs);
 3012
 3013        case YYJSON_TYPE_RAW:
 3014        case YYJSON_TYPE_STR:
 3015            return unsafe_yyjson_str_equals(lhs, rhs);
 3016
 3017        case YYJSON_TYPE_NULL:
 3018        case YYJSON_TYPE_BOOL:
 3019            return lhs->tag == rhs->tag;
 3020
 3021        default:
 3022            return false;
 3023    }
 3024}
 3025
 3026bool unsafe_yyjson_mut_equals(const yyjson_mut_val *lhs,
 3027                              const yyjson_mut_val *rhs) {
 3028    yyjson_type type = unsafe_yyjson_get_type(lhs);
 3029    if (type != unsafe_yyjson_get_type(rhs)) return false;
 3030
 3031    switch (type) {
 3032        case YYJSON_TYPE_OBJ: {
 3033            usize len = unsafe_yyjson_get_len(lhs);
 3034            if (len != unsafe_yyjson_get_len(rhs)) return false;
 3035            if (len > 0) {
 3036                yyjson_mut_obj_iter iter;
 3037                yyjson_mut_obj_iter_init(constcast(yyjson_mut_val *)rhs, &iter);
 3038                lhs = (yyjson_mut_val *)lhs->uni.ptr;
 3039                while (len-- > 0) {
 3040                    rhs = yyjson_mut_obj_iter_getn(&iter, lhs->uni.str,
 3041                                                   unsafe_yyjson_get_len(lhs));
 3042                    if (!rhs) return false;
 3043                    if (!unsafe_yyjson_mut_equals(lhs->next, rhs)) return false;
 3044                    lhs = lhs->next->next;
 3045                }
 3046            }
 3047            /* yyjson allows duplicate keys, so the check may be inaccurate */
 3048            return true;
 3049        }
 3050
 3051        case YYJSON_TYPE_ARR: {
 3052            usize len = unsafe_yyjson_get_len(lhs);
 3053            if (len != unsafe_yyjson_get_len(rhs)) return false;
 3054            if (len > 0) {
 3055                lhs = (yyjson_mut_val *)lhs->uni.ptr;
 3056                rhs = (yyjson_mut_val *)rhs->uni.ptr;
 3057                while (len-- > 0) {
 3058                    if (!unsafe_yyjson_mut_equals(lhs, rhs)) return false;
 3059                    lhs = lhs->next;
 3060                    rhs = rhs->next;
 3061                }
 3062            }
 3063            return true;
 3064        }
 3065
 3066        case YYJSON_TYPE_NUM:
 3067            return unsafe_yyjson_num_equals(lhs, rhs);
 3068
 3069        case YYJSON_TYPE_RAW:
 3070        case YYJSON_TYPE_STR:
 3071            return unsafe_yyjson_str_equals(lhs, rhs);
 3072
 3073        case YYJSON_TYPE_NULL:
 3074        case YYJSON_TYPE_BOOL:
 3075            return lhs->tag == rhs->tag;
 3076
 3077        default:
 3078            return false;
 3079    }
 3080}
 3081
 3082bool yyjson_locate_pos(const char *str, size_t len, size_t pos,
 3083                       size_t *line, size_t *col, size_t *chr) {
 3084    usize line_sum = 0, line_pos = 0, chr_sum = 0;
 3085    const u8 *cur = (const u8 *)str;
 3086    const u8 *end = cur + pos;
 3087
 3088    if (!str || pos > len) {
 3089        if (line) *line = 0;
 3090        if (col) *col = 0;
 3091        if (chr) *chr = 0;
 3092        return false;
 3093    }
 3094
 3095    if (pos >= 3 && is_utf8_bom(cur)) cur += 3; /* don't count BOM */
 3096    while (cur < end) {
 3097        u8 c = *cur;
 3098        chr_sum += 1;
 3099        if (likely(c < 0x80)) {         /* 0xxxxxxx (0x00-0x7F) ASCII */
 3100            if (c == '\n') {
 3101                line_sum += 1;
 3102                line_pos = chr_sum;
 3103            }
 3104            cur += 1;
 3105        }
 3106        else if (c < 0xC0) cur += 1;    /* 10xxxxxx (0x80-0xBF) Invalid */
 3107        else if (c < 0xE0) cur += 2;    /* 110xxxxx (0xC0-0xDF) 2-byte UTF-8 */
 3108        else if (c < 0xF0) cur += 3;    /* 1110xxxx (0xE0-0xEF) 3-byte UTF-8 */
 3109        else if (c < 0xF8) cur += 4;    /* 11110xxx (0xF0-0xF7) 4-byte UTF-8 */
 3110        else               cur += 1;    /* 11111xxx (0xF8-0xFF) Invalid */
 3111    }
 3112    if (line) *line = line_sum + 1;
 3113    if (col) *col = chr_sum - line_pos + 1;
 3114    if (chr) *chr = chr_sum;
 3115    return true;
 3116}
 3117
 3118
 3119
 3120#if !YYJSON_DISABLE_READER /* reader begin */
 3121
 3122/* Check read flag, avoids `always false` warning when disabled. */
 3123#define has_flg(_flg) unlikely(has_rflag(flg, YYJSON_READ_##_flg, 0))
 3124#define has_allow(_flg) unlikely(has_rflag(flg, YYJSON_READ_ALLOW_##_flg, 1))
 3125#define YYJSON_READ_ALLOW_TRIVIA (YYJSON_READ_ALLOW_COMMENTS | \
 3126                                  YYJSON_READ_ALLOW_EXT_WHITESPACE)
 3127static_inline bool has_rflag(yyjson_read_flag flg, yyjson_read_flag chk,
 3128                             bool non_standard) {
 3129#if YYJSON_DISABLE_NON_STANDARD
 3130    if (non_standard) return false;
 3131#endif
 3132    return (flg & chk) != 0;
 3133}
 3134
 3135
 3136
 3137/*==============================================================================
 3138 * MARK: - JSON Reader Utils (Private)
 3139 * These functions are used by JSON reader to read literals and comments.
 3140 *============================================================================*/
 3141
 3142/** Read `true` literal, `*ptr[0]` should be `t`. */
 3143static_inline bool read_true(u8 **ptr, yyjson_val *val) {
 3144    u8 *cur = *ptr;
 3145    if (likely(byte_match_4(cur, "true"))) {
 3146        val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_TRUE;
 3147        *ptr = cur + 4;
 3148        return true;
 3149    }
 3150    return false;
 3151}
 3152
 3153/** Read `false` literal, `*ptr[0]` should be `f`. */
 3154static_inline bool read_false(u8 **ptr, yyjson_val *val) {
 3155    u8 *cur = *ptr;
 3156    if (likely(byte_match_4(cur + 1, "alse"))) {
 3157        val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_FALSE;
 3158        *ptr = cur + 5;
 3159        return true;
 3160    }
 3161    return false;
 3162}
 3163
 3164/** Read `null` literal, `*ptr[0]` should be `n`. */
 3165static_inline bool read_null(u8 **ptr, yyjson_val *val) {
 3166    u8 *cur = *ptr;
 3167    if (likely(byte_match_4(cur, "null"))) {
 3168        val->tag = YYJSON_TYPE_NULL;
 3169        *ptr = cur + 4;
 3170        return true;
 3171    }
 3172    return false;
 3173}
 3174
 3175/** Read `Inf` or `Infinity` literal (ignoring case). */
 3176static_inline bool read_inf(u8 **ptr, u8 **pre,
 3177                            yyjson_read_flag flg, yyjson_val *val) {
 3178    u8 *hdr = *ptr;
 3179    u8 *cur = *ptr;
 3180    u8 **end = ptr;
 3181    bool sign = (*cur == '-');
 3182    if (*cur == '+' && !has_allow(EXT_NUMBER)) return false;
 3183    cur += char_is_sign(*cur);
 3184    if (char_to_lower(cur[0]) == 'i' &&
 3185        char_to_lower(cur[1]) == 'n' &&
 3186        char_to_lower(cur[2]) == 'f') {
 3187        if (char_to_lower(cur[3]) == 'i') {
 3188            if (char_to_lower(cur[4]) == 'n' &&
 3189                char_to_lower(cur[5]) == 'i' &&
 3190                char_to_lower(cur[6]) == 't' &&
 3191                char_to_lower(cur[7]) == 'y') {
 3192                cur += 8;
 3193            } else {
 3194                return false;
 3195            }
 3196        } else {
 3197            cur += 3;
 3198        }
 3199        *end = cur;
 3200        if (has_flg(NUMBER_AS_RAW)) {
 3201            **pre = '\0'; /* add null-terminator for previous raw string */
 3202            *pre = cur; /* save end position for current raw string */
 3203            val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
 3204            val->uni.str = (const char *)hdr;
 3205        } else {
 3206            val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
 3207            val->uni.u64 = f64_bits_inf(sign);
 3208        }
 3209        return true;
 3210    }
 3211    return false;
 3212}
 3213
 3214/** Read `NaN` literal (ignoring case). */
 3215static_inline bool read_nan(u8 **ptr, u8 **pre,
 3216                            yyjson_read_flag flg, yyjson_val *val) {
 3217    u8 *hdr = *ptr;
 3218    u8 *cur = *ptr;
 3219    u8 **end = ptr;
 3220    bool sign = (*cur == '-');
 3221    if (*cur == '+' && !has_allow(EXT_NUMBER)) return false;
 3222    cur += char_is_sign(*cur);
 3223    if (char_to_lower(cur[0]) == 'n' &&
 3224        char_to_lower(cur[1]) == 'a' &&
 3225        char_to_lower(cur[2]) == 'n') {
 3226        cur += 3;
 3227        *end = cur;
 3228        if (has_flg(NUMBER_AS_RAW)) {
 3229            **pre = '\0'; /* add null-terminator for previous raw string */
 3230            *pre = cur; /* save end position for current raw string */
 3231            val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
 3232            val->uni.str = (const char *)hdr;
 3233        } else {
 3234            val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
 3235            val->uni.u64 = f64_bits_nan(sign);
 3236        }
 3237        return true;
 3238    }
 3239    return false;
 3240}
 3241
 3242/** Read `Inf`, `Infinity` or `NaN` literal (ignoring case). */
 3243static_inline bool read_inf_or_nan(u8 **ptr, u8 **pre,
 3244                                   yyjson_read_flag flg, yyjson_val *val) {
 3245    if (read_inf(ptr, pre, flg, val)) return true;
 3246    if (read_nan(ptr, pre, flg, val)) return true;
 3247    return false;
 3248}
 3249
 3250/** Read a JSON number as raw string. */
 3251static_noinline bool read_num_raw(u8 **ptr, u8 **pre, yyjson_read_flag flg,
 3252                                  yyjson_val *val, const char **msg) {
 3253#define return_err(_pos, _msg) do { \
 3254    *msg = _msg; *end = _pos; return false; \
 3255} while (false)
 3256
 3257#define return_raw() do { \
 3258    val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
 3259    val->uni.str = (const char *)hdr; \
 3260    **pre = '\0'; *pre = cur; *end = cur; return true; \
 3261} while (false)
 3262
 3263    u8 *hdr = *ptr;
 3264    u8 *cur = *ptr;
 3265    u8 **end = ptr;
 3266
 3267    /* skip sign */
 3268    cur += (*cur == '-');
 3269
 3270    /* read first digit, check leading zero */
 3271    while (unlikely(!char_is_digit(*cur))) {
 3272        if (has_allow(EXT_NUMBER)) {
 3273            if (*cur == '+' && cur == hdr) { /* leading `+` sign */
 3274                cur++;
 3275                continue;
 3276            }
 3277            if (*cur == '.' && char_is_digit(cur[1])) { /* e.g. '.123' */
 3278                goto read_double;
 3279            }
 3280        }
 3281        if (has_allow(INF_AND_NAN)) {
 3282            if (read_inf_or_nan(ptr, pre, flg, val)) return true;
 3283        }
 3284        return_err(cur, "no digit after sign");
 3285    }
 3286
 3287    /* read integral part */
 3288    if (*cur == '0') {
 3289        cur++;
 3290        if (unlikely(char_is_digit(*cur))) {
 3291            return_err(cur - 1, "number with leading zero is not allowed");
 3292        }
 3293        if (!char_is_fp(*cur)) {
 3294            if (has_allow(EXT_NUMBER) && char_to_lower(*cur) == 'x') { /* hex */
 3295                if (!char_is_hex(*++cur)) return_err(cur, "invalid hex number");
 3296                while(char_is_hex(*cur)) cur++;
 3297            }
 3298            return_raw();
 3299        }
 3300    } else {
 3301        while (char_is_digit(*cur)) cur++;
 3302        if (!char_is_fp(*cur)) return_raw();
 3303    }
 3304
 3305read_double:
 3306    /* read fraction part */
 3307    if (*cur == '.') {
 3308        cur++;
 3309        if (!char_is_digit(*cur)) {
 3310            if (has_allow(EXT_NUMBER)) {
 3311                if (!char_is_exp(*cur)) return_raw();
 3312            } else {
 3313                return_err(cur, "no digit after decimal point");
 3314            }
 3315        }
 3316        while (char_is_digit(*cur)) cur++;
 3317    }
 3318
 3319    /* read exponent part */
 3320    if (char_is_exp(*cur)) {
 3321        cur += 1 + char_is_sign(cur[1]);
 3322        if (!char_is_digit(*cur++)) {
 3323            return_err(cur, "no digit after exponent sign");
 3324        }
 3325        while (char_is_digit(*cur)) cur++;
 3326    }
 3327
 3328    return_raw();
 3329
 3330#undef return_err
 3331#undef return_raw
 3332}
 3333
 3334/** Read a hex number. */
 3335static_noinline bool read_num_hex(u8 **ptr, u8 **pre, yyjson_read_flag flg,
 3336                                  yyjson_val *val, const char **msg) {
 3337    u8 *hdr = *ptr;
 3338    u8 *cur = *ptr;
 3339    u8 **end = ptr;
 3340    u64 sig = 0, i = 0;
 3341    bool sign;
 3342
 3343    /* skip sign and '0x' */
 3344    sign = (*cur == '-');
 3345    cur += (*cur == '-' || *cur == '+') + 2;
 3346
 3347    /* read hex */
 3348    for(; i < 16; i++) {
 3349        u8 c = hex_conv_table[cur[i]];
 3350        if (c == 0xF0) break;
 3351        sig <<= 4;
 3352        sig |= c;
 3353    }
 3354
 3355    /* check error */
 3356    if (unlikely(i == 0)) {
 3357        *msg = "invalid hex number";
 3358        return false;
 3359    }
 3360
 3361    /* check overflow */
 3362    if (unlikely(i == 16)) {
 3363        if (char_is_hex(cur[16]) || (sign && sig > ((u64)1 << 63))) {
 3364            if (!has_flg(BIGNUM_AS_RAW)) {
 3365                *msg = "hex number overflow";
 3366                return false;
 3367            }
 3368            cur += 16;
 3369            while (char_is_hex(*cur)) cur++;
 3370            **pre = '\0';
 3371            val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW;
 3372            val->uni.str = (const char *)hdr;
 3373            *pre = cur; *end = cur;
 3374            return true;
 3375        }
 3376    }
 3377
 3378    val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3);
 3379    val->uni.u64 = (u64)(sign ? (u64)(~(sig) + 1) : (u64)(sig));
 3380    *end = cur + i;
 3381    return true;
 3382}
 3383
 3384/**
 3385 Skip trivia (whitespace and comments).
 3386 This function should be used only when `char_is_trivia()` returns true.
 3387 @param ptr  (inout) Input current position, output end position.
 3388 @param eof  JSON end position.
 3389 @param flg  JSON read flags.
 3390 @return true  if at least one character was skipped.
 3391         false if no characters were skipped,
 3392               or if a multi-line comment is unterminated;
 3393               in the latter case, `ptr` will be set to `eof`.
 3394 */
 3395static_noinline bool skip_trivia(u8 **ptr, u8 *eof, yyjson_read_flag flg) {
 3396    u8 *hdr = *ptr, *cur = *ptr;
 3397    usize len;
 3398
 3399    while (cur < eof) {
 3400        u8 *loop_begin = cur;
 3401
 3402        /* skip standard whitespace */
 3403        while(char_is_space(*cur)) cur++;
 3404
 3405        /* skip extended whitespace */
 3406        if (has_allow(EXT_WHITESPACE)) {
 3407            while (char_is_space_ext(*cur)) {
 3408                cur += (len = ext_space_len(cur));
 3409                if (!len) break;
 3410            }
 3411        }
 3412
 3413        /* skip comment, do not validate encoding */
 3414        if (has_allow(COMMENTS) && cur[0] == '/') {
 3415            if (cur[1] == '/') { /* single-line comment */
 3416                cur += 2;
 3417                if (has_allow(EXT_WHITESPACE)) {
 3418                    while (cur < eof) {
 3419                        if (char_is_eol_ext(*cur)) {
 3420                            cur += (len = ext_eol_len(cur));
 3421                            if (len) break;
 3422                        }
 3423                        cur++;
 3424                    }
 3425                } else {
 3426                    while (cur < eof && !char_is_eol(*cur)) cur++;
 3427                }
 3428            } else if (cur[1] == '*') { /* multi-line comment */
 3429                cur += 2;
 3430                while (!byte_match_2(cur, "*/") && cur < eof) cur++;
 3431                if (cur == eof) {
 3432                    *ptr = eof;
 3433                    return false; /* unclosed comment */
 3434                }
 3435                cur += 2;
 3436            }
 3437        }
 3438        if (cur == loop_begin) break;
 3439    }
 3440    *ptr = cur;
 3441    return cur > hdr;
 3442}
 3443
 3444/**
 3445 Check truncated UTF-8 character.
 3446 Return true if `cur` starts a valid UTF-8 sequence that is truncated.
 3447 */
 3448static bool is_truncated_utf8(u8 *cur, u8 *eof) {
 3449    u8 c0, c1, c2;
 3450    usize len = (usize)(eof - cur);
 3451    if (cur >= eof || len >= 4) return false;
 3452    c0 = cur[0]; c1 = cur[1]; c2 = cur[2];
 3453    /* 1-byte UTF-8, not truncated */
 3454    if (c0 < 0x80) return false;
 3455    if (len == 1) {
 3456        /* 2-byte UTF-8, truncated */
 3457        if ((c0 & 0xE0) == 0xC0 && (c0 & 0x1E) != 0x00) return true;
 3458        /* 3-byte UTF-8, truncated */
 3459        if ((c0 & 0xF0) == 0xE0) return true;
 3460        /* 4-byte UTF-8, truncated */
 3461        if ((c0 & 0xF8) == 0xF0 && (c0 & 0x07) <= 0x04) return true;
 3462    } else if (len == 2) {
 3463        /* 3-byte UTF-8, truncated */
 3464        if ((c0 & 0xF0) == 0xE0 && (c1 & 0xC0) == 0x80) {
 3465            u8 t = (u8)(((c0 & 0x0F) << 1) | ((c1 & 0x20) >> 5));
 3466            return 0x01 <= t && t != 0x1B;
 3467        }
 3468        /* 4-byte UTF-8, truncated */
 3469        if ((c0 & 0xF8) == 0xF0 && (c1 & 0xC0) == 0x80) {
 3470            u8 t = (u8)(((c0 & 0x07) << 2) | ((c1 & 0x30) >> 4));
 3471            return 0x01 <= t && t <= 0x10;
 3472        }
 3473    } else if (len == 3) {
 3474        /* 4 bytes UTF-8, truncated */
 3475        if ((c0 & 0xF8) == 0xF0 && (c1 & 0xC0) == 0x80 && (c2 & 0xC0) == 0x80) {
 3476            u8 t = (u8)(((c0 & 0x07) << 2) | ((c1 & 0x30) >> 4));
 3477            return 0x01 <= t && t <= 0x10;
 3478        }
 3479    }
 3480    return false;
 3481}
 3482
 3483/**
 3484 Check truncated string.
 3485 Returns true if `cur` match `str` but is truncated.
 3486 The `str` should be lowercase ASCII letters.
 3487 */
 3488static bool is_truncated_str(u8 *cur, u8 *eof, const char *str,
 3489                             bool case_sensitive) {
 3490    usize len = strlen(str);
 3491    if (cur + len <= eof || eof <= cur) return false;
 3492    if (case_sensitive) {
 3493        return memcmp(cur, str, (usize)(eof - cur)) == 0;
 3494    }
 3495    for (; cur < eof; cur++, str++) {
 3496        if (char_to_lower(*cur) != *(const u8 *)str) return false;
 3497    }
 3498    return true;
 3499}
 3500
 3501/**
 3502 Check truncated JSON on parsing errors.
 3503 Returns true if the input is valid but truncated.
 3504 */
 3505static_noinline bool is_truncated_end(u8 *hdr, u8 *cur, u8 *eof,
 3506                                      yyjson_read_code code,
 3507                                      yyjson_read_flag flg) {
 3508    if (cur >= eof) return true;
 3509    if (code == YYJSON_READ_ERROR_LITERAL) {
 3510        if (is_truncated_str(cur, eof, "true", true) ||
 3511            is_truncated_str(cur, eof, "false", true) ||
 3512            is_truncated_str(cur, eof, "null", true)) {
 3513            return true;
 3514        }
 3515    }
 3516    if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER ||
 3517        code == YYJSON_READ_ERROR_INVALID_NUMBER ||
 3518        code == YYJSON_READ_ERROR_LITERAL) {
 3519        if (has_allow(INF_AND_NAN)) {
 3520            if (*cur == '-') cur++;
 3521            if (is_truncated_str(cur, eof, "infinity", false) ||
 3522                is_truncated_str(cur, eof, "nan", false)) {
 3523                return true;
 3524            }
 3525        }
 3526    }
 3527    if (code == YYJSON_READ_ERROR_UNEXPECTED_CONTENT) {
 3528        if (has_allow(INF_AND_NAN)) {
 3529            if (hdr + 3 <= cur &&
 3530                is_truncated_str(cur - 3, eof, "infinity", false)) {
 3531                return true; /* e.g. infin would be read as inf + in */
 3532            }
 3533        }
 3534    }
 3535    if (code == YYJSON_READ_ERROR_INVALID_STRING) {
 3536        usize len = (usize)(eof - cur);
 3537
 3538        /* unicode escape sequence */
 3539        if (*cur == '\\') {
 3540            if (len == 1) return true;
 3541            if (len <= 5) {
 3542                if (*++cur != 'u') return false;
 3543                for (++cur; cur < eof; cur++) {
 3544                    if (!char_is_hex(*cur)) return false;
 3545                }
 3546                return true;
 3547            } else if (len <= 11) {
 3548                /* incomplete surrogate pair? */
 3549                u16 hi;
 3550                if (*++cur != 'u') return false;
 3551                if (!hex_load_4(++cur, &hi)) return false;
 3552                if ((hi & 0xF800) != 0xD800) return false;
 3553                cur += 4;
 3554                if (cur >= eof) return true;
 3555                /* valid low surrogate is DC00...DFFF */
 3556                if (*cur != '\\') return false;
 3557                if (++cur >= eof) return true;
 3558                if (*cur != 'u') return false;
 3559                if (++cur >= eof) return true;
 3560                if (*cur != 'd' && *cur != 'D') return false;
 3561                if (++cur >= eof) return true;
 3562                if ((*cur < 'c' || *cur > 'f') && (*cur < 'C' || *cur > 'F'))
 3563                    return false;
 3564                if (++cur >= eof) return true;
 3565                if (!char_is_hex(*cur)) return false;
 3566                return true;
 3567            }
 3568            return false;
 3569        }
 3570
 3571        /* 2 to 4 bytes UTF-8 */
 3572        if (is_truncated_utf8(cur, eof)) {
 3573            return true;
 3574        }
 3575    }
 3576    if (has_allow(COMMENTS)) {
 3577        if (code == YYJSON_READ_ERROR_INVALID_COMMENT) {
 3578            /* unclosed multiline comment */
 3579            return true;
 3580        }
 3581        if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER &&
 3582            *cur == '/' && cur + 1 == eof) {
 3583            /* truncated beginning of comment */
 3584            return true;
 3585        }
 3586    }
 3587    if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER &&
 3588        has_allow(BOM)) {
 3589        /* truncated UTF-8 BOM */
 3590        usize len = (usize)(eof - cur);
 3591        if (cur == hdr && len < 3 && !memcmp(hdr, "\xEF\xBB\xBF", len)) {
 3592            return true;
 3593        }
 3594    }
 3595    return false;
 3596}
 3597
 3598
 3599
 3600#if !YYJSON_DISABLE_FAST_FP_CONV /* FP_READER */
 3601
 3602/*==============================================================================
 3603 * MARK: - BigInt For Floating Point Number Reader (Private)
 3604 *
 3605 * The bigint algorithm is used by floating-point number reader to get correctly
 3606 * rounded result for numbers with lots of digits. This part of code is rarely
 3607 * used for common numbers.
 3608 *============================================================================*/
 3609
 3610/** Unsigned arbitrarily large integer */
 3611typedef struct bigint {
 3612    u32 used; /* used chunks count, should not be 0 */
 3613    u64 bits[64]; /* chunks (58 is enough here) */
 3614} bigint;
 3615
 3616/**
 3617 Evaluate 'big += val'.
 3618 @param big A big number (can be 0).
 3619 @param val An unsigned integer (can be 0).
 3620 */
 3621static_inline void bigint_add_u64(bigint *big, u64 val) {
 3622    u32 idx, max;
 3623    u64 num = big->bits[0];
 3624    u64 add = num + val;
 3625    big->bits[0] = add;
 3626    if (likely((add >= num) || (add >= val))) return;
 3627    for ((void)(idx = 1), max = big->used; idx < max; idx++) {
 3628        if (likely(big->bits[idx] != U64_MAX)) {
 3629            big->bits[idx] += 1;
 3630            return;
 3631        }
 3632        big->bits[idx] = 0;
 3633    }
 3634    big->bits[big->used++] = 1;
 3635}
 3636
 3637/**
 3638 Evaluate 'big *= val'.
 3639 @param big A big number (can be 0).
 3640 @param val An unsigned integer (cannot be 0).
 3641 */
 3642static_inline void bigint_mul_u64(bigint *big, u64 val) {
 3643    u32 idx = 0, max = big->used;
 3644    u64 hi, lo, carry = 0;
 3645    for (; idx < max; idx++) {
 3646        if (big->bits[idx]) break;
 3647    }
 3648    for (; idx < max; idx++) {
 3649        u128_mul_add(big->bits[idx], val, carry, &hi, &lo);
 3650        big->bits[idx] = lo;
 3651        carry = hi;
 3652    }
 3653    if (carry) big->bits[big->used++] = carry;
 3654}
 3655
 3656/**
 3657 Evaluate 'big *= 2^exp'.
 3658 @param big A big number (can be 0).
 3659 @param exp An exponent integer (can be 0).
 3660 */
 3661static_inline void bigint_mul_pow2(bigint *big, u32 exp) {
 3662    u32 shft = exp % 64;
 3663    u32 move = exp / 64;
 3664    u32 idx = big->used;
 3665    if (unlikely(shft == 0)) {
 3666        for (; idx > 0; idx--) {
 3667            big->bits[idx + move - 1] = big->bits[idx - 1];
 3668        }
 3669        big->used += move;
 3670        while (move) big->bits[--move] = 0;
 3671    } else {
 3672        big->bits[idx] = 0;
 3673        for (; idx > 0; idx--) {
 3674            u64 num = big->bits[idx] << shft;
 3675            num |= big->bits[idx - 1] >> (64 - shft);
 3676            big->bits[idx + move] = num;
 3677        }
 3678        big->bits[move] = big->bits[0] << shft;
 3679        big->used += move + (big->bits[big->used + move] > 0);
 3680        while (move) big->bits[--move] = 0;
 3681    }
 3682}
 3683
 3684/**
 3685 Evaluate 'big *= 10^exp'.
 3686 @param big A big number (can be 0).
 3687 @param exp An exponent integer (cannot be 0).
 3688 */
 3689static_inline void bigint_mul_pow10(bigint *big, i32 exp) {
 3690    for (; exp >= U64_POW10_MAX_EXACT_EXP; exp -= U64_POW10_MAX_EXACT_EXP) {
 3691        bigint_mul_u64(big, u64_pow10_table[U64_POW10_MAX_EXACT_EXP]);
 3692    }
 3693    if (exp) {
 3694        bigint_mul_u64(big, u64_pow10_table[exp]);
 3695    }
 3696}
 3697
 3698/**
 3699 Compare two bigint.
 3700 @return -1 if 'a < b', +1 if 'a > b', 0 if 'a == b'.
 3701 */
 3702static_inline i32 bigint_cmp(bigint *a, bigint *b) {
 3703    u32 idx = a->used;
 3704    if (a->used < b->used) return -1;
 3705    if (a->used > b->used) return +1;
 3706    while (idx-- > 0) {
 3707        u64 av = a->bits[idx];
 3708        u64 bv = b->bits[idx];
 3709        if (av < bv) return -1;
 3710        if (av > bv) return +1;
 3711    }
 3712    return 0;
 3713}
 3714
 3715/**
 3716 Evaluate 'big = val'.
 3717 @param big A big number (can be 0).
 3718 @param val An unsigned integer (can be 0).
 3719 */
 3720static_inline void bigint_set_u64(bigint *big, u64 val) {
 3721    big->used = 1;
 3722    big->bits[0] = val;
 3723}
 3724
 3725/** Set a bigint with floating point number string. */
 3726static_noinline void bigint_set_buf(bigint *big, u64 sig, i32 *exp,
 3727                                    u8 *sig_cut, u8 *sig_end, u8 *dot_pos) {
 3728
 3729    if (unlikely(!sig_cut)) {
 3730        /* no digit cut, set significant part only */
 3731        bigint_set_u64(big, sig);
 3732        return;
 3733
 3734    } else {
 3735        /* some digits were cut, read them from 'sig_cut' to 'sig_end' */
 3736        u8 *hdr = sig_cut;
 3737        u8 *cur = hdr;
 3738        u32 len = 0;
 3739        u64 val = 0;
 3740        bool dig_big_cut = false;
 3741        bool has_dot = (hdr < dot_pos) & (dot_pos < sig_end);
 3742        usize dig_len_total = U64_SAFE_DIG + (usize)(sig_end - hdr) - has_dot;
 3743
 3744        sig -= (*sig_cut >= '5'); /* sig was rounded before */
 3745        if (dig_len_total > F64_MAX_DEC_DIG) {
 3746            dig_big_cut = true;
 3747            sig_end -= dig_len_total - (F64_MAX_DEC_DIG + 1);
 3748            sig_end -= (dot_pos + 1 == sig_end);
 3749            dig_len_total = (F64_MAX_DEC_DIG + 1);
 3750        }
 3751        *exp -= (i32)dig_len_total - U64_SAFE_DIG;
 3752
 3753        big->used = 1;
 3754        big->bits[0] = sig;
 3755        while (cur < sig_end) {
 3756            if (likely(cur != dot_pos)) {
 3757                val = val * 10 + (u8)(*cur++ - '0');
 3758                len++;
 3759                if (unlikely(cur == sig_end && dig_big_cut)) {
 3760                    /* The last digit must be non-zero,    */
 3761                    /* set it to '1' for correct rounding. */
 3762                    val = val - (val % 10) + 1;
 3763                }
 3764                if (len == U64_SAFE_DIG || cur == sig_end) {
 3765                    bigint_mul_pow10(big, (i32)len);
 3766                    bigint_add_u64(big, val);
 3767                    val = 0;
 3768                    len = 0;
 3769                }
 3770            } else {
 3771                cur++;
 3772            }
 3773        }
 3774    }
 3775}
 3776
 3777
 3778
 3779/*==============================================================================
 3780 * MARK: - Diy Floating Point (Private)
 3781 *============================================================================*/
 3782
 3783/** "Do It Yourself Floating Point" struct. */
 3784typedef struct diy_fp {
 3785    u64 sig; /* significand */
 3786    i32 exp; /* exponent, base 2 */
 3787    i32 pad; /* padding, useless */
 3788} diy_fp;
 3789
 3790/** Get cached rounded diy_fp for pow(10, e). The input value must be in the
 3791    range [POW10_SIG_TABLE_MIN_EXP, POW10_SIG_TABLE_MAX_EXP]. */
 3792static_inline diy_fp diy_fp_get_cached_pow10(i32 exp10) {
 3793    diy_fp fp;
 3794    u64 sig_ext;
 3795    pow10_table_get_sig(exp10, &fp.sig, &sig_ext);
 3796    pow10_table_get_exp(exp10, &fp.exp);
 3797    fp.sig += (sig_ext >> 63);
 3798    return fp;
 3799}
 3800
 3801/** Returns fp * fp2. */
 3802static_inline diy_fp diy_fp_mul(diy_fp fp, diy_fp fp2) {
 3803    u64 hi, lo;
 3804    u128_mul(fp.sig, fp2.sig, &hi, &lo);
 3805    fp.sig = hi + (lo >> 63);
 3806    fp.exp += fp2.exp + 64;
 3807    return fp;
 3808}
 3809
 3810/** Convert diy_fp to IEEE-754 raw value. */
 3811static_inline u64 diy_fp_to_ieee_raw(diy_fp fp) {
 3812    u64 sig = fp.sig;
 3813    i32 exp = fp.exp;
 3814    u32 lz_bits;
 3815    if (unlikely(fp.sig == 0)) return 0;
 3816
 3817    lz_bits = u64_lz_bits(sig);
 3818    sig <<= lz_bits;
 3819    sig >>= F64_BITS - F64_SIG_FULL_BITS;
 3820    exp -= (i32)lz_bits;
 3821    exp += F64_BITS - F64_SIG_FULL_BITS;
 3822    exp += F64_SIG_BITS;
 3823
 3824    if (unlikely(exp >= F64_MAX_BIN_EXP)) {
 3825        /* overflow */
 3826        return F64_BITS_INF;
 3827    } else if (likely(exp >= F64_MIN_BIN_EXP - 1)) {
 3828        /* normal */
 3829        exp += F64_EXP_BIAS;
 3830        return ((u64)exp << F64_SIG_BITS) | (sig & F64_SIG_MASK);
 3831    } else if (likely(exp >= F64_MIN_BIN_EXP - F64_SIG_FULL_BITS)) {
 3832        /* subnormal */
 3833        return sig >> (F64_MIN_BIN_EXP - exp - 1);
 3834    } else {
 3835        /* underflow */
 3836        return 0;
 3837    }
 3838}
 3839
 3840
 3841
 3842/*==============================================================================
 3843 * MARK: - Number Reader (Private)
 3844 *============================================================================*/
 3845
 3846/**
 3847 Read a JSON number.
 3848
 3849 1. This function assume that the floating-point number is in IEEE-754 format.
 3850 2. This function support uint64/int64/double number. If an integer number
 3851    cannot fit in uint64/int64, it will returns as a double number. If a double
 3852    number is infinite, the return value is based on flag.
 3853 3. This function (with inline attribute) may generate a lot of instructions.
 3854 */
 3855static_inline bool read_num(u8 **ptr, u8 **pre, yyjson_read_flag flg,
 3856                            yyjson_val *val, const char **msg) {
 3857#define return_err(_pos, _msg) do { \
 3858    *msg = _msg; \
 3859    *end = _pos; \
 3860    return false; \
 3861} while (false)
 3862
 3863#define return_0() do { \
 3864    val->tag = YYJSON_TYPE_NUM | (u8)((u8)sign << 3); \
 3865    val->uni.u64 = 0; \
 3866    *end = cur; return true; \
 3867} while (false)
 3868
 3869#define return_i64(_v) do { \
 3870    val->tag = YYJSON_TYPE_NUM | (u8)((u8)sign << 3); \
 3871    val->uni.u64 = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \
 3872    *end = cur; return true; \
 3873} while (false)
 3874
 3875#define return_f64(_v) do { \
 3876    val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
 3877    val->uni.f64 = sign ? -(f64)(_v) : (f64)(_v); \
 3878    *end = cur; return true; \
 3879} while (false)
 3880
 3881#define return_f64_bin(_v) do { \
 3882    val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
 3883    val->uni.u64 = ((u64)sign << 63) | (u64)(_v); \
 3884    *end = cur; return true; \
 3885} while (false)
 3886
 3887#define return_inf() do { \
 3888    if (has_flg(BIGNUM_AS_RAW)) return_raw(); \
 3889    if (has_allow(INF_AND_NAN)) return_f64_bin(F64_BITS_INF); \
 3890    else return_err(hdr, "number is infinity when parsed as double"); \
 3891} while (false)
 3892
 3893#define return_raw() do { \
 3894    **pre = '\0'; /* add null-terminator for previous raw string */ \
 3895    val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
 3896    val->uni.str = (const char *)hdr; \
 3897    *pre = cur; *end = cur; return true; \
 3898} while (false)
 3899
 3900    u8 *sig_cut = NULL; /* significant part cutting position for long number */
 3901    u8 *sig_end = NULL; /* significant part ending position */
 3902    u8 *dot_pos = NULL; /* decimal point position */
 3903
 3904    u64 sig = 0; /* significant part of the number */
 3905    i32 exp = 0; /* exponent part of the number */
 3906
 3907    bool exp_sign; /* temporary exponent sign from literal part */
 3908    i64 exp_sig = 0; /* temporary exponent number from significant part */
 3909    i64 exp_lit = 0; /* temporary exponent number from exponent literal part */
 3910    u64 num; /* temporary number for reading */
 3911    u8 *tmp; /* temporary cursor for reading */
 3912
 3913    u8 *hdr = *ptr;
 3914    u8 *cur = *ptr;
 3915    u8 **end = ptr;
 3916    bool sign;
 3917
 3918    /* read number as raw string if has `YYJSON_READ_NUMBER_AS_RAW` flag */
 3919    if (has_flg(NUMBER_AS_RAW)) {
 3920        return read_num_raw(ptr, pre, flg, val, msg);
 3921    }
 3922
 3923    sign = (*hdr == '-');
 3924    cur += sign;
 3925
 3926    /* begin with a leading zero or non-digit */
 3927    while (unlikely(!char_is_nonzero(*cur))) { /* 0 or non-digit char */
 3928        if (unlikely(*cur != '0')) { /* non-digit char */
 3929            if (has_allow(EXT_NUMBER)) {
 3930                if (*cur == '+' && cur == hdr) { /* leading `+` sign */
 3931                    cur++;
 3932                    continue;
 3933                }
 3934                if (*cur == '.' && char_is_digit(cur[1])) { /* e.g. '.123' */
 3935                    goto leading_dot;
 3936                }
 3937            }
 3938            if (has_allow(INF_AND_NAN)) {
 3939                if (read_inf_or_nan(ptr, pre, flg, val)) return true;
 3940            }
 3941            return_err(cur, "no digit after sign");
 3942        }
 3943        /* begin with 0 */
 3944        if (likely(!char_is_digit_or_fp(*++cur))) {
 3945            if (has_allow(EXT_NUMBER) && char_to_lower(*cur) == 'x') { /* hex */
 3946                return read_num_hex(ptr, pre, flg, val, msg);
 3947            }
 3948            return_0();
 3949        }
 3950        if (likely(*cur == '.')) {
 3951leading_dot:
 3952            dot_pos = cur++;
 3953            if (unlikely(!char_is_digit(*cur))) {
 3954                if (has_allow(EXT_NUMBER)) {
 3955                    if (char_is_exp(*cur)) {
 3956                        goto digi_exp_more;
 3957                    } else {
 3958                        return_f64_bin(0);
 3959                    }
 3960                }
 3961                return_err(cur, "no digit after decimal point");
 3962            }
 3963            while (unlikely(*cur == '0')) cur++;
 3964            if (likely(char_is_digit(*cur))) {
 3965                /* first non-zero digit after decimal point */
 3966                sig = (u64)(*cur - '0'); /* read first digit */
 3967                cur--;
 3968                goto digi_frac_1; /* continue read fraction part */
 3969            }
 3970        }
 3971        if (unlikely(char_is_digit(*cur))) {
 3972            return_err(cur - 1, "number with leading zero is not allowed");
 3973        }
 3974        if (unlikely(char_is_exp(*cur))) { /* 0 with any exponent is still 0 */
 3975            cur += (usize)1 + char_is_sign(cur[1]);
 3976            if (unlikely(!char_is_digit(*cur))) {
 3977                return_err(cur, "no digit after exponent sign");
 3978            }
 3979            while (char_is_digit(*++cur));
 3980        }
 3981        return_f64_bin(0);
 3982    }
 3983
 3984    /* begin with non-zero digit */
 3985    sig = (u64)(*cur - '0');
 3986
 3987    /*
 3988     Read integral part, same as the following code.
 3989
 3990         for (int i = 1; i <= 18; i++) {
 3991            num = cur[i] - '0';
 3992            if (num <= 9) sig = num + sig * 10;
 3993            else goto digi_sepr_i;
 3994         }
 3995     */
 3996#define expr_intg(i) \
 3997    if (likely((num = (u64)(cur[i] - (u8)'0')) <= 9)) sig = num + sig * 10; \
 3998    else { goto digi_sepr_##i; }
 3999    repeat_in_1_18(expr_intg)
 4000#undef expr_intg
 4001
 4002
 4003    cur += 19; /* skip continuous 19 digits */
 4004    if (!char_is_digit_or_fp(*cur)) {
 4005        /* this number is an integer consisting of 19 digits */
 4006        if (sign && (sig > ((u64)1 << 63))) { /* overflow */
 4007            if (has_flg(BIGNUM_AS_RAW)) return_raw();
 4008            return_f64(unsafe_yyjson_u64_to_f64(sig));
 4009        }
 4010        return_i64(sig);
 4011    }
 4012    goto digi_intg_more; /* read more digits in integral part */
 4013
 4014
 4015    /* process first non-digit character */
 4016#define expr_sepr(i) \
 4017    digi_sepr_##i: \
 4018    if (likely(!char_is_fp(cur[i]))) { cur += i; return_i64(sig); } \
 4019    dot_pos = cur + i; \
 4020    if (likely(cur[i] == '.')) goto digi_frac_##i; \
 4021    cur += i; sig_end = cur; goto digi_exp_more;
 4022    repeat_in_1_18(expr_sepr)
 4023#undef expr_sepr
 4024
 4025
 4026    /* read fraction part */
 4027#define expr_frac(i) \
 4028    digi_frac_##i: \
 4029    if (likely((num = (u64)(cur[i + 1] - (u8)'0')) <= 9)) \
 4030        sig = num + sig * 10; \
 4031    else { goto digi_stop_##i; }
 4032    repeat_in_1_18(expr_frac)
 4033#undef expr_frac
 4034
 4035    cur += 20; /* skip 19 digits and 1 decimal point */
 4036    if (!char_is_digit(*cur)) goto digi_frac_end; /* fraction part end */
 4037    goto digi_frac_more; /* read more digits in fraction part */
 4038
 4039
 4040    /* significant part end */
 4041#define expr_stop(i) \
 4042    digi_stop_##i: \
 4043    cur += i + 1; \
 4044    goto digi_frac_end;
 4045    repeat_in_1_18(expr_stop)
 4046#undef expr_stop
 4047
 4048
 4049    /* read more digits in integral part */
 4050digi_intg_more:
 4051    if (char_is_digit(*cur)) {
 4052        if (!char_is_digit_or_fp(cur[1])) {
 4053            /* this number is an integer consisting of 20 digits */
 4054            num = (u64)(*cur - '0');
 4055            if ((sig < (U64_MAX / 10)) ||
 4056                (sig == (U64_MAX / 10) && num <= (U64_MAX % 10))) {
 4057                sig = num + sig * 10;
 4058                cur++;
 4059                /* convert to double if overflow */
 4060                if (sign) {
 4061                    if (has_flg(BIGNUM_AS_RAW)) return_raw();
 4062                    return_f64(unsafe_yyjson_u64_to_f64(sig));
 4063                }
 4064                return_i64(sig);
 4065            }
 4066        }
 4067    }
 4068
 4069    if (char_is_exp(*cur)) {
 4070        dot_pos = cur;
 4071        goto digi_exp_more;
 4072    }
 4073
 4074    if (*cur == '.') {
 4075        dot_pos = cur++;
 4076        if (unlikely(!char_is_digit(*cur))) {
 4077            if (has_allow(EXT_NUMBER)) {
 4078                goto digi_frac_end;
 4079            }
 4080            return_err(cur, "no digit after decimal point");
 4081        }
 4082    }
 4083
 4084
 4085    /* read more digits in fraction part */
 4086digi_frac_more:
 4087    sig_cut = cur; /* too large to fit in u64, excess digits need to be cut */
 4088    sig += (*cur >= '5'); /* round */
 4089    while (char_is_digit(*++cur));
 4090    if (!dot_pos) {
 4091        if (!char_is_fp(*cur) && has_flg(BIGNUM_AS_RAW)) {
 4092            return_raw(); /* it's a large integer */
 4093        }
 4094        dot_pos = cur;
 4095        if (*cur == '.') {
 4096            if (unlikely(!char_is_digit(*++cur))) {
 4097                if (!has_allow(EXT_NUMBER)) {
 4098                    return_err(cur, "no digit after decimal point");
 4099                }
 4100            }
 4101            while (char_is_digit(*cur)) cur++;
 4102        }
 4103    }
 4104    exp_sig = (i64)(dot_pos - sig_cut);
 4105    exp_sig += (dot_pos < sig_cut);
 4106
 4107    /* ignore trailing zeros */
 4108    tmp = cur - 1;
 4109    while ((*tmp == '0' || *tmp == '.') && tmp > hdr) tmp--;
 4110    if (tmp < sig_cut) {
 4111        sig_cut = NULL;
 4112    } else {
 4113        sig_end = cur;
 4114    }
 4115
 4116    if (char_is_exp(*cur)) goto digi_exp_more;
 4117    goto digi_exp_finish;
 4118
 4119
 4120    /* fraction part end */
 4121digi_frac_end:
 4122    if (unlikely(dot_pos + 1 == cur)) {
 4123        if (!has_allow(EXT_NUMBER)) {
 4124            return_err(cur, "no digit after decimal point");
 4125        }
 4126    }
 4127    sig_end = cur;
 4128    exp_sig = -(i64)((u64)(cur - dot_pos) - 1);
 4129    if (likely(!char_is_exp(*cur))) {
 4130        if (unlikely(exp_sig < F64_MIN_DEC_EXP - 19)) {
 4131            return_f64_bin(0); /* underflow */
 4132        }
 4133        exp = (i32)exp_sig;
 4134        goto digi_finish;
 4135    } else {
 4136        goto digi_exp_more;
 4137    }
 4138
 4139
 4140    /* read exponent part */
 4141digi_exp_more:
 4142    exp_sign = (*++cur == '-');
 4143    cur += char_is_sign(*cur);
 4144    if (unlikely(!char_is_digit(*cur))) {
 4145        return_err(cur, "no digit after exponent sign");
 4146    }
 4147    while (*cur == '0') cur++;
 4148
 4149    /* read exponent literal */
 4150    tmp = cur;
 4151    while (char_is_digit(*cur)) {
 4152        exp_lit = (i64)((u8)(*cur++ - '0') + (u64)exp_lit * 10);
 4153    }
 4154    if (unlikely(cur - tmp >= U64_SAFE_DIG)) {
 4155        if (exp_sign) {
 4156            return_f64_bin(0); /* underflow */
 4157        } else {
 4158            return_inf(); /* overflow */
 4159        }
 4160    }
 4161    exp_sig += exp_sign ? -exp_lit : exp_lit;
 4162
 4163
 4164    /* validate exponent value */
 4165digi_exp_finish:
 4166    if (unlikely(exp_sig < F64_MIN_DEC_EXP - 19)) {
 4167        return_f64_bin(0); /* underflow */
 4168    }
 4169    if (unlikely(exp_sig > F64_MAX_DEC_EXP)) {
 4170        return_inf(); /* overflow */
 4171    }
 4172    exp = (i32)exp_sig;
 4173
 4174
 4175    /* all digit read finished */
 4176digi_finish:
 4177
 4178    /*
 4179     Fast path 1:
 4180
 4181     1. The floating-point number calculation should be accurate, see the
 4182        comments of macro `YYJSON_DOUBLE_MATH_CORRECT`.
 4183     2. Correct rounding should be performed (fegetround() == FE_TONEAREST).
 4184     3. The input to floating-point calculations does not lose precision,
 4185        which means: 64 - leading_zero(input) - trailing_zero(input) < 53.
 4186
 4187     We don't check all available inputs here, because that would make the code
 4188     more complicated, and not friendly to branch predictor.
 4189     */
 4190#if YYJSON_DOUBLE_MATH_CORRECT
 4191    if (sig < ((u64)1 << 53) &&
 4192        exp >= -F64_POW10_MAX_EXACT_EXP &&
 4193        exp <= +F64_POW10_MAX_EXACT_EXP) {
 4194        f64 dbl = (f64)sig;
 4195        if (exp < 0) {
 4196            dbl /= f64_pow10_table[-exp];
 4197        } else {
 4198            dbl *= f64_pow10_table[+exp];
 4199        }
 4200        return_f64(dbl);
 4201    }
 4202#endif
 4203    if (unlikely(sig == 0)) return_f64_bin(0);
 4204
 4205    /*
 4206     Fast path 2:
 4207
 4208     To keep it simple, we only accept normal number here,
 4209     let the slow path handle subnormal and infinite numbers.
 4210     */
 4211    if (likely(!sig_cut &&
 4212               exp > -F64_MAX_DEC_EXP + 1 &&
 4213               exp < +F64_MAX_DEC_EXP - 20)) {
 4214        /*
 4215         The result value is exactly equal to (sig * 10^exp),
 4216         the exponent part (10^exp) can be converted to (sig2 * 2^exp2).
 4217
 4218         The sig2 can be an infinite length number, only the highest 128 bits
 4219         is cached in the pow10_sig_table.
 4220
 4221         Now we have these bits:
 4222         sig1 (normalized 64bit)        : aaaaaaaa
 4223         sig2 (higher 64bit)            : bbbbbbbb
 4224         sig2_ext (lower 64bit)         : cccccccc
 4225         sig2_cut (extra unknown bits)  : dddddddddddd....
 4226
 4227         And the calculation process is:
 4228         ----------------------------------------
 4229                 aaaaaaaa *
 4230                 bbbbbbbbccccccccdddddddddddd....
 4231         ----------------------------------------
 4232         abababababababab +
 4233                 acacacacacacacac +
 4234                         adadadadadadadadadad....
 4235         ----------------------------------------
 4236         [hi____][lo____] +
 4237                 [hi2___][lo2___] +
 4238                         [unknown___________....]
 4239         ----------------------------------------
 4240
 4241         The addition with carry may affect higher bits, but if there is a 0
 4242         in higher bits, the bits higher than 0 will not be affected.
 4243
 4244         `lo2` + `unknown` may get a carry bit and may affect `hi2`, the max
 4245         value of `hi2` is 0xFFFFFFFFFFFFFFFE, so `hi2` will not overflow.
 4246
 4247         `lo` + `hi2` may also get a carry bit and may affect `hi`, but only
 4248         the highest significant 53 bits of `hi` is needed. If there is a 0
 4249         in the lower bits of `hi`, then all the following bits can be dropped.
 4250
 4251         To convert the result to IEEE-754 double number, we need to perform
 4252         correct rounding:
 4253         1. if bit 54 is 0, round down,
 4254         2. if bit 54 is 1 and any bit beyond bit 54 is 1, round up,
 4255         3. if bit 54 is 1 and all bits beyond bit 54 are 0, round to even,
 4256            as the extra bits is unknown, this case will not be handled here.
 4257         */
 4258
 4259        u64 raw;
 4260        u64 sig1, sig2, sig2_ext, hi, lo, hi2, lo2, add, bits;
 4261        i32 exp2;
 4262        u32 lz;
 4263        bool exact = false, carry, round_up;
 4264
 4265        /* convert (10^exp) to (sig2 * 2^exp2) */
 4266        pow10_table_get_sig(exp, &sig2, &sig2_ext);
 4267        pow10_table_get_exp(exp, &exp2);
 4268
 4269        /* normalize and multiply */
 4270        lz = u64_lz_bits(sig);
 4271        sig1 = sig << lz;
 4272        exp2 -= (i32)lz;
 4273        u128_mul(sig1, sig2, &hi, &lo);
 4274
 4275        /*
 4276         The `hi` is in range [0x4000000000000000, 0xFFFFFFFFFFFFFFFE],
 4277         To get normalized value, `hi` should be shifted to the left by 0 or 1.
 4278
 4279         The highest significant 53 bits is used by IEEE-754 double number,
 4280         and the bit 54 is used to detect rounding direction.
 4281
 4282         The lowest (64 - 54 - 1) bits is used to check whether it contains 0.
 4283         */
 4284        bits = hi & (((u64)1 << (64 - 54 - 1)) - 1);
 4285        if (bits - 1 < (((u64)1 << (64 - 54 - 1)) - 2)) {
 4286            /*
 4287             (bits != 0 && bits != 0x1FF) => (bits - 1 < 0x1FF - 1)
 4288             The `bits` is not zero, so we don't need to check `round to even`
 4289             case. The `bits` contains bit `0`, so we can drop the extra bits
 4290             after `0`.
 4291             */
 4292            exact = true;
 4293
 4294        } else {
 4295            /*
 4296             (bits == 0 || bits == 0x1FF)
 4297             The `bits` is filled with all `0` or all `1`, so we need to check
 4298             lower bits with another 64-bit multiplication.
 4299             */
 4300            u128_mul(sig1, sig2_ext, &hi2, &lo2);
 4301
 4302            add = lo + hi2;
 4303            if (add + 1 > (u64)1) {
 4304                /*
 4305                 (add != 0 && add != U64_MAX) => (add + 1 > 1)
 4306                 The `add` is not zero, so we don't need to check `round to
 4307                 even` case. The `add` contains bit `0`, so we can drop the
 4308                 extra bits after `0`. The `hi` cannot be U64_MAX, so it will
 4309                 not overflow.
 4310                 */
 4311                carry = add < lo || add < hi2;
 4312                hi += carry;
 4313                exact = true;
 4314            }
 4315        }
 4316
 4317        if (exact) {
 4318            /* normalize */
 4319            lz = hi < ((u64)1 << 63);
 4320            hi <<= lz;
 4321            exp2 -= (i32)lz;
 4322            exp2 += 64;
 4323
 4324            /* test the bit 54 and get rounding direction */
 4325            round_up = (hi & ((u64)1 << (64 - 54))) > (u64)0;
 4326            hi += (round_up ? ((u64)1 << (64 - 54)) : (u64)0);
 4327
 4328            /* test overflow */
 4329            if (hi < ((u64)1 << (64 - 54))) {
 4330                hi = ((u64)1 << 63);
 4331                exp2 += 1;
 4332            }
 4333
 4334            /* This is a normal number, convert it to IEEE-754 format. */
 4335            hi >>= F64_BITS - F64_SIG_FULL_BITS;
 4336            exp2 += F64_BITS - F64_SIG_FULL_BITS + F64_SIG_BITS;
 4337            exp2 += F64_EXP_BIAS;
 4338            raw = ((u64)exp2 << F64_SIG_BITS) | (hi & F64_SIG_MASK);
 4339            return_f64_bin(raw);
 4340        }
 4341    }
 4342
 4343    /*
 4344     Slow path: read double number exactly with diyfp.
 4345     1. Use cached diyfp to get an approximation value.
 4346     2. Use bigcomp to check the approximation value if needed.
 4347
 4348     This algorithm refers to google's double-conversion project:
 4349     https://github.com/google/double-conversion
 4350     */
 4351    {
 4352        const i32 ERR_ULP_LOG = 3;
 4353        const i32 ERR_ULP = 1 << ERR_ULP_LOG;
 4354        const i32 ERR_CACHED_POW = ERR_ULP / 2;
 4355        const i32 ERR_MUL_FIXED = ERR_ULP / 2;
 4356        const i32 DIY_SIG_BITS = 64;
 4357        const i32 EXP_BIAS = F64_EXP_BIAS + F64_SIG_BITS;
 4358        const i32 EXP_SUBNORMAL = -EXP_BIAS + 1;
 4359
 4360        u64 fp_err;
 4361        u32 bits;
 4362        i32 order_of_magnitude;
 4363        i32 effective_significand_size;
 4364        i32 precision_digits_count;
 4365        u64 precision_bits;
 4366        u64 half_way;
 4367
 4368        u64 raw;
 4369        diy_fp fp, fp_upper;
 4370        bigint big_full, big_comp;
 4371        i32 cmp;
 4372
 4373        fp.sig = sig;
 4374        fp.exp = 0;
 4375        fp_err = sig_cut ? (u64)(ERR_ULP / 2) : (u64)0;
 4376
 4377        /* normalize */
 4378        bits = u64_lz_bits(fp.sig);
 4379        fp.sig <<= bits;
 4380        fp.exp -= (i32)bits;
 4381        fp_err <<= bits;
 4382
 4383        /* multiply and add error */
 4384        fp = diy_fp_mul(fp, diy_fp_get_cached_pow10(exp));
 4385        fp_err += (u64)ERR_CACHED_POW + (fp_err != 0) + (u64)ERR_MUL_FIXED;
 4386
 4387        /* normalize */
 4388        bits = u64_lz_bits(fp.sig);
 4389        fp.sig <<= bits;
 4390        fp.exp -= (i32)bits;
 4391        fp_err <<= bits;
 4392
 4393        /* effective significand */
 4394        order_of_magnitude = DIY_SIG_BITS + fp.exp;
 4395        if (likely(order_of_magnitude >= EXP_SUBNORMAL + F64_SIG_FULL_BITS)) {
 4396            effective_significand_size = F64_SIG_FULL_BITS;
 4397        } else if (order_of_magnitude <= EXP_SUBNORMAL) {
 4398            effective_significand_size = 0;
 4399        } else {
 4400            effective_significand_size = order_of_magnitude - EXP_SUBNORMAL;
 4401        }
 4402
 4403        /* precision digits count */
 4404        precision_digits_count = DIY_SIG_BITS - effective_significand_size;
 4405        if (unlikely(precision_digits_count + ERR_ULP_LOG >= DIY_SIG_BITS)) {
 4406            i32 shr = (precision_digits_count + ERR_ULP_LOG) - DIY_SIG_BITS + 1;
 4407            fp.sig >>= shr;
 4408            fp.exp += shr;
 4409            fp_err = (fp_err >> shr) + 1 + (u32)ERR_ULP;
 4410            precision_digits_count -= shr;
 4411        }
 4412
 4413        /* half way */
 4414        precision_bits = fp.sig & (((u64)1 << precision_digits_count) - 1);
 4415        precision_bits *= (u32)ERR_ULP;
 4416        half_way = (u64)1 << (precision_digits_count - 1);
 4417        half_way *= (u32)ERR_ULP;
 4418
 4419        /* rounding */
 4420        fp.sig >>= precision_digits_count;
 4421        fp.sig += (precision_bits >= half_way + fp_err);
 4422        fp.exp += precision_digits_count;
 4423
 4424        /* get IEEE double raw value */
 4425        raw = diy_fp_to_ieee_raw(fp);
 4426        if (unlikely(raw == F64_BITS_INF)) return_inf();
 4427        if (likely(precision_bits <= half_way - fp_err ||
 4428                   precision_bits >= half_way + fp_err)) {
 4429            return_f64_bin(raw); /* number is accurate */
 4430        }
 4431        /* now the number is the correct value, or the next lower value */
 4432
 4433        /* upper boundary */
 4434        if (raw & F64_EXP_MASK) {
 4435            fp_upper.sig = (raw & F64_SIG_MASK) + ((u64)1 << F64_SIG_BITS);
 4436            fp_upper.exp = (i32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
 4437        } else {
 4438            fp_upper.sig = (raw & F64_SIG_MASK);
 4439            fp_upper.exp = 1;
 4440        }
 4441        fp_upper.exp -= F64_EXP_BIAS + F64_SIG_BITS;
 4442        fp_upper.sig <<= 1;
 4443        fp_upper.exp -= 1;
 4444        fp_upper.sig += 1; /* add half ulp */
 4445
 4446        /* compare with bigint */
 4447        bigint_set_buf(&big_full, sig, &exp, sig_cut, sig_end, dot_pos);
 4448        bigint_set_u64(&big_comp, fp_upper.sig);
 4449        if (exp >= 0) {
 4450            bigint_mul_pow10(&big_full, +exp);
 4451        } else {
 4452            bigint_mul_pow10(&big_comp, -exp);
 4453        }
 4454        if (fp_upper.exp > 0) {
 4455            bigint_mul_pow2(&big_comp, (u32)+fp_upper.exp);
 4456        } else {
 4457            bigint_mul_pow2(&big_full, (u32)-fp_upper.exp);
 4458        }
 4459        cmp = bigint_cmp(&big_full, &big_comp);
 4460        if (likely(cmp != 0)) {
 4461            /* round down or round up */
 4462            raw += (cmp > 0);
 4463        } else {
 4464            /* falls midway, round to even */
 4465            raw += (raw & 1);
 4466        }
 4467
 4468        if (unlikely(raw == F64_BITS_INF)) return_inf();
 4469        return_f64_bin(raw);
 4470    }
 4471
 4472#undef return_err
 4473#undef return_inf
 4474#undef return_0
 4475#undef return_i64
 4476#undef return_f64
 4477#undef return_f64_bin
 4478#undef return_raw
 4479}
 4480
 4481
 4482
 4483#else /* FP_READER */
 4484
 4485/**
 4486 Read a JSON number.
 4487 This is a fallback function if the custom number reader is disabled.
 4488 This function use libc's strtod() to read floating-point number.
 4489 */
 4490static_inline bool read_num(u8 **ptr, u8 **pre, yyjson_read_flag flg,
 4491                            yyjson_val *val, const char **msg) {
 4492#define return_err(_pos, _msg) do { \
 4493    *msg = _msg; \
 4494    *end = _pos; \
 4495    return false; \
 4496} while (false)
 4497
 4498#define return_0() do { \
 4499    val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); \
 4500    val->uni.u64 = 0; \
 4501    *end = cur; return true; \
 4502} while (false)
 4503
 4504#define return_i64(_v) do { \
 4505    val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); \
 4506    val->uni.u64 = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \
 4507    *end = cur; return true; \
 4508} while (false)
 4509
 4510#define return_f64(_v) do { \
 4511    val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
 4512    val->uni.f64 = sign ? -(f64)(_v) : (f64)(_v); \
 4513    *end = cur; return true; \
 4514} while (false)
 4515
 4516#define return_f64_bin(_v) do { \
 4517    val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \
 4518    val->uni.u64 = ((u64)sign << 63) | (u64)(_v); \
 4519    *end = cur; return true; \
 4520} while (false)
 4521
 4522#define return_inf() do { \
 4523    if (has_flg(BIGNUM_AS_RAW)) return_raw(); \
 4524    if (has_allow(INF_AND_NAN)) return_f64_bin(F64_BITS_INF); \
 4525    else return_err(hdr, "number is infinity when parsed as double"); \
 4526} while (false)
 4527
 4528#define return_raw() do { \
 4529    val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \
 4530    val->uni.str = (const char *)hdr; \
 4531    **pre = '\0'; *pre = cur; *end = cur; return true; \
 4532} while (false)
 4533
 4534    u64 sig, num;
 4535    u8 *hdr = *ptr;
 4536    u8 *cur = *ptr;
 4537    u8 **end = ptr;
 4538    u8 *dot = NULL;
 4539    u8 *f64_end = NULL;
 4540    bool sign;
 4541
 4542    /* read number as raw string if has `YYJSON_READ_NUMBER_AS_RAW` flag */
 4543    if (has_flg(NUMBER_AS_RAW)) {
 4544        return read_num_raw(ptr, pre, flg, val, msg);
 4545    }
 4546
 4547    sign = (*hdr == '-');
 4548    cur += sign;
 4549    sig = (u8)(*cur - '0');
 4550
 4551    /* read first digit, check leading zero */
 4552    while (unlikely(!char_is_digit(*cur))) {
 4553        if (has_allow(EXT_NUMBER)) {
 4554            if (*cur == '+' && cur == hdr) { /* leading `+` sign */
 4555                cur++;
 4556                sig = (u8)(*cur - '0');
 4557                continue;
 4558            }
 4559            if (*cur == '.' && char_is_num(cur[1])) { /* no integer part */
 4560                goto read_double; /* e.g. '.123' */
 4561            }
 4562        }
 4563        if (has_allow(INF_AND_NAN)) {
 4564            if (read_inf_or_nan(ptr, pre, flg, val)) return true;
 4565        }
 4566        return_err(cur, "no digit after sign");
 4567    }
 4568    if (*cur == '0') {
 4569        cur++;
 4570        if (unlikely(char_is_digit(*cur))) {
 4571            return_err(cur - 1, "number with leading zero is not allowed");
 4572        }
 4573        if (!char_is_fp(*cur)) {
 4574            if (has_allow(EXT_NUMBER) &&
 4575                (*cur == 'x' || *cur == 'X')) { /* hex integer */
 4576                return read_num_hex(ptr, pre, flg, val, msg);
 4577            }
 4578            return_0();
 4579        }
 4580        goto read_double;
 4581    }
 4582
 4583    /* read continuous digits, up to 19 characters */
 4584#define expr_intg(i) \
 4585    if (likely((num = (u64)(cur[i] - (u8)'0')) <= 9)) sig = num + sig * 10; \
 4586    else { cur += i; goto intg_end; }
 4587    repeat_in_1_18(expr_intg)
 4588#undef expr_intg
 4589
 4590    /* here are 19 continuous digits, skip them */
 4591    cur += 19;
 4592    if (char_is_digit(cur[0]) && !char_is_digit_or_fp(cur[1])) {
 4593        /* this number is an integer consisting of 20 digits */
 4594        num = (u8)(*cur - '0');
 4595        if ((sig < (U64_MAX / 10)) ||
 4596            (sig == (U64_MAX / 10) && num <= (U64_MAX % 10))) {
 4597            sig = num + sig * 10;
 4598            cur++;
 4599            if (sign) {
 4600                if (has_flg(BIGNUM_AS_RAW)) return_raw();
 4601                return_f64(unsafe_yyjson_u64_to_f64(sig));
 4602            }
 4603            return_i64(sig);
 4604        }
 4605    }
 4606
 4607intg_end:
 4608    /* continuous digits ended */
 4609    if (!char_is_digit_or_fp(*cur)) {
 4610        /* this number is an integer consisting of 1 to 19 digits */
 4611        if (sign && (sig > ((u64)1 << 63))) {
 4612            if (has_flg(BIGNUM_AS_RAW)) return_raw();
 4613            return_f64(unsafe_yyjson_u64_to_f64(sig));
 4614        }
 4615        return_i64(sig);
 4616    }
 4617
 4618read_double:
 4619    /* this number should be read as double */
 4620    while (char_is_digit(*cur)) cur++;
 4621    if (!char_is_fp(*cur) && has_flg(BIGNUM_AS_RAW)) {
 4622        return_raw(); /* it's a large integer */
 4623    }
 4624    while (*cur == '.') {
 4625        /* skip fraction part */
 4626        dot = cur;
 4627        cur++;
 4628        if (!char_is_digit(*cur)) {
 4629            if (has_allow(EXT_NUMBER)) {
 4630                break;
 4631            } else {
 4632                return_err(cur, "no digit after decimal point");
 4633            }
 4634        }
 4635        cur++;
 4636        while (char_is_digit(*cur)) cur++;
 4637        break;
 4638    }
 4639    if (char_is_exp(*cur)) {
 4640        /* skip exponent part */
 4641        cur += 1 + char_is_sign(cur[1]);
 4642        if (!char_is_digit(*cur)) {
 4643            return_err(cur, "no digit after exponent sign");
 4644        }
 4645        cur++;
 4646        while (char_is_digit(*cur)) cur++;
 4647    }
 4648
 4649    /*
 4650     libc's strtod() is used to parse the floating-point number.
 4651
 4652     Note that the decimal point character used by strtod() is locale-dependent,
 4653     and the rounding direction may affected by fesetround().
 4654
 4655     For currently known locales, (en, zh, ja, ko, am, he, hi) use '.' as the
 4656     decimal point, while other locales use ',' as the decimal point.
 4657
 4658     Here strtod() is called twice for different locales, but if another thread
 4659     happens calls setlocale() between two strtod(), parsing may still fail.
 4660     */
 4661    val->uni.f64 = strtod((const char *)hdr, (char **)&f64_end);
 4662    if (unlikely(f64_end != cur)) {
 4663        /* replace '.' with ',' for locale */
 4664        bool cut = (*cur == ',');
 4665        if (cut) *cur = ' ';
 4666        if (dot) *dot = ',';
 4667        val->uni.f64 = strtod((const char *)hdr, (char **)&f64_end);
 4668        /* restore ',' to '.' */
 4669        if (cut) *cur = ',';
 4670        if (dot) *dot = '.';
 4671        if (unlikely(f64_end != cur)) {
 4672            return_err(hdr, "strtod() failed to parse the number");
 4673        }
 4674    }
 4675    if (unlikely(f64_is_inf(val->uni.f64))) {
 4676        return_inf();
 4677    }
 4678    val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL;
 4679    *end = cur;
 4680    return true;
 4681
 4682#undef return_err
 4683#undef return_0
 4684#undef return_i64
 4685#undef return_f64
 4686#undef return_f64_bin
 4687#undef return_inf
 4688#undef return_raw
 4689}
 4690
 4691#endif /* FP_READER */
 4692
 4693
 4694
 4695/*==============================================================================
 4696 * MARK: - String Reader (Private)
 4697 *============================================================================*/
 4698
 4699/** Read unicode escape sequence. */
 4700static_inline bool read_uni_esc(u8 **src_ptr, u8 **dst_ptr, const char **msg) {
 4701#define return_err(_end, _msg) *msg = _msg; *src_ptr = _end; return false
 4702
 4703    u8 *src = *src_ptr;
 4704    u8 *dst = *dst_ptr;
 4705    u16 hi, lo;
 4706    u32 uni;
 4707
 4708    src += 2; /* skip `\u` */
 4709    if (unlikely(!hex_load_4(src, &hi))) {
 4710        return_err(src - 2, "invalid escaped sequence in string");
 4711    }
 4712    src += 4; /* skip hex */
 4713    if (likely((hi & 0xF800) != 0xD800)) {
 4714        /* a BMP character */
 4715        if (hi >= 0x800) {
 4716            *dst++ = (u8)(0xE0 | (hi >> 12));
 4717            *dst++ = (u8)(0x80 | ((hi >> 6) & 0x3F));
 4718            *dst++ = (u8)(0x80 | (hi & 0x3F));
 4719        } else if (hi >= 0x80) {
 4720            *dst++ = (u8)(0xC0 | (hi >> 6));
 4721            *dst++ = (u8)(0x80 | (hi & 0x3F));
 4722        } else {
 4723            *dst++ = (u8)hi;
 4724        }
 4725    } else {
 4726        /* a non-BMP character, represented as a surrogate pair */
 4727        if (unlikely((hi & 0xFC00) != 0xD800)) {
 4728            return_err(src - 6, "invalid high surrogate in string");
 4729        }
 4730        if (unlikely(!byte_match_2(src, "\\u"))) {
 4731            return_err(src - 6, "no low surrogate in string");
 4732        }
 4733        if (unlikely(!hex_load_4(src + 2, &lo))) {
 4734            return_err(src - 6, "invalid escape in string");
 4735        }
 4736        if (unlikely((lo & 0xFC00) != 0xDC00)) {
 4737            return_err(src - 6, "invalid low surrogate in string");
 4738        }
 4739        uni = ((((u32)hi - 0xD800) << 10) |
 4740                ((u32)lo - 0xDC00)) + 0x10000;
 4741        *dst++ = (u8)(0xF0 | (uni >> 18));
 4742        *dst++ = (u8)(0x80 | ((uni >> 12) & 0x3F));
 4743        *dst++ = (u8)(0x80 | ((uni >> 6) & 0x3F));
 4744        *dst++ = (u8)(0x80 | (uni & 0x3F));
 4745        src += 6;
 4746    }
 4747    *src_ptr = src;
 4748    *dst_ptr = dst;
 4749    return true;
 4750#undef return_err
 4751}
 4752
 4753/**
 4754 Read a JSON string.
 4755 @param quo The quote character (single quote or double quote).
 4756 @param ptr The head pointer of string before quote (inout).
 4757 @param eof JSON end position.
 4758 @param flg JSON read flag.
 4759 @param val The string value to be written.
 4760 @param msg The error message pointer.
 4761 @param con Continuation for incremental parsing.
 4762 @return Whether success.
 4763 */
 4764static_inline bool read_str_opt(u8 quo, u8 **ptr, u8 *eof, yyjson_read_flag flg,
 4765                                yyjson_val *val, const char **msg, u8 *con[2]) {
 4766    /*
 4767     GCC may sometimes load variables into registers too early, causing
 4768     unnecessary instructions and performance degradation. This inline assembly
 4769     serves as a hint to GCC: 'This variable will be modified, so avoid loading
 4770     it too early.' Other compilers like MSVC, Clang, and ICC can generate the
 4771     expected instructions without needing this hint.
 4772
 4773     Check out this example: https://godbolt.org/z/YG6a5W5Ec
 4774     */
 4775#define return_err(_end, _msg) do { \
 4776    *msg = _msg; \
 4777    *end = _end; \
 4778    if (con) { con[0] = _end; con[1] = dst; } \
 4779    return false; \
 4780} while (false)
 4781
 4782    u8 *hdr = *ptr + 1;
 4783    u8 **end = ptr;
 4784    u8 *src = hdr, *dst = NULL, *pos;
 4785    u32 uni, tmp;
 4786
 4787    /* Resume incremental parsing. */
 4788    if (con && unlikely(con[0])) {
 4789        src = con[0];
 4790        dst = con[1];
 4791        if (dst) goto copy_ascii;
 4792    }
 4793
 4794skip_ascii:
 4795    /*
 4796     Most strings have no escaped characters, so we can jump them quickly.
 4797
 4798     We want to make loop unrolling, as shown in the following code. Some
 4799     compiler may not generate instructions as expected, so we rewrite it with
 4800     explicit goto statements. We hope the compiler can generate instructions
 4801     like this: https://godbolt.org/z/8vjsYq
 4802
 4803     while (true) repeat16({
 4804        if (likely((char_is_ascii_skip(*src)))) src++;
 4805        else break;
 4806     })
 4807     */
 4808    if (quo == '"') {
 4809#define expr_jump(i) \
 4810    if (likely(char_is_ascii_skip(src[i]))) {} \
 4811    else goto skip_ascii_stop##i;
 4812
 4813#define expr_stop(i) \
 4814    skip_ascii_stop##i: \
 4815    src += i; \
 4816    goto skip_ascii_end;
 4817
 4818    repeat16_incr(expr_jump)
 4819    src += 16;
 4820    goto skip_ascii;
 4821    repeat16_incr(expr_stop)
 4822
 4823#undef expr_jump
 4824#undef expr_stop
 4825    } else {
 4826#define expr_jump(i) \
 4827    if (likely(char_is_ascii_skip_sq(src[i]))) {} \
 4828    else goto skip_ascii_stop_sq##i;
 4829
 4830#define expr_stop(i) \
 4831    skip_ascii_stop_sq##i: \
 4832    src += i; \
 4833    goto skip_ascii_end;
 4834
 4835    repeat16_incr(expr_jump)
 4836    src += 16;
 4837    goto skip_ascii;
 4838    repeat16_incr(expr_stop)
 4839
 4840#undef expr_jump
 4841#undef expr_stop
 4842    }
 4843
 4844skip_ascii_end:
 4845    gcc_store_barrier(*src);
 4846    if (likely(*src == quo)) {
 4847        val->tag = ((u64)(src - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR |
 4848                        (quo == '"' ? YYJSON_SUBTYPE_NOESC : 0);
 4849        val->uni.str = (const char *)hdr;
 4850        *src = '\0';
 4851        *end = src + 1;
 4852        if (con) con[0] = con[1] = NULL;
 4853        return true;
 4854    }
 4855
 4856skip_utf8:
 4857    if (*src & 0x80) { /* non-ASCII character */
 4858        /*
 4859         Non-ASCII character appears here, which means that the text is likely
 4860         to be written in non-English or emoticons. According to some common
 4861         data set statistics, byte sequences of the same length may appear
 4862         consecutively. We process the byte sequences of the same length in each
 4863         loop, which is more friendly to branch prediction.
 4864         */
 4865        pos = src;
 4866#if YYJSON_DISABLE_UTF8_VALIDATION
 4867        while (true) repeat8({
 4868            if (likely((*src & 0xF0) == 0xE0)) src += 3;
 4869            else break;
 4870        })
 4871        if (*src < 0x80) goto skip_ascii;
 4872        while (true) repeat8({
 4873            if (likely((*src & 0xE0) == 0xC0)) src += 2;
 4874            else break;
 4875        })
 4876        while (true) repeat8({
 4877            if (likely((*src & 0xF8) == 0xF0)) src += 4;
 4878            else break;
 4879        })
 4880#else
 4881        uni = byte_load_4(src);
 4882        while (is_utf8_seq3(uni)) {
 4883            src += 3;
 4884            uni = byte_load_4(src);
 4885        }
 4886        if (is_utf8_seq1(uni)) goto skip_ascii;
 4887        while (is_utf8_seq2(uni)) {
 4888            src += 2;
 4889            uni = byte_load_4(src);
 4890        }
 4891        while (is_utf8_seq4(uni)) {
 4892            src += 4;
 4893            uni = byte_load_4(src);
 4894        }
 4895#endif
 4896        if (unlikely(pos == src)) {
 4897            if (has_allow(INVALID_UNICODE)) ++src;
 4898            else return_err(src, "invalid UTF-8 encoding in string");
 4899        }
 4900        goto skip_ascii;
 4901    }
 4902
 4903    /* The escape character appears, we need to copy it. */
 4904    dst = src;
 4905copy_escape:
 4906    if (likely(*src == '\\')) {
 4907        switch (*++src) {
 4908            case '"':  *dst++ = '"';  src++; break;
 4909            case '\\': *dst++ = '\\'; src++; break;
 4910            case '/':  *dst++ = '/';  src++; break;
 4911            case 'b':  *dst++ = '\b'; src++; break;
 4912            case 'f':  *dst++ = '\f'; src++; break;
 4913            case 'n':  *dst++ = '\n'; src++; break;
 4914            case 'r':  *dst++ = '\r'; src++; break;
 4915            case 't':  *dst++ = '\t'; src++; break;
 4916            case 'u':
 4917                src--;
 4918                if (!read_uni_esc(&src, &dst, msg)) return_err(src, *msg);
 4919                break;
 4920            default: {
 4921                if (has_allow(EXT_ESCAPE)) {
 4922                    /* read extended escape (non-standard) */
 4923                    switch (*src) {
 4924                        case '\'': *dst++ = '\''; src++; break;
 4925                        case 'a':  *dst++ = '\a'; src++; break;
 4926                        case 'v':  *dst++ = '\v'; src++; break;
 4927                        case '?':  *dst++ = '\?'; src++; break;
 4928                        case 'e':  *dst++ = 0x1B; src++; break;
 4929                        case '0':
 4930                            if (!char_is_digit(src[1])) {
 4931                                *dst++ = '\0'; src++; break;
 4932                            }
 4933                            return_err(src - 1, "octal escape is not allowed");
 4934                        case '1': case '2': case '3': case '4':
 4935                        case '5': case '6': case '7': case '8': case '9':
 4936                            return_err(src - 1, "invalid number escape");
 4937                        case 'x': {
 4938                            u8 c;
 4939                            if (hex_load_2(src + 1, &c)) {
 4940                                src += 3;
 4941                                if (c <= 0x7F) { /* 1-byte ASCII */
 4942                                    *dst++ = c;
 4943                                } else { /* 2-byte UTF-8 */
 4944                                    *dst++ = (u8)(0xC0 | (c >> 6));
 4945                                    *dst++ = (u8)(0x80 | (c & 0x3F));
 4946                                }
 4947                                break;
 4948                            }
 4949                            return_err(src - 1, "invalid hex escape");
 4950                        }
 4951                        case '\n': src++; break;
 4952                        case '\r': src++; src += (*src == '\n'); break;
 4953                        case 0xE2: /* Line terminator: U+2028, U+2029 */
 4954                            if ((src[1] == 0x80 && src[2] == 0xA8) ||
 4955                                (src[1] == 0x80 && src[2] == 0xA9)) {
 4956                                src += 3;
 4957                            }
 4958                            break;
 4959                        default:
 4960                            break; /* skip */
 4961                    }
 4962                } else if (quo == '\'' && *src == '\'') {
 4963                    *dst++ = '\''; src++; break;
 4964                } else {
 4965                    return_err(src - 1, "invalid escaped sequence in string");
 4966                }
 4967            }
 4968        }
 4969    } else if (likely(*src == quo)) {
 4970        val->tag = ((u64)(dst - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR;
 4971        val->uni.str = (const char *)hdr;
 4972        *dst = '\0';
 4973        *end = src + 1;
 4974        if (con) con[0] = con[1] = NULL;
 4975        return true;
 4976    } else {
 4977        if (!has_allow(INVALID_UNICODE)) {
 4978            return_err(src, "unexpected control character in string");
 4979        }
 4980        if (src >= eof) return_err(src, "unclosed string");
 4981        *dst++ = *src++;
 4982    }
 4983
 4984copy_ascii:
 4985    /*
 4986     Copy continuous ASCII, loop unrolling, same as the following code:
 4987
 4988     while (true) repeat16({
 4989        if (char_is_ascii_skip(*src)) *dst++ = *src++;
 4990        else break;
 4991     })
 4992     */
 4993    if (quo == '"') {
 4994#define expr_jump(i) \
 4995    if (likely((char_is_ascii_skip(src[i])))) {} \
 4996    else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; }
 4997    repeat16_incr(expr_jump)
 4998#undef expr_jump
 4999    } else {
 5000#define expr_jump(i) \
 5001    if (likely((char_is_ascii_skip_sq(src[i])))) {} \
 5002    else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; }
 5003    repeat16_incr(expr_jump)
 5004#undef expr_jump
 5005    }
 5006
 5007    byte_move_16(dst, src);
 5008    dst += 16; src += 16;
 5009    goto copy_ascii;
 5010
 5011    /*
 5012     The memory is copied forward since `dst < src`.
 5013     So it's safe to move one extra byte to reduce instruction count.
 5014     */
 5015#define expr_jump(i) \
 5016    copy_ascii_stop_##i: \
 5017    byte_move_forward(dst, src, i); \
 5018    dst += i; src += i; \
 5019    goto copy_utf8;
 5020    repeat16_incr(expr_jump)
 5021#undef expr_jump
 5022
 5023copy_utf8:
 5024    if (*src & 0x80) { /* non-ASCII character */
 5025        pos = src;
 5026        uni = byte_load_4(src);
 5027#if YYJSON_DISABLE_UTF8_VALIDATION
 5028        while (true) repeat4({
 5029            if ((uni & utf8_seq(b3_mask)) == utf8_seq(b3_patt)) {
 5030                byte_copy_4(dst, &uni);
 5031                dst += 3; src += 3;
 5032                uni = byte_load_4(src);
 5033            } else break;
 5034        })
 5035        if ((uni & utf8_seq(b1_mask)) == utf8_seq(b1_patt)) goto copy_ascii;
 5036        while (true) repeat4({
 5037            if ((uni & utf8_seq(b2_mask)) == utf8_seq(b2_patt)) {
 5038                byte_copy_2(dst, &uni);
 5039                dst += 2; src += 2;
 5040                uni = byte_load_4(src);
 5041            } else break;
 5042        })
 5043        while (true) repeat4({
 5044            if ((uni & utf8_seq(b4_mask)) == utf8_seq(b4_patt)) {
 5045                byte_copy_4(dst, &uni);
 5046                dst += 4; src += 4;
 5047                uni = byte_load_4(src);
 5048            } else break;
 5049        })
 5050#else
 5051        while (is_utf8_seq3(uni)) {
 5052            byte_copy_4(dst, &uni);
 5053            dst += 3; src += 3;
 5054            uni = byte_load_4(src);
 5055        }
 5056        if (is_utf8_seq1(uni)) goto copy_ascii;
 5057        while (is_utf8_seq2(uni)) {
 5058            byte_copy_2(dst, &uni);
 5059            dst += 2; src += 2;
 5060            uni = byte_load_4(src);
 5061        }
 5062        while (is_utf8_seq4(uni)) {
 5063            byte_copy_4(dst, &uni);
 5064            dst += 4; src += 4;
 5065            uni = byte_load_4(src);
 5066        }
 5067#endif
 5068        if (unlikely(pos == src)) {
 5069            if (!has_allow(INVALID_UNICODE)) {
 5070                return_err(src, MSG_ERR_UTF8);
 5071            }
 5072            goto copy_ascii_stop_1;
 5073        }
 5074        goto copy_ascii;
 5075    }
 5076    goto copy_escape;
 5077
 5078#undef return_err
 5079}
 5080
 5081static_inline bool read_str(u8 **ptr, u8 *eof, yyjson_read_flag flg,
 5082                            yyjson_val *val, const char **msg) {
 5083    return read_str_opt('\"', ptr, eof, flg, val, msg, NULL);
 5084}
 5085
 5086static_inline bool read_str_con(u8 **ptr, u8 *eof, yyjson_read_flag flg,
 5087                                yyjson_val *val, const char **msg, u8 **con) {
 5088    return read_str_opt('\"', ptr, eof, flg, val, msg, con);
 5089}
 5090
 5091static_noinline bool read_str_sq(u8 **ptr, u8 *eof, yyjson_read_flag flg,
 5092                                 yyjson_val *val, const char **msg) {
 5093    return read_str_opt('\'', ptr, eof, flg, val, msg, NULL);
 5094}
 5095
 5096/** Read unquoted key (identifier name). */
 5097static_noinline bool read_str_id(u8 **ptr, u8 *eof, yyjson_read_flag flg,
 5098                                 u8 **pre, yyjson_val *val, const char **msg) {
 5099#define return_err(_end, _msg) do { \
 5100    *msg = _msg; \
 5101    *end = _end; \
 5102    return false; \
 5103} while (false)
 5104
 5105#define return_suc(_str_end, _cur_end) do { \
 5106    val->tag = ((u64)(_str_end - hdr) << YYJSON_TAG_BIT) | \
 5107                (u64)(YYJSON_TYPE_STR); \
 5108    val->uni.str = (const char *)hdr; \
 5109    *pre = _str_end; *end = _cur_end; \
 5110    return true; \
 5111} while (false)
 5112
 5113    u8 *hdr = *ptr;
 5114    u8 **end = ptr;
 5115    u8 *src = hdr, *dst = NULL;
 5116    u32 uni, tmp;
 5117
 5118    /* add null-terminator for previous raw string */
 5119    **pre = '\0';
 5120
 5121skip_ascii:
 5122#define expr_jump(i) \
 5123    if (likely(char_is_id_ascii(src[i]))) {} \
 5124    else goto skip_ascii_stop##i;
 5125
 5126#define expr_stop(i) \
 5127    skip_ascii_stop##i: \
 5128    src += i; \
 5129    goto skip_ascii_end;
 5130
 5131    repeat16_incr(expr_jump)
 5132    src += 16;
 5133    goto skip_ascii;
 5134    repeat16_incr(expr_stop)
 5135
 5136#undef expr_jump
 5137#undef expr_stop
 5138
 5139skip_ascii_end:
 5140    gcc_store_barrier(*src);
 5141    if (likely(!char_is_id_next(*src))) {
 5142        return_suc(src, src);
 5143    }
 5144
 5145skip_utf8:
 5146    while (*src >= 0x80) {
 5147        if (has_allow(EXT_WHITESPACE)) {
 5148            if (char_is_space_ext(*src) && ext_space_len(src)) {
 5149                return_suc(src, src);
 5150            }
 5151        }
 5152        uni = byte_load_4(src);
 5153        if (is_utf8_seq2(uni)) {
 5154            src += 2;
 5155        } else if (is_utf8_seq3(uni)) {
 5156            src += 3;
 5157        } else if (is_utf8_seq4(uni)) {
 5158            src += 4;
 5159        } else {
 5160#if !YYJSON_DISABLE_UTF8_VALIDATION
 5161            if (!has_allow(INVALID_UNICODE)) return_err(src, MSG_ERR_UTF8);
 5162#endif
 5163            src += 1;
 5164        }
 5165    }
 5166    if (char_is_id_ascii(*src)) goto skip_ascii;
 5167
 5168    /* The escape character appears, we need to copy it. */
 5169    dst = src;
 5170copy_escape:
 5171    if (byte_match_2(src, "\\u")) {
 5172        if (!read_uni_esc(&src, &dst, msg)) return_err(src, *msg);
 5173    } else {
 5174        if (!char_is_id_next(*src)) return_suc(dst, src);
 5175        return_err(src, "unexpected character in key");
 5176    }
 5177
 5178copy_ascii:
 5179    /*
 5180     Copy continuous ASCII, loop unrolling, same as the following code:
 5181
 5182     while (true) repeat16({
 5183        if (char_is_ascii_skip(*src)) *dst++ = *src++;
 5184        else break;
 5185     })
 5186     */
 5187#define expr_jump(i) \
 5188    if (likely((char_is_id_ascii(src[i])))) {} \
 5189    else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; }
 5190    repeat16_incr(expr_jump)
 5191#undef expr_jump
 5192
 5193    byte_move_16(dst, src);
 5194    dst += 16; src += 16;
 5195    goto copy_ascii;
 5196
 5197#define expr_jump(i) \
 5198    copy_ascii_stop_##i: \
 5199    byte_move_forward(dst, src, i); \
 5200    dst += i; src += i; \
 5201    goto copy_utf8;
 5202    repeat16_incr(expr_jump)
 5203#undef expr_jump
 5204
 5205copy_utf8:
 5206    while (*src >= 0x80) { /* non-ASCII character */
 5207        if (has_allow(EXT_WHITESPACE)) {
 5208            if (char_is_space_ext(*src) && ext_space_len(src)) {
 5209                return_suc(dst, src);
 5210            }
 5211        }
 5212        uni = byte_load_4(src);
 5213        if (is_utf8_seq2(uni)) {
 5214            byte_copy_2(dst, &uni);
 5215            dst += 2; src += 2;
 5216        } else if (is_utf8_seq3(uni)) {
 5217            byte_copy_4(dst, &uni);
 5218            dst += 3; src += 3;
 5219        } else if (is_utf8_seq4(uni)) {
 5220            byte_copy_4(dst, &uni);
 5221            dst += 4; src += 4;
 5222        } else {
 5223#if !YYJSON_DISABLE_UTF8_VALIDATION
 5224            if (!has_allow(INVALID_UNICODE)) return_err(src, MSG_ERR_UTF8);
 5225#endif
 5226            *dst = *src;
 5227            dst += 1; src += 1;
 5228        }
 5229    }
 5230    if (char_is_id_ascii(*src)) goto copy_ascii;
 5231    goto copy_escape;
 5232
 5233#undef return_err
 5234#undef return_suc
 5235}
 5236
 5237
 5238
 5239/*==============================================================================
 5240 * MARK: - JSON Reader Implementation (Private)
 5241 *
 5242 * We use goto statements to build the finite state machine (FSM).
 5243 * The FSM's state was held by program counter (PC) and the 'goto' make the
 5244 * state transitions.
 5245 *============================================================================*/
 5246
 5247/** Read single value JSON document. */
 5248static_noinline yyjson_doc *read_root_single(u8 *hdr, u8 *cur, u8 *eof,
 5249                                             yyjson_alc alc,
 5250                                             yyjson_read_flag flg,
 5251                                             yyjson_read_err *err) {
 5252#define return_err(_pos, _code, _msg) do { \
 5253    if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \
 5254        err->pos = (usize)(eof - hdr); \
 5255        err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
 5256        err->msg = MSG_NOT_END; \
 5257    } else { \
 5258        err->pos = (usize)(_pos - hdr); \
 5259        err->code = YYJSON_READ_ERROR_##_code; \
 5260        err->msg = _msg; \
 5261    } \
 5262    if (val_hdr) alc.free(alc.ctx, val_hdr); \
 5263    return NULL; \
 5264} while (false)
 5265
 5266    usize hdr_len; /* value count used by doc */
 5267    usize alc_num; /* value count capacity */
 5268    yyjson_val *val_hdr; /* the head of allocated values */
 5269    yyjson_val *val; /* current value */
 5270    yyjson_doc *doc; /* the JSON document, equals to val_hdr */
 5271    const char *msg; /* error message */
 5272
 5273    u8 raw_end[1]; /* raw end for null-terminator */
 5274    u8 *raw_ptr = raw_end;
 5275    u8 **pre = &raw_ptr; /* previous raw end pointer */
 5276
 5277    hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
 5278    hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
 5279    alc_num = hdr_len + 1; /* single value */
 5280
 5281    val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_num * sizeof(yyjson_val));
 5282    if (unlikely(!val_hdr)) goto fail_alloc;
 5283    val = val_hdr + hdr_len;
 5284
 5285    if (char_is_num(*cur)) {
 5286        if (likely(read_num(&cur, pre, flg, val, &msg))) goto doc_end;
 5287        goto fail_number;
 5288    }
 5289    if (*cur == '"') {
 5290        if (likely(read_str(&cur, eof, flg, val, &msg))) goto doc_end;
 5291        goto fail_string;
 5292    }
 5293    if (*cur == 't') {
 5294        if (likely(read_true(&cur, val))) goto doc_end;
 5295        goto fail_literal_true;
 5296    }
 5297    if (*cur == 'f') {
 5298        if (likely(read_false(&cur, val))) goto doc_end;
 5299        goto fail_literal_false;
 5300    }
 5301    if (*cur == 'n') {
 5302        if (likely(read_null(&cur, val))) goto doc_end;
 5303        if (has_allow(INF_AND_NAN)) {
 5304            if (read_nan(&cur, pre, flg, val)) goto doc_end;
 5305        }
 5306        goto fail_literal_null;
 5307    }
 5308    if (has_allow(INF_AND_NAN)) {
 5309        if (read_inf_or_nan(&cur, pre, flg, val)) goto doc_end;
 5310    }
 5311    if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
 5312        if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto doc_end;
 5313        goto fail_string;
 5314    }
 5315    goto fail_character;
 5316
 5317doc_end:
 5318    /* check invalid contents after json document */
 5319    if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) {
 5320        while (char_is_space(*cur)) cur++;
 5321        if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
 5322            if (!skip_trivia(&cur, eof, flg) && cur == eof) {
 5323                goto fail_comment;
 5324            }
 5325        }
 5326        if (unlikely(cur < eof)) goto fail_garbage;
 5327    }
 5328
 5329    **pre = '\0';
 5330    doc = (yyjson_doc *)val_hdr;
 5331    doc->root = val_hdr + hdr_len;
 5332    doc->alc = alc;
 5333    doc->dat_read = (usize)(cur - hdr);
 5334    doc->val_read = 1;
 5335    doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
 5336    return doc;
 5337
 5338fail_string:        return_err(cur, INVALID_STRING, msg);
 5339fail_number:        return_err(cur, INVALID_NUMBER, msg);
 5340fail_alloc:         return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
 5341fail_literal_true:  return_err(cur, LITERAL, MSG_CHAR_T);
 5342fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F);
 5343fail_literal_null:  return_err(cur, LITERAL, MSG_CHAR_N);
 5344fail_character:     return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
 5345fail_comment:       return_err(cur, INVALID_COMMENT, MSG_COMMENT);
 5346fail_garbage:       return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
 5347fail_depth:         return_err(cur, DEPTH, MSG_DEPTH);
 5348
 5349#undef return_err
 5350}
 5351
 5352/** Read JSON document (accept all style, but optimized for minify). */
 5353static_inline yyjson_doc *read_root_minify(u8 *hdr, u8 *cur, u8 *eof,
 5354                                           yyjson_alc alc,
 5355                                           yyjson_read_flag flg,
 5356                                           yyjson_read_err *err) {
 5357#define return_err(_pos, _code, _msg) do { \
 5358    if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \
 5359        err->pos = (usize)(eof - hdr); \
 5360        err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
 5361        err->msg = MSG_NOT_END; \
 5362    } else { \
 5363        err->pos = (usize)(_pos - hdr); \
 5364        err->code = YYJSON_READ_ERROR_##_code; \
 5365        err->msg = _msg; \
 5366    } \
 5367    if (val_hdr) alc.free(alc.ctx, val_hdr); \
 5368    return NULL; \
 5369} while (false)
 5370
 5371#define val_incr() do { \
 5372    val++; \
 5373    if (unlikely(val >= val_end)) { \
 5374        usize alc_old = alc_len; \
 5375        usize val_ofs = (usize)(val - val_hdr); \
 5376        usize ctn_ofs = (usize)(ctn - val_hdr); \
 5377        alc_len += alc_len / 2; \
 5378        if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \
 5379        val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
 5380            alc_old * sizeof(yyjson_val), \
 5381            alc_len * sizeof(yyjson_val)); \
 5382        if ((!val_tmp)) goto fail_alloc; \
 5383        val = val_tmp + val_ofs; \
 5384        ctn = val_tmp + ctn_ofs; \
 5385        val_hdr = val_tmp; \
 5386        val_end = val_tmp + (alc_len - 2); \
 5387    } \
 5388} while (false)
 5389
 5390    usize dat_len; /* data length in bytes, hint for allocator */
 5391    usize hdr_len; /* value count used by yyjson_doc */
 5392    usize alc_len; /* value count allocated */
 5393    usize alc_max; /* maximum value count for allocator */
 5394    usize ctn_len; /* the number of elements in current container */
 5395    yyjson_val *val_hdr; /* the head of allocated values */
 5396    yyjson_val *val_end; /* the end of allocated values */
 5397    yyjson_val *val_tmp; /* temporary pointer for realloc */
 5398    yyjson_val *val; /* current JSON value */
 5399    yyjson_val *ctn; /* current container */
 5400    yyjson_val *ctn_parent; /* parent of current container */
 5401    yyjson_doc *doc; /* the JSON document, equals to val_hdr */
 5402    const char *msg; /* error message */
 5403
 5404    u8 raw_end[1]; /* raw end for null-terminator */
 5405    u8 *raw_ptr = raw_end;
 5406    u8 **pre = &raw_ptr; /* previous raw end pointer */
 5407
 5408#if YYJSON_READER_DEPTH_LIMIT
 5409    usize ctn_depth = 0; /* current array/object depth */
 5410#endif
 5411
 5412    dat_len = has_flg(STOP_WHEN_DONE) ? 256 : (usize)(eof - cur);
 5413    hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
 5414    hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
 5415    alc_max = USIZE_MAX / sizeof(yyjson_val);
 5416    alc_len = hdr_len + (dat_len / YYJSON_READER_ESTIMATED_MINIFY_RATIO) + 4;
 5417    alc_len = yyjson_min(alc_len, alc_max);
 5418
 5419    val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_len * sizeof(yyjson_val));
 5420    if (unlikely(!val_hdr)) goto fail_alloc;
 5421    val_end = val_hdr + (alc_len - 2); /* padding for key-value pair reading */
 5422    val = val_hdr + hdr_len;
 5423    ctn = val;
 5424    ctn_len = 0;
 5425
 5426    if (*cur++ == '{') {
 5427        ctn->tag = YYJSON_TYPE_OBJ;
 5428        ctn->uni.ofs = 0;
 5429        goto obj_key_begin;
 5430    } else {
 5431        ctn->tag = YYJSON_TYPE_ARR;
 5432        ctn->uni.ofs = 0;
 5433        goto arr_val_begin;
 5434    }
 5435
 5436arr_begin:
 5437#if YYJSON_READER_DEPTH_LIMIT
 5438    ctn_depth++;
 5439    if (unlikely(ctn_depth >= (usize)YYJSON_READER_DEPTH_LIMIT)) {
 5440        goto fail_depth;
 5441    }
 5442#endif
 5443    /* save current container */
 5444    ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
 5445               (ctn->tag & YYJSON_TAG_MASK);
 5446
 5447    /* create a new array value, save parent container offset */
 5448    val_incr();
 5449    val->tag = YYJSON_TYPE_ARR;
 5450    val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
 5451
 5452    /* push the new array value as current container */
 5453    ctn = val;
 5454    ctn_len = 0;
 5455
 5456arr_val_begin:
 5457    if (*cur == '{') {
 5458        cur++;
 5459        goto obj_begin;
 5460    }
 5461    if (*cur == '[') {
 5462        cur++;
 5463        goto arr_begin;
 5464    }
 5465    if (char_is_num(*cur)) {
 5466        val_incr();
 5467        ctn_len++;
 5468        if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_end;
 5469        goto fail_number;
 5470    }
 5471    if (*cur == '"') {
 5472        val_incr();
 5473        ctn_len++;
 5474        if (likely(read_str(&cur, eof, flg, val, &msg))) goto arr_val_end;
 5475        goto fail_string;
 5476    }
 5477    if (*cur == 't') {
 5478        val_incr();
 5479        ctn_len++;
 5480        if (likely(read_true(&cur, val))) goto arr_val_end;
 5481        goto fail_literal_true;
 5482    }
 5483    if (*cur == 'f') {
 5484        val_incr();
 5485        ctn_len++;
 5486        if (likely(read_false(&cur, val))) goto arr_val_end;
 5487        goto fail_literal_false;
 5488    }
 5489    if (*cur == 'n') {
 5490        val_incr();
 5491        ctn_len++;
 5492        if (likely(read_null(&cur, val))) goto arr_val_end;
 5493        if (has_allow(INF_AND_NAN)) {
 5494            if (read_nan(&cur, pre, flg, val)) goto arr_val_end;
 5495        }
 5496        goto fail_literal_null;
 5497    }
 5498    if (*cur == ']') {
 5499        cur++;
 5500        if (likely(ctn_len == 0)) goto arr_end;
 5501        if (has_allow(TRAILING_COMMAS)) goto arr_end;
 5502        do { cur--; } while (*cur != ',');
 5503        goto fail_trailing_comma;
 5504    }
 5505    if (char_is_space(*cur)) {
 5506        while (char_is_space(*++cur));
 5507        goto arr_val_begin;
 5508    }
 5509    if (has_allow(INF_AND_NAN) &&
 5510        (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
 5511        val_incr();
 5512        ctn_len++;
 5513        if (read_inf_or_nan(&cur, pre, flg, val)) goto arr_val_end;
 5514        goto fail_character_val;
 5515    }
 5516    if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
 5517        val_incr();
 5518        ctn_len++;
 5519        if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto arr_val_end;
 5520        goto fail_string;
 5521    }
 5522    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
 5523        if (skip_trivia(&cur, eof, flg)) goto arr_val_begin;
 5524        if (cur == eof) goto fail_comment;
 5525    }
 5526    goto fail_character_val;
 5527
 5528arr_val_end:
 5529    if (*cur == ',') {
 5530        cur++;
 5531        goto arr_val_begin;
 5532    }
 5533    if (*cur == ']') {
 5534        cur++;
 5535        goto arr_end;
 5536    }
 5537    if (char_is_space(*cur)) {
 5538        while (char_is_space(*++cur));
 5539        goto arr_val_end;
 5540    }
 5541    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
 5542        if (skip_trivia(&cur, eof, flg)) goto arr_val_end;
 5543        if (cur == eof) goto fail_comment;
 5544    }
 5545    goto fail_character_arr_end;
 5546
 5547arr_end:
 5548#if YYJSON_READER_DEPTH_LIMIT
 5549    ctn_depth--;
 5550#endif
 5551    /* get parent container */
 5552    ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
 5553
 5554    /* save the next sibling value offset */
 5555    ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
 5556    ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
 5557    if (unlikely(ctn == ctn_parent)) goto doc_end;
 5558
 5559    /* pop parent as current container */
 5560    ctn = ctn_parent;
 5561    ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
 5562    if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
 5563        goto obj_val_end;
 5564    } else {
 5565        goto arr_val_end;
 5566    }
 5567
 5568obj_begin:
 5569#if YYJSON_READER_DEPTH_LIMIT
 5570    ctn_depth++;
 5571    if (unlikely(ctn_depth >= (usize)YYJSON_READER_DEPTH_LIMIT)) {
 5572        goto fail_depth;
 5573    }
 5574#endif
 5575    /* push container */
 5576    ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
 5577               (ctn->tag & YYJSON_TAG_MASK);
 5578    val_incr();
 5579    val->tag = YYJSON_TYPE_OBJ;
 5580    /* offset to the parent */
 5581    val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
 5582    ctn = val;
 5583    ctn_len = 0;
 5584
 5585obj_key_begin:
 5586    if (likely(*cur == '"')) {
 5587        val_incr();
 5588        ctn_len++;
 5589        if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_key_end;
 5590        goto fail_string;
 5591    }
 5592    if (likely(*cur == '}')) {
 5593        cur++;
 5594        if (likely(ctn_len == 0)) goto obj_end;
 5595        if (has_allow(TRAILING_COMMAS)) goto obj_end;
 5596        do { cur--; } while (*cur != ',');
 5597        goto fail_trailing_comma;
 5598    }
 5599    if (char_is_space(*cur)) {
 5600        while (char_is_space(*++cur));
 5601        goto obj_key_begin;
 5602    }
 5603    if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
 5604        val_incr();
 5605        ctn_len++;
 5606        if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_key_end;
 5607        goto fail_string;
 5608    }
 5609    if (has_allow(UNQUOTED_KEY) && char_is_id_start(*cur)) {
 5610        val_incr();
 5611        ctn_len++;
 5612        if (read_str_id(&cur, eof, flg, pre, val, &msg)) goto obj_key_end;
 5613        goto fail_string;
 5614    }
 5615    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
 5616        if (skip_trivia(&cur, eof, flg)) goto obj_key_begin;
 5617        if (cur == eof) goto fail_comment;
 5618    }
 5619    goto fail_character_obj_key;
 5620
 5621obj_key_end:
 5622    if (*cur == ':') {
 5623        cur++;
 5624        goto obj_val_begin;
 5625    }
 5626    if (char_is_space(*cur)) {
 5627        while (char_is_space(*++cur));
 5628        goto obj_key_end;
 5629    }
 5630    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
 5631        if (skip_trivia(&cur, eof, flg)) goto obj_key_end;
 5632        if (cur == eof) goto fail_comment;
 5633    }
 5634    goto fail_character_obj_sep;
 5635
 5636obj_val_begin:
 5637    if (*cur == '"') {
 5638        val++;
 5639        ctn_len++;
 5640        if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_val_end;
 5641        goto fail_string;
 5642    }
 5643    if (char_is_num(*cur)) {
 5644        val++;
 5645        ctn_len++;
 5646        if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_end;
 5647        goto fail_number;
 5648    }
 5649    if (*cur == '{') {
 5650        cur++;
 5651        goto obj_begin;
 5652    }
 5653    if (*cur == '[') {
 5654        cur++;
 5655        goto arr_begin;
 5656    }
 5657    if (*cur == 't') {
 5658        val++;
 5659        ctn_len++;
 5660        if (likely(read_true(&cur, val))) goto obj_val_end;
 5661        goto fail_literal_true;
 5662    }
 5663    if (*cur == 'f') {
 5664        val++;
 5665        ctn_len++;
 5666        if (likely(read_false(&cur, val))) goto obj_val_end;
 5667        goto fail_literal_false;
 5668    }
 5669    if (*cur == 'n') {
 5670        val++;
 5671        ctn_len++;
 5672        if (likely(read_null(&cur, val))) goto obj_val_end;
 5673        if (has_allow(INF_AND_NAN)) {
 5674            if (read_nan(&cur, pre, flg, val)) goto obj_val_end;
 5675        }
 5676        goto fail_literal_null;
 5677    }
 5678    if (char_is_space(*cur)) {
 5679        while (char_is_space(*++cur));
 5680        goto obj_val_begin;
 5681    }
 5682    if (has_allow(INF_AND_NAN) &&
 5683        (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
 5684        val++;
 5685        ctn_len++;
 5686        if (read_inf_or_nan(&cur, pre, flg, val)) goto obj_val_end;
 5687        goto fail_character_val;
 5688    }
 5689    if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
 5690        val++;
 5691        ctn_len++;
 5692        if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_val_end;
 5693        goto fail_string;
 5694    }
 5695    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
 5696        if (skip_trivia(&cur, eof, flg)) goto obj_val_begin;
 5697        if (cur == eof) goto fail_comment;
 5698    }
 5699    goto fail_character_val;
 5700
 5701obj_val_end:
 5702    if (likely(*cur == ',')) {
 5703        cur++;
 5704        goto obj_key_begin;
 5705    }
 5706    if (likely(*cur == '}')) {
 5707        cur++;
 5708        goto obj_end;
 5709    }
 5710    if (char_is_space(*cur)) {
 5711        while (char_is_space(*++cur));
 5712        goto obj_val_end;
 5713    }
 5714    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
 5715        if (skip_trivia(&cur, eof, flg)) goto obj_val_end;
 5716        if (cur == eof) goto fail_comment;
 5717    }
 5718    goto fail_character_obj_end;
 5719
 5720obj_end:
 5721#if YYJSON_READER_DEPTH_LIMIT
 5722    ctn_depth--;
 5723#endif
 5724    /* pop container */
 5725    ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
 5726    /* point to the next value */
 5727    ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
 5728    ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
 5729    if (unlikely(ctn == ctn_parent)) goto doc_end;
 5730    ctn = ctn_parent;
 5731    ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
 5732    if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
 5733        goto obj_val_end;
 5734    } else {
 5735        goto arr_val_end;
 5736    }
 5737
 5738doc_end:
 5739    /* check invalid contents after json document */
 5740    if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) {
 5741        while (char_is_space(*cur)) cur++;
 5742        if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
 5743            if (!skip_trivia(&cur, eof, flg) && cur == eof) {
 5744                goto fail_comment;
 5745            }
 5746        }
 5747        if (unlikely(cur < eof)) goto fail_garbage;
 5748    }
 5749
 5750    **pre = '\0';
 5751    doc = (yyjson_doc *)val_hdr;
 5752    doc->root = val_hdr + hdr_len;
 5753    doc->alc = alc;
 5754    doc->dat_read = (usize)(cur - hdr);
 5755    doc->val_read = (usize)((val - doc->root) + 1);
 5756    doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
 5757    return doc;
 5758
 5759fail_string:            return_err(cur, INVALID_STRING, msg);
 5760fail_number:            return_err(cur, INVALID_NUMBER, msg);
 5761fail_alloc:             return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
 5762fail_trailing_comma:    return_err(cur, JSON_STRUCTURE, MSG_COMMA);
 5763fail_literal_true:      return_err(cur, LITERAL, MSG_CHAR_T);
 5764fail_literal_false:     return_err(cur, LITERAL, MSG_CHAR_F);
 5765fail_literal_null:      return_err(cur, LITERAL, MSG_CHAR_N);
 5766fail_character_val:     return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
 5767fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END);
 5768fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY);
 5769fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
 5770fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
 5771fail_comment:           return_err(cur, INVALID_COMMENT, MSG_COMMENT);
 5772fail_garbage:           return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
 5773fail_depth:             return_err(cur, DEPTH, MSG_DEPTH);
 5774
 5775#undef val_incr
 5776#undef return_err
 5777}
 5778
 5779/** Read JSON document (accept all style, but optimized for pretty). */
 5780static_inline yyjson_doc *read_root_pretty(u8 *hdr, u8 *cur, u8 *eof,
 5781                                           yyjson_alc alc,
 5782                                           yyjson_read_flag flg,
 5783                                           yyjson_read_err *err) {
 5784#define return_err(_pos, _code, _msg) do { \
 5785    if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \
 5786        err->pos = (usize)(eof - hdr); \
 5787        err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \
 5788        err->msg = MSG_NOT_END; \
 5789    } else { \
 5790        err->pos = (usize)(_pos - hdr); \
 5791        err->code = YYJSON_READ_ERROR_##_code; \
 5792        err->msg = _msg; \
 5793    } \
 5794    if (val_hdr) alc.free(alc.ctx, val_hdr); \
 5795    return NULL; \
 5796} while (false)
 5797
 5798#define val_incr() do { \
 5799    val++; \
 5800    if (unlikely(val >= val_end)) { \
 5801        usize alc_old = alc_len; \
 5802        usize val_ofs = (usize)(val - val_hdr); \
 5803        usize ctn_ofs = (usize)(ctn - val_hdr); \
 5804        alc_len += alc_len / 2; \
 5805        if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \
 5806        val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
 5807            alc_old * sizeof(yyjson_val), \
 5808            alc_len * sizeof(yyjson_val)); \
 5809        if ((!val_tmp)) goto fail_alloc; \
 5810        val = val_tmp + val_ofs; \
 5811        ctn = val_tmp + ctn_ofs; \
 5812        val_hdr = val_tmp; \
 5813        val_end = val_tmp + (alc_len - 2); \
 5814    } \
 5815} while (false)
 5816
 5817    usize dat_len; /* data length in bytes, hint for allocator */
 5818    usize hdr_len; /* value count used by yyjson_doc */
 5819    usize alc_len; /* value count allocated */
 5820    usize alc_max; /* maximum value count for allocator */
 5821    usize ctn_len; /* the number of elements in current container */
 5822    yyjson_val *val_hdr; /* the head of allocated values */
 5823    yyjson_val *val_end; /* the end of allocated values */
 5824    yyjson_val *val_tmp; /* temporary pointer for realloc */
 5825    yyjson_val *val; /* current JSON value */
 5826    yyjson_val *ctn; /* current container */
 5827    yyjson_val *ctn_parent; /* parent of current container */
 5828    yyjson_doc *doc; /* the JSON document, equals to val_hdr */
 5829    const char *msg; /* error message */
 5830
 5831    u8 raw_end[1]; /* raw end for null-terminator */
 5832    u8 *raw_ptr = raw_end;
 5833    u8 **pre = &raw_ptr; /* previous raw end pointer */
 5834#if YYJSON_READER_DEPTH_LIMIT
 5835    usize ctn_depth = 0; /* current array/object depth */
 5836#endif
 5837
 5838    dat_len = has_flg(STOP_WHEN_DONE) ? 256 : (usize)(eof - cur);
 5839    hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
 5840    hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
 5841    alc_max = USIZE_MAX / sizeof(yyjson_val);
 5842    alc_len = hdr_len + (dat_len / YYJSON_READER_ESTIMATED_PRETTY_RATIO) + 4;
 5843    alc_len = yyjson_min(alc_len, alc_max);
 5844
 5845    val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_len * sizeof(yyjson_val));
 5846    if (unlikely(!val_hdr)) goto fail_alloc;
 5847    val_end = val_hdr + (alc_len - 2); /* padding for key-value pair reading */
 5848    val = val_hdr + hdr_len;
 5849    ctn = val;
 5850    ctn_len = 0;
 5851
 5852    if (*cur++ == '{') {
 5853        ctn->tag = YYJSON_TYPE_OBJ;
 5854        ctn->uni.ofs = 0;
 5855        if (*cur == '\n') cur++;
 5856        goto obj_key_begin;
 5857    } else {
 5858        ctn->tag = YYJSON_TYPE_ARR;
 5859        ctn->uni.ofs = 0;
 5860        if (*cur == '\n') cur++;
 5861        goto arr_val_begin;
 5862    }
 5863
 5864arr_begin:
 5865#if YYJSON_READER_DEPTH_LIMIT
 5866    ctn_depth++;
 5867    if (unlikely(ctn_depth >= (usize)YYJSON_READER_DEPTH_LIMIT)) {
 5868        goto fail_depth;
 5869    }
 5870#endif
 5871
 5872    /* save current container */
 5873    ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
 5874               (ctn->tag & YYJSON_TAG_MASK);
 5875
 5876    /* create a new array value, save parent container offset */
 5877    val_incr();
 5878    val->tag = YYJSON_TYPE_ARR;
 5879    val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
 5880
 5881    /* push the new array value as current container */
 5882    ctn = val;
 5883    ctn_len = 0;
 5884    if (*cur == '\n') cur++;
 5885
 5886arr_val_begin:
 5887#if YYJSON_IS_REAL_GCC
 5888    while (true) repeat16({
 5889        if (byte_match_2(cur, "  ")) cur += 2;
 5890        else break;
 5891    })
 5892#else
 5893    while (true) repeat16({
 5894        if (likely(byte_match_2(cur, "  "))) cur += 2;
 5895        else break;
 5896    })
 5897#endif
 5898
 5899    if (*cur == '{') {
 5900        cur++;
 5901        goto obj_begin;
 5902    }
 5903    if (*cur == '[') {
 5904        cur++;
 5905        goto arr_begin;
 5906    }
 5907    if (char_is_num(*cur)) {
 5908        val_incr();
 5909        ctn_len++;
 5910        if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_end;
 5911        goto fail_number;
 5912    }
 5913    if (*cur == '"') {
 5914        val_incr();
 5915        ctn_len++;
 5916        if (likely(read_str(&cur, eof, flg, val, &msg))) goto arr_val_end;
 5917        goto fail_string;
 5918    }
 5919    if (*cur == 't') {
 5920        val_incr();
 5921        ctn_len++;
 5922        if (likely(read_true(&cur, val))) goto arr_val_end;
 5923        goto fail_literal_true;
 5924    }
 5925    if (*cur == 'f') {
 5926        val_incr();
 5927        ctn_len++;
 5928        if (likely(read_false(&cur, val))) goto arr_val_end;
 5929        goto fail_literal_false;
 5930    }
 5931    if (*cur == 'n') {
 5932        val_incr();
 5933        ctn_len++;
 5934        if (likely(read_null(&cur, val))) goto arr_val_end;
 5935        if (has_allow(INF_AND_NAN)) {
 5936            if (read_nan(&cur, pre, flg, val)) goto arr_val_end;
 5937        }
 5938        goto fail_literal_null;
 5939    }
 5940    if (*cur == ']') {
 5941        cur++;
 5942        if (likely(ctn_len == 0)) goto arr_end;
 5943        if (has_allow(TRAILING_COMMAS)) goto arr_end;
 5944        do { cur--; } while (*cur != ',');
 5945        goto fail_trailing_comma;
 5946    }
 5947    if (char_is_space(*cur)) {
 5948        while (char_is_space(*++cur));
 5949        goto arr_val_begin;
 5950    }
 5951    if (has_allow(INF_AND_NAN) &&
 5952        (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
 5953        val_incr();
 5954        ctn_len++;
 5955        if (read_inf_or_nan(&cur, pre, flg, val)) goto arr_val_end;
 5956        goto fail_character_val;
 5957    }
 5958    if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
 5959        val_incr();
 5960        ctn_len++;
 5961        if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto arr_val_end;
 5962        goto fail_string;
 5963    }
 5964    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
 5965        if (skip_trivia(&cur, eof, flg)) goto arr_val_begin;
 5966        if (cur == eof) goto fail_comment;
 5967    }
 5968    goto fail_character_val;
 5969
 5970arr_val_end:
 5971    if (byte_match_2(cur, ",\n")) {
 5972        cur += 2;
 5973        goto arr_val_begin;
 5974    }
 5975    if (*cur == ',') {
 5976        cur++;
 5977        goto arr_val_begin;
 5978    }
 5979    if (*cur == ']') {
 5980        cur++;
 5981        goto arr_end;
 5982    }
 5983    if (char_is_space(*cur)) {
 5984        while (char_is_space(*++cur));
 5985        goto arr_val_end;
 5986    }
 5987    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
 5988        if (skip_trivia(&cur, eof, flg)) goto arr_val_end;
 5989        if (cur == eof) goto fail_comment;
 5990    }
 5991    goto fail_character_arr_end;
 5992
 5993arr_end:
 5994#if YYJSON_READER_DEPTH_LIMIT
 5995    ctn_depth--;
 5996#endif
 5997    /* get parent container */
 5998    ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
 5999
 6000    /* save the next sibling value offset */
 6001    ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
 6002    ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
 6003    if (unlikely(ctn == ctn_parent)) goto doc_end;
 6004
 6005    /* pop parent as current container */
 6006    ctn = ctn_parent;
 6007    ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
 6008    if (*cur == '\n') cur++;
 6009    if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
 6010        goto obj_val_end;
 6011    } else {
 6012        goto arr_val_end;
 6013    }
 6014
 6015obj_begin:
 6016#if YYJSON_READER_DEPTH_LIMIT
 6017    ctn_depth++;
 6018    if (unlikely(ctn_depth >= (usize)YYJSON_READER_DEPTH_LIMIT)) {
 6019        goto fail_depth;
 6020    }
 6021#endif
 6022
 6023    /* push container */
 6024    ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
 6025               (ctn->tag & YYJSON_TAG_MASK);
 6026    val_incr();
 6027    val->tag = YYJSON_TYPE_OBJ;
 6028    /* offset to the parent */
 6029    val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
 6030    ctn = val;
 6031    ctn_len = 0;
 6032    if (*cur == '\n') cur++;
 6033
 6034obj_key_begin:
 6035#if YYJSON_IS_REAL_GCC
 6036    while (true) repeat16({
 6037        if (byte_match_2(cur, "  ")) cur += 2;
 6038        else break;
 6039    })
 6040#else
 6041    while (true) repeat16({
 6042        if (likely(byte_match_2(cur, "  "))) cur += 2;
 6043        else break;
 6044    })
 6045#endif
 6046    if (likely(*cur == '"')) {
 6047        val_incr();
 6048        ctn_len++;
 6049        if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_key_end;
 6050        goto fail_string;
 6051    }
 6052    if (likely(*cur == '}')) {
 6053        cur++;
 6054        if (likely(ctn_len == 0)) goto obj_end;
 6055        if (has_allow(TRAILING_COMMAS)) goto obj_end;
 6056        do { cur--; } while (*cur != ',');
 6057        goto fail_trailing_comma;
 6058    }
 6059    if (char_is_space(*cur)) {
 6060        while (char_is_space(*++cur));
 6061        goto obj_key_begin;
 6062    }
 6063    if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
 6064        val_incr();
 6065        ctn_len++;
 6066        if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_key_end;
 6067        goto fail_string;
 6068    }
 6069    if (has_allow(UNQUOTED_KEY) && char_is_id_start(*cur)) {
 6070        val_incr();
 6071        ctn_len++;
 6072        if (read_str_id(&cur, eof, flg, pre, val, &msg)) goto obj_key_end;
 6073        goto fail_string;
 6074    }
 6075    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
 6076        if (skip_trivia(&cur, eof, flg)) goto obj_key_begin;
 6077        if (cur == eof) goto fail_comment;
 6078    }
 6079    goto fail_character_obj_key;
 6080
 6081obj_key_end:
 6082    if (byte_match_2(cur, ": ")) {
 6083        cur += 2;
 6084        goto obj_val_begin;
 6085    }
 6086    if (*cur == ':') {
 6087        cur++;
 6088        goto obj_val_begin;
 6089    }
 6090    if (char_is_space(*cur)) {
 6091        while (char_is_space(*++cur));
 6092        goto obj_key_end;
 6093    }
 6094    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
 6095        if (skip_trivia(&cur, eof, flg)) goto obj_key_end;
 6096        if (cur == eof) goto fail_comment;
 6097    }
 6098    goto fail_character_obj_sep;
 6099
 6100obj_val_begin:
 6101    if (*cur == '"') {
 6102        val++;
 6103        ctn_len++;
 6104        if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_val_end;
 6105        goto fail_string;
 6106    }
 6107    if (char_is_num(*cur)) {
 6108        val++;
 6109        ctn_len++;
 6110        if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_end;
 6111        goto fail_number;
 6112    }
 6113    if (*cur == '{') {
 6114        cur++;
 6115        goto obj_begin;
 6116    }
 6117    if (*cur == '[') {
 6118        cur++;
 6119        goto arr_begin;
 6120    }
 6121    if (*cur == 't') {
 6122        val++;
 6123        ctn_len++;
 6124        if (likely(read_true(&cur, val))) goto obj_val_end;
 6125        goto fail_literal_true;
 6126    }
 6127    if (*cur == 'f') {
 6128        val++;
 6129        ctn_len++;
 6130        if (likely(read_false(&cur, val))) goto obj_val_end;
 6131        goto fail_literal_false;
 6132    }
 6133    if (*cur == 'n') {
 6134        val++;
 6135        ctn_len++;
 6136        if (likely(read_null(&cur, val))) goto obj_val_end;
 6137        if (has_allow(INF_AND_NAN)) {
 6138            if (read_nan(&cur, pre, flg, val)) goto obj_val_end;
 6139        }
 6140        goto fail_literal_null;
 6141    }
 6142    if (char_is_space(*cur)) {
 6143        while (char_is_space(*++cur));
 6144        goto obj_val_begin;
 6145    }
 6146    if (has_allow(INF_AND_NAN) &&
 6147        (*cur == 'i' || *cur == 'I' || *cur == 'N')) {
 6148        val++;
 6149        ctn_len++;
 6150        if (read_inf_or_nan(&cur, pre, flg, val)) goto obj_val_end;
 6151        goto fail_character_val;
 6152    }
 6153    if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') {
 6154        val++;
 6155        ctn_len++;
 6156        if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_val_end;
 6157        goto fail_string;
 6158    }
 6159    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
 6160        if (skip_trivia(&cur, eof, flg)) goto obj_val_begin;
 6161        if (cur == eof) goto fail_comment;
 6162    }
 6163    goto fail_character_val;
 6164
 6165obj_val_end:
 6166    if (byte_match_2(cur, ",\n")) {
 6167        cur += 2;
 6168        goto obj_key_begin;
 6169    }
 6170    if (likely(*cur == ',')) {
 6171        cur++;
 6172        goto obj_key_begin;
 6173    }
 6174    if (likely(*cur == '}')) {
 6175        cur++;
 6176        goto obj_end;
 6177    }
 6178    if (char_is_space(*cur)) {
 6179        while (char_is_space(*++cur));
 6180        goto obj_val_end;
 6181    }
 6182    if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
 6183        if (skip_trivia(&cur, eof, flg)) goto obj_val_end;
 6184        if (cur == eof) goto fail_comment;
 6185    }
 6186    goto fail_character_obj_end;
 6187
 6188obj_end:
 6189#if YYJSON_READER_DEPTH_LIMIT
 6190    ctn_depth--;
 6191#endif
 6192
 6193    /* pop container */
 6194    ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
 6195    /* point to the next value */
 6196    ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
 6197    ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
 6198    if (unlikely(ctn == ctn_parent)) goto doc_end;
 6199    ctn = ctn_parent;
 6200    ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
 6201    if (*cur == '\n') cur++;
 6202    if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
 6203        goto obj_val_end;
 6204    } else {
 6205        goto arr_val_end;
 6206    }
 6207
 6208doc_end:
 6209    /* check invalid contents after json document */
 6210    if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) {
 6211        while (char_is_space(*cur)) cur++;
 6212        if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
 6213            if (!skip_trivia(&cur, eof, flg) && cur == eof) {
 6214                goto fail_comment;
 6215            }
 6216        }
 6217        if (unlikely(cur < eof)) goto fail_garbage;
 6218    }
 6219
 6220    **pre = '\0';
 6221    doc = (yyjson_doc *)val_hdr;
 6222    doc->root = val_hdr + hdr_len;
 6223    doc->alc = alc;
 6224    doc->dat_read = (usize)(cur - hdr);
 6225    doc->val_read = (usize)((val - doc->root) + 1);
 6226    doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
 6227    return doc;
 6228
 6229fail_string:            return_err(cur, INVALID_STRING, msg);
 6230fail_number:            return_err(cur, INVALID_NUMBER, msg);
 6231fail_alloc:             return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
 6232fail_trailing_comma:    return_err(cur, JSON_STRUCTURE, MSG_COMMA);
 6233fail_literal_true:      return_err(cur, LITERAL, MSG_CHAR_T);
 6234fail_literal_false:     return_err(cur, LITERAL, MSG_CHAR_F);
 6235fail_literal_null:      return_err(cur, LITERAL, MSG_CHAR_N);
 6236fail_character_val:     return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
 6237fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END);
 6238fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY);
 6239fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
 6240fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
 6241fail_comment:           return_err(cur, INVALID_COMMENT, MSG_COMMENT);
 6242fail_garbage:           return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
 6243fail_depth:             return_err(cur, DEPTH, MSG_DEPTH);
 6244
 6245#undef val_incr
 6246#undef return_err
 6247}
 6248
 6249
 6250
 6251/*==============================================================================
 6252 * MARK: - JSON Reader (Public)
 6253 *============================================================================*/
 6254
 6255yyjson_doc *yyjson_read_opts(char *dat, usize len,
 6256                             yyjson_read_flag flg,
 6257                             const yyjson_alc *alc_ptr,
 6258                             yyjson_read_err *err) {
 6259#define return_err(_pos, _code, _msg) do { \
 6260    err->pos = (usize)(_pos); \
 6261    err->msg = _msg; \
 6262    err->code = YYJSON_READ_ERROR_##_code; \
 6263    if (!has_flg(INSITU) && hdr) alc.free(alc.ctx, (void *)hdr); \
 6264    return NULL; \
 6265} while (false)
 6266
 6267    yyjson_read_err tmp_err;
 6268    yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
 6269    yyjson_doc *doc;
 6270    u8 *hdr = NULL, *eof, *cur;
 6271
 6272    /* validate input parameters */
 6273    if (!err) err = &tmp_err;
 6274    if (unlikely(!dat)) return_err(0, INVALID_PARAMETER, "input data is NULL");
 6275    if (unlikely(!len)) return_err(0, INVALID_PARAMETER, "input length is 0");
 6276
 6277    /* add 4-byte zero padding for input data if necessary */
 6278    if (has_flg(INSITU)) {
 6279        hdr = (u8 *)dat;
 6280        eof = (u8 *)dat + len;
 6281        cur = (u8 *)dat;
 6282    } else {
 6283        if (unlikely(len >= USIZE_MAX - YYJSON_PADDING_SIZE)) {
 6284            return_err(0, MEMORY_ALLOCATION, MSG_MALLOC);
 6285        }
 6286        hdr = (u8 *)alc.malloc(alc.ctx, len + YYJSON_PADDING_SIZE);
 6287        if (unlikely(!hdr)) {
 6288            return_err(0, MEMORY_ALLOCATION, MSG_MALLOC);
 6289        }
 6290        eof = hdr + len;
 6291        cur = hdr;
 6292        memcpy(hdr, dat, len);
 6293    }
 6294    memset(eof, 0, YYJSON_PADDING_SIZE);
 6295
 6296    if (has_allow(BOM)) {
 6297        if (len >= 3 && is_utf8_bom(cur)) cur += 3;
 6298    }
 6299
 6300    /* skip empty contents before json document */
 6301    if (unlikely(!char_is_ctn(*cur))) {
 6302        while (char_is_space(*cur)) cur++;
 6303        if (unlikely(!char_is_ctn(*cur))) {
 6304            if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
 6305                if (!skip_trivia(&cur, eof, flg) && cur == eof) {
 6306                    return_err(cur - hdr, INVALID_COMMENT, MSG_COMMENT);
 6307                }
 6308            }
 6309        }
 6310        if (unlikely(cur >= eof)) {
 6311            return_err(0, EMPTY_CONTENT, "input data is empty");
 6312        }
 6313    }
 6314
 6315    /* read json document */
 6316    if (likely(char_is_ctn(*cur))) {
 6317        if (char_is_space(cur[1]) && char_is_space(cur[2])) {
 6318            doc = read_root_pretty(hdr, cur, eof, alc, flg, err);
 6319        } else {
 6320            doc = read_root_minify(hdr, cur, eof, alc, flg, err);
 6321        }
 6322    } else {
 6323        doc = read_root_single(hdr, cur, eof, alc, flg, err);
 6324    }
 6325
 6326    /* check result */
 6327    if (likely(doc)) {
 6328        memset(err, 0, sizeof(yyjson_read_err));
 6329    } else {
 6330        /* RFC 8259: JSON text MUST be encoded using UTF-8 */
 6331        if (err->pos == 0 && err->code != YYJSON_READ_ERROR_MEMORY_ALLOCATION) {
 6332            if (is_utf8_bom(hdr)) err->msg = MSG_ERR_BOM;
 6333            else if (len >= 4 && is_utf32_bom(hdr)) err->msg = MSG_ERR_UTF32;
 6334            else if (len >= 2 && is_utf16_bom(hdr)) err->msg = MSG_ERR_UTF16;
 6335        }
 6336        if (!has_flg(INSITU)) alc.free(alc.ctx, hdr);
 6337    }
 6338    return doc;
 6339
 6340#undef return_err
 6341}
 6342
 6343#if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE
 6344
 6345yyjson_doc *yyjson_read_file(const char *path,
 6346                             yyjson_read_flag flg,
 6347                             const yyjson_alc *alc_ptr,
 6348                             yyjson_read_err *err) {
 6349#define return_err(_code, _msg) do { \
 6350    err->pos = 0; \
 6351    err->msg = _msg; \
 6352    err->code = YYJSON_READ_ERROR_##_code; \
 6353    return NULL; \
 6354} while (false)
 6355
 6356    yyjson_read_err tmp_err;
 6357    yyjson_doc *doc;
 6358    FILE *file;
 6359
 6360    if (!err) err = &tmp_err;
 6361    if (unlikely(!path)) return_err(INVALID_PARAMETER, "input path is NULL");
 6362
 6363    file = fopen_readonly(path);
 6364    if (unlikely(!file)) return_err(FILE_OPEN, MSG_FREAD);
 6365
 6366    doc = yyjson_read_fp(file, flg, alc_ptr, err);
 6367    fclose(file);
 6368    return doc;
 6369
 6370#undef return_err
 6371}
 6372
 6373yyjson_doc *yyjson_read_fp(FILE *file,
 6374                           yyjson_read_flag flg,
 6375                           const yyjson_alc *alc_ptr,
 6376                           yyjson_read_err *err) {
 6377#define return_err(_code, _msg) do { \
 6378    err->pos = 0; \
 6379    err->msg = _msg; \
 6380    err->code = YYJSON_READ_ERROR_##_code; \
 6381    if (buf) alc.free(alc.ctx, buf); \
 6382    return NULL; \
 6383} while (false)
 6384
 6385    yyjson_read_err tmp_err;
 6386    yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
 6387    yyjson_doc *doc;
 6388
 6389    long file_size = 0, file_pos;
 6390    void *buf = NULL;
 6391    usize buf_size = 0;
 6392    usize dat_size = 0;
 6393
 6394    /* validate input parameters */
 6395    if (!err) err = &tmp_err;
 6396    if (unlikely(!file)) return_err(INVALID_PARAMETER, "input file is NULL");
 6397
 6398    /* get current position */
 6399    file_pos = ftell(file);
 6400    if (file_pos != -1) {
 6401        /* get total file size, may fail */
 6402        if (fseek(file, 0, SEEK_END) == 0) {
 6403            file_size = ftell(file);
 6404            if (file_size == -1) file_size = 0;
 6405        }
 6406        /* reset to original position, may fail */
 6407        if (fseek(file, file_pos, SEEK_SET) != 0) file_size = 0;
 6408        /* get file size from current position to end */
 6409        if (file_size > 0) file_size -= file_pos;
 6410    }
 6411
 6412    /* read file */
 6413    if (file_size > 0) {
 6414        /* read the entire file in one call */
 6415        dat_size = (usize)file_size;
 6416        buf_size = dat_size + YYJSON_PADDING_SIZE;
 6417        buf = alc.malloc(alc.ctx, buf_size);
 6418        if (buf == NULL) {
 6419            return_err(MEMORY_ALLOCATION, MSG_MALLOC);
 6420        }
 6421        if (fread_safe(buf, dat_size, file) != dat_size) {
 6422            return_err(FILE_READ, MSG_FREAD);
 6423        }
 6424    } else {
 6425        /* failed to get file size, read it as a stream */
 6426        usize chunk_min = (usize)64;
 6427        usize chunk_max = (usize)512 * 1024 * 1024;
 6428        usize chunk_now = chunk_min;
 6429        usize read_size;
 6430        void *tmp;
 6431
 6432        buf_size = YYJSON_PADDING_SIZE;
 6433        while (true) {
 6434            if (buf_size + chunk_now < buf_size) { /* overflow */
 6435                return_err(MEMORY_ALLOCATION, MSG_MALLOC);
 6436            }
 6437            buf_size += chunk_now;
 6438            if (!buf) {
 6439                buf = alc.malloc(alc.ctx, buf_size);
 6440                if (!buf) return_err(MEMORY_ALLOCATION, MSG_MALLOC);
 6441            } else {
 6442                tmp = alc.realloc(alc.ctx, buf, buf_size - chunk_now, buf_size);
 6443                if (!tmp) return_err(MEMORY_ALLOCATION, MSG_MALLOC);
 6444                buf = tmp;
 6445            }
 6446            tmp = ((u8 *)buf) + buf_size - YYJSON_PADDING_SIZE - chunk_now;
 6447            read_size = fread_safe(tmp, chunk_now, file);
 6448            dat_size += read_size;
 6449            if (read_size != chunk_now) {
 6450                if (ferror(file)) return_err(FILE_READ, MSG_FREAD);
 6451                break;
 6452            }
 6453
 6454            chunk_now *= 2;
 6455            if (chunk_now > chunk_max) chunk_now = chunk_max;
 6456        }
 6457    }
 6458
 6459    /* read JSON */
 6460    memset((u8 *)buf + dat_size, 0, YYJSON_PADDING_SIZE);
 6461    flg |= YYJSON_READ_INSITU;
 6462    doc = yyjson_read_opts((char *)buf, dat_size, flg, &alc, err);
 6463    if (doc) {
 6464        doc->str_pool = (char *)buf;
 6465        return doc;
 6466    } else {
 6467        alc.free(alc.ctx, buf);
 6468        return NULL;
 6469    }
 6470
 6471#undef return_err
 6472}
 6473
 6474#endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */
 6475
 6476const char *yyjson_read_number(const char *dat,
 6477                               yyjson_val *val,
 6478                               yyjson_read_flag flg,
 6479                               const yyjson_alc *alc,
 6480                               yyjson_read_err *err) {
 6481#define return_err(_pos, _code, _msg) do { \
 6482    err->pos = _pos > hdr ? (usize)(_pos - hdr) : 0; \
 6483    err->msg = _msg; \
 6484    err->code = YYJSON_READ_ERROR_##_code; \
 6485    return NULL; \
 6486} while (false)
 6487
 6488    u8 *hdr = constcast(u8 *)dat, *cur = hdr;
 6489    u8 raw_end[1]; /* raw end for null-terminator */
 6490    u8 *raw_ptr = raw_end;
 6491    u8 **pre = &raw_ptr; /* previous raw end pointer */
 6492    const char *msg;
 6493    yyjson_read_err tmp_err;
 6494
 6495#if YYJSON_DISABLE_FAST_FP_CONV
 6496    u8 buf[128];
 6497    usize dat_len;
 6498#endif
 6499
 6500    if (!err) err = &tmp_err;
 6501    if (unlikely(!dat)) {
 6502        return_err(cur, INVALID_PARAMETER, "input data is NULL");
 6503    }
 6504    if (unlikely(!val)) {
 6505        return_err(cur, INVALID_PARAMETER, "output value is NULL");
 6506    }
 6507
 6508#if YYJSON_DISABLE_FAST_FP_CONV
 6509    if (!alc) alc = &YYJSON_DEFAULT_ALC;
 6510    dat_len = strlen(dat);
 6511    if (dat_len < sizeof(buf)) {
 6512        memcpy(buf, dat, dat_len + 1);
 6513        hdr = buf;
 6514        cur = hdr;
 6515    } else {
 6516        hdr = (u8 *)alc->malloc(alc->ctx, dat_len + 1);
 6517        cur = hdr;
 6518        if (unlikely(!hdr)) {
 6519            return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
 6520        }
 6521        memcpy(hdr, dat, dat_len + 1);
 6522    }
 6523    hdr[dat_len] = 0;
 6524#endif
 6525
 6526#if YYJSON_DISABLE_FAST_FP_CONV
 6527    if (!read_num(&cur, pre, flg, val, &msg)) {
 6528        if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr);
 6529        return_err(cur, INVALID_NUMBER, msg);
 6530    }
 6531    if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr);
 6532    if (yyjson_is_raw(val)) val->uni.str = dat;
 6533    return dat + (cur - hdr);
 6534#else
 6535    if (!read_num(&cur, pre, flg, val, &msg)) {
 6536        return_err(cur, INVALID_NUMBER, msg);
 6537    }
 6538    return (const char *)cur;
 6539#endif
 6540
 6541#undef return_err
 6542}
 6543
 6544
 6545
 6546/*==============================================================================
 6547 * MARK: - Incremental JSON Reader (Public)
 6548 *============================================================================*/
 6549
 6550#if !YYJSON_DISABLE_INCR_READER
 6551
 6552/* labels within yyjson_incr_read() to resume incremental parsing */
 6553#define LABEL_doc_begin     0
 6554#define LABEL_arr_val_begin 1
 6555#define LABEL_arr_val_end   2
 6556#define LABEL_obj_key_begin 3
 6557#define LABEL_obj_key_end   4
 6558#define LABEL_obj_val_begin 5
 6559#define LABEL_obj_val_end   6
 6560#define LABEL_doc_end       7
 6561
 6562/** State for incremental JSON reader, opaque in the API. */
 6563struct yyjson_incr_state {
 6564    u32 label; /* current parser goto label */
 6565    yyjson_alc alc; /* allocator */
 6566    yyjson_read_flag flg; /* read flags */
 6567    u8 *hdr; /* JSON data header */
 6568    u8 *cur; /* current position in JSON data */
 6569    usize buf_len; /* total buffer length (without padding) */
 6570    usize hdr_len; /* value count used by yyjson_doc */
 6571    usize alc_len; /* value count allocated */
 6572    usize ctn_len; /* the number of elements in current container */
 6573#if YYJSON_READER_DEPTH_LIMIT
 6574    usize ctn_depth; /* current array/object depth */
 6575#endif
 6576    yyjson_val *val_hdr; /* the head of allocated values */
 6577    yyjson_val *val_end; /* the end of allocated values */
 6578    yyjson_val *val; /* current JSON value */
 6579    yyjson_val *ctn; /* current container */
 6580    u8 *str_con[2]; /* string parser incremental state */
 6581    u8 *raw_ptr; /* pending position for a deferred raw null-terminator */
 6582    u8 raw_end[1]; /* dummy target for the first deferred null-terminator */
 6583};
 6584
 6585yyjson_incr_state *yyjson_incr_new(char *buf, size_t buf_len,
 6586                                   yyjson_read_flag flg,
 6587                                   const yyjson_alc *alc_ptr) {
 6588    yyjson_incr_state *state = NULL;
 6589    yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
 6590
 6591    /* remove non-standard flags */
 6592    flg &= ~YYJSON_READ_JSON5;
 6593    flg &= ~YYJSON_READ_ALLOW_BOM;
 6594    flg &= ~YYJSON_READ_ALLOW_INVALID_UNICODE;
 6595
 6596    if (unlikely(!buf)) return NULL;
 6597    if (unlikely(buf_len >= USIZE_MAX - YYJSON_PADDING_SIZE)) return NULL;
 6598    state = (yyjson_incr_state *)alc.malloc(alc.ctx, sizeof(*state));
 6599    if (!state) return NULL;
 6600    memset(state, 0, sizeof(yyjson_incr_state));
 6601    state->alc = alc;
 6602    state->flg = flg;
 6603    state->buf_len = buf_len;
 6604
 6605    /* add 4-byte zero padding for input data if necessary */
 6606    if (has_flg(INSITU)) {
 6607        state->hdr = (u8 *)buf;
 6608    } else {
 6609        state->hdr = (u8 *)alc.malloc(alc.ctx, buf_len + YYJSON_PADDING_SIZE);
 6610        if (unlikely(!state->hdr)) {
 6611            alc.free(alc.ctx, state);
 6612            return NULL;
 6613        }
 6614        memcpy(state->hdr, buf, buf_len);
 6615    }
 6616    memset(state->hdr + buf_len, 0, YYJSON_PADDING_SIZE);
 6617    state->cur = state->hdr;
 6618    state->raw_ptr = state->raw_end;
 6619    state->label = LABEL_doc_begin;
 6620    return state;
 6621}
 6622
 6623void yyjson_incr_free(yyjson_incr_state *state) {
 6624    if (state) {
 6625        yyjson_alc alc = state->alc;
 6626        memset(&state->alc, 0, sizeof(alc));
 6627        if (state->val_hdr) {
 6628            alc.free(alc.ctx, (void *)state->val_hdr);
 6629        }
 6630        if (state->hdr && !(state->flg & YYJSON_READ_INSITU)) {
 6631            alc.free(alc.ctx, state->hdr);
 6632        }
 6633        alc.free(alc.ctx, state);
 6634    }
 6635}
 6636
 6637yyjson_doc *yyjson_incr_read(yyjson_incr_state *state, size_t len,
 6638                             yyjson_read_err *err) {
 6639#define return_err_inv_param(_msg) do { \
 6640    err->pos = 0; \
 6641    err->msg = _msg; \
 6642    err->code = YYJSON_READ_ERROR_INVALID_PARAMETER; \
 6643    return NULL; \
 6644} while (false)
 6645
 6646#define return_err(_pos, _code, _msg) do { \
 6647    if (is_truncated_end(hdr, _pos, end, YYJSON_READ_ERROR_##_code, flg)) { \
 6648        goto unexpected_end; \
 6649    } else { \
 6650        err->pos = (usize)(_pos - hdr); \
 6651        err->code = YYJSON_READ_ERROR_##_code; \
 6652        err->msg = _msg; \
 6653    } \
 6654    return NULL; \
 6655} while (false)
 6656
 6657#define val_incr() do { \
 6658    val++; \
 6659    if (unlikely(val >= val_end)) { \
 6660        usize alc_old = alc_len; \
 6661        alc_len += alc_len / 2; \
 6662        if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \
 6663        val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \
 6664                                            alc_old * sizeof(yyjson_val), \
 6665                                            alc_len * sizeof(yyjson_val)); \
 6666        if ((!val_tmp)) goto fail_alloc; \
 6667        val = val_tmp + (usize)(val - val_hdr); \
 6668        ctn = val_tmp + (usize)(ctn - val_hdr); \
 6669        state->val = val_tmp + (usize)(state->val - val_hdr); \
 6670        state->val_hdr = val_hdr = val_tmp; \
 6671        val_end = val_tmp + (alc_len - 2); \
 6672        state->val_end = val_end; \
 6673    } \
 6674} while (false)
 6675
 6676    /* save position where it's possible to resume incremental parsing */
 6677#if YYJSON_READER_DEPTH_LIMIT
 6678#define save_incr_depth() (state->ctn_depth = ctn_depth)
 6679#else
 6680#define save_incr_depth() ((void)0)
 6681#endif
 6682#define save_incr_state(_label) do { \
 6683    state->label = LABEL_##_label; \
 6684    state->cur = cur; \
 6685    state->val = val; \
 6686    state->ctn_len = ctn_len; \
 6687    save_incr_depth(); \
 6688    state->hdr_len = hdr_len; \
 6689    state->raw_ptr = raw_ptr; \
 6690    if (unlikely(cur >= end)) goto unexpected_end; \
 6691} while (false)
 6692
 6693#define check_maybe_truncated_number() do { \
 6694    if (unlikely(cur >= end)) { \
 6695        if (unlikely(cur > state->cur + INCR_NUM_MAX_LEN)) { \
 6696            msg = "number too long"; \
 6697            goto fail_number; \
 6698        } \
 6699        goto unexpected_end; \
 6700    } \
 6701} while (false)
 6702
 6703    u8 *hdr = NULL, *end = NULL, *cur = NULL;
 6704    yyjson_read_flag flg;
 6705    yyjson_alc alc;
 6706    usize dat_len; /* data length in bytes, hint for allocator */
 6707    usize hdr_len; /* value count used by yyjson_doc */
 6708    usize alc_len; /* value count allocated */
 6709    usize alc_max; /* maximum value count for allocator */
 6710    usize ctn_len; /* the number of elements in current container */
 6711    yyjson_val *val_hdr; /* the head of allocated values */
 6712    yyjson_val *val_end; /* the end of allocated values */
 6713    yyjson_val *val_tmp; /* temporary pointer for realloc */
 6714    yyjson_val *val; /* current JSON value */
 6715    yyjson_val *ctn; /* current container */
 6716    yyjson_val *ctn_parent; /* parent of current container */
 6717    yyjson_doc *doc; /* the JSON document, equals to val_hdr */
 6718    const char *msg; /* error message */
 6719
 6720    yyjson_read_err tmp_err;
 6721    u8 *raw_ptr; /* deferred raw null-terminator position, committed at save */
 6722    u8 **pre = &raw_ptr; /* previous raw end pointer */
 6723    u8 **con = NULL; /* for incremental string parsing */
 6724    u8 saved_end = '\0'; /* saved end char */
 6725
 6726#if YYJSON_READER_DEPTH_LIMIT
 6727    usize ctn_depth = 0; /* current array/object depth */
 6728#endif
 6729
 6730    /* validate input parameters */
 6731    if (!err) err = &tmp_err;
 6732    if (unlikely(!state)) {
 6733        return_err_inv_param("input state is NULL");
 6734    }
 6735    if (unlikely(!len)) {
 6736        return_err_inv_param("input length is 0");
 6737    }
 6738    if (unlikely(len > state->buf_len)) {
 6739        return_err_inv_param("length is greater than total input length");
 6740    }
 6741
 6742    /* restore state saved from the previous call */
 6743    hdr = state->hdr;
 6744    end = state->hdr + len;
 6745    cur = state->cur;
 6746    flg = state->flg;
 6747    alc = state->alc;
 6748    ctn_len = state->ctn_len;
 6749#if YYJSON_READER_DEPTH_LIMIT
 6750    ctn_depth = state->ctn_depth;
 6751#endif
 6752    hdr_len = state->hdr_len;
 6753    alc_len = state->alc_len;
 6754    val = state->val;
 6755    val_hdr = state->val_hdr;
 6756    val_end = state->val_end;
 6757    ctn = state->ctn;
 6758    con = state->str_con;
 6759    raw_ptr = state->raw_ptr;
 6760    alc_max = USIZE_MAX / sizeof(yyjson_val);
 6761
 6762    /* insert null terminator to make us stop at the specified end, even if
 6763       the data contains more valid JSON */
 6764    saved_end = *end;
 6765    *end = '\0';
 6766
 6767    /* resume parsing from the last save point */
 6768    switch (state->label) {
 6769    case LABEL_doc_begin: goto doc_begin;
 6770    case LABEL_arr_val_begin: goto arr_val_begin;
 6771    case LABEL_arr_val_end: goto arr_val_end;
 6772    case LABEL_obj_key_begin: goto obj_key_begin;
 6773    case LABEL_obj_key_end: goto obj_key_end;
 6774    case LABEL_obj_val_begin: goto obj_val_begin;
 6775    case LABEL_obj_val_end: goto obj_val_end;
 6776    case LABEL_doc_end: goto doc_end;
 6777    default: return_err_inv_param("invalid incremental state");
 6778    }
 6779
 6780doc_begin:
 6781    /* skip empty contents before json document */
 6782    if (unlikely(!char_is_ctn(*cur))) {
 6783        while (char_is_space(*cur)) cur++;
 6784        if (unlikely(cur >= end)) goto unexpected_end; /* input data is empty */
 6785    }
 6786
 6787    /* allocate memory for document */
 6788    if (!val_hdr) {
 6789        hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
 6790        hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
 6791        if (likely(char_is_ctn(*cur))) {
 6792            dat_len = has_flg(STOP_WHEN_DONE) ? 256 : state->buf_len;
 6793            alc_len = hdr_len +
 6794                    (dat_len / YYJSON_READER_ESTIMATED_MINIFY_RATIO) + 4;
 6795            alc_len = yyjson_min(alc_len, alc_max);
 6796        } else {
 6797            alc_len = hdr_len + 1; /* single value */
 6798        }
 6799        val_hdr = (yyjson_val *)alc.malloc(alc.ctx,
 6800                                           alc_len * sizeof(yyjson_val));
 6801        if (unlikely(!val_hdr)) goto fail_alloc;
 6802        val_end = val_hdr + (alc_len - 2); /* padding for kv pair reading */
 6803        val = val_hdr + hdr_len;
 6804        ctn = val;
 6805        ctn_len = 0;
 6806        state->val_hdr = val_hdr;
 6807        state->val_end = val_end;
 6808        save_incr_state(doc_begin);
 6809    }
 6810
 6811    /* read json document */
 6812    if (*cur == '{') {
 6813        cur++;
 6814        ctn->tag = YYJSON_TYPE_OBJ;
 6815        ctn->uni.ofs = 0;
 6816        goto obj_key_begin;
 6817    }
 6818    if (*cur == '[') {
 6819        cur++;
 6820        ctn->tag = YYJSON_TYPE_ARR;
 6821        ctn->uni.ofs = 0;
 6822        goto arr_val_begin;
 6823    }
 6824    if (char_is_num(*cur)) {
 6825        if (likely(read_num(&cur, pre, flg, val, &msg))) {
 6826            /* a root number may continue with more digits in a later chunk */
 6827            if (unlikely(len < state->buf_len)) check_maybe_truncated_number();
 6828            goto doc_end;
 6829        }
 6830        goto fail_number;
 6831    }
 6832    if (*cur == '"') {
 6833        if (likely(read_str_con(&cur, end, flg, val, &msg, con))) goto doc_end;
 6834        goto fail_string;
 6835    }
 6836    if (*cur == 't') {
 6837        if (likely(read_true(&cur, val))) goto doc_end;
 6838        goto fail_literal_true;
 6839    }
 6840    if (*cur == 'f') {
 6841        if (likely(read_false(&cur, val))) goto doc_end;
 6842        goto fail_literal_false;
 6843    }
 6844    if (*cur == 'n') {
 6845        if (likely(read_null(&cur, val))) goto doc_end;
 6846        goto fail_literal_null;
 6847    }
 6848
 6849    msg = "unexpected character, expected a valid root value";
 6850    if (cur == hdr) {
 6851        /* RFC 8259: JSON text MUST be encoded using UTF-8 */
 6852        if (is_utf8_bom(hdr)) msg = MSG_ERR_BOM;
 6853        else if (len >= 4 && is_utf32_bom(hdr)) msg = MSG_ERR_UTF32;
 6854        else if (len >= 2 && is_utf16_bom(hdr)) msg = MSG_ERR_UTF16;
 6855    }
 6856    return_err(cur, UNEXPECTED_CHARACTER, msg);
 6857
 6858arr_begin:
 6859#if YYJSON_READER_DEPTH_LIMIT
 6860    ctn_depth++;
 6861    if (unlikely(ctn_depth >= (usize)YYJSON_READER_DEPTH_LIMIT)) {
 6862        goto fail_depth;
 6863    }
 6864#endif
 6865
 6866    /* save current container */
 6867    ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
 6868               (ctn->tag & YYJSON_TAG_MASK);
 6869
 6870    /* create a new array value, save parent container offset */
 6871    val_incr();
 6872    val->tag = YYJSON_TYPE_ARR;
 6873    val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
 6874
 6875    /* push the new array value as current container */
 6876    ctn = val;
 6877    ctn_len = 0;
 6878
 6879arr_val_begin:
 6880    save_incr_state(arr_val_begin);
 6881arr_val_continue:
 6882    if (*cur == '{') {
 6883        cur++;
 6884        goto obj_begin;
 6885    }
 6886    if (*cur == '[') {
 6887        cur++;
 6888        goto arr_begin;
 6889    }
 6890    if (char_is_num(*cur)) {
 6891        val_incr();
 6892        ctn_len++;
 6893        if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_maybe_end;
 6894        goto fail_number;
 6895    }
 6896    if (*cur == '"') {
 6897        val_incr();
 6898        ctn_len++;
 6899        if (likely(read_str_con(&cur, end, flg, val, &msg, con)))
 6900            goto arr_val_end;
 6901        goto fail_string;
 6902    }
 6903    if (*cur == 't') {
 6904        val_incr();
 6905        ctn_len++;
 6906        if (likely(read_true(&cur, val))) goto arr_val_end;
 6907        goto fail_literal_true;
 6908    }
 6909    if (*cur == 'f') {
 6910        val_incr();
 6911        ctn_len++;
 6912        if (likely(read_false(&cur, val))) goto arr_val_end;
 6913        goto fail_literal_false;
 6914    }
 6915    if (*cur == 'n') {
 6916        val_incr();
 6917        ctn_len++;
 6918        if (likely(read_null(&cur, val))) goto arr_val_end;
 6919        goto fail_literal_null;
 6920    }
 6921    if (*cur == ']') {
 6922        cur++;
 6923        if (likely(ctn_len == 0)) goto arr_end;
 6924        do { cur--; } while (*cur != ',');
 6925        goto fail_trailing_comma;
 6926    }
 6927    if (char_is_space(*cur)) {
 6928        while (char_is_space(*++cur));
 6929        goto arr_val_continue;
 6930    }
 6931    goto fail_character_val;
 6932
 6933arr_val_maybe_end:
 6934    /* if incremental parsing stops in the middle of a number, it may continue
 6935       with more digits, so arr val maybe didn't end yet */
 6936    check_maybe_truncated_number();
 6937
 6938arr_val_end:
 6939    save_incr_state(arr_val_end);
 6940    if (*cur == ',') {
 6941        cur++;
 6942        goto arr_val_begin;
 6943    }
 6944    if (*cur == ']') {
 6945        cur++;
 6946        goto arr_end;
 6947    }
 6948    if (char_is_space(*cur)) {
 6949        while (char_is_space(*++cur));
 6950        goto arr_val_end;
 6951    }
 6952    goto fail_character_arr_end;
 6953
 6954arr_end:
 6955#if YYJSON_READER_DEPTH_LIMIT
 6956    ctn_depth--;
 6957#endif
 6958    /* get parent container */
 6959    ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
 6960
 6961    /* save the next sibling value offset */
 6962    ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
 6963    ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR;
 6964    if (unlikely(ctn == ctn_parent)) goto doc_end;
 6965
 6966    /* pop parent as current container */
 6967    ctn = ctn_parent;
 6968    ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
 6969    if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
 6970        goto obj_val_end;
 6971    } else {
 6972        goto arr_val_end;
 6973    }
 6974
 6975obj_begin:
 6976#if YYJSON_READER_DEPTH_LIMIT
 6977    ctn_depth++;
 6978    if (unlikely(ctn_depth >= (usize)YYJSON_READER_DEPTH_LIMIT)) {
 6979        goto fail_depth;
 6980    }
 6981#endif
 6982
 6983    /* push container */
 6984    ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
 6985               (ctn->tag & YYJSON_TAG_MASK);
 6986    val_incr();
 6987    val->tag = YYJSON_TYPE_OBJ;
 6988    /* offset to the parent */
 6989    val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
 6990    ctn = val;
 6991    ctn_len = 0;
 6992
 6993obj_key_begin:
 6994    save_incr_state(obj_key_begin);
 6995obj_key_continue:
 6996    if (likely(*cur == '"')) {
 6997        val_incr();
 6998        ctn_len++;
 6999        if (likely(read_str_con(&cur, end, flg, val, &msg, con)))
 7000            goto obj_key_end;
 7001        goto fail_string;
 7002    }
 7003    if (likely(*cur == '}')) {
 7004        cur++;
 7005        if (likely(ctn_len == 0)) goto obj_end;
 7006        do { cur--; } while (*cur != ',');
 7007        goto fail_trailing_comma;
 7008    }
 7009    if (char_is_space(*cur)) {
 7010        while (char_is_space(*++cur));
 7011        goto obj_key_continue;
 7012    }
 7013    goto fail_character_obj_key;
 7014
 7015obj_key_end:
 7016    save_incr_state(obj_key_end);
 7017    if (*cur == ':') {
 7018        cur++;
 7019        goto obj_val_begin;
 7020    }
 7021    if (char_is_space(*cur)) {
 7022        while (char_is_space(*++cur));
 7023        goto obj_key_end;
 7024    }
 7025    goto fail_character_obj_sep;
 7026
 7027obj_val_begin:
 7028    save_incr_state(obj_val_begin);
 7029obj_val_continue:
 7030    if (*cur == '"') {
 7031        val++;
 7032        ctn_len++;
 7033        if (likely(read_str_con(&cur, end, flg, val, &msg, con)))
 7034            goto obj_val_end;
 7035        goto fail_string;
 7036    }
 7037    if (char_is_num(*cur)) {
 7038        val++;
 7039        ctn_len++;
 7040        if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_maybe_end;
 7041        goto fail_number;
 7042    }
 7043    if (*cur == '{') {
 7044        cur++;
 7045        goto obj_begin;
 7046    }
 7047    if (*cur == '[') {
 7048        cur++;
 7049        goto arr_begin;
 7050    }
 7051    if (*cur == 't') {
 7052        val++;
 7053        ctn_len++;
 7054        if (likely(read_true(&cur, val))) goto obj_val_end;
 7055        goto fail_literal_true;
 7056    }
 7057    if (*cur == 'f') {
 7058        val++;
 7059        ctn_len++;
 7060        if (likely(read_false(&cur, val))) goto obj_val_end;
 7061        goto fail_literal_false;
 7062    }
 7063    if (*cur == 'n') {
 7064        val++;
 7065        ctn_len++;
 7066        if (likely(read_null(&cur, val))) goto obj_val_end;
 7067        goto fail_literal_null;
 7068    }
 7069    if (char_is_space(*cur)) {
 7070        while (char_is_space(*++cur));
 7071        goto obj_val_continue;
 7072    }
 7073    goto fail_character_val;
 7074
 7075obj_val_maybe_end:
 7076    /* if incremental parsing stops in the middle of a number, it may continue
 7077       with more digits, so obj val maybe didn't end yet */
 7078    check_maybe_truncated_number();
 7079
 7080obj_val_end:
 7081    save_incr_state(obj_val_end);
 7082    if (likely(*cur == ',')) {
 7083        cur++;
 7084        goto obj_key_begin;
 7085    }
 7086    if (likely(*cur == '}')) {
 7087        cur++;
 7088        goto obj_end;
 7089    }
 7090    if (char_is_space(*cur)) {
 7091        while (char_is_space(*++cur));
 7092        goto obj_val_end;
 7093    }
 7094    goto fail_character_obj_end;
 7095
 7096obj_end:
 7097#if YYJSON_READER_DEPTH_LIMIT
 7098    ctn_depth--;
 7099#endif
 7100
 7101    /* pop container */
 7102    ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
 7103    /* point to the next value */
 7104    ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val);
 7105    ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ;
 7106    if (unlikely(ctn == ctn_parent)) goto doc_end;
 7107    ctn = ctn_parent;
 7108    ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT);
 7109    if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) {
 7110        goto obj_val_end;
 7111    } else {
 7112        goto arr_val_end;
 7113    }
 7114
 7115doc_end:
 7116    /* check invalid contents after json document */
 7117    if (unlikely(cur < end || len < state->buf_len) &&
 7118        !has_flg(STOP_WHEN_DONE)) {
 7119        save_incr_state(doc_end);
 7120        while (char_is_space(*cur)) cur++;
 7121        if (unlikely(cur < end)) goto fail_garbage;
 7122        /* the document is complete for the bytes seen so far, but more input
 7123           is still pending; it may hold trailing content that has to be
 7124           rejected, so request the remaining data before finalizing */
 7125        if (unlikely(len < state->buf_len)) goto unexpected_end;
 7126    }
 7127
 7128    **pre = '\0';
 7129    doc = (yyjson_doc *)val_hdr;
 7130    doc->root = val_hdr + hdr_len;
 7131    doc->alc = alc;
 7132    doc->dat_read = (usize)(cur - hdr);
 7133    doc->val_read = (usize)((val - doc->root) + 1);
 7134    doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr;
 7135    state->hdr = NULL;
 7136    state->val_hdr = NULL;
 7137    memset(err, 0, sizeof(yyjson_read_err));
 7138    return doc;
 7139
 7140unexpected_end:
 7141    err->pos = len;
 7142    /* if no more data, stop the incr read */
 7143    if (unlikely(len >= state->buf_len)) {
 7144        err->code = YYJSON_READ_ERROR_UNEXPECTED_END;
 7145        err->msg = MSG_NOT_END;
 7146        return NULL;
 7147    }
 7148    /* save parser state in extended error struct, in addition to what was
 7149     * stored in the last save_incr_state */
 7150    err->code = YYJSON_READ_ERROR_MORE;
 7151    err->msg = "need more data";
 7152    state->val_end = val_end;
 7153    state->ctn = ctn;
 7154    state->alc_len = alc_len;
 7155    /* restore the end where we've inserted a null terminator */
 7156    *end = saved_end;
 7157    return NULL;
 7158
 7159fail_string:            return_err(cur, INVALID_STRING, msg);
 7160fail_number:            return_err(cur, INVALID_NUMBER, msg);
 7161fail_alloc:             return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC);
 7162fail_trailing_comma:    return_err(cur, JSON_STRUCTURE, MSG_COMMA);
 7163fail_literal_true:      return_err(cur, LITERAL, MSG_CHAR_T);
 7164fail_literal_false:     return_err(cur, LITERAL, MSG_CHAR_F);
 7165fail_literal_null:      return_err(cur, LITERAL, MSG_CHAR_N);
 7166fail_character_val:     return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
 7167fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END);
 7168fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY);
 7169fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
 7170fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
 7171fail_garbage:           return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
 7172fail_depth:             return_err(cur, DEPTH, MSG_DEPTH);
 7173
 7174#undef val_incr
 7175#undef return_err
 7176#undef return_err_inv_param
 7177#undef save_incr_state
 7178#undef save_incr_depth
 7179#undef check_maybe_truncated_number
 7180}
 7181
 7182#endif /* YYJSON_DISABLE_INCR_READER */
 7183
 7184#undef has_flg
 7185#undef has_allow
 7186#endif /* YYJSON_DISABLE_READER */
 7187
 7188
 7189
 7190#if !YYJSON_DISABLE_WRITER /* writer begin */
 7191
 7192/* Check write flag, avoids `always false` warning when disabled. */
 7193#define has_flg(_flg) unlikely(has_wflag(flg, YYJSON_WRITE_##_flg, 0))
 7194#define has_allow(_flg) unlikely(has_wflag(flg, YYJSON_WRITE_ALLOW_##_flg, 1))
 7195static_inline bool has_wflag(yyjson_write_flag flg, yyjson_write_flag chk,
 7196                             bool non_standard) {
 7197#if YYJSON_DISABLE_NON_STANDARD
 7198    if (non_standard) return false;
 7199#endif
 7200    return (flg & chk) != 0;
 7201}
 7202
 7203/*==============================================================================
 7204 * MARK: - Integer Writer (Private)
 7205 *
 7206 * The maximum value of uint32_t is 4294967295 (10 digits),
 7207 * these digits are named as 'aabbccddee' here.
 7208 *
 7209 * Although most compilers may convert the "division by constant value" into
 7210 * "multiply and shift", manual conversion can still help some compilers
 7211 * generate fewer and better instructions.
 7212 *
 7213 * Reference:
 7214 * Division by Invariant Integers using Multiplication, 1994.
 7215 * https://gmplib.org/~tege/divcnst-pldi94.pdf
 7216 * Improved division by invariant integers, 2011.
 7217 * https://gmplib.org/~tege/division-paper.pdf
 7218 *============================================================================*/
 7219
 7220/** Digit table from 00 to 99. */
 7221yyjson_align(2)
 7222static const char digit_table[200] = {
 7223    '0', '0', '0', '1', '0', '2', '0', '3', '0', '4',
 7224    '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
 7225    '1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
 7226    '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
 7227    '2', '0', '2', '1', '2', '2', '2', '3', '2', '4',
 7228    '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
 7229    '3', '0', '3', '1', '3', '2', '3', '3', '3', '4',
 7230    '3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
 7231    '4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
 7232    '4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
 7233    '5', '0', '5', '1', '5', '2', '5', '3', '5', '4',
 7234    '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
 7235    '6', '0', '6', '1', '6', '2', '6', '3', '6', '4',
 7236    '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
 7237    '7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
 7238    '7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
 7239    '8', '0', '8', '1', '8', '2', '8', '3', '8', '4',
 7240    '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
 7241    '9', '0', '9', '1', '9', '2', '9', '3', '9', '4',
 7242    '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'
 7243};
 7244
 7245static_inline u8 *write_u32_len_8(u32 val, u8 *buf) {
 7246    u32 aa, bb, cc, dd, aabb, ccdd;                 /* 8 digits: aabbccdd */
 7247    aabb = (u32)(((u64)val * 109951163) >> 40);     /* (val / 10000) */
 7248    ccdd = val - aabb * 10000;                      /* (val % 10000) */
 7249    aa = (aabb * 5243) >> 19;                       /* (aabb / 100) */
 7250    cc = (ccdd * 5243) >> 19;                       /* (ccdd / 100) */
 7251    bb = aabb - aa * 100;                           /* (aabb % 100) */
 7252    dd = ccdd - cc * 100;                           /* (ccdd % 100) */
 7253    byte_copy_2(buf + 0, digit_table + aa * 2);
 7254    byte_copy_2(buf + 2, digit_table + bb * 2);
 7255    byte_copy_2(buf + 4, digit_table + cc * 2);
 7256    byte_copy_2(buf + 6, digit_table + dd * 2);
 7257    return buf + 8;
 7258}
 7259
 7260static_inline u8 *write_u32_len_4(u32 val, u8 *buf) {
 7261    u32 aa, bb;                                     /* 4 digits: aabb */
 7262    aa = (val * 5243) >> 19;                        /* (val / 100) */
 7263    bb = val - aa * 100;                            /* (val % 100) */
 7264    byte_copy_2(buf + 0, digit_table + aa * 2);
 7265    byte_copy_2(buf + 2, digit_table + bb * 2);
 7266    return buf + 4;
 7267}
 7268
 7269static_inline u8 *write_u32_len_1_to_8(u32 val, u8 *buf) {
 7270    u32 aa, bb, cc, dd, aabb, bbcc, ccdd, lz;
 7271
 7272    if (val < 100) {                                /* 1-2 digits: aa */
 7273        lz = val < 10;                              /* leading zero: 0 or 1 */
 7274        byte_copy_2(buf + 0, digit_table + val * 2 + lz);
 7275        buf -= lz;
 7276        return buf + 2;
 7277
 7278    } else if (val < 10000) {                       /* 3-4 digits: aabb */
 7279        aa = (val * 5243) >> 19;                    /* (val / 100) */
 7280        bb = val - aa * 100;                        /* (val % 100) */
 7281        lz = aa < 10;                               /* leading zero: 0 or 1 */
 7282        byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
 7283        buf -= lz;
 7284        byte_copy_2(buf + 2, digit_table + bb * 2);
 7285        return buf + 4;
 7286
 7287    } else if (val < 1000000) {                     /* 5-6 digits: aabbcc */
 7288        aa = (u32)(((u64)val * 429497) >> 32);      /* (val / 10000) */
 7289        bbcc = val - aa * 10000;                    /* (val % 10000) */
 7290        bb = (bbcc * 5243) >> 19;                   /* (bbcc / 100) */
 7291        cc = bbcc - bb * 100;                       /* (bbcc % 100) */
 7292        lz = aa < 10;                               /* leading zero: 0 or 1 */
 7293        byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
 7294        buf -= lz;
 7295        byte_copy_2(buf + 2, digit_table + bb * 2);
 7296        byte_copy_2(buf + 4, digit_table + cc * 2);
 7297        return buf + 6;
 7298
 7299    } else {                                        /* 7-8 digits: aabbccdd */
 7300        aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
 7301        ccdd = val - aabb * 10000;                  /* (val % 10000) */
 7302        aa = (aabb * 5243) >> 19;                   /* (aabb / 100) */
 7303        cc = (ccdd * 5243) >> 19;                   /* (ccdd / 100) */
 7304        bb = aabb - aa * 100;                       /* (aabb % 100) */
 7305        dd = ccdd - cc * 100;                       /* (ccdd % 100) */
 7306        lz = aa < 10;                               /* leading zero: 0 or 1 */
 7307        byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
 7308        buf -= lz;
 7309        byte_copy_2(buf + 2, digit_table + bb * 2);
 7310        byte_copy_2(buf + 4, digit_table + cc * 2);
 7311        byte_copy_2(buf + 6, digit_table + dd * 2);
 7312        return buf + 8;
 7313    }
 7314}
 7315
 7316static_inline u8 *write_u32_len_5_to_8(u32 val, u8 *buf) {
 7317    u32 aa, bb, cc, dd, aabb, bbcc, ccdd, lz;
 7318
 7319    if (val < 1000000) {                            /* 5-6 digits: aabbcc */
 7320        aa = (u32)(((u64)val * 429497) >> 32);      /* (val / 10000) */
 7321        bbcc = val - aa * 10000;                    /* (val % 10000) */
 7322        bb = (bbcc * 5243) >> 19;                   /* (bbcc / 100) */
 7323        cc = bbcc - bb * 100;                       /* (bbcc % 100) */
 7324        lz = aa < 10;                               /* leading zero: 0 or 1 */
 7325        byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
 7326        buf -= lz;
 7327        byte_copy_2(buf + 2, digit_table + bb * 2);
 7328        byte_copy_2(buf + 4, digit_table + cc * 2);
 7329        return buf + 6;
 7330
 7331    } else {                                        /* 7-8 digits: aabbccdd */
 7332        aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */
 7333        ccdd = val - aabb * 10000;                  /* (val % 10000) */
 7334        aa = (aabb * 5243) >> 19;                   /* (aabb / 100) */
 7335        cc = (ccdd * 5243) >> 19;                   /* (ccdd / 100) */
 7336        bb = aabb - aa * 100;                       /* (aabb % 100) */
 7337        dd = ccdd - cc * 100;                       /* (ccdd % 100) */
 7338        lz = aa < 10;                               /* leading zero: 0 or 1 */
 7339        byte_copy_2(buf + 0, digit_table + aa * 2 + lz);
 7340        buf -= lz;
 7341        byte_copy_2(buf + 2, digit_table + bb * 2);
 7342        byte_copy_2(buf + 4, digit_table + cc * 2);
 7343        byte_copy_2(buf + 6, digit_table + dd * 2);
 7344        return buf + 8;
 7345    }
 7346}
 7347
 7348static_inline u8 *write_u64(u64 val, u8 *buf) {
 7349    u64 tmp, hgh;
 7350    u32 mid, low;
 7351
 7352    if (val < 100000000) {                          /* 1-8 digits */
 7353        buf = write_u32_len_1_to_8((u32)val, buf);
 7354        return buf;
 7355
 7356    } else if (val < (u64)100000000 * 100000000) {  /* 9-16 digits */
 7357        hgh = val / 100000000;                      /* (val / 100000000) */
 7358        low = (u32)(val - hgh * 100000000);         /* (val % 100000000) */
 7359        buf = write_u32_len_1_to_8((u32)hgh, buf);
 7360        buf = write_u32_len_8(low, buf);
 7361        return buf;
 7362
 7363    } else {                                        /* 17-20 digits */
 7364        tmp = val / 100000000;                      /* (val / 100000000) */
 7365        low = (u32)(val - tmp * 100000000);         /* (val % 100000000) */
 7366        hgh = (u32)(tmp / 10000);                   /* (tmp / 10000) */
 7367        mid = (u32)(tmp - hgh * 10000);             /* (tmp % 10000) */
 7368        buf = write_u32_len_5_to_8((u32)hgh, buf);
 7369        buf = write_u32_len_4(mid, buf);
 7370        buf = write_u32_len_8(low, buf);
 7371        return buf;
 7372    }
 7373}
 7374
 7375
 7376
 7377/*==============================================================================
 7378 * MARK: - Number Writer (Private)
 7379 *============================================================================*/
 7380
 7381#if !YYJSON_DISABLE_FAST_FP_CONV  /* FP_WRITER */
 7382
 7383/** Trailing zero count table for number 0 to 99.
 7384    (generated with misc/make_tables.c) */
 7385static const u8 dec_trailing_zero_table[] = {
 7386    2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 7387    1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 7388    1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 7389    1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 7390    1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 7391    1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 7392    1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 7393    1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 7394    1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 7395    1, 0, 0, 0, 0, 0, 0, 0, 0, 0
 7396};
 7397
 7398static_inline u8 *write_u64_len_1_to_16(u64 val, u8 *buf) {
 7399    u64 hgh;
 7400    u32 low;
 7401    if (val < 100000000) {                          /* 1-8 digits */
 7402        buf = write_u32_len_1_to_8((u32)val, buf);
 7403        return buf;
 7404    } else {                                        /* 9-16 digits */
 7405        hgh = val / 100000000;                      /* (val / 100000000) */
 7406        low = (u32)(val - hgh * 100000000);         /* (val % 100000000) */
 7407        buf = write_u32_len_1_to_8((u32)hgh, buf);
 7408        buf = write_u32_len_8(low, buf);
 7409        return buf;
 7410    }
 7411}
 7412
 7413static_inline u8 *write_u64_len_1_to_17(u64 val, u8 *buf) {
 7414    u64 hgh;
 7415    u32 mid, low, one;
 7416    if (val >= (u64)100000000 * 10000000) {         /* len: 16 to 17 */
 7417        hgh = val / 100000000;                      /* (val / 100000000) */
 7418        low = (u32)(val - hgh * 100000000);         /* (val % 100000000) */
 7419        one = (u32)(hgh / 100000000);               /* (hgh / 100000000) */
 7420        mid = (u32)(hgh - (u64)one * 100000000);    /* (hgh % 100000000) */
 7421        *buf = (u8)((u8)one + (u8)'0');
 7422        buf += one > 0;
 7423        buf = write_u32_len_8(mid, buf);
 7424        buf = write_u32_len_8(low, buf);
 7425        return buf;
 7426    } else if (val >= (u64)100000000){              /* len: 9 to 15 */
 7427        hgh = val / 100000000;                      /* (val / 100000000) */
 7428        low = (u32)(val - hgh * 100000000);         /* (val % 100000000) */
 7429        buf = write_u32_len_1_to_8((u32)hgh, buf);
 7430        buf = write_u32_len_8(low, buf);
 7431        return buf;
 7432    } else {                                        /* len: 1 to 8 */
 7433        buf = write_u32_len_1_to_8((u32)val, buf);
 7434        return buf;
 7435    }
 7436}
 7437
 7438/**
 7439 Write an unsigned integer with a length of 7 to 9 with trailing zero trimmed.
 7440 These digits are named as "abbccddee" here.
 7441 For example, input 123456000, output "123456".
 7442 */
 7443static_inline u8 *write_u32_len_7_to_9_trim(u32 val, u8 *buf) {
 7444    bool lz;
 7445    u32 tz, tz1, tz2;
 7446
 7447    u32 abbcc = val / 10000;                        /* (abbccddee / 10000) */
 7448    u32 ddee = val - abbcc * 10000;                 /* (abbccddee % 10000) */
 7449    u32 abb = (u32)(((u64)abbcc * 167773) >> 24);   /* (abbcc / 100) */
 7450    u32 a = (abb * 41) >> 12;                       /* (abb / 100) */
 7451    u32 bb = abb - a * 100;                         /* (abb % 100) */
 7452    u32 cc = abbcc - abb * 100;                     /* (abbcc % 100) */
 7453
 7454    /* write abbcc */
 7455    buf[0] = (u8)(a + '0');
 7456    buf += a > 0;
 7457    lz = bb < 10 && a == 0;
 7458    byte_copy_2(buf + 0, digit_table + bb * 2 + lz);
 7459    buf -= lz;
 7460    byte_copy_2(buf + 2, digit_table + cc * 2);
 7461
 7462    if (ddee) {
 7463        u32 dd = (ddee * 5243) >> 19;               /* (ddee / 100) */
 7464        u32 ee = ddee - dd * 100;                   /* (ddee % 100) */
 7465        byte_copy_2(buf + 4, digit_table + dd * 2);
 7466        byte_copy_2(buf + 6, digit_table + ee * 2);
 7467        tz1 = dec_trailing_zero_table[dd];
 7468        tz2 = dec_trailing_zero_table[ee];
 7469        tz = ee ? tz2 : (tz1 + 2);
 7470        buf += 8 - tz;
 7471        return buf;
 7472    } else {
 7473        tz1 = dec_trailing_zero_table[bb];
 7474        tz2 = dec_trailing_zero_table[cc];
 7475        tz = cc ? tz2 : (tz1 + tz2);
 7476        buf += 4 - tz;
 7477        return buf;
 7478    }
 7479}
 7480
 7481/**
 7482 Write an unsigned integer with a length of 16 or 17 with trailing zero trimmed.
 7483 These digits are named as "abbccddeeffgghhii" here.
 7484 For example, input 1234567890123000, output "1234567890123".
 7485 */
 7486static_inline u8 *write_u64_len_16_to_17_trim(u64 val, u8 *buf) {
 7487    u32 tz, tz1, tz2;
 7488
 7489    u32 abbccddee = (u32)(val / 100000000);
 7490    u32 ffgghhii = (u32)(val - (u64)abbccddee * 100000000);
 7491    u32 abbcc = abbccddee / 10000;
 7492    u32 ddee = abbccddee - abbcc * 10000;
 7493    u32 abb = (u32)(((u64)abbcc * 167773) >> 24);   /* (abbcc / 100) */
 7494    u32 a = (abb * 41) >> 12;                       /* (abb / 100) */
 7495    u32 bb = abb - a * 100;                         /* (abb % 100) */
 7496    u32 cc = abbcc - abb * 100;                     /* (abbcc % 100) */
 7497    buf[0] = (u8)(a + '0');
 7498    buf += a > 0;
 7499    byte_copy_2(buf + 0, digit_table + bb * 2);
 7500    byte_copy_2(buf + 2, digit_table + cc * 2);
 7501
 7502    if (ffgghhii) {
 7503        u32 dd = (ddee * 5243) >> 19;               /* (ddee / 100) */
 7504        u32 ee = ddee - dd * 100;                   /* (ddee % 100) */
 7505        u32 ffgg = (u32)(((u64)ffgghhii * 109951163) >> 40); /* (val / 10000) */
 7506        u32 hhii = ffgghhii - ffgg * 10000;         /* (val % 10000) */
 7507        u32 ff = (ffgg * 5243) >> 19;               /* (aabb / 100) */
 7508        u32 gg = ffgg - ff * 100;                   /* (aabb % 100) */
 7509        byte_copy_2(buf + 4, digit_table + dd * 2);
 7510        byte_copy_2(buf + 6, digit_table + ee * 2);
 7511        byte_copy_2(buf + 8, digit_table + ff * 2);
 7512        byte_copy_2(buf + 10, digit_table + gg * 2);
 7513        if (hhii) {
 7514            u32 hh = (hhii * 5243) >> 19;           /* (ccdd / 100) */
 7515            u32 ii = hhii - hh * 100;               /* (ccdd % 100) */
 7516            byte_copy_2(buf + 12, digit_table + hh * 2);
 7517            byte_copy_2(buf + 14, digit_table + ii * 2);
 7518            tz1 = dec_trailing_zero_table[hh];
 7519            tz2 = dec_trailing_zero_table[ii];
 7520            tz = ii ? tz2 : (tz1 + 2);
 7521            return buf + 16 - tz;
 7522        } else {
 7523            tz1 = dec_trailing_zero_table[ff];
 7524            tz2 = dec_trailing_zero_table[gg];
 7525            tz = gg ? tz2 : (tz1 + 2);
 7526            return buf + 12 - tz;
 7527        }
 7528    } else {
 7529        if (ddee) {
 7530            u32 dd = (ddee * 5243) >> 19;           /* (ddee / 100) */
 7531            u32 ee = ddee - dd * 100;               /* (ddee % 100) */
 7532            byte_copy_2(buf + 4, digit_table + dd * 2);
 7533            byte_copy_2(buf + 6, digit_table + ee * 2);
 7534            tz1 = dec_trailing_zero_table[dd];
 7535            tz2 = dec_trailing_zero_table[ee];
 7536            tz = ee ? tz2 : (tz1 + 2);
 7537            return buf + 8 - tz;
 7538        } else {
 7539            tz1 = dec_trailing_zero_table[bb];
 7540            tz2 = dec_trailing_zero_table[cc];
 7541            tz = cc ? tz2 : (tz1 + tz2);
 7542            return buf + 4 - tz;
 7543        }
 7544    }
 7545}
 7546
 7547/** Write exponent part in range `e-45` to `e38`. */
 7548static_inline u8 *write_f32_exp(i32 exp, u8 *buf) {
 7549    bool lz;
 7550    byte_copy_2(buf, "e-");
 7551    buf += 2 - (exp >= 0);
 7552    exp = exp < 0 ? -exp : exp;
 7553    lz = exp < 10;
 7554    byte_copy_2(buf + 0, digit_table + (u32)exp * 2 + lz);
 7555    return buf + 2 - lz;
 7556}
 7557
 7558/** Write exponent part in range `e-324` to `e308`. */
 7559static_inline u8 *write_f64_exp(i32 exp, u8 *buf) {
 7560    byte_copy_2(buf, "e-");
 7561    buf += 2 - (exp >= 0);
 7562    exp = exp < 0 ? -exp : exp;
 7563    if (exp < 100) {
 7564        bool lz = exp < 10;
 7565        byte_copy_2(buf + 0, digit_table + (u32)exp * 2 + lz);
 7566        return buf + 2 - lz;
 7567    } else {
 7568        u32 hi = ((u32)exp * 656) >> 16;    /* exp / 100 */
 7569        u32 lo = (u32)exp - hi * 100;       /* exp % 100 */
 7570        buf[0] = (u8)((u8)hi + (u8)'0');
 7571        byte_copy_2(buf + 1, digit_table + lo * 2);
 7572        return buf + 3;
 7573    }
 7574}
 7575
 7576/** Magic number for fast `divide by power of 10`. */
 7577typedef struct {
 7578    u64 p10, mul;
 7579    u32 shr1, shr2;
 7580} div_pow10_magic;
 7581
 7582/** Generated with llvm, see https://github.com/llvm/llvm-project/
 7583    blob/main/llvm/lib/Support/DivisionByConstantInfo.cpp */
 7584static const div_pow10_magic div_pow10_table[] = {
 7585    { U64(0x00000000, 0x00000001), U64(0x00000000, 0x00000000), 0,  0  },
 7586    { U64(0x00000000, 0x0000000A), U64(0xCCCCCCCC, 0xCCCCCCCD), 0,  3  },
 7587    { U64(0x00000000, 0x00000064), U64(0x28F5C28F, 0x5C28F5C3), 2,  2  },
 7588    { U64(0x00000000, 0x000003E8), U64(0x20C49BA5, 0xE353F7CF), 3,  4  },
 7589    { U64(0x00000000, 0x00002710), U64(0x346DC5D6, 0x3886594B), 0,  11 },
 7590    { U64(0x00000000, 0x000186A0), U64(0x0A7C5AC4, 0x71B47843), 5,  7  },
 7591    { U64(0x00000000, 0x000F4240), U64(0x431BDE82, 0xD7B634DB), 0,  18 },
 7592    { U64(0x00000000, 0x00989680), U64(0xD6BF94D5, 0xE57A42BD), 0,  23 },
 7593    { U64(0x00000000, 0x05F5E100), U64(0xABCC7711, 0x8461CEFD), 0,  26 },
 7594    { U64(0x00000000, 0x3B9ACA00), U64(0x0044B82F, 0xA09B5A53), 9,  11 },
 7595    { U64(0x00000002, 0x540BE400), U64(0xDBE6FECE, 0xBDEDD5BF), 0,  33 },
 7596    { U64(0x00000017, 0x4876E800), U64(0xAFEBFF0B, 0xCB24AAFF), 0,  36 },
 7597    { U64(0x000000E8, 0xD4A51000), U64(0x232F3302, 0x5BD42233), 0,  37 },
 7598    { U64(0x00000918, 0x4E72A000), U64(0x384B84D0, 0x92ED0385), 0,  41 },
 7599    { U64(0x00005AF3, 0x107A4000), U64(0x0B424DC3, 0x5095CD81), 0,  42 },
 7600    { U64(0x00038D7E, 0xA4C68000), U64(0x00024075, 0xF3DCEAC3), 15, 20 },
 7601    { U64(0x002386F2, 0x6FC10000), U64(0x39A5652F, 0xB1137857), 0,  51 },
 7602    { U64(0x01634578, 0x5D8A0000), U64(0x00005C3B, 0xD5191B53), 17, 22 },
 7603    { U64(0x0DE0B6B3, 0xA7640000), U64(0x000049C9, 0x7747490F), 18, 24 },
 7604    { U64(0x8AC72304, 0x89E80000), U64(0x760F253E, 0xDB4AB0d3), 0,  62 },
 7605};
 7606
 7607/** Divide a number by power of 10. */
 7608static_inline void div_pow10(u64 num, u32 exp, u64 *div, u64 *mod, u64 *p10) {
 7609    u64 hi, lo;
 7610    div_pow10_magic m = div_pow10_table[exp];
 7611    u128_mul(num >> m.shr1, m.mul, &hi, &lo);
 7612    *div = hi >> m.shr2;
 7613    *mod = num - (*div * m.p10);
 7614    *p10 = m.p10;
 7615}
 7616
 7617/** Multiplies 64-bit integer and returns highest 64-bit rounded value. */
 7618static_inline u32 u64_round_to_odd(u64 u, u32 cp) {
 7619    u64 hi, lo;
 7620    u32 y_hi, y_lo;
 7621    u128_mul(cp, u, &hi, &lo);
 7622    y_hi = (u32)hi;
 7623    y_lo = (u32)(lo >> 32);
 7624    return y_hi | (y_lo > 1);
 7625}
 7626
 7627/** Multiplies 128-bit integer and returns highest 64-bit rounded value. */
 7628static_inline u64 u128_round_to_odd(u64 hi, u64 lo, u64 cp) {
 7629    u64 x_hi, x_lo, y_hi, y_lo;
 7630    u128_mul(cp, lo, &x_hi, &x_lo);
 7631    u128_mul_add(cp, hi, x_hi, &y_hi, &y_lo);
 7632    return y_hi | (y_lo > 1);
 7633}
 7634
 7635/** Convert f32 from binary to decimal (shortest but may have trailing zeros).
 7636    The input should not be 0, inf or nan. */
 7637static_inline void f32_bin_to_dec(u32 sig_raw, u32 exp_raw,
 7638                                  u32 sig_bin, i32 exp_bin,
 7639                                  u32 *sig_dec, i32 *exp_dec) {
 7640
 7641    bool is_even, irregular, round_up, trim;
 7642    bool u0_inside, u1_inside, w0_inside, w1_inside;
 7643    u64 p10_hi, p10_lo, hi, lo;
 7644    u32 s, sp, cb, cbl, cbr, vb, vbl, vbr, upper, lower, mid;
 7645    i32 k, h;
 7646
 7647    /* Fast path, see f64_bin_to_dec(). */
 7648    while (likely(sig_raw)) {
 7649        u32 mod, dec, add_1, add_10, s_hi, s_lo;
 7650        u32 c, half_ulp, t0, t1;
 7651
 7652        /* k = floor(exp_bin * log10(2)); */
 7653        /* h = exp_bin + floor(log2(10) * -k); (h = 0/1/2/3) */
 7654        k = (i32)(exp_bin * 315653) >> 20;
 7655        h = exp_bin + ((-k * 217707) >> 16);
 7656        pow10_table_get_sig(-k, &p10_hi, &p10_lo);
 7657
 7658        /* sig_bin << (1/2/3/4) */
 7659        cb = sig_bin << (h + 1);
 7660        u128_mul(cb, p10_hi, &hi, &lo);
 7661        s_hi = (u32)(hi);
 7662        s_lo = (u32)(lo >> 32);
 7663        mod = s_hi % 10;
 7664        dec = s_hi - mod;
 7665
 7666        /* right shift 4 to fit in u32 */
 7667        c = (mod << (32 - 4)) | (s_lo >> 4);
 7668        half_ulp = (u32)(p10_hi >> (32 + 4 - h));
 7669
 7670        /* check w1, u0, w0 range */
 7671        w1_inside = (s_lo >= ((u32)1 << 31));
 7672        if (unlikely(s_lo == ((u32)1 << 31))) break;
 7673        u0_inside = (half_ulp >= c);
 7674        if (unlikely(half_ulp == c)) break;
 7675        t0 = (u32)10 << (32 - 4);
 7676        t1 = c + half_ulp;
 7677        w0_inside = (t1 >= t0);
 7678        if (unlikely(t0 - t1 <= (u32)1)) break;
 7679
 7680        trim = (u0_inside | w0_inside);
 7681        add_10 = (w0_inside ? 10 : 0);
 7682        add_1 = mod + w1_inside;
 7683        *sig_dec = dec + (trim ? add_10 : add_1);
 7684        *exp_dec = k;
 7685        return;
 7686    }
 7687
 7688    /* Schubfach algorithm, see f64_bin_to_dec(). */
 7689    irregular = (sig_raw == 0 && exp_raw > 1);
 7690    is_even = !(sig_bin & 1);
 7691    cbl = 4 * sig_bin - 2 + irregular;
 7692    cb  = 4 * sig_bin;
 7693    cbr = 4 * sig_bin + 2;
 7694
 7695    /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */
 7696    /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */
 7697    k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20;
 7698    h = exp_bin + ((-k * 217707) >> 16) + 1;
 7699    pow10_table_get_sig(-k, &p10_hi, &p10_lo);
 7700    p10_hi += 1;
 7701
 7702    vbl = u64_round_to_odd(p10_hi, cbl << h);
 7703    vb  = u64_round_to_odd(p10_hi, cb  << h);
 7704    vbr = u64_round_to_odd(p10_hi, cbr << h);
 7705    lower = vbl + !is_even;
 7706    upper = vbr - !is_even;
 7707
 7708    s = vb / 4;
 7709    if (s >= 10) {
 7710        sp = s / 10;
 7711        u0_inside = (lower <= 40 * sp);
 7712        w0_inside = (upper >= 40 * sp + 40);
 7713        if (u0_inside != w0_inside) {
 7714            *sig_dec = sp * 10 + (w0_inside ? 10 : 0);
 7715            *exp_dec = k;
 7716            return;
 7717        }
 7718    }
 7719    u1_inside = (lower <= 4 * s);
 7720    w1_inside = (upper >= 4 * s + 4);
 7721    mid = 4 * s + 2;
 7722    round_up = (vb > mid) || (vb == mid && (s & 1) != 0);
 7723    *sig_dec = s + ((u1_inside != w1_inside) ? w1_inside : round_up);
 7724    *exp_dec = k;
 7725}
 7726
 7727/** Convert f64 from binary to decimal (shortest but may have trailing zeros).
 7728    The input should not be 0, inf or nan. */
 7729static_inline void f64_bin_to_dec(u64 sig_raw, u32 exp_raw,
 7730                                  u64 sig_bin, i32 exp_bin,
 7731                                  u64 *sig_dec, i32 *exp_dec) {
 7732
 7733    bool is_even, irregular, round_up, trim;
 7734    bool u0_inside, u1_inside, w0_inside, w1_inside;
 7735    u64 s, sp, cb, cbl, cbr, vb, vbl, vbr, p10_hi, p10_lo, upper, lower, mid;
 7736    i32 k, h;
 7737
 7738    /*
 7739     Fast path:
 7740     For regular spacing significand 'c', there are 4 candidates:
 7741
 7742             u0             u1 c  w1                            w0
 7743     ----|----|----|----|----|-*--|----|----|----|----|----|----|----|----
 7744         9    0    1    2    3    4    5    6    7    8    9    0    1
 7745           |___________________|___________________|
 7746                             1ulp
 7747
 7748     The `1ulp` is in the range [1.0, 10.0).
 7749     If (c - 0.5ulp < u0), trim the last digit and round down.
 7750     If (c + 0.5ulp > w0), trim the last digit and round up.
 7751     If (c - 0.5ulp < u1), round down.
 7752     If (c + 0.5ulp > w1), round up.
 7753     */
 7754    while (likely(sig_raw)) {
 7755        u64 mod, dec, add_1, add_10, s_hi, s_lo;
 7756        u64 c, half_ulp, t0, t1;
 7757
 7758        /* k = floor(exp_bin * log10(2)); */
 7759        /* h = exp_bin + floor(log2(10) * -k); (h = 0/1/2/3) */
 7760        k = (i32)(exp_bin * 315653) >> 20;
 7761        h = exp_bin + ((-k * 217707) >> 16);
 7762        pow10_table_get_sig(-k, &p10_hi, &p10_lo);
 7763
 7764        /* sig_bin << (1/2/3/4) */
 7765        cb = sig_bin << (h + 1);
 7766        u128_mul(cb, p10_lo, &s_hi, &s_lo);
 7767        u128_mul_add(cb, p10_hi, s_hi, &s_hi, &s_lo);
 7768        mod = s_hi % 10;
 7769        dec = s_hi - mod;
 7770
 7771        /* right shift 4 to fit in u64 */
 7772        c = (mod << (64 - 4)) | (s_lo >> 4);
 7773        half_ulp = p10_hi >> (4 - h);
 7774
 7775        /* check w1, u0, w0 range */
 7776        w1_inside = (s_lo >= ((u64)1 << 63));
 7777        if (unlikely(s_lo == ((u64)1 << 63))) break;
 7778        u0_inside = (half_ulp >= c);
 7779        if (unlikely(half_ulp == c)) break;
 7780        t0 = ((u64)10 << (64 - 4));
 7781        t1 = c + half_ulp;
 7782        w0_inside = (t1 >= t0);
 7783        if (unlikely(t0 - t1 <= (u64)1)) break;
 7784
 7785        trim = (u0_inside | w0_inside);
 7786        add_10 = (w0_inside ? 10 : 0);
 7787        add_1 = mod + w1_inside;
 7788        *sig_dec = dec + (trim ? add_10 : add_1);
 7789        *exp_dec = k;
 7790        return;
 7791    }
 7792
 7793    /*
 7794     Schubfach algorithm:
 7795     Raffaello Giulietti, The Schubfach way to render doubles, 2022.
 7796     https://drive.google.com/file/d/1gp5xv4CAa78SVgCeWfGqqI4FfYYYuNFb (Paper)
 7797     https://github.com/openjdk/jdk/pull/3402 (Java implementation)
 7798     https://github.com/abolz/Drachennest (C++ implementation)
 7799     */
 7800    irregular = (sig_raw == 0 && exp_raw > 1);
 7801    is_even = !(sig_bin & 1);
 7802    cbl = 4 * sig_bin - 2 + irregular;
 7803    cb  = 4 * sig_bin;
 7804    cbr = 4 * sig_bin + 2;
 7805
 7806    /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */
 7807    /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */
 7808    k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20;
 7809    h = exp_bin + ((-k * 217707) >> 16) + 1;
 7810    pow10_table_get_sig(-k, &p10_hi, &p10_lo);
 7811    p10_lo += 1;
 7812
 7813    vbl = u128_round_to_odd(p10_hi, p10_lo, cbl << h);
 7814    vb  = u128_round_to_odd(p10_hi, p10_lo, cb  << h);
 7815    vbr = u128_round_to_odd(p10_hi, p10_lo, cbr << h);
 7816    lower = vbl + !is_even;
 7817    upper = vbr - !is_even;
 7818
 7819    s = vb / 4;
 7820    if (s >= 10) {
 7821        sp = s / 10;
 7822        u0_inside = (lower <= 40 * sp);
 7823        w0_inside = (upper >= 40 * sp + 40);
 7824        if (u0_inside != w0_inside) {
 7825            *sig_dec = sp * 10 + (w0_inside ? 10 : 0);
 7826            *exp_dec = k;
 7827            return;
 7828        }
 7829    }
 7830    u1_inside = (lower <= 4 * s);
 7831    w1_inside = (upper >= 4 * s + 4);
 7832    mid = 4 * s + 2;
 7833    round_up = (vb > mid) || (vb == mid && (s & 1) != 0);
 7834    *sig_dec = s + ((u1_inside != w1_inside) ? w1_inside : round_up);
 7835    *exp_dec = k;
 7836}
 7837
 7838/** Convert f64 from binary to decimal (fast but not the shortest).
 7839    The input should not be 0, inf, nan. */
 7840static_inline void f64_bin_to_dec_fast(u64 sig_raw, u32 exp_raw,
 7841                                       u64 sig_bin, i32 exp_bin,
 7842                                       u64 *sig_dec, i32 *exp_dec,
 7843                                       bool *round_up) {
 7844    u64 cb, p10_hi, p10_lo, s_hi, s_lo;
 7845    i32 k, h;
 7846    bool irregular, u;
 7847
 7848    irregular = (sig_raw == 0 && exp_raw > 1);
 7849
 7850    /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */
 7851    /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */
 7852    k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20;
 7853    h = exp_bin + ((-k * 217707) >> 16);
 7854    pow10_table_get_sig(-k, &p10_hi, &p10_lo);
 7855
 7856    /* sig_bin << (1/2/3/4) */
 7857    cb = sig_bin << (h + 1);
 7858    u128_mul(cb, p10_lo, &s_hi, &s_lo);
 7859    u128_mul_add(cb, p10_hi, s_hi, &s_hi, &s_lo);
 7860
 7861    /* round up */
 7862    u = s_lo >= (irregular ? U64(0x55555555, 0x55555555) : ((u64)1 << 63));
 7863
 7864    *sig_dec = s_hi + u;
 7865    *exp_dec = k;
 7866    *round_up = u;
 7867    return;
 7868}
 7869
 7870/** Write inf/nan if allowed. */
 7871static_inline u8 *write_inf_or_nan(u8 *buf, yyjson_write_flag flg,
 7872                                   u64 sig_raw, bool sign) {
 7873    if (has_flg(INF_AND_NAN_AS_NULL)) {
 7874        byte_copy_4(buf, "null");
 7875        return buf + 4;
 7876    }
 7877    if (has_allow(INF_AND_NAN)) {
 7878        if (sig_raw == 0) {
 7879            buf[0] = '-';
 7880            buf += sign;
 7881            byte_copy_8(buf, "Infinity");
 7882            return buf + 8;
 7883        } else {
 7884            byte_copy_4(buf, "NaN");
 7885            return buf + 3;
 7886        }
 7887    }
 7888    return NULL;
 7889}
 7890
 7891/**
 7892 Write a float number (requires 40 bytes buffer).
 7893 We follow the ECMAScript specification for printing floating-point numbers,
 7894 similar to `Number.prototype.toString()`, but with the following changes:
 7895 1. Keep the negative sign of `-0.0` to preserve input information.
 7896 2. Keep the decimal point to indicate that the number is floating-point.
 7897 3. Remove positive sign in the exponent part.
 7898 */
 7899static_noinline u8 *write_f32_raw(u8 *buf, u64 raw_f64,
 7900                                  yyjson_write_flag flg) {
 7901    u32 sig_bin, sig_dec, sig_raw;
 7902    i32 exp_bin, exp_dec, sig_len, dot_ofs;
 7903    u32 exp_raw, raw;
 7904    u8 *end;
 7905    bool sign;
 7906
 7907    /* cast double to float */
 7908    raw = f32_to_bits(f64_to_f32(f64_from_bits(raw_f64)));
 7909
 7910    /* decode raw bytes from IEEE-754 double format. */
 7911    sign = (bool)(raw >> (F32_BITS - 1));
 7912    sig_raw = raw & F32_SIG_MASK;
 7913    exp_raw = (raw & F32_EXP_MASK) >> F32_SIG_BITS;
 7914
 7915    /* return inf or nan */
 7916    if (unlikely(exp_raw == ((u32)1 << F32_EXP_BITS) - 1)) {
 7917        return write_inf_or_nan(buf, flg, sig_raw, sign);
 7918    }
 7919
 7920    /* add sign for all finite number */
 7921    buf[0] = '-';
 7922    buf += sign;
 7923
 7924    /* return zero */
 7925    if ((raw << 1) == 0) {
 7926        byte_copy_4(buf, "0.0");
 7927        return buf + 3;
 7928    }
 7929
 7930    if (likely(exp_raw != 0)) {
 7931        /* normal number */
 7932        sig_bin = sig_raw | ((u32)1 << F32_SIG_BITS);
 7933        exp_bin = (i32)exp_raw - F32_EXP_BIAS - F32_SIG_BITS;
 7934
 7935        /* fast path for small integer number without fraction */
 7936        if ((-F32_SIG_BITS <= exp_bin && exp_bin <= 0) &&
 7937            (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) {
 7938            sig_dec = sig_bin >> -exp_bin; /* range: [1, 0xFFFFFF] */
 7939            buf = write_u32_len_1_to_8(sig_dec, buf);
 7940            byte_copy_2(buf, ".0");
 7941            return buf + 2;
 7942        }
 7943
 7944        /* binary to decimal */
 7945        f32_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
 7946
 7947        /* the sig length is 7 or 9 */
 7948        sig_len = 7 + (sig_dec >= (u32)10000000) + (sig_dec >= (u32)100000000);
 7949
 7950        /* the decimal point offset relative to the first digit */
 7951        dot_ofs = sig_len + exp_dec;
 7952
 7953        if (-6 < dot_ofs && dot_ofs <= 21) {
 7954            i32 num_sep_pos, dot_set_pos, pre_ofs;
 7955            u8 *num_hdr, *num_end, *num_sep, *dot_end;
 7956            bool no_pre_zero;
 7957
 7958            /* fill zeros */
 7959            memset(buf, '0', 32);
 7960
 7961            /* not prefixed with zero, e.g. 1.234, 1234.0 */
 7962            no_pre_zero = (dot_ofs > 0);
 7963
 7964            /* write the number as digits */
 7965            pre_ofs = no_pre_zero ? 0 : (2 - dot_ofs);
 7966            num_hdr = buf + pre_ofs;
 7967            num_end = write_u32_len_7_to_9_trim(sig_dec, num_hdr);
 7968
 7969            /* separate these digits to leave a space for dot */
 7970            num_sep_pos = no_pre_zero ? dot_ofs : 0;
 7971            num_sep = num_hdr + num_sep_pos;
 7972            byte_move_8(num_sep + no_pre_zero, num_sep);
 7973            num_end += no_pre_zero;
 7974
 7975            /* write the dot */
 7976            dot_set_pos = yyjson_max(dot_ofs, 1);
 7977            buf[dot_set_pos] = '.';
 7978
 7979            /* return the ending */
 7980            dot_end = buf + dot_ofs + 2;
 7981            return yyjson_max(dot_end, num_end);
 7982
 7983        } else {
 7984            /* write with scientific notation, e.g. 1.234e56 */
 7985            end = write_u32_len_7_to_9_trim(sig_dec, buf + 1);
 7986            end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */
 7987            exp_dec += sig_len - 1;
 7988            buf[0] = buf[1];
 7989            buf[1] = '.';
 7990            return write_f32_exp(exp_dec, end);
 7991        }
 7992
 7993    } else {
 7994        /* subnormal number */
 7995        sig_bin = sig_raw;
 7996        exp_bin = 1 - F32_EXP_BIAS - F32_SIG_BITS;
 7997
 7998        /* binary to decimal */
 7999        f32_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
 8000
 8001        /* write significand part */
 8002        end = write_u32_len_1_to_8(sig_dec, buf + 1);
 8003        buf[0] = buf[1];
 8004        buf[1] = '.';
 8005        exp_dec += (i32)(end - buf) - 2;
 8006
 8007        /* trim trailing zeros */
 8008        end -= *(end - 1) == '0'; /* branchless for last zero */
 8009        end -= *(end - 1) == '0'; /* branchless for second last zero */
 8010        while (*(end - 1) == '0') end--; /* for unlikely more zeros */
 8011        end -= *(end - 1) == '.'; /* remove dot, e.g. 2.e-321 -> 2e-321 */
 8012
 8013        /* write exponent part */
 8014        return write_f32_exp(exp_dec, end);
 8015    }
 8016}
 8017
 8018/**
 8019 Write a double number (requires 40 bytes buffer).
 8020 We follow the ECMAScript specification for printing floating-point numbers,
 8021 similar to `Number.prototype.toString()`, but with the following changes:
 8022 1. Keep the negative sign of `-0.0` to preserve input information.
 8023 2. Keep the decimal point to indicate that the number is floating-point.
 8024 3. Remove positive sign in the exponent part.
 8025 */
 8026static_noinline u8 *write_f64_raw(u8 *buf, u64 raw, yyjson_write_flag flg) {
 8027    u64 sig_bin, sig_dec, sig_raw;
 8028    i32 exp_bin, exp_dec, sig_len, dot_ofs;
 8029    u32 exp_raw;
 8030    u8 *end;
 8031    bool sign;
 8032
 8033    /* decode raw bytes from IEEE-754 double format. */
 8034    sign = (bool)(raw >> (F64_BITS - 1));
 8035    sig_raw = raw & F64_SIG_MASK;
 8036    exp_raw = (u32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
 8037
 8038    /* return inf or nan */
 8039    if (unlikely(exp_raw == ((u32)1 << F64_EXP_BITS) - 1)) {
 8040        return write_inf_or_nan(buf, flg, sig_raw, sign);
 8041    }
 8042
 8043    /* add sign for all finite number */
 8044    buf[0] = '-';
 8045    buf += sign;
 8046
 8047    /* return zero */
 8048    if ((raw << 1) == 0) {
 8049        byte_copy_4(buf, "0.0");
 8050        return buf + 3;
 8051    }
 8052
 8053    if (likely(exp_raw != 0)) {
 8054        /* normal number */
 8055        sig_bin = sig_raw | ((u64)1 << F64_SIG_BITS);
 8056        exp_bin = (i32)exp_raw - F64_EXP_BIAS - F64_SIG_BITS;
 8057
 8058        /* fast path for small integer number without fraction */
 8059        if ((-F64_SIG_BITS <= exp_bin && exp_bin <= 0) &&
 8060            (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) {
 8061            sig_dec = sig_bin >> -exp_bin; /* range: [1, 0x1FFFFFFFFFFFFF] */
 8062            buf = write_u64_len_1_to_16(sig_dec, buf);
 8063            byte_copy_2(buf, ".0");
 8064            return buf + 2;
 8065        }
 8066
 8067        /* binary to decimal */
 8068        f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
 8069
 8070        /* the sig length is 16 or 17 */
 8071        sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
 8072
 8073        /* the decimal point offset relative to the first digit */
 8074        dot_ofs = sig_len + exp_dec;
 8075
 8076        if (-6 < dot_ofs && dot_ofs <= 21) {
 8077            i32 num_sep_pos, dot_set_pos, pre_ofs;
 8078            u8 *num_hdr, *num_end, *num_sep, *dot_end;
 8079            bool no_pre_zero;
 8080
 8081            /* fill zeros */
 8082            memset(buf, '0', 32);
 8083
 8084            /* not prefixed with zero, e.g. 1.234, 1234.0 */
 8085            no_pre_zero = (dot_ofs > 0);
 8086
 8087            /* write the number as digits */
 8088            pre_ofs = no_pre_zero ? 0 : (2 - dot_ofs);
 8089            num_hdr = buf + pre_ofs;
 8090            num_end = write_u64_len_16_to_17_trim(sig_dec, num_hdr);
 8091
 8092            /* separate these digits to leave a space for dot */
 8093            num_sep_pos = no_pre_zero ? dot_ofs : 0;
 8094            num_sep = num_hdr + num_sep_pos;
 8095            byte_move_16(num_sep + no_pre_zero, num_sep);
 8096            num_end += no_pre_zero;
 8097
 8098            /* write the dot */
 8099            dot_set_pos = yyjson_max(dot_ofs, 1);
 8100            buf[dot_set_pos] = '.';
 8101
 8102            /* return the ending */
 8103            dot_end = buf + dot_ofs + 2;
 8104            return yyjson_max(dot_end, num_end);
 8105
 8106        } else {
 8107            /* write with scientific notation, e.g. 1.234e56 */
 8108            end = write_u64_len_16_to_17_trim(sig_dec, buf + 1);
 8109            end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */
 8110            exp_dec += sig_len - 1;
 8111            buf[0] = buf[1];
 8112            buf[1] = '.';
 8113            return write_f64_exp(exp_dec, end);
 8114        }
 8115
 8116    } else {
 8117        /* subnormal number */
 8118        sig_bin = sig_raw;
 8119        exp_bin = 1 - F64_EXP_BIAS - F64_SIG_BITS;
 8120
 8121        /* binary to decimal */
 8122        f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec);
 8123
 8124        /* write significand part */
 8125        end = write_u64_len_1_to_17(sig_dec, buf + 1);
 8126        buf[0] = buf[1];
 8127        buf[1] = '.';
 8128        exp_dec += (i32)(end - buf) - 2;
 8129
 8130        /* trim trailing zeros */
 8131        end -= *(end - 1) == '0'; /* branchless for last zero */
 8132        end -= *(end - 1) == '0'; /* branchless for second last zero */
 8133        while (*(end - 1) == '0') end--; /* for unlikely more zeros */
 8134        end -= *(end - 1) == '.'; /* remove dot, e.g. 2.e-321 -> 2e-321 */
 8135
 8136        /* write exponent part */
 8137        return write_f64_exp(exp_dec, end);
 8138    }
 8139}
 8140
 8141/**
 8142 Write a double number using fixed-point notation (requires 40 bytes buffer).
 8143
 8144 We follow the ECMAScript specification for printing floating-point numbers,
 8145 similar to `Number.prototype.toFixed(prec)`, but with the following changes:
 8146 1. Keep the negative sign of `-0.0` to preserve input information.
 8147 2. Keep the decimal point to indicate that the number is floating-point.
 8148 3. Remove positive sign in the exponent part.
 8149 4. Remove trailing zeros and reduce unnecessary precision.
 8150 */
 8151static_noinline u8 *write_f64_raw_fixed(u8 *buf, u64 raw, yyjson_write_flag flg,
 8152                                        u32 prec) {
 8153    u64 sig_bin, sig_dec, sig_raw;
 8154    i32 exp_bin, exp_dec, sig_len, dot_ofs;
 8155    u32 exp_raw;
 8156    u8 *end;
 8157    bool sign;
 8158
 8159    /* decode raw bytes from IEEE-754 double format. */
 8160    sign = (bool)(raw >> (F64_BITS - 1));
 8161    sig_raw = raw & F64_SIG_MASK;
 8162    exp_raw = (u32)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
 8163
 8164    /* return inf or nan */
 8165    if (unlikely(exp_raw == ((u32)1 << F64_EXP_BITS) - 1)) {
 8166        return write_inf_or_nan(buf, flg, sig_raw, sign);
 8167    }
 8168
 8169    /* add sign for all finite number */
 8170    buf[0] = '-';
 8171    buf += sign;
 8172
 8173    /* return zero */
 8174    if ((raw << 1) == 0) {
 8175        byte_copy_4(buf, "0.0");
 8176        return buf + 3;
 8177    }
 8178
 8179    if (likely(exp_raw != 0)) {
 8180        /* normal number */
 8181        sig_bin = sig_raw | ((u64)1 << F64_SIG_BITS);
 8182        exp_bin = (i32)exp_raw - F64_EXP_BIAS - F64_SIG_BITS;
 8183
 8184        /* fast path for small integer number without fraction */
 8185        if ((-F64_SIG_BITS <= exp_bin && exp_bin <= 0) &&
 8186            (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) {
 8187            sig_dec = sig_bin >> -exp_bin; /* range: [1, 0x1FFFFFFFFFFFFF] */
 8188            buf = write_u64_len_1_to_16(sig_dec, buf);
 8189            byte_copy_2(buf, ".0");
 8190            return buf + 2;
 8191        }
 8192
 8193        /* only `fabs(num) < 1e21` are processed here. */
 8194        if ((raw << 1) < (U64(0x444B1AE4, 0xD6E2EF50) << 1)) {
 8195            i32 num_sep_pos, dot_set_pos, pre_ofs;
 8196            u8 *num_hdr, *num_end, *num_sep;
 8197            bool round_up, no_pre_zero;
 8198
 8199            /* binary to decimal */
 8200            f64_bin_to_dec_fast(sig_raw, exp_raw, sig_bin, exp_bin,
 8201                                &sig_dec, &exp_dec, &round_up);
 8202
 8203            /* the sig length is 16 or 17 */
 8204            sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
 8205
 8206            /* limit the length of digits after the decimal point */
 8207            if (exp_dec < -1) {
 8208                i32 sig_len_cut = -exp_dec - (i32)prec;
 8209                if (sig_len_cut > sig_len) {
 8210                    byte_copy_4(buf, "0.0");
 8211                    return buf + 3;
 8212                }
 8213                if (sig_len_cut > 0) {
 8214                    u64 div, mod, p10;
 8215
 8216                    /* remove round up */
 8217                    sig_dec -= round_up;
 8218                    sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
 8219
 8220                    /* cut off some digits */
 8221                    div_pow10(sig_dec, (u32)sig_len_cut, &div, &mod, &p10);
 8222
 8223                    /* add round up */
 8224                    sig_dec = div + (mod >= p10 / 2);
 8225
 8226                    /* update exp and sig length */
 8227                    exp_dec += sig_len_cut;
 8228                    sig_len -= sig_len_cut;
 8229                    sig_len += (sig_len >= 0) &&
 8230                               (sig_dec >= div_pow10_table[sig_len].p10);
 8231                }
 8232                if (sig_len <= 0) {
 8233                    byte_copy_4(buf, "0.0");
 8234                    return buf + 3;
 8235                }
 8236            }
 8237
 8238            /* fill zeros */
 8239            memset(buf, '0', 32);
 8240
 8241            /* the decimal point offset relative to the first digit */
 8242            dot_ofs = sig_len + exp_dec;
 8243
 8244            /* not prefixed with zero, e.g. 1.234, 1234.0 */
 8245            no_pre_zero = (dot_ofs > 0);
 8246
 8247            /* write the number as digits */
 8248            pre_ofs = no_pre_zero ? 0 : (1 - dot_ofs);
 8249            num_hdr = buf + pre_ofs;
 8250            num_end = write_u64_len_1_to_17(sig_dec, num_hdr);
 8251
 8252            /* separate these digits to leave a space for dot */
 8253            num_sep_pos = no_pre_zero ? dot_ofs : -dot_ofs;
 8254            num_sep = buf + num_sep_pos;
 8255            byte_move_16(num_sep + 1, num_sep);
 8256            num_end += (exp_dec < 0);
 8257
 8258            /* write the dot */
 8259            dot_set_pos = yyjson_max(dot_ofs, 1);
 8260            buf[dot_set_pos] = '.';
 8261
 8262            /* remove trailing zeros */
 8263            buf += dot_set_pos + 2;
 8264            buf = yyjson_max(buf, num_end);
 8265            buf -= *(buf - 1) == '0'; /* branchless for last zero */
 8266            buf -= *(buf - 1) == '0'; /* branchless for second last zero */
 8267            while (*(buf - 1) == '0') buf--; /* for unlikely more zeros */
 8268            buf += *(buf - 1) == '.'; /* keep a zero after dot */
 8269            return buf;
 8270
 8271        } else {
 8272            /* binary to decimal */
 8273            f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin,
 8274                           &sig_dec, &exp_dec);
 8275
 8276            /* the sig length is 16 or 17 */
 8277            sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000);
 8278
 8279            /* write with scientific notation, e.g. 1.234e56 */
 8280            end = write_u64_len_16_to_17_trim(sig_dec, buf + 1);
 8281            end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */
 8282            exp_dec += sig_len - 1;
 8283            buf[0] = buf[1];
 8284            buf[1] = '.';
 8285            return write_f64_exp(exp_dec, end);
 8286        }
 8287    } else {
 8288        /* subnormal number */
 8289        byte_copy_4(buf, "0.0");
 8290        return buf + 3;
 8291    }
 8292}
 8293
 8294#else /* FP_WRITER */
 8295
 8296#if YYJSON_MSC_VER >= 1400
 8297#define snprintf_num(buf, len, fmt, dig, val) \
 8298    sprintf_s((char *)buf, len, fmt, dig, val)
 8299#elif defined(snprintf) || (YYJSON_STDC_VER >= 199901L)
 8300#define snprintf_num(buf, len, fmt, dig, val) \
 8301    snprintf((char *)buf, len, fmt, dig, val)
 8302#else
 8303#define snprintf_num(buf, len, fmt, dig, val) \
 8304    sprintf((char *)buf, fmt, dig, val)
 8305#endif
 8306
 8307static_noinline u8 *write_fp_reformat(u8 *buf, int len,
 8308                                    yyjson_write_flag flg, bool fixed) {
 8309    u8 *cur = buf;
 8310    if (unlikely(len < 1)) return NULL;
 8311    cur += (*cur == '-');
 8312    if (unlikely(!char_is_digit(*cur))) {
 8313        /* nan, inf, or bad output */
 8314        if (has_flg(INF_AND_NAN_AS_NULL)) {
 8315            byte_copy_4(buf, "null");
 8316            return buf + 4;
 8317        } else if (has_allow(INF_AND_NAN)) {
 8318            if (*cur == 'i') {
 8319                byte_copy_8(cur, "Infinity");
 8320                return cur + 8;
 8321            } else if (*cur == 'n') {
 8322                byte_copy_4(buf, "NaN");
 8323                return buf + 3;
 8324            }
 8325        }
 8326        return NULL;
 8327    } else {
 8328        /* finite number */
 8329        u8 *end = buf + len, *dot = NULL, *exp = NULL;
 8330
 8331        /*
 8332         The snprintf() function is locale-dependent. For currently known
 8333         locales, (en, zh, ja, ko, am, he, hi) use '.' as the decimal point,
 8334         while other locales use ',' as the decimal point. we need to replace
 8335         ',' with '.' to avoid the locale setting.
 8336         */
 8337        for (; cur < end; cur++) {
 8338            switch (*cur) {
 8339                case ',': *cur = '.'; /* fallthrough */
 8340                case '.': dot = cur; break;
 8341                case 'e': exp = cur; break;
 8342                default: break;
 8343            }
 8344        }
 8345        if (fixed) {
 8346            /* remove trailing zeros */
 8347            while (*(end - 1) == '0') end--;
 8348            end += *(end - 1) == '.';
 8349        } else {
 8350            if (!dot && !exp) {
 8351                /* add decimal point, e.g. 123 -> 123.0 */
 8352                byte_copy_2(end, ".0");
 8353                end += 2;
 8354            } else if (exp) {
 8355                cur = exp + 1;
 8356                /* remove positive sign in the exponent part */
 8357                if (*cur == '+') {
 8358                    memmove(cur, cur + 1, (usize)(end - cur - 1));
 8359                    end--;
 8360                }
 8361                cur += (*cur == '-');
 8362                /* remove leading zeros in the exponent part */
 8363                if (*cur == '0') {
 8364                    u8 *hdr = cur++;
 8365                    while (*cur == '0') cur++;
 8366                    memmove(hdr, cur, (usize)(end - cur));
 8367                    end -= (usize)(cur - hdr);
 8368                }
 8369            }
 8370        }
 8371        return end;
 8372    }
 8373}
 8374
 8375/** Write a double number (requires 40 bytes buffer). */
 8376static_noinline u8 *write_f64_raw(u8 *buf, u64 raw, yyjson_write_flag flg) {
 8377#if defined(DBL_DECIMAL_DIG) && DBL_DECIMAL_DIG < F64_DEC_DIG
 8378    int dig = DBL_DECIMAL_DIG;
 8379#else
 8380    int dig = F64_DEC_DIG;
 8381#endif
 8382    f64 val = f64_from_bits(raw);
 8383    int len = snprintf_num(buf, FP_BUF_LEN, "%.*g", dig, val);
 8384    return write_fp_reformat(buf, len, flg, false);
 8385}
 8386
 8387/** Write a double number (requires 40 bytes buffer). */
 8388static_noinline u8 *write_f32_raw(u8 *buf, u64 raw, yyjson_write_flag flg) {
 8389#if defined(FLT_DECIMAL_DIG) && FLT_DECIMAL_DIG < F32_DEC_DIG
 8390    int dig = FLT_DECIMAL_DIG;
 8391#else
 8392    int dig = F32_DEC_DIG;
 8393#endif
 8394    f64 val = (f64)f64_to_f32(f64_from_bits(raw));
 8395    int len = snprintf_num(buf, FP_BUF_LEN, "%.*g", dig, val);
 8396    return write_fp_reformat(buf, len, flg, false);
 8397}
 8398
 8399/** Write a double number (requires 40 bytes buffer). */
 8400static_noinline u8 *write_f64_raw_fixed(u8 *buf, u64 raw,
 8401                                        yyjson_write_flag flg, u32 prec) {
 8402    f64 val = (f64)f64_from_bits(raw);
 8403    if (-1e21 < val && val < 1e21) {
 8404        int len = snprintf_num(buf, FP_BUF_LEN, "%.*f", (int)prec, val);
 8405        return write_fp_reformat(buf, len, flg, true);
 8406    } else {
 8407        return write_f64_raw(buf, raw, flg);
 8408    }
 8409}
 8410
 8411#endif /* FP_WRITER */
 8412
 8413/** Write a JSON number (requires 40 bytes buffer). */
 8414static_inline u8 *write_num(u8 *cur, yyjson_val *val, yyjson_write_flag flg) {
 8415    if (!(val->tag & YYJSON_SUBTYPE_REAL)) {
 8416        u64 pos = val->uni.u64;
 8417        u64 neg = ~pos + 1;
 8418        usize sign = ((val->tag & YYJSON_SUBTYPE_SINT) > 0) & ((i64)pos < 0);
 8419        *cur = '-';
 8420        return write_u64(sign ? neg : pos, cur + sign);
 8421    } else {
 8422        u64 raw = val->uni.u64;
 8423        u32 val_fmt = (u32)(val->tag >> 32);
 8424        u32 all_fmt = flg;
 8425        u32 fmt = val_fmt | all_fmt;
 8426        if (likely(!(fmt >> (32 - YYJSON_WRITE_FP_FLAG_BITS)))) {
 8427            /* double to shortest */
 8428            return write_f64_raw(cur, raw, flg);
 8429        } else if (fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS)) {
 8430            /* double to fixed */
 8431            u32 val_prec = val_fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS);
 8432            u32 all_prec = all_fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS);
 8433            u32 prec = val_prec ? val_prec : all_prec;
 8434            return write_f64_raw_fixed(cur, raw, flg, prec);
 8435        } else {
 8436            if (fmt & YYJSON_WRITE_FP_TO_FLOAT) {
 8437                /* float to shortest */
 8438                return write_f32_raw(cur, raw, flg);
 8439            } else {
 8440                /* double to shortest */
 8441                return write_f64_raw(cur, raw, flg);
 8442            }
 8443        }
 8444    }
 8445}
 8446
 8447char *yyjson_write_number(const yyjson_val *val, char *buf) {
 8448    if (unlikely(!val || !buf)) return NULL;
 8449    switch (val->tag & YYJSON_TAG_MASK) {
 8450        case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_UINT: {
 8451            buf = (char *)write_u64(val->uni.u64, (u8 *)buf);
 8452            *buf = '\0';
 8453            return buf;
 8454        }
 8455        case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_SINT: {
 8456            u64 pos = val->uni.u64;
 8457            u64 neg = ~pos + 1;
 8458            usize sign = ((i64)pos < 0);
 8459            *buf = '-';
 8460            buf = (char *)write_u64(sign ? neg : pos, (u8 *)buf + sign);
 8461            *buf = '\0';
 8462            return buf;
 8463        }
 8464        case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL: {
 8465            u64 raw = val->uni.u64;
 8466            u32 fmt = (u32)(val->tag >> 32);
 8467            u32 flg = YYJSON_WRITE_ALLOW_INF_AND_NAN;
 8468            if (likely(!(fmt >> (32 - YYJSON_WRITE_FP_FLAG_BITS)))) {
 8469                buf = (char *)write_f64_raw((u8 *)buf, raw, flg);
 8470            } else if (fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS)) {
 8471                u32 prec = fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS);
 8472                buf = (char *)write_f64_raw_fixed((u8 *)buf, raw, flg, prec);
 8473            } else {
 8474                if (fmt & YYJSON_WRITE_FP_TO_FLOAT) {
 8475                    buf = (char *)write_f32_raw((u8 *)buf, raw, flg);
 8476                } else {
 8477                    buf = (char *)write_f64_raw((u8 *)buf, raw, flg);
 8478                }
 8479            }
 8480            if (buf) *buf = '\0';
 8481            return buf;
 8482        }
 8483        default: return NULL;
 8484    }
 8485}
 8486
 8487
 8488
 8489/*==============================================================================
 8490 * MARK: - String Writer (Private)
 8491 *============================================================================*/
 8492
 8493/** Character encode type, if (type > CHAR_ENC_ERR_1) bytes = type / 2; */
 8494typedef u8 char_enc_type;
 8495#define CHAR_ENC_CPY_1  0 /* 1-byte UTF-8, copy. */
 8496#define CHAR_ENC_ERR_1  1 /* 1-byte UTF-8, error. */
 8497#define CHAR_ENC_ESC_A  2 /* 1-byte ASCII, escaped as '\x'. */
 8498#define CHAR_ENC_ESC_1  3 /* 1-byte UTF-8, escaped as '\uXXXX'. */
 8499#define CHAR_ENC_CPY_2  4 /* 2-byte UTF-8, copy. */
 8500#define CHAR_ENC_ESC_2  5 /* 2-byte UTF-8, escaped as '\uXXXX'. */
 8501#define CHAR_ENC_CPY_3  6 /* 3-byte UTF-8, copy. */
 8502#define CHAR_ENC_ESC_3  7 /* 3-byte UTF-8, escaped as '\uXXXX'. */
 8503#define CHAR_ENC_CPY_4  8 /* 4-byte UTF-8, copy. */
 8504#define CHAR_ENC_ESC_4  9 /* 4-byte UTF-8, escaped as '\uXXXX\uXXXX'. */
 8505
 8506/** Character encode type table: don't escape unicode, don't escape '/'.
 8507    (generated with misc/make_tables.c) */
 8508static const char_enc_type enc_table_cpy[256] = {
 8509    3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
 8510    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
 8511    0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 8512    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 8513    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 8514    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
 8515    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 8516    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 8517    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 8518    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 8519    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 8520    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 8521    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
 8522    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
 8523    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
 8524    8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1
 8525};
 8526
 8527/** Character encode type table: don't escape unicode, escape '/'.
 8528    (generated with misc/make_tables.c) */
 8529static const char_enc_type enc_table_cpy_slash[256] = {
 8530    3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
 8531    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
 8532    0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
 8533    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 8534    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 8535    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
 8536    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 8537    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 8538    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 8539    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 8540    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 8541    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 8542    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
 8543    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
 8544    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
 8545    8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1
 8546};
 8547
 8548/** Character encode type table: escape unicode, don't escape '/'.
 8549    (generated with misc/make_tables.c) */
 8550static const char_enc_type enc_table_esc[256] = {
 8551    3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
 8552    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
 8553    0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 8554    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 8555    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 8556    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
 8557    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 8558    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 8559    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 8560    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 8561    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 8562    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 8563    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
 8564    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
 8565    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
 8566    9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1
 8567};
 8568
 8569/** Character encode type table: escape unicode, escape '/'.
 8570    (generated with misc/make_tables.c) */
 8571static const char_enc_type enc_table_esc_slash[256] = {
 8572    3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3,
 8573    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
 8574    0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
 8575    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 8576    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 8577    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
 8578    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 8579    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 8580    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 8581    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 8582    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 8583    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 8584    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
 8585    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
 8586    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
 8587    9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1
 8588};
 8589
 8590/** Escaped hex character table: ["00" "01" "02" ... "FD" "FE" "FF"].
 8591    (generated with misc/make_tables.c) */
 8592yyjson_align(2)
 8593static const u8 esc_hex_char_table[512] = {
 8594    '0', '0', '0', '1', '0', '2', '0', '3',
 8595    '0', '4', '0', '5', '0', '6', '0', '7',
 8596    '0', '8', '0', '9', '0', 'A', '0', 'B',
 8597    '0', 'C', '0', 'D', '0', 'E', '0', 'F',
 8598    '1', '0', '1', '1', '1', '2', '1', '3',
 8599    '1', '4', '1', '5', '1', '6', '1', '7',
 8600    '1', '8', '1', '9', '1', 'A', '1', 'B',
 8601    '1', 'C', '1', 'D', '1', 'E', '1', 'F',
 8602    '2', '0', '2', '1', '2', '2', '2', '3',
 8603    '2', '4', '2', '5', '2', '6', '2', '7',
 8604    '2', '8', '2', '9', '2', 'A', '2', 'B',
 8605    '2', 'C', '2', 'D', '2', 'E', '2', 'F',
 8606    '3', '0', '3', '1', '3', '2', '3', '3',
 8607    '3', '4', '3', '5', '3', '6', '3', '7',
 8608    '3', '8', '3', '9', '3', 'A', '3', 'B',
 8609    '3', 'C', '3', 'D', '3', 'E', '3', 'F',
 8610    '4', '0', '4', '1', '4', '2', '4', '3',
 8611    '4', '4', '4', '5', '4', '6', '4', '7',
 8612    '4', '8', '4', '9', '4', 'A', '4', 'B',
 8613    '4', 'C', '4', 'D', '4', 'E', '4', 'F',
 8614    '5', '0', '5', '1', '5', '2', '5', '3',
 8615    '5', '4', '5', '5', '5', '6', '5', '7',
 8616    '5', '8', '5', '9', '5', 'A', '5', 'B',
 8617    '5', 'C', '5', 'D', '5', 'E', '5', 'F',
 8618    '6', '0', '6', '1', '6', '2', '6', '3',
 8619    '6', '4', '6', '5', '6', '6', '6', '7',
 8620    '6', '8', '6', '9', '6', 'A', '6', 'B',
 8621    '6', 'C', '6', 'D', '6', 'E', '6', 'F',
 8622    '7', '0', '7', '1', '7', '2', '7', '3',
 8623    '7', '4', '7', '5', '7', '6', '7', '7',
 8624    '7', '8', '7', '9', '7', 'A', '7', 'B',
 8625    '7', 'C', '7', 'D', '7', 'E', '7', 'F',
 8626    '8', '0', '8', '1', '8', '2', '8', '3',
 8627    '8', '4', '8', '5', '8', '6', '8', '7',
 8628    '8', '8', '8', '9', '8', 'A', '8', 'B',
 8629    '8', 'C', '8', 'D', '8', 'E', '8', 'F',
 8630    '9', '0', '9', '1', '9', '2', '9', '3',
 8631    '9', '4', '9', '5', '9', '6', '9', '7',
 8632    '9', '8', '9', '9', '9', 'A', '9', 'B',
 8633    '9', 'C', '9', 'D', '9', 'E', '9', 'F',
 8634    'A', '0', 'A', '1', 'A', '2', 'A', '3',
 8635    'A', '4', 'A', '5', 'A', '6', 'A', '7',
 8636    'A', '8', 'A', '9', 'A', 'A', 'A', 'B',
 8637    'A', 'C', 'A', 'D', 'A', 'E', 'A', 'F',
 8638    'B', '0', 'B', '1', 'B', '2', 'B', '3',
 8639    'B', '4', 'B', '5', 'B', '6', 'B', '7',
 8640    'B', '8', 'B', '9', 'B', 'A', 'B', 'B',
 8641    'B', 'C', 'B', 'D', 'B', 'E', 'B', 'F',
 8642    'C', '0', 'C', '1', 'C', '2', 'C', '3',
 8643    'C', '4', 'C', '5', 'C', '6', 'C', '7',
 8644    'C', '8', 'C', '9', 'C', 'A', 'C', 'B',
 8645    'C', 'C', 'C', 'D', 'C', 'E', 'C', 'F',
 8646    'D', '0', 'D', '1', 'D', '2', 'D', '3',
 8647    'D', '4', 'D', '5', 'D', '6', 'D', '7',
 8648    'D', '8', 'D', '9', 'D', 'A', 'D', 'B',
 8649    'D', 'C', 'D', 'D', 'D', 'E', 'D', 'F',
 8650    'E', '0', 'E', '1', 'E', '2', 'E', '3',
 8651    'E', '4', 'E', '5', 'E', '6', 'E', '7',
 8652    'E', '8', 'E', '9', 'E', 'A', 'E', 'B',
 8653    'E', 'C', 'E', 'D', 'E', 'E', 'E', 'F',
 8654    'F', '0', 'F', '1', 'F', '2', 'F', '3',
 8655    'F', '4', 'F', '5', 'F', '6', 'F', '7',
 8656    'F', '8', 'F', '9', 'F', 'A', 'F', 'B',
 8657    'F', 'C', 'F', 'D', 'F', 'E', 'F', 'F'
 8658};
 8659
 8660/** Lowercase variant of esc_hex_char_table. */
 8661yyjson_align(2)
 8662static const u8 esc_hex_char_table_lower[512] = {
 8663    '0', '0', '0', '1', '0', '2', '0', '3',
 8664    '0', '4', '0', '5', '0', '6', '0', '7',
 8665    '0', '8', '0', '9', '0', 'a', '0', 'b',
 8666    '0', 'c', '0', 'd', '0', 'e', '0', 'f',
 8667    '1', '0', '1', '1', '1', '2', '1', '3',
 8668    '1', '4', '1', '5', '1', '6', '1', '7',
 8669    '1', '8', '1', '9', '1', 'a', '1', 'b',
 8670    '1', 'c', '1', 'd', '1', 'e', '1', 'f',
 8671    '2', '0', '2', '1', '2', '2', '2', '3',
 8672    '2', '4', '2', '5', '2', '6', '2', '7',
 8673    '2', '8', '2', '9', '2', 'a', '2', 'b',
 8674    '2', 'c', '2', 'd', '2', 'e', '2', 'f',
 8675    '3', '0', '3', '1', '3', '2', '3', '3',
 8676    '3', '4', '3', '5', '3', '6', '3', '7',
 8677    '3', '8', '3', '9', '3', 'a', '3', 'b',
 8678    '3', 'c', '3', 'd', '3', 'e', '3', 'f',
 8679    '4', '0', '4', '1', '4', '2', '4', '3',
 8680    '4', '4', '4', '5', '4', '6', '4', '7',
 8681    '4', '8', '4', '9', '4', 'a', '4', 'b',
 8682    '4', 'c', '4', 'd', '4', 'e', '4', 'f',
 8683    '5', '0', '5', '1', '5', '2', '5', '3',
 8684    '5', '4', '5', '5', '5', '6', '5', '7',
 8685    '5', '8', '5', '9', '5', 'a', '5', 'b',
 8686    '5', 'c', '5', 'd', '5', 'e', '5', 'f',
 8687    '6', '0', '6', '1', '6', '2', '6', '3',
 8688    '6', '4', '6', '5', '6', '6', '6', '7',
 8689    '6', '8', '6', '9', '6', 'a', '6', 'b',
 8690    '6', 'c', '6', 'd', '6', 'e', '6', 'f',
 8691    '7', '0', '7', '1', '7', '2', '7', '3',
 8692    '7', '4', '7', '5', '7', '6', '7', '7',
 8693    '7', '8', '7', '9', '7', 'a', '7', 'b',
 8694    '7', 'c', '7', 'd', '7', 'e', '7', 'f',
 8695    '8', '0', '8', '1', '8', '2', '8', '3',
 8696    '8', '4', '8', '5', '8', '6', '8', '7',
 8697    '8', '8', '8', '9', '8', 'a', '8', 'b',
 8698    '8', 'c', '8', 'd', '8', 'e', '8', 'f',
 8699    '9', '0', '9', '1', '9', '2', '9', '3',
 8700    '9', '4', '9', '5', '9', '6', '9', '7',
 8701    '9', '8', '9', '9', '9', 'a', '9', 'b',
 8702    '9', 'c', '9', 'd', '9', 'e', '9', 'f',
 8703    'a', '0', 'a', '1', 'a', '2', 'a', '3',
 8704    'a', '4', 'a', '5', 'a', '6', 'a', '7',
 8705    'a', '8', 'a', '9', 'a', 'a', 'a', 'b',
 8706    'a', 'c', 'a', 'd', 'a', 'e', 'a', 'f',
 8707    'b', '0', 'b', '1', 'b', '2', 'b', '3',
 8708    'b', '4', 'b', '5', 'b', '6', 'b', '7',
 8709    'b', '8', 'b', '9', 'b', 'a', 'b', 'b',
 8710    'b', 'c', 'b', 'd', 'b', 'e', 'b', 'f',
 8711    'c', '0', 'c', '1', 'c', '2', 'c', '3',
 8712    'c', '4', 'c', '5', 'c', '6', 'c', '7',
 8713    'c', '8', 'c', '9', 'c', 'a', 'c', 'b',
 8714    'c', 'c', 'c', 'd', 'c', 'e', 'c', 'f',
 8715    'd', '0', 'd', '1', 'd', '2', 'd', '3',
 8716    'd', '4', 'd', '5', 'd', '6', 'd', '7',
 8717    'd', '8', 'd', '9', 'd', 'a', 'd', 'b',
 8718    'd', 'c', 'd', 'd', 'd', 'e', 'd', 'f',
 8719    'e', '0', 'e', '1', 'e', '2', 'e', '3',
 8720    'e', '4', 'e', '5', 'e', '6', 'e', '7',
 8721    'e', '8', 'e', '9', 'e', 'a', 'e', 'b',
 8722    'e', 'c', 'e', 'd', 'e', 'e', 'e', 'f',
 8723    'f', '0', 'f', '1', 'f', '2', 'f', '3',
 8724    'f', '4', 'f', '5', 'f', '6', 'f', '7',
 8725    'f', '8', 'f', '9', 'f', 'a', 'f', 'b',
 8726    'f', 'c', 'f', 'd', 'f', 'e', 'f', 'f'
 8727};
 8728
 8729/** Escaped single character table. (generated with misc/make_tables.c) */
 8730yyjson_align(2)
 8731static const u8 esc_single_char_table[512] = {
 8732    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8733    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8734    '\\', 'b', '\\', 't', '\\', 'n', ' ', ' ',
 8735    '\\', 'f', '\\', 'r', ' ', ' ', ' ', ' ',
 8736    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8737    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8738    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8739    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8740    ' ', ' ', ' ', ' ', '\\', '"', ' ', ' ',
 8741    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8742    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8743    ' ', ' ', ' ', ' ', ' ', ' ', '\\', '/',
 8744    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8745    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8746    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8747    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8748    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8749    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8750    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8751    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8752    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8753    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8754    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8755    '\\', '\\', ' ', ' ', ' ', ' ', ' ', ' ',
 8756    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8757    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8758    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8759    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8760    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8761    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8762    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8763    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8764    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8765    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8766    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8767    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8768    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8769    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8770    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8771    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8772    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8773    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8774    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8775    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8776    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8777    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8778    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8779    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8780    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8781    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8782    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8783    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8784    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8785    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8786    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8787    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8788    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8789    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8790    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8791    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8792    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8793    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8794    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 8795    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
 8796};
 8797
 8798/** Returns the hex digit table to use for \uXXXX escapes. */
 8799static_inline const u8 *get_hex_table_with_flag(yyjson_write_flag flg) {
 8800    return has_flg(LOWERCASE_HEX)
 8801        ? esc_hex_char_table_lower
 8802        : esc_hex_char_table;
 8803}
 8804
 8805/** Returns the encode table with options. */
 8806static_inline const char_enc_type *get_enc_table_with_flag(
 8807    yyjson_write_flag flg) {
 8808    if (has_flg(ESCAPE_UNICODE)) {
 8809        if (has_flg(ESCAPE_SLASHES)) {
 8810            return enc_table_esc_slash;
 8811        } else {
 8812            return enc_table_esc;
 8813        }
 8814    } else {
 8815        if (has_flg(ESCAPE_SLASHES)) {
 8816            return enc_table_cpy_slash;
 8817        } else {
 8818            return enc_table_cpy;
 8819        }
 8820    }
 8821}
 8822
 8823/** Write raw string. */
 8824static_inline u8 *write_raw(u8 *cur, const u8 *raw, usize raw_len) {
 8825    memcpy(cur, raw, raw_len);
 8826    return cur + raw_len;
 8827}
 8828
 8829/**
 8830 Write string no-escape.
 8831 @param cur Buffer cursor.
 8832 @param str A UTF-8 string, null-terminator is not required.
 8833 @param str_len Length of string in bytes.
 8834 @return The buffer cursor after string.
 8835 */
 8836static_inline u8 *write_str_noesc(u8 *cur, const u8 *str, usize str_len) {
 8837    *cur++ = '"';
 8838    while (str_len >= 16) {
 8839        byte_copy_16(cur, str);
 8840        cur += 16;
 8841        str += 16;
 8842        str_len -= 16;
 8843    }
 8844    while (str_len >= 4) {
 8845        byte_copy_4(cur, str);
 8846        cur += 4;
 8847        str += 4;
 8848        str_len -= 4;
 8849    }
 8850    while (str_len) {
 8851        *cur++ = *str++;
 8852        str_len -= 1;
 8853    }
 8854    *cur++ = '"';
 8855    return cur;
 8856}
 8857
 8858/**
 8859 Write UTF-8 string (requires len * 6 + 2 bytes buffer).
 8860 @param cur Buffer cursor.
 8861 @param esc Escape unicode.
 8862 @param inv Allow invalid unicode.
 8863 @param str A UTF-8 string, null-terminator is not required.
 8864 @param str_len Length of string in bytes.
 8865 @param enc_table Encode type table for character.
 8866 @return The buffer cursor after string, or NULL on invalid unicode.
 8867 */
 8868static_inline u8 *write_str(u8 *cur, bool esc, bool inv,
 8869                            const u8 *str, usize str_len,
 8870                            const char_enc_type *enc_table,
 8871                            const u8 *hex_table) {
 8872    /* The replacement character U+FFFD, used to indicate invalid character.
 8873       Looked up via hex_table so that LOWERCASE_HEX produces "fffd" while
 8874       the default produces "FFFD". */
 8875    const v32 pre = {{ '\\', 'u', '0', '0' }};
 8876
 8877    const u8 *src = str;
 8878    const u8 *end = str + str_len;
 8879    *cur++ = '"';
 8880
 8881copy_ascii:
 8882    /*
 8883     Copy continuous ASCII, loop unrolling, same as the following code:
 8884
 8885         while (end > src) (
 8886            if (unlikely(enc_table[*src])) break;
 8887            *cur++ = *src++;
 8888         );
 8889     */
 8890#define expr_jump(i) \
 8891    if (unlikely(enc_table[src[i]])) goto stop_char_##i;
 8892
 8893#define expr_stop(i) \
 8894    stop_char_##i: \
 8895    memcpy(cur, src, i); \
 8896    cur += i; src += i; goto copy_utf8;
 8897
 8898    while (end - src >= 16) {
 8899        repeat16_incr(expr_jump)
 8900        byte_copy_16(cur, src);
 8901        cur += 16; src += 16;
 8902    }
 8903
 8904    while (end - src >= 4) {
 8905        repeat4_incr(expr_jump)
 8906        byte_copy_4(cur, src);
 8907        cur += 4; src += 4;
 8908    }
 8909
 8910    while (end > src) {
 8911        expr_jump(0)
 8912        *cur++ = *src++;
 8913    }
 8914
 8915    *cur++ = '"';
 8916    return cur;
 8917
 8918    repeat16_incr(expr_stop)
 8919
 8920#undef expr_jump
 8921#undef expr_stop
 8922
 8923copy_utf8:
 8924    if (unlikely(src + 4 > end)) {
 8925        if (end == src) goto copy_end;
 8926        if (end - src < enc_table[*src] / 2) goto err_one;
 8927    }
 8928    switch (enc_table[*src]) {
 8929        case CHAR_ENC_CPY_1: {
 8930            *cur++ = *src++;
 8931            goto copy_ascii;
 8932        }
 8933        case CHAR_ENC_CPY_2: {
 8934#if YYJSON_DISABLE_UTF8_VALIDATION
 8935            byte_copy_2(cur, src);
 8936#else
 8937            u32 uni = 0;
 8938            byte_copy_2(&uni, src);
 8939            if (unlikely(!is_utf8_seq2(uni))) goto err_cpy;
 8940            byte_copy_2(cur, &uni);
 8941#endif
 8942            cur += 2;
 8943            src += 2;
 8944            goto copy_utf8;
 8945        }
 8946        case CHAR_ENC_CPY_3: {
 8947#if YYJSON_DISABLE_UTF8_VALIDATION
 8948            if (likely(src + 4 <= end)) {
 8949                byte_copy_4(cur, src);
 8950            } else {
 8951                byte_copy_2(cur, src);
 8952                cur[2] = src[2];
 8953            }
 8954#else
 8955            u32 uni, tmp;
 8956            if (likely(src + 4 <= end)) {
 8957                uni = byte_load_4(src);
 8958                if (unlikely(!is_utf8_seq3(uni))) goto err_cpy;
 8959                byte_copy_4(cur, src);
 8960            } else {
 8961                uni = byte_load_3(src);
 8962                if (unlikely(!is_utf8_seq3(uni))) goto err_cpy;
 8963                byte_copy_4(cur, &uni);
 8964            }
 8965#endif
 8966            cur += 3;
 8967            src += 3;
 8968            goto copy_utf8;
 8969        }
 8970        case CHAR_ENC_CPY_4: {
 8971#if YYJSON_DISABLE_UTF8_VALIDATION
 8972            byte_copy_4(cur, src);
 8973#else
 8974            u32 uni, tmp;
 8975            uni = byte_load_4(src);
 8976            if (unlikely(!is_utf8_seq4(uni))) goto err_cpy;
 8977            byte_copy_4(cur, src);
 8978#endif
 8979            cur += 4;
 8980            src += 4;
 8981            goto copy_utf8;
 8982        }
 8983        case CHAR_ENC_ESC_A: {
 8984            byte_copy_2(cur, &esc_single_char_table[*src * 2]);
 8985            cur += 2;
 8986            src += 1;
 8987            goto copy_utf8;
 8988        }
 8989        case CHAR_ENC_ESC_1: {
 8990            byte_copy_4(cur + 0, &pre);
 8991            byte_copy_2(cur + 4, &hex_table[*src * 2]);
 8992            cur += 6;
 8993            src += 1;
 8994            goto copy_utf8;
 8995        }
 8996        case CHAR_ENC_ESC_2: {
 8997            u16 u;
 8998#if !YYJSON_DISABLE_UTF8_VALIDATION
 8999            u32 v4 = 0;
 9000            u16 v2 = byte_load_2(src);
 9001            byte_copy_2(&v4, &v2);
 9002            if (unlikely(!is_utf8_seq2(v4))) goto err_esc;
 9003#endif
 9004            u = (u16)(((u16)(src[0] & 0x1F) << 6) |
 9005                      ((u16)(src[1] & 0x3F) << 0));
 9006            byte_copy_2(cur + 0, &pre);
 9007            byte_copy_2(cur + 2, &hex_table[(u >> 8) * 2]);
 9008            byte_copy_2(cur + 4, &hex_table[(u & 0xFF) * 2]);
 9009            cur += 6;
 9010            src += 2;
 9011            goto copy_utf8;
 9012        }
 9013        case CHAR_ENC_ESC_3: {
 9014            u16 u;
 9015            u32 v, tmp;
 9016#if !YYJSON_DISABLE_UTF8_VALIDATION
 9017            v = byte_load_3(src);
 9018            if (unlikely(!is_utf8_seq3(v))) goto err_esc;
 9019#endif
 9020            u = (u16)(((u16)(src[0] & 0x0F) << 12) |
 9021                      ((u16)(src[1] & 0x3F) << 6) |
 9022                      ((u16)(src[2] & 0x3F) << 0));
 9023            byte_copy_2(cur + 0, &pre);
 9024            byte_copy_2(cur + 2, &hex_table[(u >> 8) * 2]);
 9025            byte_copy_2(cur + 4, &hex_table[(u & 0xFF) * 2]);
 9026            cur += 6;
 9027            src += 3;
 9028            goto copy_utf8;
 9029        }
 9030        case CHAR_ENC_ESC_4: {
 9031            u32 hi, lo, u, v, tmp;
 9032#if !YYJSON_DISABLE_UTF8_VALIDATION
 9033            v = byte_load_4(src);
 9034            if (unlikely(!is_utf8_seq4(v))) goto err_esc;
 9035#endif
 9036            u = ((u32)(src[0] & 0x07) << 18) |
 9037                ((u32)(src[1] & 0x3F) << 12) |
 9038                ((u32)(src[2] & 0x3F) << 6) |
 9039                ((u32)(src[3] & 0x3F) << 0);
 9040            u -= 0x10000;
 9041            hi = (u >> 10) + 0xD800;
 9042            lo = (u & 0x3FF) + 0xDC00;
 9043            byte_copy_2(cur + 0, &pre);
 9044            byte_copy_2(cur + 2, &hex_table[(hi >> 8) * 2]);
 9045            byte_copy_2(cur + 4, &hex_table[(hi & 0xFF) * 2]);
 9046            byte_copy_2(cur + 6, &pre);
 9047            byte_copy_2(cur + 8, &hex_table[(lo >> 8) * 2]);
 9048            byte_copy_2(cur + 10, &hex_table[(lo & 0xFF) * 2]);
 9049            cur += 12;
 9050            src += 4;
 9051            goto copy_utf8;
 9052        }
 9053        case CHAR_ENC_ERR_1: {
 9054            goto err_one;
 9055        }
 9056        default: break; /* unreachable */
 9057    }
 9058
 9059copy_end:
 9060    *cur++ = '"';
 9061    return cur;
 9062
 9063err_one:
 9064    if (esc) goto err_esc;
 9065    else goto err_cpy;
 9066
 9067err_cpy:
 9068    if (!inv) return NULL;
 9069    *cur++ = *src++;
 9070    goto copy_utf8;
 9071
 9072err_esc:
 9073    if (!inv) return NULL;
 9074    byte_copy_2(cur + 0, &pre);
 9075    /* U+FFFD = 0xFFFD, written as two pairs from hex_table so that
 9076       LOWERCASE_HEX produces "fffd". Replaces a single byte_copy_4
 9077       from a hardcoded uppercase "FFFD" v32; same total output, one
 9078       extra load on the (rare) invalid-UTF-8-with-ALLOW path. */
 9079    byte_copy_2(cur + 2, &hex_table[0xFF * 2]);
 9080    byte_copy_2(cur + 4, &hex_table[0xFD * 2]);
 9081    cur += 6;
 9082    src += 1;
 9083    goto copy_utf8;
 9084}
 9085
 9086
 9087
 9088/*==============================================================================
 9089 * MARK: - JSON Writer Utilities (Private)
 9090 *============================================================================*/
 9091
 9092/** Write null (requires 8 bytes buffer). */
 9093static_inline u8 *write_null(u8 *cur) {
 9094    v64 v = {{ 'n', 'u', 'l', 'l', ',', '\n', 0, 0 }};
 9095    byte_copy_8(cur, &v);
 9096    return cur + 4;
 9097}
 9098
 9099/** Write bool (requires 8 bytes buffer). */
 9100static_inline u8 *write_bool(u8 *cur, bool val) {
 9101    v64 v0 = {{ 'f', 'a', 'l', 's', 'e', ',', '\n', 0 }};
 9102    v64 v1 = {{ 't', 'r', 'u', 'e', ',', '\n', 0, 0 }};
 9103    if (val) {
 9104        byte_copy_8(cur, &v1);
 9105    } else {
 9106        byte_copy_8(cur, &v0);
 9107    }
 9108    return cur + 5 - val;
 9109}
 9110
 9111/** Write indent (requires level x 4 bytes buffer).
 9112    Param spaces should not larger than 4. */
 9113static_inline u8 *write_indent(u8 *cur, usize level, usize spaces) {
 9114    while (level-- > 0) {
 9115        byte_copy_4(cur, "    ");
 9116        cur += spaces;
 9117    }
 9118    return cur;
 9119}
 9120
 9121#if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE
 9122
 9123/** Write data to file pointer. */
 9124static bool write_dat_to_fp(FILE *fp, u8 *dat, usize len,
 9125                            yyjson_write_err *err) {
 9126    if (fwrite(dat, 1, len, fp) != len) {
 9127        err->msg = "file writing failed";
 9128        err->code = YYJSON_WRITE_ERROR_FILE_WRITE;
 9129        return false;
 9130    }
 9131    return true;
 9132}
 9133
 9134/** Write data to file. */
 9135static bool write_dat_to_file(const char *path, u8 *dat, usize len,
 9136                              yyjson_write_err *err) {
 9137#define return_err(_code, _msg) do { \
 9138    err->msg = _msg; \
 9139    err->code = YYJSON_WRITE_ERROR_##_code; \
 9140    if (file) fclose(file); \
 9141    return false; \
 9142} while (false)
 9143
 9144    FILE *file = fopen_writeonly(path);
 9145    if (file == NULL) {
 9146        return_err(FILE_OPEN, MSG_FOPEN);
 9147    }
 9148    if (fwrite(dat, 1, len, file) != len) {
 9149        return_err(FILE_WRITE, MSG_FWRITE);
 9150    }
 9151    if (fclose(file) != 0) {
 9152        file = NULL;
 9153        return_err(FILE_WRITE, MSG_FCLOSE);
 9154    }
 9155    return true;
 9156
 9157#undef return_err
 9158}
 9159
 9160#endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */
 9161
 9162
 9163
 9164/*==============================================================================
 9165 * MARK: - JSON Writer Implementation (Private)
 9166 *============================================================================*/
 9167
 9168typedef struct yyjson_write_ctx {
 9169    usize tag;
 9170} yyjson_write_ctx;
 9171
 9172static_inline void yyjson_write_ctx_set(yyjson_write_ctx *ctx,
 9173                                        usize size, bool is_obj) {
 9174    ctx->tag = (size << 1) | (usize)is_obj;
 9175}
 9176
 9177static_inline void yyjson_write_ctx_get(yyjson_write_ctx *ctx,
 9178                                        usize *size, bool *is_obj) {
 9179    usize tag = ctx->tag;
 9180    *size = tag >> 1;
 9181    *is_obj = (bool)(tag & 1);
 9182}
 9183
 9184/** Write single JSON value. */
 9185static_inline u8 *write_root_single(yyjson_val *val,
 9186                                    yyjson_write_flag flg,
 9187                                    yyjson_alc alc,
 9188                                    char *buf, usize *dat_len,
 9189                                    yyjson_write_err *err) {
 9190#define return_err(_code, _msg) do { \
 9191    if (hdr) alc.free(alc.ctx, (void *)hdr); \
 9192    *dat_len = 0; \
 9193    err->code = YYJSON_WRITE_ERROR_##_code; \
 9194    err->msg = _msg; \
 9195    return NULL; \
 9196} while (false)
 9197
 9198#define incr_len(_len) do { \
 9199    if (buf) hdr = *dat_len >= _len ? (u8 *)buf : (u8 *)NULL; \
 9200    else hdr = (u8 *)alc.malloc(alc.ctx, _len); \
 9201    if (!hdr) goto fail_alloc; \
 9202    cur = hdr; \
 9203} while (false)
 9204
 9205#define check_str_len(_len) do { \
 9206    if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
 9207        goto fail_alloc; \
 9208} while (false)
 9209
 9210    u8 *hdr = NULL, *cur;
 9211    usize str_len;
 9212    const u8 *str_ptr;
 9213    const char_enc_type *enc_table = get_enc_table_with_flag(flg);
 9214    const u8 *hex_table = get_hex_table_with_flag(flg);
 9215    bool cpy = (enc_table == enc_table_cpy);
 9216    bool esc = has_flg(ESCAPE_UNICODE) != 0;
 9217    bool inv = has_allow(INVALID_UNICODE) != 0;
 9218    bool newline = has_flg(NEWLINE_AT_END) != 0;
 9219    const usize end_len = 2; /* '\n' and '\0' */
 9220
 9221    switch (unsafe_yyjson_get_type(val)) {
 9222        case YYJSON_TYPE_RAW:
 9223            str_len = unsafe_yyjson_get_len(val);
 9224            str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
 9225            check_str_len(str_len);
 9226            incr_len(str_len + end_len);
 9227            cur = write_raw(cur, str_ptr, str_len);
 9228            break;
 9229
 9230        case YYJSON_TYPE_STR:
 9231            str_len = unsafe_yyjson_get_len(val);
 9232            str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
 9233            check_str_len(str_len);
 9234            incr_len(str_len * 6 + 2 + end_len);
 9235            if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
 9236                cur = write_str_noesc(cur, str_ptr, str_len);
 9237            } else {
 9238                cur = write_str(cur, esc, inv, str_ptr, str_len,
 9239                                enc_table, hex_table);
 9240                if (unlikely(!cur)) goto fail_str;
 9241            }
 9242            break;
 9243
 9244        case YYJSON_TYPE_NUM:
 9245            incr_len(FP_BUF_LEN + end_len);
 9246            cur = write_num(cur, val, flg);
 9247            if (unlikely(!cur)) goto fail_num;
 9248            break;
 9249
 9250        case YYJSON_TYPE_BOOL:
 9251            incr_len(8);
 9252            cur = write_bool(cur, unsafe_yyjson_get_bool(val));
 9253            break;
 9254
 9255        case YYJSON_TYPE_NULL:
 9256            incr_len(8);
 9257            cur = write_null(cur);
 9258            break;
 9259
 9260        case YYJSON_TYPE_ARR:
 9261            incr_len(2 + end_len);
 9262            byte_copy_2(cur, "[]");
 9263            cur += 2;
 9264            break;
 9265
 9266        case YYJSON_TYPE_OBJ:
 9267            incr_len(2 + end_len);
 9268            byte_copy_2(cur, "{}");
 9269            cur += 2;
 9270            break;
 9271
 9272        default:
 9273            goto fail_type;
 9274    }
 9275
 9276    if (newline) *cur++ = '\n';
 9277    *cur = '\0';
 9278    *dat_len = (usize)(cur - hdr);
 9279    memset(err, 0, sizeof(yyjson_write_err));
 9280    return hdr;
 9281
 9282fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
 9283fail_type:  return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
 9284fail_num:   return_err(NAN_OR_INF, MSG_NAN_INF);
 9285fail_str:   return_err(INVALID_STRING, MSG_ERR_UTF8);
 9286
 9287#undef return_err
 9288#undef check_str_len
 9289#undef incr_len
 9290}
 9291
 9292/** Write JSON document minify.
 9293    The root of this document should be a non-empty container. */
 9294static_inline u8 *write_root_minify(const yyjson_val *root,
 9295                                    const yyjson_write_flag flg,
 9296                                    const yyjson_alc alc,
 9297                                    char *buf, usize *dat_len,
 9298                                    yyjson_write_err *err) {
 9299#define return_err(_code, _msg) do { \
 9300    *dat_len = 0; \
 9301    err->code = YYJSON_WRITE_ERROR_##_code; \
 9302    err->msg = _msg; \
 9303    if (hdr) alc.free(alc.ctx, hdr); \
 9304    return NULL; \
 9305} while (false)
 9306
 9307#define incr_len(_len) do { \
 9308    ext_len = (usize)(_len); \
 9309    if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
 9310        usize ctx_pos = (usize)((u8 *)ctx - hdr); \
 9311        usize cur_pos = (usize)(cur - hdr); \
 9312        yyjson_assume((u8 *)ctx <= (u8 *)end); \
 9313        ctx_len = (usize)((u8 *)end - (u8 *)ctx); \
 9314        alc_inc = yyjson_max(alc_len / 2, ext_len); \
 9315        alc_inc = size_align_up(alc_inc, sizeof(yyjson_write_ctx)); \
 9316        if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
 9317            goto fail_alloc; \
 9318        alc_len += alc_inc; \
 9319        tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
 9320        if (unlikely(!tmp)) goto fail_alloc; \
 9321        ctx_tmp = (yyjson_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
 9322        memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
 9323        ctx = ctx_tmp; \
 9324        cur = tmp + cur_pos; \
 9325        end = tmp + alc_len; \
 9326        hdr = tmp; \
 9327    } \
 9328} while (false)
 9329
 9330#define check_str_len(_len) do { \
 9331    if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
 9332        goto fail_alloc; \
 9333} while (false)
 9334
 9335    yyjson_val *val;
 9336    yyjson_type val_type;
 9337    usize ctn_len, ctn_len_tmp;
 9338    bool ctn_obj, ctn_obj_tmp, is_key;
 9339    u8 *hdr, *cur, *end, *tmp;
 9340    yyjson_write_ctx *ctx, *ctx_tmp;
 9341    usize alc_len, alc_inc, ctx_len, ext_len, str_len;
 9342#if YYJSON_WRITER_DEPTH_LIMIT
 9343    usize ctn_depth = 0;
 9344#endif
 9345    const u8 *str_ptr;
 9346    const char_enc_type *enc_table = get_enc_table_with_flag(flg);
 9347    const u8 *hex_table = get_hex_table_with_flag(flg);
 9348    bool cpy = (enc_table == enc_table_cpy);
 9349    bool esc = has_flg(ESCAPE_UNICODE) != 0;
 9350    bool inv = has_allow(INVALID_UNICODE) != 0;
 9351    bool newline = has_flg(NEWLINE_AT_END) != 0;
 9352
 9353    if (buf) {
 9354        hdr = (u8 *)buf;
 9355        alc_len = *dat_len;
 9356        alc_len = size_align_down(alc_len, sizeof(yyjson_write_ctx));
 9357        if (alc_len <= sizeof(yyjson_write_ctx)) goto fail_alloc;
 9358    } else {
 9359        alc_len = root->uni.ofs / sizeof(yyjson_val);
 9360        alc_len = alc_len * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64;
 9361        alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx));
 9362        hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
 9363        if (!hdr) goto fail_alloc;
 9364    }
 9365    cur = hdr;
 9366    end = hdr + alc_len;
 9367    ctx = (yyjson_write_ctx *)(void *)end;
 9368
 9369doc_begin:
 9370    val = constcast(yyjson_val *)root;
 9371    val_type = unsafe_yyjson_get_type(val);
 9372    ctn_obj = (val_type == YYJSON_TYPE_OBJ);
 9373    ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
 9374    *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
 9375    val++;
 9376
 9377val_begin:
 9378    val_type = unsafe_yyjson_get_type(val);
 9379    if (val_type == YYJSON_TYPE_STR) {
 9380        is_key = ((u8)ctn_obj & (u8)~ctn_len);
 9381        str_len = unsafe_yyjson_get_len(val);
 9382        str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
 9383        check_str_len(str_len);
 9384        incr_len(str_len * 6 + 16);
 9385        if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
 9386            cur = write_str_noesc(cur, str_ptr, str_len);
 9387        } else {
 9388            cur = write_str(cur, esc, inv, str_ptr, str_len,
 9389                            enc_table, hex_table);
 9390            if (unlikely(!cur)) goto fail_str;
 9391        }
 9392        *cur++ = is_key ? ':' : ',';
 9393        goto val_end;
 9394    }
 9395    if (val_type == YYJSON_TYPE_NUM) {
 9396        incr_len(FP_BUF_LEN);
 9397        cur = write_num(cur, val, flg);
 9398        if (unlikely(!cur)) goto fail_num;
 9399        *cur++ = ',';
 9400        goto val_end;
 9401    }
 9402    if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
 9403                    (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
 9404        ctn_len_tmp = unsafe_yyjson_get_len(val);
 9405        ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
 9406        incr_len(2 * sizeof(*ctx));
 9407#if YYJSON_WRITER_DEPTH_LIMIT
 9408        ctn_depth++;
 9409        if (unlikely(ctn_depth >= (usize)YYJSON_WRITER_DEPTH_LIMIT)) {
 9410            goto fail_depth;
 9411        }
 9412#endif
 9413        if (unlikely(ctn_len_tmp == 0)) {
 9414#if YYJSON_WRITER_DEPTH_LIMIT
 9415            ctn_depth--;
 9416#endif
 9417            /* write empty container */
 9418            *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
 9419            *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
 9420            *cur++ = ',';
 9421            goto val_end;
 9422        } else {
 9423            /* push context, setup new container */
 9424            yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj);
 9425            ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
 9426            ctn_obj = ctn_obj_tmp;
 9427            *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
 9428            val++;
 9429            goto val_begin;
 9430        }
 9431    }
 9432    if (val_type == YYJSON_TYPE_BOOL) {
 9433        incr_len(16);
 9434        cur = write_bool(cur, unsafe_yyjson_get_bool(val));
 9435        cur++;
 9436        goto val_end;
 9437    }
 9438    if (val_type == YYJSON_TYPE_NULL) {
 9439        incr_len(16);
 9440        cur = write_null(cur);
 9441        cur++;
 9442        goto val_end;
 9443    }
 9444    if (val_type == YYJSON_TYPE_RAW) {
 9445        str_len = unsafe_yyjson_get_len(val);
 9446        str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
 9447        check_str_len(str_len);
 9448        incr_len(str_len + 2);
 9449        cur = write_raw(cur, str_ptr, str_len);
 9450        *cur++ = ',';
 9451        goto val_end;
 9452    }
 9453    goto fail_type;
 9454
 9455val_end:
 9456    val++;
 9457    ctn_len--;
 9458    if (unlikely(ctn_len == 0)) goto ctn_end;
 9459    goto val_begin;
 9460
 9461ctn_end:
 9462#if YYJSON_WRITER_DEPTH_LIMIT
 9463    ctn_depth--;
 9464#endif
 9465    cur--;
 9466    *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
 9467    *cur++ = ',';
 9468    if (unlikely((u8 *)ctx >= end)) goto doc_end;
 9469    yyjson_write_ctx_get(ctx++, &ctn_len, &ctn_obj);
 9470    ctn_len--;
 9471    if (likely(ctn_len > 0)) {
 9472        goto val_begin;
 9473    } else {
 9474        goto ctn_end;
 9475    }
 9476
 9477doc_end:
 9478    if (newline) {
 9479        incr_len(2);
 9480        *(cur - 1) = '\n';
 9481        cur++;
 9482    }
 9483    *--cur = '\0';
 9484    *dat_len = (usize)(cur - hdr);
 9485    memset(err, 0, sizeof(yyjson_write_err));
 9486    return hdr;
 9487
 9488fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
 9489fail_type:  return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
 9490fail_num:   return_err(NAN_OR_INF, MSG_NAN_INF);
 9491fail_str:   return_err(INVALID_STRING, MSG_ERR_UTF8);
 9492#if YYJSON_WRITER_DEPTH_LIMIT
 9493fail_depth: return_err(DEPTH, MSG_DEPTH);
 9494#endif
 9495
 9496#undef return_err
 9497#undef incr_len
 9498#undef check_str_len
 9499}
 9500
 9501/** Write JSON document pretty.
 9502    The root of this document should be a non-empty container. */
 9503static_inline u8 *write_root_pretty(const yyjson_val *root,
 9504                                    const yyjson_write_flag flg,
 9505                                    const yyjson_alc alc,
 9506                                    char *buf, usize *dat_len,
 9507                                    yyjson_write_err *err) {
 9508#define return_err(_code, _msg) do { \
 9509    *dat_len = 0; \
 9510    err->code = YYJSON_WRITE_ERROR_##_code; \
 9511    err->msg = _msg; \
 9512    if (hdr) alc.free(alc.ctx, hdr); \
 9513    return NULL; \
 9514} while (false)
 9515
 9516#define incr_len(_len) do { \
 9517    ext_len = (usize)(_len); \
 9518    if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
 9519        usize ctx_pos = (usize)((u8 *)ctx - hdr); \
 9520        usize cur_pos = (usize)(cur - hdr); \
 9521        yyjson_assume((u8 *)ctx <= (u8 *)end); \
 9522        ctx_len = (usize)((u8 *)end - (u8 *)ctx); \
 9523        alc_inc = yyjson_max(alc_len / 2, ext_len); \
 9524        alc_inc = size_align_up(alc_inc, sizeof(yyjson_write_ctx)); \
 9525        if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
 9526            goto fail_alloc; \
 9527        alc_len += alc_inc; \
 9528        tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
 9529        if (unlikely(!tmp)) goto fail_alloc; \
 9530        ctx_tmp = (yyjson_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
 9531        memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
 9532        ctx = ctx_tmp; \
 9533        cur = tmp + cur_pos; \
 9534        end = tmp + alc_len; \
 9535        hdr = tmp; \
 9536    } \
 9537} while (false)
 9538
 9539#define check_str_len(_len) do { \
 9540    if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
 9541        goto fail_alloc; \
 9542} while (false)
 9543
 9544    yyjson_val *val;
 9545    yyjson_type val_type;
 9546    usize ctn_len, ctn_len_tmp;
 9547    bool ctn_obj, ctn_obj_tmp, is_key, no_indent;
 9548    u8 *hdr, *cur, *end, *tmp;
 9549    yyjson_write_ctx *ctx, *ctx_tmp;
 9550    usize alc_len, alc_inc, ctx_len, ext_len, str_len, level;
 9551#if YYJSON_WRITER_DEPTH_LIMIT
 9552    usize ctn_depth = 0;
 9553#endif
 9554    const u8 *str_ptr;
 9555    const char_enc_type *enc_table = get_enc_table_with_flag(flg);
 9556    const u8 *hex_table = get_hex_table_with_flag(flg);
 9557    bool cpy = (enc_table == enc_table_cpy);
 9558    bool esc = has_flg(ESCAPE_UNICODE) != 0;
 9559    bool inv = has_allow(INVALID_UNICODE) != 0;
 9560    usize spaces = has_flg(PRETTY_TWO_SPACES) ? 2 : 4;
 9561    bool newline = has_flg(NEWLINE_AT_END) != 0;
 9562
 9563    if (buf) {
 9564        hdr = (u8 *)buf;
 9565        alc_len = *dat_len;
 9566        alc_len = size_align_down(alc_len, sizeof(yyjson_write_ctx));
 9567        if (alc_len <= sizeof(yyjson_write_ctx)) goto fail_alloc;
 9568    } else {
 9569        alc_len = root->uni.ofs / sizeof(yyjson_val);
 9570        alc_len = alc_len * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64;
 9571        alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx));
 9572        hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
 9573        if (!hdr) goto fail_alloc;
 9574    }
 9575    cur = hdr;
 9576    end = hdr + alc_len;
 9577    ctx = (yyjson_write_ctx *)(void *)end;
 9578
 9579doc_begin:
 9580    val = constcast(yyjson_val *)root;
 9581    val_type = unsafe_yyjson_get_type(val);
 9582    ctn_obj = (val_type == YYJSON_TYPE_OBJ);
 9583    ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
 9584    *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
 9585    *cur++ = '\n';
 9586    val++;
 9587    level = 1;
 9588
 9589val_begin:
 9590    val_type = unsafe_yyjson_get_type(val);
 9591    if (val_type == YYJSON_TYPE_STR) {
 9592        is_key = (bool)((u8)ctn_obj & (u8)~ctn_len);
 9593        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
 9594        str_len = unsafe_yyjson_get_len(val);
 9595        str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
 9596        check_str_len(str_len);
 9597        if ((sizeof(usize) < 8) && !no_indent &&
 9598            level > (USIZE_MAX - 16 - str_len * 6) / 4) goto fail_alloc;
 9599        incr_len(str_len * 6 + 16 + (no_indent ? 0 : level * 4));
 9600        cur = write_indent(cur, no_indent ? 0 : level, spaces);
 9601        if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
 9602            cur = write_str_noesc(cur, str_ptr, str_len);
 9603        } else {
 9604            cur = write_str(cur, esc, inv, str_ptr, str_len,
 9605                            enc_table, hex_table);
 9606            if (unlikely(!cur)) goto fail_str;
 9607        }
 9608        *cur++ = is_key ? ':' : ',';
 9609        *cur++ = is_key ? ' ' : '\n';
 9610        goto val_end;
 9611    }
 9612    if (val_type == YYJSON_TYPE_NUM) {
 9613        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
 9614        incr_len(FP_BUF_LEN + (no_indent ? 0 : level * 4));
 9615        cur = write_indent(cur, no_indent ? 0 : level, spaces);
 9616        cur = write_num(cur, val, flg);
 9617        if (unlikely(!cur)) goto fail_num;
 9618        *cur++ = ',';
 9619        *cur++ = '\n';
 9620        goto val_end;
 9621    }
 9622    if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
 9623                    (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
 9624        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
 9625        ctn_len_tmp = unsafe_yyjson_get_len(val);
 9626        ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
 9627        incr_len(2 * sizeof(*ctx) + (no_indent ? 0 : level * 4));
 9628#if YYJSON_WRITER_DEPTH_LIMIT
 9629        ctn_depth++;
 9630        if (unlikely(ctn_depth >= (usize)YYJSON_WRITER_DEPTH_LIMIT)) {
 9631            goto fail_depth;
 9632        }
 9633#endif
 9634        if (unlikely(ctn_len_tmp == 0)) {
 9635#if YYJSON_WRITER_DEPTH_LIMIT
 9636            ctn_depth--;
 9637#endif
 9638            /* write empty container */
 9639            cur = write_indent(cur, no_indent ? 0 : level, spaces);
 9640            *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
 9641            *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
 9642            *cur++ = ',';
 9643            *cur++ = '\n';
 9644            goto val_end;
 9645        } else {
 9646            /* push context, setup new container */
 9647            yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj);
 9648            ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
 9649            ctn_obj = ctn_obj_tmp;
 9650            cur = write_indent(cur, no_indent ? 0 : level, spaces);
 9651            level++;
 9652            *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
 9653            *cur++ = '\n';
 9654            val++;
 9655            goto val_begin;
 9656        }
 9657    }
 9658    if (val_type == YYJSON_TYPE_BOOL) {
 9659        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
 9660        incr_len(16 + (no_indent ? 0 : level * 4));
 9661        cur = write_indent(cur, no_indent ? 0 : level, spaces);
 9662        cur = write_bool(cur, unsafe_yyjson_get_bool(val));
 9663        cur += 2;
 9664        goto val_end;
 9665    }
 9666    if (val_type == YYJSON_TYPE_NULL) {
 9667        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
 9668        incr_len(16 + (no_indent ? 0 : level * 4));
 9669        cur = write_indent(cur, no_indent ? 0 : level, spaces);
 9670        cur = write_null(cur);
 9671        cur += 2;
 9672        goto val_end;
 9673    }
 9674    if (val_type == YYJSON_TYPE_RAW) {
 9675        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
 9676        str_len = unsafe_yyjson_get_len(val);
 9677        str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
 9678        check_str_len(str_len);
 9679        incr_len(str_len + 3 + (no_indent ? 0 : level * 4));
 9680        cur = write_indent(cur, no_indent ? 0 : level, spaces);
 9681        cur = write_raw(cur, str_ptr, str_len);
 9682        *cur++ = ',';
 9683        *cur++ = '\n';
 9684        goto val_end;
 9685    }
 9686    goto fail_type;
 9687
 9688val_end:
 9689    val++;
 9690    ctn_len--;
 9691    if (unlikely(ctn_len == 0)) goto ctn_end;
 9692    goto val_begin;
 9693
 9694ctn_end:
 9695#if YYJSON_WRITER_DEPTH_LIMIT
 9696    ctn_depth--;
 9697#endif
 9698    cur -= 2;
 9699    *cur++ = '\n';
 9700    incr_len(level * 4);
 9701    cur = write_indent(cur, --level, spaces);
 9702    *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
 9703    if (unlikely((u8 *)ctx >= end)) goto doc_end;
 9704    yyjson_write_ctx_get(ctx++, &ctn_len, &ctn_obj);
 9705    ctn_len--;
 9706    *cur++ = ',';
 9707    *cur++ = '\n';
 9708    if (likely(ctn_len > 0)) {
 9709        goto val_begin;
 9710    } else {
 9711        goto ctn_end;
 9712    }
 9713
 9714doc_end:
 9715    if (newline) {
 9716        incr_len(2);
 9717        *cur++ = '\n';
 9718    }
 9719    *cur = '\0';
 9720    *dat_len = (usize)(cur - hdr);
 9721    memset(err, 0, sizeof(yyjson_write_err));
 9722    return hdr;
 9723
 9724fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
 9725fail_type:  return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
 9726fail_num:   return_err(NAN_OR_INF, MSG_NAN_INF);
 9727fail_str:   return_err(INVALID_STRING, MSG_ERR_UTF8);
 9728#if YYJSON_WRITER_DEPTH_LIMIT
 9729fail_depth: return_err(DEPTH, MSG_DEPTH);
 9730#endif
 9731
 9732#undef return_err
 9733#undef incr_len
 9734#undef check_str_len
 9735}
 9736
 9737static char *write_root(const yyjson_val *val,
 9738                        yyjson_write_flag flg,
 9739                        const yyjson_alc *alc_ptr,
 9740                        char *buf, usize *dat_len,
 9741                        yyjson_write_err *err) {
 9742    yyjson_write_err tmp_err;
 9743    usize tmp_dat_len;
 9744    yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
 9745    yyjson_val *root = constcast(yyjson_val *)val;
 9746
 9747    if (!err) err = &tmp_err;
 9748    if (!dat_len) dat_len = &tmp_dat_len;
 9749
 9750    if (unlikely(!root)) {
 9751        *dat_len = 0;
 9752        err->msg = "input JSON is NULL";
 9753        err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
 9754        return NULL;
 9755    }
 9756
 9757    if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) {
 9758        return (char *)write_root_single(root, flg, alc, buf, dat_len, err);
 9759    } else if (flg & (YYJSON_WRITE_PRETTY | YYJSON_WRITE_PRETTY_TWO_SPACES)) {
 9760        return (char *)write_root_pretty(root, flg, alc, buf, dat_len, err);
 9761    } else {
 9762        return (char *)write_root_minify(root, flg, alc, buf, dat_len, err);
 9763    }
 9764}
 9765
 9766
 9767
 9768/*==============================================================================
 9769 * MARK: - JSON Writer (Public)
 9770 *============================================================================*/
 9771
 9772char *yyjson_val_write_opts(const yyjson_val *val,
 9773                            yyjson_write_flag flg,
 9774                            const yyjson_alc *alc_ptr,
 9775                            usize *dat_len,
 9776                            yyjson_write_err *err) {
 9777    return write_root(val, flg, alc_ptr, NULL, dat_len, err);
 9778}
 9779
 9780char *yyjson_write_opts(const yyjson_doc *doc,
 9781                        yyjson_write_flag flg,
 9782                        const yyjson_alc *alc_ptr,
 9783                        usize *dat_len,
 9784                        yyjson_write_err *err) {
 9785    yyjson_val *root = doc ? doc->root : NULL;
 9786    return write_root(root, flg, alc_ptr, NULL, dat_len, err);
 9787}
 9788
 9789#if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE
 9790
 9791bool yyjson_val_write_file(const char *path,
 9792                           const yyjson_val *val,
 9793                           yyjson_write_flag flg,
 9794                           const yyjson_alc *alc_ptr,
 9795                           yyjson_write_err *err) {
 9796    yyjson_write_err tmp_err;
 9797    yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
 9798    u8 *dat;
 9799    usize dat_len = 0;
 9800    yyjson_val *root = constcast(yyjson_val *)val;
 9801    bool suc;
 9802
 9803    if (!err) err = &tmp_err;
 9804    if (unlikely(!path || !*path)) {
 9805        err->msg = "input path is invalid";
 9806        err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
 9807        return false;
 9808    }
 9809
 9810    dat = (u8 *)write_root(root, flg, &alc, NULL, &dat_len, err);
 9811    if (unlikely(!dat)) return false;
 9812    suc = write_dat_to_file(path, dat, dat_len, err);
 9813    alc.free(alc.ctx, dat);
 9814    return suc;
 9815}
 9816
 9817bool yyjson_val_write_fp(FILE *fp,
 9818                         const yyjson_val *val,
 9819                         yyjson_write_flag flg,
 9820                         const yyjson_alc *alc_ptr,
 9821                         yyjson_write_err *err) {
 9822    yyjson_write_err tmp_err;
 9823    yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
 9824    u8 *dat;
 9825    usize dat_len = 0;
 9826    yyjson_val *root = constcast(yyjson_val *)val;
 9827    bool suc;
 9828
 9829    if (!err) err = &tmp_err;
 9830    if (unlikely(!fp)) {
 9831        err->msg = "input fp is invalid";
 9832        err->code = YYJSON_READ_ERROR_INVALID_PARAMETER;
 9833        return false;
 9834    }
 9835
 9836    dat = (u8 *)write_root(root, flg, &alc, NULL, &dat_len, err);
 9837    if (unlikely(!dat)) return false;
 9838    suc = write_dat_to_fp(fp, dat, dat_len, err);
 9839    alc.free(alc.ctx, dat);
 9840    return suc;
 9841}
 9842
 9843bool yyjson_write_file(const char *path,
 9844                       const yyjson_doc *doc,
 9845                       yyjson_write_flag flg,
 9846                       const yyjson_alc *alc_ptr,
 9847                       yyjson_write_err *err) {
 9848    yyjson_val *root = doc ? doc->root : NULL;
 9849    return yyjson_val_write_file(path, root, flg, alc_ptr, err);
 9850}
 9851
 9852bool yyjson_write_fp(FILE *fp,
 9853                     const yyjson_doc *doc,
 9854                     yyjson_write_flag flg,
 9855                     const yyjson_alc *alc_ptr,
 9856                     yyjson_write_err *err) {
 9857    yyjson_val *root = doc ? doc->root : NULL;
 9858    return yyjson_val_write_fp(fp, root, flg, alc_ptr, err);
 9859}
 9860
 9861#endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */
 9862
 9863size_t yyjson_val_write_buf(char *buf, size_t buf_len,
 9864                            const yyjson_val *val,
 9865                            yyjson_write_flag flg,
 9866                            yyjson_write_err *err) {
 9867    if (unlikely(!buf || !buf_len)) {
 9868        if (err) err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
 9869        if (err) err->msg = "input buf or buf_len is invalid";
 9870        return 0;
 9871    } else {
 9872        write_root(val, flg, &YYJSON_NULL_ALC, buf, &buf_len, err);
 9873        return buf_len;
 9874    }
 9875}
 9876
 9877size_t yyjson_write_buf(char *buf, size_t buf_len,
 9878                        const yyjson_doc *doc,
 9879                        yyjson_write_flag flg,
 9880                        yyjson_write_err *err) {
 9881    yyjson_val *root = doc ? doc->root : NULL;
 9882    return yyjson_val_write_buf(buf, buf_len, root, flg, err);
 9883}
 9884
 9885
 9886
 9887/*==============================================================================
 9888 * MARK: - Mutable JSON Writer Implementation (Private)
 9889 *============================================================================*/
 9890
 9891typedef struct yyjson_mut_write_ctx {
 9892    usize tag;
 9893    yyjson_mut_val *ctn;
 9894} yyjson_mut_write_ctx;
 9895
 9896static_inline void yyjson_mut_write_ctx_set(yyjson_mut_write_ctx *ctx,
 9897                                            yyjson_mut_val *ctn,
 9898                                            usize size, bool is_obj) {
 9899    ctx->tag = (size << 1) | (usize)is_obj;
 9900    ctx->ctn = ctn;
 9901}
 9902
 9903static_inline void yyjson_mut_write_ctx_get(yyjson_mut_write_ctx *ctx,
 9904                                            yyjson_mut_val **ctn,
 9905                                            usize *size, bool *is_obj) {
 9906    usize tag = ctx->tag;
 9907    *size = tag >> 1;
 9908    *is_obj = (bool)(tag & 1);
 9909    *ctn = ctx->ctn;
 9910}
 9911
 9912/** Get the estimated number of values for the mutable JSON document. */
 9913static_inline usize yyjson_mut_doc_estimated_val_num(
 9914    const yyjson_mut_doc *doc) {
 9915    usize sum = 0;
 9916    yyjson_val_chunk *chunk = doc->val_pool.chunks;
 9917    while (chunk) {
 9918        sum += chunk->chunk_size / sizeof(yyjson_mut_val) - 1;
 9919        if (chunk == doc->val_pool.chunks) {
 9920            sum -= (usize)(doc->val_pool.end - doc->val_pool.cur);
 9921        }
 9922        chunk = chunk->next;
 9923    }
 9924    return sum;
 9925}
 9926
 9927/** Write single JSON value. */
 9928static_inline u8 *mut_write_root_single(yyjson_mut_val *val,
 9929                                        yyjson_write_flag flg,
 9930                                        yyjson_alc alc,
 9931                                        char *buf, usize *dat_len,
 9932                                        yyjson_write_err *err) {
 9933    return write_root_single((yyjson_val *)val, flg, alc, buf, dat_len, err);
 9934}
 9935
 9936/** Write JSON document minify.
 9937    The root of this document should be a non-empty container. */
 9938static_inline u8 *mut_write_root_minify(const yyjson_mut_val *root,
 9939                                        usize estimated_val_num,
 9940                                        yyjson_write_flag flg,
 9941                                        yyjson_alc alc,
 9942                                        char *buf, usize *dat_len,
 9943                                        yyjson_write_err *err) {
 9944#define return_err(_code, _msg) do { \
 9945    *dat_len = 0; \
 9946    err->code = YYJSON_WRITE_ERROR_##_code; \
 9947    err->msg = _msg; \
 9948    if (hdr) alc.free(alc.ctx, hdr); \
 9949    return NULL; \
 9950} while (false)
 9951
 9952#define incr_len(_len) do { \
 9953    ext_len = (usize)(_len); \
 9954    if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
 9955        usize ctx_pos = (usize)((u8 *)ctx - hdr); \
 9956        usize cur_pos = (usize)(cur - hdr); \
 9957        yyjson_assume((u8 *)ctx <= (u8 *)end); \
 9958        ctx_len = (usize)((u8 *)end - (u8 *)ctx); \
 9959        alc_inc = yyjson_max(alc_len / 2, ext_len); \
 9960        alc_inc = size_align_up(alc_inc, sizeof(yyjson_mut_write_ctx)); \
 9961        if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
 9962            goto fail_alloc; \
 9963        alc_len += alc_inc; \
 9964        tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
 9965        if (unlikely(!tmp)) goto fail_alloc; \
 9966        ctx_tmp = (yyjson_mut_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
 9967        memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
 9968        ctx = ctx_tmp; \
 9969        cur = tmp + cur_pos; \
 9970        end = tmp + alc_len; \
 9971        hdr = tmp; \
 9972    } \
 9973} while (false)
 9974
 9975#define check_str_len(_len) do { \
 9976    if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
 9977        goto fail_alloc; \
 9978} while (false)
 9979
 9980    yyjson_mut_val *val, *ctn;
 9981    yyjson_type val_type;
 9982    usize ctn_len, ctn_len_tmp;
 9983    bool ctn_obj, ctn_obj_tmp, is_key;
 9984    u8 *hdr, *cur, *end, *tmp;
 9985    yyjson_mut_write_ctx *ctx, *ctx_tmp;
 9986    usize alc_len, alc_inc, ctx_len, ext_len, str_len;
 9987#if YYJSON_WRITER_DEPTH_LIMIT
 9988    usize ctn_depth = 0;
 9989#endif
 9990    const u8 *str_ptr;
 9991    const char_enc_type *enc_table = get_enc_table_with_flag(flg);
 9992    const u8 *hex_table = get_hex_table_with_flag(flg);
 9993    bool cpy = (enc_table == enc_table_cpy);
 9994    bool esc = has_flg(ESCAPE_UNICODE) != 0;
 9995    bool inv = has_allow(INVALID_UNICODE) != 0;
 9996    bool newline = has_flg(NEWLINE_AT_END) != 0;
 9997
 9998    if (buf) {
 9999        hdr = (u8 *)buf;
10000        alc_len = *dat_len;
10001        alc_len = size_align_down(alc_len, sizeof(yyjson_mut_write_ctx));
10002        if (alc_len <= sizeof(yyjson_mut_write_ctx)) goto fail_alloc;
10003    } else {
10004        alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64;
10005        alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx));
10006        hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
10007        if (!hdr) goto fail_alloc;
10008    }
10009    cur = hdr;
10010    end = hdr + alc_len;
10011    ctx = (yyjson_mut_write_ctx *)(void *)end;
10012
10013doc_begin:
10014    val = constcast(yyjson_mut_val *)root;
10015    val_type = unsafe_yyjson_get_type(val);
10016    ctn_obj = (val_type == YYJSON_TYPE_OBJ);
10017    ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
10018    *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
10019    ctn = val;
10020    val = (yyjson_mut_val *)val->uni.ptr; /* tail */
10021    val = ctn_obj ? val->next->next : val->next;
10022
10023val_begin:
10024    val_type = unsafe_yyjson_get_type(val);
10025    if (val_type == YYJSON_TYPE_STR) {
10026        is_key = ((u8)ctn_obj & (u8)~ctn_len);
10027        str_len = unsafe_yyjson_get_len(val);
10028        str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
10029        check_str_len(str_len);
10030        incr_len(str_len * 6 + 16);
10031        if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
10032            cur = write_str_noesc(cur, str_ptr, str_len);
10033        } else {
10034            cur = write_str(cur, esc, inv, str_ptr, str_len,
10035                            enc_table, hex_table);
10036            if (unlikely(!cur)) goto fail_str;
10037        }
10038        *cur++ = is_key ? ':' : ',';
10039        goto val_end;
10040    }
10041    if (val_type == YYJSON_TYPE_NUM) {
10042        incr_len(FP_BUF_LEN);
10043        cur = write_num(cur, (yyjson_val *)val, flg);
10044        if (unlikely(!cur)) goto fail_num;
10045        *cur++ = ',';
10046        goto val_end;
10047    }
10048    if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
10049                    (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
10050        ctn_len_tmp = unsafe_yyjson_get_len(val);
10051        ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
10052        incr_len(2 * sizeof(*ctx));
10053#if YYJSON_WRITER_DEPTH_LIMIT
10054        ctn_depth++;
10055        if (unlikely(ctn_depth >= (usize)YYJSON_WRITER_DEPTH_LIMIT)) {
10056            goto fail_depth;
10057        }
10058#endif
10059        if (unlikely(ctn_len_tmp == 0)) {
10060#if YYJSON_WRITER_DEPTH_LIMIT
10061            ctn_depth--;
10062#endif
10063            /* write empty container */
10064            *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
10065            *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
10066            *cur++ = ',';
10067            goto val_end;
10068        } else {
10069            /* push context, setup new container */
10070            yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj);
10071            ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
10072            ctn_obj = ctn_obj_tmp;
10073            *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
10074            ctn = val;
10075            val = (yyjson_mut_val *)ctn->uni.ptr; /* tail */
10076            val = ctn_obj ? val->next->next : val->next;
10077            goto val_begin;
10078        }
10079    }
10080    if (val_type == YYJSON_TYPE_BOOL) {
10081        incr_len(16);
10082        cur = write_bool(cur, unsafe_yyjson_get_bool(val));
10083        cur++;
10084        goto val_end;
10085    }
10086    if (val_type == YYJSON_TYPE_NULL) {
10087        incr_len(16);
10088        cur = write_null(cur);
10089        cur++;
10090        goto val_end;
10091    }
10092    if (val_type == YYJSON_TYPE_RAW) {
10093        str_len = unsafe_yyjson_get_len(val);
10094        str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
10095        check_str_len(str_len);
10096        incr_len(str_len + 2);
10097        cur = write_raw(cur, str_ptr, str_len);
10098        *cur++ = ',';
10099        goto val_end;
10100    }
10101    goto fail_type;
10102
10103val_end:
10104    ctn_len--;
10105    if (unlikely(ctn_len == 0)) goto ctn_end;
10106    val = val->next;
10107    goto val_begin;
10108
10109ctn_end:
10110#if YYJSON_WRITER_DEPTH_LIMIT
10111    ctn_depth--;
10112#endif
10113    cur--;
10114    *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
10115    *cur++ = ',';
10116    if (unlikely((u8 *)ctx >= end)) goto doc_end;
10117    val = ctn->next;
10118    yyjson_mut_write_ctx_get(ctx++, &ctn, &ctn_len, &ctn_obj);
10119    ctn_len--;
10120    if (likely(ctn_len > 0)) {
10121        goto val_begin;
10122    } else {
10123        goto ctn_end;
10124    }
10125
10126doc_end:
10127    if (newline) {
10128        incr_len(2);
10129        *(cur - 1) = '\n';
10130        cur++;
10131    }
10132    *--cur = '\0';
10133    *dat_len = (usize)(cur - hdr);
10134    err->code = YYJSON_WRITE_SUCCESS;
10135    err->msg = NULL;
10136    return hdr;
10137
10138fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
10139fail_type:  return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
10140fail_num:   return_err(NAN_OR_INF, MSG_NAN_INF);
10141fail_str:   return_err(INVALID_STRING, MSG_ERR_UTF8);
10142#if YYJSON_WRITER_DEPTH_LIMIT
10143fail_depth: return_err(DEPTH, MSG_DEPTH);
10144#endif
10145
10146#undef return_err
10147#undef incr_len
10148#undef check_str_len
10149}
10150
10151/** Write JSON document pretty.
10152    The root of this document should be a non-empty container. */
10153static_inline u8 *mut_write_root_pretty(const yyjson_mut_val *root,
10154                                        usize estimated_val_num,
10155                                        yyjson_write_flag flg,
10156                                        yyjson_alc alc,
10157                                        char *buf, usize *dat_len,
10158                                        yyjson_write_err *err) {
10159#define return_err(_code, _msg) do { \
10160    *dat_len = 0; \
10161    err->code = YYJSON_WRITE_ERROR_##_code; \
10162    err->msg = _msg; \
10163    if (hdr) alc.free(alc.ctx, hdr); \
10164    return NULL; \
10165} while (false)
10166
10167#define incr_len(_len) do { \
10168    ext_len = (usize)(_len); \
10169    if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \
10170        usize ctx_pos = (usize)((u8 *)ctx - hdr); \
10171        usize cur_pos = (usize)(cur - hdr); \
10172        yyjson_assume((u8 *)ctx <= (u8 *)end); \
10173        ctx_len = (usize)((u8 *)end - (u8 *)ctx); \
10174        alc_inc = yyjson_max(alc_len / 2, ext_len); \
10175        alc_inc = size_align_up(alc_inc, sizeof(yyjson_mut_write_ctx)); \
10176        if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \
10177            goto fail_alloc; \
10178        alc_len += alc_inc; \
10179        tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \
10180        if (unlikely(!tmp)) goto fail_alloc; \
10181        ctx_tmp = (yyjson_mut_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \
10182        memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \
10183        ctx = ctx_tmp; \
10184        cur = tmp + cur_pos; \
10185        end = tmp + alc_len; \
10186        hdr = tmp; \
10187    } \
10188} while (false)
10189
10190#define check_str_len(_len) do { \
10191    if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \
10192        goto fail_alloc; \
10193} while (false)
10194
10195    yyjson_mut_val *val, *ctn;
10196    yyjson_type val_type;
10197    usize ctn_len, ctn_len_tmp;
10198    bool ctn_obj, ctn_obj_tmp, is_key, no_indent;
10199    u8 *hdr, *cur, *end, *tmp;
10200    yyjson_mut_write_ctx *ctx, *ctx_tmp;
10201    usize alc_len, alc_inc, ctx_len, ext_len, str_len, level;
10202#if YYJSON_WRITER_DEPTH_LIMIT
10203    usize ctn_depth = 0;
10204#endif
10205    const u8 *str_ptr;
10206    const char_enc_type *enc_table = get_enc_table_with_flag(flg);
10207    const u8 *hex_table = get_hex_table_with_flag(flg);
10208    bool cpy = (enc_table == enc_table_cpy);
10209    bool esc = has_flg(ESCAPE_UNICODE) != 0;
10210    bool inv = has_allow(INVALID_UNICODE) != 0;
10211    usize spaces = has_flg(PRETTY_TWO_SPACES) ? 2 : 4;
10212    bool newline = has_flg(NEWLINE_AT_END) != 0;
10213
10214    if (buf) {
10215        hdr = (u8 *)buf;
10216        alc_len = *dat_len;
10217        alc_len = size_align_down(alc_len, sizeof(yyjson_mut_write_ctx));
10218        if (alc_len <= sizeof(yyjson_mut_write_ctx)) goto fail_alloc;
10219    } else {
10220        alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64;
10221        alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx));
10222        hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
10223        if (!hdr) goto fail_alloc;
10224    }
10225    cur = hdr;
10226    end = hdr + alc_len;
10227    ctx = (yyjson_mut_write_ctx *)(void *)end;
10228
10229doc_begin:
10230    val = constcast(yyjson_mut_val *)root;
10231    val_type = unsafe_yyjson_get_type(val);
10232    ctn_obj = (val_type == YYJSON_TYPE_OBJ);
10233    ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj;
10234    *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
10235    *cur++ = '\n';
10236    ctn = val;
10237    val = (yyjson_mut_val *)val->uni.ptr; /* tail */
10238    val = ctn_obj ? val->next->next : val->next;
10239    level = 1;
10240
10241val_begin:
10242    val_type = unsafe_yyjson_get_type(val);
10243    if (val_type == YYJSON_TYPE_STR) {
10244        is_key = (bool)((u8)ctn_obj & (u8)~ctn_len);
10245        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10246        str_len = unsafe_yyjson_get_len(val);
10247        str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
10248        check_str_len(str_len);
10249        if ((sizeof(usize) < 8) && !no_indent &&
10250            level > (USIZE_MAX - 16 - str_len * 6) / 4) goto fail_alloc;
10251        incr_len(str_len * 6 + 16 + (no_indent ? 0 : level * 4));
10252        cur = write_indent(cur, no_indent ? 0 : level, spaces);
10253        if (likely(cpy) && unsafe_yyjson_get_subtype(val)) {
10254            cur = write_str_noesc(cur, str_ptr, str_len);
10255        } else {
10256            cur = write_str(cur, esc, inv, str_ptr, str_len,
10257                            enc_table, hex_table);
10258            if (unlikely(!cur)) goto fail_str;
10259        }
10260        *cur++ = is_key ? ':' : ',';
10261        *cur++ = is_key ? ' ' : '\n';
10262        goto val_end;
10263    }
10264    if (val_type == YYJSON_TYPE_NUM) {
10265        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10266        incr_len(FP_BUF_LEN + (no_indent ? 0 : level * 4));
10267        cur = write_indent(cur, no_indent ? 0 : level, spaces);
10268        cur = write_num(cur, (yyjson_val *)val, flg);
10269        if (unlikely(!cur)) goto fail_num;
10270        *cur++ = ',';
10271        *cur++ = '\n';
10272        goto val_end;
10273    }
10274    if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) ==
10275                    (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
10276        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10277        ctn_len_tmp = unsafe_yyjson_get_len(val);
10278        ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
10279        incr_len(2 * sizeof(*ctx) + (no_indent ? 0 : level * 4));
10280#if YYJSON_WRITER_DEPTH_LIMIT
10281        ctn_depth++;
10282        if (unlikely(ctn_depth >= (usize)YYJSON_WRITER_DEPTH_LIMIT)) {
10283            goto fail_depth;
10284        }
10285#endif
10286        if (unlikely(ctn_len_tmp == 0)) {
10287#if YYJSON_WRITER_DEPTH_LIMIT
10288            ctn_depth--;
10289#endif
10290            /* write empty container */
10291            cur = write_indent(cur, no_indent ? 0 : level, spaces);
10292            *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
10293            *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
10294            *cur++ = ',';
10295            *cur++ = '\n';
10296            goto val_end;
10297        } else {
10298            /* push context, setup new container */
10299            yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj);
10300            ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
10301            ctn_obj = ctn_obj_tmp;
10302            cur = write_indent(cur, no_indent ? 0 : level, spaces);
10303            level++;
10304            *cur++ = (u8)('[' | ((u8)ctn_obj << 5));
10305            *cur++ = '\n';
10306            ctn = val;
10307            val = (yyjson_mut_val *)ctn->uni.ptr; /* tail */
10308            val = ctn_obj ? val->next->next : val->next;
10309            goto val_begin;
10310        }
10311    }
10312    if (val_type == YYJSON_TYPE_BOOL) {
10313        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10314        incr_len(16 + (no_indent ? 0 : level * 4));
10315        cur = write_indent(cur, no_indent ? 0 : level, spaces);
10316        cur = write_bool(cur, unsafe_yyjson_get_bool(val));
10317        cur += 2;
10318        goto val_end;
10319    }
10320    if (val_type == YYJSON_TYPE_NULL) {
10321        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10322        incr_len(16 + (no_indent ? 0 : level * 4));
10323        cur = write_indent(cur, no_indent ? 0 : level, spaces);
10324        cur = write_null(cur);
10325        cur += 2;
10326        goto val_end;
10327    }
10328    if (val_type == YYJSON_TYPE_RAW) {
10329        no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
10330        str_len = unsafe_yyjson_get_len(val);
10331        str_ptr = (const u8 *)unsafe_yyjson_get_str(val);
10332        check_str_len(str_len);
10333        incr_len(str_len + 3 + (no_indent ? 0 : level * 4));
10334        cur = write_indent(cur, no_indent ? 0 : level, spaces);
10335        cur = write_raw(cur, str_ptr, str_len);
10336        *cur++ = ',';
10337        *cur++ = '\n';
10338        goto val_end;
10339    }
10340    goto fail_type;
10341
10342val_end:
10343    ctn_len--;
10344    if (unlikely(ctn_len == 0)) goto ctn_end;
10345    val = val->next;
10346    goto val_begin;
10347
10348ctn_end:
10349#if YYJSON_WRITER_DEPTH_LIMIT
10350    ctn_depth--;
10351#endif
10352    cur -= 2;
10353    *cur++ = '\n';
10354    incr_len(level * 4);
10355    cur = write_indent(cur, --level, spaces);
10356    *cur++ = (u8)(']' | ((u8)ctn_obj << 5));
10357    if (unlikely((u8 *)ctx >= end)) goto doc_end;
10358    val = ctn->next;
10359    yyjson_mut_write_ctx_get(ctx++, &ctn, &ctn_len, &ctn_obj);
10360    ctn_len--;
10361    *cur++ = ',';
10362    *cur++ = '\n';
10363    if (likely(ctn_len > 0)) {
10364        goto val_begin;
10365    } else {
10366        goto ctn_end;
10367    }
10368
10369doc_end:
10370    if (newline) {
10371        incr_len(2);
10372        *cur++ = '\n';
10373    }
10374    *cur = '\0';
10375    *dat_len = (usize)(cur - hdr);
10376    err->code = YYJSON_WRITE_SUCCESS;
10377    err->msg = NULL;
10378    return hdr;
10379
10380fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC);
10381fail_type:  return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE);
10382fail_num:   return_err(NAN_OR_INF, MSG_NAN_INF);
10383fail_str:   return_err(INVALID_STRING, MSG_ERR_UTF8);
10384#if YYJSON_WRITER_DEPTH_LIMIT
10385fail_depth: return_err(DEPTH, MSG_DEPTH);
10386#endif
10387
10388#undef return_err
10389#undef incr_len
10390#undef check_str_len
10391}
10392
10393static char *mut_write_root(const yyjson_mut_val *val,
10394                            usize estimated_val_num,
10395                            yyjson_write_flag flg,
10396                            const yyjson_alc *alc_ptr,
10397                            char *buf, usize *dat_len,
10398                            yyjson_write_err *err) {
10399    yyjson_write_err tmp_err;
10400    usize tmp_dat_len;
10401    yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
10402    yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
10403
10404    if (!err) err = &tmp_err;
10405    if (!dat_len) dat_len = &tmp_dat_len;
10406
10407    if (unlikely(!root)) {
10408        *dat_len = 0;
10409        err->msg = "input JSON is NULL";
10410        err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
10411        return NULL;
10412    }
10413
10414    if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) {
10415        return (char *)mut_write_root_single(root, flg, alc, buf, dat_len, err);
10416    } else if (flg & (YYJSON_WRITE_PRETTY | YYJSON_WRITE_PRETTY_TWO_SPACES)) {
10417        return (char *)mut_write_root_pretty(root, estimated_val_num,
10418                                             flg, alc, buf, dat_len, err);
10419    } else {
10420        return (char *)mut_write_root_minify(root, estimated_val_num,
10421                                             flg, alc, buf, dat_len, err);
10422    }
10423}
10424
10425
10426
10427/*==============================================================================
10428 * MARK: - Mutable JSON Writer (Public)
10429 *============================================================================*/
10430
10431char *yyjson_mut_val_write_opts(const yyjson_mut_val *val,
10432                                yyjson_write_flag flg,
10433                                const yyjson_alc *alc_ptr,
10434                                usize *dat_len,
10435                                yyjson_write_err *err) {
10436    return mut_write_root(val, 0, flg, alc_ptr, NULL, dat_len, err);
10437}
10438
10439char *yyjson_mut_write_opts(const yyjson_mut_doc *doc,
10440                            yyjson_write_flag flg,
10441                            const yyjson_alc *alc_ptr,
10442                            usize *dat_len,
10443                            yyjson_write_err *err) {
10444    yyjson_mut_val *root;
10445    usize estimated_val_num;
10446    if (likely(doc)) {
10447        root = doc->root;
10448        estimated_val_num = yyjson_mut_doc_estimated_val_num(doc);
10449    } else {
10450        root = NULL;
10451        estimated_val_num = 0;
10452    }
10453    return mut_write_root(root, estimated_val_num,
10454                          flg, alc_ptr, NULL, dat_len, err);
10455}
10456
10457size_t yyjson_mut_val_write_buf(char *buf, size_t buf_len,
10458                                const yyjson_mut_val *val,
10459                                yyjson_write_flag flg,
10460                                yyjson_write_err *err) {
10461    if (unlikely(!buf || !buf_len)) {
10462        if (err) err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
10463        if (err) err->msg = "input buf or buf_len is invalid";
10464        return 0;
10465    } else {
10466        mut_write_root(val, 0, flg, &YYJSON_NULL_ALC, buf, &buf_len, err);
10467        return buf_len;
10468    }
10469}
10470
10471size_t yyjson_mut_write_buf(char *buf, size_t buf_len,
10472                            const yyjson_mut_doc *doc,
10473                            yyjson_write_flag flg,
10474                            yyjson_write_err *err) {
10475    yyjson_mut_val *root = doc ? doc->root : NULL;
10476    return yyjson_mut_val_write_buf(buf, buf_len, root, flg, err);
10477}
10478
10479#if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE
10480
10481bool yyjson_mut_val_write_file(const char *path,
10482                               const yyjson_mut_val *val,
10483                               yyjson_write_flag flg,
10484                               const yyjson_alc *alc_ptr,
10485                               yyjson_write_err *err) {
10486    yyjson_write_err tmp_err;
10487    yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
10488    u8 *dat;
10489    usize dat_len = 0;
10490    yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
10491    bool suc;
10492
10493    if (!err) err = &tmp_err;
10494    if (unlikely(!path || !*path)) {
10495        err->msg = "input path is invalid";
10496        err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
10497        return false;
10498    }
10499
10500    dat = (u8 *)yyjson_mut_val_write_opts(root, flg, &alc, &dat_len, err);
10501    if (unlikely(!dat)) return false;
10502    suc = write_dat_to_file(path, dat, dat_len, err);
10503    alc.free(alc.ctx, dat);
10504    return suc;
10505}
10506
10507bool yyjson_mut_val_write_fp(FILE *fp,
10508                             const yyjson_mut_val *val,
10509                             yyjson_write_flag flg,
10510                             const yyjson_alc *alc_ptr,
10511                             yyjson_write_err *err) {
10512    yyjson_write_err tmp_err;
10513    yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
10514    u8 *dat;
10515    usize dat_len = 0;
10516    yyjson_mut_val *root = constcast(yyjson_mut_val *)val;
10517    bool suc;
10518
10519    if (!err) err = &tmp_err;
10520    if (unlikely(!fp)) {
10521        err->msg = "input fp is invalid";
10522        err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
10523        return false;
10524    }
10525
10526    dat = (u8 *)yyjson_mut_val_write_opts(root, flg, &alc, &dat_len, err);
10527    if (unlikely(!dat)) return false;
10528    suc = write_dat_to_fp(fp, dat, dat_len, err);
10529    alc.free(alc.ctx, dat);
10530    return suc;
10531}
10532
10533bool yyjson_mut_write_file(const char *path,
10534                           const yyjson_mut_doc *doc,
10535                           yyjson_write_flag flg,
10536                           const yyjson_alc *alc_ptr,
10537                           yyjson_write_err *err) {
10538    yyjson_mut_val *root = doc ? doc->root : NULL;
10539    return yyjson_mut_val_write_file(path, root, flg, alc_ptr, err);
10540}
10541
10542bool yyjson_mut_write_fp(FILE *fp,
10543                         const yyjson_mut_doc *doc,
10544                         yyjson_write_flag flg,
10545                         const yyjson_alc *alc_ptr,
10546                         yyjson_write_err *err) {
10547    yyjson_mut_val *root = doc ? doc->root : NULL;
10548    return yyjson_mut_val_write_fp(fp, root, flg, alc_ptr, err);
10549}
10550
10551#endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */
10552
10553#undef has_flg
10554#undef has_allow
10555#endif /* YYJSON_DISABLE_WRITER */
10556
10557
10558
10559#if !YYJSON_DISABLE_UTILS
10560
10561/*==============================================================================
10562 * MARK: - JSON Pointer API (RFC 6901) (Public)
10563 *============================================================================*/
10564
10565/**
10566 Get a token from JSON pointer string.
10567 @param ptr [in]  string that points to current token prefix `/`
10568            [out] string that points to next token prefix `/`, or string end
10569 @param end [in] end of the entire JSON Pointer string
10570 @param len [out] unescaped token length
10571 @param esc [out] number of escaped characters in this token
10572 @return head of the token, or NULL if syntax error
10573 */
10574static_inline const char *ptr_next_token(const char **ptr, const char *end,
10575                                         usize *len, usize *esc) {
10576    const char *hdr = *ptr + 1;
10577    const char *cur = hdr;
10578    /* skip unescaped characters */
10579    while (cur < end && *cur != '/' && *cur != '~') cur++;
10580    if (likely(cur == end || *cur != '~')) {
10581        /* no escaped characters, return */
10582        *ptr = cur;
10583        *len = (usize)(cur - hdr);
10584        *esc = 0;
10585        return hdr;
10586    } else {
10587        /* handle escaped characters */
10588        usize esc_num = 0;
10589        while (cur < end && *cur != '/') {
10590            if (*cur++ == '~') {
10591                if (cur == end || (*cur != '0' && *cur != '1')) {
10592                    *ptr = cur - 1;
10593                    return NULL;
10594                }
10595                esc_num++;
10596            }
10597        }
10598        *ptr = cur;
10599        *len = (usize)(cur - hdr) - esc_num;
10600        *esc = esc_num;
10601        return hdr;
10602    }
10603}
10604
10605/**
10606 Convert token string to index.
10607 @param cur [in]  token head
10608 @param len [in]  token length
10609 @param idx [out] the index number, or USIZE_MAX if token is '-'
10610 @return true if token is a valid array index
10611 */
10612static_inline bool ptr_token_to_idx(const char *cur, usize len, usize *idx) {
10613    const char *end = cur + len;
10614    usize num = 0, add;
10615    if (unlikely(len == 0 || len > USIZE_SAFE_DIG)) return false;
10616    if (*cur == '0') {
10617        if (unlikely(len > 1)) return false;
10618        *idx = 0;
10619        return true;
10620    }
10621    if (*cur == '-') {
10622        if (unlikely(len > 1)) return false;
10623        *idx = USIZE_MAX;
10624        return true;
10625    }
10626    for (; cur < end && (add = (usize)((u8)*cur - (u8)'0')) <= 9; cur++) {
10627        num = num * 10 + add;
10628    }
10629    if (unlikely(num == 0 || cur < end)) return false;
10630    *idx = num;
10631    return true;
10632}
10633
10634/**
10635 Compare JSON key with token.
10636 @param key a string key (yyjson_val or yyjson_mut_val)
10637 @param token a JSON pointer token
10638 @param len unescaped token length
10639 @param esc number of escaped characters in this token
10640 @return true if `str` is equal to `token`
10641 */
10642static_inline bool ptr_token_eq(void *key,
10643                                const char *token, usize len, usize esc) {
10644    yyjson_val *val = (yyjson_val *)key;
10645    if (unsafe_yyjson_get_len(val) != len) return false;
10646    if (likely(!esc)) {
10647        return memcmp(val->uni.str, token, len) == 0;
10648    } else {
10649        const char *str = val->uni.str;
10650        for (; len-- > 0; token++, str++) {
10651            if (*token == '~') {
10652                if (*str != (*++token == '0' ? '~' : '/')) return false;
10653            } else {
10654                if (*str != *token) return false;
10655            }
10656        }
10657        return true;
10658    }
10659}
10660
10661/**
10662 Get a value from array by token.
10663 @param arr   an array, should not be NULL or non-array type
10664 @param token a JSON pointer token
10665 @param len   unescaped token length
10666 @param esc   number of escaped characters in this token
10667 @return value at index, or NULL if token is not index or index is out of range
10668 */
10669static_inline yyjson_val *ptr_arr_get(const yyjson_val *arr, const char *token,
10670                                      usize len, usize esc) {
10671    yyjson_val *val = unsafe_yyjson_get_first(arr);
10672    usize num = unsafe_yyjson_get_len(arr), idx = 0;
10673    if (unlikely(num == 0)) return NULL;
10674    if (unlikely(!ptr_token_to_idx(token, len, &idx))) return NULL;
10675    if (unlikely(idx >= num)) return NULL;
10676    if (unsafe_yyjson_arr_is_flat(arr)) {
10677        return val + idx;
10678    } else {
10679        while (idx-- > 0) val = unsafe_yyjson_get_next(val);
10680        return val;
10681    }
10682}
10683
10684/**
10685 Get a value from object by token.
10686 @param obj   [in] an object, should not be NULL or non-object type
10687 @param token [in] a JSON pointer token
10688 @param len   [in] unescaped token length
10689 @param esc   [in] number of escaped characters in this token
10690 @return value associated with the token, or NULL if no value
10691 */
10692static_inline yyjson_val *ptr_obj_get(const yyjson_val *obj, const char *token,
10693                                      usize len, usize esc) {
10694    yyjson_val *key = unsafe_yyjson_get_first(obj);
10695    usize num = unsafe_yyjson_get_len(obj);
10696    if (unlikely(num == 0)) return NULL;
10697    for (; num > 0; num--, key = unsafe_yyjson_get_next(key + 1)) {
10698        if (ptr_token_eq(key, token, len, esc)) return key + 1;
10699    }
10700    return NULL;
10701}
10702
10703/**
10704 Get a value from array by token.
10705 @param arr   [in] an array, should not be NULL or non-array type
10706 @param token [in] a JSON pointer token
10707 @param len   [in] unescaped token length
10708 @param esc   [in] number of escaped characters in this token
10709 @param pre   [out] previous (sibling) value of the returned value
10710 @param last  [out] whether index is last
10711 @return value at index, or NULL if token is not index or index is out of range
10712 */
10713static_inline yyjson_mut_val *ptr_mut_arr_get(const yyjson_mut_val *arr,
10714                                              const char *token,
10715                                              usize len, usize esc,
10716                                              yyjson_mut_val **pre,
10717                                              bool *last) {
10718    yyjson_mut_val *val = (yyjson_mut_val *)arr->uni.ptr; /* last (tail) */
10719    usize num = unsafe_yyjson_get_len(arr), idx;
10720    if (last) *last = false;
10721    if (pre) *pre = NULL;
10722    if (unlikely(num == 0)) {
10723        if (last && len == 1 && (*token == '0' || *token == '-')) *last = true;
10724        return NULL;
10725    }
10726    if (unlikely(!ptr_token_to_idx(token, len, &idx))) return NULL;
10727    if (last) *last = (idx == num || idx == USIZE_MAX);
10728    if (unlikely(idx >= num)) return NULL;
10729    while (idx-- > 0) val = val->next;
10730    if (pre) *pre = val;
10731    return val->next;
10732}
10733
10734/**
10735 Get a value from object by token.
10736 @param obj   [in] an object, should not be NULL or non-object type
10737 @param token [in] a JSON pointer token
10738 @param len   [in] unescaped token length
10739 @param esc   [in] number of escaped characters in this token
10740 @param pre   [out] previous (sibling) key of the returned value's key
10741 @return value associated with the token, or NULL if no value
10742 */
10743static_inline yyjson_mut_val *ptr_mut_obj_get(const yyjson_mut_val *obj,
10744                                              const char *token,
10745                                              usize len, usize esc,
10746                                              yyjson_mut_val **pre) {
10747    yyjson_mut_val *pre_key = (yyjson_mut_val *)obj->uni.ptr, *key;
10748    usize num = unsafe_yyjson_get_len(obj);
10749    if (pre) *pre = NULL;
10750    if (unlikely(num == 0)) return NULL;
10751    for (; num > 0; num--, pre_key = key) {
10752        key = pre_key->next->next;
10753        if (ptr_token_eq(key, token, len, esc)) {
10754            if (pre) *pre = pre_key;
10755            return key->next;
10756        }
10757    }
10758    return NULL;
10759}
10760
10761/**
10762 Create a string value with JSON pointer token.
10763 @param token [in] a JSON pointer token
10764 @param len   [in] unescaped token length
10765 @param esc   [in] number of escaped characters in this token
10766 @param doc   [in] used for memory allocation when creating value
10767 @return new string value, or NULL if memory allocation failed
10768 */
10769static_inline yyjson_mut_val *ptr_new_key(const char *token,
10770                                          usize len, usize esc,
10771                                          yyjson_mut_doc *doc) {
10772    const char *src = token;
10773    if (likely(!esc)) {
10774        return yyjson_mut_strncpy(doc, src, len);
10775    } else {
10776        const char *end = src + len + esc;
10777        char *dst = unsafe_yyjson_mut_str_alc(doc, len + esc);
10778        char *str = dst;
10779        if (unlikely(!dst)) return NULL;
10780        for (; src < end; src++, dst++) {
10781            if (*src != '~') *dst = *src;
10782            else *dst = (*++src == '0' ? '~' : '/');
10783        }
10784        *dst = '\0';
10785        return yyjson_mut_strn(doc, str, len);
10786    }
10787}
10788
10789/* macros for yyjson_ptr */
10790#define return_err(_ret, _code, _pos, _msg) do { \
10791    if (err) { \
10792        err->code = YYJSON_PTR_ERR_##_code; \
10793        err->msg = _msg; \
10794        err->pos = (usize)(_pos); \
10795    } \
10796    return _ret; \
10797} while (false)
10798
10799#define return_err_resolve(_ret, _pos) \
10800    return_err(_ret, RESOLVE, _pos, "JSON pointer cannot be resolved")
10801#define return_err_syntax(_ret, _pos) \
10802    return_err(_ret, SYNTAX, _pos, "invalid escaped character")
10803#define return_err_alloc(_ret) \
10804    return_err(_ret, MEMORY_ALLOCATION, 0, "failed to create value")
10805
10806yyjson_val *unsafe_yyjson_ptr_getx(const yyjson_val *val,
10807                                   const char *ptr, size_t ptr_len,
10808                                   yyjson_ptr_err *err) {
10809
10810    const char *hdr = ptr, *end = ptr + ptr_len, *token;
10811    usize len, esc;
10812    yyjson_type type;
10813
10814    while (true) {
10815        token = ptr_next_token(&ptr, end, &len, &esc);
10816        if (unlikely(!token)) return_err_syntax(NULL, ptr - hdr);
10817        type = unsafe_yyjson_get_type(val);
10818        if (type == YYJSON_TYPE_OBJ) {
10819            val = ptr_obj_get(val, token, len, esc);
10820        } else if (type == YYJSON_TYPE_ARR) {
10821            val = ptr_arr_get(val, token, len, esc);
10822        } else {
10823            val = NULL;
10824        }
10825        if (!val) return_err_resolve(NULL, token - hdr);
10826        if (ptr == end) return constcast(yyjson_val *)val;
10827    }
10828}
10829
10830yyjson_mut_val *unsafe_yyjson_mut_ptr_getx(
10831    const yyjson_mut_val *val, const char *ptr, size_t ptr_len,
10832    yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
10833
10834    const char *hdr = ptr, *end = ptr + ptr_len, *token;
10835    usize len, esc;
10836    yyjson_mut_val *ctn, *pre = NULL;
10837    yyjson_type type;
10838    bool idx_is_last = false;
10839
10840    while (true) {
10841        token = ptr_next_token(&ptr, end, &len, &esc);
10842        if (unlikely(!token)) return_err_syntax(NULL, ptr - hdr);
10843        ctn = constcast(yyjson_mut_val *)val;
10844        type = unsafe_yyjson_get_type(val);
10845        if (type == YYJSON_TYPE_OBJ) {
10846            val = ptr_mut_obj_get(val, token, len, esc, &pre);
10847        } else if (type == YYJSON_TYPE_ARR) {
10848            val = ptr_mut_arr_get(val, token, len, esc, &pre, &idx_is_last);
10849        } else {
10850            val = NULL;
10851        }
10852        if (ctx && (ptr == end)) {
10853            if (type == YYJSON_TYPE_OBJ ||
10854                (type == YYJSON_TYPE_ARR && (val || idx_is_last))) {
10855                ctx->ctn = ctn;
10856                ctx->pre = pre;
10857            }
10858        }
10859        if (!val) return_err_resolve(NULL, token - hdr);
10860        if (ptr == end) return constcast(yyjson_mut_val *)val;
10861    }
10862}
10863
10864bool unsafe_yyjson_mut_ptr_putx(
10865    yyjson_mut_val *val, const char *ptr, size_t ptr_len,
10866    yyjson_mut_val *new_val, yyjson_mut_doc *doc, bool create_parent,
10867    bool insert_new, yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
10868
10869    const char *hdr = ptr, *end = ptr + ptr_len, *token;
10870    usize token_len, esc, ctn_len;
10871    yyjson_mut_val *ctn, *key, *pre = NULL;
10872    yyjson_mut_val *sep_ctn = NULL, *sep_key = NULL, *sep_val = NULL;
10873    yyjson_type ctn_type;
10874    bool idx_is_last = false;
10875
10876    /* skip exist parent nodes */
10877    while (true) {
10878        token = ptr_next_token(&ptr, end, &token_len, &esc);
10879        if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
10880        ctn = val;
10881        ctn_type = unsafe_yyjson_get_type(ctn);
10882        if (ctn_type == YYJSON_TYPE_OBJ) {
10883            val = ptr_mut_obj_get(ctn, token, token_len, esc, &pre);
10884        } else if (ctn_type == YYJSON_TYPE_ARR) {
10885            val = ptr_mut_arr_get(ctn, token, token_len, esc, &pre,
10886                                  &idx_is_last);
10887        } else return_err_resolve(false, token - hdr);
10888        if (!val) break;
10889        if (ptr == end) break; /* is last token */
10890    }
10891
10892    /* create parent nodes if not exist */
10893    if (unlikely(ptr != end)) { /* not last token */
10894        if (!create_parent) return_err_resolve(false, token - hdr);
10895
10896        /* add value at last index if container is array */
10897        if (ctn_type == YYJSON_TYPE_ARR) {
10898            if (!idx_is_last || !insert_new) {
10899                return_err_resolve(false, token - hdr);
10900            }
10901            val = yyjson_mut_obj(doc);
10902            if (!val) return_err_alloc(false);
10903
10904            /* delay attaching until all operations are completed */
10905            sep_ctn = ctn;
10906            sep_key = NULL;
10907            sep_val = val;
10908
10909            /* move to next token */
10910            ctn = val;
10911            val = NULL;
10912            ctn_type = YYJSON_TYPE_OBJ;
10913            token = ptr_next_token(&ptr, end, &token_len, &esc);
10914            if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
10915        }
10916
10917        /* container is object, create parent nodes */
10918        while (ptr != end) { /* not last token */
10919            key = ptr_new_key(token, token_len, esc, doc);
10920            if (!key) return_err_alloc(false);
10921            val = yyjson_mut_obj(doc);
10922            if (!val) return_err_alloc(false);
10923
10924            /* delay attaching until all operations are completed */
10925            if (!sep_ctn) {
10926                sep_ctn = ctn;
10927                sep_key = key;
10928                sep_val = val;
10929            } else {
10930                yyjson_mut_obj_add(ctn, key, val);
10931            }
10932
10933            /* move to next token */
10934            ctn = val;
10935            val = NULL;
10936            token = ptr_next_token(&ptr, end, &token_len, &esc);
10937            if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
10938        }
10939    }
10940
10941    /* JSON pointer is resolved, insert or replace target value */
10942    ctn_len = unsafe_yyjson_get_len(ctn);
10943    if (ctn_type == YYJSON_TYPE_OBJ) {
10944        if (ctx) ctx->ctn = ctn;
10945        if (!val || insert_new) {
10946            /* insert new key-value pair */
10947            key = ptr_new_key(token, token_len, esc, doc);
10948            if (unlikely(!key)) return_err_alloc(false);
10949            if (ctx) ctx->pre = ctn_len ? (yyjson_mut_val *)ctn->uni.ptr : key;
10950            unsafe_yyjson_mut_obj_add(ctn, key, new_val, ctn_len);
10951        } else {
10952            /* replace exist value */
10953            key = pre->next->next;
10954            if (ctx) ctx->pre = pre;
10955            if (ctx) ctx->old = val;
10956            yyjson_mut_obj_put(ctn, key, new_val);
10957        }
10958    } else {
10959        /* array */
10960        if (ctx && (val || idx_is_last)) ctx->ctn = ctn;
10961        if (insert_new) {
10962            /* append new value */
10963            if (val) {
10964                pre->next = new_val;
10965                new_val->next = val;
10966                if (ctx) ctx->pre = pre;
10967                unsafe_yyjson_set_len(ctn, ctn_len + 1);
10968            } else if (idx_is_last) {
10969                if (ctx) ctx->pre = ctn_len ?
10970                    (yyjson_mut_val *)ctn->uni.ptr : new_val;
10971                yyjson_mut_arr_append(ctn, new_val);
10972            } else {
10973                return_err_resolve(false, token - hdr);
10974            }
10975        } else {
10976            /* replace exist value */
10977            if (!val) return_err_resolve(false, token - hdr);
10978            if (ctn_len > 1) {
10979                new_val->next = val->next;
10980                pre->next = new_val;
10981                if (ctn->uni.ptr == val) ctn->uni.ptr = new_val;
10982            } else {
10983                new_val->next = new_val;
10984                ctn->uni.ptr = new_val;
10985                pre = new_val;
10986            }
10987            if (ctx) ctx->pre = pre;
10988            if (ctx) ctx->old = val;
10989        }
10990    }
10991
10992    /* all operations are completed, attach the new components to the target */
10993    if (unlikely(sep_ctn)) {
10994        if (sep_key) yyjson_mut_obj_add(sep_ctn, sep_key, sep_val);
10995        else yyjson_mut_arr_append(sep_ctn, sep_val);
10996    }
10997    return true;
10998}
10999
11000yyjson_mut_val *unsafe_yyjson_mut_ptr_replacex(
11001    yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val,
11002    yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
11003
11004    yyjson_mut_val *cur_val;
11005    yyjson_ptr_ctx cur_ctx;
11006    memset(&cur_ctx, 0, sizeof(cur_ctx));
11007    if (!ctx) ctx = &cur_ctx;
11008    cur_val = unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err);
11009    if (!cur_val) return NULL;
11010
11011    if (yyjson_mut_is_obj(ctx->ctn)) {
11012        yyjson_mut_val *key = ctx->pre->next->next;
11013        yyjson_mut_obj_put(ctx->ctn, key, new_val);
11014    } else {
11015        yyjson_ptr_ctx_replace(ctx, new_val);
11016    }
11017    ctx->old = cur_val;
11018    return cur_val;
11019}
11020
11021yyjson_mut_val *unsafe_yyjson_mut_ptr_removex(
11022    yyjson_mut_val *val, const char *ptr, size_t len,
11023    yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) {
11024
11025    yyjson_mut_val *cur_val;
11026    yyjson_ptr_ctx cur_ctx;
11027    memset(&cur_ctx, 0, sizeof(cur_ctx));
11028    if (!ctx) ctx = &cur_ctx;
11029    cur_val = unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err);
11030    if (cur_val) {
11031        if (yyjson_mut_is_obj(ctx->ctn)) {
11032            yyjson_mut_val *key = ctx->pre->next->next;
11033            yyjson_mut_obj_put(ctx->ctn, key, NULL);
11034        } else {
11035            yyjson_ptr_ctx_remove(ctx);
11036        }
11037        ctx->pre = NULL;
11038        ctx->old = cur_val;
11039    }
11040    return cur_val;
11041}
11042
11043/* macros for yyjson_ptr */
11044#undef return_err
11045#undef return_err_resolve
11046#undef return_err_syntax
11047#undef return_err_alloc
11048
11049
11050
11051/*==============================================================================
11052 * MARK: - JSON Patch API (RFC 6902) (Public)
11053 *============================================================================*/
11054
11055/* JSON Patch operation */
11056typedef enum patch_op {
11057    PATCH_OP_ADD,       /* path, value */
11058    PATCH_OP_REMOVE,    /* path */
11059    PATCH_OP_REPLACE,   /* path, value */
11060    PATCH_OP_MOVE,      /* from, path */
11061    PATCH_OP_COPY,      /* from, path */
11062    PATCH_OP_TEST,      /* path, value */
11063    PATCH_OP_NONE       /* invalid */
11064} patch_op;
11065
11066static patch_op patch_op_get(yyjson_val *op) {
11067    const char *str = op->uni.str;
11068    switch (unsafe_yyjson_get_len(op)) {
11069        case 3:
11070            if (!memcmp(str, "add", 3)) return PATCH_OP_ADD;
11071            return PATCH_OP_NONE;
11072        case 4:
11073            if (!memcmp(str, "move", 4)) return PATCH_OP_MOVE;
11074            if (!memcmp(str, "copy", 4)) return PATCH_OP_COPY;
11075            if (!memcmp(str, "test", 4)) return PATCH_OP_TEST;
11076            return PATCH_OP_NONE;
11077        case 6:
11078            if (!memcmp(str, "remove", 6)) return PATCH_OP_REMOVE;
11079            return PATCH_OP_NONE;
11080        case 7:
11081            if (!memcmp(str, "replace", 7)) return PATCH_OP_REPLACE;
11082            return PATCH_OP_NONE;
11083        default:
11084            return PATCH_OP_NONE;
11085    }
11086}
11087
11088/* macros for yyjson_patch */
11089#define return_err(_code, _msg) do { \
11090    if (err->ptr.code == YYJSON_PTR_ERR_MEMORY_ALLOCATION) { \
11091        err->code = YYJSON_PATCH_ERROR_MEMORY_ALLOCATION; \
11092        err->msg = _msg; \
11093        memset(&err->ptr, 0, sizeof(yyjson_ptr_err)); \
11094    } else { \
11095        err->code = YYJSON_PATCH_ERROR_##_code; \
11096        err->msg = _msg; \
11097        err->idx = iter.idx ? iter.idx - 1 : 0; \
11098    } \
11099    return NULL; \
11100} while (false)
11101
11102#define return_err_copy() \
11103    return_err(MEMORY_ALLOCATION, "failed to copy value")
11104#define return_err_key(_key) \
11105    return_err(MISSING_KEY, "missing key " _key)
11106#define return_err_val(_key) \
11107    return_err(INVALID_MEMBER, "invalid member " _key)
11108
11109#define ptr_get(_ptr) yyjson_mut_ptr_getx( \
11110    root, _ptr->uni.str, _ptr##_len, NULL, &err->ptr)
11111#define ptr_add(_ptr, _val) yyjson_mut_ptr_addx( \
11112    root, _ptr->uni.str, _ptr##_len, _val, doc, false, NULL, &err->ptr)
11113#define ptr_remove(_ptr) yyjson_mut_ptr_removex( \
11114    root, _ptr->uni.str, _ptr##_len, NULL, &err->ptr)
11115#define ptr_replace(_ptr, _val)yyjson_mut_ptr_replacex( \
11116    root, _ptr->uni.str, _ptr##_len, _val, NULL, &err->ptr)
11117
11118yyjson_mut_val *yyjson_patch(yyjson_mut_doc *doc,
11119                             const yyjson_val *orig,
11120                             const yyjson_val *patch,
11121                             yyjson_patch_err *err) {
11122
11123    yyjson_mut_val *root;
11124    yyjson_val *obj;
11125    yyjson_arr_iter iter;
11126    yyjson_patch_err err_tmp;
11127    if (!err) err = &err_tmp;
11128    memset(err, 0, sizeof(*err));
11129    memset(&iter, 0, sizeof(iter));
11130
11131    if (unlikely(!doc || !orig || !patch)) {
11132        return_err(INVALID_PARAMETER, "input parameter is NULL");
11133    }
11134    if (unlikely(!yyjson_is_arr(patch))) {
11135        return_err(INVALID_PARAMETER, "input patch is not array");
11136    }
11137    root = yyjson_val_mut_copy(doc, orig);
11138    if (unlikely(!root)) return_err_copy();
11139
11140    /* iterate through the patch array */
11141    yyjson_arr_iter_init(patch, &iter);
11142    while ((obj = yyjson_arr_iter_next(&iter))) {
11143        patch_op op_enum;
11144        yyjson_val *op, *path, *from = NULL, *value;
11145        yyjson_mut_val *val = NULL, *test;
11146        usize path_len, from_len = 0;
11147        if (unlikely(!unsafe_yyjson_is_obj(obj))) {
11148            return_err(INVALID_OPERATION, "JSON patch operation is not object");
11149        }
11150
11151        /* get required member: op */
11152        op = yyjson_obj_get(obj, "op");
11153        if (unlikely(!op)) return_err_key("`op`");
11154        if (unlikely(!yyjson_is_str(op))) return_err_val("`op`");
11155        op_enum = patch_op_get(op);
11156
11157        /* get required member: path */
11158        path = yyjson_obj_get(obj, "path");
11159        if (unlikely(!path)) return_err_key("`path`");
11160        if (unlikely(!yyjson_is_str(path))) return_err_val("`path`");
11161        path_len = unsafe_yyjson_get_len(path);
11162
11163        /* get required member: value, from */
11164        switch ((int)op_enum) {
11165            case PATCH_OP_ADD: case PATCH_OP_REPLACE: case PATCH_OP_TEST:
11166                value = yyjson_obj_get(obj, "value");
11167                if (unlikely(!value)) return_err_key("`value`");
11168                val = yyjson_val_mut_copy(doc, value);
11169                if (unlikely(!val)) return_err_copy();
11170                break;
11171            case PATCH_OP_MOVE: case PATCH_OP_COPY:
11172                from = yyjson_obj_get(obj, "from");
11173                if (unlikely(!from)) return_err_key("`from`");
11174                if (unlikely(!yyjson_is_str(from))) return_err_val("`from`");
11175                from_len = unsafe_yyjson_get_len(from);
11176                break;
11177            default:
11178                break;
11179        }
11180
11181        /* perform an operation */
11182        switch ((int)op_enum) {
11183            case PATCH_OP_ADD: /* add(path, val) */
11184                if (unlikely(path_len == 0)) { root = val; break; }
11185                if (unlikely(!ptr_add(path, val))) {
11186                    return_err(POINTER, "failed to add `path`");
11187                }
11188                break;
11189            case PATCH_OP_REMOVE: /* remove(path) */
11190                if (unlikely(!ptr_remove(path))) {
11191                    return_err(POINTER, "failed to remove `path`");
11192                }
11193                break;
11194            case PATCH_OP_REPLACE: /* replace(path, val) */
11195                if (unlikely(path_len == 0)) { root = val; break; }
11196                if (unlikely(!ptr_replace(path, val))) {
11197                    return_err(POINTER, "failed to replace `path`");
11198                }
11199                break;
11200            case PATCH_OP_MOVE: /* val = remove(from), add(path, val) */
11201                if (unlikely(from_len == 0 && path_len == 0)) break;
11202                val = ptr_remove(from);
11203                if (unlikely(!val)) {
11204                    return_err(POINTER, "failed to remove `from`");
11205                }
11206                if (unlikely(path_len == 0)) { root = val; break; }
11207                if (unlikely(!ptr_add(path, val))) {
11208                    return_err(POINTER, "failed to add `path`");
11209                }
11210                break;
11211            case PATCH_OP_COPY: /* val = get(from).copy, add(path, val) */
11212                val = ptr_get(from);
11213                if (unlikely(!val)) {
11214                    return_err(POINTER, "failed to get `from`");
11215                }
11216                if (unlikely(path_len == 0)) { root = val; break; }
11217                val = yyjson_mut_val_mut_copy(doc, val);
11218                if (unlikely(!val)) return_err_copy();
11219                if (unlikely(!ptr_add(path, val))) {
11220                    return_err(POINTER, "failed to add `path`");
11221                }
11222                break;
11223            case PATCH_OP_TEST: /* test = get(path), test.eq(val) */
11224                test = ptr_get(path);
11225                if (unlikely(!test)) {
11226                    return_err(POINTER, "failed to get `path`");
11227                }
11228                if (unlikely(!yyjson_mut_equals(val, test))) {
11229                    return_err(EQUAL, "failed to test equal");
11230                }
11231                break;
11232            default:
11233                return_err(INVALID_MEMBER, "unsupported `op`");
11234        }
11235    }
11236    return root;
11237}
11238
11239yyjson_mut_val *yyjson_mut_patch(yyjson_mut_doc *doc,
11240                                 const yyjson_mut_val *orig,
11241                                 const yyjson_mut_val *patch,
11242                                 yyjson_patch_err *err) {
11243    yyjson_mut_val *root, *obj;
11244    yyjson_mut_arr_iter iter;
11245    yyjson_patch_err err_tmp;
11246    if (!err) err = &err_tmp;
11247    memset(err, 0, sizeof(*err));
11248    memset(&iter, 0, sizeof(iter));
11249
11250    if (unlikely(!doc || !orig || !patch)) {
11251        return_err(INVALID_PARAMETER, "input parameter is NULL");
11252    }
11253    if (unlikely(!yyjson_mut_is_arr(patch))) {
11254        return_err(INVALID_PARAMETER, "input patch is not array");
11255    }
11256    root = yyjson_mut_val_mut_copy(doc, orig);
11257    if (unlikely(!root)) return_err_copy();
11258
11259    /* iterate through the patch array */
11260    yyjson_mut_arr_iter_init(constcast(yyjson_mut_val *)patch, &iter);
11261    while ((obj = yyjson_mut_arr_iter_next(&iter))) {
11262        patch_op op_enum;
11263        yyjson_mut_val *op, *path, *from = NULL, *value;
11264        yyjson_mut_val *val = NULL, *test;
11265        usize path_len, from_len = 0;
11266        if (!unsafe_yyjson_is_obj(obj)) {
11267            return_err(INVALID_OPERATION, "JSON patch operation is not object");
11268        }
11269
11270        /* get required member: op */
11271        op = yyjson_mut_obj_get(obj, "op");
11272        if (unlikely(!op)) return_err_key("`op`");
11273        if (unlikely(!yyjson_mut_is_str(op))) return_err_val("`op`");
11274        op_enum = patch_op_get((yyjson_val *)(void *)op);
11275
11276        /* get required member: path */
11277        path = yyjson_mut_obj_get(obj, "path");
11278        if (unlikely(!path)) return_err_key("`path`");
11279        if (unlikely(!yyjson_mut_is_str(path))) return_err_val("`path`");
11280        path_len = unsafe_yyjson_get_len(path);
11281
11282        /* get required member: value, from */
11283        switch ((int)op_enum) {
11284            case PATCH_OP_ADD: case PATCH_OP_REPLACE: case PATCH_OP_TEST:
11285                value = yyjson_mut_obj_get(obj, "value");
11286                if (unlikely(!value)) return_err_key("`value`");
11287                val = yyjson_mut_val_mut_copy(doc, value);
11288                if (unlikely(!val)) return_err_copy();
11289                break;
11290            case PATCH_OP_MOVE: case PATCH_OP_COPY:
11291                from = yyjson_mut_obj_get(obj, "from");
11292                if (unlikely(!from)) return_err_key("`from`");
11293                if (unlikely(!yyjson_mut_is_str(from))) {
11294                    return_err_val("`from`");
11295                }
11296                from_len = unsafe_yyjson_get_len(from);
11297                break;
11298            default:
11299                break;
11300        }
11301
11302        /* perform an operation */
11303        switch ((int)op_enum) {
11304            case PATCH_OP_ADD: /* add(path, val) */
11305                if (unlikely(path_len == 0)) { root = val; break; }
11306                if (unlikely(!ptr_add(path, val))) {
11307                    return_err(POINTER, "failed to add `path`");
11308                }
11309                break;
11310            case PATCH_OP_REMOVE: /* remove(path) */
11311                if (unlikely(!ptr_remove(path))) {
11312                    return_err(POINTER, "failed to remove `path`");
11313                }
11314                break;
11315            case PATCH_OP_REPLACE: /* replace(path, val) */
11316                if (unlikely(path_len == 0)) { root = val; break; }
11317                if (unlikely(!ptr_replace(path, val))) {
11318                    return_err(POINTER, "failed to replace `path`");
11319                }
11320                break;
11321            case PATCH_OP_MOVE: /* val = remove(from), add(path, val) */
11322                if (unlikely(from_len == 0 && path_len == 0)) break;
11323                val = ptr_remove(from);
11324                if (unlikely(!val)) {
11325                    return_err(POINTER, "failed to remove `from`");
11326                }
11327                if (unlikely(path_len == 0)) { root = val; break; }
11328                if (unlikely(!ptr_add(path, val))) {
11329                    return_err(POINTER, "failed to add `path`");
11330                }
11331                break;
11332            case PATCH_OP_COPY: /* val = get(from).copy, add(path, val) */
11333                val = ptr_get(from);
11334                if (unlikely(!val)) {
11335                    return_err(POINTER, "failed to get `from`");
11336                }
11337                if (unlikely(path_len == 0)) { root = val; break; }
11338                val = yyjson_mut_val_mut_copy(doc, val);
11339                if (unlikely(!val)) return_err_copy();
11340                if (unlikely(!ptr_add(path, val))) {
11341                    return_err(POINTER, "failed to add `path`");
11342                }
11343                break;
11344            case PATCH_OP_TEST: /* test = get(path), test.eq(val) */
11345                test = ptr_get(path);
11346                if (unlikely(!test)) {
11347                    return_err(POINTER, "failed to get `path`");
11348                }
11349                if (unlikely(!yyjson_mut_equals(val, test))) {
11350                    return_err(EQUAL, "failed to test equal");
11351                }
11352                break;
11353            default:
11354                return_err(INVALID_MEMBER, "unsupported `op`");
11355        }
11356    }
11357    return root;
11358}
11359
11360/* macros for yyjson_patch */
11361#undef return_err
11362#undef return_err_copy
11363#undef return_err_key
11364#undef return_err_val
11365#undef ptr_get
11366#undef ptr_add
11367#undef ptr_remove
11368#undef ptr_replace
11369
11370
11371
11372/*==============================================================================
11373 * MARK: - JSON Merge-Patch API (RFC 7386) (Public)
11374 *============================================================================*/
11375
11376yyjson_mut_val *yyjson_merge_patch(yyjson_mut_doc *doc,
11377                                   const yyjson_val *orig,
11378                                   const yyjson_val *patch) {
11379    usize idx, max;
11380    yyjson_val *key, *orig_val, *patch_val, local_orig;
11381    yyjson_mut_val *builder, *mut_key, *mut_val, *merged_val;
11382
11383    if (unlikely(!yyjson_is_obj(patch))) {
11384        return yyjson_val_mut_copy(doc, patch);
11385    }
11386
11387    builder = yyjson_mut_obj(doc);
11388    if (unlikely(!builder)) return NULL;
11389
11390    memset(&local_orig, 0, sizeof(local_orig));
11391    if (!yyjson_is_obj(orig)) {
11392        local_orig.tag = builder->tag;
11393        local_orig.uni = builder->uni;
11394        orig = &local_orig;
11395    }
11396
11397    /* If orig is contributing, copy any items not modified by the patch */
11398    if (orig != &local_orig) {
11399        yyjson_obj_foreach(orig, idx, max, key, orig_val) {
11400            patch_val = yyjson_obj_getn(patch,
11401                                        unsafe_yyjson_get_str(key),
11402                                        unsafe_yyjson_get_len(key));
11403            if (!patch_val) {
11404                mut_key = yyjson_val_mut_copy(doc, key);
11405                mut_val = yyjson_val_mut_copy(doc, orig_val);
11406                if (!yyjson_mut_obj_add(builder, mut_key, mut_val)) return NULL;
11407            }
11408        }
11409    }
11410
11411    /* Merge items modified by the patch. */
11412    yyjson_obj_foreach(patch, idx, max, key, patch_val) {
11413        /* null indicates the field is removed. */
11414        if (unsafe_yyjson_is_null(patch_val)) {
11415            continue;
11416        }
11417        mut_key = yyjson_val_mut_copy(doc, key);
11418        orig_val = yyjson_obj_getn(orig,
11419                                   unsafe_yyjson_get_str(key),
11420                                   unsafe_yyjson_get_len(key));
11421        merged_val = yyjson_merge_patch(doc, orig_val, patch_val);
11422        if (!yyjson_mut_obj_add(builder, mut_key, merged_val)) return NULL;
11423    }
11424
11425    return builder;
11426}
11427
11428yyjson_mut_val *yyjson_mut_merge_patch(yyjson_mut_doc *doc,
11429                                       const yyjson_mut_val *orig,
11430                                       const yyjson_mut_val *patch) {
11431    usize idx, max;
11432    yyjson_mut_val *key, *orig_val, *patch_val, local_orig;
11433    yyjson_mut_val *builder, *mut_key, *mut_val, *merged_val;
11434
11435    if (unlikely(!yyjson_mut_is_obj(patch))) {
11436        return yyjson_mut_val_mut_copy(doc, patch);
11437    }
11438
11439    builder = yyjson_mut_obj(doc);
11440    if (unlikely(!builder)) return NULL;
11441
11442    memset(&local_orig, 0, sizeof(local_orig));
11443    if (!yyjson_mut_is_obj(orig)) {
11444        local_orig.tag = builder->tag;
11445        local_orig.uni = builder->uni;
11446        orig = &local_orig;
11447    }
11448
11449    /* If orig is contributing, copy any items not modified by the patch */
11450    if (orig != &local_orig) {
11451        yyjson_mut_obj_foreach(orig, idx, max, key, orig_val) {
11452            patch_val = yyjson_mut_obj_getn(patch,
11453                                            unsafe_yyjson_get_str(key),
11454                                            unsafe_yyjson_get_len(key));
11455            if (!patch_val) {
11456                mut_key = yyjson_mut_val_mut_copy(doc, key);
11457                mut_val = yyjson_mut_val_mut_copy(doc, orig_val);
11458                if (!yyjson_mut_obj_add(builder, mut_key, mut_val)) return NULL;
11459            }
11460        }
11461    }
11462
11463    /* Merge items modified by the patch. */
11464    yyjson_mut_obj_foreach(patch, idx, max, key, patch_val) {
11465        /* null indicates the field is removed. */
11466        if (unsafe_yyjson_is_null(patch_val)) {
11467            continue;
11468        }
11469        mut_key = yyjson_mut_val_mut_copy(doc, key);
11470        orig_val = yyjson_mut_obj_getn(orig,
11471                                       unsafe_yyjson_get_str(key),
11472                                       unsafe_yyjson_get_len(key));
11473        merged_val = yyjson_mut_merge_patch(doc, orig_val, patch_val);
11474        if (!yyjson_mut_obj_add(builder, mut_key, merged_val)) return NULL;
11475    }
11476
11477    return builder;
11478}
11479
11480#endif /* YYJSON_DISABLE_UTILS */