| 1 | /*============================================================================== |
| 2 | * Created by Yaoyuan on 2019/3/9. |
| 3 | * Copyright (C) 2019 Yaoyuan <ibireme@gmail.com>. |
| 4 | * |
| 5 | * Released under the MIT License: |
| 6 | * https://github.com/ibireme/yyjson/blob/master/LICENSE |
| 7 | *============================================================================*/ |
| 8 | |
| 9 | #include "yyjson.h" |
| 10 | #include <math.h> |
| 11 | |
| 12 | |
| 13 | |
| 14 | /*============================================================================== |
| 15 | * Compile Hint Begin |
| 16 | *============================================================================*/ |
| 17 | |
| 18 | /* warning suppress begin */ |
| 19 | #if defined(__clang__) |
| 20 | # pragma clang diagnostic push |
| 21 | # pragma clang diagnostic ignored "-Wunused-function" |
| 22 | # pragma clang diagnostic ignored "-Wunused-parameter" |
| 23 | # pragma clang diagnostic ignored "-Wunused-label" |
| 24 | # pragma clang diagnostic ignored "-Wunused-macros" |
| 25 | #elif defined(__GNUC__) |
| 26 | # if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) |
| 27 | # pragma GCC diagnostic push |
| 28 | # endif |
| 29 | # pragma GCC diagnostic ignored "-Wunused-function" |
| 30 | # pragma GCC diagnostic ignored "-Wunused-parameter" |
| 31 | # pragma GCC diagnostic ignored "-Wunused-label" |
| 32 | # pragma GCC diagnostic ignored "-Wunused-macros" |
| 33 | #elif defined(_MSC_VER) |
| 34 | # pragma warning(push) |
| 35 | # pragma warning(disable:4100) /* unreferenced formal parameter */ |
| 36 | # pragma warning(disable:4102) /* unreferenced label */ |
| 37 | # pragma warning(disable:4127) /* conditional expression is constant */ |
| 38 | # pragma warning(disable:4706) /* assignment within conditional expression */ |
| 39 | #endif |
| 40 | |
| 41 | |
| 42 | |
| 43 | /*============================================================================== |
| 44 | * Version |
| 45 | *============================================================================*/ |
| 46 | |
| 47 | uint32_t yyjson_version(void) { |
| 48 | return YYJSON_VERSION_HEX; |
| 49 | } |
| 50 | |
| 51 | |
| 52 | |
| 53 | /*============================================================================== |
| 54 | * Flags |
| 55 | *============================================================================*/ |
| 56 | |
| 57 | /* gcc version check */ |
| 58 | #if defined(__GNUC__) |
| 59 | # if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) |
| 60 | # define yyjson_gcc_available(major, minor, patch) \ |
| 61 | ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) \ |
| 62 | >= (major * 10000 + minor * 100 + patch)) |
| 63 | # elif defined(__GNUC_MINOR__) |
| 64 | # define yyjson_gcc_available(major, minor, patch) \ |
| 65 | ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100) \ |
| 66 | >= (major * 10000 + minor * 100 + patch)) |
| 67 | # else |
| 68 | # define yyjson_gcc_available(major, minor, patch) \ |
| 69 | ((__GNUC__ * 10000) >= (major * 10000 + minor * 100 + patch)) |
| 70 | # endif |
| 71 | #else |
| 72 | # define yyjson_gcc_available(major, minor, patch) 0 |
| 73 | #endif |
| 74 | |
| 75 | /* real gcc check */ |
| 76 | #if !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__ICC) && \ |
| 77 | defined(__GNUC__) && defined(__GNUC_MINOR__) |
| 78 | # define YYJSON_IS_REAL_GCC 1 |
| 79 | #else |
| 80 | # define YYJSON_IS_REAL_GCC 0 |
| 81 | #endif |
| 82 | |
| 83 | /* msvc intrinsic */ |
| 84 | #if YYJSON_MSC_VER >= 1400 |
| 85 | # include <intrin.h> |
| 86 | # if defined(_M_AMD64) || defined(_M_ARM64) |
| 87 | # define MSC_HAS_BIT_SCAN_64 1 |
| 88 | # pragma intrinsic(_BitScanForward64) |
| 89 | # pragma intrinsic(_BitScanReverse64) |
| 90 | # else |
| 91 | # define MSC_HAS_BIT_SCAN_64 0 |
| 92 | # endif |
| 93 | # if defined(_M_AMD64) || defined(_M_ARM64) || \ |
| 94 | defined(_M_IX86) || defined(_M_ARM) |
| 95 | # define MSC_HAS_BIT_SCAN 1 |
| 96 | # pragma intrinsic(_BitScanForward) |
| 97 | # pragma intrinsic(_BitScanReverse) |
| 98 | # else |
| 99 | # define MSC_HAS_BIT_SCAN 0 |
| 100 | # endif |
| 101 | # if defined(_M_AMD64) |
| 102 | # define MSC_HAS_UMUL128 1 |
| 103 | # pragma intrinsic(_umul128) |
| 104 | # else |
| 105 | # define MSC_HAS_UMUL128 0 |
| 106 | # endif |
| 107 | #else |
| 108 | # define MSC_HAS_BIT_SCAN_64 0 |
| 109 | # define MSC_HAS_BIT_SCAN 0 |
| 110 | # define MSC_HAS_UMUL128 0 |
| 111 | #endif |
| 112 | |
| 113 | /* gcc builtin */ |
| 114 | #if yyjson_has_builtin(__builtin_clzll) || yyjson_gcc_available(3, 4, 0) |
| 115 | # define GCC_HAS_CLZLL 1 |
| 116 | #else |
| 117 | # define GCC_HAS_CLZLL 0 |
| 118 | #endif |
| 119 | |
| 120 | #if yyjson_has_builtin(__builtin_ctzll) || yyjson_gcc_available(3, 4, 0) |
| 121 | # define GCC_HAS_CTZLL 1 |
| 122 | #else |
| 123 | # define GCC_HAS_CTZLL 0 |
| 124 | #endif |
| 125 | |
| 126 | /* int128 type */ |
| 127 | #if defined(__SIZEOF_INT128__) && (__SIZEOF_INT128__ == 16) && \ |
| 128 | (defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER)) |
| 129 | # define YYJSON_HAS_INT128 1 |
| 130 | #else |
| 131 | # define YYJSON_HAS_INT128 0 |
| 132 | #endif |
| 133 | |
| 134 | /* IEEE 754 floating-point binary representation */ |
| 135 | #if defined(__STDC_IEC_559__) || defined(__STDC_IEC_60559_BFP__) |
| 136 | # define YYJSON_HAS_IEEE_754 1 |
| 137 | #elif (FLT_RADIX == 2) && (DBL_MANT_DIG == 53) && (DBL_DIG == 15) && \ |
| 138 | (DBL_MIN_EXP == -1021) && (DBL_MAX_EXP == 1024) && \ |
| 139 | (DBL_MIN_10_EXP == -307) && (DBL_MAX_10_EXP == 308) |
| 140 | # define YYJSON_HAS_IEEE_754 1 |
| 141 | #else |
| 142 | # define YYJSON_HAS_IEEE_754 0 |
| 143 | #endif |
| 144 | |
| 145 | /* |
| 146 | Correct rounding in double number computations. |
| 147 | |
| 148 | On the x86 architecture, some compilers may use x87 FPU instructions for |
| 149 | floating-point arithmetic. The x87 FPU loads all floating point number as |
| 150 | 80-bit double-extended precision internally, then rounds the result to original |
| 151 | precision, which may produce inaccurate results. For a more detailed |
| 152 | explanation, see the paper: https://arxiv.org/abs/cs/0701192 |
| 153 | |
| 154 | Here are some examples of double precision calculation error: |
| 155 | |
| 156 | 2877.0 / 1e6 == 0.002877, but x87 returns 0.0028770000000000002 |
| 157 | 43683.0 * 1e21 == 4.3683e25, but x87 returns 4.3683000000000004e25 |
| 158 | |
| 159 | Here are some examples of compiler flags to generate x87 instructions on x86: |
| 160 | |
| 161 | clang -m32 -mno-sse |
| 162 | gcc/icc -m32 -mfpmath=387 |
| 163 | msvc /arch:SSE or /arch:IA32 |
| 164 | |
| 165 | If we are sure that there's no similar error described above, we can define the |
| 166 | YYJSON_DOUBLE_MATH_CORRECT as 1 to enable the fast path calculation. This is |
| 167 | not an accurate detection, it's just try to avoid the error at compile-time. |
| 168 | An accurate detection can be done at run-time: |
| 169 | |
| 170 | bool is_double_math_correct(void) { |
| 171 | volatile double r = 43683.0; |
| 172 | r *= 1e21; |
| 173 | return r == 4.3683e25; |
| 174 | } |
| 175 | |
| 176 | See also: utils.h in https://github.com/google/double-conversion/ |
| 177 | */ |
| 178 | #if !defined(FLT_EVAL_METHOD) && defined(__FLT_EVAL_METHOD__) |
| 179 | # define FLT_EVAL_METHOD __FLT_EVAL_METHOD__ |
| 180 | #endif |
| 181 | |
| 182 | #if defined(FLT_EVAL_METHOD) && FLT_EVAL_METHOD != 0 && FLT_EVAL_METHOD != 1 |
| 183 | # define YYJSON_DOUBLE_MATH_CORRECT 0 |
| 184 | #elif defined(i386) || defined(__i386) || defined(__i386__) || \ |
| 185 | defined(_X86_) || defined(__X86__) || defined(_M_IX86) || \ |
| 186 | defined(__I86__) || defined(__IA32__) || defined(__THW_INTEL) |
| 187 | # if (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP == 2) || \ |
| 188 | (defined(__SSE2_MATH__) && __SSE2_MATH__) |
| 189 | # define YYJSON_DOUBLE_MATH_CORRECT 1 |
| 190 | # else |
| 191 | # define YYJSON_DOUBLE_MATH_CORRECT 0 |
| 192 | # endif |
| 193 | #elif defined(__mc68000__) || defined(__pnacl__) || defined(__native_client__) |
| 194 | # define YYJSON_DOUBLE_MATH_CORRECT 0 |
| 195 | #else |
| 196 | # define YYJSON_DOUBLE_MATH_CORRECT 1 |
| 197 | #endif |
| 198 | |
| 199 | /* endian */ |
| 200 | #if yyjson_has_include(<sys/types.h>) |
| 201 | # include <sys/types.h> |
| 202 | #endif |
| 203 | |
| 204 | #if yyjson_has_include(<endian.h>) |
| 205 | # include <endian.h> |
| 206 | #elif yyjson_has_include(<machine/endian.h>) |
| 207 | # include <machine/endian.h> |
| 208 | #elif yyjson_has_include(<sys/endian.h>) |
| 209 | # include <sys/endian.h> |
| 210 | #endif |
| 211 | |
| 212 | #define YYJSON_BIG_ENDIAN 4321 |
| 213 | #define YYJSON_LITTLE_ENDIAN 1234 |
| 214 | |
| 215 | #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ |
| 216 | # if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ |
| 217 | # define YYJSON_ENDIAN YYJSON_BIG_ENDIAN |
| 218 | # elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
| 219 | # define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN |
| 220 | # endif |
| 221 | |
| 222 | #elif defined(__BYTE_ORDER) && __BYTE_ORDER |
| 223 | # if __BYTE_ORDER == __BIG_ENDIAN |
| 224 | # define YYJSON_ENDIAN YYJSON_BIG_ENDIAN |
| 225 | # elif __BYTE_ORDER == __LITTLE_ENDIAN |
| 226 | # define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN |
| 227 | # endif |
| 228 | |
| 229 | #elif defined(BYTE_ORDER) && BYTE_ORDER |
| 230 | # if BYTE_ORDER == BIG_ENDIAN |
| 231 | # define YYJSON_ENDIAN YYJSON_BIG_ENDIAN |
| 232 | # elif BYTE_ORDER == LITTLE_ENDIAN |
| 233 | # define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN |
| 234 | # endif |
| 235 | |
| 236 | #elif (defined(__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__ == 1) || \ |
| 237 | defined(__i386) || defined(__i386__) || \ |
| 238 | defined(_X86_) || defined(__X86__) || \ |
| 239 | defined(_M_IX86) || defined(__THW_INTEL__) || \ |
| 240 | defined(__x86_64) || defined(__x86_64__) || \ |
| 241 | defined(__amd64) || defined(__amd64__) || \ |
| 242 | defined(_M_AMD64) || defined(_M_X64) || \ |
| 243 | defined(__ia64) || defined(_IA64) || defined(__IA64__) || \ |
| 244 | defined(__ia64__) || defined(_M_IA64) || defined(__itanium__) || \ |
| 245 | defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \ |
| 246 | defined(__alpha) || defined(__alpha__) || defined(_M_ALPHA) || \ |
| 247 | defined(__riscv) || defined(__riscv__) || \ |
| 248 | defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || \ |
| 249 | defined(__EMSCRIPTEN__) || defined(__wasm__) || \ |
| 250 | defined(__loongarch__) |
| 251 | # define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN |
| 252 | |
| 253 | #elif (defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ == 1) || \ |
| 254 | defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \ |
| 255 | defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) || \ |
| 256 | defined(_ARCH_PPC) || defined(_ARCH_PPC64) || \ |
| 257 | defined(__ppc) || defined(__ppc__) || \ |
| 258 | defined(__sparc) || defined(__sparc__) || defined(__sparc64__) || \ |
| 259 | defined(__or1k__) || defined(__OR1K__) |
| 260 | # define YYJSON_ENDIAN YYJSON_BIG_ENDIAN |
| 261 | |
| 262 | #else |
| 263 | # define YYJSON_ENDIAN 0 /* unknown endian, detect at run-time */ |
| 264 | #endif |
| 265 | |
| 266 | /* |
| 267 | Unaligned memory access detection. |
| 268 | |
| 269 | Some architectures cannot perform unaligned memory access, or unaligned memory |
| 270 | accesses can have a large performance penalty. Modern compilers can make some |
| 271 | optimizations for unaligned access. For example: https://godbolt.org/z/Ejo3Pa |
| 272 | |
| 273 | typedef struct { char c[2] } vec2; |
| 274 | void copy_vec2(vec2 *dst, vec2 *src) { |
| 275 | *dst = *src; |
| 276 | } |
| 277 | |
| 278 | Compiler may generate `load/store` or `move` instruction if target architecture |
| 279 | supports unaligned access, otherwise it may generate `call memcpy` instruction. |
| 280 | |
| 281 | We want to avoid `memcpy` calls, so we should disable unaligned access by |
| 282 | define `YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS` as 1 on these architectures. |
| 283 | */ |
| 284 | #ifndef YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
| 285 | # if defined(i386) || defined(__i386) || defined(__i386__) || \ |
| 286 | defined(__i486__) || defined(__i586__) || defined(__i686__) || \ |
| 287 | defined(_X86_) || defined(__X86__) || defined(_M_IX86) || \ |
| 288 | defined(__I86__) || defined(__IA32__) || \ |
| 289 | defined(__THW_INTEL) || defined(__THW_INTEL__) || \ |
| 290 | defined(__x86_64) || defined(__x86_64__) || \ |
| 291 | defined(__amd64) || defined(__amd64__) || \ |
| 292 | defined(_M_AMD64) || defined(_M_X64) |
| 293 | # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 0 /* x86 */ |
| 294 | |
| 295 | # elif defined(__ia64) || defined(_IA64) || defined(__IA64__) || \ |
| 296 | defined(__ia64__) || defined(_M_IA64) || defined(__itanium__) |
| 297 | # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* Itanium */ |
| 298 | |
| 299 | # elif defined(__arm64) || defined(__arm64__) || \ |
| 300 | defined(__AARCH64EL__) || defined(__AARCH64EB__) || \ |
| 301 | defined(__aarch64__) || defined(_M_ARM64) |
| 302 | # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 0 /* ARM64 */ |
| 303 | |
| 304 | # elif defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) || \ |
| 305 | defined(__ARM_ARCH_5TEJ__) || defined(__ARM_ARCH_5TE__) || \ |
| 306 | defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6KZ__) || \ |
| 307 | defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6K__) |
| 308 | # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* ARM */ |
| 309 | |
| 310 | # elif defined(__ppc64__) || defined(__PPC64__) || \ |
| 311 | defined(__powerpc64__) || defined(_ARCH_PPC64) || \ |
| 312 | defined(__ppc) || defined(__ppc__) || defined(__PPC__) || \ |
| 313 | defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) || \ |
| 314 | defined(_ARCH_PPC) || defined(_M_PPC) || \ |
| 315 | defined(__PPCGECKO__) || defined(__PPCBROADWAY__) || defined(_XENON) |
| 316 | # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 0 /* PowerPC */ |
| 317 | |
| 318 | # elif defined(__loongarch__) |
| 319 | # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 0 /* loongarch */ |
| 320 | |
| 321 | # else |
| 322 | # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 0 /* Unknown */ |
| 323 | # endif |
| 324 | |
| 325 | #endif |
| 326 | |
| 327 | /* |
| 328 | Estimated initial ratio of the JSON data (data_size / value_count). |
| 329 | For example: |
| 330 | |
| 331 | data: {"id":12345678,"name":"Harry"} |
| 332 | data_size: 30 |
| 333 | value_count: 5 |
| 334 | ratio: 6 |
| 335 | |
| 336 | yyjson uses dynamic memory with a growth factor of 1.5 when reading and writing |
| 337 | JSON, the ratios below are used to determine the initial memory size. |
| 338 | |
| 339 | A too large ratio will waste memory, and a too small ratio will cause multiple |
| 340 | memory growths and degrade performance. Currently, these ratios are generated |
| 341 | with some commonly used JSON datasets. |
| 342 | */ |
| 343 | #define YYJSON_READER_ESTIMATED_PRETTY_RATIO 16 |
| 344 | #define YYJSON_READER_ESTIMATED_MINIFY_RATIO 6 |
| 345 | #define YYJSON_WRITER_ESTIMATED_PRETTY_RATIO 32 |
| 346 | #define YYJSON_WRITER_ESTIMATED_MINIFY_RATIO 18 |
| 347 | |
| 348 | /* The initial and maximum size of the memory pool's chunk in yyjson_mut_doc. */ |
| 349 | #define YYJSON_MUT_DOC_STR_POOL_INIT_SIZE 0x100 |
| 350 | #define YYJSON_MUT_DOC_STR_POOL_MAX_SIZE 0x10000000 |
| 351 | #define YYJSON_MUT_DOC_VAL_POOL_INIT_SIZE (0x10 * sizeof(yyjson_mut_val)) |
| 352 | #define YYJSON_MUT_DOC_VAL_POOL_MAX_SIZE (0x1000000 * sizeof(yyjson_mut_val)) |
| 353 | |
| 354 | /* Default value for compile-time options. */ |
| 355 | #ifndef YYJSON_DISABLE_READER |
| 356 | #define YYJSON_DISABLE_READER 0 |
| 357 | #endif |
| 358 | #ifndef YYJSON_DISABLE_WRITER |
| 359 | #define YYJSON_DISABLE_WRITER 0 |
| 360 | #endif |
| 361 | #ifndef YYJSON_DISABLE_UTILS |
| 362 | #define YYJSON_DISABLE_UTILS 0 |
| 363 | #endif |
| 364 | #ifndef YYJSON_DISABLE_FAST_FP_CONV |
| 365 | #define YYJSON_DISABLE_FAST_FP_CONV 0 |
| 366 | #endif |
| 367 | #ifndef YYJSON_DISABLE_NON_STANDARD |
| 368 | #define YYJSON_DISABLE_NON_STANDARD 0 |
| 369 | #endif |
| 370 | |
| 371 | |
| 372 | |
| 373 | /*============================================================================== |
| 374 | * Macros |
| 375 | *============================================================================*/ |
| 376 | |
| 377 | /* Macros used for loop unrolling and other purpose. */ |
| 378 | #define repeat2(x) { x x } |
| 379 | #define repeat3(x) { x x x } |
| 380 | #define repeat4(x) { x x x x } |
| 381 | #define repeat8(x) { x x x x x x x x } |
| 382 | #define repeat16(x) { x x x x x x x x x x x x x x x x } |
| 383 | |
| 384 | #define repeat2_incr(x) { x(0) x(1) } |
| 385 | #define repeat4_incr(x) { x(0) x(1) x(2) x(3) } |
| 386 | #define repeat8_incr(x) { x(0) x(1) x(2) x(3) x(4) x(5) x(6) x(7) } |
| 387 | #define repeat16_incr(x) { x(0) x(1) x(2) x(3) x(4) x(5) x(6) x(7) \ |
| 388 | x(8) x(9) x(10) x(11) x(12) x(13) x(14) x(15) } |
| 389 | |
| 390 | #define repeat_in_1_18(x) { x(1) x(2) x(3) x(4) x(5) x(6) x(7) x(8) \ |
| 391 | x(9) x(10) x(11) x(12) x(13) x(14) x(15) x(16) \ |
| 392 | x(17) x(18) } |
| 393 | |
| 394 | /* Macros used to provide branch prediction information for compiler. */ |
| 395 | #undef likely |
| 396 | #define likely(x) yyjson_likely(x) |
| 397 | #undef unlikely |
| 398 | #define unlikely(x) yyjson_unlikely(x) |
| 399 | |
| 400 | /* Macros used to provide inline information for compiler. */ |
| 401 | #undef static_inline |
| 402 | #define static_inline static yyjson_inline |
| 403 | #undef static_noinline |
| 404 | #define static_noinline static yyjson_noinline |
| 405 | |
| 406 | /* Macros for min and max. */ |
| 407 | #undef yyjson_min |
| 408 | #define yyjson_min(x, y) ((x) < (y) ? (x) : (y)) |
| 409 | #undef yyjson_max |
| 410 | #define yyjson_max(x, y) ((x) > (y) ? (x) : (y)) |
| 411 | |
| 412 | /* Used to write u64 literal for C89 which doesn't support "ULL" suffix. */ |
| 413 | #undef U64 |
| 414 | #define U64(hi, lo) ((((u64)hi##UL) << 32U) + lo##UL) |
| 415 | |
| 416 | /* Used to cast away (remove) const qualifier. */ |
| 417 | #define constcast(type) (type)(void *)(size_t)(const void *) |
| 418 | |
| 419 | |
| 420 | |
| 421 | /*============================================================================== |
| 422 | * Integer Constants |
| 423 | *============================================================================*/ |
| 424 | |
| 425 | /* U64 constant values */ |
| 426 | #undef U64_MAX |
| 427 | #define U64_MAX U64(0xFFFFFFFF, 0xFFFFFFFF) |
| 428 | #undef I64_MAX |
| 429 | #define I64_MAX U64(0x7FFFFFFF, 0xFFFFFFFF) |
| 430 | #undef USIZE_MAX |
| 431 | #define USIZE_MAX ((usize)(~(usize)0)) |
| 432 | |
| 433 | /* Maximum number of digits for reading u32/u64/usize safety (not overflow). */ |
| 434 | #undef U32_SAFE_DIG |
| 435 | #define U32_SAFE_DIG 9 /* u32 max is 4294967295, 10 digits */ |
| 436 | #undef U64_SAFE_DIG |
| 437 | #define U64_SAFE_DIG 19 /* u64 max is 18446744073709551615, 20 digits */ |
| 438 | #undef USIZE_SAFE_DIG |
| 439 | #define USIZE_SAFE_DIG (sizeof(usize) == 64 ? U64_SAFE_DIG : U32_SAFE_DIG) |
| 440 | |
| 441 | |
| 442 | |
| 443 | /*============================================================================== |
| 444 | * IEEE-754 Double Number Constants |
| 445 | *============================================================================*/ |
| 446 | |
| 447 | /* Inf raw value (positive) */ |
| 448 | #define F64_RAW_INF U64(0x7FF00000, 0x00000000) |
| 449 | |
| 450 | /* NaN raw value (quiet NaN, no payload, no sign) */ |
| 451 | #if defined(__hppa__) || (defined(__mips__) && !defined(__mips_nan2008)) |
| 452 | #define F64_RAW_NAN U64(0x7FF7FFFF, 0xFFFFFFFF) |
| 453 | #else |
| 454 | #define F64_RAW_NAN U64(0x7FF80000, 0x00000000) |
| 455 | #endif |
| 456 | |
| 457 | /* double number bits */ |
| 458 | #define F64_BITS 64 |
| 459 | |
| 460 | /* double number exponent part bits */ |
| 461 | #define F64_EXP_BITS 11 |
| 462 | |
| 463 | /* double number significand part bits */ |
| 464 | #define F64_SIG_BITS 52 |
| 465 | |
| 466 | /* double number significand part bits (with 1 hidden bit) */ |
| 467 | #define F64_SIG_FULL_BITS 53 |
| 468 | |
| 469 | /* double number significand bit mask */ |
| 470 | #define F64_SIG_MASK U64(0x000FFFFF, 0xFFFFFFFF) |
| 471 | |
| 472 | /* double number exponent bit mask */ |
| 473 | #define F64_EXP_MASK U64(0x7FF00000, 0x00000000) |
| 474 | |
| 475 | /* double number exponent bias */ |
| 476 | #define F64_EXP_BIAS 1023 |
| 477 | |
| 478 | /* double number significant digits count in decimal */ |
| 479 | #define F64_DEC_DIG 17 |
| 480 | |
| 481 | /* max significant digits count in decimal when reading double number */ |
| 482 | #define F64_MAX_DEC_DIG 768 |
| 483 | |
| 484 | /* maximum decimal power of double number (1.7976931348623157e308) */ |
| 485 | #define F64_MAX_DEC_EXP 308 |
| 486 | |
| 487 | /* minimum decimal power of double number (4.9406564584124654e-324) */ |
| 488 | #define F64_MIN_DEC_EXP (-324) |
| 489 | |
| 490 | /* maximum binary power of double number */ |
| 491 | #define F64_MAX_BIN_EXP 1024 |
| 492 | |
| 493 | /* minimum binary power of double number */ |
| 494 | #define F64_MIN_BIN_EXP (-1021) |
| 495 | |
| 496 | |
| 497 | |
| 498 | /*============================================================================== |
| 499 | * Types |
| 500 | *============================================================================*/ |
| 501 | |
| 502 | /** Type define for primitive types. */ |
| 503 | typedef float f32; |
| 504 | typedef double f64; |
| 505 | typedef int8_t i8; |
| 506 | typedef uint8_t u8; |
| 507 | typedef int16_t i16; |
| 508 | typedef uint16_t u16; |
| 509 | typedef int32_t i32; |
| 510 | typedef uint32_t u32; |
| 511 | typedef int64_t i64; |
| 512 | typedef uint64_t u64; |
| 513 | typedef size_t usize; |
| 514 | |
| 515 | /** 128-bit integer, used by floating-point number reader and writer. */ |
| 516 | #if YYJSON_HAS_INT128 |
| 517 | __extension__ typedef __int128 i128; |
| 518 | __extension__ typedef unsigned __int128 u128; |
| 519 | #endif |
| 520 | |
| 521 | /** 16/32/64-bit vector */ |
| 522 | typedef struct v16 { char c1, c2; } v16; |
| 523 | typedef struct v32 { char c1, c2, c3, c4; } v32; |
| 524 | typedef struct v64 { char c1, c2, c3, c4, c5, c6, c7, c8; } v64; |
| 525 | |
| 526 | /** 16/32/64-bit vector union, used for unaligned memory access on modern CPU */ |
| 527 | typedef union v16_uni { v16 v; u16 u; } v16_uni; |
| 528 | typedef union v32_uni { v32 v; u32 u; } v32_uni; |
| 529 | typedef union v64_uni { v64 v; u64 u; } v64_uni; |
| 530 | |
| 531 | |
| 532 | |
| 533 | /*============================================================================== |
| 534 | * Load/Store Utils |
| 535 | *============================================================================*/ |
| 536 | |
| 537 | #define byte_move_idx(x) ((u8 *)dst)[x] = ((u8 *)src)[x]; |
| 538 | |
| 539 | static_inline void byte_move_2(void *dst, const void *src) { |
| 540 | #if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
| 541 | repeat2_incr(byte_move_idx) |
| 542 | #else |
| 543 | memmove(dst, src, 2); |
| 544 | #endif |
| 545 | } |
| 546 | |
| 547 | static_inline void byte_move_4(void *dst, const void *src) { |
| 548 | #if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
| 549 | repeat4_incr(byte_move_idx) |
| 550 | #else |
| 551 | memmove(dst, src, 4); |
| 552 | #endif |
| 553 | } |
| 554 | |
| 555 | static_inline void byte_move_8(void *dst, const void *src) { |
| 556 | #if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
| 557 | repeat8_incr(byte_move_idx) |
| 558 | #else |
| 559 | memmove(dst, src, 8); |
| 560 | #endif |
| 561 | } |
| 562 | |
| 563 | static_inline void byte_move_16(void *dst, const void *src) { |
| 564 | #if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
| 565 | repeat16_incr(byte_move_idx) |
| 566 | #else |
| 567 | memmove(dst, src, 16); |
| 568 | #endif |
| 569 | } |
| 570 | |
| 571 | static_inline void byte_copy_2(void *dst, const void *src) { |
| 572 | #if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
| 573 | repeat2_incr(byte_move_idx) |
| 574 | #else |
| 575 | memcpy(dst, src, 2); |
| 576 | #endif |
| 577 | } |
| 578 | |
| 579 | static_inline void byte_copy_4(void *dst, const void *src) { |
| 580 | #if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
| 581 | repeat4_incr(byte_move_idx) |
| 582 | #else |
| 583 | memcpy(dst, src, 4); |
| 584 | #endif |
| 585 | } |
| 586 | |
| 587 | static_inline void byte_copy_8(void *dst, const void *src) { |
| 588 | #if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
| 589 | repeat8_incr(byte_move_idx) |
| 590 | #else |
| 591 | memcpy(dst, src, 8); |
| 592 | #endif |
| 593 | } |
| 594 | |
| 595 | static_inline void byte_copy_16(void *dst, const void *src) { |
| 596 | #if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
| 597 | repeat16_incr(byte_move_idx) |
| 598 | #else |
| 599 | memcpy(dst, src, 16); |
| 600 | #endif |
| 601 | } |
| 602 | |
| 603 | static_inline bool byte_match_2(void *buf, const char *pat) { |
| 604 | #if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
| 605 | return |
| 606 | ((u8 *)buf)[0] == ((const u8 *)pat)[0] && |
| 607 | ((u8 *)buf)[1] == ((const u8 *)pat)[1]; |
| 608 | #else |
| 609 | v16_uni u1, u2; |
| 610 | u1.v = *(const v16 *)pat; |
| 611 | u2.v = *(const v16 *)buf; |
| 612 | return u1.u == u2.u; |
| 613 | #endif |
| 614 | } |
| 615 | |
| 616 | static_inline bool byte_match_4(void *buf, const char *pat) { |
| 617 | #if YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
| 618 | return |
| 619 | ((u8 *)buf)[0] == ((const u8 *)pat)[0] && |
| 620 | ((u8 *)buf)[1] == ((const u8 *)pat)[1] && |
| 621 | ((u8 *)buf)[2] == ((const u8 *)pat)[2] && |
| 622 | ((u8 *)buf)[3] == ((const u8 *)pat)[3]; |
| 623 | #else |
| 624 | v32_uni u1, u2; |
| 625 | u1.v = *(const v32 *)pat; |
| 626 | u2.v = *(const v32 *)buf; |
| 627 | return u1.u == u2.u; |
| 628 | #endif |
| 629 | } |
| 630 | |
| 631 | static_inline u16 byte_load_2(const void *src) { |
| 632 | v16_uni uni; |
| 633 | uni.v = *(const v16 *)src; |
| 634 | return uni.u; |
| 635 | } |
| 636 | |
| 637 | static_inline u32 byte_load_3(const void *src) { |
| 638 | v32_uni uni; |
| 639 | ((v16_uni *)&uni)->v = *(const v16 *)src; |
| 640 | uni.v.c3 = ((const char *)src)[2]; |
| 641 | uni.v.c4 = 0; |
| 642 | return uni.u; |
| 643 | } |
| 644 | |
| 645 | static_inline u32 byte_load_4(const void *src) { |
| 646 | v32_uni uni; |
| 647 | uni.v = *(const v32 *)src; |
| 648 | return uni.u; |
| 649 | } |
| 650 | |
| 651 | #undef byte_move_expr |
| 652 | |
| 653 | |
| 654 | |
| 655 | /*============================================================================== |
| 656 | * Number Utils |
| 657 | * These functions are used to detect and convert NaN and Inf numbers. |
| 658 | *============================================================================*/ |
| 659 | |
| 660 | /** |
| 661 | This union is used to avoid violating the strict aliasing rule in C. |
| 662 | `memcpy` can be used in both C and C++, but it may reduce performance without |
| 663 | compiler optimization. |
| 664 | */ |
| 665 | typedef union { u64 u; f64 f; } f64_uni; |
| 666 | |
| 667 | /** Convert raw binary to double. */ |
| 668 | static_inline f64 f64_from_raw(u64 u) { |
| 669 | #ifndef __cplusplus |
| 670 | f64_uni uni; |
| 671 | uni.u = u; |
| 672 | return uni.f; |
| 673 | #else |
| 674 | f64 f; |
| 675 | memcpy(&f, &u, 8); |
| 676 | return f; |
| 677 | #endif |
| 678 | } |
| 679 | |
| 680 | /** Convert double to raw binary. */ |
| 681 | static_inline u64 f64_to_raw(f64 f) { |
| 682 | #ifndef __cplusplus |
| 683 | f64_uni uni; |
| 684 | uni.f = f; |
| 685 | return uni.u; |
| 686 | #else |
| 687 | u64 u; |
| 688 | memcpy(&u, &f, 8); |
| 689 | return u; |
| 690 | #endif |
| 691 | } |
| 692 | |
| 693 | /** Get raw 'infinity' with sign. */ |
| 694 | static_inline u64 f64_raw_get_inf(bool sign) { |
| 695 | #if YYJSON_HAS_IEEE_754 |
| 696 | return F64_RAW_INF | ((u64)sign << 63); |
| 697 | #elif defined(INFINITY) |
| 698 | return f64_to_raw(sign ? -INFINITY : INFINITY); |
| 699 | #else |
| 700 | return f64_to_raw(sign ? -HUGE_VAL : HUGE_VAL); |
| 701 | #endif |
| 702 | } |
| 703 | |
| 704 | /** Get raw 'nan' with sign. */ |
| 705 | static_inline u64 f64_raw_get_nan(bool sign) { |
| 706 | #if YYJSON_HAS_IEEE_754 |
| 707 | return F64_RAW_NAN | ((u64)sign << 63); |
| 708 | #elif defined(NAN) |
| 709 | return f64_to_raw(sign ? (f64)-NAN : (f64)NAN); |
| 710 | #else |
| 711 | return f64_to_raw((sign ? -0.0 : 0.0) / 0.0); |
| 712 | #endif |
| 713 | } |
| 714 | |
| 715 | /** |
| 716 | Convert normalized u64 (highest bit is 1) to f64. |
| 717 | |
| 718 | Some compiler (such as Microsoft Visual C++ 6.0) do not support converting |
| 719 | number from u64 to f64. This function will first convert u64 to i64 and then |
| 720 | to f64, with `to nearest` rounding mode. |
| 721 | */ |
| 722 | static_inline f64 normalized_u64_to_f64(u64 val) { |
| 723 | #if YYJSON_U64_TO_F64_NO_IMPL |
| 724 | i64 sig = (i64)((val >> 1) | (val & 1)); |
| 725 | return ((f64)sig) * (f64)2.0; |
| 726 | #else |
| 727 | return (f64)val; |
| 728 | #endif |
| 729 | } |
| 730 | |
| 731 | |
| 732 | |
| 733 | /*============================================================================== |
| 734 | * Size Utils |
| 735 | * These functions are used for memory allocation. |
| 736 | *============================================================================*/ |
| 737 | |
| 738 | /** Returns whether the size is overflow after increment. */ |
| 739 | static_inline bool size_add_is_overflow(usize size, usize add) { |
| 740 | return size > (size + add); |
| 741 | } |
| 742 | |
| 743 | /** Returns whether the size is power of 2 (size should not be 0). */ |
| 744 | static_inline bool size_is_pow2(usize size) { |
| 745 | return (size & (size - 1)) == 0; |
| 746 | } |
| 747 | |
| 748 | /** Align size upwards (may overflow). */ |
| 749 | static_inline usize size_align_up(usize size, usize align) { |
| 750 | if (size_is_pow2(align)) { |
| 751 | return (size + (align - 1)) & ~(align - 1); |
| 752 | } else { |
| 753 | return size + align - (size + align - 1) % align - 1; |
| 754 | } |
| 755 | } |
| 756 | |
| 757 | /** Align size downwards. */ |
| 758 | static_inline usize size_align_down(usize size, usize align) { |
| 759 | if (size_is_pow2(align)) { |
| 760 | return size & ~(align - 1); |
| 761 | } else { |
| 762 | return size - (size % align); |
| 763 | } |
| 764 | } |
| 765 | |
| 766 | /** Align address upwards (may overflow). */ |
| 767 | static_inline void *mem_align_up(void *mem, usize align) { |
| 768 | usize size; |
| 769 | memcpy(&size, &mem, sizeof(usize)); |
| 770 | size = size_align_up(size, align); |
| 771 | memcpy(&mem, &size, sizeof(usize)); |
| 772 | return mem; |
| 773 | } |
| 774 | |
| 775 | |
| 776 | |
| 777 | /*============================================================================== |
| 778 | * Bits Utils |
| 779 | * These functions are used by the floating-point number reader and writer. |
| 780 | *============================================================================*/ |
| 781 | |
| 782 | /** Returns the number of leading 0-bits in value (input should not be 0). */ |
| 783 | static_inline u32 u64_lz_bits(u64 v) { |
| 784 | #if GCC_HAS_CLZLL |
| 785 | return (u32)__builtin_clzll(v); |
| 786 | #elif MSC_HAS_BIT_SCAN_64 |
| 787 | unsigned long r; |
| 788 | _BitScanReverse64(&r, v); |
| 789 | return (u32)63 - (u32)r; |
| 790 | #elif MSC_HAS_BIT_SCAN |
| 791 | unsigned long hi, lo; |
| 792 | bool hi_set = _BitScanReverse(&hi, (u32)(v >> 32)) != 0; |
| 793 | _BitScanReverse(&lo, (u32)v); |
| 794 | hi |= 32; |
| 795 | return (u32)63 - (u32)(hi_set ? hi : lo); |
| 796 | #else |
| 797 | /* |
| 798 | branchless, use de Bruijn sequences |
| 799 | see: https://www.chessprogramming.org/BitScan |
| 800 | */ |
| 801 | const u8 table[64] = { |
| 802 | 63, 16, 62, 7, 15, 36, 61, 3, 6, 14, 22, 26, 35, 47, 60, 2, |
| 803 | 9, 5, 28, 11, 13, 21, 42, 19, 25, 31, 34, 40, 46, 52, 59, 1, |
| 804 | 17, 8, 37, 4, 23, 27, 48, 10, 29, 12, 43, 20, 32, 41, 53, 18, |
| 805 | 38, 24, 49, 30, 44, 33, 54, 39, 50, 45, 55, 51, 56, 57, 58, 0 |
| 806 | }; |
| 807 | v |= v >> 1; |
| 808 | v |= v >> 2; |
| 809 | v |= v >> 4; |
| 810 | v |= v >> 8; |
| 811 | v |= v >> 16; |
| 812 | v |= v >> 32; |
| 813 | return table[(v * U64(0x03F79D71, 0xB4CB0A89)) >> 58]; |
| 814 | #endif |
| 815 | } |
| 816 | |
| 817 | /** Returns the number of trailing 0-bits in value (input should not be 0). */ |
| 818 | static_inline u32 u64_tz_bits(u64 v) { |
| 819 | #if GCC_HAS_CTZLL |
| 820 | return (u32)__builtin_ctzll(v); |
| 821 | #elif MSC_HAS_BIT_SCAN_64 |
| 822 | unsigned long r; |
| 823 | _BitScanForward64(&r, v); |
| 824 | return (u32)r; |
| 825 | #elif MSC_HAS_BIT_SCAN |
| 826 | unsigned long lo, hi; |
| 827 | bool lo_set = _BitScanForward(&lo, (u32)(v)) != 0; |
| 828 | _BitScanForward(&hi, (u32)(v >> 32)); |
| 829 | hi += 32; |
| 830 | return lo_set ? lo : hi; |
| 831 | #else |
| 832 | /* |
| 833 | branchless, use de Bruijn sequences |
| 834 | see: https://www.chessprogramming.org/BitScan |
| 835 | */ |
| 836 | const u8 table[64] = { |
| 837 | 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, |
| 838 | 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, |
| 839 | 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, |
| 840 | 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 |
| 841 | }; |
| 842 | return table[((v & (~v + 1)) * U64(0x022FDD63, 0xCC95386D)) >> 58]; |
| 843 | #endif |
| 844 | } |
| 845 | |
| 846 | |
| 847 | |
| 848 | /*============================================================================== |
| 849 | * 128-bit Integer Utils |
| 850 | * These functions are used by the floating-point number reader and writer. |
| 851 | *============================================================================*/ |
| 852 | |
| 853 | /** Multiplies two 64-bit unsigned integers (a * b), |
| 854 | returns the 128-bit result as 'hi' and 'lo'. */ |
| 855 | static_inline void u128_mul(u64 a, u64 b, u64 *hi, u64 *lo) { |
| 856 | #if YYJSON_HAS_INT128 |
| 857 | u128 m = (u128)a * b; |
| 858 | *hi = (u64)(m >> 64); |
| 859 | *lo = (u64)(m); |
| 860 | #elif MSC_HAS_UMUL128 |
| 861 | *lo = _umul128(a, b, hi); |
| 862 | #else |
| 863 | u32 a0 = (u32)(a), a1 = (u32)(a >> 32); |
| 864 | u32 b0 = (u32)(b), b1 = (u32)(b >> 32); |
| 865 | u64 p00 = (u64)a0 * b0, p01 = (u64)a0 * b1; |
| 866 | u64 p10 = (u64)a1 * b0, p11 = (u64)a1 * b1; |
| 867 | u64 m0 = p01 + (p00 >> 32); |
| 868 | u32 m00 = (u32)(m0), m01 = (u32)(m0 >> 32); |
| 869 | u64 m1 = p10 + m00; |
| 870 | u32 m10 = (u32)(m1), m11 = (u32)(m1 >> 32); |
| 871 | *hi = p11 + m01 + m11; |
| 872 | *lo = ((u64)m10 << 32) | (u32)p00; |
| 873 | #endif |
| 874 | } |
| 875 | |
| 876 | /** Multiplies two 64-bit unsigned integers and add a value (a * b + c), |
| 877 | returns the 128-bit result as 'hi' and 'lo'. */ |
| 878 | static_inline void u128_mul_add(u64 a, u64 b, u64 c, u64 *hi, u64 *lo) { |
| 879 | #if YYJSON_HAS_INT128 |
| 880 | u128 m = (u128)a * b + c; |
| 881 | *hi = (u64)(m >> 64); |
| 882 | *lo = (u64)(m); |
| 883 | #else |
| 884 | u64 h, l, t; |
| 885 | u128_mul(a, b, &h, &l); |
| 886 | t = l + c; |
| 887 | h += (u64)(((t < l) | (t < c))); |
| 888 | *hi = h; |
| 889 | *lo = t; |
| 890 | #endif |
| 891 | } |
| 892 | |
| 893 | |
| 894 | |
| 895 | /*============================================================================== |
| 896 | * File Utils |
| 897 | * These functions are used to read and write JSON files. |
| 898 | *============================================================================*/ |
| 899 | |
| 900 | #define YYJSON_FOPEN_EXT |
| 901 | #if !defined(_MSC_VER) && defined(__GLIBC__) && defined(__GLIBC_PREREQ) |
| 902 | # if __GLIBC_PREREQ(2, 7) |
| 903 | # undef YYJSON_FOPEN_EXT |
| 904 | # define YYJSON_FOPEN_EXT "e" /* glibc extension to enable O_CLOEXEC */ |
| 905 | # endif |
| 906 | #endif |
| 907 | |
| 908 | static_inline FILE *fopen_safe(const char *path, const char *mode) { |
| 909 | #if YYJSON_MSC_VER >= 1400 |
| 910 | FILE *file = NULL; |
| 911 | if (fopen_s(&file, path, mode) != 0) return NULL; |
| 912 | return file; |
| 913 | #else |
| 914 | return fopen(path, mode); |
| 915 | #endif |
| 916 | } |
| 917 | |
| 918 | static_inline FILE *fopen_readonly(const char *path) { |
| 919 | return fopen_safe(path, "rb" YYJSON_FOPEN_EXT); |
| 920 | } |
| 921 | |
| 922 | static_inline FILE *fopen_writeonly(const char *path) { |
| 923 | return fopen_safe(path, "wb" YYJSON_FOPEN_EXT); |
| 924 | } |
| 925 | |
| 926 | static_inline usize fread_safe(void *buf, usize size, FILE *file) { |
| 927 | #if YYJSON_MSC_VER >= 1400 |
| 928 | return fread_s(buf, size, 1, size, file); |
| 929 | #else |
| 930 | return fread(buf, 1, size, file); |
| 931 | #endif |
| 932 | } |
| 933 | |
| 934 | |
| 935 | |
| 936 | /*============================================================================== |
| 937 | * Default Memory Allocator |
| 938 | * This is a simple libc memory allocator wrapper. |
| 939 | *============================================================================*/ |
| 940 | |
| 941 | static void *default_malloc(void *ctx, usize size) { |
| 942 | return malloc(size); |
| 943 | } |
| 944 | |
| 945 | static void *default_realloc(void *ctx, void *ptr, usize old_size, usize size) { |
| 946 | return realloc(ptr, size); |
| 947 | } |
| 948 | |
| 949 | static void default_free(void *ctx, void *ptr) { |
| 950 | free(ptr); |
| 951 | } |
| 952 | |
| 953 | static const yyjson_alc YYJSON_DEFAULT_ALC = { |
| 954 | default_malloc, |
| 955 | default_realloc, |
| 956 | default_free, |
| 957 | NULL |
| 958 | }; |
| 959 | |
| 960 | static void *null_malloc(void *ctx, usize size) { |
| 961 | return NULL; |
| 962 | } |
| 963 | |
| 964 | static void *null_realloc(void *ctx, void *ptr, usize old_size, usize size) { |
| 965 | return NULL; |
| 966 | } |
| 967 | |
| 968 | static void null_free(void *ctx, void *ptr) { |
| 969 | return; |
| 970 | } |
| 971 | |
| 972 | static const yyjson_alc YYJSON_NULL_ALC = { |
| 973 | null_malloc, |
| 974 | null_realloc, |
| 975 | null_free, |
| 976 | NULL |
| 977 | }; |
| 978 | |
| 979 | |
| 980 | |
| 981 | /*============================================================================== |
| 982 | * Pool Memory Allocator |
| 983 | * This is a simple memory allocator that uses linked list memory chunk. |
| 984 | * The following code will be executed only when the library user creates |
| 985 | * this allocator manually. |
| 986 | *============================================================================*/ |
| 987 | |
| 988 | /** chunk header */ |
| 989 | typedef struct pool_chunk { |
| 990 | usize size; /* chunk memory size (include chunk header) */ |
| 991 | struct pool_chunk *next; |
| 992 | } pool_chunk; |
| 993 | |
| 994 | /** ctx header */ |
| 995 | typedef struct pool_ctx { |
| 996 | usize size; /* total memory size (include ctx header) */ |
| 997 | pool_chunk *free_list; |
| 998 | } pool_ctx; |
| 999 | |
| 1000 | static void *pool_malloc(void *ctx_ptr, usize size) { |
| 1001 | pool_ctx *ctx = (pool_ctx *)ctx_ptr; |
| 1002 | pool_chunk *next, *prev = NULL, *cur = ctx->free_list; |
| 1003 | |
| 1004 | if (unlikely(size == 0 || size >= ctx->size)) return NULL; |
| 1005 | size = size_align_up(size, sizeof(pool_chunk)) + sizeof(pool_chunk); |
| 1006 | |
| 1007 | while (cur) { |
| 1008 | if (cur->size < size) { |
| 1009 | /* not enough space, try next chunk */ |
| 1010 | prev = cur; |
| 1011 | cur = cur->next; |
| 1012 | continue; |
| 1013 | } |
| 1014 | if (cur->size >= size + sizeof(pool_chunk) * 2) { |
| 1015 | /* too much space, split this chunk */ |
| 1016 | next = (pool_chunk *)(void *)((u8 *)cur + size); |
| 1017 | next->size = cur->size - size; |
| 1018 | next->next = cur->next; |
| 1019 | cur->size = size; |
| 1020 | } else { |
| 1021 | /* just enough space, use whole chunk */ |
| 1022 | next = cur->next; |
| 1023 | } |
| 1024 | if (prev) prev->next = next; |
| 1025 | else ctx->free_list = next; |
| 1026 | return (void *)(cur + 1); |
| 1027 | } |
| 1028 | return NULL; |
| 1029 | } |
| 1030 | |
| 1031 | static void pool_free(void *ctx_ptr, void *ptr) { |
| 1032 | pool_ctx *ctx = (pool_ctx *)ctx_ptr; |
| 1033 | pool_chunk *cur = ((pool_chunk *)ptr) - 1; |
| 1034 | pool_chunk *prev = NULL, *next = ctx->free_list; |
| 1035 | |
| 1036 | while (next && next < cur) { |
| 1037 | prev = next; |
| 1038 | next = next->next; |
| 1039 | } |
| 1040 | if (prev) prev->next = cur; |
| 1041 | else ctx->free_list = cur; |
| 1042 | cur->next = next; |
| 1043 | |
| 1044 | if (next && ((u8 *)cur + cur->size) == (u8 *)next) { |
| 1045 | /* merge cur to higher chunk */ |
| 1046 | cur->size += next->size; |
| 1047 | cur->next = next->next; |
| 1048 | } |
| 1049 | if (prev && ((u8 *)prev + prev->size) == (u8 *)cur) { |
| 1050 | /* merge cur to lower chunk */ |
| 1051 | prev->size += cur->size; |
| 1052 | prev->next = cur->next; |
| 1053 | } |
| 1054 | } |
| 1055 | |
| 1056 | static void *pool_realloc(void *ctx_ptr, void *ptr, |
| 1057 | usize old_size, usize size) { |
| 1058 | pool_ctx *ctx = (pool_ctx *)ctx_ptr; |
| 1059 | pool_chunk *cur = ((pool_chunk *)ptr) - 1, *prev, *next, *tmp; |
| 1060 | usize free_size; |
| 1061 | void *new_ptr; |
| 1062 | |
| 1063 | if (unlikely(size == 0 || size >= ctx->size)) return NULL; |
| 1064 | size = size_align_up(size, sizeof(pool_chunk)) + sizeof(pool_chunk); |
| 1065 | |
| 1066 | /* reduce size */ |
| 1067 | if (unlikely(size <= cur->size)) { |
| 1068 | free_size = cur->size - size; |
| 1069 | if (free_size >= sizeof(pool_chunk) * 2) { |
| 1070 | tmp = (pool_chunk *)(void *)((u8 *)cur + cur->size - free_size); |
| 1071 | tmp->size = free_size; |
| 1072 | pool_free(ctx_ptr, (void *)(tmp + 1)); |
| 1073 | cur->size -= free_size; |
| 1074 | } |
| 1075 | return ptr; |
| 1076 | } |
| 1077 | |
| 1078 | /* find next and prev chunk */ |
| 1079 | prev = NULL; |
| 1080 | next = ctx->free_list; |
| 1081 | while (next && next < cur) { |
| 1082 | prev = next; |
| 1083 | next = next->next; |
| 1084 | } |
| 1085 | |
| 1086 | /* merge to higher chunk if they are contiguous */ |
| 1087 | if ((u8 *)cur + cur->size == (u8 *)next && |
| 1088 | cur->size + next->size >= size) { |
| 1089 | free_size = cur->size + next->size - size; |
| 1090 | if (free_size > sizeof(pool_chunk) * 2) { |
| 1091 | tmp = (pool_chunk *)(void *)((u8 *)cur + size); |
| 1092 | if (prev) prev->next = tmp; |
| 1093 | else ctx->free_list = tmp; |
| 1094 | tmp->next = next->next; |
| 1095 | tmp->size = free_size; |
| 1096 | cur->size = size; |
| 1097 | } else { |
| 1098 | if (prev) prev->next = next->next; |
| 1099 | else ctx->free_list = next->next; |
| 1100 | cur->size += next->size; |
| 1101 | } |
| 1102 | return ptr; |
| 1103 | } |
| 1104 | |
| 1105 | /* fallback to malloc and memcpy */ |
| 1106 | new_ptr = pool_malloc(ctx_ptr, size - sizeof(pool_chunk)); |
| 1107 | if (new_ptr) { |
| 1108 | memcpy(new_ptr, ptr, cur->size - sizeof(pool_chunk)); |
| 1109 | pool_free(ctx_ptr, ptr); |
| 1110 | } |
| 1111 | return new_ptr; |
| 1112 | } |
| 1113 | |
| 1114 | bool yyjson_alc_pool_init(yyjson_alc *alc, void *buf, usize size) { |
| 1115 | pool_chunk *chunk; |
| 1116 | pool_ctx *ctx; |
| 1117 | |
| 1118 | if (unlikely(!alc)) return false; |
| 1119 | *alc = YYJSON_NULL_ALC; |
| 1120 | if (size < sizeof(pool_ctx) * 4) return false; |
| 1121 | ctx = (pool_ctx *)mem_align_up(buf, sizeof(pool_ctx)); |
| 1122 | if (unlikely(!ctx)) return false; |
| 1123 | size -= (usize)((u8 *)ctx - (u8 *)buf); |
| 1124 | size = size_align_down(size, sizeof(pool_ctx)); |
| 1125 | |
| 1126 | chunk = (pool_chunk *)(ctx + 1); |
| 1127 | chunk->size = size - sizeof(pool_ctx); |
| 1128 | chunk->next = NULL; |
| 1129 | ctx->size = size; |
| 1130 | ctx->free_list = chunk; |
| 1131 | |
| 1132 | alc->malloc = pool_malloc; |
| 1133 | alc->realloc = pool_realloc; |
| 1134 | alc->free = pool_free; |
| 1135 | alc->ctx = (void *)ctx; |
| 1136 | return true; |
| 1137 | } |
| 1138 | |
| 1139 | |
| 1140 | |
| 1141 | /*============================================================================== |
| 1142 | * JSON document and value |
| 1143 | *============================================================================*/ |
| 1144 | |
| 1145 | static_inline void unsafe_yyjson_str_pool_release(yyjson_str_pool *pool, |
| 1146 | yyjson_alc *alc) { |
| 1147 | yyjson_str_chunk *chunk = pool->chunks, *next; |
| 1148 | while (chunk) { |
| 1149 | next = chunk->next; |
| 1150 | alc->free(alc->ctx, chunk); |
| 1151 | chunk = next; |
| 1152 | } |
| 1153 | } |
| 1154 | |
| 1155 | static_inline void unsafe_yyjson_val_pool_release(yyjson_val_pool *pool, |
| 1156 | yyjson_alc *alc) { |
| 1157 | yyjson_val_chunk *chunk = pool->chunks, *next; |
| 1158 | while (chunk) { |
| 1159 | next = chunk->next; |
| 1160 | alc->free(alc->ctx, chunk); |
| 1161 | chunk = next; |
| 1162 | } |
| 1163 | } |
| 1164 | |
| 1165 | bool unsafe_yyjson_str_pool_grow(yyjson_str_pool *pool, |
| 1166 | const yyjson_alc *alc, usize len) { |
| 1167 | yyjson_str_chunk *chunk; |
| 1168 | usize size, max_len; |
| 1169 | |
| 1170 | /* create a new chunk */ |
| 1171 | max_len = USIZE_MAX - sizeof(yyjson_str_chunk); |
| 1172 | if (unlikely(len > max_len)) return false; |
| 1173 | size = len + sizeof(yyjson_str_chunk); |
| 1174 | size = yyjson_max(pool->chunk_size, size); |
| 1175 | chunk = (yyjson_str_chunk *)alc->malloc(alc->ctx, size); |
| 1176 | if (unlikely(!chunk)) return false; |
| 1177 | |
| 1178 | /* insert the new chunk as the head of the linked list */ |
| 1179 | chunk->next = pool->chunks; |
| 1180 | chunk->chunk_size = size; |
| 1181 | pool->chunks = chunk; |
| 1182 | pool->cur = (char *)chunk + sizeof(yyjson_str_chunk); |
| 1183 | pool->end = (char *)chunk + size; |
| 1184 | |
| 1185 | /* the next chunk is twice the size of the current one */ |
| 1186 | size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max); |
| 1187 | if (size < pool->chunk_size) size = pool->chunk_size_max; /* overflow */ |
| 1188 | pool->chunk_size = size; |
| 1189 | return true; |
| 1190 | } |
| 1191 | |
| 1192 | bool unsafe_yyjson_val_pool_grow(yyjson_val_pool *pool, |
| 1193 | const yyjson_alc *alc, usize count) { |
| 1194 | yyjson_val_chunk *chunk; |
| 1195 | usize size, max_count; |
| 1196 | |
| 1197 | /* create a new chunk */ |
| 1198 | max_count = USIZE_MAX / sizeof(yyjson_mut_val) - 1; |
| 1199 | if (unlikely(count > max_count)) return false; |
| 1200 | size = (count + 1) * sizeof(yyjson_mut_val); |
| 1201 | size = yyjson_max(pool->chunk_size, size); |
| 1202 | chunk = (yyjson_val_chunk *)alc->malloc(alc->ctx, size); |
| 1203 | if (unlikely(!chunk)) return false; |
| 1204 | |
| 1205 | /* insert the new chunk as the head of the linked list */ |
| 1206 | chunk->next = pool->chunks; |
| 1207 | chunk->chunk_size = size; |
| 1208 | pool->chunks = chunk; |
| 1209 | pool->cur = (yyjson_mut_val *)(void *)((u8 *)chunk) + 1; |
| 1210 | pool->end = (yyjson_mut_val *)(void *)((u8 *)chunk + size); |
| 1211 | |
| 1212 | /* the next chunk is twice the size of the current one */ |
| 1213 | size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max); |
| 1214 | if (size < pool->chunk_size) size = pool->chunk_size_max; /* overflow */ |
| 1215 | pool->chunk_size = size; |
| 1216 | return true; |
| 1217 | } |
| 1218 | |
| 1219 | bool yyjson_mut_doc_set_str_pool_size(yyjson_mut_doc *doc, size_t len) { |
| 1220 | usize max_size = USIZE_MAX - sizeof(yyjson_str_chunk); |
| 1221 | if (!doc || !len || len > max_size) return false; |
| 1222 | doc->str_pool.chunk_size = len + sizeof(yyjson_str_chunk); |
| 1223 | return true; |
| 1224 | } |
| 1225 | |
| 1226 | bool yyjson_mut_doc_set_val_pool_size(yyjson_mut_doc *doc, size_t count) { |
| 1227 | usize max_count = USIZE_MAX / sizeof(yyjson_mut_val) - 1; |
| 1228 | if (!doc || !count || count > max_count) return false; |
| 1229 | doc->val_pool.chunk_size = (count + 1) * sizeof(yyjson_mut_val); |
| 1230 | return true; |
| 1231 | } |
| 1232 | |
| 1233 | void yyjson_mut_doc_free(yyjson_mut_doc *doc) { |
| 1234 | if (doc) { |
| 1235 | yyjson_alc alc = doc->alc; |
| 1236 | unsafe_yyjson_str_pool_release(&doc->str_pool, &alc); |
| 1237 | unsafe_yyjson_val_pool_release(&doc->val_pool, &alc); |
| 1238 | alc.free(alc.ctx, doc); |
| 1239 | } |
| 1240 | } |
| 1241 | |
| 1242 | yyjson_mut_doc *yyjson_mut_doc_new(const yyjson_alc *alc) { |
| 1243 | yyjson_mut_doc *doc; |
| 1244 | if (!alc) alc = &YYJSON_DEFAULT_ALC; |
| 1245 | doc = (yyjson_mut_doc *)alc->malloc(alc->ctx, sizeof(yyjson_mut_doc)); |
| 1246 | if (!doc) return NULL; |
| 1247 | memset(doc, 0, sizeof(yyjson_mut_doc)); |
| 1248 | |
| 1249 | doc->alc = *alc; |
| 1250 | doc->str_pool.chunk_size = YYJSON_MUT_DOC_STR_POOL_INIT_SIZE; |
| 1251 | doc->str_pool.chunk_size_max = YYJSON_MUT_DOC_STR_POOL_MAX_SIZE; |
| 1252 | doc->val_pool.chunk_size = YYJSON_MUT_DOC_VAL_POOL_INIT_SIZE; |
| 1253 | doc->val_pool.chunk_size_max = YYJSON_MUT_DOC_VAL_POOL_MAX_SIZE; |
| 1254 | return doc; |
| 1255 | } |
| 1256 | |
| 1257 | yyjson_mut_doc *yyjson_doc_mut_copy(yyjson_doc *doc, const yyjson_alc *alc) { |
| 1258 | yyjson_mut_doc *m_doc; |
| 1259 | yyjson_mut_val *m_val; |
| 1260 | |
| 1261 | if (!doc || !doc->root) return NULL; |
| 1262 | m_doc = yyjson_mut_doc_new(alc); |
| 1263 | if (!m_doc) return NULL; |
| 1264 | m_val = yyjson_val_mut_copy(m_doc, doc->root); |
| 1265 | if (!m_val) { |
| 1266 | yyjson_mut_doc_free(m_doc); |
| 1267 | return NULL; |
| 1268 | } |
| 1269 | yyjson_mut_doc_set_root(m_doc, m_val); |
| 1270 | return m_doc; |
| 1271 | } |
| 1272 | |
| 1273 | yyjson_mut_doc *yyjson_mut_doc_mut_copy(yyjson_mut_doc *doc, |
| 1274 | const yyjson_alc *alc) { |
| 1275 | yyjson_mut_doc *m_doc; |
| 1276 | yyjson_mut_val *m_val; |
| 1277 | |
| 1278 | if (!doc) return NULL; |
| 1279 | if (!doc->root) return yyjson_mut_doc_new(alc); |
| 1280 | |
| 1281 | m_doc = yyjson_mut_doc_new(alc); |
| 1282 | if (!m_doc) return NULL; |
| 1283 | m_val = yyjson_mut_val_mut_copy(m_doc, doc->root); |
| 1284 | if (!m_val) { |
| 1285 | yyjson_mut_doc_free(m_doc); |
| 1286 | return NULL; |
| 1287 | } |
| 1288 | yyjson_mut_doc_set_root(m_doc, m_val); |
| 1289 | return m_doc; |
| 1290 | } |
| 1291 | |
| 1292 | yyjson_mut_val *yyjson_val_mut_copy(yyjson_mut_doc *m_doc, |
| 1293 | yyjson_val *i_vals) { |
| 1294 | /* |
| 1295 | The immutable object or array stores all sub-values in a contiguous memory, |
| 1296 | We copy them to another contiguous memory as mutable values, |
| 1297 | then reconnect the mutable values with the original relationship. |
| 1298 | */ |
| 1299 | |
| 1300 | usize i_vals_len; |
| 1301 | yyjson_mut_val *m_vals, *m_val; |
| 1302 | yyjson_val *i_val, *i_end; |
| 1303 | |
| 1304 | if (!m_doc || !i_vals) return NULL; |
| 1305 | i_end = unsafe_yyjson_get_next(i_vals); |
| 1306 | i_vals_len = (usize)(unsafe_yyjson_get_next(i_vals) - i_vals); |
| 1307 | m_vals = unsafe_yyjson_mut_val(m_doc, i_vals_len); |
| 1308 | if (!m_vals) return NULL; |
| 1309 | i_val = i_vals; |
| 1310 | m_val = m_vals; |
| 1311 | |
| 1312 | for (; i_val < i_end; i_val++, m_val++) { |
| 1313 | yyjson_type type = unsafe_yyjson_get_type(i_val); |
| 1314 | m_val->tag = i_val->tag; |
| 1315 | m_val->uni.u64 = i_val->uni.u64; |
| 1316 | if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) { |
| 1317 | const char *str = i_val->uni.str; |
| 1318 | usize str_len = unsafe_yyjson_get_len(i_val); |
| 1319 | m_val->uni.str = unsafe_yyjson_mut_strncpy(m_doc, str, str_len); |
| 1320 | if (!m_val->uni.str) return NULL; |
| 1321 | } else if (type == YYJSON_TYPE_ARR) { |
| 1322 | usize len = unsafe_yyjson_get_len(i_val); |
| 1323 | if (len > 0) { |
| 1324 | yyjson_val *ii_val = i_val + 1, *ii_next; |
| 1325 | yyjson_mut_val *mm_val = m_val + 1, *mm_ctn = m_val, *mm_next; |
| 1326 | while (len-- > 1) { |
| 1327 | ii_next = unsafe_yyjson_get_next(ii_val); |
| 1328 | mm_next = mm_val + (ii_next - ii_val); |
| 1329 | mm_val->next = mm_next; |
| 1330 | ii_val = ii_next; |
| 1331 | mm_val = mm_next; |
| 1332 | } |
| 1333 | mm_val->next = mm_ctn + 1; |
| 1334 | mm_ctn->uni.ptr = mm_val; |
| 1335 | } |
| 1336 | } else if (type == YYJSON_TYPE_OBJ) { |
| 1337 | usize len = unsafe_yyjson_get_len(i_val); |
| 1338 | if (len > 0) { |
| 1339 | yyjson_val *ii_key = i_val + 1, *ii_nextkey; |
| 1340 | yyjson_mut_val *mm_key = m_val + 1, *mm_ctn = m_val; |
| 1341 | yyjson_mut_val *mm_nextkey; |
| 1342 | while (len-- > 1) { |
| 1343 | ii_nextkey = unsafe_yyjson_get_next(ii_key + 1); |
| 1344 | mm_nextkey = mm_key + (ii_nextkey - ii_key); |
| 1345 | mm_key->next = mm_key + 1; |
| 1346 | mm_key->next->next = mm_nextkey; |
| 1347 | ii_key = ii_nextkey; |
| 1348 | mm_key = mm_nextkey; |
| 1349 | } |
| 1350 | mm_key->next = mm_key + 1; |
| 1351 | mm_key->next->next = mm_ctn + 1; |
| 1352 | mm_ctn->uni.ptr = mm_key; |
| 1353 | } |
| 1354 | } |
| 1355 | } |
| 1356 | |
| 1357 | return m_vals; |
| 1358 | } |
| 1359 | |
| 1360 | static yyjson_mut_val *unsafe_yyjson_mut_val_mut_copy(yyjson_mut_doc *m_doc, |
| 1361 | yyjson_mut_val *m_vals) { |
| 1362 | /* |
| 1363 | The mutable object or array stores all sub-values in a circular linked |
| 1364 | list, so we can traverse them in the same loop. The traversal starts from |
| 1365 | the last item, continues with the first item in a list, and ends with the |
| 1366 | second to last item, which needs to be linked to the last item to close the |
| 1367 | circle. |
| 1368 | */ |
| 1369 | |
| 1370 | yyjson_mut_val *m_val = unsafe_yyjson_mut_val(m_doc, 1); |
| 1371 | if (unlikely(!m_val)) return NULL; |
| 1372 | m_val->tag = m_vals->tag; |
| 1373 | |
| 1374 | switch (unsafe_yyjson_get_type(m_vals)) { |
| 1375 | case YYJSON_TYPE_OBJ: |
| 1376 | case YYJSON_TYPE_ARR: |
| 1377 | if (unsafe_yyjson_get_len(m_vals) > 0) { |
| 1378 | yyjson_mut_val *last = (yyjson_mut_val *)m_vals->uni.ptr; |
| 1379 | yyjson_mut_val *next = last->next, *prev; |
| 1380 | prev = unsafe_yyjson_mut_val_mut_copy(m_doc, last); |
| 1381 | if (!prev) return NULL; |
| 1382 | m_val->uni.ptr = (void *)prev; |
| 1383 | while (next != last) { |
| 1384 | prev->next = unsafe_yyjson_mut_val_mut_copy(m_doc, next); |
| 1385 | if (!prev->next) return NULL; |
| 1386 | prev = prev->next; |
| 1387 | next = next->next; |
| 1388 | } |
| 1389 | prev->next = (yyjson_mut_val *)m_val->uni.ptr; |
| 1390 | } |
| 1391 | break; |
| 1392 | |
| 1393 | case YYJSON_TYPE_RAW: |
| 1394 | case YYJSON_TYPE_STR: { |
| 1395 | const char *str = m_vals->uni.str; |
| 1396 | usize str_len = unsafe_yyjson_get_len(m_vals); |
| 1397 | m_val->uni.str = unsafe_yyjson_mut_strncpy(m_doc, str, str_len); |
| 1398 | if (!m_val->uni.str) return NULL; |
| 1399 | break; |
| 1400 | } |
| 1401 | |
| 1402 | default: |
| 1403 | m_val->uni = m_vals->uni; |
| 1404 | break; |
| 1405 | } |
| 1406 | |
| 1407 | return m_val; |
| 1408 | } |
| 1409 | |
| 1410 | yyjson_mut_val *yyjson_mut_val_mut_copy(yyjson_mut_doc *doc, |
| 1411 | yyjson_mut_val *val) { |
| 1412 | if (doc && val) return unsafe_yyjson_mut_val_mut_copy(doc, val); |
| 1413 | return NULL; |
| 1414 | } |
| 1415 | |
| 1416 | /* Count the number of values and the total length of the strings. */ |
| 1417 | static void yyjson_mut_stat(yyjson_mut_val *val, |
| 1418 | usize *val_sum, usize *str_sum) { |
| 1419 | yyjson_type type = unsafe_yyjson_get_type(val); |
| 1420 | *val_sum += 1; |
| 1421 | if (type == YYJSON_TYPE_ARR || type == YYJSON_TYPE_OBJ) { |
| 1422 | yyjson_mut_val *child = (yyjson_mut_val *)val->uni.ptr; |
| 1423 | usize len = unsafe_yyjson_get_len(val), i; |
| 1424 | len <<= (u8)(type == YYJSON_TYPE_OBJ); |
| 1425 | *val_sum += len; |
| 1426 | for (i = 0; i < len; i++) { |
| 1427 | yyjson_type stype = unsafe_yyjson_get_type(child); |
| 1428 | if (stype == YYJSON_TYPE_STR || stype == YYJSON_TYPE_RAW) { |
| 1429 | *str_sum += unsafe_yyjson_get_len(child) + 1; |
| 1430 | } else if (stype == YYJSON_TYPE_ARR || stype == YYJSON_TYPE_OBJ) { |
| 1431 | yyjson_mut_stat(child, val_sum, str_sum); |
| 1432 | *val_sum -= 1; |
| 1433 | } |
| 1434 | child = child->next; |
| 1435 | } |
| 1436 | } else if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) { |
| 1437 | *str_sum += unsafe_yyjson_get_len(val) + 1; |
| 1438 | } |
| 1439 | } |
| 1440 | |
| 1441 | /* Copy mutable values to immutable value pool. */ |
| 1442 | static usize yyjson_imut_copy(yyjson_val **val_ptr, char **buf_ptr, |
| 1443 | yyjson_mut_val *mval) { |
| 1444 | yyjson_val *val = *val_ptr; |
| 1445 | yyjson_type type = unsafe_yyjson_get_type(mval); |
| 1446 | if (type == YYJSON_TYPE_ARR || type == YYJSON_TYPE_OBJ) { |
| 1447 | yyjson_mut_val *child = (yyjson_mut_val *)mval->uni.ptr; |
| 1448 | usize len = unsafe_yyjson_get_len(mval), i; |
| 1449 | usize val_sum = 1; |
| 1450 | if (type == YYJSON_TYPE_OBJ) { |
| 1451 | if (len) child = child->next->next; |
| 1452 | len <<= 1; |
| 1453 | } else { |
| 1454 | if (len) child = child->next; |
| 1455 | } |
| 1456 | *val_ptr = val + 1; |
| 1457 | for (i = 0; i < len; i++) { |
| 1458 | val_sum += yyjson_imut_copy(val_ptr, buf_ptr, child); |
| 1459 | child = child->next; |
| 1460 | } |
| 1461 | val->tag = mval->tag; |
| 1462 | val->uni.ofs = val_sum * sizeof(yyjson_val); |
| 1463 | return val_sum; |
| 1464 | } else if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) { |
| 1465 | char *buf = *buf_ptr; |
| 1466 | usize len = unsafe_yyjson_get_len(mval); |
| 1467 | memcpy((void *)buf, (const void *)mval->uni.str, len); |
| 1468 | buf[len] = '\0'; |
| 1469 | val->tag = mval->tag; |
| 1470 | val->uni.str = buf; |
| 1471 | *val_ptr = val + 1; |
| 1472 | *buf_ptr = buf + len + 1; |
| 1473 | return 1; |
| 1474 | } else { |
| 1475 | val->tag = mval->tag; |
| 1476 | val->uni = mval->uni; |
| 1477 | *val_ptr = val + 1; |
| 1478 | return 1; |
| 1479 | } |
| 1480 | } |
| 1481 | |
| 1482 | yyjson_doc *yyjson_mut_doc_imut_copy(yyjson_mut_doc *mdoc, |
| 1483 | const yyjson_alc *alc) { |
| 1484 | if (!mdoc) return NULL; |
| 1485 | return yyjson_mut_val_imut_copy(mdoc->root, alc); |
| 1486 | } |
| 1487 | |
| 1488 | yyjson_doc *yyjson_mut_val_imut_copy(yyjson_mut_val *mval, |
| 1489 | const yyjson_alc *alc) { |
| 1490 | usize val_num = 0, str_sum = 0, hdr_size, buf_size; |
| 1491 | yyjson_doc *doc = NULL; |
| 1492 | yyjson_val *val_hdr = NULL; |
| 1493 | |
| 1494 | /* This value should be NULL here. Setting a non-null value suppresses |
| 1495 | warning from the clang analyzer. */ |
| 1496 | char *str_hdr = (char *)(void *)&str_sum; |
| 1497 | if (!mval) return NULL; |
| 1498 | if (!alc) alc = &YYJSON_DEFAULT_ALC; |
| 1499 | |
| 1500 | /* traverse the input value to get pool size */ |
| 1501 | yyjson_mut_stat(mval, &val_num, &str_sum); |
| 1502 | |
| 1503 | /* create doc and val pool */ |
| 1504 | hdr_size = size_align_up(sizeof(yyjson_doc), sizeof(yyjson_val)); |
| 1505 | buf_size = hdr_size + val_num * sizeof(yyjson_val); |
| 1506 | doc = (yyjson_doc *)alc->malloc(alc->ctx, buf_size); |
| 1507 | if (!doc) return NULL; |
| 1508 | memset(doc, 0, sizeof(yyjson_doc)); |
| 1509 | val_hdr = (yyjson_val *)(void *)((char *)(void *)doc + hdr_size); |
| 1510 | doc->root = val_hdr; |
| 1511 | doc->alc = *alc; |
| 1512 | |
| 1513 | /* create str pool */ |
| 1514 | if (str_sum > 0) { |
| 1515 | str_hdr = (char *)alc->malloc(alc->ctx, str_sum); |
| 1516 | doc->str_pool = str_hdr; |
| 1517 | if (!str_hdr) { |
| 1518 | alc->free(alc->ctx, (void *)doc); |
| 1519 | return NULL; |
| 1520 | } |
| 1521 | } |
| 1522 | |
| 1523 | /* copy vals and strs */ |
| 1524 | doc->val_read = yyjson_imut_copy(&val_hdr, &str_hdr, mval); |
| 1525 | doc->dat_read = str_sum + 1; |
| 1526 | return doc; |
| 1527 | } |
| 1528 | |
| 1529 | static_inline bool unsafe_yyjson_num_equals(void *lhs, void *rhs) { |
| 1530 | yyjson_val_uni *luni = &((yyjson_val *)lhs)->uni; |
| 1531 | yyjson_val_uni *runi = &((yyjson_val *)rhs)->uni; |
| 1532 | yyjson_subtype lt = unsafe_yyjson_get_subtype(lhs); |
| 1533 | yyjson_subtype rt = unsafe_yyjson_get_subtype(rhs); |
| 1534 | if (lt == rt) |
| 1535 | return luni->u64 == runi->u64; |
| 1536 | if (lt == YYJSON_SUBTYPE_SINT && rt == YYJSON_SUBTYPE_UINT) |
| 1537 | return luni->i64 >= 0 && luni->u64 == runi->u64; |
| 1538 | if (lt == YYJSON_SUBTYPE_UINT && rt == YYJSON_SUBTYPE_SINT) |
| 1539 | return runi->i64 >= 0 && luni->u64 == runi->u64; |
| 1540 | return false; |
| 1541 | } |
| 1542 | |
| 1543 | static_inline bool unsafe_yyjson_str_equals(void *lhs, void *rhs) { |
| 1544 | usize len = unsafe_yyjson_get_len(lhs); |
| 1545 | if (len != unsafe_yyjson_get_len(rhs)) return false; |
| 1546 | return !memcmp(unsafe_yyjson_get_str(lhs), |
| 1547 | unsafe_yyjson_get_str(rhs), len); |
| 1548 | } |
| 1549 | |
| 1550 | bool unsafe_yyjson_equals(yyjson_val *lhs, yyjson_val *rhs) { |
| 1551 | yyjson_type type = unsafe_yyjson_get_type(lhs); |
| 1552 | if (type != unsafe_yyjson_get_type(rhs)) return false; |
| 1553 | |
| 1554 | switch (type) { |
| 1555 | case YYJSON_TYPE_OBJ: { |
| 1556 | usize len = unsafe_yyjson_get_len(lhs); |
| 1557 | if (len != unsafe_yyjson_get_len(rhs)) return false; |
| 1558 | if (len > 0) { |
| 1559 | yyjson_obj_iter iter; |
| 1560 | yyjson_obj_iter_init(rhs, &iter); |
| 1561 | lhs = unsafe_yyjson_get_first(lhs); |
| 1562 | while (len-- > 0) { |
| 1563 | rhs = yyjson_obj_iter_getn(&iter, lhs->uni.str, |
| 1564 | unsafe_yyjson_get_len(lhs)); |
| 1565 | if (!rhs || !unsafe_yyjson_equals(lhs + 1, rhs)) |
| 1566 | return false; |
| 1567 | lhs = unsafe_yyjson_get_next(lhs + 1); |
| 1568 | } |
| 1569 | } |
| 1570 | /* yyjson allows duplicate keys, so the check may be inaccurate */ |
| 1571 | return true; |
| 1572 | } |
| 1573 | |
| 1574 | case YYJSON_TYPE_ARR: { |
| 1575 | usize len = unsafe_yyjson_get_len(lhs); |
| 1576 | if (len != unsafe_yyjson_get_len(rhs)) return false; |
| 1577 | if (len > 0) { |
| 1578 | lhs = unsafe_yyjson_get_first(lhs); |
| 1579 | rhs = unsafe_yyjson_get_first(rhs); |
| 1580 | while (len-- > 0) { |
| 1581 | if (!unsafe_yyjson_equals(lhs, rhs)) return false; |
| 1582 | lhs = unsafe_yyjson_get_next(lhs); |
| 1583 | rhs = unsafe_yyjson_get_next(rhs); |
| 1584 | } |
| 1585 | } |
| 1586 | return true; |
| 1587 | } |
| 1588 | |
| 1589 | case YYJSON_TYPE_NUM: |
| 1590 | return unsafe_yyjson_num_equals(lhs, rhs); |
| 1591 | |
| 1592 | case YYJSON_TYPE_RAW: |
| 1593 | case YYJSON_TYPE_STR: |
| 1594 | return unsafe_yyjson_str_equals(lhs, rhs); |
| 1595 | |
| 1596 | case YYJSON_TYPE_NULL: |
| 1597 | case YYJSON_TYPE_BOOL: |
| 1598 | return lhs->tag == rhs->tag; |
| 1599 | |
| 1600 | default: |
| 1601 | return false; |
| 1602 | } |
| 1603 | } |
| 1604 | |
| 1605 | bool unsafe_yyjson_mut_equals(yyjson_mut_val *lhs, yyjson_mut_val *rhs) { |
| 1606 | yyjson_type type = unsafe_yyjson_get_type(lhs); |
| 1607 | if (type != unsafe_yyjson_get_type(rhs)) return false; |
| 1608 | |
| 1609 | switch (type) { |
| 1610 | case YYJSON_TYPE_OBJ: { |
| 1611 | usize len = unsafe_yyjson_get_len(lhs); |
| 1612 | if (len != unsafe_yyjson_get_len(rhs)) return false; |
| 1613 | if (len > 0) { |
| 1614 | yyjson_mut_obj_iter iter; |
| 1615 | yyjson_mut_obj_iter_init(rhs, &iter); |
| 1616 | lhs = (yyjson_mut_val *)lhs->uni.ptr; |
| 1617 | while (len-- > 0) { |
| 1618 | rhs = yyjson_mut_obj_iter_getn(&iter, lhs->uni.str, |
| 1619 | unsafe_yyjson_get_len(lhs)); |
| 1620 | if (!rhs || !unsafe_yyjson_mut_equals(lhs->next, rhs)) |
| 1621 | return false; |
| 1622 | lhs = lhs->next->next; |
| 1623 | } |
| 1624 | } |
| 1625 | /* yyjson allows duplicate keys, so the check may be inaccurate */ |
| 1626 | return true; |
| 1627 | } |
| 1628 | |
| 1629 | case YYJSON_TYPE_ARR: { |
| 1630 | usize len = unsafe_yyjson_get_len(lhs); |
| 1631 | if (len != unsafe_yyjson_get_len(rhs)) return false; |
| 1632 | if (len > 0) { |
| 1633 | lhs = (yyjson_mut_val *)lhs->uni.ptr; |
| 1634 | rhs = (yyjson_mut_val *)rhs->uni.ptr; |
| 1635 | while (len-- > 0) { |
| 1636 | if (!unsafe_yyjson_mut_equals(lhs, rhs)) return false; |
| 1637 | lhs = lhs->next; |
| 1638 | rhs = rhs->next; |
| 1639 | } |
| 1640 | } |
| 1641 | return true; |
| 1642 | } |
| 1643 | |
| 1644 | case YYJSON_TYPE_NUM: |
| 1645 | return unsafe_yyjson_num_equals(lhs, rhs); |
| 1646 | |
| 1647 | case YYJSON_TYPE_RAW: |
| 1648 | case YYJSON_TYPE_STR: |
| 1649 | return unsafe_yyjson_str_equals(lhs, rhs); |
| 1650 | |
| 1651 | case YYJSON_TYPE_NULL: |
| 1652 | case YYJSON_TYPE_BOOL: |
| 1653 | return lhs->tag == rhs->tag; |
| 1654 | |
| 1655 | default: |
| 1656 | return false; |
| 1657 | } |
| 1658 | } |
| 1659 | |
| 1660 | |
| 1661 | |
| 1662 | #if !YYJSON_DISABLE_UTILS |
| 1663 | |
| 1664 | /*============================================================================== |
| 1665 | * JSON Pointer API (RFC 6901) |
| 1666 | *============================================================================*/ |
| 1667 | |
| 1668 | /** |
| 1669 | Get a token from JSON pointer string. |
| 1670 | @param ptr [in,out] |
| 1671 | in: string that points to current token prefix `/` |
| 1672 | out: string that points to next token prefix `/`, or string end |
| 1673 | @param end [in] end of the entire JSON Pointer string |
| 1674 | @param len [out] unescaped token length |
| 1675 | @param esc [out] number of escaped characters in this token |
| 1676 | @return head of the token, or NULL if syntax error |
| 1677 | */ |
| 1678 | static_inline const char *ptr_next_token(const char **ptr, const char *end, |
| 1679 | usize *len, usize *esc) { |
| 1680 | const char *hdr = *ptr + 1; |
| 1681 | const char *cur = hdr; |
| 1682 | /* skip unescaped characters */ |
| 1683 | while (cur < end && *cur != '/' && *cur != '~') cur++; |
| 1684 | if (likely(cur == end || *cur != '~')) { |
| 1685 | /* no escaped characters, return */ |
| 1686 | *ptr = cur; |
| 1687 | *len = (usize)(cur - hdr); |
| 1688 | *esc = 0; |
| 1689 | return hdr; |
| 1690 | } else { |
| 1691 | /* handle escaped characters */ |
| 1692 | usize esc_num = 0; |
| 1693 | while (cur < end && *cur != '/') { |
| 1694 | if (*cur++ == '~') { |
| 1695 | if (cur == end || (*cur != '0' && *cur != '1')) { |
| 1696 | *ptr = cur - 1; |
| 1697 | return NULL; |
| 1698 | } |
| 1699 | esc_num++; |
| 1700 | } |
| 1701 | } |
| 1702 | *ptr = cur; |
| 1703 | *len = (usize)(cur - hdr) - esc_num; |
| 1704 | *esc = esc_num; |
| 1705 | return hdr; |
| 1706 | } |
| 1707 | } |
| 1708 | |
| 1709 | /** |
| 1710 | Convert token string to index. |
| 1711 | @param cur [in] token head |
| 1712 | @param len [in] token length |
| 1713 | @param idx [out] the index number, or USIZE_MAX if token is '-' |
| 1714 | @return true if token is a valid array index |
| 1715 | */ |
| 1716 | static_inline bool ptr_token_to_idx(const char *cur, usize len, usize *idx) { |
| 1717 | const char *end = cur + len; |
| 1718 | usize num = 0, add; |
| 1719 | if (unlikely(len == 0 || len > USIZE_SAFE_DIG)) return false; |
| 1720 | if (*cur == '0') { |
| 1721 | if (unlikely(len > 1)) return false; |
| 1722 | *idx = 0; |
| 1723 | return true; |
| 1724 | } |
| 1725 | if (*cur == '-') { |
| 1726 | if (unlikely(len > 1)) return false; |
| 1727 | *idx = USIZE_MAX; |
| 1728 | return true; |
| 1729 | } |
| 1730 | for (; cur < end && (add = (usize)((u8)*cur - (u8)'0')) <= 9; cur++) { |
| 1731 | num = num * 10 + add; |
| 1732 | } |
| 1733 | if (unlikely(num == 0 || cur < end)) return false; |
| 1734 | *idx = num; |
| 1735 | return true; |
| 1736 | } |
| 1737 | |
| 1738 | /** |
| 1739 | Compare JSON key with token. |
| 1740 | @param key a string key (yyjson_val or yyjson_mut_val) |
| 1741 | @param token a JSON pointer token |
| 1742 | @param len unescaped token length |
| 1743 | @param esc number of escaped characters in this token |
| 1744 | @return true if `str` is equals to `token` |
| 1745 | */ |
| 1746 | static_inline bool ptr_token_eq(void *key, |
| 1747 | const char *token, usize len, usize esc) { |
| 1748 | yyjson_val *val = (yyjson_val *)key; |
| 1749 | if (unsafe_yyjson_get_len(val) != len) return false; |
| 1750 | if (likely(!esc)) { |
| 1751 | return memcmp(val->uni.str, token, len) == 0; |
| 1752 | } else { |
| 1753 | const char *str = val->uni.str; |
| 1754 | for (; len-- > 0; token++, str++) { |
| 1755 | if (*token == '~') { |
| 1756 | if (*str != (*++token == '0' ? '~' : '/')) return false; |
| 1757 | } else { |
| 1758 | if (*str != *token) return false; |
| 1759 | } |
| 1760 | } |
| 1761 | return true; |
| 1762 | } |
| 1763 | } |
| 1764 | |
| 1765 | /** |
| 1766 | Get a value from array by token. |
| 1767 | @param arr an array, should not be NULL or non-array type |
| 1768 | @param token a JSON pointer token |
| 1769 | @param len unescaped token length |
| 1770 | @param esc number of escaped characters in this token |
| 1771 | @return value at index, or NULL if token is not index or index is out of range |
| 1772 | */ |
| 1773 | static_inline yyjson_val *ptr_arr_get(yyjson_val *arr, const char *token, |
| 1774 | usize len, usize esc) { |
| 1775 | yyjson_val *val = unsafe_yyjson_get_first(arr); |
| 1776 | usize num = unsafe_yyjson_get_len(arr), idx = 0; |
| 1777 | if (unlikely(num == 0)) return NULL; |
| 1778 | if (unlikely(!ptr_token_to_idx(token, len, &idx))) return NULL; |
| 1779 | if (unlikely(idx >= num)) return NULL; |
| 1780 | if (unsafe_yyjson_arr_is_flat(arr)) { |
| 1781 | return val + idx; |
| 1782 | } else { |
| 1783 | while (idx-- > 0) val = unsafe_yyjson_get_next(val); |
| 1784 | return val; |
| 1785 | } |
| 1786 | } |
| 1787 | |
| 1788 | /** |
| 1789 | Get a value from object by token. |
| 1790 | @param obj [in] an object, should not be NULL or non-object type |
| 1791 | @param token [in] a JSON pointer token |
| 1792 | @param len [in] unescaped token length |
| 1793 | @param esc [in] number of escaped characters in this token |
| 1794 | @return value associated with the token, or NULL if no value |
| 1795 | */ |
| 1796 | static_inline yyjson_val *ptr_obj_get(yyjson_val *obj, const char *token, |
| 1797 | usize len, usize esc) { |
| 1798 | yyjson_val *key = unsafe_yyjson_get_first(obj); |
| 1799 | usize num = unsafe_yyjson_get_len(obj); |
| 1800 | if (unlikely(num == 0)) return NULL; |
| 1801 | for (; num > 0; num--, key = unsafe_yyjson_get_next(key + 1)) { |
| 1802 | if (ptr_token_eq(key, token, len, esc)) return key + 1; |
| 1803 | } |
| 1804 | return NULL; |
| 1805 | } |
| 1806 | |
| 1807 | /** |
| 1808 | Get a value from array by token. |
| 1809 | @param arr [in] an array, should not be NULL or non-array type |
| 1810 | @param token [in] a JSON pointer token |
| 1811 | @param len [in] unescaped token length |
| 1812 | @param esc [in] number of escaped characters in this token |
| 1813 | @param pre [out] previous (sibling) value of the returned value |
| 1814 | @param last [out] whether index is last |
| 1815 | @return value at index, or NULL if token is not index or index is out of range |
| 1816 | */ |
| 1817 | static_inline yyjson_mut_val *ptr_mut_arr_get(yyjson_mut_val *arr, |
| 1818 | const char *token, |
| 1819 | usize len, usize esc, |
| 1820 | yyjson_mut_val **pre, |
| 1821 | bool *last) { |
| 1822 | yyjson_mut_val *val = (yyjson_mut_val *)arr->uni.ptr; /* last (tail) */ |
| 1823 | usize num = unsafe_yyjson_get_len(arr), idx; |
| 1824 | if (last) *last = false; |
| 1825 | if (pre) *pre = NULL; |
| 1826 | if (unlikely(num == 0)) { |
| 1827 | if (last && len == 1 && (*token == '0' || *token == '-')) *last = true; |
| 1828 | return NULL; |
| 1829 | } |
| 1830 | if (unlikely(!ptr_token_to_idx(token, len, &idx))) return NULL; |
| 1831 | if (last) *last = (idx == num || idx == USIZE_MAX); |
| 1832 | if (unlikely(idx >= num)) return NULL; |
| 1833 | while (idx-- > 0) val = val->next; |
| 1834 | *pre = val; |
| 1835 | return val->next; |
| 1836 | } |
| 1837 | |
| 1838 | /** |
| 1839 | Get a value from object by token. |
| 1840 | @param obj [in] an object, should not be NULL or non-object type |
| 1841 | @param token [in] a JSON pointer token |
| 1842 | @param len [in] unescaped token length |
| 1843 | @param esc [in] number of escaped characters in this token |
| 1844 | @param pre [out] previous (sibling) key of the returned value's key |
| 1845 | @return value associated with the token, or NULL if no value |
| 1846 | */ |
| 1847 | static_inline yyjson_mut_val *ptr_mut_obj_get(yyjson_mut_val *obj, |
| 1848 | const char *token, |
| 1849 | usize len, usize esc, |
| 1850 | yyjson_mut_val **pre) { |
| 1851 | yyjson_mut_val *pre_key = (yyjson_mut_val *)obj->uni.ptr, *key; |
| 1852 | usize num = unsafe_yyjson_get_len(obj); |
| 1853 | if (pre) *pre = NULL; |
| 1854 | if (unlikely(num == 0)) return NULL; |
| 1855 | for (; num > 0; num--, pre_key = key) { |
| 1856 | key = pre_key->next->next; |
| 1857 | if (ptr_token_eq(key, token, len, esc)) { |
| 1858 | *pre = pre_key; |
| 1859 | return key->next; |
| 1860 | } |
| 1861 | } |
| 1862 | return NULL; |
| 1863 | } |
| 1864 | |
| 1865 | /** |
| 1866 | Create a string value with JSON pointer token. |
| 1867 | @param token [in] a JSON pointer token |
| 1868 | @param len [in] unescaped token length |
| 1869 | @param esc [in] number of escaped characters in this token |
| 1870 | @param doc [in] used for memory allocation when creating value |
| 1871 | @return new string value, or NULL if memory allocation failed |
| 1872 | */ |
| 1873 | static_inline yyjson_mut_val *ptr_new_key(const char *token, |
| 1874 | usize len, usize esc, |
| 1875 | yyjson_mut_doc *doc) { |
| 1876 | const char *src = token; |
| 1877 | if (likely(!esc)) { |
| 1878 | return yyjson_mut_strncpy(doc, src, len); |
| 1879 | } else { |
| 1880 | const char *end = src + len + esc; |
| 1881 | char *dst = unsafe_yyjson_mut_str_alc(doc, len + esc); |
| 1882 | char *str = dst; |
| 1883 | if (unlikely(!dst)) return NULL; |
| 1884 | for (; src < end; src++, dst++) { |
| 1885 | if (*src != '~') *dst = *src; |
| 1886 | else *dst = (*++src == '0' ? '~' : '/'); |
| 1887 | } |
| 1888 | *dst = '\0'; |
| 1889 | return yyjson_mut_strn(doc, str, len); |
| 1890 | } |
| 1891 | } |
| 1892 | |
| 1893 | /* macros for yyjson_ptr */ |
| 1894 | #define return_err(_ret, _code, _pos, _msg) do { \ |
| 1895 | if (err) { \ |
| 1896 | err->code = YYJSON_PTR_ERR_##_code; \ |
| 1897 | err->msg = _msg; \ |
| 1898 | err->pos = (usize)(_pos); \ |
| 1899 | } \ |
| 1900 | return _ret; \ |
| 1901 | } while (false) |
| 1902 | |
| 1903 | #define return_err_resolve(_ret, _pos) \ |
| 1904 | return_err(_ret, RESOLVE, _pos, "JSON pointer cannot be resolved") |
| 1905 | #define return_err_syntax(_ret, _pos) \ |
| 1906 | return_err(_ret, SYNTAX, _pos, "invalid escaped character") |
| 1907 | #define return_err_alloc(_ret) \ |
| 1908 | return_err(_ret, MEMORY_ALLOCATION, 0, "failed to create value") |
| 1909 | |
| 1910 | yyjson_val *unsafe_yyjson_ptr_getx(yyjson_val *val, |
| 1911 | const char *ptr, size_t ptr_len, |
| 1912 | yyjson_ptr_err *err) { |
| 1913 | |
| 1914 | const char *hdr = ptr, *end = ptr + ptr_len, *token; |
| 1915 | usize len, esc; |
| 1916 | yyjson_type type; |
| 1917 | |
| 1918 | while (true) { |
| 1919 | token = ptr_next_token(&ptr, end, &len, &esc); |
| 1920 | if (unlikely(!token)) return_err_syntax(NULL, ptr - hdr); |
| 1921 | type = unsafe_yyjson_get_type(val); |
| 1922 | if (type == YYJSON_TYPE_OBJ) { |
| 1923 | val = ptr_obj_get(val, token, len, esc); |
| 1924 | } else if (type == YYJSON_TYPE_ARR) { |
| 1925 | val = ptr_arr_get(val, token, len, esc); |
| 1926 | } else { |
| 1927 | val = NULL; |
| 1928 | } |
| 1929 | if (!val) return_err_resolve(NULL, token - hdr); |
| 1930 | if (ptr == end) return val; |
| 1931 | } |
| 1932 | } |
| 1933 | |
| 1934 | yyjson_mut_val *unsafe_yyjson_mut_ptr_getx(yyjson_mut_val *val, |
| 1935 | const char *ptr, |
| 1936 | size_t ptr_len, |
| 1937 | yyjson_ptr_ctx *ctx, |
| 1938 | yyjson_ptr_err *err) { |
| 1939 | |
| 1940 | const char *hdr = ptr, *end = ptr + ptr_len, *token; |
| 1941 | usize len, esc; |
| 1942 | yyjson_mut_val *ctn, *pre = NULL; |
| 1943 | yyjson_type type; |
| 1944 | bool idx_is_last = false; |
| 1945 | |
| 1946 | while (true) { |
| 1947 | token = ptr_next_token(&ptr, end, &len, &esc); |
| 1948 | if (unlikely(!token)) return_err_syntax(NULL, ptr - hdr); |
| 1949 | ctn = val; |
| 1950 | type = unsafe_yyjson_get_type(val); |
| 1951 | if (type == YYJSON_TYPE_OBJ) { |
| 1952 | val = ptr_mut_obj_get(val, token, len, esc, &pre); |
| 1953 | } else if (type == YYJSON_TYPE_ARR) { |
| 1954 | val = ptr_mut_arr_get(val, token, len, esc, &pre, &idx_is_last); |
| 1955 | } else { |
| 1956 | val = NULL; |
| 1957 | } |
| 1958 | if (ctx && (ptr == end)) { |
| 1959 | if (type == YYJSON_TYPE_OBJ || |
| 1960 | (type == YYJSON_TYPE_ARR && (val || idx_is_last))) { |
| 1961 | ctx->ctn = ctn; |
| 1962 | ctx->pre = pre; |
| 1963 | } |
| 1964 | } |
| 1965 | if (!val) return_err_resolve(NULL, token - hdr); |
| 1966 | if (ptr == end) return val; |
| 1967 | } |
| 1968 | } |
| 1969 | |
| 1970 | bool unsafe_yyjson_mut_ptr_putx(yyjson_mut_val *val, |
| 1971 | const char *ptr, size_t ptr_len, |
| 1972 | yyjson_mut_val *new_val, |
| 1973 | yyjson_mut_doc *doc, |
| 1974 | bool create_parent, bool insert_new, |
| 1975 | yyjson_ptr_ctx *ctx, |
| 1976 | yyjson_ptr_err *err) { |
| 1977 | |
| 1978 | const char *hdr = ptr, *end = ptr + ptr_len, *token; |
| 1979 | usize token_len, esc, ctn_len; |
| 1980 | yyjson_mut_val *ctn, *key, *pre = NULL; |
| 1981 | yyjson_mut_val *sep_ctn = NULL, *sep_key = NULL, *sep_val = NULL; |
| 1982 | yyjson_type ctn_type; |
| 1983 | bool idx_is_last = false; |
| 1984 | |
| 1985 | /* skip exist parent nodes */ |
| 1986 | while (true) { |
| 1987 | token = ptr_next_token(&ptr, end, &token_len, &esc); |
| 1988 | if (unlikely(!token)) return_err_syntax(false, ptr - hdr); |
| 1989 | ctn = val; |
| 1990 | ctn_type = unsafe_yyjson_get_type(ctn); |
| 1991 | if (ctn_type == YYJSON_TYPE_OBJ) { |
| 1992 | val = ptr_mut_obj_get(ctn, token, token_len, esc, &pre); |
| 1993 | } else if (ctn_type == YYJSON_TYPE_ARR) { |
| 1994 | val = ptr_mut_arr_get(ctn, token, token_len, esc, &pre, |
| 1995 | &idx_is_last); |
| 1996 | } else return_err_resolve(false, token - hdr); |
| 1997 | if (!val) break; |
| 1998 | if (ptr == end) break; /* is last token */ |
| 1999 | } |
| 2000 | |
| 2001 | /* create parent nodes if not exist */ |
| 2002 | if (unlikely(ptr != end)) { /* not last token */ |
| 2003 | if (!create_parent) return_err_resolve(false, token - hdr); |
| 2004 | |
| 2005 | /* add value at last index if container is array */ |
| 2006 | if (ctn_type == YYJSON_TYPE_ARR) { |
| 2007 | if (!idx_is_last || !insert_new) { |
| 2008 | return_err_resolve(false, token - hdr); |
| 2009 | } |
| 2010 | val = yyjson_mut_obj(doc); |
| 2011 | if (!val) return_err_alloc(false); |
| 2012 | |
| 2013 | /* delay attaching until all operations are completed */ |
| 2014 | sep_ctn = ctn; |
| 2015 | sep_key = NULL; |
| 2016 | sep_val = val; |
| 2017 | |
| 2018 | /* move to next token */ |
| 2019 | ctn = val; |
| 2020 | val = NULL; |
| 2021 | ctn_type = YYJSON_TYPE_OBJ; |
| 2022 | token = ptr_next_token(&ptr, end, &token_len, &esc); |
| 2023 | if (unlikely(!token)) return_err_resolve(false, token - hdr); |
| 2024 | } |
| 2025 | |
| 2026 | /* container is object, create parent nodes */ |
| 2027 | while (ptr != end) { /* not last token */ |
| 2028 | key = ptr_new_key(token, token_len, esc, doc); |
| 2029 | if (!key) return_err_alloc(false); |
| 2030 | val = yyjson_mut_obj(doc); |
| 2031 | if (!val) return_err_alloc(false); |
| 2032 | |
| 2033 | /* delay attaching until all operations are completed */ |
| 2034 | if (!sep_ctn) { |
| 2035 | sep_ctn = ctn; |
| 2036 | sep_key = key; |
| 2037 | sep_val = val; |
| 2038 | } else { |
| 2039 | yyjson_mut_obj_add(ctn, key, val); |
| 2040 | } |
| 2041 | |
| 2042 | /* move to next token */ |
| 2043 | ctn = val; |
| 2044 | val = NULL; |
| 2045 | token = ptr_next_token(&ptr, end, &token_len, &esc); |
| 2046 | if (unlikely(!token)) return_err_syntax(false, ptr - hdr); |
| 2047 | } |
| 2048 | } |
| 2049 | |
| 2050 | /* JSON pointer is resolved, insert or replace target value */ |
| 2051 | ctn_len = unsafe_yyjson_get_len(ctn); |
| 2052 | if (ctn_type == YYJSON_TYPE_OBJ) { |
| 2053 | if (ctx) ctx->ctn = ctn; |
| 2054 | if (!val || insert_new) { |
| 2055 | /* insert new key-value pair */ |
| 2056 | key = ptr_new_key(token, token_len, esc, doc); |
| 2057 | if (unlikely(!key)) return_err_alloc(false); |
| 2058 | if (ctx) ctx->pre = ctn_len ? (yyjson_mut_val *)ctn->uni.ptr : key; |
| 2059 | unsafe_yyjson_mut_obj_add(ctn, key, new_val, ctn_len); |
| 2060 | } else { |
| 2061 | /* replace exist value */ |
| 2062 | key = pre->next->next; |
| 2063 | if (ctx) ctx->pre = pre; |
| 2064 | if (ctx) ctx->old = val; |
| 2065 | yyjson_mut_obj_put(ctn, key, new_val); |
| 2066 | } |
| 2067 | } else { |
| 2068 | /* array */ |
| 2069 | if (ctx && (val || idx_is_last)) ctx->ctn = ctn; |
| 2070 | if (insert_new) { |
| 2071 | /* append new value */ |
| 2072 | if (val) { |
| 2073 | pre->next = new_val; |
| 2074 | new_val->next = val; |
| 2075 | if (ctx) ctx->pre = pre; |
| 2076 | unsafe_yyjson_set_len(ctn, ctn_len + 1); |
| 2077 | } else if (idx_is_last) { |
| 2078 | if (ctx) ctx->pre = ctn_len ? |
| 2079 | (yyjson_mut_val *)ctn->uni.ptr : new_val; |
| 2080 | yyjson_mut_arr_append(ctn, new_val); |
| 2081 | } else { |
| 2082 | return_err_resolve(false, token - hdr); |
| 2083 | } |
| 2084 | } else { |
| 2085 | /* replace exist value */ |
| 2086 | if (!val) return_err_resolve(false, token - hdr); |
| 2087 | if (ctn_len > 1) { |
| 2088 | new_val->next = val->next; |
| 2089 | pre->next = new_val; |
| 2090 | if (ctn->uni.ptr == val) ctn->uni.ptr = new_val; |
| 2091 | } else { |
| 2092 | new_val->next = new_val; |
| 2093 | ctn->uni.ptr = new_val; |
| 2094 | pre = new_val; |
| 2095 | } |
| 2096 | if (ctx) ctx->pre = pre; |
| 2097 | if (ctx) ctx->old = val; |
| 2098 | } |
| 2099 | } |
| 2100 | |
| 2101 | /* all operations are completed, attach the new components to the target */ |
| 2102 | if (unlikely(sep_ctn)) { |
| 2103 | if (sep_key) yyjson_mut_obj_add(sep_ctn, sep_key, sep_val); |
| 2104 | else yyjson_mut_arr_append(sep_ctn, sep_val); |
| 2105 | } |
| 2106 | return true; |
| 2107 | } |
| 2108 | |
| 2109 | yyjson_mut_val *unsafe_yyjson_mut_ptr_replacex( |
| 2110 | yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val, |
| 2111 | yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) { |
| 2112 | |
| 2113 | yyjson_mut_val *cur_val; |
| 2114 | yyjson_ptr_ctx cur_ctx; |
| 2115 | memset(&cur_ctx, 0, sizeof(cur_ctx)); |
| 2116 | if (!ctx) ctx = &cur_ctx; |
| 2117 | cur_val = unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err); |
| 2118 | if (!cur_val) return NULL; |
| 2119 | |
| 2120 | if (yyjson_mut_is_obj(ctx->ctn)) { |
| 2121 | yyjson_mut_val *key = ctx->pre->next->next; |
| 2122 | yyjson_mut_obj_put(ctx->ctn, key, new_val); |
| 2123 | } else { |
| 2124 | yyjson_ptr_ctx_replace(ctx, new_val); |
| 2125 | } |
| 2126 | ctx->old = cur_val; |
| 2127 | return cur_val; |
| 2128 | } |
| 2129 | |
| 2130 | yyjson_mut_val *unsafe_yyjson_mut_ptr_removex(yyjson_mut_val *val, |
| 2131 | const char *ptr, |
| 2132 | size_t len, |
| 2133 | yyjson_ptr_ctx *ctx, |
| 2134 | yyjson_ptr_err *err) { |
| 2135 | yyjson_mut_val *cur_val; |
| 2136 | yyjson_ptr_ctx cur_ctx; |
| 2137 | memset(&cur_ctx, 0, sizeof(cur_ctx)); |
| 2138 | if (!ctx) ctx = &cur_ctx; |
| 2139 | cur_val = unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err); |
| 2140 | if (cur_val) { |
| 2141 | if (yyjson_mut_is_obj(ctx->ctn)) { |
| 2142 | yyjson_mut_val *key = ctx->pre->next->next; |
| 2143 | yyjson_mut_obj_put(ctx->ctn, key, NULL); |
| 2144 | } else { |
| 2145 | yyjson_ptr_ctx_remove(ctx); |
| 2146 | } |
| 2147 | ctx->pre = NULL; |
| 2148 | ctx->old = cur_val; |
| 2149 | } |
| 2150 | return cur_val; |
| 2151 | } |
| 2152 | |
| 2153 | /* macros for yyjson_ptr */ |
| 2154 | #undef return_err |
| 2155 | #undef return_err_resolve |
| 2156 | #undef return_err_syntax |
| 2157 | #undef return_err_alloc |
| 2158 | |
| 2159 | |
| 2160 | |
| 2161 | /*============================================================================== |
| 2162 | * JSON Patch API (RFC 6902) |
| 2163 | *============================================================================*/ |
| 2164 | |
| 2165 | /* JSON Patch operation */ |
| 2166 | typedef enum patch_op { |
| 2167 | PATCH_OP_ADD, /* path, value */ |
| 2168 | PATCH_OP_REMOVE, /* path */ |
| 2169 | PATCH_OP_REPLACE, /* path, value */ |
| 2170 | PATCH_OP_MOVE, /* from, path */ |
| 2171 | PATCH_OP_COPY, /* from, path */ |
| 2172 | PATCH_OP_TEST, /* path, value */ |
| 2173 | PATCH_OP_NONE /* invalid */ |
| 2174 | } patch_op; |
| 2175 | |
| 2176 | static patch_op patch_op_get(yyjson_val *op) { |
| 2177 | const char *str = op->uni.str; |
| 2178 | switch (unsafe_yyjson_get_len(op)) { |
| 2179 | case 3: |
| 2180 | if (!memcmp(str, "add" , 3)) return PATCH_OP_ADD; |
| 2181 | return PATCH_OP_NONE; |
| 2182 | case 4: |
| 2183 | if (!memcmp(str, "move" , 4)) return PATCH_OP_MOVE; |
| 2184 | if (!memcmp(str, "copy" , 4)) return PATCH_OP_COPY; |
| 2185 | if (!memcmp(str, "test" , 4)) return PATCH_OP_TEST; |
| 2186 | return PATCH_OP_NONE; |
| 2187 | case 6: |
| 2188 | if (!memcmp(str, "remove" , 6)) return PATCH_OP_REMOVE; |
| 2189 | return PATCH_OP_NONE; |
| 2190 | case 7: |
| 2191 | if (!memcmp(str, "replace" , 7)) return PATCH_OP_REPLACE; |
| 2192 | return PATCH_OP_NONE; |
| 2193 | default: |
| 2194 | return PATCH_OP_NONE; |
| 2195 | } |
| 2196 | } |
| 2197 | |
| 2198 | /* macros for yyjson_patch */ |
| 2199 | #define return_err(_code, _msg) do { \ |
| 2200 | if (err->ptr.code == YYJSON_PTR_ERR_MEMORY_ALLOCATION) { \ |
| 2201 | err->code = YYJSON_PATCH_ERROR_MEMORY_ALLOCATION; \ |
| 2202 | err->msg = _msg; \ |
| 2203 | memset(&err->ptr, 0, sizeof(yyjson_ptr_err)); \ |
| 2204 | } else { \ |
| 2205 | err->code = YYJSON_PATCH_ERROR_##_code; \ |
| 2206 | err->msg = _msg; \ |
| 2207 | err->idx = iter.idx ? iter.idx - 1 : 0; \ |
| 2208 | } \ |
| 2209 | return NULL; \ |
| 2210 | } while (false) |
| 2211 | |
| 2212 | #define return_err_copy() \ |
| 2213 | return_err(MEMORY_ALLOCATION, "failed to copy value") |
| 2214 | #define return_err_key(_key) \ |
| 2215 | return_err(MISSING_KEY, "missing key " _key) |
| 2216 | #define return_err_val(_key) \ |
| 2217 | return_err(INVALID_MEMBER, "invalid member " _key) |
| 2218 | |
| 2219 | #define ptr_get(_ptr) yyjson_mut_ptr_getx( \ |
| 2220 | root, _ptr->uni.str, _ptr##_len, NULL, &err->ptr) |
| 2221 | #define ptr_add(_ptr, _val) yyjson_mut_ptr_addx( \ |
| 2222 | root, _ptr->uni.str, _ptr##_len, _val, doc, false, NULL, &err->ptr) |
| 2223 | #define ptr_remove(_ptr) yyjson_mut_ptr_removex( \ |
| 2224 | root, _ptr->uni.str, _ptr##_len, NULL, &err->ptr) |
| 2225 | #define ptr_replace(_ptr, _val)yyjson_mut_ptr_replacex( \ |
| 2226 | root, _ptr->uni.str, _ptr##_len, _val, NULL, &err->ptr) |
| 2227 | |
| 2228 | yyjson_mut_val *yyjson_patch(yyjson_mut_doc *doc, |
| 2229 | yyjson_val *orig, |
| 2230 | yyjson_val *patch, |
| 2231 | yyjson_patch_err *err) { |
| 2232 | |
| 2233 | yyjson_mut_val *root; |
| 2234 | yyjson_val *obj; |
| 2235 | yyjson_arr_iter iter; |
| 2236 | yyjson_patch_err err_tmp; |
| 2237 | if (!err) err = &err_tmp; |
| 2238 | memset(err, 0, sizeof(*err)); |
| 2239 | memset(&iter, 0, sizeof(iter)); |
| 2240 | |
| 2241 | if (unlikely(!doc || !orig || !patch)) { |
| 2242 | return_err(INVALID_PARAMETER, "input parameter is NULL" ); |
| 2243 | } |
| 2244 | if (unlikely(!yyjson_is_arr(patch))) { |
| 2245 | return_err(INVALID_PARAMETER, "input patch is not array" ); |
| 2246 | } |
| 2247 | root = yyjson_val_mut_copy(doc, orig); |
| 2248 | if (unlikely(!root)) return_err_copy(); |
| 2249 | |
| 2250 | /* iterate through the patch array */ |
| 2251 | yyjson_arr_iter_init(patch, &iter); |
| 2252 | while ((obj = yyjson_arr_iter_next(&iter))) { |
| 2253 | patch_op op_enum; |
| 2254 | yyjson_val *op, *path, *from = NULL, *value; |
| 2255 | yyjson_mut_val *val = NULL, *test; |
| 2256 | usize path_len, from_len = 0; |
| 2257 | if (unlikely(!unsafe_yyjson_is_obj(obj))) { |
| 2258 | return_err(INVALID_OPERATION, "JSON patch operation is not object" ); |
| 2259 | } |
| 2260 | |
| 2261 | /* get required member: op */ |
| 2262 | op = yyjson_obj_get(obj, "op" ); |
| 2263 | if (unlikely(!op)) return_err_key("`op`" ); |
| 2264 | if (unlikely(!yyjson_is_str(op))) return_err_val("`op`" ); |
| 2265 | op_enum = patch_op_get(op); |
| 2266 | |
| 2267 | /* get required member: path */ |
| 2268 | path = yyjson_obj_get(obj, "path" ); |
| 2269 | if (unlikely(!path)) return_err_key("`path`" ); |
| 2270 | if (unlikely(!yyjson_is_str(path))) return_err_val("`path`" ); |
| 2271 | path_len = unsafe_yyjson_get_len(path); |
| 2272 | |
| 2273 | /* get required member: value, from */ |
| 2274 | switch (op_enum) { |
| 2275 | case PATCH_OP_ADD: case PATCH_OP_REPLACE: case PATCH_OP_TEST: |
| 2276 | value = yyjson_obj_get(obj, "value" ); |
| 2277 | if (unlikely(!value)) return_err_key("`value`" ); |
| 2278 | val = yyjson_val_mut_copy(doc, value); |
| 2279 | if (unlikely(!val)) return_err_copy(); |
| 2280 | break; |
| 2281 | case PATCH_OP_MOVE: case PATCH_OP_COPY: |
| 2282 | from = yyjson_obj_get(obj, "from" ); |
| 2283 | if (unlikely(!from)) return_err_key("`from`" ); |
| 2284 | if (unlikely(!yyjson_is_str(from))) return_err_val("`from`" ); |
| 2285 | from_len = unsafe_yyjson_get_len(from); |
| 2286 | break; |
| 2287 | default: |
| 2288 | break; |
| 2289 | } |
| 2290 | |
| 2291 | /* perform an operation */ |
| 2292 | switch (op_enum) { |
| 2293 | case PATCH_OP_ADD: /* add(path, val) */ |
| 2294 | if (unlikely(path_len == 0)) { root = val; break; } |
| 2295 | if (unlikely(!ptr_add(path, val))) { |
| 2296 | return_err(POINTER, "failed to add `path`" ); |
| 2297 | } |
| 2298 | break; |
| 2299 | case PATCH_OP_REMOVE: /* remove(path) */ |
| 2300 | if (unlikely(!ptr_remove(path))) { |
| 2301 | return_err(POINTER, "failed to remove `path`" ); |
| 2302 | } |
| 2303 | break; |
| 2304 | case PATCH_OP_REPLACE: /* replace(path, val) */ |
| 2305 | if (unlikely(path_len == 0)) { root = val; break; } |
| 2306 | if (unlikely(!ptr_replace(path, val))) { |
| 2307 | return_err(POINTER, "failed to replace `path`" ); |
| 2308 | } |
| 2309 | break; |
| 2310 | case PATCH_OP_MOVE: /* val = remove(from), add(path, val) */ |
| 2311 | if (unlikely(from_len == 0 && path_len == 0)) break; |
| 2312 | val = ptr_remove(from); |
| 2313 | if (unlikely(!val)) { |
| 2314 | return_err(POINTER, "failed to remove `from`" ); |
| 2315 | } |
| 2316 | if (unlikely(path_len == 0)) { root = val; break; } |
| 2317 | if (unlikely(!ptr_add(path, val))) { |
| 2318 | return_err(POINTER, "failed to add `path`" ); |
| 2319 | } |
| 2320 | break; |
| 2321 | case PATCH_OP_COPY: /* val = get(from).copy, add(path, val) */ |
| 2322 | val = ptr_get(from); |
| 2323 | if (unlikely(!val)) { |
| 2324 | return_err(POINTER, "failed to get `from`" ); |
| 2325 | } |
| 2326 | if (unlikely(path_len == 0)) { root = val; break; } |
| 2327 | val = yyjson_mut_val_mut_copy(doc, val); |
| 2328 | if (unlikely(!val)) return_err_copy(); |
| 2329 | if (unlikely(!ptr_add(path, val))) { |
| 2330 | return_err(POINTER, "failed to add `path`" ); |
| 2331 | } |
| 2332 | break; |
| 2333 | case PATCH_OP_TEST: /* test = get(path), test.eq(val) */ |
| 2334 | test = ptr_get(path); |
| 2335 | if (unlikely(!test)) { |
| 2336 | return_err(POINTER, "failed to get `path`" ); |
| 2337 | } |
| 2338 | if (unlikely(!yyjson_mut_equals(val, test))) { |
| 2339 | return_err(EQUAL, "failed to test equal" ); |
| 2340 | } |
| 2341 | break; |
| 2342 | default: |
| 2343 | return_err(INVALID_MEMBER, "unsupported `op`" ); |
| 2344 | } |
| 2345 | } |
| 2346 | return root; |
| 2347 | } |
| 2348 | |
| 2349 | yyjson_mut_val *yyjson_mut_patch(yyjson_mut_doc *doc, |
| 2350 | yyjson_mut_val *orig, |
| 2351 | yyjson_mut_val *patch, |
| 2352 | yyjson_patch_err *err) { |
| 2353 | yyjson_mut_val *root, *obj; |
| 2354 | yyjson_mut_arr_iter iter; |
| 2355 | yyjson_patch_err err_tmp; |
| 2356 | if (!err) err = &err_tmp; |
| 2357 | memset(err, 0, sizeof(*err)); |
| 2358 | memset(&iter, 0, sizeof(iter)); |
| 2359 | |
| 2360 | if (unlikely(!doc || !orig || !patch)) { |
| 2361 | return_err(INVALID_PARAMETER, "input parameter is NULL" ); |
| 2362 | } |
| 2363 | if (unlikely(!yyjson_mut_is_arr(patch))) { |
| 2364 | return_err(INVALID_PARAMETER, "input patch is not array" ); |
| 2365 | } |
| 2366 | root = yyjson_mut_val_mut_copy(doc, orig); |
| 2367 | if (unlikely(!root)) return_err_copy(); |
| 2368 | |
| 2369 | /* iterate through the patch array */ |
| 2370 | yyjson_mut_arr_iter_init(patch, &iter); |
| 2371 | while ((obj = yyjson_mut_arr_iter_next(&iter))) { |
| 2372 | patch_op op_enum; |
| 2373 | yyjson_mut_val *op, *path, *from = NULL, *value; |
| 2374 | yyjson_mut_val *val = NULL, *test; |
| 2375 | usize path_len, from_len = 0; |
| 2376 | if (!unsafe_yyjson_is_obj(obj)) { |
| 2377 | return_err(INVALID_OPERATION, "JSON patch operation is not object" ); |
| 2378 | } |
| 2379 | |
| 2380 | /* get required member: op */ |
| 2381 | op = yyjson_mut_obj_get(obj, "op" ); |
| 2382 | if (unlikely(!op)) return_err_key("`op`" ); |
| 2383 | if (unlikely(!yyjson_mut_is_str(op))) return_err_val("`op`" ); |
| 2384 | op_enum = patch_op_get((yyjson_val *)(void *)op); |
| 2385 | |
| 2386 | /* get required member: path */ |
| 2387 | path = yyjson_mut_obj_get(obj, "path" ); |
| 2388 | if (unlikely(!path)) return_err_key("`path`" ); |
| 2389 | if (unlikely(!yyjson_mut_is_str(path))) return_err_val("`path`" ); |
| 2390 | path_len = unsafe_yyjson_get_len(path); |
| 2391 | |
| 2392 | /* get required member: value, from */ |
| 2393 | switch (op_enum) { |
| 2394 | case PATCH_OP_ADD: case PATCH_OP_REPLACE: case PATCH_OP_TEST: |
| 2395 | value = yyjson_mut_obj_get(obj, "value" ); |
| 2396 | if (unlikely(!value)) return_err_key("`value`" ); |
| 2397 | val = yyjson_mut_val_mut_copy(doc, value); |
| 2398 | if (unlikely(!val)) return_err_copy(); |
| 2399 | break; |
| 2400 | case PATCH_OP_MOVE: case PATCH_OP_COPY: |
| 2401 | from = yyjson_mut_obj_get(obj, "from" ); |
| 2402 | if (unlikely(!from)) return_err_key("`from`" ); |
| 2403 | if (unlikely(!yyjson_mut_is_str(from))) { |
| 2404 | return_err_val("`from`" ); |
| 2405 | } |
| 2406 | from_len = unsafe_yyjson_get_len(from); |
| 2407 | break; |
| 2408 | default: |
| 2409 | break; |
| 2410 | } |
| 2411 | |
| 2412 | /* perform an operation */ |
| 2413 | switch (op_enum) { |
| 2414 | case PATCH_OP_ADD: /* add(path, val) */ |
| 2415 | if (unlikely(path_len == 0)) { root = val; break; } |
| 2416 | if (unlikely(!ptr_add(path, val))) { |
| 2417 | return_err(POINTER, "failed to add `path`" ); |
| 2418 | } |
| 2419 | break; |
| 2420 | case PATCH_OP_REMOVE: /* remove(path) */ |
| 2421 | if (unlikely(!ptr_remove(path))) { |
| 2422 | return_err(POINTER, "failed to remove `path`" ); |
| 2423 | } |
| 2424 | break; |
| 2425 | case PATCH_OP_REPLACE: /* replace(path, val) */ |
| 2426 | if (unlikely(path_len == 0)) { root = val; break; } |
| 2427 | if (unlikely(!ptr_replace(path, val))) { |
| 2428 | return_err(POINTER, "failed to replace `path`" ); |
| 2429 | } |
| 2430 | break; |
| 2431 | case PATCH_OP_MOVE: /* val = remove(from), add(path, val) */ |
| 2432 | if (unlikely(from_len == 0 && path_len == 0)) break; |
| 2433 | val = ptr_remove(from); |
| 2434 | if (unlikely(!val)) { |
| 2435 | return_err(POINTER, "failed to remove `from`" ); |
| 2436 | } |
| 2437 | if (unlikely(path_len == 0)) { root = val; break; } |
| 2438 | if (unlikely(!ptr_add(path, val))) { |
| 2439 | return_err(POINTER, "failed to add `path`" ); |
| 2440 | } |
| 2441 | break; |
| 2442 | case PATCH_OP_COPY: /* val = get(from).copy, add(path, val) */ |
| 2443 | val = ptr_get(from); |
| 2444 | if (unlikely(!val)) { |
| 2445 | return_err(POINTER, "failed to get `from`" ); |
| 2446 | } |
| 2447 | if (unlikely(path_len == 0)) { root = val; break; } |
| 2448 | val = yyjson_mut_val_mut_copy(doc, val); |
| 2449 | if (unlikely(!val)) return_err_copy(); |
| 2450 | if (unlikely(!ptr_add(path, val))) { |
| 2451 | return_err(POINTER, "failed to add `path`" ); |
| 2452 | } |
| 2453 | break; |
| 2454 | case PATCH_OP_TEST: /* test = get(path), test.eq(val) */ |
| 2455 | test = ptr_get(path); |
| 2456 | if (unlikely(!test)) { |
| 2457 | return_err(POINTER, "failed to get `path`" ); |
| 2458 | } |
| 2459 | if (unlikely(!yyjson_mut_equals(val, test))) { |
| 2460 | return_err(EQUAL, "failed to test equal" ); |
| 2461 | } |
| 2462 | break; |
| 2463 | default: |
| 2464 | return_err(INVALID_MEMBER, "unsupported `op`" ); |
| 2465 | } |
| 2466 | } |
| 2467 | return root; |
| 2468 | } |
| 2469 | |
| 2470 | /* macros for yyjson_patch */ |
| 2471 | #undef return_err |
| 2472 | #undef return_err_copy |
| 2473 | #undef return_err_key |
| 2474 | #undef return_err_val |
| 2475 | #undef ptr_get |
| 2476 | #undef ptr_add |
| 2477 | #undef ptr_remove |
| 2478 | #undef ptr_replace |
| 2479 | |
| 2480 | |
| 2481 | |
| 2482 | /*============================================================================== |
| 2483 | * JSON Merge-Patch API (RFC 7386) |
| 2484 | *============================================================================*/ |
| 2485 | |
| 2486 | yyjson_mut_val *yyjson_merge_patch(yyjson_mut_doc *doc, |
| 2487 | yyjson_val *orig, |
| 2488 | yyjson_val *patch) { |
| 2489 | usize idx, max; |
| 2490 | yyjson_val *key, *orig_val, *patch_val, local_orig; |
| 2491 | yyjson_mut_val *builder, *mut_key, *mut_val, *merged_val; |
| 2492 | |
| 2493 | if (unlikely(!yyjson_is_obj(patch))) { |
| 2494 | return yyjson_val_mut_copy(doc, patch); |
| 2495 | } |
| 2496 | |
| 2497 | builder = yyjson_mut_obj(doc); |
| 2498 | if (unlikely(!builder)) return NULL; |
| 2499 | |
| 2500 | if (!yyjson_is_obj(orig)) { |
| 2501 | orig = &local_orig; |
| 2502 | orig->tag = builder->tag; |
| 2503 | orig->uni = builder->uni; |
| 2504 | } |
| 2505 | |
| 2506 | /* If orig is contributing, copy any items not modified by the patch */ |
| 2507 | if (orig != &local_orig) { |
| 2508 | yyjson_obj_foreach(orig, idx, max, key, orig_val) { |
| 2509 | patch_val = yyjson_obj_getn(patch, |
| 2510 | unsafe_yyjson_get_str(key), |
| 2511 | unsafe_yyjson_get_len(key)); |
| 2512 | if (!patch_val) { |
| 2513 | mut_key = yyjson_val_mut_copy(doc, key); |
| 2514 | mut_val = yyjson_val_mut_copy(doc, orig_val); |
| 2515 | if (!yyjson_mut_obj_add(builder, mut_key, mut_val)) return NULL; |
| 2516 | } |
| 2517 | } |
| 2518 | } |
| 2519 | |
| 2520 | /* Merge items modified by the patch. */ |
| 2521 | yyjson_obj_foreach(patch, idx, max, key, patch_val) { |
| 2522 | /* null indicates the field is removed. */ |
| 2523 | if (unsafe_yyjson_is_null(patch_val)) { |
| 2524 | continue; |
| 2525 | } |
| 2526 | mut_key = yyjson_val_mut_copy(doc, key); |
| 2527 | orig_val = yyjson_obj_getn(orig, |
| 2528 | unsafe_yyjson_get_str(key), |
| 2529 | unsafe_yyjson_get_len(key)); |
| 2530 | merged_val = yyjson_merge_patch(doc, orig_val, patch_val); |
| 2531 | if (!yyjson_mut_obj_add(builder, mut_key, merged_val)) return NULL; |
| 2532 | } |
| 2533 | |
| 2534 | return builder; |
| 2535 | } |
| 2536 | |
| 2537 | yyjson_mut_val *yyjson_mut_merge_patch(yyjson_mut_doc *doc, |
| 2538 | yyjson_mut_val *orig, |
| 2539 | yyjson_mut_val *patch) { |
| 2540 | usize idx, max; |
| 2541 | yyjson_mut_val *key, *orig_val, *patch_val, local_orig; |
| 2542 | yyjson_mut_val *builder, *mut_key, *mut_val, *merged_val; |
| 2543 | |
| 2544 | if (unlikely(!yyjson_mut_is_obj(patch))) { |
| 2545 | return yyjson_mut_val_mut_copy(doc, patch); |
| 2546 | } |
| 2547 | |
| 2548 | builder = yyjson_mut_obj(doc); |
| 2549 | if (unlikely(!builder)) return NULL; |
| 2550 | |
| 2551 | if (!yyjson_mut_is_obj(orig)) { |
| 2552 | orig = &local_orig; |
| 2553 | orig->tag = builder->tag; |
| 2554 | orig->uni = builder->uni; |
| 2555 | } |
| 2556 | |
| 2557 | /* If orig is contributing, copy any items not modified by the patch */ |
| 2558 | if (orig != &local_orig) { |
| 2559 | yyjson_mut_obj_foreach(orig, idx, max, key, orig_val) { |
| 2560 | patch_val = yyjson_mut_obj_getn(patch, |
| 2561 | unsafe_yyjson_get_str(key), |
| 2562 | unsafe_yyjson_get_len(key)); |
| 2563 | if (!patch_val) { |
| 2564 | mut_key = yyjson_mut_val_mut_copy(doc, key); |
| 2565 | mut_val = yyjson_mut_val_mut_copy(doc, orig_val); |
| 2566 | if (!yyjson_mut_obj_add(builder, mut_key, mut_val)) return NULL; |
| 2567 | } |
| 2568 | } |
| 2569 | } |
| 2570 | |
| 2571 | /* Merge items modified by the patch. */ |
| 2572 | yyjson_mut_obj_foreach(patch, idx, max, key, patch_val) { |
| 2573 | /* null indicates the field is removed. */ |
| 2574 | if (unsafe_yyjson_is_null(patch_val)) { |
| 2575 | continue; |
| 2576 | } |
| 2577 | mut_key = yyjson_mut_val_mut_copy(doc, key); |
| 2578 | orig_val = yyjson_mut_obj_getn(orig, |
| 2579 | unsafe_yyjson_get_str(key), |
| 2580 | unsafe_yyjson_get_len(key)); |
| 2581 | merged_val = yyjson_mut_merge_patch(doc, orig_val, patch_val); |
| 2582 | if (!yyjson_mut_obj_add(builder, mut_key, merged_val)) return NULL; |
| 2583 | } |
| 2584 | |
| 2585 | return builder; |
| 2586 | } |
| 2587 | |
| 2588 | #endif /* YYJSON_DISABLE_UTILS */ |
| 2589 | |
| 2590 | |
| 2591 | |
| 2592 | /*============================================================================== |
| 2593 | * Power10 Lookup Table |
| 2594 | * These data are used by the floating-point number reader and writer. |
| 2595 | *============================================================================*/ |
| 2596 | |
| 2597 | #if (!YYJSON_DISABLE_READER || !YYJSON_DISABLE_WRITER) && \ |
| 2598 | (!YYJSON_DISABLE_FAST_FP_CONV) |
| 2599 | |
| 2600 | /** Minimum decimal exponent in pow10_sig_table. */ |
| 2601 | #define POW10_SIG_TABLE_MIN_EXP -343 |
| 2602 | |
| 2603 | /** Maximum decimal exponent in pow10_sig_table. */ |
| 2604 | #define POW10_SIG_TABLE_MAX_EXP 324 |
| 2605 | |
| 2606 | /** Minimum exact decimal exponent in pow10_sig_table */ |
| 2607 | #define POW10_SIG_TABLE_MIN_EXACT_EXP 0 |
| 2608 | |
| 2609 | /** Maximum exact decimal exponent in pow10_sig_table */ |
| 2610 | #define POW10_SIG_TABLE_MAX_EXACT_EXP 55 |
| 2611 | |
| 2612 | /** Normalized significant 128 bits of pow10, no rounded up (size: 10.4KB). |
| 2613 | This lookup table is used by both the double number reader and writer. |
| 2614 | (generate with misc/make_tables.c) */ |
| 2615 | static const u64 pow10_sig_table[] = { |
| 2616 | U64(0xBF29DCAB, 0xA82FDEAE), U64(0x7432EE87, 0x3880FC33), /* ~= 10^-343 */ |
| 2617 | U64(0xEEF453D6, 0x923BD65A), U64(0x113FAA29, 0x06A13B3F), /* ~= 10^-342 */ |
| 2618 | U64(0x9558B466, 0x1B6565F8), U64(0x4AC7CA59, 0xA424C507), /* ~= 10^-341 */ |
| 2619 | U64(0xBAAEE17F, 0xA23EBF76), U64(0x5D79BCF0, 0x0D2DF649), /* ~= 10^-340 */ |
| 2620 | U64(0xE95A99DF, 0x8ACE6F53), U64(0xF4D82C2C, 0x107973DC), /* ~= 10^-339 */ |
| 2621 | U64(0x91D8A02B, 0xB6C10594), U64(0x79071B9B, 0x8A4BE869), /* ~= 10^-338 */ |
| 2622 | U64(0xB64EC836, 0xA47146F9), U64(0x9748E282, 0x6CDEE284), /* ~= 10^-337 */ |
| 2623 | U64(0xE3E27A44, 0x4D8D98B7), U64(0xFD1B1B23, 0x08169B25), /* ~= 10^-336 */ |
| 2624 | U64(0x8E6D8C6A, 0xB0787F72), U64(0xFE30F0F5, 0xE50E20F7), /* ~= 10^-335 */ |
| 2625 | U64(0xB208EF85, 0x5C969F4F), U64(0xBDBD2D33, 0x5E51A935), /* ~= 10^-334 */ |
| 2626 | U64(0xDE8B2B66, 0xB3BC4723), U64(0xAD2C7880, 0x35E61382), /* ~= 10^-333 */ |
| 2627 | U64(0x8B16FB20, 0x3055AC76), U64(0x4C3BCB50, 0x21AFCC31), /* ~= 10^-332 */ |
| 2628 | U64(0xADDCB9E8, 0x3C6B1793), U64(0xDF4ABE24, 0x2A1BBF3D), /* ~= 10^-331 */ |
| 2629 | U64(0xD953E862, 0x4B85DD78), U64(0xD71D6DAD, 0x34A2AF0D), /* ~= 10^-330 */ |
| 2630 | U64(0x87D4713D, 0x6F33AA6B), U64(0x8672648C, 0x40E5AD68), /* ~= 10^-329 */ |
| 2631 | U64(0xA9C98D8C, 0xCB009506), U64(0x680EFDAF, 0x511F18C2), /* ~= 10^-328 */ |
| 2632 | U64(0xD43BF0EF, 0xFDC0BA48), U64(0x0212BD1B, 0x2566DEF2), /* ~= 10^-327 */ |
| 2633 | U64(0x84A57695, 0xFE98746D), U64(0x014BB630, 0xF7604B57), /* ~= 10^-326 */ |
| 2634 | U64(0xA5CED43B, 0x7E3E9188), U64(0x419EA3BD, 0x35385E2D), /* ~= 10^-325 */ |
| 2635 | U64(0xCF42894A, 0x5DCE35EA), U64(0x52064CAC, 0x828675B9), /* ~= 10^-324 */ |
| 2636 | U64(0x818995CE, 0x7AA0E1B2), U64(0x7343EFEB, 0xD1940993), /* ~= 10^-323 */ |
| 2637 | U64(0xA1EBFB42, 0x19491A1F), U64(0x1014EBE6, 0xC5F90BF8), /* ~= 10^-322 */ |
| 2638 | U64(0xCA66FA12, 0x9F9B60A6), U64(0xD41A26E0, 0x77774EF6), /* ~= 10^-321 */ |
| 2639 | U64(0xFD00B897, 0x478238D0), U64(0x8920B098, 0x955522B4), /* ~= 10^-320 */ |
| 2640 | U64(0x9E20735E, 0x8CB16382), U64(0x55B46E5F, 0x5D5535B0), /* ~= 10^-319 */ |
| 2641 | U64(0xC5A89036, 0x2FDDBC62), U64(0xEB2189F7, 0x34AA831D), /* ~= 10^-318 */ |
| 2642 | U64(0xF712B443, 0xBBD52B7B), U64(0xA5E9EC75, 0x01D523E4), /* ~= 10^-317 */ |
| 2643 | U64(0x9A6BB0AA, 0x55653B2D), U64(0x47B233C9, 0x2125366E), /* ~= 10^-316 */ |
| 2644 | U64(0xC1069CD4, 0xEABE89F8), U64(0x999EC0BB, 0x696E840A), /* ~= 10^-315 */ |
| 2645 | U64(0xF148440A, 0x256E2C76), U64(0xC00670EA, 0x43CA250D), /* ~= 10^-314 */ |
| 2646 | U64(0x96CD2A86, 0x5764DBCA), U64(0x38040692, 0x6A5E5728), /* ~= 10^-313 */ |
| 2647 | U64(0xBC807527, 0xED3E12BC), U64(0xC6050837, 0x04F5ECF2), /* ~= 10^-312 */ |
| 2648 | U64(0xEBA09271, 0xE88D976B), U64(0xF7864A44, 0xC633682E), /* ~= 10^-311 */ |
| 2649 | U64(0x93445B87, 0x31587EA3), U64(0x7AB3EE6A, 0xFBE0211D), /* ~= 10^-310 */ |
| 2650 | U64(0xB8157268, 0xFDAE9E4C), U64(0x5960EA05, 0xBAD82964), /* ~= 10^-309 */ |
| 2651 | U64(0xE61ACF03, 0x3D1A45DF), U64(0x6FB92487, 0x298E33BD), /* ~= 10^-308 */ |
| 2652 | U64(0x8FD0C162, 0x06306BAB), U64(0xA5D3B6D4, 0x79F8E056), /* ~= 10^-307 */ |
| 2653 | U64(0xB3C4F1BA, 0x87BC8696), U64(0x8F48A489, 0x9877186C), /* ~= 10^-306 */ |
| 2654 | U64(0xE0B62E29, 0x29ABA83C), U64(0x331ACDAB, 0xFE94DE87), /* ~= 10^-305 */ |
| 2655 | U64(0x8C71DCD9, 0xBA0B4925), U64(0x9FF0C08B, 0x7F1D0B14), /* ~= 10^-304 */ |
| 2656 | U64(0xAF8E5410, 0x288E1B6F), U64(0x07ECF0AE, 0x5EE44DD9), /* ~= 10^-303 */ |
| 2657 | U64(0xDB71E914, 0x32B1A24A), U64(0xC9E82CD9, 0xF69D6150), /* ~= 10^-302 */ |
| 2658 | U64(0x892731AC, 0x9FAF056E), U64(0xBE311C08, 0x3A225CD2), /* ~= 10^-301 */ |
| 2659 | U64(0xAB70FE17, 0xC79AC6CA), U64(0x6DBD630A, 0x48AAF406), /* ~= 10^-300 */ |
| 2660 | U64(0xD64D3D9D, 0xB981787D), U64(0x092CBBCC, 0xDAD5B108), /* ~= 10^-299 */ |
| 2661 | U64(0x85F04682, 0x93F0EB4E), U64(0x25BBF560, 0x08C58EA5), /* ~= 10^-298 */ |
| 2662 | U64(0xA76C5823, 0x38ED2621), U64(0xAF2AF2B8, 0x0AF6F24E), /* ~= 10^-297 */ |
| 2663 | U64(0xD1476E2C, 0x07286FAA), U64(0x1AF5AF66, 0x0DB4AEE1), /* ~= 10^-296 */ |
| 2664 | U64(0x82CCA4DB, 0x847945CA), U64(0x50D98D9F, 0xC890ED4D), /* ~= 10^-295 */ |
| 2665 | U64(0xA37FCE12, 0x6597973C), U64(0xE50FF107, 0xBAB528A0), /* ~= 10^-294 */ |
| 2666 | U64(0xCC5FC196, 0xFEFD7D0C), U64(0x1E53ED49, 0xA96272C8), /* ~= 10^-293 */ |
| 2667 | U64(0xFF77B1FC, 0xBEBCDC4F), U64(0x25E8E89C, 0x13BB0F7A), /* ~= 10^-292 */ |
| 2668 | U64(0x9FAACF3D, 0xF73609B1), U64(0x77B19161, 0x8C54E9AC), /* ~= 10^-291 */ |
| 2669 | U64(0xC795830D, 0x75038C1D), U64(0xD59DF5B9, 0xEF6A2417), /* ~= 10^-290 */ |
| 2670 | U64(0xF97AE3D0, 0xD2446F25), U64(0x4B057328, 0x6B44AD1D), /* ~= 10^-289 */ |
| 2671 | U64(0x9BECCE62, 0x836AC577), U64(0x4EE367F9, 0x430AEC32), /* ~= 10^-288 */ |
| 2672 | U64(0xC2E801FB, 0x244576D5), U64(0x229C41F7, 0x93CDA73F), /* ~= 10^-287 */ |
| 2673 | U64(0xF3A20279, 0xED56D48A), U64(0x6B435275, 0x78C1110F), /* ~= 10^-286 */ |
| 2674 | U64(0x9845418C, 0x345644D6), U64(0x830A1389, 0x6B78AAA9), /* ~= 10^-285 */ |
| 2675 | U64(0xBE5691EF, 0x416BD60C), U64(0x23CC986B, 0xC656D553), /* ~= 10^-284 */ |
| 2676 | U64(0xEDEC366B, 0x11C6CB8F), U64(0x2CBFBE86, 0xB7EC8AA8), /* ~= 10^-283 */ |
| 2677 | U64(0x94B3A202, 0xEB1C3F39), U64(0x7BF7D714, 0x32F3D6A9), /* ~= 10^-282 */ |
| 2678 | U64(0xB9E08A83, 0xA5E34F07), U64(0xDAF5CCD9, 0x3FB0CC53), /* ~= 10^-281 */ |
| 2679 | U64(0xE858AD24, 0x8F5C22C9), U64(0xD1B3400F, 0x8F9CFF68), /* ~= 10^-280 */ |
| 2680 | U64(0x91376C36, 0xD99995BE), U64(0x23100809, 0xB9C21FA1), /* ~= 10^-279 */ |
| 2681 | U64(0xB5854744, 0x8FFFFB2D), U64(0xABD40A0C, 0x2832A78A), /* ~= 10^-278 */ |
| 2682 | U64(0xE2E69915, 0xB3FFF9F9), U64(0x16C90C8F, 0x323F516C), /* ~= 10^-277 */ |
| 2683 | U64(0x8DD01FAD, 0x907FFC3B), U64(0xAE3DA7D9, 0x7F6792E3), /* ~= 10^-276 */ |
| 2684 | U64(0xB1442798, 0xF49FFB4A), U64(0x99CD11CF, 0xDF41779C), /* ~= 10^-275 */ |
| 2685 | U64(0xDD95317F, 0x31C7FA1D), U64(0x40405643, 0xD711D583), /* ~= 10^-274 */ |
| 2686 | U64(0x8A7D3EEF, 0x7F1CFC52), U64(0x482835EA, 0x666B2572), /* ~= 10^-273 */ |
| 2687 | U64(0xAD1C8EAB, 0x5EE43B66), U64(0xDA324365, 0x0005EECF), /* ~= 10^-272 */ |
| 2688 | U64(0xD863B256, 0x369D4A40), U64(0x90BED43E, 0x40076A82), /* ~= 10^-271 */ |
| 2689 | U64(0x873E4F75, 0xE2224E68), U64(0x5A7744A6, 0xE804A291), /* ~= 10^-270 */ |
| 2690 | U64(0xA90DE353, 0x5AAAE202), U64(0x711515D0, 0xA205CB36), /* ~= 10^-269 */ |
| 2691 | U64(0xD3515C28, 0x31559A83), U64(0x0D5A5B44, 0xCA873E03), /* ~= 10^-268 */ |
| 2692 | U64(0x8412D999, 0x1ED58091), U64(0xE858790A, 0xFE9486C2), /* ~= 10^-267 */ |
| 2693 | U64(0xA5178FFF, 0x668AE0B6), U64(0x626E974D, 0xBE39A872), /* ~= 10^-266 */ |
| 2694 | U64(0xCE5D73FF, 0x402D98E3), U64(0xFB0A3D21, 0x2DC8128F), /* ~= 10^-265 */ |
| 2695 | U64(0x80FA687F, 0x881C7F8E), U64(0x7CE66634, 0xBC9D0B99), /* ~= 10^-264 */ |
| 2696 | U64(0xA139029F, 0x6A239F72), U64(0x1C1FFFC1, 0xEBC44E80), /* ~= 10^-263 */ |
| 2697 | U64(0xC9874347, 0x44AC874E), U64(0xA327FFB2, 0x66B56220), /* ~= 10^-262 */ |
| 2698 | U64(0xFBE91419, 0x15D7A922), U64(0x4BF1FF9F, 0x0062BAA8), /* ~= 10^-261 */ |
| 2699 | U64(0x9D71AC8F, 0xADA6C9B5), U64(0x6F773FC3, 0x603DB4A9), /* ~= 10^-260 */ |
| 2700 | U64(0xC4CE17B3, 0x99107C22), U64(0xCB550FB4, 0x384D21D3), /* ~= 10^-259 */ |
| 2701 | U64(0xF6019DA0, 0x7F549B2B), U64(0x7E2A53A1, 0x46606A48), /* ~= 10^-258 */ |
| 2702 | U64(0x99C10284, 0x4F94E0FB), U64(0x2EDA7444, 0xCBFC426D), /* ~= 10^-257 */ |
| 2703 | U64(0xC0314325, 0x637A1939), U64(0xFA911155, 0xFEFB5308), /* ~= 10^-256 */ |
| 2704 | U64(0xF03D93EE, 0xBC589F88), U64(0x793555AB, 0x7EBA27CA), /* ~= 10^-255 */ |
| 2705 | U64(0x96267C75, 0x35B763B5), U64(0x4BC1558B, 0x2F3458DE), /* ~= 10^-254 */ |
| 2706 | U64(0xBBB01B92, 0x83253CA2), U64(0x9EB1AAED, 0xFB016F16), /* ~= 10^-253 */ |
| 2707 | U64(0xEA9C2277, 0x23EE8BCB), U64(0x465E15A9, 0x79C1CADC), /* ~= 10^-252 */ |
| 2708 | U64(0x92A1958A, 0x7675175F), U64(0x0BFACD89, 0xEC191EC9), /* ~= 10^-251 */ |
| 2709 | U64(0xB749FAED, 0x14125D36), U64(0xCEF980EC, 0x671F667B), /* ~= 10^-250 */ |
| 2710 | U64(0xE51C79A8, 0x5916F484), U64(0x82B7E127, 0x80E7401A), /* ~= 10^-249 */ |
| 2711 | U64(0x8F31CC09, 0x37AE58D2), U64(0xD1B2ECB8, 0xB0908810), /* ~= 10^-248 */ |
| 2712 | U64(0xB2FE3F0B, 0x8599EF07), U64(0x861FA7E6, 0xDCB4AA15), /* ~= 10^-247 */ |
| 2713 | U64(0xDFBDCECE, 0x67006AC9), U64(0x67A791E0, 0x93E1D49A), /* ~= 10^-246 */ |
| 2714 | U64(0x8BD6A141, 0x006042BD), U64(0xE0C8BB2C, 0x5C6D24E0), /* ~= 10^-245 */ |
| 2715 | U64(0xAECC4991, 0x4078536D), U64(0x58FAE9F7, 0x73886E18), /* ~= 10^-244 */ |
| 2716 | U64(0xDA7F5BF5, 0x90966848), U64(0xAF39A475, 0x506A899E), /* ~= 10^-243 */ |
| 2717 | U64(0x888F9979, 0x7A5E012D), U64(0x6D8406C9, 0x52429603), /* ~= 10^-242 */ |
| 2718 | U64(0xAAB37FD7, 0xD8F58178), U64(0xC8E5087B, 0xA6D33B83), /* ~= 10^-241 */ |
| 2719 | U64(0xD5605FCD, 0xCF32E1D6), U64(0xFB1E4A9A, 0x90880A64), /* ~= 10^-240 */ |
| 2720 | U64(0x855C3BE0, 0xA17FCD26), U64(0x5CF2EEA0, 0x9A55067F), /* ~= 10^-239 */ |
| 2721 | U64(0xA6B34AD8, 0xC9DFC06F), U64(0xF42FAA48, 0xC0EA481E), /* ~= 10^-238 */ |
| 2722 | U64(0xD0601D8E, 0xFC57B08B), U64(0xF13B94DA, 0xF124DA26), /* ~= 10^-237 */ |
| 2723 | U64(0x823C1279, 0x5DB6CE57), U64(0x76C53D08, 0xD6B70858), /* ~= 10^-236 */ |
| 2724 | U64(0xA2CB1717, 0xB52481ED), U64(0x54768C4B, 0x0C64CA6E), /* ~= 10^-235 */ |
| 2725 | U64(0xCB7DDCDD, 0xA26DA268), U64(0xA9942F5D, 0xCF7DFD09), /* ~= 10^-234 */ |
| 2726 | U64(0xFE5D5415, 0x0B090B02), U64(0xD3F93B35, 0x435D7C4C), /* ~= 10^-233 */ |
| 2727 | U64(0x9EFA548D, 0x26E5A6E1), U64(0xC47BC501, 0x4A1A6DAF), /* ~= 10^-232 */ |
| 2728 | U64(0xC6B8E9B0, 0x709F109A), U64(0x359AB641, 0x9CA1091B), /* ~= 10^-231 */ |
| 2729 | U64(0xF867241C, 0x8CC6D4C0), U64(0xC30163D2, 0x03C94B62), /* ~= 10^-230 */ |
| 2730 | U64(0x9B407691, 0xD7FC44F8), U64(0x79E0DE63, 0x425DCF1D), /* ~= 10^-229 */ |
| 2731 | U64(0xC2109436, 0x4DFB5636), U64(0x985915FC, 0x12F542E4), /* ~= 10^-228 */ |
| 2732 | U64(0xF294B943, 0xE17A2BC4), U64(0x3E6F5B7B, 0x17B2939D), /* ~= 10^-227 */ |
| 2733 | U64(0x979CF3CA, 0x6CEC5B5A), U64(0xA705992C, 0xEECF9C42), /* ~= 10^-226 */ |
| 2734 | U64(0xBD8430BD, 0x08277231), U64(0x50C6FF78, 0x2A838353), /* ~= 10^-225 */ |
| 2735 | U64(0xECE53CEC, 0x4A314EBD), U64(0xA4F8BF56, 0x35246428), /* ~= 10^-224 */ |
| 2736 | U64(0x940F4613, 0xAE5ED136), U64(0x871B7795, 0xE136BE99), /* ~= 10^-223 */ |
| 2737 | U64(0xB9131798, 0x99F68584), U64(0x28E2557B, 0x59846E3F), /* ~= 10^-222 */ |
| 2738 | U64(0xE757DD7E, 0xC07426E5), U64(0x331AEADA, 0x2FE589CF), /* ~= 10^-221 */ |
| 2739 | U64(0x9096EA6F, 0x3848984F), U64(0x3FF0D2C8, 0x5DEF7621), /* ~= 10^-220 */ |
| 2740 | U64(0xB4BCA50B, 0x065ABE63), U64(0x0FED077A, 0x756B53A9), /* ~= 10^-219 */ |
| 2741 | U64(0xE1EBCE4D, 0xC7F16DFB), U64(0xD3E84959, 0x12C62894), /* ~= 10^-218 */ |
| 2742 | U64(0x8D3360F0, 0x9CF6E4BD), U64(0x64712DD7, 0xABBBD95C), /* ~= 10^-217 */ |
| 2743 | U64(0xB080392C, 0xC4349DEC), U64(0xBD8D794D, 0x96AACFB3), /* ~= 10^-216 */ |
| 2744 | U64(0xDCA04777, 0xF541C567), U64(0xECF0D7A0, 0xFC5583A0), /* ~= 10^-215 */ |
| 2745 | U64(0x89E42CAA, 0xF9491B60), U64(0xF41686C4, 0x9DB57244), /* ~= 10^-214 */ |
| 2746 | U64(0xAC5D37D5, 0xB79B6239), U64(0x311C2875, 0xC522CED5), /* ~= 10^-213 */ |
| 2747 | U64(0xD77485CB, 0x25823AC7), U64(0x7D633293, 0x366B828B), /* ~= 10^-212 */ |
| 2748 | U64(0x86A8D39E, 0xF77164BC), U64(0xAE5DFF9C, 0x02033197), /* ~= 10^-211 */ |
| 2749 | U64(0xA8530886, 0xB54DBDEB), U64(0xD9F57F83, 0x0283FDFC), /* ~= 10^-210 */ |
| 2750 | U64(0xD267CAA8, 0x62A12D66), U64(0xD072DF63, 0xC324FD7B), /* ~= 10^-209 */ |
| 2751 | U64(0x8380DEA9, 0x3DA4BC60), U64(0x4247CB9E, 0x59F71E6D), /* ~= 10^-208 */ |
| 2752 | U64(0xA4611653, 0x8D0DEB78), U64(0x52D9BE85, 0xF074E608), /* ~= 10^-207 */ |
| 2753 | U64(0xCD795BE8, 0x70516656), U64(0x67902E27, 0x6C921F8B), /* ~= 10^-206 */ |
| 2754 | U64(0x806BD971, 0x4632DFF6), U64(0x00BA1CD8, 0xA3DB53B6), /* ~= 10^-205 */ |
| 2755 | U64(0xA086CFCD, 0x97BF97F3), U64(0x80E8A40E, 0xCCD228A4), /* ~= 10^-204 */ |
| 2756 | U64(0xC8A883C0, 0xFDAF7DF0), U64(0x6122CD12, 0x8006B2CD), /* ~= 10^-203 */ |
| 2757 | U64(0xFAD2A4B1, 0x3D1B5D6C), U64(0x796B8057, 0x20085F81), /* ~= 10^-202 */ |
| 2758 | U64(0x9CC3A6EE, 0xC6311A63), U64(0xCBE33036, 0x74053BB0), /* ~= 10^-201 */ |
| 2759 | U64(0xC3F490AA, 0x77BD60FC), U64(0xBEDBFC44, 0x11068A9C), /* ~= 10^-200 */ |
| 2760 | U64(0xF4F1B4D5, 0x15ACB93B), U64(0xEE92FB55, 0x15482D44), /* ~= 10^-199 */ |
| 2761 | U64(0x99171105, 0x2D8BF3C5), U64(0x751BDD15, 0x2D4D1C4A), /* ~= 10^-198 */ |
| 2762 | U64(0xBF5CD546, 0x78EEF0B6), U64(0xD262D45A, 0x78A0635D), /* ~= 10^-197 */ |
| 2763 | U64(0xEF340A98, 0x172AACE4), U64(0x86FB8971, 0x16C87C34), /* ~= 10^-196 */ |
| 2764 | U64(0x9580869F, 0x0E7AAC0E), U64(0xD45D35E6, 0xAE3D4DA0), /* ~= 10^-195 */ |
| 2765 | U64(0xBAE0A846, 0xD2195712), U64(0x89748360, 0x59CCA109), /* ~= 10^-194 */ |
| 2766 | U64(0xE998D258, 0x869FACD7), U64(0x2BD1A438, 0x703FC94B), /* ~= 10^-193 */ |
| 2767 | U64(0x91FF8377, 0x5423CC06), U64(0x7B6306A3, 0x4627DDCF), /* ~= 10^-192 */ |
| 2768 | U64(0xB67F6455, 0x292CBF08), U64(0x1A3BC84C, 0x17B1D542), /* ~= 10^-191 */ |
| 2769 | U64(0xE41F3D6A, 0x7377EECA), U64(0x20CABA5F, 0x1D9E4A93), /* ~= 10^-190 */ |
| 2770 | U64(0x8E938662, 0x882AF53E), U64(0x547EB47B, 0x7282EE9C), /* ~= 10^-189 */ |
| 2771 | U64(0xB23867FB, 0x2A35B28D), U64(0xE99E619A, 0x4F23AA43), /* ~= 10^-188 */ |
| 2772 | U64(0xDEC681F9, 0xF4C31F31), U64(0x6405FA00, 0xE2EC94D4), /* ~= 10^-187 */ |
| 2773 | U64(0x8B3C113C, 0x38F9F37E), U64(0xDE83BC40, 0x8DD3DD04), /* ~= 10^-186 */ |
| 2774 | U64(0xAE0B158B, 0x4738705E), U64(0x9624AB50, 0xB148D445), /* ~= 10^-185 */ |
| 2775 | U64(0xD98DDAEE, 0x19068C76), U64(0x3BADD624, 0xDD9B0957), /* ~= 10^-184 */ |
| 2776 | U64(0x87F8A8D4, 0xCFA417C9), U64(0xE54CA5D7, 0x0A80E5D6), /* ~= 10^-183 */ |
| 2777 | U64(0xA9F6D30A, 0x038D1DBC), U64(0x5E9FCF4C, 0xCD211F4C), /* ~= 10^-182 */ |
| 2778 | U64(0xD47487CC, 0x8470652B), U64(0x7647C320, 0x0069671F), /* ~= 10^-181 */ |
| 2779 | U64(0x84C8D4DF, 0xD2C63F3B), U64(0x29ECD9F4, 0x0041E073), /* ~= 10^-180 */ |
| 2780 | U64(0xA5FB0A17, 0xC777CF09), U64(0xF4681071, 0x00525890), /* ~= 10^-179 */ |
| 2781 | U64(0xCF79CC9D, 0xB955C2CC), U64(0x7182148D, 0x4066EEB4), /* ~= 10^-178 */ |
| 2782 | U64(0x81AC1FE2, 0x93D599BF), U64(0xC6F14CD8, 0x48405530), /* ~= 10^-177 */ |
| 2783 | U64(0xA21727DB, 0x38CB002F), U64(0xB8ADA00E, 0x5A506A7C), /* ~= 10^-176 */ |
| 2784 | U64(0xCA9CF1D2, 0x06FDC03B), U64(0xA6D90811, 0xF0E4851C), /* ~= 10^-175 */ |
| 2785 | U64(0xFD442E46, 0x88BD304A), U64(0x908F4A16, 0x6D1DA663), /* ~= 10^-174 */ |
| 2786 | U64(0x9E4A9CEC, 0x15763E2E), U64(0x9A598E4E, 0x043287FE), /* ~= 10^-173 */ |
| 2787 | U64(0xC5DD4427, 0x1AD3CDBA), U64(0x40EFF1E1, 0x853F29FD), /* ~= 10^-172 */ |
| 2788 | U64(0xF7549530, 0xE188C128), U64(0xD12BEE59, 0xE68EF47C), /* ~= 10^-171 */ |
| 2789 | U64(0x9A94DD3E, 0x8CF578B9), U64(0x82BB74F8, 0x301958CE), /* ~= 10^-170 */ |
| 2790 | U64(0xC13A148E, 0x3032D6E7), U64(0xE36A5236, 0x3C1FAF01), /* ~= 10^-169 */ |
| 2791 | U64(0xF18899B1, 0xBC3F8CA1), U64(0xDC44E6C3, 0xCB279AC1), /* ~= 10^-168 */ |
| 2792 | U64(0x96F5600F, 0x15A7B7E5), U64(0x29AB103A, 0x5EF8C0B9), /* ~= 10^-167 */ |
| 2793 | U64(0xBCB2B812, 0xDB11A5DE), U64(0x7415D448, 0xF6B6F0E7), /* ~= 10^-166 */ |
| 2794 | U64(0xEBDF6617, 0x91D60F56), U64(0x111B495B, 0x3464AD21), /* ~= 10^-165 */ |
| 2795 | U64(0x936B9FCE, 0xBB25C995), U64(0xCAB10DD9, 0x00BEEC34), /* ~= 10^-164 */ |
| 2796 | U64(0xB84687C2, 0x69EF3BFB), U64(0x3D5D514F, 0x40EEA742), /* ~= 10^-163 */ |
| 2797 | U64(0xE65829B3, 0x046B0AFA), U64(0x0CB4A5A3, 0x112A5112), /* ~= 10^-162 */ |
| 2798 | U64(0x8FF71A0F, 0xE2C2E6DC), U64(0x47F0E785, 0xEABA72AB), /* ~= 10^-161 */ |
| 2799 | U64(0xB3F4E093, 0xDB73A093), U64(0x59ED2167, 0x65690F56), /* ~= 10^-160 */ |
| 2800 | U64(0xE0F218B8, 0xD25088B8), U64(0x306869C1, 0x3EC3532C), /* ~= 10^-159 */ |
| 2801 | U64(0x8C974F73, 0x83725573), U64(0x1E414218, 0xC73A13FB), /* ~= 10^-158 */ |
| 2802 | U64(0xAFBD2350, 0x644EEACF), U64(0xE5D1929E, 0xF90898FA), /* ~= 10^-157 */ |
| 2803 | U64(0xDBAC6C24, 0x7D62A583), U64(0xDF45F746, 0xB74ABF39), /* ~= 10^-156 */ |
| 2804 | U64(0x894BC396, 0xCE5DA772), U64(0x6B8BBA8C, 0x328EB783), /* ~= 10^-155 */ |
| 2805 | U64(0xAB9EB47C, 0x81F5114F), U64(0x066EA92F, 0x3F326564), /* ~= 10^-154 */ |
| 2806 | U64(0xD686619B, 0xA27255A2), U64(0xC80A537B, 0x0EFEFEBD), /* ~= 10^-153 */ |
| 2807 | U64(0x8613FD01, 0x45877585), U64(0xBD06742C, 0xE95F5F36), /* ~= 10^-152 */ |
| 2808 | U64(0xA798FC41, 0x96E952E7), U64(0x2C481138, 0x23B73704), /* ~= 10^-151 */ |
| 2809 | U64(0xD17F3B51, 0xFCA3A7A0), U64(0xF75A1586, 0x2CA504C5), /* ~= 10^-150 */ |
| 2810 | U64(0x82EF8513, 0x3DE648C4), U64(0x9A984D73, 0xDBE722FB), /* ~= 10^-149 */ |
| 2811 | U64(0xA3AB6658, 0x0D5FDAF5), U64(0xC13E60D0, 0xD2E0EBBA), /* ~= 10^-148 */ |
| 2812 | U64(0xCC963FEE, 0x10B7D1B3), U64(0x318DF905, 0x079926A8), /* ~= 10^-147 */ |
| 2813 | U64(0xFFBBCFE9, 0x94E5C61F), U64(0xFDF17746, 0x497F7052), /* ~= 10^-146 */ |
| 2814 | U64(0x9FD561F1, 0xFD0F9BD3), U64(0xFEB6EA8B, 0xEDEFA633), /* ~= 10^-145 */ |
| 2815 | U64(0xC7CABA6E, 0x7C5382C8), U64(0xFE64A52E, 0xE96B8FC0), /* ~= 10^-144 */ |
| 2816 | U64(0xF9BD690A, 0x1B68637B), U64(0x3DFDCE7A, 0xA3C673B0), /* ~= 10^-143 */ |
| 2817 | U64(0x9C1661A6, 0x51213E2D), U64(0x06BEA10C, 0xA65C084E), /* ~= 10^-142 */ |
| 2818 | U64(0xC31BFA0F, 0xE5698DB8), U64(0x486E494F, 0xCFF30A62), /* ~= 10^-141 */ |
| 2819 | U64(0xF3E2F893, 0xDEC3F126), U64(0x5A89DBA3, 0xC3EFCCFA), /* ~= 10^-140 */ |
| 2820 | U64(0x986DDB5C, 0x6B3A76B7), U64(0xF8962946, 0x5A75E01C), /* ~= 10^-139 */ |
| 2821 | U64(0xBE895233, 0x86091465), U64(0xF6BBB397, 0xF1135823), /* ~= 10^-138 */ |
| 2822 | U64(0xEE2BA6C0, 0x678B597F), U64(0x746AA07D, 0xED582E2C), /* ~= 10^-137 */ |
| 2823 | U64(0x94DB4838, 0x40B717EF), U64(0xA8C2A44E, 0xB4571CDC), /* ~= 10^-136 */ |
| 2824 | U64(0xBA121A46, 0x50E4DDEB), U64(0x92F34D62, 0x616CE413), /* ~= 10^-135 */ |
| 2825 | U64(0xE896A0D7, 0xE51E1566), U64(0x77B020BA, 0xF9C81D17), /* ~= 10^-134 */ |
| 2826 | U64(0x915E2486, 0xEF32CD60), U64(0x0ACE1474, 0xDC1D122E), /* ~= 10^-133 */ |
| 2827 | U64(0xB5B5ADA8, 0xAAFF80B8), U64(0x0D819992, 0x132456BA), /* ~= 10^-132 */ |
| 2828 | U64(0xE3231912, 0xD5BF60E6), U64(0x10E1FFF6, 0x97ED6C69), /* ~= 10^-131 */ |
| 2829 | U64(0x8DF5EFAB, 0xC5979C8F), U64(0xCA8D3FFA, 0x1EF463C1), /* ~= 10^-130 */ |
| 2830 | U64(0xB1736B96, 0xB6FD83B3), U64(0xBD308FF8, 0xA6B17CB2), /* ~= 10^-129 */ |
| 2831 | U64(0xDDD0467C, 0x64BCE4A0), U64(0xAC7CB3F6, 0xD05DDBDE), /* ~= 10^-128 */ |
| 2832 | U64(0x8AA22C0D, 0xBEF60EE4), U64(0x6BCDF07A, 0x423AA96B), /* ~= 10^-127 */ |
| 2833 | U64(0xAD4AB711, 0x2EB3929D), U64(0x86C16C98, 0xD2C953C6), /* ~= 10^-126 */ |
| 2834 | U64(0xD89D64D5, 0x7A607744), U64(0xE871C7BF, 0x077BA8B7), /* ~= 10^-125 */ |
| 2835 | U64(0x87625F05, 0x6C7C4A8B), U64(0x11471CD7, 0x64AD4972), /* ~= 10^-124 */ |
| 2836 | U64(0xA93AF6C6, 0xC79B5D2D), U64(0xD598E40D, 0x3DD89BCF), /* ~= 10^-123 */ |
| 2837 | U64(0xD389B478, 0x79823479), U64(0x4AFF1D10, 0x8D4EC2C3), /* ~= 10^-122 */ |
| 2838 | U64(0x843610CB, 0x4BF160CB), U64(0xCEDF722A, 0x585139BA), /* ~= 10^-121 */ |
| 2839 | U64(0xA54394FE, 0x1EEDB8FE), U64(0xC2974EB4, 0xEE658828), /* ~= 10^-120 */ |
| 2840 | U64(0xCE947A3D, 0xA6A9273E), U64(0x733D2262, 0x29FEEA32), /* ~= 10^-119 */ |
| 2841 | U64(0x811CCC66, 0x8829B887), U64(0x0806357D, 0x5A3F525F), /* ~= 10^-118 */ |
| 2842 | U64(0xA163FF80, 0x2A3426A8), U64(0xCA07C2DC, 0xB0CF26F7), /* ~= 10^-117 */ |
| 2843 | U64(0xC9BCFF60, 0x34C13052), U64(0xFC89B393, 0xDD02F0B5), /* ~= 10^-116 */ |
| 2844 | U64(0xFC2C3F38, 0x41F17C67), U64(0xBBAC2078, 0xD443ACE2), /* ~= 10^-115 */ |
| 2845 | U64(0x9D9BA783, 0x2936EDC0), U64(0xD54B944B, 0x84AA4C0D), /* ~= 10^-114 */ |
| 2846 | U64(0xC5029163, 0xF384A931), U64(0x0A9E795E, 0x65D4DF11), /* ~= 10^-113 */ |
| 2847 | U64(0xF64335BC, 0xF065D37D), U64(0x4D4617B5, 0xFF4A16D5), /* ~= 10^-112 */ |
| 2848 | U64(0x99EA0196, 0x163FA42E), U64(0x504BCED1, 0xBF8E4E45), /* ~= 10^-111 */ |
| 2849 | U64(0xC06481FB, 0x9BCF8D39), U64(0xE45EC286, 0x2F71E1D6), /* ~= 10^-110 */ |
| 2850 | U64(0xF07DA27A, 0x82C37088), U64(0x5D767327, 0xBB4E5A4C), /* ~= 10^-109 */ |
| 2851 | U64(0x964E858C, 0x91BA2655), U64(0x3A6A07F8, 0xD510F86F), /* ~= 10^-108 */ |
| 2852 | U64(0xBBE226EF, 0xB628AFEA), U64(0x890489F7, 0x0A55368B), /* ~= 10^-107 */ |
| 2853 | U64(0xEADAB0AB, 0xA3B2DBE5), U64(0x2B45AC74, 0xCCEA842E), /* ~= 10^-106 */ |
| 2854 | U64(0x92C8AE6B, 0x464FC96F), U64(0x3B0B8BC9, 0x0012929D), /* ~= 10^-105 */ |
| 2855 | U64(0xB77ADA06, 0x17E3BBCB), U64(0x09CE6EBB, 0x40173744), /* ~= 10^-104 */ |
| 2856 | U64(0xE5599087, 0x9DDCAABD), U64(0xCC420A6A, 0x101D0515), /* ~= 10^-103 */ |
| 2857 | U64(0x8F57FA54, 0xC2A9EAB6), U64(0x9FA94682, 0x4A12232D), /* ~= 10^-102 */ |
| 2858 | U64(0xB32DF8E9, 0xF3546564), U64(0x47939822, 0xDC96ABF9), /* ~= 10^-101 */ |
| 2859 | U64(0xDFF97724, 0x70297EBD), U64(0x59787E2B, 0x93BC56F7), /* ~= 10^-100 */ |
| 2860 | U64(0x8BFBEA76, 0xC619EF36), U64(0x57EB4EDB, 0x3C55B65A), /* ~= 10^-99 */ |
| 2861 | U64(0xAEFAE514, 0x77A06B03), U64(0xEDE62292, 0x0B6B23F1), /* ~= 10^-98 */ |
| 2862 | U64(0xDAB99E59, 0x958885C4), U64(0xE95FAB36, 0x8E45ECED), /* ~= 10^-97 */ |
| 2863 | U64(0x88B402F7, 0xFD75539B), U64(0x11DBCB02, 0x18EBB414), /* ~= 10^-96 */ |
| 2864 | U64(0xAAE103B5, 0xFCD2A881), U64(0xD652BDC2, 0x9F26A119), /* ~= 10^-95 */ |
| 2865 | U64(0xD59944A3, 0x7C0752A2), U64(0x4BE76D33, 0x46F0495F), /* ~= 10^-94 */ |
| 2866 | U64(0x857FCAE6, 0x2D8493A5), U64(0x6F70A440, 0x0C562DDB), /* ~= 10^-93 */ |
| 2867 | U64(0xA6DFBD9F, 0xB8E5B88E), U64(0xCB4CCD50, 0x0F6BB952), /* ~= 10^-92 */ |
| 2868 | U64(0xD097AD07, 0xA71F26B2), U64(0x7E2000A4, 0x1346A7A7), /* ~= 10^-91 */ |
| 2869 | U64(0x825ECC24, 0xC873782F), U64(0x8ED40066, 0x8C0C28C8), /* ~= 10^-90 */ |
| 2870 | U64(0xA2F67F2D, 0xFA90563B), U64(0x72890080, 0x2F0F32FA), /* ~= 10^-89 */ |
| 2871 | U64(0xCBB41EF9, 0x79346BCA), U64(0x4F2B40A0, 0x3AD2FFB9), /* ~= 10^-88 */ |
| 2872 | U64(0xFEA126B7, 0xD78186BC), U64(0xE2F610C8, 0x4987BFA8), /* ~= 10^-87 */ |
| 2873 | U64(0x9F24B832, 0xE6B0F436), U64(0x0DD9CA7D, 0x2DF4D7C9), /* ~= 10^-86 */ |
| 2874 | U64(0xC6EDE63F, 0xA05D3143), U64(0x91503D1C, 0x79720DBB), /* ~= 10^-85 */ |
| 2875 | U64(0xF8A95FCF, 0x88747D94), U64(0x75A44C63, 0x97CE912A), /* ~= 10^-84 */ |
| 2876 | U64(0x9B69DBE1, 0xB548CE7C), U64(0xC986AFBE, 0x3EE11ABA), /* ~= 10^-83 */ |
| 2877 | U64(0xC24452DA, 0x229B021B), U64(0xFBE85BAD, 0xCE996168), /* ~= 10^-82 */ |
| 2878 | U64(0xF2D56790, 0xAB41C2A2), U64(0xFAE27299, 0x423FB9C3), /* ~= 10^-81 */ |
| 2879 | U64(0x97C560BA, 0x6B0919A5), U64(0xDCCD879F, 0xC967D41A), /* ~= 10^-80 */ |
| 2880 | U64(0xBDB6B8E9, 0x05CB600F), U64(0x5400E987, 0xBBC1C920), /* ~= 10^-79 */ |
| 2881 | U64(0xED246723, 0x473E3813), U64(0x290123E9, 0xAAB23B68), /* ~= 10^-78 */ |
| 2882 | U64(0x9436C076, 0x0C86E30B), U64(0xF9A0B672, 0x0AAF6521), /* ~= 10^-77 */ |
| 2883 | U64(0xB9447093, 0x8FA89BCE), U64(0xF808E40E, 0x8D5B3E69), /* ~= 10^-76 */ |
| 2884 | U64(0xE7958CB8, 0x7392C2C2), U64(0xB60B1D12, 0x30B20E04), /* ~= 10^-75 */ |
| 2885 | U64(0x90BD77F3, 0x483BB9B9), U64(0xB1C6F22B, 0x5E6F48C2), /* ~= 10^-74 */ |
| 2886 | U64(0xB4ECD5F0, 0x1A4AA828), U64(0x1E38AEB6, 0x360B1AF3), /* ~= 10^-73 */ |
| 2887 | U64(0xE2280B6C, 0x20DD5232), U64(0x25C6DA63, 0xC38DE1B0), /* ~= 10^-72 */ |
| 2888 | U64(0x8D590723, 0x948A535F), U64(0x579C487E, 0x5A38AD0E), /* ~= 10^-71 */ |
| 2889 | U64(0xB0AF48EC, 0x79ACE837), U64(0x2D835A9D, 0xF0C6D851), /* ~= 10^-70 */ |
| 2890 | U64(0xDCDB1B27, 0x98182244), U64(0xF8E43145, 0x6CF88E65), /* ~= 10^-69 */ |
| 2891 | U64(0x8A08F0F8, 0xBF0F156B), U64(0x1B8E9ECB, 0x641B58FF), /* ~= 10^-68 */ |
| 2892 | U64(0xAC8B2D36, 0xEED2DAC5), U64(0xE272467E, 0x3D222F3F), /* ~= 10^-67 */ |
| 2893 | U64(0xD7ADF884, 0xAA879177), U64(0x5B0ED81D, 0xCC6ABB0F), /* ~= 10^-66 */ |
| 2894 | U64(0x86CCBB52, 0xEA94BAEA), U64(0x98E94712, 0x9FC2B4E9), /* ~= 10^-65 */ |
| 2895 | U64(0xA87FEA27, 0xA539E9A5), U64(0x3F2398D7, 0x47B36224), /* ~= 10^-64 */ |
| 2896 | U64(0xD29FE4B1, 0x8E88640E), U64(0x8EEC7F0D, 0x19A03AAD), /* ~= 10^-63 */ |
| 2897 | U64(0x83A3EEEE, 0xF9153E89), U64(0x1953CF68, 0x300424AC), /* ~= 10^-62 */ |
| 2898 | U64(0xA48CEAAA, 0xB75A8E2B), U64(0x5FA8C342, 0x3C052DD7), /* ~= 10^-61 */ |
| 2899 | U64(0xCDB02555, 0x653131B6), U64(0x3792F412, 0xCB06794D), /* ~= 10^-60 */ |
| 2900 | U64(0x808E1755, 0x5F3EBF11), U64(0xE2BBD88B, 0xBEE40BD0), /* ~= 10^-59 */ |
| 2901 | U64(0xA0B19D2A, 0xB70E6ED6), U64(0x5B6ACEAE, 0xAE9D0EC4), /* ~= 10^-58 */ |
| 2902 | U64(0xC8DE0475, 0x64D20A8B), U64(0xF245825A, 0x5A445275), /* ~= 10^-57 */ |
| 2903 | U64(0xFB158592, 0xBE068D2E), U64(0xEED6E2F0, 0xF0D56712), /* ~= 10^-56 */ |
| 2904 | U64(0x9CED737B, 0xB6C4183D), U64(0x55464DD6, 0x9685606B), /* ~= 10^-55 */ |
| 2905 | U64(0xC428D05A, 0xA4751E4C), U64(0xAA97E14C, 0x3C26B886), /* ~= 10^-54 */ |
| 2906 | U64(0xF5330471, 0x4D9265DF), U64(0xD53DD99F, 0x4B3066A8), /* ~= 10^-53 */ |
| 2907 | U64(0x993FE2C6, 0xD07B7FAB), U64(0xE546A803, 0x8EFE4029), /* ~= 10^-52 */ |
| 2908 | U64(0xBF8FDB78, 0x849A5F96), U64(0xDE985204, 0x72BDD033), /* ~= 10^-51 */ |
| 2909 | U64(0xEF73D256, 0xA5C0F77C), U64(0x963E6685, 0x8F6D4440), /* ~= 10^-50 */ |
| 2910 | U64(0x95A86376, 0x27989AAD), U64(0xDDE70013, 0x79A44AA8), /* ~= 10^-49 */ |
| 2911 | U64(0xBB127C53, 0xB17EC159), U64(0x5560C018, 0x580D5D52), /* ~= 10^-48 */ |
| 2912 | U64(0xE9D71B68, 0x9DDE71AF), U64(0xAAB8F01E, 0x6E10B4A6), /* ~= 10^-47 */ |
| 2913 | U64(0x92267121, 0x62AB070D), U64(0xCAB39613, 0x04CA70E8), /* ~= 10^-46 */ |
| 2914 | U64(0xB6B00D69, 0xBB55C8D1), U64(0x3D607B97, 0xC5FD0D22), /* ~= 10^-45 */ |
| 2915 | U64(0xE45C10C4, 0x2A2B3B05), U64(0x8CB89A7D, 0xB77C506A), /* ~= 10^-44 */ |
| 2916 | U64(0x8EB98A7A, 0x9A5B04E3), U64(0x77F3608E, 0x92ADB242), /* ~= 10^-43 */ |
| 2917 | U64(0xB267ED19, 0x40F1C61C), U64(0x55F038B2, 0x37591ED3), /* ~= 10^-42 */ |
| 2918 | U64(0xDF01E85F, 0x912E37A3), U64(0x6B6C46DE, 0xC52F6688), /* ~= 10^-41 */ |
| 2919 | U64(0x8B61313B, 0xBABCE2C6), U64(0x2323AC4B, 0x3B3DA015), /* ~= 10^-40 */ |
| 2920 | U64(0xAE397D8A, 0xA96C1B77), U64(0xABEC975E, 0x0A0D081A), /* ~= 10^-39 */ |
| 2921 | U64(0xD9C7DCED, 0x53C72255), U64(0x96E7BD35, 0x8C904A21), /* ~= 10^-38 */ |
| 2922 | U64(0x881CEA14, 0x545C7575), U64(0x7E50D641, 0x77DA2E54), /* ~= 10^-37 */ |
| 2923 | U64(0xAA242499, 0x697392D2), U64(0xDDE50BD1, 0xD5D0B9E9), /* ~= 10^-36 */ |
| 2924 | U64(0xD4AD2DBF, 0xC3D07787), U64(0x955E4EC6, 0x4B44E864), /* ~= 10^-35 */ |
| 2925 | U64(0x84EC3C97, 0xDA624AB4), U64(0xBD5AF13B, 0xEF0B113E), /* ~= 10^-34 */ |
| 2926 | U64(0xA6274BBD, 0xD0FADD61), U64(0xECB1AD8A, 0xEACDD58E), /* ~= 10^-33 */ |
| 2927 | U64(0xCFB11EAD, 0x453994BA), U64(0x67DE18ED, 0xA5814AF2), /* ~= 10^-32 */ |
| 2928 | U64(0x81CEB32C, 0x4B43FCF4), U64(0x80EACF94, 0x8770CED7), /* ~= 10^-31 */ |
| 2929 | U64(0xA2425FF7, 0x5E14FC31), U64(0xA1258379, 0xA94D028D), /* ~= 10^-30 */ |
| 2930 | U64(0xCAD2F7F5, 0x359A3B3E), U64(0x096EE458, 0x13A04330), /* ~= 10^-29 */ |
| 2931 | U64(0xFD87B5F2, 0x8300CA0D), U64(0x8BCA9D6E, 0x188853FC), /* ~= 10^-28 */ |
| 2932 | U64(0x9E74D1B7, 0x91E07E48), U64(0x775EA264, 0xCF55347D), /* ~= 10^-27 */ |
| 2933 | U64(0xC6120625, 0x76589DDA), U64(0x95364AFE, 0x032A819D), /* ~= 10^-26 */ |
| 2934 | U64(0xF79687AE, 0xD3EEC551), U64(0x3A83DDBD, 0x83F52204), /* ~= 10^-25 */ |
| 2935 | U64(0x9ABE14CD, 0x44753B52), U64(0xC4926A96, 0x72793542), /* ~= 10^-24 */ |
| 2936 | U64(0xC16D9A00, 0x95928A27), U64(0x75B7053C, 0x0F178293), /* ~= 10^-23 */ |
| 2937 | U64(0xF1C90080, 0xBAF72CB1), U64(0x5324C68B, 0x12DD6338), /* ~= 10^-22 */ |
| 2938 | U64(0x971DA050, 0x74DA7BEE), U64(0xD3F6FC16, 0xEBCA5E03), /* ~= 10^-21 */ |
| 2939 | U64(0xBCE50864, 0x92111AEA), U64(0x88F4BB1C, 0xA6BCF584), /* ~= 10^-20 */ |
| 2940 | U64(0xEC1E4A7D, 0xB69561A5), U64(0x2B31E9E3, 0xD06C32E5), /* ~= 10^-19 */ |
| 2941 | U64(0x9392EE8E, 0x921D5D07), U64(0x3AFF322E, 0x62439FCF), /* ~= 10^-18 */ |
| 2942 | U64(0xB877AA32, 0x36A4B449), U64(0x09BEFEB9, 0xFAD487C2), /* ~= 10^-17 */ |
| 2943 | U64(0xE69594BE, 0xC44DE15B), U64(0x4C2EBE68, 0x7989A9B3), /* ~= 10^-16 */ |
| 2944 | U64(0x901D7CF7, 0x3AB0ACD9), U64(0x0F9D3701, 0x4BF60A10), /* ~= 10^-15 */ |
| 2945 | U64(0xB424DC35, 0x095CD80F), U64(0x538484C1, 0x9EF38C94), /* ~= 10^-14 */ |
| 2946 | U64(0xE12E1342, 0x4BB40E13), U64(0x2865A5F2, 0x06B06FB9), /* ~= 10^-13 */ |
| 2947 | U64(0x8CBCCC09, 0x6F5088CB), U64(0xF93F87B7, 0x442E45D3), /* ~= 10^-12 */ |
| 2948 | U64(0xAFEBFF0B, 0xCB24AAFE), U64(0xF78F69A5, 0x1539D748), /* ~= 10^-11 */ |
| 2949 | U64(0xDBE6FECE, 0xBDEDD5BE), U64(0xB573440E, 0x5A884D1B), /* ~= 10^-10 */ |
| 2950 | U64(0x89705F41, 0x36B4A597), U64(0x31680A88, 0xF8953030), /* ~= 10^-9 */ |
| 2951 | U64(0xABCC7711, 0x8461CEFC), U64(0xFDC20D2B, 0x36BA7C3D), /* ~= 10^-8 */ |
| 2952 | U64(0xD6BF94D5, 0xE57A42BC), U64(0x3D329076, 0x04691B4C), /* ~= 10^-7 */ |
| 2953 | U64(0x8637BD05, 0xAF6C69B5), U64(0xA63F9A49, 0xC2C1B10F), /* ~= 10^-6 */ |
| 2954 | U64(0xA7C5AC47, 0x1B478423), U64(0x0FCF80DC, 0x33721D53), /* ~= 10^-5 */ |
| 2955 | U64(0xD1B71758, 0xE219652B), U64(0xD3C36113, 0x404EA4A8), /* ~= 10^-4 */ |
| 2956 | U64(0x83126E97, 0x8D4FDF3B), U64(0x645A1CAC, 0x083126E9), /* ~= 10^-3 */ |
| 2957 | U64(0xA3D70A3D, 0x70A3D70A), U64(0x3D70A3D7, 0x0A3D70A3), /* ~= 10^-2 */ |
| 2958 | U64(0xCCCCCCCC, 0xCCCCCCCC), U64(0xCCCCCCCC, 0xCCCCCCCC), /* ~= 10^-1 */ |
| 2959 | U64(0x80000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^0 */ |
| 2960 | U64(0xA0000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^1 */ |
| 2961 | U64(0xC8000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^2 */ |
| 2962 | U64(0xFA000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^3 */ |
| 2963 | U64(0x9C400000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^4 */ |
| 2964 | U64(0xC3500000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^5 */ |
| 2965 | U64(0xF4240000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^6 */ |
| 2966 | U64(0x98968000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^7 */ |
| 2967 | U64(0xBEBC2000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^8 */ |
| 2968 | U64(0xEE6B2800, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^9 */ |
| 2969 | U64(0x9502F900, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^10 */ |
| 2970 | U64(0xBA43B740, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^11 */ |
| 2971 | U64(0xE8D4A510, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^12 */ |
| 2972 | U64(0x9184E72A, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^13 */ |
| 2973 | U64(0xB5E620F4, 0x80000000), U64(0x00000000, 0x00000000), /* == 10^14 */ |
| 2974 | U64(0xE35FA931, 0xA0000000), U64(0x00000000, 0x00000000), /* == 10^15 */ |
| 2975 | U64(0x8E1BC9BF, 0x04000000), U64(0x00000000, 0x00000000), /* == 10^16 */ |
| 2976 | U64(0xB1A2BC2E, 0xC5000000), U64(0x00000000, 0x00000000), /* == 10^17 */ |
| 2977 | U64(0xDE0B6B3A, 0x76400000), U64(0x00000000, 0x00000000), /* == 10^18 */ |
| 2978 | U64(0x8AC72304, 0x89E80000), U64(0x00000000, 0x00000000), /* == 10^19 */ |
| 2979 | U64(0xAD78EBC5, 0xAC620000), U64(0x00000000, 0x00000000), /* == 10^20 */ |
| 2980 | U64(0xD8D726B7, 0x177A8000), U64(0x00000000, 0x00000000), /* == 10^21 */ |
| 2981 | U64(0x87867832, 0x6EAC9000), U64(0x00000000, 0x00000000), /* == 10^22 */ |
| 2982 | U64(0xA968163F, 0x0A57B400), U64(0x00000000, 0x00000000), /* == 10^23 */ |
| 2983 | U64(0xD3C21BCE, 0xCCEDA100), U64(0x00000000, 0x00000000), /* == 10^24 */ |
| 2984 | U64(0x84595161, 0x401484A0), U64(0x00000000, 0x00000000), /* == 10^25 */ |
| 2985 | U64(0xA56FA5B9, 0x9019A5C8), U64(0x00000000, 0x00000000), /* == 10^26 */ |
| 2986 | U64(0xCECB8F27, 0xF4200F3A), U64(0x00000000, 0x00000000), /* == 10^27 */ |
| 2987 | U64(0x813F3978, 0xF8940984), U64(0x40000000, 0x00000000), /* == 10^28 */ |
| 2988 | U64(0xA18F07D7, 0x36B90BE5), U64(0x50000000, 0x00000000), /* == 10^29 */ |
| 2989 | U64(0xC9F2C9CD, 0x04674EDE), U64(0xA4000000, 0x00000000), /* == 10^30 */ |
| 2990 | U64(0xFC6F7C40, 0x45812296), U64(0x4D000000, 0x00000000), /* == 10^31 */ |
| 2991 | U64(0x9DC5ADA8, 0x2B70B59D), U64(0xF0200000, 0x00000000), /* == 10^32 */ |
| 2992 | U64(0xC5371912, 0x364CE305), U64(0x6C280000, 0x00000000), /* == 10^33 */ |
| 2993 | U64(0xF684DF56, 0xC3E01BC6), U64(0xC7320000, 0x00000000), /* == 10^34 */ |
| 2994 | U64(0x9A130B96, 0x3A6C115C), U64(0x3C7F4000, 0x00000000), /* == 10^35 */ |
| 2995 | U64(0xC097CE7B, 0xC90715B3), U64(0x4B9F1000, 0x00000000), /* == 10^36 */ |
| 2996 | U64(0xF0BDC21A, 0xBB48DB20), U64(0x1E86D400, 0x00000000), /* == 10^37 */ |
| 2997 | U64(0x96769950, 0xB50D88F4), U64(0x13144480, 0x00000000), /* == 10^38 */ |
| 2998 | U64(0xBC143FA4, 0xE250EB31), U64(0x17D955A0, 0x00000000), /* == 10^39 */ |
| 2999 | U64(0xEB194F8E, 0x1AE525FD), U64(0x5DCFAB08, 0x00000000), /* == 10^40 */ |
| 3000 | U64(0x92EFD1B8, 0xD0CF37BE), U64(0x5AA1CAE5, 0x00000000), /* == 10^41 */ |
| 3001 | U64(0xB7ABC627, 0x050305AD), U64(0xF14A3D9E, 0x40000000), /* == 10^42 */ |
| 3002 | U64(0xE596B7B0, 0xC643C719), U64(0x6D9CCD05, 0xD0000000), /* == 10^43 */ |
| 3003 | U64(0x8F7E32CE, 0x7BEA5C6F), U64(0xE4820023, 0xA2000000), /* == 10^44 */ |
| 3004 | U64(0xB35DBF82, 0x1AE4F38B), U64(0xDDA2802C, 0x8A800000), /* == 10^45 */ |
| 3005 | U64(0xE0352F62, 0xA19E306E), U64(0xD50B2037, 0xAD200000), /* == 10^46 */ |
| 3006 | U64(0x8C213D9D, 0xA502DE45), U64(0x4526F422, 0xCC340000), /* == 10^47 */ |
| 3007 | U64(0xAF298D05, 0x0E4395D6), U64(0x9670B12B, 0x7F410000), /* == 10^48 */ |
| 3008 | U64(0xDAF3F046, 0x51D47B4C), U64(0x3C0CDD76, 0x5F114000), /* == 10^49 */ |
| 3009 | U64(0x88D8762B, 0xF324CD0F), U64(0xA5880A69, 0xFB6AC800), /* == 10^50 */ |
| 3010 | U64(0xAB0E93B6, 0xEFEE0053), U64(0x8EEA0D04, 0x7A457A00), /* == 10^51 */ |
| 3011 | U64(0xD5D238A4, 0xABE98068), U64(0x72A49045, 0x98D6D880), /* == 10^52 */ |
| 3012 | U64(0x85A36366, 0xEB71F041), U64(0x47A6DA2B, 0x7F864750), /* == 10^53 */ |
| 3013 | U64(0xA70C3C40, 0xA64E6C51), U64(0x999090B6, 0x5F67D924), /* == 10^54 */ |
| 3014 | U64(0xD0CF4B50, 0xCFE20765), U64(0xFFF4B4E3, 0xF741CF6D), /* == 10^55 */ |
| 3015 | U64(0x82818F12, 0x81ED449F), U64(0xBFF8F10E, 0x7A8921A4), /* ~= 10^56 */ |
| 3016 | U64(0xA321F2D7, 0x226895C7), U64(0xAFF72D52, 0x192B6A0D), /* ~= 10^57 */ |
| 3017 | U64(0xCBEA6F8C, 0xEB02BB39), U64(0x9BF4F8A6, 0x9F764490), /* ~= 10^58 */ |
| 3018 | U64(0xFEE50B70, 0x25C36A08), U64(0x02F236D0, 0x4753D5B4), /* ~= 10^59 */ |
| 3019 | U64(0x9F4F2726, 0x179A2245), U64(0x01D76242, 0x2C946590), /* ~= 10^60 */ |
| 3020 | U64(0xC722F0EF, 0x9D80AAD6), U64(0x424D3AD2, 0xB7B97EF5), /* ~= 10^61 */ |
| 3021 | U64(0xF8EBAD2B, 0x84E0D58B), U64(0xD2E08987, 0x65A7DEB2), /* ~= 10^62 */ |
| 3022 | U64(0x9B934C3B, 0x330C8577), U64(0x63CC55F4, 0x9F88EB2F), /* ~= 10^63 */ |
| 3023 | U64(0xC2781F49, 0xFFCFA6D5), U64(0x3CBF6B71, 0xC76B25FB), /* ~= 10^64 */ |
| 3024 | U64(0xF316271C, 0x7FC3908A), U64(0x8BEF464E, 0x3945EF7A), /* ~= 10^65 */ |
| 3025 | U64(0x97EDD871, 0xCFDA3A56), U64(0x97758BF0, 0xE3CBB5AC), /* ~= 10^66 */ |
| 3026 | U64(0xBDE94E8E, 0x43D0C8EC), U64(0x3D52EEED, 0x1CBEA317), /* ~= 10^67 */ |
| 3027 | U64(0xED63A231, 0xD4C4FB27), U64(0x4CA7AAA8, 0x63EE4BDD), /* ~= 10^68 */ |
| 3028 | U64(0x945E455F, 0x24FB1CF8), U64(0x8FE8CAA9, 0x3E74EF6A), /* ~= 10^69 */ |
| 3029 | U64(0xB975D6B6, 0xEE39E436), U64(0xB3E2FD53, 0x8E122B44), /* ~= 10^70 */ |
| 3030 | U64(0xE7D34C64, 0xA9C85D44), U64(0x60DBBCA8, 0x7196B616), /* ~= 10^71 */ |
| 3031 | U64(0x90E40FBE, 0xEA1D3A4A), U64(0xBC8955E9, 0x46FE31CD), /* ~= 10^72 */ |
| 3032 | U64(0xB51D13AE, 0xA4A488DD), U64(0x6BABAB63, 0x98BDBE41), /* ~= 10^73 */ |
| 3033 | U64(0xE264589A, 0x4DCDAB14), U64(0xC696963C, 0x7EED2DD1), /* ~= 10^74 */ |
| 3034 | U64(0x8D7EB760, 0x70A08AEC), U64(0xFC1E1DE5, 0xCF543CA2), /* ~= 10^75 */ |
| 3035 | U64(0xB0DE6538, 0x8CC8ADA8), U64(0x3B25A55F, 0x43294BCB), /* ~= 10^76 */ |
| 3036 | U64(0xDD15FE86, 0xAFFAD912), U64(0x49EF0EB7, 0x13F39EBE), /* ~= 10^77 */ |
| 3037 | U64(0x8A2DBF14, 0x2DFCC7AB), U64(0x6E356932, 0x6C784337), /* ~= 10^78 */ |
| 3038 | U64(0xACB92ED9, 0x397BF996), U64(0x49C2C37F, 0x07965404), /* ~= 10^79 */ |
| 3039 | U64(0xD7E77A8F, 0x87DAF7FB), U64(0xDC33745E, 0xC97BE906), /* ~= 10^80 */ |
| 3040 | U64(0x86F0AC99, 0xB4E8DAFD), U64(0x69A028BB, 0x3DED71A3), /* ~= 10^81 */ |
| 3041 | U64(0xA8ACD7C0, 0x222311BC), U64(0xC40832EA, 0x0D68CE0C), /* ~= 10^82 */ |
| 3042 | U64(0xD2D80DB0, 0x2AABD62B), U64(0xF50A3FA4, 0x90C30190), /* ~= 10^83 */ |
| 3043 | U64(0x83C7088E, 0x1AAB65DB), U64(0x792667C6, 0xDA79E0FA), /* ~= 10^84 */ |
| 3044 | U64(0xA4B8CAB1, 0xA1563F52), U64(0x577001B8, 0x91185938), /* ~= 10^85 */ |
| 3045 | U64(0xCDE6FD5E, 0x09ABCF26), U64(0xED4C0226, 0xB55E6F86), /* ~= 10^86 */ |
| 3046 | U64(0x80B05E5A, 0xC60B6178), U64(0x544F8158, 0x315B05B4), /* ~= 10^87 */ |
| 3047 | U64(0xA0DC75F1, 0x778E39D6), U64(0x696361AE, 0x3DB1C721), /* ~= 10^88 */ |
| 3048 | U64(0xC913936D, 0xD571C84C), U64(0x03BC3A19, 0xCD1E38E9), /* ~= 10^89 */ |
| 3049 | U64(0xFB587849, 0x4ACE3A5F), U64(0x04AB48A0, 0x4065C723), /* ~= 10^90 */ |
| 3050 | U64(0x9D174B2D, 0xCEC0E47B), U64(0x62EB0D64, 0x283F9C76), /* ~= 10^91 */ |
| 3051 | U64(0xC45D1DF9, 0x42711D9A), U64(0x3BA5D0BD, 0x324F8394), /* ~= 10^92 */ |
| 3052 | U64(0xF5746577, 0x930D6500), U64(0xCA8F44EC, 0x7EE36479), /* ~= 10^93 */ |
| 3053 | U64(0x9968BF6A, 0xBBE85F20), U64(0x7E998B13, 0xCF4E1ECB), /* ~= 10^94 */ |
| 3054 | U64(0xBFC2EF45, 0x6AE276E8), U64(0x9E3FEDD8, 0xC321A67E), /* ~= 10^95 */ |
| 3055 | U64(0xEFB3AB16, 0xC59B14A2), U64(0xC5CFE94E, 0xF3EA101E), /* ~= 10^96 */ |
| 3056 | U64(0x95D04AEE, 0x3B80ECE5), U64(0xBBA1F1D1, 0x58724A12), /* ~= 10^97 */ |
| 3057 | U64(0xBB445DA9, 0xCA61281F), U64(0x2A8A6E45, 0xAE8EDC97), /* ~= 10^98 */ |
| 3058 | U64(0xEA157514, 0x3CF97226), U64(0xF52D09D7, 0x1A3293BD), /* ~= 10^99 */ |
| 3059 | U64(0x924D692C, 0xA61BE758), U64(0x593C2626, 0x705F9C56), /* ~= 10^100 */ |
| 3060 | U64(0xB6E0C377, 0xCFA2E12E), U64(0x6F8B2FB0, 0x0C77836C), /* ~= 10^101 */ |
| 3061 | U64(0xE498F455, 0xC38B997A), U64(0x0B6DFB9C, 0x0F956447), /* ~= 10^102 */ |
| 3062 | U64(0x8EDF98B5, 0x9A373FEC), U64(0x4724BD41, 0x89BD5EAC), /* ~= 10^103 */ |
| 3063 | U64(0xB2977EE3, 0x00C50FE7), U64(0x58EDEC91, 0xEC2CB657), /* ~= 10^104 */ |
| 3064 | U64(0xDF3D5E9B, 0xC0F653E1), U64(0x2F2967B6, 0x6737E3ED), /* ~= 10^105 */ |
| 3065 | U64(0x8B865B21, 0x5899F46C), U64(0xBD79E0D2, 0x0082EE74), /* ~= 10^106 */ |
| 3066 | U64(0xAE67F1E9, 0xAEC07187), U64(0xECD85906, 0x80A3AA11), /* ~= 10^107 */ |
| 3067 | U64(0xDA01EE64, 0x1A708DE9), U64(0xE80E6F48, 0x20CC9495), /* ~= 10^108 */ |
| 3068 | U64(0x884134FE, 0x908658B2), U64(0x3109058D, 0x147FDCDD), /* ~= 10^109 */ |
| 3069 | U64(0xAA51823E, 0x34A7EEDE), U64(0xBD4B46F0, 0x599FD415), /* ~= 10^110 */ |
| 3070 | U64(0xD4E5E2CD, 0xC1D1EA96), U64(0x6C9E18AC, 0x7007C91A), /* ~= 10^111 */ |
| 3071 | U64(0x850FADC0, 0x9923329E), U64(0x03E2CF6B, 0xC604DDB0), /* ~= 10^112 */ |
| 3072 | U64(0xA6539930, 0xBF6BFF45), U64(0x84DB8346, 0xB786151C), /* ~= 10^113 */ |
| 3073 | U64(0xCFE87F7C, 0xEF46FF16), U64(0xE6126418, 0x65679A63), /* ~= 10^114 */ |
| 3074 | U64(0x81F14FAE, 0x158C5F6E), U64(0x4FCB7E8F, 0x3F60C07E), /* ~= 10^115 */ |
| 3075 | U64(0xA26DA399, 0x9AEF7749), U64(0xE3BE5E33, 0x0F38F09D), /* ~= 10^116 */ |
| 3076 | U64(0xCB090C80, 0x01AB551C), U64(0x5CADF5BF, 0xD3072CC5), /* ~= 10^117 */ |
| 3077 | U64(0xFDCB4FA0, 0x02162A63), U64(0x73D9732F, 0xC7C8F7F6), /* ~= 10^118 */ |
| 3078 | U64(0x9E9F11C4, 0x014DDA7E), U64(0x2867E7FD, 0xDCDD9AFA), /* ~= 10^119 */ |
| 3079 | U64(0xC646D635, 0x01A1511D), U64(0xB281E1FD, 0x541501B8), /* ~= 10^120 */ |
| 3080 | U64(0xF7D88BC2, 0x4209A565), U64(0x1F225A7C, 0xA91A4226), /* ~= 10^121 */ |
| 3081 | U64(0x9AE75759, 0x6946075F), U64(0x3375788D, 0xE9B06958), /* ~= 10^122 */ |
| 3082 | U64(0xC1A12D2F, 0xC3978937), U64(0x0052D6B1, 0x641C83AE), /* ~= 10^123 */ |
| 3083 | U64(0xF209787B, 0xB47D6B84), U64(0xC0678C5D, 0xBD23A49A), /* ~= 10^124 */ |
| 3084 | U64(0x9745EB4D, 0x50CE6332), U64(0xF840B7BA, 0x963646E0), /* ~= 10^125 */ |
| 3085 | U64(0xBD176620, 0xA501FBFF), U64(0xB650E5A9, 0x3BC3D898), /* ~= 10^126 */ |
| 3086 | U64(0xEC5D3FA8, 0xCE427AFF), U64(0xA3E51F13, 0x8AB4CEBE), /* ~= 10^127 */ |
| 3087 | U64(0x93BA47C9, 0x80E98CDF), U64(0xC66F336C, 0x36B10137), /* ~= 10^128 */ |
| 3088 | U64(0xB8A8D9BB, 0xE123F017), U64(0xB80B0047, 0x445D4184), /* ~= 10^129 */ |
| 3089 | U64(0xE6D3102A, 0xD96CEC1D), U64(0xA60DC059, 0x157491E5), /* ~= 10^130 */ |
| 3090 | U64(0x9043EA1A, 0xC7E41392), U64(0x87C89837, 0xAD68DB2F), /* ~= 10^131 */ |
| 3091 | U64(0xB454E4A1, 0x79DD1877), U64(0x29BABE45, 0x98C311FB), /* ~= 10^132 */ |
| 3092 | U64(0xE16A1DC9, 0xD8545E94), U64(0xF4296DD6, 0xFEF3D67A), /* ~= 10^133 */ |
| 3093 | U64(0x8CE2529E, 0x2734BB1D), U64(0x1899E4A6, 0x5F58660C), /* ~= 10^134 */ |
| 3094 | U64(0xB01AE745, 0xB101E9E4), U64(0x5EC05DCF, 0xF72E7F8F), /* ~= 10^135 */ |
| 3095 | U64(0xDC21A117, 0x1D42645D), U64(0x76707543, 0xF4FA1F73), /* ~= 10^136 */ |
| 3096 | U64(0x899504AE, 0x72497EBA), U64(0x6A06494A, 0x791C53A8), /* ~= 10^137 */ |
| 3097 | U64(0xABFA45DA, 0x0EDBDE69), U64(0x0487DB9D, 0x17636892), /* ~= 10^138 */ |
| 3098 | U64(0xD6F8D750, 0x9292D603), U64(0x45A9D284, 0x5D3C42B6), /* ~= 10^139 */ |
| 3099 | U64(0x865B8692, 0x5B9BC5C2), U64(0x0B8A2392, 0xBA45A9B2), /* ~= 10^140 */ |
| 3100 | U64(0xA7F26836, 0xF282B732), U64(0x8E6CAC77, 0x68D7141E), /* ~= 10^141 */ |
| 3101 | U64(0xD1EF0244, 0xAF2364FF), U64(0x3207D795, 0x430CD926), /* ~= 10^142 */ |
| 3102 | U64(0x8335616A, 0xED761F1F), U64(0x7F44E6BD, 0x49E807B8), /* ~= 10^143 */ |
| 3103 | U64(0xA402B9C5, 0xA8D3A6E7), U64(0x5F16206C, 0x9C6209A6), /* ~= 10^144 */ |
| 3104 | U64(0xCD036837, 0x130890A1), U64(0x36DBA887, 0xC37A8C0F), /* ~= 10^145 */ |
| 3105 | U64(0x80222122, 0x6BE55A64), U64(0xC2494954, 0xDA2C9789), /* ~= 10^146 */ |
| 3106 | U64(0xA02AA96B, 0x06DEB0FD), U64(0xF2DB9BAA, 0x10B7BD6C), /* ~= 10^147 */ |
| 3107 | U64(0xC83553C5, 0xC8965D3D), U64(0x6F928294, 0x94E5ACC7), /* ~= 10^148 */ |
| 3108 | U64(0xFA42A8B7, 0x3ABBF48C), U64(0xCB772339, 0xBA1F17F9), /* ~= 10^149 */ |
| 3109 | U64(0x9C69A972, 0x84B578D7), U64(0xFF2A7604, 0x14536EFB), /* ~= 10^150 */ |
| 3110 | U64(0xC38413CF, 0x25E2D70D), U64(0xFEF51385, 0x19684ABA), /* ~= 10^151 */ |
| 3111 | U64(0xF46518C2, 0xEF5B8CD1), U64(0x7EB25866, 0x5FC25D69), /* ~= 10^152 */ |
| 3112 | U64(0x98BF2F79, 0xD5993802), U64(0xEF2F773F, 0xFBD97A61), /* ~= 10^153 */ |
| 3113 | U64(0xBEEEFB58, 0x4AFF8603), U64(0xAAFB550F, 0xFACFD8FA), /* ~= 10^154 */ |
| 3114 | U64(0xEEAABA2E, 0x5DBF6784), U64(0x95BA2A53, 0xF983CF38), /* ~= 10^155 */ |
| 3115 | U64(0x952AB45C, 0xFA97A0B2), U64(0xDD945A74, 0x7BF26183), /* ~= 10^156 */ |
| 3116 | U64(0xBA756174, 0x393D88DF), U64(0x94F97111, 0x9AEEF9E4), /* ~= 10^157 */ |
| 3117 | U64(0xE912B9D1, 0x478CEB17), U64(0x7A37CD56, 0x01AAB85D), /* ~= 10^158 */ |
| 3118 | U64(0x91ABB422, 0xCCB812EE), U64(0xAC62E055, 0xC10AB33A), /* ~= 10^159 */ |
| 3119 | U64(0xB616A12B, 0x7FE617AA), U64(0x577B986B, 0x314D6009), /* ~= 10^160 */ |
| 3120 | U64(0xE39C4976, 0x5FDF9D94), U64(0xED5A7E85, 0xFDA0B80B), /* ~= 10^161 */ |
| 3121 | U64(0x8E41ADE9, 0xFBEBC27D), U64(0x14588F13, 0xBE847307), /* ~= 10^162 */ |
| 3122 | U64(0xB1D21964, 0x7AE6B31C), U64(0x596EB2D8, 0xAE258FC8), /* ~= 10^163 */ |
| 3123 | U64(0xDE469FBD, 0x99A05FE3), U64(0x6FCA5F8E, 0xD9AEF3BB), /* ~= 10^164 */ |
| 3124 | U64(0x8AEC23D6, 0x80043BEE), U64(0x25DE7BB9, 0x480D5854), /* ~= 10^165 */ |
| 3125 | U64(0xADA72CCC, 0x20054AE9), U64(0xAF561AA7, 0x9A10AE6A), /* ~= 10^166 */ |
| 3126 | U64(0xD910F7FF, 0x28069DA4), U64(0x1B2BA151, 0x8094DA04), /* ~= 10^167 */ |
| 3127 | U64(0x87AA9AFF, 0x79042286), U64(0x90FB44D2, 0xF05D0842), /* ~= 10^168 */ |
| 3128 | U64(0xA99541BF, 0x57452B28), U64(0x353A1607, 0xAC744A53), /* ~= 10^169 */ |
| 3129 | U64(0xD3FA922F, 0x2D1675F2), U64(0x42889B89, 0x97915CE8), /* ~= 10^170 */ |
| 3130 | U64(0x847C9B5D, 0x7C2E09B7), U64(0x69956135, 0xFEBADA11), /* ~= 10^171 */ |
| 3131 | U64(0xA59BC234, 0xDB398C25), U64(0x43FAB983, 0x7E699095), /* ~= 10^172 */ |
| 3132 | U64(0xCF02B2C2, 0x1207EF2E), U64(0x94F967E4, 0x5E03F4BB), /* ~= 10^173 */ |
| 3133 | U64(0x8161AFB9, 0x4B44F57D), U64(0x1D1BE0EE, 0xBAC278F5), /* ~= 10^174 */ |
| 3134 | U64(0xA1BA1BA7, 0x9E1632DC), U64(0x6462D92A, 0x69731732), /* ~= 10^175 */ |
| 3135 | U64(0xCA28A291, 0x859BBF93), U64(0x7D7B8F75, 0x03CFDCFE), /* ~= 10^176 */ |
| 3136 | U64(0xFCB2CB35, 0xE702AF78), U64(0x5CDA7352, 0x44C3D43E), /* ~= 10^177 */ |
| 3137 | U64(0x9DEFBF01, 0xB061ADAB), U64(0x3A088813, 0x6AFA64A7), /* ~= 10^178 */ |
| 3138 | U64(0xC56BAEC2, 0x1C7A1916), U64(0x088AAA18, 0x45B8FDD0), /* ~= 10^179 */ |
| 3139 | U64(0xF6C69A72, 0xA3989F5B), U64(0x8AAD549E, 0x57273D45), /* ~= 10^180 */ |
| 3140 | U64(0x9A3C2087, 0xA63F6399), U64(0x36AC54E2, 0xF678864B), /* ~= 10^181 */ |
| 3141 | U64(0xC0CB28A9, 0x8FCF3C7F), U64(0x84576A1B, 0xB416A7DD), /* ~= 10^182 */ |
| 3142 | U64(0xF0FDF2D3, 0xF3C30B9F), U64(0x656D44A2, 0xA11C51D5), /* ~= 10^183 */ |
| 3143 | U64(0x969EB7C4, 0x7859E743), U64(0x9F644AE5, 0xA4B1B325), /* ~= 10^184 */ |
| 3144 | U64(0xBC4665B5, 0x96706114), U64(0x873D5D9F, 0x0DDE1FEE), /* ~= 10^185 */ |
| 3145 | U64(0xEB57FF22, 0xFC0C7959), U64(0xA90CB506, 0xD155A7EA), /* ~= 10^186 */ |
| 3146 | U64(0x9316FF75, 0xDD87CBD8), U64(0x09A7F124, 0x42D588F2), /* ~= 10^187 */ |
| 3147 | U64(0xB7DCBF53, 0x54E9BECE), U64(0x0C11ED6D, 0x538AEB2F), /* ~= 10^188 */ |
| 3148 | U64(0xE5D3EF28, 0x2A242E81), U64(0x8F1668C8, 0xA86DA5FA), /* ~= 10^189 */ |
| 3149 | U64(0x8FA47579, 0x1A569D10), U64(0xF96E017D, 0x694487BC), /* ~= 10^190 */ |
| 3150 | U64(0xB38D92D7, 0x60EC4455), U64(0x37C981DC, 0xC395A9AC), /* ~= 10^191 */ |
| 3151 | U64(0xE070F78D, 0x3927556A), U64(0x85BBE253, 0xF47B1417), /* ~= 10^192 */ |
| 3152 | U64(0x8C469AB8, 0x43B89562), U64(0x93956D74, 0x78CCEC8E), /* ~= 10^193 */ |
| 3153 | U64(0xAF584166, 0x54A6BABB), U64(0x387AC8D1, 0x970027B2), /* ~= 10^194 */ |
| 3154 | U64(0xDB2E51BF, 0xE9D0696A), U64(0x06997B05, 0xFCC0319E), /* ~= 10^195 */ |
| 3155 | U64(0x88FCF317, 0xF22241E2), U64(0x441FECE3, 0xBDF81F03), /* ~= 10^196 */ |
| 3156 | U64(0xAB3C2FDD, 0xEEAAD25A), U64(0xD527E81C, 0xAD7626C3), /* ~= 10^197 */ |
| 3157 | U64(0xD60B3BD5, 0x6A5586F1), U64(0x8A71E223, 0xD8D3B074), /* ~= 10^198 */ |
| 3158 | U64(0x85C70565, 0x62757456), U64(0xF6872D56, 0x67844E49), /* ~= 10^199 */ |
| 3159 | U64(0xA738C6BE, 0xBB12D16C), U64(0xB428F8AC, 0x016561DB), /* ~= 10^200 */ |
| 3160 | U64(0xD106F86E, 0x69D785C7), U64(0xE13336D7, 0x01BEBA52), /* ~= 10^201 */ |
| 3161 | U64(0x82A45B45, 0x0226B39C), U64(0xECC00246, 0x61173473), /* ~= 10^202 */ |
| 3162 | U64(0xA34D7216, 0x42B06084), U64(0x27F002D7, 0xF95D0190), /* ~= 10^203 */ |
| 3163 | U64(0xCC20CE9B, 0xD35C78A5), U64(0x31EC038D, 0xF7B441F4), /* ~= 10^204 */ |
| 3164 | U64(0xFF290242, 0xC83396CE), U64(0x7E670471, 0x75A15271), /* ~= 10^205 */ |
| 3165 | U64(0x9F79A169, 0xBD203E41), U64(0x0F0062C6, 0xE984D386), /* ~= 10^206 */ |
| 3166 | U64(0xC75809C4, 0x2C684DD1), U64(0x52C07B78, 0xA3E60868), /* ~= 10^207 */ |
| 3167 | U64(0xF92E0C35, 0x37826145), U64(0xA7709A56, 0xCCDF8A82), /* ~= 10^208 */ |
| 3168 | U64(0x9BBCC7A1, 0x42B17CCB), U64(0x88A66076, 0x400BB691), /* ~= 10^209 */ |
| 3169 | U64(0xC2ABF989, 0x935DDBFE), U64(0x6ACFF893, 0xD00EA435), /* ~= 10^210 */ |
| 3170 | U64(0xF356F7EB, 0xF83552FE), U64(0x0583F6B8, 0xC4124D43), /* ~= 10^211 */ |
| 3171 | U64(0x98165AF3, 0x7B2153DE), U64(0xC3727A33, 0x7A8B704A), /* ~= 10^212 */ |
| 3172 | U64(0xBE1BF1B0, 0x59E9A8D6), U64(0x744F18C0, 0x592E4C5C), /* ~= 10^213 */ |
| 3173 | U64(0xEDA2EE1C, 0x7064130C), U64(0x1162DEF0, 0x6F79DF73), /* ~= 10^214 */ |
| 3174 | U64(0x9485D4D1, 0xC63E8BE7), U64(0x8ADDCB56, 0x45AC2BA8), /* ~= 10^215 */ |
| 3175 | U64(0xB9A74A06, 0x37CE2EE1), U64(0x6D953E2B, 0xD7173692), /* ~= 10^216 */ |
| 3176 | U64(0xE8111C87, 0xC5C1BA99), U64(0xC8FA8DB6, 0xCCDD0437), /* ~= 10^217 */ |
| 3177 | U64(0x910AB1D4, 0xDB9914A0), U64(0x1D9C9892, 0x400A22A2), /* ~= 10^218 */ |
| 3178 | U64(0xB54D5E4A, 0x127F59C8), U64(0x2503BEB6, 0xD00CAB4B), /* ~= 10^219 */ |
| 3179 | U64(0xE2A0B5DC, 0x971F303A), U64(0x2E44AE64, 0x840FD61D), /* ~= 10^220 */ |
| 3180 | U64(0x8DA471A9, 0xDE737E24), U64(0x5CEAECFE, 0xD289E5D2), /* ~= 10^221 */ |
| 3181 | U64(0xB10D8E14, 0x56105DAD), U64(0x7425A83E, 0x872C5F47), /* ~= 10^222 */ |
| 3182 | U64(0xDD50F199, 0x6B947518), U64(0xD12F124E, 0x28F77719), /* ~= 10^223 */ |
| 3183 | U64(0x8A5296FF, 0xE33CC92F), U64(0x82BD6B70, 0xD99AAA6F), /* ~= 10^224 */ |
| 3184 | U64(0xACE73CBF, 0xDC0BFB7B), U64(0x636CC64D, 0x1001550B), /* ~= 10^225 */ |
| 3185 | U64(0xD8210BEF, 0xD30EFA5A), U64(0x3C47F7E0, 0x5401AA4E), /* ~= 10^226 */ |
| 3186 | U64(0x8714A775, 0xE3E95C78), U64(0x65ACFAEC, 0x34810A71), /* ~= 10^227 */ |
| 3187 | U64(0xA8D9D153, 0x5CE3B396), U64(0x7F1839A7, 0x41A14D0D), /* ~= 10^228 */ |
| 3188 | U64(0xD31045A8, 0x341CA07C), U64(0x1EDE4811, 0x1209A050), /* ~= 10^229 */ |
| 3189 | U64(0x83EA2B89, 0x2091E44D), U64(0x934AED0A, 0xAB460432), /* ~= 10^230 */ |
| 3190 | U64(0xA4E4B66B, 0x68B65D60), U64(0xF81DA84D, 0x5617853F), /* ~= 10^231 */ |
| 3191 | U64(0xCE1DE406, 0x42E3F4B9), U64(0x36251260, 0xAB9D668E), /* ~= 10^232 */ |
| 3192 | U64(0x80D2AE83, 0xE9CE78F3), U64(0xC1D72B7C, 0x6B426019), /* ~= 10^233 */ |
| 3193 | U64(0xA1075A24, 0xE4421730), U64(0xB24CF65B, 0x8612F81F), /* ~= 10^234 */ |
| 3194 | U64(0xC94930AE, 0x1D529CFC), U64(0xDEE033F2, 0x6797B627), /* ~= 10^235 */ |
| 3195 | U64(0xFB9B7CD9, 0xA4A7443C), U64(0x169840EF, 0x017DA3B1), /* ~= 10^236 */ |
| 3196 | U64(0x9D412E08, 0x06E88AA5), U64(0x8E1F2895, 0x60EE864E), /* ~= 10^237 */ |
| 3197 | U64(0xC491798A, 0x08A2AD4E), U64(0xF1A6F2BA, 0xB92A27E2), /* ~= 10^238 */ |
| 3198 | U64(0xF5B5D7EC, 0x8ACB58A2), U64(0xAE10AF69, 0x6774B1DB), /* ~= 10^239 */ |
| 3199 | U64(0x9991A6F3, 0xD6BF1765), U64(0xACCA6DA1, 0xE0A8EF29), /* ~= 10^240 */ |
| 3200 | U64(0xBFF610B0, 0xCC6EDD3F), U64(0x17FD090A, 0x58D32AF3), /* ~= 10^241 */ |
| 3201 | U64(0xEFF394DC, 0xFF8A948E), U64(0xDDFC4B4C, 0xEF07F5B0), /* ~= 10^242 */ |
| 3202 | U64(0x95F83D0A, 0x1FB69CD9), U64(0x4ABDAF10, 0x1564F98E), /* ~= 10^243 */ |
| 3203 | U64(0xBB764C4C, 0xA7A4440F), U64(0x9D6D1AD4, 0x1ABE37F1), /* ~= 10^244 */ |
| 3204 | U64(0xEA53DF5F, 0xD18D5513), U64(0x84C86189, 0x216DC5ED), /* ~= 10^245 */ |
| 3205 | U64(0x92746B9B, 0xE2F8552C), U64(0x32FD3CF5, 0xB4E49BB4), /* ~= 10^246 */ |
| 3206 | U64(0xB7118682, 0xDBB66A77), U64(0x3FBC8C33, 0x221DC2A1), /* ~= 10^247 */ |
| 3207 | U64(0xE4D5E823, 0x92A40515), U64(0x0FABAF3F, 0xEAA5334A), /* ~= 10^248 */ |
| 3208 | U64(0x8F05B116, 0x3BA6832D), U64(0x29CB4D87, 0xF2A7400E), /* ~= 10^249 */ |
| 3209 | U64(0xB2C71D5B, 0xCA9023F8), U64(0x743E20E9, 0xEF511012), /* ~= 10^250 */ |
| 3210 | U64(0xDF78E4B2, 0xBD342CF6), U64(0x914DA924, 0x6B255416), /* ~= 10^251 */ |
| 3211 | U64(0x8BAB8EEF, 0xB6409C1A), U64(0x1AD089B6, 0xC2F7548E), /* ~= 10^252 */ |
| 3212 | U64(0xAE9672AB, 0xA3D0C320), U64(0xA184AC24, 0x73B529B1), /* ~= 10^253 */ |
| 3213 | U64(0xDA3C0F56, 0x8CC4F3E8), U64(0xC9E5D72D, 0x90A2741E), /* ~= 10^254 */ |
| 3214 | U64(0x88658996, 0x17FB1871), U64(0x7E2FA67C, 0x7A658892), /* ~= 10^255 */ |
| 3215 | U64(0xAA7EEBFB, 0x9DF9DE8D), U64(0xDDBB901B, 0x98FEEAB7), /* ~= 10^256 */ |
| 3216 | U64(0xD51EA6FA, 0x85785631), U64(0x552A7422, 0x7F3EA565), /* ~= 10^257 */ |
| 3217 | U64(0x8533285C, 0x936B35DE), U64(0xD53A8895, 0x8F87275F), /* ~= 10^258 */ |
| 3218 | U64(0xA67FF273, 0xB8460356), U64(0x8A892ABA, 0xF368F137), /* ~= 10^259 */ |
| 3219 | U64(0xD01FEF10, 0xA657842C), U64(0x2D2B7569, 0xB0432D85), /* ~= 10^260 */ |
| 3220 | U64(0x8213F56A, 0x67F6B29B), U64(0x9C3B2962, 0x0E29FC73), /* ~= 10^261 */ |
| 3221 | U64(0xA298F2C5, 0x01F45F42), U64(0x8349F3BA, 0x91B47B8F), /* ~= 10^262 */ |
| 3222 | U64(0xCB3F2F76, 0x42717713), U64(0x241C70A9, 0x36219A73), /* ~= 10^263 */ |
| 3223 | U64(0xFE0EFB53, 0xD30DD4D7), U64(0xED238CD3, 0x83AA0110), /* ~= 10^264 */ |
| 3224 | U64(0x9EC95D14, 0x63E8A506), U64(0xF4363804, 0x324A40AA), /* ~= 10^265 */ |
| 3225 | U64(0xC67BB459, 0x7CE2CE48), U64(0xB143C605, 0x3EDCD0D5), /* ~= 10^266 */ |
| 3226 | U64(0xF81AA16F, 0xDC1B81DA), U64(0xDD94B786, 0x8E94050A), /* ~= 10^267 */ |
| 3227 | U64(0x9B10A4E5, 0xE9913128), U64(0xCA7CF2B4, 0x191C8326), /* ~= 10^268 */ |
| 3228 | U64(0xC1D4CE1F, 0x63F57D72), U64(0xFD1C2F61, 0x1F63A3F0), /* ~= 10^269 */ |
| 3229 | U64(0xF24A01A7, 0x3CF2DCCF), U64(0xBC633B39, 0x673C8CEC), /* ~= 10^270 */ |
| 3230 | U64(0x976E4108, 0x8617CA01), U64(0xD5BE0503, 0xE085D813), /* ~= 10^271 */ |
| 3231 | U64(0xBD49D14A, 0xA79DBC82), U64(0x4B2D8644, 0xD8A74E18), /* ~= 10^272 */ |
| 3232 | U64(0xEC9C459D, 0x51852BA2), U64(0xDDF8E7D6, 0x0ED1219E), /* ~= 10^273 */ |
| 3233 | U64(0x93E1AB82, 0x52F33B45), U64(0xCABB90E5, 0xC942B503), /* ~= 10^274 */ |
| 3234 | U64(0xB8DA1662, 0xE7B00A17), U64(0x3D6A751F, 0x3B936243), /* ~= 10^275 */ |
| 3235 | U64(0xE7109BFB, 0xA19C0C9D), U64(0x0CC51267, 0x0A783AD4), /* ~= 10^276 */ |
| 3236 | U64(0x906A617D, 0x450187E2), U64(0x27FB2B80, 0x668B24C5), /* ~= 10^277 */ |
| 3237 | U64(0xB484F9DC, 0x9641E9DA), U64(0xB1F9F660, 0x802DEDF6), /* ~= 10^278 */ |
| 3238 | U64(0xE1A63853, 0xBBD26451), U64(0x5E7873F8, 0xA0396973), /* ~= 10^279 */ |
| 3239 | U64(0x8D07E334, 0x55637EB2), U64(0xDB0B487B, 0x6423E1E8), /* ~= 10^280 */ |
| 3240 | U64(0xB049DC01, 0x6ABC5E5F), U64(0x91CE1A9A, 0x3D2CDA62), /* ~= 10^281 */ |
| 3241 | U64(0xDC5C5301, 0xC56B75F7), U64(0x7641A140, 0xCC7810FB), /* ~= 10^282 */ |
| 3242 | U64(0x89B9B3E1, 0x1B6329BA), U64(0xA9E904C8, 0x7FCB0A9D), /* ~= 10^283 */ |
| 3243 | U64(0xAC2820D9, 0x623BF429), U64(0x546345FA, 0x9FBDCD44), /* ~= 10^284 */ |
| 3244 | U64(0xD732290F, 0xBACAF133), U64(0xA97C1779, 0x47AD4095), /* ~= 10^285 */ |
| 3245 | U64(0x867F59A9, 0xD4BED6C0), U64(0x49ED8EAB, 0xCCCC485D), /* ~= 10^286 */ |
| 3246 | U64(0xA81F3014, 0x49EE8C70), U64(0x5C68F256, 0xBFFF5A74), /* ~= 10^287 */ |
| 3247 | U64(0xD226FC19, 0x5C6A2F8C), U64(0x73832EEC, 0x6FFF3111), /* ~= 10^288 */ |
| 3248 | U64(0x83585D8F, 0xD9C25DB7), U64(0xC831FD53, 0xC5FF7EAB), /* ~= 10^289 */ |
| 3249 | U64(0xA42E74F3, 0xD032F525), U64(0xBA3E7CA8, 0xB77F5E55), /* ~= 10^290 */ |
| 3250 | U64(0xCD3A1230, 0xC43FB26F), U64(0x28CE1BD2, 0xE55F35EB), /* ~= 10^291 */ |
| 3251 | U64(0x80444B5E, 0x7AA7CF85), U64(0x7980D163, 0xCF5B81B3), /* ~= 10^292 */ |
| 3252 | U64(0xA0555E36, 0x1951C366), U64(0xD7E105BC, 0xC332621F), /* ~= 10^293 */ |
| 3253 | U64(0xC86AB5C3, 0x9FA63440), U64(0x8DD9472B, 0xF3FEFAA7), /* ~= 10^294 */ |
| 3254 | U64(0xFA856334, 0x878FC150), U64(0xB14F98F6, 0xF0FEB951), /* ~= 10^295 */ |
| 3255 | U64(0x9C935E00, 0xD4B9D8D2), U64(0x6ED1BF9A, 0x569F33D3), /* ~= 10^296 */ |
| 3256 | U64(0xC3B83581, 0x09E84F07), U64(0x0A862F80, 0xEC4700C8), /* ~= 10^297 */ |
| 3257 | U64(0xF4A642E1, 0x4C6262C8), U64(0xCD27BB61, 0x2758C0FA), /* ~= 10^298 */ |
| 3258 | U64(0x98E7E9CC, 0xCFBD7DBD), U64(0x8038D51C, 0xB897789C), /* ~= 10^299 */ |
| 3259 | U64(0xBF21E440, 0x03ACDD2C), U64(0xE0470A63, 0xE6BD56C3), /* ~= 10^300 */ |
| 3260 | U64(0xEEEA5D50, 0x04981478), U64(0x1858CCFC, 0xE06CAC74), /* ~= 10^301 */ |
| 3261 | U64(0x95527A52, 0x02DF0CCB), U64(0x0F37801E, 0x0C43EBC8), /* ~= 10^302 */ |
| 3262 | U64(0xBAA718E6, 0x8396CFFD), U64(0xD3056025, 0x8F54E6BA), /* ~= 10^303 */ |
| 3263 | U64(0xE950DF20, 0x247C83FD), U64(0x47C6B82E, 0xF32A2069), /* ~= 10^304 */ |
| 3264 | U64(0x91D28B74, 0x16CDD27E), U64(0x4CDC331D, 0x57FA5441), /* ~= 10^305 */ |
| 3265 | U64(0xB6472E51, 0x1C81471D), U64(0xE0133FE4, 0xADF8E952), /* ~= 10^306 */ |
| 3266 | U64(0xE3D8F9E5, 0x63A198E5), U64(0x58180FDD, 0xD97723A6), /* ~= 10^307 */ |
| 3267 | U64(0x8E679C2F, 0x5E44FF8F), U64(0x570F09EA, 0xA7EA7648), /* ~= 10^308 */ |
| 3268 | U64(0xB201833B, 0x35D63F73), U64(0x2CD2CC65, 0x51E513DA), /* ~= 10^309 */ |
| 3269 | U64(0xDE81E40A, 0x034BCF4F), U64(0xF8077F7E, 0xA65E58D1), /* ~= 10^310 */ |
| 3270 | U64(0x8B112E86, 0x420F6191), U64(0xFB04AFAF, 0x27FAF782), /* ~= 10^311 */ |
| 3271 | U64(0xADD57A27, 0xD29339F6), U64(0x79C5DB9A, 0xF1F9B563), /* ~= 10^312 */ |
| 3272 | U64(0xD94AD8B1, 0xC7380874), U64(0x18375281, 0xAE7822BC), /* ~= 10^313 */ |
| 3273 | U64(0x87CEC76F, 0x1C830548), U64(0x8F229391, 0x0D0B15B5), /* ~= 10^314 */ |
| 3274 | U64(0xA9C2794A, 0xE3A3C69A), U64(0xB2EB3875, 0x504DDB22), /* ~= 10^315 */ |
| 3275 | U64(0xD433179D, 0x9C8CB841), U64(0x5FA60692, 0xA46151EB), /* ~= 10^316 */ |
| 3276 | U64(0x849FEEC2, 0x81D7F328), U64(0xDBC7C41B, 0xA6BCD333), /* ~= 10^317 */ |
| 3277 | U64(0xA5C7EA73, 0x224DEFF3), U64(0x12B9B522, 0x906C0800), /* ~= 10^318 */ |
| 3278 | U64(0xCF39E50F, 0xEAE16BEF), U64(0xD768226B, 0x34870A00), /* ~= 10^319 */ |
| 3279 | U64(0x81842F29, 0xF2CCE375), U64(0xE6A11583, 0x00D46640), /* ~= 10^320 */ |
| 3280 | U64(0xA1E53AF4, 0x6F801C53), U64(0x60495AE3, 0xC1097FD0), /* ~= 10^321 */ |
| 3281 | U64(0xCA5E89B1, 0x8B602368), U64(0x385BB19C, 0xB14BDFC4), /* ~= 10^322 */ |
| 3282 | U64(0xFCF62C1D, 0xEE382C42), U64(0x46729E03, 0xDD9ED7B5), /* ~= 10^323 */ |
| 3283 | U64(0x9E19DB92, 0xB4E31BA9), U64(0x6C07A2C2, 0x6A8346D1) /* ~= 10^324 */ |
| 3284 | }; |
| 3285 | |
| 3286 | /** |
| 3287 | Get the cached pow10 value from pow10_sig_table. |
| 3288 | @param exp10 The exponent of pow(10, e). This value must in range |
| 3289 | POW10_SIG_TABLE_MIN_EXP to POW10_SIG_TABLE_MAX_EXP. |
| 3290 | @param hi The highest 64 bits of pow(10, e). |
| 3291 | @param lo The lower 64 bits after `hi`. |
| 3292 | */ |
| 3293 | static_inline void pow10_table_get_sig(i32 exp10, u64 *hi, u64 *lo) { |
| 3294 | i32 idx = exp10 - (POW10_SIG_TABLE_MIN_EXP); |
| 3295 | *hi = pow10_sig_table[idx * 2]; |
| 3296 | *lo = pow10_sig_table[idx * 2 + 1]; |
| 3297 | } |
| 3298 | |
| 3299 | /** |
| 3300 | Get the exponent (base 2) for highest 64 bits significand in pow10_sig_table. |
| 3301 | */ |
| 3302 | static_inline void pow10_table_get_exp(i32 exp10, i32 *exp2) { |
| 3303 | /* e2 = floor(log2(pow(10, e))) - 64 + 1 */ |
| 3304 | /* = floor(e * log2(10) - 63) */ |
| 3305 | *exp2 = (exp10 * 217706 - 4128768) >> 16; |
| 3306 | } |
| 3307 | |
| 3308 | #endif |
| 3309 | |
| 3310 | |
| 3311 | |
| 3312 | #if !YYJSON_DISABLE_READER |
| 3313 | |
| 3314 | /*============================================================================== |
| 3315 | * JSON Character Matcher |
| 3316 | *============================================================================*/ |
| 3317 | |
| 3318 | /** Character type */ |
| 3319 | typedef u8 char_type; |
| 3320 | |
| 3321 | /** Whitespace character: ' ', '\\t', '\\n', '\\r'. */ |
| 3322 | static const char_type CHAR_TYPE_SPACE = 1 << 0; |
| 3323 | |
| 3324 | /** Number character: '-', [0-9]. */ |
| 3325 | static const char_type CHAR_TYPE_NUMBER = 1 << 1; |
| 3326 | |
| 3327 | /** JSON Escaped character: '"', '\', [0x00-0x1F]. */ |
| 3328 | static const char_type CHAR_TYPE_ESC_ASCII = 1 << 2; |
| 3329 | |
| 3330 | /** Non-ASCII character: [0x80-0xFF]. */ |
| 3331 | static const char_type CHAR_TYPE_NON_ASCII = 1 << 3; |
| 3332 | |
| 3333 | /** JSON container character: '{', '['. */ |
| 3334 | static const char_type CHAR_TYPE_CONTAINER = 1 << 4; |
| 3335 | |
| 3336 | /** Comment character: '/'. */ |
| 3337 | static const char_type = 1 << 5; |
| 3338 | |
| 3339 | /** Line end character: '\\n', '\\r', '\0'. */ |
| 3340 | static const char_type CHAR_TYPE_LINE_END = 1 << 6; |
| 3341 | |
| 3342 | /** Hexadecimal numeric character: [0-9a-fA-F]. */ |
| 3343 | static const char_type CHAR_TYPE_HEX = 1 << 7; |
| 3344 | |
| 3345 | /** Character type table (generate with misc/make_tables.c) */ |
| 3346 | static const char_type char_table[256] = { |
| 3347 | 0x44, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, |
| 3348 | 0x04, 0x05, 0x45, 0x04, 0x04, 0x45, 0x04, 0x04, |
| 3349 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, |
| 3350 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, |
| 3351 | 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 3352 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x20, |
| 3353 | 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, |
| 3354 | 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 3355 | 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, |
| 3356 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 3357 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 3358 | 0x00, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00, |
| 3359 | 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, |
| 3360 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 3361 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 3362 | 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, |
| 3363 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, |
| 3364 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, |
| 3365 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, |
| 3366 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, |
| 3367 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, |
| 3368 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, |
| 3369 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, |
| 3370 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, |
| 3371 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, |
| 3372 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, |
| 3373 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, |
| 3374 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, |
| 3375 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, |
| 3376 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, |
| 3377 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, |
| 3378 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 |
| 3379 | }; |
| 3380 | |
| 3381 | /** Match a character with specified type. */ |
| 3382 | static_inline bool char_is_type(u8 c, char_type type) { |
| 3383 | return (char_table[c] & type) != 0; |
| 3384 | } |
| 3385 | |
| 3386 | /** Match a whitespace: ' ', '\\t', '\\n', '\\r'. */ |
| 3387 | static_inline bool char_is_space(u8 c) { |
| 3388 | return char_is_type(c, (char_type)CHAR_TYPE_SPACE); |
| 3389 | } |
| 3390 | |
| 3391 | /** Match a whitespace or comment: ' ', '\\t', '\\n', '\\r', '/'. */ |
| 3392 | static_inline bool (u8 c) { |
| 3393 | return char_is_type(c, (char_type)(CHAR_TYPE_SPACE | CHAR_TYPE_COMMENT)); |
| 3394 | } |
| 3395 | |
| 3396 | /** Match a JSON number: '-', [0-9]. */ |
| 3397 | static_inline bool char_is_number(u8 c) { |
| 3398 | return char_is_type(c, (char_type)CHAR_TYPE_NUMBER); |
| 3399 | } |
| 3400 | |
| 3401 | /** Match a JSON container: '{', '['. */ |
| 3402 | static_inline bool char_is_container(u8 c) { |
| 3403 | return char_is_type(c, (char_type)CHAR_TYPE_CONTAINER); |
| 3404 | } |
| 3405 | |
| 3406 | /** Match a stop character in ASCII string: '"', '\', [0x00-0x1F,0x80-0xFF]. */ |
| 3407 | static_inline bool char_is_ascii_stop(u8 c) { |
| 3408 | return char_is_type(c, (char_type)(CHAR_TYPE_ESC_ASCII | |
| 3409 | CHAR_TYPE_NON_ASCII)); |
| 3410 | } |
| 3411 | |
| 3412 | /** Match a line end character: '\\n', '\\r', '\0'. */ |
| 3413 | static_inline bool char_is_line_end(u8 c) { |
| 3414 | return char_is_type(c, (char_type)CHAR_TYPE_LINE_END); |
| 3415 | } |
| 3416 | |
| 3417 | /** Match a hexadecimal numeric character: [0-9a-fA-F]. */ |
| 3418 | static_inline bool char_is_hex(u8 c) { |
| 3419 | return char_is_type(c, (char_type)CHAR_TYPE_HEX); |
| 3420 | } |
| 3421 | |
| 3422 | |
| 3423 | |
| 3424 | /*============================================================================== |
| 3425 | * Digit Character Matcher |
| 3426 | *============================================================================*/ |
| 3427 | |
| 3428 | /** Digit type */ |
| 3429 | typedef u8 digi_type; |
| 3430 | |
| 3431 | /** Digit: '0'. */ |
| 3432 | static const digi_type DIGI_TYPE_ZERO = 1 << 0; |
| 3433 | |
| 3434 | /** Digit: [1-9]. */ |
| 3435 | static const digi_type DIGI_TYPE_NONZERO = 1 << 1; |
| 3436 | |
| 3437 | /** Plus sign (positive): '+'. */ |
| 3438 | static const digi_type DIGI_TYPE_POS = 1 << 2; |
| 3439 | |
| 3440 | /** Minus sign (negative): '-'. */ |
| 3441 | static const digi_type DIGI_TYPE_NEG = 1 << 3; |
| 3442 | |
| 3443 | /** Decimal point: '.' */ |
| 3444 | static const digi_type DIGI_TYPE_DOT = 1 << 4; |
| 3445 | |
| 3446 | /** Exponent sign: 'e, 'E'. */ |
| 3447 | static const digi_type DIGI_TYPE_EXP = 1 << 5; |
| 3448 | |
| 3449 | /** Digit type table (generate with misc/make_tables.c) */ |
| 3450 | static const digi_type digi_table[256] = { |
| 3451 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 3452 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 3453 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 3454 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 3455 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 3456 | 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x10, 0x00, |
| 3457 | 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, |
| 3458 | 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 3459 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, |
| 3460 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 3461 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 3462 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 3463 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, |
| 3464 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 3465 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 3466 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
| 3467 | }; |
| 3468 | |
| 3469 | /** Match a character with specified type. */ |
| 3470 | static_inline bool digi_is_type(u8 d, digi_type type) { |
| 3471 | return (digi_table[d] & type) != 0; |
| 3472 | } |
| 3473 | |
| 3474 | /** Match a sign: '+', '-' */ |
| 3475 | static_inline bool digi_is_sign(u8 d) { |
| 3476 | return digi_is_type(d, (digi_type)(DIGI_TYPE_POS | DIGI_TYPE_NEG)); |
| 3477 | } |
| 3478 | |
| 3479 | /** Match a none zero digit: [1-9] */ |
| 3480 | static_inline bool digi_is_nonzero(u8 d) { |
| 3481 | return digi_is_type(d, (digi_type)DIGI_TYPE_NONZERO); |
| 3482 | } |
| 3483 | |
| 3484 | /** Match a digit: [0-9] */ |
| 3485 | static_inline bool digi_is_digit(u8 d) { |
| 3486 | return digi_is_type(d, (digi_type)(DIGI_TYPE_ZERO | DIGI_TYPE_NONZERO)); |
| 3487 | } |
| 3488 | |
| 3489 | /** Match an exponent sign: 'e', 'E'. */ |
| 3490 | static_inline bool digi_is_exp(u8 d) { |
| 3491 | return digi_is_type(d, (digi_type)DIGI_TYPE_EXP); |
| 3492 | } |
| 3493 | |
| 3494 | /** Match a floating point indicator: '.', 'e', 'E'. */ |
| 3495 | static_inline bool digi_is_fp(u8 d) { |
| 3496 | return digi_is_type(d, (digi_type)(DIGI_TYPE_DOT | DIGI_TYPE_EXP)); |
| 3497 | } |
| 3498 | |
| 3499 | /** Match a digit or floating point indicator: [0-9], '.', 'e', 'E'. */ |
| 3500 | static_inline bool digi_is_digit_or_fp(u8 d) { |
| 3501 | return digi_is_type(d, (digi_type)(DIGI_TYPE_ZERO | DIGI_TYPE_NONZERO | |
| 3502 | DIGI_TYPE_DOT | DIGI_TYPE_EXP)); |
| 3503 | } |
| 3504 | |
| 3505 | |
| 3506 | |
| 3507 | /*============================================================================== |
| 3508 | * Hex Character Reader |
| 3509 | * This function is used by JSON reader to read escaped characters. |
| 3510 | *============================================================================*/ |
| 3511 | |
| 3512 | /** |
| 3513 | This table is used to convert 4 hex character sequence to a number. |
| 3514 | A valid hex character [0-9A-Fa-f] will mapped to it's raw number [0x00, 0x0F], |
| 3515 | an invalid hex character will mapped to [0xF0]. |
| 3516 | (generate with misc/make_tables.c) |
| 3517 | */ |
| 3518 | static const u8 hex_conv_table[256] = { |
| 3519 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3520 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3521 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3522 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3523 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3524 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3525 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 3526 | 0x08, 0x09, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3527 | 0xF0, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF0, |
| 3528 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3529 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3530 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3531 | 0xF0, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF0, |
| 3532 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3533 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3534 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3535 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3536 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3537 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3538 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3539 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3540 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3541 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3542 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3543 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3544 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3545 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3546 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3547 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3548 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3549 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
| 3550 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0 |
| 3551 | }; |
| 3552 | |
| 3553 | /** |
| 3554 | Scans an escaped character sequence as a UTF-16 code unit (branchless). |
| 3555 | e.g. "\\u005C" should pass "005C" as `cur`. |
| 3556 | |
| 3557 | This requires the string has 4-byte zero padding. |
| 3558 | */ |
| 3559 | static_inline bool read_hex_u16(const u8 *cur, u16 *val) { |
| 3560 | u16 c0, c1, c2, c3, t0, t1; |
| 3561 | c0 = hex_conv_table[cur[0]]; |
| 3562 | c1 = hex_conv_table[cur[1]]; |
| 3563 | c2 = hex_conv_table[cur[2]]; |
| 3564 | c3 = hex_conv_table[cur[3]]; |
| 3565 | t0 = (u16)((c0 << 8) | c2); |
| 3566 | t1 = (u16)((c1 << 8) | c3); |
| 3567 | *val = (u16)((t0 << 4) | t1); |
| 3568 | return ((t0 | t1) & (u16)0xF0F0) == 0; |
| 3569 | } |
| 3570 | |
| 3571 | |
| 3572 | |
| 3573 | /*============================================================================== |
| 3574 | * JSON Reader Utils |
| 3575 | * These functions are used by JSON reader to read literals and comments. |
| 3576 | *============================================================================*/ |
| 3577 | |
| 3578 | /** Read 'true' literal, '*cur' should be 't'. */ |
| 3579 | static_inline bool read_true(u8 **ptr, yyjson_val *val) { |
| 3580 | u8 *cur = *ptr; |
| 3581 | u8 **end = ptr; |
| 3582 | if (likely(byte_match_4(cur, "true" ))) { |
| 3583 | val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_TRUE; |
| 3584 | *end = cur + 4; |
| 3585 | return true; |
| 3586 | } |
| 3587 | return false; |
| 3588 | } |
| 3589 | |
| 3590 | /** Read 'false' literal, '*cur' should be 'f'. */ |
| 3591 | static_inline bool read_false(u8 **ptr, yyjson_val *val) { |
| 3592 | u8 *cur = *ptr; |
| 3593 | u8 **end = ptr; |
| 3594 | if (likely(byte_match_4(cur + 1, "alse" ))) { |
| 3595 | val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_FALSE; |
| 3596 | *end = cur + 5; |
| 3597 | return true; |
| 3598 | } |
| 3599 | return false; |
| 3600 | } |
| 3601 | |
| 3602 | /** Read 'null' literal, '*cur' should be 'n'. */ |
| 3603 | static_inline bool read_null(u8 **ptr, yyjson_val *val) { |
| 3604 | u8 *cur = *ptr; |
| 3605 | u8 **end = ptr; |
| 3606 | if (likely(byte_match_4(cur, "null" ))) { |
| 3607 | val->tag = YYJSON_TYPE_NULL; |
| 3608 | *end = cur + 4; |
| 3609 | return true; |
| 3610 | } |
| 3611 | return false; |
| 3612 | } |
| 3613 | |
| 3614 | /** Read 'Inf' or 'Infinity' literal (ignoring case). */ |
| 3615 | static_inline bool read_inf(bool sign, u8 **ptr, u8 **pre, yyjson_val *val) { |
| 3616 | #if !YYJSON_DISABLE_NON_STANDARD |
| 3617 | u8 *hdr = *ptr - sign; |
| 3618 | u8 *cur = *ptr; |
| 3619 | u8 **end = ptr; |
| 3620 | if ((cur[0] == 'I' || cur[0] == 'i') && |
| 3621 | (cur[1] == 'N' || cur[1] == 'n') && |
| 3622 | (cur[2] == 'F' || cur[2] == 'f')) { |
| 3623 | if ((cur[3] == 'I' || cur[3] == 'i') && |
| 3624 | (cur[4] == 'N' || cur[4] == 'n') && |
| 3625 | (cur[5] == 'I' || cur[5] == 'i') && |
| 3626 | (cur[6] == 'T' || cur[6] == 't') && |
| 3627 | (cur[7] == 'Y' || cur[7] == 'y')) { |
| 3628 | cur += 8; |
| 3629 | } else { |
| 3630 | cur += 3; |
| 3631 | } |
| 3632 | *end = cur; |
| 3633 | if (pre) { |
| 3634 | /* add null-terminator for previous raw string */ |
| 3635 | if (*pre) **pre = '\0'; |
| 3636 | *pre = cur; |
| 3637 | val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; |
| 3638 | val->uni.str = (const char *)hdr; |
| 3639 | } else { |
| 3640 | val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; |
| 3641 | val->uni.u64 = f64_raw_get_inf(sign); |
| 3642 | } |
| 3643 | return true; |
| 3644 | } |
| 3645 | #endif |
| 3646 | return false; |
| 3647 | } |
| 3648 | |
| 3649 | /** Read 'NaN' literal (ignoring case). */ |
| 3650 | static_inline bool read_nan(bool sign, u8 **ptr, u8 **pre, yyjson_val *val) { |
| 3651 | #if !YYJSON_DISABLE_NON_STANDARD |
| 3652 | u8 *hdr = *ptr - sign; |
| 3653 | u8 *cur = *ptr; |
| 3654 | u8 **end = ptr; |
| 3655 | if ((cur[0] == 'N' || cur[0] == 'n') && |
| 3656 | (cur[1] == 'A' || cur[1] == 'a') && |
| 3657 | (cur[2] == 'N' || cur[2] == 'n')) { |
| 3658 | cur += 3; |
| 3659 | *end = cur; |
| 3660 | if (pre) { |
| 3661 | /* add null-terminator for previous raw string */ |
| 3662 | if (*pre) **pre = '\0'; |
| 3663 | *pre = cur; |
| 3664 | val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; |
| 3665 | val->uni.str = (const char *)hdr; |
| 3666 | } else { |
| 3667 | val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; |
| 3668 | val->uni.u64 = f64_raw_get_nan(sign); |
| 3669 | } |
| 3670 | return true; |
| 3671 | } |
| 3672 | #endif |
| 3673 | return false; |
| 3674 | } |
| 3675 | |
| 3676 | /** Read 'Inf', 'Infinity' or 'NaN' literal (ignoring case). */ |
| 3677 | static_inline bool read_inf_or_nan(bool sign, u8 **ptr, u8 **pre, |
| 3678 | yyjson_val *val) { |
| 3679 | if (read_inf(sign, ptr, pre, val)) return true; |
| 3680 | if (read_nan(sign, ptr, pre, val)) return true; |
| 3681 | return false; |
| 3682 | } |
| 3683 | |
| 3684 | /** Read a JSON number as raw string. */ |
| 3685 | static_noinline bool read_number_raw(u8 **ptr, |
| 3686 | u8 **pre, |
| 3687 | yyjson_read_flag flg, |
| 3688 | yyjson_val *val, |
| 3689 | const char **msg) { |
| 3690 | |
| 3691 | #define return_err(_pos, _msg) do { \ |
| 3692 | *msg = _msg; \ |
| 3693 | *end = _pos; \ |
| 3694 | return false; \ |
| 3695 | } while (false) |
| 3696 | |
| 3697 | #define return_raw() do { \ |
| 3698 | val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \ |
| 3699 | val->uni.str = (const char *)hdr; \ |
| 3700 | *pre = cur; *end = cur; return true; \ |
| 3701 | } while (false) |
| 3702 | |
| 3703 | u8 *hdr = *ptr; |
| 3704 | u8 *cur = *ptr; |
| 3705 | u8 **end = ptr; |
| 3706 | |
| 3707 | /* add null-terminator for previous raw string */ |
| 3708 | if (*pre) **pre = '\0'; |
| 3709 | |
| 3710 | /* skip sign */ |
| 3711 | cur += (*cur == '-'); |
| 3712 | |
| 3713 | /* read first digit, check leading zero */ |
| 3714 | if (unlikely(!digi_is_digit(*cur))) { |
| 3715 | if (flg & YYJSON_READ_ALLOW_INF_AND_NAN) { |
| 3716 | if (read_inf_or_nan(*hdr == '-', &cur, pre, val)) return_raw(); |
| 3717 | } |
| 3718 | return_err(cur, "no digit after minus sign" ); |
| 3719 | } |
| 3720 | |
| 3721 | /* read integral part */ |
| 3722 | if (*cur == '0') { |
| 3723 | cur++; |
| 3724 | if (unlikely(digi_is_digit(*cur))) { |
| 3725 | return_err(cur - 1, "number with leading zero is not allowed" ); |
| 3726 | } |
| 3727 | if (!digi_is_fp(*cur)) return_raw(); |
| 3728 | } else { |
| 3729 | while (digi_is_digit(*cur)) cur++; |
| 3730 | if (!digi_is_fp(*cur)) return_raw(); |
| 3731 | } |
| 3732 | |
| 3733 | /* read fraction part */ |
| 3734 | if (*cur == '.') { |
| 3735 | cur++; |
| 3736 | if (!digi_is_digit(*cur++)) { |
| 3737 | return_err(cur, "no digit after decimal point" ); |
| 3738 | } |
| 3739 | while (digi_is_digit(*cur)) cur++; |
| 3740 | } |
| 3741 | |
| 3742 | /* read exponent part */ |
| 3743 | if (digi_is_exp(*cur)) { |
| 3744 | cur += 1 + digi_is_sign(cur[1]); |
| 3745 | if (!digi_is_digit(*cur++)) { |
| 3746 | return_err(cur, "no digit after exponent sign" ); |
| 3747 | } |
| 3748 | while (digi_is_digit(*cur)) cur++; |
| 3749 | } |
| 3750 | |
| 3751 | return_raw(); |
| 3752 | |
| 3753 | #undef return_err |
| 3754 | #undef return_raw |
| 3755 | } |
| 3756 | |
| 3757 | /** |
| 3758 | Skips spaces and comments as many as possible. |
| 3759 | |
| 3760 | It will return false in these cases: |
| 3761 | 1. No character is skipped. The 'end' pointer is set as input cursor. |
| 3762 | 2. A multiline comment is not closed. The 'end' pointer is set as the head |
| 3763 | of this comment block. |
| 3764 | */ |
| 3765 | static_noinline bool skip_spaces_and_comments(u8 **ptr) { |
| 3766 | u8 *hdr = *ptr; |
| 3767 | u8 *cur = *ptr; |
| 3768 | u8 **end = ptr; |
| 3769 | while (true) { |
| 3770 | if (byte_match_2(cur, "/*" )) { |
| 3771 | hdr = cur; |
| 3772 | cur += 2; |
| 3773 | while (true) { |
| 3774 | if (byte_match_2(cur, "*/" )) { |
| 3775 | cur += 2; |
| 3776 | break; |
| 3777 | } |
| 3778 | if (*cur == 0) { |
| 3779 | *end = hdr; |
| 3780 | return false; |
| 3781 | } |
| 3782 | cur++; |
| 3783 | } |
| 3784 | continue; |
| 3785 | } |
| 3786 | if (byte_match_2(cur, "//" )) { |
| 3787 | cur += 2; |
| 3788 | while (!char_is_line_end(*cur)) cur++; |
| 3789 | continue; |
| 3790 | } |
| 3791 | if (char_is_space(*cur)) { |
| 3792 | cur += 1; |
| 3793 | while (char_is_space(*cur)) cur++; |
| 3794 | continue; |
| 3795 | } |
| 3796 | break; |
| 3797 | } |
| 3798 | *end = cur; |
| 3799 | return hdr != cur; |
| 3800 | } |
| 3801 | |
| 3802 | /** |
| 3803 | Check truncated string. |
| 3804 | Returns true if `cur` match `str` but is truncated. |
| 3805 | */ |
| 3806 | static_inline bool is_truncated_str(u8 *cur, u8 *end, |
| 3807 | const char *str, |
| 3808 | bool case_sensitive) { |
| 3809 | usize len = strlen(str); |
| 3810 | if (cur + len <= end || end <= cur) return false; |
| 3811 | if (case_sensitive) { |
| 3812 | return memcmp(cur, str, (usize)(end - cur)) == 0; |
| 3813 | } |
| 3814 | for (; cur < end; cur++, str++) { |
| 3815 | if ((*cur != (u8)*str) && (*cur != (u8)*str - 'a' + 'A')) { |
| 3816 | return false; |
| 3817 | } |
| 3818 | } |
| 3819 | return true; |
| 3820 | } |
| 3821 | |
| 3822 | /** |
| 3823 | Check truncated JSON on parsing errors. |
| 3824 | Returns true if the input is valid but truncated. |
| 3825 | */ |
| 3826 | static_noinline bool is_truncated_end(u8 *hdr, u8 *cur, u8 *end, |
| 3827 | yyjson_read_code code, |
| 3828 | yyjson_read_flag flg) { |
| 3829 | if (cur >= end) return true; |
| 3830 | if (code == YYJSON_READ_ERROR_LITERAL) { |
| 3831 | if (is_truncated_str(cur, end, "true" , true) || |
| 3832 | is_truncated_str(cur, end, "false" , true) || |
| 3833 | is_truncated_str(cur, end, "null" , true)) { |
| 3834 | return true; |
| 3835 | } |
| 3836 | } |
| 3837 | if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER || |
| 3838 | code == YYJSON_READ_ERROR_INVALID_NUMBER || |
| 3839 | code == YYJSON_READ_ERROR_LITERAL) { |
| 3840 | if ((flg & YYJSON_READ_ALLOW_INF_AND_NAN)) { |
| 3841 | if (*cur == '-') cur++; |
| 3842 | if (is_truncated_str(cur, end, "infinity" , false) || |
| 3843 | is_truncated_str(cur, end, "nan" , false)) { |
| 3844 | return true; |
| 3845 | } |
| 3846 | } |
| 3847 | } |
| 3848 | if (code == YYJSON_READ_ERROR_UNEXPECTED_CONTENT) { |
| 3849 | if (flg & YYJSON_READ_ALLOW_INF_AND_NAN) { |
| 3850 | if (hdr + 3 <= cur && |
| 3851 | is_truncated_str(cur - 3, end, "infinity" , false)) { |
| 3852 | return true; /* e.g. infin would be read as inf + in */ |
| 3853 | } |
| 3854 | } |
| 3855 | } |
| 3856 | if (code == YYJSON_READ_ERROR_INVALID_STRING) { |
| 3857 | usize len = (usize)(end - cur); |
| 3858 | |
| 3859 | /* unicode escape sequence */ |
| 3860 | if (*cur == '\\') { |
| 3861 | if (len == 1) return true; |
| 3862 | if (len <= 5) { |
| 3863 | if (*++cur != 'u') return false; |
| 3864 | for (++cur; cur < end; cur++) { |
| 3865 | if (!char_is_hex(*cur)) return false; |
| 3866 | } |
| 3867 | return true; |
| 3868 | } |
| 3869 | return false; |
| 3870 | } |
| 3871 | |
| 3872 | /* 2 to 4 bytes UTF-8, see `read_string()` for details. */ |
| 3873 | if (*cur & 0x80) { |
| 3874 | u8 c0 = cur[0], c1 = cur[1], c2 = cur[2]; |
| 3875 | if (len == 1) { |
| 3876 | /* 2 bytes UTF-8, truncated */ |
| 3877 | if ((c0 & 0xE0) == 0xC0 && (c0 & 0x1E) != 0x00) return true; |
| 3878 | /* 3 bytes UTF-8, truncated */ |
| 3879 | if ((c0 & 0xF0) == 0xE0) return true; |
| 3880 | /* 4 bytes UTF-8, truncated */ |
| 3881 | if ((c0 & 0xF8) == 0xF0 && (c0 & 0x07) <= 0x04) return true; |
| 3882 | } |
| 3883 | if (len == 2) { |
| 3884 | /* 3 bytes UTF-8, truncated */ |
| 3885 | if ((c0 & 0xF0) == 0xE0 && |
| 3886 | (c1 & 0xC0) == 0x80) { |
| 3887 | u8 pat = (u8)(((c0 & 0x0F) << 1) | ((c1 & 0x20) >> 5)); |
| 3888 | return 0x01 <= pat && pat != 0x1B; |
| 3889 | } |
| 3890 | /* 4 bytes UTF-8, truncated */ |
| 3891 | if ((c0 & 0xF8) == 0xF0 && |
| 3892 | (c1 & 0xC0) == 0x80) { |
| 3893 | u8 pat = (u8)(((c0 & 0x07) << 2) | ((c1 & 0x30) >> 4)); |
| 3894 | return 0x01 <= pat && pat <= 0x10; |
| 3895 | } |
| 3896 | } |
| 3897 | if (len == 3) { |
| 3898 | /* 4 bytes UTF-8, truncated */ |
| 3899 | if ((c0 & 0xF8) == 0xF0 && |
| 3900 | (c1 & 0xC0) == 0x80 && |
| 3901 | (c2 & 0xC0) == 0x80) { |
| 3902 | u8 pat = (u8)(((c0 & 0x07) << 2) | ((c1 & 0x30) >> 4)); |
| 3903 | return 0x01 <= pat && pat <= 0x10; |
| 3904 | } |
| 3905 | } |
| 3906 | } |
| 3907 | } |
| 3908 | return false; |
| 3909 | } |
| 3910 | |
| 3911 | |
| 3912 | |
| 3913 | #if YYJSON_HAS_IEEE_754 && !YYJSON_DISABLE_FAST_FP_CONV /* FP_READER */ |
| 3914 | |
| 3915 | /*============================================================================== |
| 3916 | * BigInt For Floating Point Number Reader |
| 3917 | * |
| 3918 | * The bigint algorithm is used by floating-point number reader to get correctly |
| 3919 | * rounded result for numbers with lots of digits. This part of code is rarely |
| 3920 | * used for common numbers. |
| 3921 | *============================================================================*/ |
| 3922 | |
| 3923 | /** Maximum exponent of exact pow10 */ |
| 3924 | #define U64_POW10_MAX_EXP 19 |
| 3925 | |
| 3926 | /** Table: [ 10^0, ..., 10^19 ] (generate with misc/make_tables.c) */ |
| 3927 | static const u64 u64_pow10_table[U64_POW10_MAX_EXP + 1] = { |
| 3928 | U64(0x00000000, 0x00000001), U64(0x00000000, 0x0000000A), |
| 3929 | U64(0x00000000, 0x00000064), U64(0x00000000, 0x000003E8), |
| 3930 | U64(0x00000000, 0x00002710), U64(0x00000000, 0x000186A0), |
| 3931 | U64(0x00000000, 0x000F4240), U64(0x00000000, 0x00989680), |
| 3932 | U64(0x00000000, 0x05F5E100), U64(0x00000000, 0x3B9ACA00), |
| 3933 | U64(0x00000002, 0x540BE400), U64(0x00000017, 0x4876E800), |
| 3934 | U64(0x000000E8, 0xD4A51000), U64(0x00000918, 0x4E72A000), |
| 3935 | U64(0x00005AF3, 0x107A4000), U64(0x00038D7E, 0xA4C68000), |
| 3936 | U64(0x002386F2, 0x6FC10000), U64(0x01634578, 0x5D8A0000), |
| 3937 | U64(0x0DE0B6B3, 0xA7640000), U64(0x8AC72304, 0x89E80000) |
| 3938 | }; |
| 3939 | |
| 3940 | /** Maximum numbers of chunks used by a bigint (58 is enough here). */ |
| 3941 | #define BIGINT_MAX_CHUNKS 64 |
| 3942 | |
| 3943 | /** Unsigned arbitrarily large integer */ |
| 3944 | typedef struct bigint { |
| 3945 | u32 used; /* used chunks count, should not be 0 */ |
| 3946 | u64 bits[BIGINT_MAX_CHUNKS]; /* chunks */ |
| 3947 | } bigint; |
| 3948 | |
| 3949 | /** |
| 3950 | Evaluate 'big += val'. |
| 3951 | @param big A big number (can be 0). |
| 3952 | @param val An unsigned integer (can be 0). |
| 3953 | */ |
| 3954 | static_inline void bigint_add_u64(bigint *big, u64 val) { |
| 3955 | u32 idx, max; |
| 3956 | u64 num = big->bits[0]; |
| 3957 | u64 add = num + val; |
| 3958 | big->bits[0] = add; |
| 3959 | if (likely((add >= num) || (add >= val))) return; |
| 3960 | for ((void)(idx = 1), max = big->used; idx < max; idx++) { |
| 3961 | if (likely(big->bits[idx] != U64_MAX)) { |
| 3962 | big->bits[idx] += 1; |
| 3963 | return; |
| 3964 | } |
| 3965 | big->bits[idx] = 0; |
| 3966 | } |
| 3967 | big->bits[big->used++] = 1; |
| 3968 | } |
| 3969 | |
| 3970 | /** |
| 3971 | Evaluate 'big *= val'. |
| 3972 | @param big A big number (can be 0). |
| 3973 | @param val An unsigned integer (cannot be 0). |
| 3974 | */ |
| 3975 | static_inline void bigint_mul_u64(bigint *big, u64 val) { |
| 3976 | u32 idx = 0, max = big->used; |
| 3977 | u64 hi, lo, carry = 0; |
| 3978 | for (; idx < max; idx++) { |
| 3979 | if (big->bits[idx]) break; |
| 3980 | } |
| 3981 | for (; idx < max; idx++) { |
| 3982 | u128_mul_add(big->bits[idx], val, carry, &hi, &lo); |
| 3983 | big->bits[idx] = lo; |
| 3984 | carry = hi; |
| 3985 | } |
| 3986 | if (carry) big->bits[big->used++] = carry; |
| 3987 | } |
| 3988 | |
| 3989 | /** |
| 3990 | Evaluate 'big *= 2^exp'. |
| 3991 | @param big A big number (can be 0). |
| 3992 | @param exp An exponent integer (can be 0). |
| 3993 | */ |
| 3994 | static_inline void bigint_mul_pow2(bigint *big, u32 exp) { |
| 3995 | u32 shft = exp % 64; |
| 3996 | u32 move = exp / 64; |
| 3997 | u32 idx = big->used; |
| 3998 | if (unlikely(shft == 0)) { |
| 3999 | for (; idx > 0; idx--) { |
| 4000 | big->bits[idx + move - 1] = big->bits[idx - 1]; |
| 4001 | } |
| 4002 | big->used += move; |
| 4003 | while (move) big->bits[--move] = 0; |
| 4004 | } else { |
| 4005 | big->bits[idx] = 0; |
| 4006 | for (; idx > 0; idx--) { |
| 4007 | u64 num = big->bits[idx] << shft; |
| 4008 | num |= big->bits[idx - 1] >> (64 - shft); |
| 4009 | big->bits[idx + move] = num; |
| 4010 | } |
| 4011 | big->bits[move] = big->bits[0] << shft; |
| 4012 | big->used += move + (big->bits[big->used + move] > 0); |
| 4013 | while (move) big->bits[--move] = 0; |
| 4014 | } |
| 4015 | } |
| 4016 | |
| 4017 | /** |
| 4018 | Evaluate 'big *= 10^exp'. |
| 4019 | @param big A big number (can be 0). |
| 4020 | @param exp An exponent integer (cannot be 0). |
| 4021 | */ |
| 4022 | static_inline void bigint_mul_pow10(bigint *big, i32 exp) { |
| 4023 | for (; exp >= U64_POW10_MAX_EXP; exp -= U64_POW10_MAX_EXP) { |
| 4024 | bigint_mul_u64(big, u64_pow10_table[U64_POW10_MAX_EXP]); |
| 4025 | } |
| 4026 | if (exp) { |
| 4027 | bigint_mul_u64(big, u64_pow10_table[exp]); |
| 4028 | } |
| 4029 | } |
| 4030 | |
| 4031 | /** |
| 4032 | Compare two bigint. |
| 4033 | @return -1 if 'a < b', +1 if 'a > b', 0 if 'a == b'. |
| 4034 | */ |
| 4035 | static_inline i32 bigint_cmp(bigint *a, bigint *b) { |
| 4036 | u32 idx = a->used; |
| 4037 | if (a->used < b->used) return -1; |
| 4038 | if (a->used > b->used) return +1; |
| 4039 | while (idx-- > 0) { |
| 4040 | u64 av = a->bits[idx]; |
| 4041 | u64 bv = b->bits[idx]; |
| 4042 | if (av < bv) return -1; |
| 4043 | if (av > bv) return +1; |
| 4044 | } |
| 4045 | return 0; |
| 4046 | } |
| 4047 | |
| 4048 | /** |
| 4049 | Evaluate 'big = val'. |
| 4050 | @param big A big number (can be 0). |
| 4051 | @param val An unsigned integer (can be 0). |
| 4052 | */ |
| 4053 | static_inline void bigint_set_u64(bigint *big, u64 val) { |
| 4054 | big->used = 1; |
| 4055 | big->bits[0] = val; |
| 4056 | } |
| 4057 | |
| 4058 | /** Set a bigint with floating point number string. */ |
| 4059 | static_noinline void bigint_set_buf(bigint *big, u64 sig, i32 *exp, |
| 4060 | u8 *sig_cut, u8 *sig_end, u8 *dot_pos) { |
| 4061 | |
| 4062 | if (unlikely(!sig_cut)) { |
| 4063 | /* no digit cut, set significant part only */ |
| 4064 | bigint_set_u64(big, sig); |
| 4065 | return; |
| 4066 | |
| 4067 | } else { |
| 4068 | /* some digits were cut, read them from 'sig_cut' to 'sig_end' */ |
| 4069 | u8 *hdr = sig_cut; |
| 4070 | u8 *cur = hdr; |
| 4071 | u32 len = 0; |
| 4072 | u64 val = 0; |
| 4073 | bool dig_big_cut = false; |
| 4074 | bool has_dot = (hdr < dot_pos) & (dot_pos < sig_end); |
| 4075 | u32 dig_len_total = U64_SAFE_DIG + (u32)(sig_end - hdr) - has_dot; |
| 4076 | |
| 4077 | sig -= (*sig_cut >= '5'); /* sig was rounded before */ |
| 4078 | if (dig_len_total > F64_MAX_DEC_DIG) { |
| 4079 | dig_big_cut = true; |
| 4080 | sig_end -= dig_len_total - (F64_MAX_DEC_DIG + 1); |
| 4081 | sig_end -= (dot_pos + 1 == sig_end); |
| 4082 | dig_len_total = (F64_MAX_DEC_DIG + 1); |
| 4083 | } |
| 4084 | *exp -= (i32)dig_len_total - U64_SAFE_DIG; |
| 4085 | |
| 4086 | big->used = 1; |
| 4087 | big->bits[0] = sig; |
| 4088 | while (cur < sig_end) { |
| 4089 | if (likely(cur != dot_pos)) { |
| 4090 | val = val * 10 + (u8)(*cur++ - '0'); |
| 4091 | len++; |
| 4092 | if (unlikely(cur == sig_end && dig_big_cut)) { |
| 4093 | /* The last digit must be non-zero, */ |
| 4094 | /* set it to '1' for correct rounding. */ |
| 4095 | val = val - (val % 10) + 1; |
| 4096 | } |
| 4097 | if (len == U64_SAFE_DIG || cur == sig_end) { |
| 4098 | bigint_mul_pow10(big, (i32)len); |
| 4099 | bigint_add_u64(big, val); |
| 4100 | val = 0; |
| 4101 | len = 0; |
| 4102 | } |
| 4103 | } else { |
| 4104 | cur++; |
| 4105 | } |
| 4106 | } |
| 4107 | } |
| 4108 | } |
| 4109 | |
| 4110 | |
| 4111 | |
| 4112 | /*============================================================================== |
| 4113 | * Diy Floating Point |
| 4114 | *============================================================================*/ |
| 4115 | |
| 4116 | /** "Do It Yourself Floating Point" struct. */ |
| 4117 | typedef struct diy_fp { |
| 4118 | u64 sig; /* significand */ |
| 4119 | i32 exp; /* exponent, base 2 */ |
| 4120 | i32 pad; /* padding, useless */ |
| 4121 | } diy_fp; |
| 4122 | |
| 4123 | /** Get cached rounded diy_fp with pow(10, e) The input value must in range |
| 4124 | [POW10_SIG_TABLE_MIN_EXP, POW10_SIG_TABLE_MAX_EXP]. */ |
| 4125 | static_inline diy_fp diy_fp_get_cached_pow10(i32 exp10) { |
| 4126 | diy_fp fp; |
| 4127 | u64 sig_ext; |
| 4128 | pow10_table_get_sig(exp10, &fp.sig, &sig_ext); |
| 4129 | pow10_table_get_exp(exp10, &fp.exp); |
| 4130 | fp.sig += (sig_ext >> 63); |
| 4131 | return fp; |
| 4132 | } |
| 4133 | |
| 4134 | /** Returns fp * fp2. */ |
| 4135 | static_inline diy_fp diy_fp_mul(diy_fp fp, diy_fp fp2) { |
| 4136 | u64 hi, lo; |
| 4137 | u128_mul(fp.sig, fp2.sig, &hi, &lo); |
| 4138 | fp.sig = hi + (lo >> 63); |
| 4139 | fp.exp += fp2.exp + 64; |
| 4140 | return fp; |
| 4141 | } |
| 4142 | |
| 4143 | /** Convert diy_fp to IEEE-754 raw value. */ |
| 4144 | static_inline u64 diy_fp_to_ieee_raw(diy_fp fp) { |
| 4145 | u64 sig = fp.sig; |
| 4146 | i32 exp = fp.exp; |
| 4147 | u32 lz_bits; |
| 4148 | if (unlikely(fp.sig == 0)) return 0; |
| 4149 | |
| 4150 | lz_bits = u64_lz_bits(sig); |
| 4151 | sig <<= lz_bits; |
| 4152 | sig >>= F64_BITS - F64_SIG_FULL_BITS; |
| 4153 | exp -= (i32)lz_bits; |
| 4154 | exp += F64_BITS - F64_SIG_FULL_BITS; |
| 4155 | exp += F64_SIG_BITS; |
| 4156 | |
| 4157 | if (unlikely(exp >= F64_MAX_BIN_EXP)) { |
| 4158 | /* overflow */ |
| 4159 | return F64_RAW_INF; |
| 4160 | } else if (likely(exp >= F64_MIN_BIN_EXP - 1)) { |
| 4161 | /* normal */ |
| 4162 | exp += F64_EXP_BIAS; |
| 4163 | return ((u64)exp << F64_SIG_BITS) | (sig & F64_SIG_MASK); |
| 4164 | } else if (likely(exp >= F64_MIN_BIN_EXP - F64_SIG_FULL_BITS)) { |
| 4165 | /* subnormal */ |
| 4166 | return sig >> (F64_MIN_BIN_EXP - exp - 1); |
| 4167 | } else { |
| 4168 | /* underflow */ |
| 4169 | return 0; |
| 4170 | } |
| 4171 | } |
| 4172 | |
| 4173 | |
| 4174 | |
| 4175 | /*============================================================================== |
| 4176 | * JSON Number Reader (IEEE-754) |
| 4177 | *============================================================================*/ |
| 4178 | |
| 4179 | /** Maximum exact pow10 exponent for double value. */ |
| 4180 | #define F64_POW10_EXP_MAX_EXACT 22 |
| 4181 | |
| 4182 | /** Cached pow10 table. */ |
| 4183 | static const f64 f64_pow10_table[] = { |
| 4184 | 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, |
| 4185 | 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22 |
| 4186 | }; |
| 4187 | |
| 4188 | /** |
| 4189 | Read a JSON number. |
| 4190 | |
| 4191 | 1. This function assume that the floating-point number is in IEEE-754 format. |
| 4192 | 2. This function support uint64/int64/double number. If an integer number |
| 4193 | cannot fit in uint64/int64, it will returns as a double number. If a double |
| 4194 | number is infinite, the return value is based on flag. |
| 4195 | 3. This function (with inline attribute) may generate a lot of instructions. |
| 4196 | */ |
| 4197 | static_inline bool read_number(u8 **ptr, |
| 4198 | u8 **pre, |
| 4199 | yyjson_read_flag flg, |
| 4200 | yyjson_val *val, |
| 4201 | const char **msg) { |
| 4202 | |
| 4203 | #define return_err(_pos, _msg) do { \ |
| 4204 | *msg = _msg; \ |
| 4205 | *end = _pos; \ |
| 4206 | return false; \ |
| 4207 | } while (false) |
| 4208 | |
| 4209 | #define return_0() do { \ |
| 4210 | val->tag = YYJSON_TYPE_NUM | (u8)((u8)sign << 3); \ |
| 4211 | val->uni.u64 = 0; \ |
| 4212 | *end = cur; return true; \ |
| 4213 | } while (false) |
| 4214 | |
| 4215 | #define return_i64(_v) do { \ |
| 4216 | val->tag = YYJSON_TYPE_NUM | (u8)((u8)sign << 3); \ |
| 4217 | val->uni.u64 = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \ |
| 4218 | *end = cur; return true; \ |
| 4219 | } while (false) |
| 4220 | |
| 4221 | #define return_f64(_v) do { \ |
| 4222 | val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \ |
| 4223 | val->uni.f64 = sign ? -(f64)(_v) : (f64)(_v); \ |
| 4224 | *end = cur; return true; \ |
| 4225 | } while (false) |
| 4226 | |
| 4227 | #define return_f64_bin(_v) do { \ |
| 4228 | val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \ |
| 4229 | val->uni.u64 = ((u64)sign << 63) | (u64)(_v); \ |
| 4230 | *end = cur; return true; \ |
| 4231 | } while (false) |
| 4232 | |
| 4233 | #define return_inf() do { \ |
| 4234 | if (flg & YYJSON_READ_BIGNUM_AS_RAW) return_raw(); \ |
| 4235 | if (flg & YYJSON_READ_ALLOW_INF_AND_NAN) return_f64_bin(F64_RAW_INF); \ |
| 4236 | else return_err(hdr, "number is infinity when parsed as double"); \ |
| 4237 | } while (false) |
| 4238 | |
| 4239 | #define return_raw() do { \ |
| 4240 | if (*pre) **pre = '\0'; /* add null-terminator for previous raw string */ \ |
| 4241 | val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \ |
| 4242 | val->uni.str = (const char *)hdr; \ |
| 4243 | *pre = cur; *end = cur; return true; \ |
| 4244 | } while (false) |
| 4245 | |
| 4246 | u8 *sig_cut = NULL; /* significant part cutting position for long number */ |
| 4247 | u8 *sig_end = NULL; /* significant part ending position */ |
| 4248 | u8 *dot_pos = NULL; /* decimal point position */ |
| 4249 | |
| 4250 | u64 sig = 0; /* significant part of the number */ |
| 4251 | i32 exp = 0; /* exponent part of the number */ |
| 4252 | |
| 4253 | bool exp_sign; /* temporary exponent sign from literal part */ |
| 4254 | i64 exp_sig = 0; /* temporary exponent number from significant part */ |
| 4255 | i64 exp_lit = 0; /* temporary exponent number from exponent literal part */ |
| 4256 | u64 num; /* temporary number for reading */ |
| 4257 | u8 *tmp; /* temporary cursor for reading */ |
| 4258 | |
| 4259 | u8 *hdr = *ptr; |
| 4260 | u8 *cur = *ptr; |
| 4261 | u8 **end = ptr; |
| 4262 | bool sign; |
| 4263 | |
| 4264 | /* read number as raw string if has `YYJSON_READ_NUMBER_AS_RAW` flag */ |
| 4265 | if (unlikely(pre && !(flg & YYJSON_READ_BIGNUM_AS_RAW))) { |
| 4266 | return read_number_raw(ptr, pre, flg, val, msg); |
| 4267 | } |
| 4268 | |
| 4269 | sign = (*hdr == '-'); |
| 4270 | cur += sign; |
| 4271 | |
| 4272 | /* begin with a leading zero or non-digit */ |
| 4273 | if (unlikely(!digi_is_nonzero(*cur))) { /* 0 or non-digit char */ |
| 4274 | if (unlikely(*cur != '0')) { /* non-digit char */ |
| 4275 | if (flg & YYJSON_READ_ALLOW_INF_AND_NAN) { |
| 4276 | if (read_inf_or_nan(sign, &cur, pre, val)) { |
| 4277 | *end = cur; |
| 4278 | return true; |
| 4279 | } |
| 4280 | } |
| 4281 | return_err(cur, "no digit after minus sign" ); |
| 4282 | } |
| 4283 | /* begin with 0 */ |
| 4284 | if (likely(!digi_is_digit_or_fp(*++cur))) return_0(); |
| 4285 | if (likely(*cur == '.')) { |
| 4286 | dot_pos = cur++; |
| 4287 | if (unlikely(!digi_is_digit(*cur))) { |
| 4288 | return_err(cur, "no digit after decimal point" ); |
| 4289 | } |
| 4290 | while (unlikely(*cur == '0')) cur++; |
| 4291 | if (likely(digi_is_digit(*cur))) { |
| 4292 | /* first non-zero digit after decimal point */ |
| 4293 | sig = (u64)(*cur - '0'); /* read first digit */ |
| 4294 | cur--; |
| 4295 | goto digi_frac_1; /* continue read fraction part */ |
| 4296 | } |
| 4297 | } |
| 4298 | if (unlikely(digi_is_digit(*cur))) { |
| 4299 | return_err(cur - 1, "number with leading zero is not allowed" ); |
| 4300 | } |
| 4301 | if (unlikely(digi_is_exp(*cur))) { /* 0 with any exponent is still 0 */ |
| 4302 | cur += (usize)1 + digi_is_sign(cur[1]); |
| 4303 | if (unlikely(!digi_is_digit(*cur))) { |
| 4304 | return_err(cur, "no digit after exponent sign" ); |
| 4305 | } |
| 4306 | while (digi_is_digit(*++cur)); |
| 4307 | } |
| 4308 | return_f64_bin(0); |
| 4309 | } |
| 4310 | |
| 4311 | /* begin with non-zero digit */ |
| 4312 | sig = (u64)(*cur - '0'); |
| 4313 | |
| 4314 | /* |
| 4315 | Read integral part, same as the following code. |
| 4316 | |
| 4317 | for (int i = 1; i <= 18; i++) { |
| 4318 | num = cur[i] - '0'; |
| 4319 | if (num <= 9) sig = num + sig * 10; |
| 4320 | else goto digi_sepr_i; |
| 4321 | } |
| 4322 | */ |
| 4323 | #define expr_intg(i) \ |
| 4324 | if (likely((num = (u64)(cur[i] - (u8)'0')) <= 9)) sig = num + sig * 10; \ |
| 4325 | else { goto digi_sepr_##i; } |
| 4326 | repeat_in_1_18(expr_intg) |
| 4327 | #undef expr_intg |
| 4328 | |
| 4329 | |
| 4330 | cur += 19; /* skip continuous 19 digits */ |
| 4331 | if (!digi_is_digit_or_fp(*cur)) { |
| 4332 | /* this number is an integer consisting of 19 digits */ |
| 4333 | if (sign && (sig > ((u64)1 << 63))) { /* overflow */ |
| 4334 | if (flg & YYJSON_READ_BIGNUM_AS_RAW) return_raw(); |
| 4335 | return_f64(normalized_u64_to_f64(sig)); |
| 4336 | } |
| 4337 | return_i64(sig); |
| 4338 | } |
| 4339 | goto digi_intg_more; /* read more digits in integral part */ |
| 4340 | |
| 4341 | |
| 4342 | /* process first non-digit character */ |
| 4343 | #define expr_sepr(i) \ |
| 4344 | digi_sepr_##i: \ |
| 4345 | if (likely(!digi_is_fp(cur[i]))) { cur += i; return_i64(sig); } \ |
| 4346 | dot_pos = cur + i; \ |
| 4347 | if (likely(cur[i] == '.')) goto digi_frac_##i; \ |
| 4348 | cur += i; sig_end = cur; goto digi_exp_more; |
| 4349 | repeat_in_1_18(expr_sepr) |
| 4350 | #undef expr_sepr |
| 4351 | |
| 4352 | |
| 4353 | /* read fraction part */ |
| 4354 | #define expr_frac(i) \ |
| 4355 | digi_frac_##i: \ |
| 4356 | if (likely((num = (u64)(cur[i + 1] - (u8)'0')) <= 9)) \ |
| 4357 | sig = num + sig * 10; \ |
| 4358 | else { goto digi_stop_##i; } |
| 4359 | repeat_in_1_18(expr_frac) |
| 4360 | #undef expr_frac |
| 4361 | |
| 4362 | cur += 20; /* skip 19 digits and 1 decimal point */ |
| 4363 | if (!digi_is_digit(*cur)) goto digi_frac_end; /* fraction part end */ |
| 4364 | goto digi_frac_more; /* read more digits in fraction part */ |
| 4365 | |
| 4366 | |
| 4367 | /* significant part end */ |
| 4368 | #define expr_stop(i) \ |
| 4369 | digi_stop_##i: \ |
| 4370 | cur += i + 1; \ |
| 4371 | goto digi_frac_end; |
| 4372 | repeat_in_1_18(expr_stop) |
| 4373 | #undef expr_stop |
| 4374 | |
| 4375 | |
| 4376 | /* read more digits in integral part */ |
| 4377 | digi_intg_more: |
| 4378 | if (digi_is_digit(*cur)) { |
| 4379 | if (!digi_is_digit_or_fp(cur[1])) { |
| 4380 | /* this number is an integer consisting of 20 digits */ |
| 4381 | num = (u64)(*cur - '0'); |
| 4382 | if ((sig < (U64_MAX / 10)) || |
| 4383 | (sig == (U64_MAX / 10) && num <= (U64_MAX % 10))) { |
| 4384 | sig = num + sig * 10; |
| 4385 | cur++; |
| 4386 | /* convert to double if overflow */ |
| 4387 | if (sign) { |
| 4388 | if (flg & YYJSON_READ_BIGNUM_AS_RAW) return_raw(); |
| 4389 | return_f64(normalized_u64_to_f64(sig)); |
| 4390 | } |
| 4391 | return_i64(sig); |
| 4392 | } |
| 4393 | } |
| 4394 | } |
| 4395 | |
| 4396 | if (digi_is_exp(*cur)) { |
| 4397 | dot_pos = cur; |
| 4398 | goto digi_exp_more; |
| 4399 | } |
| 4400 | |
| 4401 | if (*cur == '.') { |
| 4402 | dot_pos = cur++; |
| 4403 | if (!digi_is_digit(*cur)) { |
| 4404 | return_err(cur, "no digit after decimal point" ); |
| 4405 | } |
| 4406 | } |
| 4407 | |
| 4408 | |
| 4409 | /* read more digits in fraction part */ |
| 4410 | digi_frac_more: |
| 4411 | sig_cut = cur; /* too large to fit in u64, excess digits need to be cut */ |
| 4412 | sig += (*cur >= '5'); /* round */ |
| 4413 | while (digi_is_digit(*++cur)); |
| 4414 | if (!dot_pos) { |
| 4415 | if (!digi_is_fp(*cur) && (flg & YYJSON_READ_BIGNUM_AS_RAW)) { |
| 4416 | return_raw(); /* it's a large integer */ |
| 4417 | } |
| 4418 | dot_pos = cur; |
| 4419 | if (*cur == '.') { |
| 4420 | if (!digi_is_digit(*++cur)) { |
| 4421 | return_err(cur, "no digit after decimal point" ); |
| 4422 | } |
| 4423 | while (digi_is_digit(*cur)) cur++; |
| 4424 | } |
| 4425 | } |
| 4426 | exp_sig = (i64)(dot_pos - sig_cut); |
| 4427 | exp_sig += (dot_pos < sig_cut); |
| 4428 | |
| 4429 | /* ignore trailing zeros */ |
| 4430 | tmp = cur - 1; |
| 4431 | while (*tmp == '0' || *tmp == '.') tmp--; |
| 4432 | if (tmp < sig_cut) { |
| 4433 | sig_cut = NULL; |
| 4434 | } else { |
| 4435 | sig_end = cur; |
| 4436 | } |
| 4437 | |
| 4438 | if (digi_is_exp(*cur)) goto digi_exp_more; |
| 4439 | goto digi_exp_finish; |
| 4440 | |
| 4441 | |
| 4442 | /* fraction part end */ |
| 4443 | digi_frac_end: |
| 4444 | if (unlikely(dot_pos + 1 == cur)) { |
| 4445 | return_err(cur, "no digit after decimal point" ); |
| 4446 | } |
| 4447 | sig_end = cur; |
| 4448 | exp_sig = -(i64)((u64)(cur - dot_pos) - 1); |
| 4449 | if (likely(!digi_is_exp(*cur))) { |
| 4450 | if (unlikely(exp_sig < F64_MIN_DEC_EXP - 19)) { |
| 4451 | return_f64_bin(0); /* underflow */ |
| 4452 | } |
| 4453 | exp = (i32)exp_sig; |
| 4454 | goto digi_finish; |
| 4455 | } else { |
| 4456 | goto digi_exp_more; |
| 4457 | } |
| 4458 | |
| 4459 | |
| 4460 | /* read exponent part */ |
| 4461 | digi_exp_more: |
| 4462 | exp_sign = (*++cur == '-'); |
| 4463 | cur += digi_is_sign(*cur); |
| 4464 | if (unlikely(!digi_is_digit(*cur))) { |
| 4465 | return_err(cur, "no digit after exponent sign" ); |
| 4466 | } |
| 4467 | while (*cur == '0') cur++; |
| 4468 | |
| 4469 | /* read exponent literal */ |
| 4470 | tmp = cur; |
| 4471 | while (digi_is_digit(*cur)) { |
| 4472 | exp_lit = (i64)((u8)(*cur++ - '0') + (u64)exp_lit * 10); |
| 4473 | } |
| 4474 | if (unlikely(cur - tmp >= U64_SAFE_DIG)) { |
| 4475 | if (exp_sign) { |
| 4476 | return_f64_bin(0); /* underflow */ |
| 4477 | } else { |
| 4478 | return_inf(); /* overflow */ |
| 4479 | } |
| 4480 | } |
| 4481 | exp_sig += exp_sign ? -exp_lit : exp_lit; |
| 4482 | |
| 4483 | |
| 4484 | /* validate exponent value */ |
| 4485 | digi_exp_finish: |
| 4486 | if (unlikely(exp_sig < F64_MIN_DEC_EXP - 19)) { |
| 4487 | return_f64_bin(0); /* underflow */ |
| 4488 | } |
| 4489 | if (unlikely(exp_sig > F64_MAX_DEC_EXP)) { |
| 4490 | return_inf(); /* overflow */ |
| 4491 | } |
| 4492 | exp = (i32)exp_sig; |
| 4493 | |
| 4494 | |
| 4495 | /* all digit read finished */ |
| 4496 | digi_finish: |
| 4497 | |
| 4498 | /* |
| 4499 | Fast path 1: |
| 4500 | |
| 4501 | 1. The floating-point number calculation should be accurate, see the |
| 4502 | comments of macro `YYJSON_DOUBLE_MATH_CORRECT`. |
| 4503 | 2. Correct rounding should be performed (fegetround() == FE_TONEAREST). |
| 4504 | 3. The input of floating point number calculation does not lose precision, |
| 4505 | which means: 64 - leading_zero(input) - trailing_zero(input) < 53. |
| 4506 | |
| 4507 | We don't check all available inputs here, because that would make the code |
| 4508 | more complicated, and not friendly to branch predictor. |
| 4509 | */ |
| 4510 | #if YYJSON_DOUBLE_MATH_CORRECT |
| 4511 | if (sig < ((u64)1 << 53) && |
| 4512 | exp >= -F64_POW10_EXP_MAX_EXACT && |
| 4513 | exp <= +F64_POW10_EXP_MAX_EXACT) { |
| 4514 | f64 dbl = (f64)sig; |
| 4515 | if (exp < 0) { |
| 4516 | dbl /= f64_pow10_table[-exp]; |
| 4517 | } else { |
| 4518 | dbl *= f64_pow10_table[+exp]; |
| 4519 | } |
| 4520 | return_f64(dbl); |
| 4521 | } |
| 4522 | #endif |
| 4523 | |
| 4524 | /* |
| 4525 | Fast path 2: |
| 4526 | |
| 4527 | To keep it simple, we only accept normal number here, |
| 4528 | let the slow path to handle subnormal and infinity number. |
| 4529 | */ |
| 4530 | if (likely(!sig_cut && |
| 4531 | exp > -F64_MAX_DEC_EXP + 1 && |
| 4532 | exp < +F64_MAX_DEC_EXP - 20)) { |
| 4533 | /* |
| 4534 | The result value is exactly equal to (sig * 10^exp), |
| 4535 | the exponent part (10^exp) can be converted to (sig2 * 2^exp2). |
| 4536 | |
| 4537 | The sig2 can be an infinite length number, only the highest 128 bits |
| 4538 | is cached in the pow10_sig_table. |
| 4539 | |
| 4540 | Now we have these bits: |
| 4541 | sig1 (normalized 64bit) : aaaaaaaa |
| 4542 | sig2 (higher 64bit) : bbbbbbbb |
| 4543 | sig2_ext (lower 64bit) : cccccccc |
| 4544 | sig2_cut (extra unknown bits) : dddddddddddd.... |
| 4545 | |
| 4546 | And the calculation process is: |
| 4547 | ---------------------------------------- |
| 4548 | aaaaaaaa * |
| 4549 | bbbbbbbbccccccccdddddddddddd.... |
| 4550 | ---------------------------------------- |
| 4551 | abababababababab + |
| 4552 | acacacacacacacac + |
| 4553 | adadadadadadadadadad.... |
| 4554 | ---------------------------------------- |
| 4555 | [hi____][lo____] + |
| 4556 | [hi2___][lo2___] + |
| 4557 | [unknown___________....] |
| 4558 | ---------------------------------------- |
| 4559 | |
| 4560 | The addition with carry may affect higher bits, but if there is a 0 |
| 4561 | in higher bits, the bits higher than 0 will not be affected. |
| 4562 | |
| 4563 | `lo2` + `unknown` may get a carry bit and may affect `hi2`, the max |
| 4564 | value of `hi2` is 0xFFFFFFFFFFFFFFFE, so `hi2` will not overflow. |
| 4565 | |
| 4566 | `lo` + `hi2` may also get a carry bit and may affect `hi`, but only |
| 4567 | the highest significant 53 bits of `hi` is needed. If there is a 0 |
| 4568 | in the lower bits of `hi`, then all the following bits can be dropped. |
| 4569 | |
| 4570 | To convert the result to IEEE-754 double number, we need to perform |
| 4571 | correct rounding: |
| 4572 | 1. if bit 54 is 0, round down, |
| 4573 | 2. if bit 54 is 1 and any bit beyond bit 54 is 1, round up, |
| 4574 | 3. if bit 54 is 1 and all bits beyond bit 54 are 0, round to even, |
| 4575 | as the extra bits is unknown, this case will not be handled here. |
| 4576 | */ |
| 4577 | |
| 4578 | u64 raw; |
| 4579 | u64 sig1, sig2, sig2_ext, hi, lo, hi2, lo2, add, bits; |
| 4580 | i32 exp2; |
| 4581 | u32 lz; |
| 4582 | bool exact = false, carry, round_up; |
| 4583 | |
| 4584 | /* convert (10^exp) to (sig2 * 2^exp2) */ |
| 4585 | pow10_table_get_sig(exp, &sig2, &sig2_ext); |
| 4586 | pow10_table_get_exp(exp, &exp2); |
| 4587 | |
| 4588 | /* normalize and multiply */ |
| 4589 | lz = u64_lz_bits(sig); |
| 4590 | sig1 = sig << lz; |
| 4591 | exp2 -= (i32)lz; |
| 4592 | u128_mul(sig1, sig2, &hi, &lo); |
| 4593 | |
| 4594 | /* |
| 4595 | The `hi` is in range [0x4000000000000000, 0xFFFFFFFFFFFFFFFE], |
| 4596 | To get normalized value, `hi` should be shifted to the left by 0 or 1. |
| 4597 | |
| 4598 | The highest significant 53 bits is used by IEEE-754 double number, |
| 4599 | and the bit 54 is used to detect rounding direction. |
| 4600 | |
| 4601 | The lowest (64 - 54 - 1) bits is used to check whether it contains 0. |
| 4602 | */ |
| 4603 | bits = hi & (((u64)1 << (64 - 54 - 1)) - 1); |
| 4604 | if (bits - 1 < (((u64)1 << (64 - 54 - 1)) - 2)) { |
| 4605 | /* |
| 4606 | (bits != 0 && bits != 0x1FF) => (bits - 1 < 0x1FF - 1) |
| 4607 | The `bits` is not zero, so we don't need to check `round to even` |
| 4608 | case. The `bits` contains bit `0`, so we can drop the extra bits |
| 4609 | after `0`. |
| 4610 | */ |
| 4611 | exact = true; |
| 4612 | |
| 4613 | } else { |
| 4614 | /* |
| 4615 | (bits == 0 || bits == 0x1FF) |
| 4616 | The `bits` is filled with all `0` or all `1`, so we need to check |
| 4617 | lower bits with another 64-bit multiplication. |
| 4618 | */ |
| 4619 | u128_mul(sig1, sig2_ext, &hi2, &lo2); |
| 4620 | |
| 4621 | add = lo + hi2; |
| 4622 | if (add + 1 > (u64)1) { |
| 4623 | /* |
| 4624 | (add != 0 && add != U64_MAX) => (add + 1 > 1) |
| 4625 | The `add` is not zero, so we don't need to check `round to |
| 4626 | even` case. The `add` contains bit `0`, so we can drop the |
| 4627 | extra bits after `0`. The `hi` cannot be U64_MAX, so it will |
| 4628 | not overflow. |
| 4629 | */ |
| 4630 | carry = add < lo || add < hi2; |
| 4631 | hi += carry; |
| 4632 | exact = true; |
| 4633 | } |
| 4634 | } |
| 4635 | |
| 4636 | if (exact) { |
| 4637 | /* normalize */ |
| 4638 | lz = hi < ((u64)1 << 63); |
| 4639 | hi <<= lz; |
| 4640 | exp2 -= (i32)lz; |
| 4641 | exp2 += 64; |
| 4642 | |
| 4643 | /* test the bit 54 and get rounding direction */ |
| 4644 | round_up = (hi & ((u64)1 << (64 - 54))) > (u64)0; |
| 4645 | hi += (round_up ? ((u64)1 << (64 - 54)) : (u64)0); |
| 4646 | |
| 4647 | /* test overflow */ |
| 4648 | if (hi < ((u64)1 << (64 - 54))) { |
| 4649 | hi = ((u64)1 << 63); |
| 4650 | exp2 += 1; |
| 4651 | } |
| 4652 | |
| 4653 | /* This is a normal number, convert it to IEEE-754 format. */ |
| 4654 | hi >>= F64_BITS - F64_SIG_FULL_BITS; |
| 4655 | exp2 += F64_BITS - F64_SIG_FULL_BITS + F64_SIG_BITS; |
| 4656 | exp2 += F64_EXP_BIAS; |
| 4657 | raw = ((u64)exp2 << F64_SIG_BITS) | (hi & F64_SIG_MASK); |
| 4658 | return_f64_bin(raw); |
| 4659 | } |
| 4660 | } |
| 4661 | |
| 4662 | /* |
| 4663 | Slow path: read double number exactly with diyfp. |
| 4664 | 1. Use cached diyfp to get an approximation value. |
| 4665 | 2. Use bigcomp to check the approximation value if needed. |
| 4666 | |
| 4667 | This algorithm refers to google's double-conversion project: |
| 4668 | https://github.com/google/double-conversion |
| 4669 | */ |
| 4670 | { |
| 4671 | const i32 ERR_ULP_LOG = 3; |
| 4672 | const i32 ERR_ULP = 1 << ERR_ULP_LOG; |
| 4673 | const i32 ERR_CACHED_POW = ERR_ULP / 2; |
| 4674 | const i32 ERR_MUL_FIXED = ERR_ULP / 2; |
| 4675 | const i32 DIY_SIG_BITS = 64; |
| 4676 | const i32 EXP_BIAS = F64_EXP_BIAS + F64_SIG_BITS; |
| 4677 | const i32 EXP_SUBNORMAL = -EXP_BIAS + 1; |
| 4678 | |
| 4679 | u64 fp_err; |
| 4680 | u32 bits; |
| 4681 | i32 order_of_magnitude; |
| 4682 | i32 effective_significand_size; |
| 4683 | i32 precision_digits_count; |
| 4684 | u64 precision_bits; |
| 4685 | u64 half_way; |
| 4686 | |
| 4687 | u64 raw; |
| 4688 | diy_fp fp, fp_upper; |
| 4689 | bigint big_full, big_comp; |
| 4690 | i32 cmp; |
| 4691 | |
| 4692 | fp.sig = sig; |
| 4693 | fp.exp = 0; |
| 4694 | fp_err = sig_cut ? (u64)(ERR_ULP / 2) : (u64)0; |
| 4695 | |
| 4696 | /* normalize */ |
| 4697 | bits = u64_lz_bits(fp.sig); |
| 4698 | fp.sig <<= bits; |
| 4699 | fp.exp -= (i32)bits; |
| 4700 | fp_err <<= bits; |
| 4701 | |
| 4702 | /* multiply and add error */ |
| 4703 | fp = diy_fp_mul(fp, diy_fp_get_cached_pow10(exp)); |
| 4704 | fp_err += (u64)ERR_CACHED_POW + (fp_err != 0) + (u64)ERR_MUL_FIXED; |
| 4705 | |
| 4706 | /* normalize */ |
| 4707 | bits = u64_lz_bits(fp.sig); |
| 4708 | fp.sig <<= bits; |
| 4709 | fp.exp -= (i32)bits; |
| 4710 | fp_err <<= bits; |
| 4711 | |
| 4712 | /* effective significand */ |
| 4713 | order_of_magnitude = DIY_SIG_BITS + fp.exp; |
| 4714 | if (likely(order_of_magnitude >= EXP_SUBNORMAL + F64_SIG_FULL_BITS)) { |
| 4715 | effective_significand_size = F64_SIG_FULL_BITS; |
| 4716 | } else if (order_of_magnitude <= EXP_SUBNORMAL) { |
| 4717 | effective_significand_size = 0; |
| 4718 | } else { |
| 4719 | effective_significand_size = order_of_magnitude - EXP_SUBNORMAL; |
| 4720 | } |
| 4721 | |
| 4722 | /* precision digits count */ |
| 4723 | precision_digits_count = DIY_SIG_BITS - effective_significand_size; |
| 4724 | if (unlikely(precision_digits_count + ERR_ULP_LOG >= DIY_SIG_BITS)) { |
| 4725 | i32 shr = (precision_digits_count + ERR_ULP_LOG) - DIY_SIG_BITS + 1; |
| 4726 | fp.sig >>= shr; |
| 4727 | fp.exp += shr; |
| 4728 | fp_err = (fp_err >> shr) + 1 + (u32)ERR_ULP; |
| 4729 | precision_digits_count -= shr; |
| 4730 | } |
| 4731 | |
| 4732 | /* half way */ |
| 4733 | precision_bits = fp.sig & (((u64)1 << precision_digits_count) - 1); |
| 4734 | precision_bits *= (u32)ERR_ULP; |
| 4735 | half_way = (u64)1 << (precision_digits_count - 1); |
| 4736 | half_way *= (u32)ERR_ULP; |
| 4737 | |
| 4738 | /* rounding */ |
| 4739 | fp.sig >>= precision_digits_count; |
| 4740 | fp.sig += (precision_bits >= half_way + fp_err); |
| 4741 | fp.exp += precision_digits_count; |
| 4742 | |
| 4743 | /* get IEEE double raw value */ |
| 4744 | raw = diy_fp_to_ieee_raw(fp); |
| 4745 | if (unlikely(raw == F64_RAW_INF)) return_inf(); |
| 4746 | if (likely(precision_bits <= half_way - fp_err || |
| 4747 | precision_bits >= half_way + fp_err)) { |
| 4748 | return_f64_bin(raw); /* number is accurate */ |
| 4749 | } |
| 4750 | /* now the number is the correct value, or the next lower value */ |
| 4751 | |
| 4752 | /* upper boundary */ |
| 4753 | if (raw & F64_EXP_MASK) { |
| 4754 | fp_upper.sig = (raw & F64_SIG_MASK) + ((u64)1 << F64_SIG_BITS); |
| 4755 | fp_upper.exp = (i32)((raw & F64_EXP_MASK) >> F64_SIG_BITS); |
| 4756 | } else { |
| 4757 | fp_upper.sig = (raw & F64_SIG_MASK); |
| 4758 | fp_upper.exp = 1; |
| 4759 | } |
| 4760 | fp_upper.exp -= F64_EXP_BIAS + F64_SIG_BITS; |
| 4761 | fp_upper.sig <<= 1; |
| 4762 | fp_upper.exp -= 1; |
| 4763 | fp_upper.sig += 1; /* add half ulp */ |
| 4764 | |
| 4765 | /* compare with bigint */ |
| 4766 | bigint_set_buf(&big_full, sig, &exp, sig_cut, sig_end, dot_pos); |
| 4767 | bigint_set_u64(&big_comp, fp_upper.sig); |
| 4768 | if (exp >= 0) { |
| 4769 | bigint_mul_pow10(&big_full, +exp); |
| 4770 | } else { |
| 4771 | bigint_mul_pow10(&big_comp, -exp); |
| 4772 | } |
| 4773 | if (fp_upper.exp > 0) { |
| 4774 | bigint_mul_pow2(&big_comp, (u32)+fp_upper.exp); |
| 4775 | } else { |
| 4776 | bigint_mul_pow2(&big_full, (u32)-fp_upper.exp); |
| 4777 | } |
| 4778 | cmp = bigint_cmp(&big_full, &big_comp); |
| 4779 | if (likely(cmp != 0)) { |
| 4780 | /* round down or round up */ |
| 4781 | raw += (cmp > 0); |
| 4782 | } else { |
| 4783 | /* falls midway, round to even */ |
| 4784 | raw += (raw & 1); |
| 4785 | } |
| 4786 | |
| 4787 | if (unlikely(raw == F64_RAW_INF)) return_inf(); |
| 4788 | return_f64_bin(raw); |
| 4789 | } |
| 4790 | |
| 4791 | #undef return_err |
| 4792 | #undef return_inf |
| 4793 | #undef return_0 |
| 4794 | #undef return_i64 |
| 4795 | #undef return_f64 |
| 4796 | #undef return_f64_bin |
| 4797 | #undef return_raw |
| 4798 | } |
| 4799 | |
| 4800 | |
| 4801 | |
| 4802 | #else /* FP_READER */ |
| 4803 | |
| 4804 | /** |
| 4805 | Read a JSON number. |
| 4806 | This is a fallback function if the custom number reader is disabled. |
| 4807 | This function use libc's strtod() to read floating-point number. |
| 4808 | */ |
| 4809 | static_inline bool read_number(u8 **ptr, |
| 4810 | u8 **pre, |
| 4811 | yyjson_read_flag flg, |
| 4812 | yyjson_val *val, |
| 4813 | const char **msg) { |
| 4814 | |
| 4815 | #define return_err(_pos, _msg) do { \ |
| 4816 | *msg = _msg; \ |
| 4817 | *end = _pos; \ |
| 4818 | return false; \ |
| 4819 | } while (false) |
| 4820 | |
| 4821 | #define return_0() do { \ |
| 4822 | val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); \ |
| 4823 | val->uni.u64 = 0; \ |
| 4824 | *end = cur; return true; \ |
| 4825 | } while (false) |
| 4826 | |
| 4827 | #define return_i64(_v) do { \ |
| 4828 | val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); \ |
| 4829 | val->uni.u64 = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \ |
| 4830 | *end = cur; return true; \ |
| 4831 | } while (false) |
| 4832 | |
| 4833 | #define return_f64(_v) do { \ |
| 4834 | val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \ |
| 4835 | val->uni.f64 = sign ? -(f64)(_v) : (f64)(_v); \ |
| 4836 | *end = cur; return true; \ |
| 4837 | } while (false) |
| 4838 | |
| 4839 | #define return_f64_bin(_v) do { \ |
| 4840 | val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \ |
| 4841 | val->uni.u64 = ((u64)sign << 63) | (u64)(_v); \ |
| 4842 | *end = cur; return true; \ |
| 4843 | } while (false) |
| 4844 | |
| 4845 | #define return_inf() do { \ |
| 4846 | if (flg & YYJSON_READ_BIGNUM_AS_RAW) return_raw(); \ |
| 4847 | if (flg & YYJSON_READ_ALLOW_INF_AND_NAN) return_f64_bin(F64_RAW_INF); \ |
| 4848 | else return_err(hdr, "number is infinity when parsed as double"); \ |
| 4849 | } while (false) |
| 4850 | |
| 4851 | #define return_raw() do { \ |
| 4852 | if (*pre) **pre = '\0'; /* add null-terminator for previous raw string */ \ |
| 4853 | val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \ |
| 4854 | val->uni.str = (const char *)hdr; \ |
| 4855 | *pre = cur; *end = cur; return true; \ |
| 4856 | } while (false) |
| 4857 | |
| 4858 | u64 sig, num; |
| 4859 | u8 *hdr = *ptr; |
| 4860 | u8 *cur = *ptr; |
| 4861 | u8 **end = ptr; |
| 4862 | u8 *dot = NULL; |
| 4863 | u8 *f64_end = NULL; |
| 4864 | bool sign; |
| 4865 | |
| 4866 | /* read number as raw string if has `YYJSON_READ_NUMBER_AS_RAW` flag */ |
| 4867 | if (unlikely(pre && !(flg & YYJSON_READ_BIGNUM_AS_RAW))) { |
| 4868 | return read_number_raw(ptr, pre, flg, val, msg); |
| 4869 | } |
| 4870 | |
| 4871 | sign = (*hdr == '-'); |
| 4872 | cur += sign; |
| 4873 | sig = (u8)(*cur - '0'); |
| 4874 | |
| 4875 | /* read first digit, check leading zero */ |
| 4876 | if (unlikely(!digi_is_digit(*cur))) { |
| 4877 | if (flg & YYJSON_READ_ALLOW_INF_AND_NAN) { |
| 4878 | if (read_inf_or_nan(sign, &cur, pre, val)) { |
| 4879 | *end = cur; |
| 4880 | return true; |
| 4881 | } |
| 4882 | } |
| 4883 | return_err(cur, "no digit after minus sign" ); |
| 4884 | } |
| 4885 | if (*cur == '0') { |
| 4886 | cur++; |
| 4887 | if (unlikely(digi_is_digit(*cur))) { |
| 4888 | return_err(cur - 1, "number with leading zero is not allowed" ); |
| 4889 | } |
| 4890 | if (!digi_is_fp(*cur)) return_0(); |
| 4891 | goto read_double; |
| 4892 | } |
| 4893 | |
| 4894 | /* read continuous digits, up to 19 characters */ |
| 4895 | #define expr_intg(i) \ |
| 4896 | if (likely((num = (u64)(cur[i] - (u8)'0')) <= 9)) sig = num + sig * 10; \ |
| 4897 | else { cur += i; goto intg_end; } |
| 4898 | repeat_in_1_18(expr_intg) |
| 4899 | #undef expr_intg |
| 4900 | |
| 4901 | /* here are 19 continuous digits, skip them */ |
| 4902 | cur += 19; |
| 4903 | if (digi_is_digit(cur[0]) && !digi_is_digit_or_fp(cur[1])) { |
| 4904 | /* this number is an integer consisting of 20 digits */ |
| 4905 | num = (u8)(*cur - '0'); |
| 4906 | if ((sig < (U64_MAX / 10)) || |
| 4907 | (sig == (U64_MAX / 10) && num <= (U64_MAX % 10))) { |
| 4908 | sig = num + sig * 10; |
| 4909 | cur++; |
| 4910 | if (sign) { |
| 4911 | if (flg & YYJSON_READ_BIGNUM_AS_RAW) return_raw(); |
| 4912 | return_f64(normalized_u64_to_f64(sig)); |
| 4913 | } |
| 4914 | return_i64(sig); |
| 4915 | } |
| 4916 | } |
| 4917 | |
| 4918 | intg_end: |
| 4919 | /* continuous digits ended */ |
| 4920 | if (!digi_is_digit_or_fp(*cur)) { |
| 4921 | /* this number is an integer consisting of 1 to 19 digits */ |
| 4922 | if (sign && (sig > ((u64)1 << 63))) { |
| 4923 | if (flg & YYJSON_READ_BIGNUM_AS_RAW) return_raw(); |
| 4924 | return_f64(normalized_u64_to_f64(sig)); |
| 4925 | } |
| 4926 | return_i64(sig); |
| 4927 | } |
| 4928 | |
| 4929 | read_double: |
| 4930 | /* this number should be read as double */ |
| 4931 | while (digi_is_digit(*cur)) cur++; |
| 4932 | if (!digi_is_fp(*cur) && (flg & YYJSON_READ_BIGNUM_AS_RAW)) { |
| 4933 | return_raw(); /* it's a large integer */ |
| 4934 | } |
| 4935 | if (*cur == '.') { |
| 4936 | /* skip fraction part */ |
| 4937 | dot = cur; |
| 4938 | cur++; |
| 4939 | if (!digi_is_digit(*cur)) { |
| 4940 | return_err(cur, "no digit after decimal point" ); |
| 4941 | } |
| 4942 | cur++; |
| 4943 | while (digi_is_digit(*cur)) cur++; |
| 4944 | } |
| 4945 | if (digi_is_exp(*cur)) { |
| 4946 | /* skip exponent part */ |
| 4947 | cur += 1 + digi_is_sign(cur[1]); |
| 4948 | if (!digi_is_digit(*cur)) { |
| 4949 | return_err(cur, "no digit after exponent sign" ); |
| 4950 | } |
| 4951 | cur++; |
| 4952 | while (digi_is_digit(*cur)) cur++; |
| 4953 | } |
| 4954 | |
| 4955 | /* |
| 4956 | libc's strtod() is used to parse the floating-point number. |
| 4957 | |
| 4958 | Note that the decimal point character used by strtod() is locale-dependent, |
| 4959 | and the rounding direction may affected by fesetround(). |
| 4960 | |
| 4961 | For currently known locales, (en, zh, ja, ko, am, he, hi) use '.' as the |
| 4962 | decimal point, while other locales use ',' as the decimal point. |
| 4963 | |
| 4964 | Here strtod() is called twice for different locales, but if another thread |
| 4965 | happens calls setlocale() between two strtod(), parsing may still fail. |
| 4966 | */ |
| 4967 | val->uni.f64 = strtod((const char *)hdr, (char **)&f64_end); |
| 4968 | if (unlikely(f64_end != cur)) { |
| 4969 | /* replace '.' with ',' for locale */ |
| 4970 | bool cut = (*cur == ','); |
| 4971 | if (cut) *cur = ' '; |
| 4972 | if (dot) *dot = ','; |
| 4973 | val->uni.f64 = strtod((const char *)hdr, (char **)&f64_end); |
| 4974 | /* restore ',' to '.' */ |
| 4975 | if (cut) *cur = ','; |
| 4976 | if (dot) *dot = '.'; |
| 4977 | if (unlikely(f64_end != cur)) { |
| 4978 | return_err(hdr, "strtod() failed to parse the number" ); |
| 4979 | } |
| 4980 | } |
| 4981 | if (unlikely(val->uni.f64 >= HUGE_VAL || val->uni.f64 <= -HUGE_VAL)) { |
| 4982 | return_inf(); |
| 4983 | } |
| 4984 | val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; |
| 4985 | *end = cur; |
| 4986 | return true; |
| 4987 | |
| 4988 | #undef return_err |
| 4989 | #undef return_0 |
| 4990 | #undef return_i64 |
| 4991 | #undef return_f64 |
| 4992 | #undef return_f64_bin |
| 4993 | #undef return_inf |
| 4994 | #undef return_raw |
| 4995 | } |
| 4996 | |
| 4997 | #endif /* FP_READER */ |
| 4998 | |
| 4999 | |
| 5000 | |
| 5001 | /*============================================================================== |
| 5002 | * JSON String Reader |
| 5003 | *============================================================================*/ |
| 5004 | |
| 5005 | /** |
| 5006 | Read a JSON string. |
| 5007 | @param ptr The head pointer of string before '"' prefix (inout). |
| 5008 | @param lst JSON last position. |
| 5009 | @param inv Allow invalid unicode. |
| 5010 | @param val The string value to be written. |
| 5011 | @param msg The error message pointer. |
| 5012 | @return Whether success. |
| 5013 | */ |
| 5014 | static_inline bool read_string(u8 **ptr, |
| 5015 | u8 *lst, |
| 5016 | bool inv, |
| 5017 | yyjson_val *val, |
| 5018 | const char **msg) { |
| 5019 | /* |
| 5020 | Each unicode code point is encoded as 1 to 4 bytes in UTF-8 encoding, |
| 5021 | we use 4-byte mask and pattern value to validate UTF-8 byte sequence, |
| 5022 | this requires the input data to have 4-byte zero padding. |
| 5023 | --------------------------------------------------- |
| 5024 | 1 byte |
| 5025 | unicode range [U+0000, U+007F] |
| 5026 | unicode min [.......0] |
| 5027 | unicode max [.1111111] |
| 5028 | bit pattern [0.......] |
| 5029 | --------------------------------------------------- |
| 5030 | 2 byte |
| 5031 | unicode range [U+0080, U+07FF] |
| 5032 | unicode min [......10 ..000000] |
| 5033 | unicode max [...11111 ..111111] |
| 5034 | bit require [...xxxx. ........] (1E 00) |
| 5035 | bit mask [xxx..... xx......] (E0 C0) |
| 5036 | bit pattern [110..... 10......] (C0 80) |
| 5037 | --------------------------------------------------- |
| 5038 | 3 byte |
| 5039 | unicode range [U+0800, U+FFFF] |
| 5040 | unicode min [........ ..100000 ..000000] |
| 5041 | unicode max [....1111 ..111111 ..111111] |
| 5042 | bit require [....xxxx ..x..... ........] (0F 20 00) |
| 5043 | bit mask [xxxx.... xx...... xx......] (F0 C0 C0) |
| 5044 | bit pattern [1110.... 10...... 10......] (E0 80 80) |
| 5045 | --------------------------------------------------- |
| 5046 | 3 byte invalid (reserved for surrogate halves) |
| 5047 | unicode range [U+D800, U+DFFF] |
| 5048 | unicode min [....1101 ..100000 ..000000] |
| 5049 | unicode max [....1101 ..111111 ..111111] |
| 5050 | bit mask [....xxxx ..x..... ........] (0F 20 00) |
| 5051 | bit pattern [....1101 ..1..... ........] (0D 20 00) |
| 5052 | --------------------------------------------------- |
| 5053 | 4 byte |
| 5054 | unicode range [U+10000, U+10FFFF] |
| 5055 | unicode min [........ ...10000 ..000000 ..000000] |
| 5056 | unicode max [.....100 ..001111 ..111111 ..111111] |
| 5057 | bit require [.....xxx ..xx.... ........ ........] (07 30 00 00) |
| 5058 | bit mask [xxxxx... xx...... xx...... xx......] (F8 C0 C0 C0) |
| 5059 | bit pattern [11110... 10...... 10...... 10......] (F0 80 80 80) |
| 5060 | --------------------------------------------------- |
| 5061 | */ |
| 5062 | #if YYJSON_ENDIAN == YYJSON_BIG_ENDIAN |
| 5063 | const u32 b1_mask = 0x80000000UL; |
| 5064 | const u32 b1_patt = 0x00000000UL; |
| 5065 | const u32 b2_mask = 0xE0C00000UL; |
| 5066 | const u32 b2_patt = 0xC0800000UL; |
| 5067 | const u32 b2_requ = 0x1E000000UL; |
| 5068 | const u32 b3_mask = 0xF0C0C000UL; |
| 5069 | const u32 b3_patt = 0xE0808000UL; |
| 5070 | const u32 b3_requ = 0x0F200000UL; |
| 5071 | const u32 b3_erro = 0x0D200000UL; |
| 5072 | const u32 b4_mask = 0xF8C0C0C0UL; |
| 5073 | const u32 b4_patt = 0xF0808080UL; |
| 5074 | const u32 b4_requ = 0x07300000UL; |
| 5075 | const u32 b4_err0 = 0x04000000UL; |
| 5076 | const u32 b4_err1 = 0x03300000UL; |
| 5077 | #elif YYJSON_ENDIAN == YYJSON_LITTLE_ENDIAN |
| 5078 | const u32 b1_mask = 0x00000080UL; |
| 5079 | const u32 b1_patt = 0x00000000UL; |
| 5080 | const u32 b2_mask = 0x0000C0E0UL; |
| 5081 | const u32 b2_patt = 0x000080C0UL; |
| 5082 | const u32 b2_requ = 0x0000001EUL; |
| 5083 | const u32 b3_mask = 0x00C0C0F0UL; |
| 5084 | const u32 b3_patt = 0x008080E0UL; |
| 5085 | const u32 b3_requ = 0x0000200FUL; |
| 5086 | const u32 b3_erro = 0x0000200DUL; |
| 5087 | const u32 b4_mask = 0xC0C0C0F8UL; |
| 5088 | const u32 b4_patt = 0x808080F0UL; |
| 5089 | const u32 b4_requ = 0x00003007UL; |
| 5090 | const u32 b4_err0 = 0x00000004UL; |
| 5091 | const u32 b4_err1 = 0x00003003UL; |
| 5092 | #else |
| 5093 | v32_uni b1_mask_uni = {{ 0x80, 0x00, 0x00, 0x00 }}; |
| 5094 | v32_uni b1_patt_uni = {{ 0x00, 0x00, 0x00, 0x00 }}; |
| 5095 | v32_uni b2_mask_uni = {{ 0xE0, 0xC0, 0x00, 0x00 }}; |
| 5096 | v32_uni b2_patt_uni = {{ 0xC0, 0x80, 0x00, 0x00 }}; |
| 5097 | v32_uni b2_requ_uni = {{ 0x1E, 0x00, 0x00, 0x00 }}; |
| 5098 | v32_uni b3_mask_uni = {{ 0xF0, 0xC0, 0xC0, 0x00 }}; |
| 5099 | v32_uni b3_patt_uni = {{ 0xE0, 0x80, 0x80, 0x00 }}; |
| 5100 | v32_uni b3_requ_uni = {{ 0x0F, 0x20, 0x00, 0x00 }}; |
| 5101 | v32_uni b3_erro_uni = {{ 0x0D, 0x20, 0x00, 0x00 }}; |
| 5102 | v32_uni b4_mask_uni = {{ 0xF8, 0xC0, 0xC0, 0xC0 }}; |
| 5103 | v32_uni b4_patt_uni = {{ 0xF0, 0x80, 0x80, 0x80 }}; |
| 5104 | v32_uni b4_requ_uni = {{ 0x07, 0x30, 0x00, 0x00 }}; |
| 5105 | v32_uni b4_err0_uni = {{ 0x04, 0x00, 0x00, 0x00 }}; |
| 5106 | v32_uni b4_err1_uni = {{ 0x03, 0x30, 0x00, 0x00 }}; |
| 5107 | u32 b1_mask = b1_mask_uni.u; |
| 5108 | u32 b1_patt = b1_patt_uni.u; |
| 5109 | u32 b2_mask = b2_mask_uni.u; |
| 5110 | u32 b2_patt = b2_patt_uni.u; |
| 5111 | u32 b2_requ = b2_requ_uni.u; |
| 5112 | u32 b3_mask = b3_mask_uni.u; |
| 5113 | u32 b3_patt = b3_patt_uni.u; |
| 5114 | u32 b3_requ = b3_requ_uni.u; |
| 5115 | u32 b3_erro = b3_erro_uni.u; |
| 5116 | u32 b4_mask = b4_mask_uni.u; |
| 5117 | u32 b4_patt = b4_patt_uni.u; |
| 5118 | u32 b4_requ = b4_requ_uni.u; |
| 5119 | u32 b4_err0 = b4_err0_uni.u; |
| 5120 | u32 b4_err1 = b4_err1_uni.u; |
| 5121 | #endif |
| 5122 | |
| 5123 | #define is_valid_seq_1(uni) ( \ |
| 5124 | ((uni & b1_mask) == b1_patt) \ |
| 5125 | ) |
| 5126 | |
| 5127 | #define is_valid_seq_2(uni) ( \ |
| 5128 | ((uni & b2_mask) == b2_patt) && \ |
| 5129 | ((uni & b2_requ)) \ |
| 5130 | ) |
| 5131 | |
| 5132 | #define is_valid_seq_3(uni) ( \ |
| 5133 | ((uni & b3_mask) == b3_patt) && \ |
| 5134 | ((tmp = (uni & b3_requ))) && \ |
| 5135 | ((tmp != b3_erro)) \ |
| 5136 | ) |
| 5137 | |
| 5138 | #define is_valid_seq_4(uni) ( \ |
| 5139 | ((uni & b4_mask) == b4_patt) && \ |
| 5140 | ((tmp = (uni & b4_requ))) && \ |
| 5141 | ((tmp & b4_err0) == 0 || (tmp & b4_err1) == 0) \ |
| 5142 | ) |
| 5143 | |
| 5144 | #define return_err(_end, _msg) do { \ |
| 5145 | *msg = _msg; \ |
| 5146 | *end = _end; \ |
| 5147 | return false; \ |
| 5148 | } while (false) |
| 5149 | |
| 5150 | u8 *cur = *ptr; |
| 5151 | u8 **end = ptr; |
| 5152 | u8 *src = ++cur, *dst, *pos; |
| 5153 | u16 hi, lo; |
| 5154 | u32 uni, tmp; |
| 5155 | |
| 5156 | skip_ascii: |
| 5157 | /* Most strings have no escaped characters, so we can jump them quickly. */ |
| 5158 | |
| 5159 | skip_ascii_begin: |
| 5160 | /* |
| 5161 | We want to make loop unrolling, as shown in the following code. Some |
| 5162 | compiler may not generate instructions as expected, so we rewrite it with |
| 5163 | explicit goto statements. We hope the compiler can generate instructions |
| 5164 | like this: https://godbolt.org/z/8vjsYq |
| 5165 | |
| 5166 | while (true) repeat16({ |
| 5167 | if (likely(!(char_is_ascii_stop(*src)))) src++; |
| 5168 | else break; |
| 5169 | }) |
| 5170 | */ |
| 5171 | #define expr_jump(i) \ |
| 5172 | if (likely(!char_is_ascii_stop(src[i]))) {} \ |
| 5173 | else goto skip_ascii_stop##i; |
| 5174 | |
| 5175 | #define expr_stop(i) \ |
| 5176 | skip_ascii_stop##i: \ |
| 5177 | src += i; \ |
| 5178 | goto skip_ascii_end; |
| 5179 | |
| 5180 | repeat16_incr(expr_jump) |
| 5181 | src += 16; |
| 5182 | goto skip_ascii_begin; |
| 5183 | repeat16_incr(expr_stop) |
| 5184 | |
| 5185 | #undef expr_jump |
| 5186 | #undef expr_stop |
| 5187 | |
| 5188 | skip_ascii_end: |
| 5189 | |
| 5190 | /* |
| 5191 | GCC may store src[i] in a register at each line of expr_jump(i) above. |
| 5192 | These instructions are useless and will degrade performance. |
| 5193 | This inline asm is a hint for gcc: "the memory has been modified, |
| 5194 | do not cache it". |
| 5195 | |
| 5196 | MSVC, Clang, ICC can generate expected instructions without this hint. |
| 5197 | */ |
| 5198 | #if YYJSON_IS_REAL_GCC |
| 5199 | __asm__ volatile("" :"=m" (*src)); |
| 5200 | #endif |
| 5201 | if (likely(*src == '"')) { |
| 5202 | val->tag = ((u64)(src - cur) << YYJSON_TAG_BIT) | |
| 5203 | (u64)(YYJSON_TYPE_STR | YYJSON_SUBTYPE_NOESC); |
| 5204 | val->uni.str = (const char *)cur; |
| 5205 | *src = '\0'; |
| 5206 | *end = src + 1; |
| 5207 | return true; |
| 5208 | } |
| 5209 | |
| 5210 | skip_utf8: |
| 5211 | if (*src & 0x80) { /* non-ASCII character */ |
| 5212 | /* |
| 5213 | Non-ASCII character appears here, which means that the text is likely |
| 5214 | to be written in non-English or emoticons. According to some common |
| 5215 | data set statistics, byte sequences of the same length may appear |
| 5216 | consecutively. We process the byte sequences of the same length in each |
| 5217 | loop, which is more friendly to branch prediction. |
| 5218 | */ |
| 5219 | pos = src; |
| 5220 | uni = byte_load_4(src); |
| 5221 | while (is_valid_seq_3(uni)) { |
| 5222 | src += 3; |
| 5223 | uni = byte_load_4(src); |
| 5224 | } |
| 5225 | if (is_valid_seq_1(uni)) goto skip_ascii; |
| 5226 | while (is_valid_seq_2(uni)) { |
| 5227 | src += 2; |
| 5228 | uni = byte_load_4(src); |
| 5229 | } |
| 5230 | while (is_valid_seq_4(uni)) { |
| 5231 | src += 4; |
| 5232 | uni = byte_load_4(src); |
| 5233 | } |
| 5234 | if (unlikely(pos == src)) { |
| 5235 | if (!inv) return_err(src, "invalid UTF-8 encoding in string" ); |
| 5236 | ++src; |
| 5237 | } |
| 5238 | goto skip_ascii; |
| 5239 | } |
| 5240 | |
| 5241 | /* The escape character appears, we need to copy it. */ |
| 5242 | dst = src; |
| 5243 | copy_escape: |
| 5244 | if (likely(*src == '\\')) { |
| 5245 | switch (*++src) { |
| 5246 | case '"': *dst++ = '"'; src++; break; |
| 5247 | case '\\': *dst++ = '\\'; src++; break; |
| 5248 | case '/': *dst++ = '/'; src++; break; |
| 5249 | case 'b': *dst++ = '\b'; src++; break; |
| 5250 | case 'f': *dst++ = '\f'; src++; break; |
| 5251 | case 'n': *dst++ = '\n'; src++; break; |
| 5252 | case 'r': *dst++ = '\r'; src++; break; |
| 5253 | case 't': *dst++ = '\t'; src++; break; |
| 5254 | case 'u': |
| 5255 | if (unlikely(!read_hex_u16(++src, &hi))) { |
| 5256 | return_err(src - 2, "invalid escaped sequence in string" ); |
| 5257 | } |
| 5258 | src += 4; |
| 5259 | if (likely((hi & 0xF800) != 0xD800)) { |
| 5260 | /* a BMP character */ |
| 5261 | if (hi >= 0x800) { |
| 5262 | *dst++ = (u8)(0xE0 | (hi >> 12)); |
| 5263 | *dst++ = (u8)(0x80 | ((hi >> 6) & 0x3F)); |
| 5264 | *dst++ = (u8)(0x80 | (hi & 0x3F)); |
| 5265 | } else if (hi >= 0x80) { |
| 5266 | *dst++ = (u8)(0xC0 | (hi >> 6)); |
| 5267 | *dst++ = (u8)(0x80 | (hi & 0x3F)); |
| 5268 | } else { |
| 5269 | *dst++ = (u8)hi; |
| 5270 | } |
| 5271 | } else { |
| 5272 | /* a non-BMP character, represented as a surrogate pair */ |
| 5273 | if (unlikely((hi & 0xFC00) != 0xD800)) { |
| 5274 | return_err(src - 6, "invalid high surrogate in string" ); |
| 5275 | } |
| 5276 | if (unlikely(!byte_match_2(src, "\\u" ))) { |
| 5277 | return_err(src, "no low surrogate in string" ); |
| 5278 | } |
| 5279 | if (unlikely(!read_hex_u16(src + 2, &lo))) { |
| 5280 | return_err(src, "invalid escaped sequence in string" ); |
| 5281 | } |
| 5282 | if (unlikely((lo & 0xFC00) != 0xDC00)) { |
| 5283 | return_err(src, "invalid low surrogate in string" ); |
| 5284 | } |
| 5285 | uni = ((((u32)hi - 0xD800) << 10) | |
| 5286 | ((u32)lo - 0xDC00)) + 0x10000; |
| 5287 | *dst++ = (u8)(0xF0 | (uni >> 18)); |
| 5288 | *dst++ = (u8)(0x80 | ((uni >> 12) & 0x3F)); |
| 5289 | *dst++ = (u8)(0x80 | ((uni >> 6) & 0x3F)); |
| 5290 | *dst++ = (u8)(0x80 | (uni & 0x3F)); |
| 5291 | src += 6; |
| 5292 | } |
| 5293 | break; |
| 5294 | default: return_err(src, "invalid escaped character in string" ); |
| 5295 | } |
| 5296 | } else if (likely(*src == '"')) { |
| 5297 | val->tag = ((u64)(dst - cur) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; |
| 5298 | val->uni.str = (const char *)cur; |
| 5299 | *dst = '\0'; |
| 5300 | *end = src + 1; |
| 5301 | return true; |
| 5302 | } else { |
| 5303 | if (!inv) return_err(src, "unexpected control character in string" ); |
| 5304 | if (src >= lst) return_err(src, "unclosed string" ); |
| 5305 | *dst++ = *src++; |
| 5306 | } |
| 5307 | |
| 5308 | copy_ascii: |
| 5309 | /* |
| 5310 | Copy continuous ASCII, loop unrolling, same as the following code: |
| 5311 | |
| 5312 | while (true) repeat16({ |
| 5313 | if (unlikely(char_is_ascii_stop(*src))) break; |
| 5314 | *dst++ = *src++; |
| 5315 | }) |
| 5316 | */ |
| 5317 | #if YYJSON_IS_REAL_GCC |
| 5318 | # define expr_jump(i) \ |
| 5319 | if (likely(!(char_is_ascii_stop(src[i])))) {} \ |
| 5320 | else { __asm__ volatile("":"=m"(src[i])); goto copy_ascii_stop_##i; } |
| 5321 | #else |
| 5322 | # define expr_jump(i) \ |
| 5323 | if (likely(!(char_is_ascii_stop(src[i])))) {} \ |
| 5324 | else { goto copy_ascii_stop_##i; } |
| 5325 | #endif |
| 5326 | repeat16_incr(expr_jump) |
| 5327 | #undef expr_jump |
| 5328 | |
| 5329 | byte_move_16(dst, src); |
| 5330 | src += 16; |
| 5331 | dst += 16; |
| 5332 | goto copy_ascii; |
| 5333 | |
| 5334 | copy_ascii_stop_0: |
| 5335 | goto copy_utf8; |
| 5336 | copy_ascii_stop_1: |
| 5337 | byte_move_2(dst, src); |
| 5338 | src += 1; |
| 5339 | dst += 1; |
| 5340 | goto copy_utf8; |
| 5341 | copy_ascii_stop_2: |
| 5342 | byte_move_2(dst, src); |
| 5343 | src += 2; |
| 5344 | dst += 2; |
| 5345 | goto copy_utf8; |
| 5346 | copy_ascii_stop_3: |
| 5347 | byte_move_4(dst, src); |
| 5348 | src += 3; |
| 5349 | dst += 3; |
| 5350 | goto copy_utf8; |
| 5351 | copy_ascii_stop_4: |
| 5352 | byte_move_4(dst, src); |
| 5353 | src += 4; |
| 5354 | dst += 4; |
| 5355 | goto copy_utf8; |
| 5356 | copy_ascii_stop_5: |
| 5357 | byte_move_4(dst, src); |
| 5358 | byte_move_2(dst + 4, src + 4); |
| 5359 | src += 5; |
| 5360 | dst += 5; |
| 5361 | goto copy_utf8; |
| 5362 | copy_ascii_stop_6: |
| 5363 | byte_move_4(dst, src); |
| 5364 | byte_move_2(dst + 4, src + 4); |
| 5365 | src += 6; |
| 5366 | dst += 6; |
| 5367 | goto copy_utf8; |
| 5368 | copy_ascii_stop_7: |
| 5369 | byte_move_8(dst, src); |
| 5370 | src += 7; |
| 5371 | dst += 7; |
| 5372 | goto copy_utf8; |
| 5373 | copy_ascii_stop_8: |
| 5374 | byte_move_8(dst, src); |
| 5375 | src += 8; |
| 5376 | dst += 8; |
| 5377 | goto copy_utf8; |
| 5378 | copy_ascii_stop_9: |
| 5379 | byte_move_8(dst, src); |
| 5380 | byte_move_2(dst + 8, src + 8); |
| 5381 | src += 9; |
| 5382 | dst += 9; |
| 5383 | goto copy_utf8; |
| 5384 | copy_ascii_stop_10: |
| 5385 | byte_move_8(dst, src); |
| 5386 | byte_move_2(dst + 8, src + 8); |
| 5387 | src += 10; |
| 5388 | dst += 10; |
| 5389 | goto copy_utf8; |
| 5390 | copy_ascii_stop_11: |
| 5391 | byte_move_8(dst, src); |
| 5392 | byte_move_4(dst + 8, src + 8); |
| 5393 | src += 11; |
| 5394 | dst += 11; |
| 5395 | goto copy_utf8; |
| 5396 | copy_ascii_stop_12: |
| 5397 | byte_move_8(dst, src); |
| 5398 | byte_move_4(dst + 8, src + 8); |
| 5399 | src += 12; |
| 5400 | dst += 12; |
| 5401 | goto copy_utf8; |
| 5402 | copy_ascii_stop_13: |
| 5403 | byte_move_8(dst, src); |
| 5404 | byte_move_4(dst + 8, src + 8); |
| 5405 | byte_move_2(dst + 12, src + 12); |
| 5406 | src += 13; |
| 5407 | dst += 13; |
| 5408 | goto copy_utf8; |
| 5409 | copy_ascii_stop_14: |
| 5410 | byte_move_8(dst, src); |
| 5411 | byte_move_4(dst + 8, src + 8); |
| 5412 | byte_move_2(dst + 12, src + 12); |
| 5413 | src += 14; |
| 5414 | dst += 14; |
| 5415 | goto copy_utf8; |
| 5416 | copy_ascii_stop_15: |
| 5417 | byte_move_16(dst, src); |
| 5418 | src += 15; |
| 5419 | dst += 15; |
| 5420 | goto copy_utf8; |
| 5421 | |
| 5422 | copy_utf8: |
| 5423 | if (*src & 0x80) { /* non-ASCII character */ |
| 5424 | pos = src; |
| 5425 | uni = byte_load_4(src); |
| 5426 | while (is_valid_seq_3(uni)) { |
| 5427 | byte_copy_4(dst, &uni); |
| 5428 | dst += 3; |
| 5429 | src += 3; |
| 5430 | uni = byte_load_4(src); |
| 5431 | } |
| 5432 | if (is_valid_seq_1(uni)) goto copy_ascii; |
| 5433 | while (is_valid_seq_2(uni)) { |
| 5434 | byte_copy_2(dst, &uni); |
| 5435 | dst += 2; |
| 5436 | src += 2; |
| 5437 | uni = byte_load_4(src); |
| 5438 | } |
| 5439 | while (is_valid_seq_4(uni)) { |
| 5440 | byte_copy_4(dst, &uni); |
| 5441 | dst += 4; |
| 5442 | src += 4; |
| 5443 | uni = byte_load_4(src); |
| 5444 | } |
| 5445 | if (unlikely(pos == src)) { |
| 5446 | if (!inv) return_err(src, "invalid UTF-8 encoding in string" ); |
| 5447 | goto copy_ascii_stop_1; |
| 5448 | } |
| 5449 | goto copy_ascii; |
| 5450 | } |
| 5451 | goto copy_escape; |
| 5452 | |
| 5453 | #undef return_err |
| 5454 | #undef is_valid_seq_1 |
| 5455 | #undef is_valid_seq_2 |
| 5456 | #undef is_valid_seq_3 |
| 5457 | #undef is_valid_seq_4 |
| 5458 | } |
| 5459 | |
| 5460 | |
| 5461 | |
| 5462 | /*============================================================================== |
| 5463 | * JSON Reader Implementation |
| 5464 | * |
| 5465 | * We use goto statements to build the finite state machine (FSM). |
| 5466 | * The FSM's state was held by program counter (PC) and the 'goto' make the |
| 5467 | * state transitions. |
| 5468 | *============================================================================*/ |
| 5469 | |
| 5470 | /** Read single value JSON document. */ |
| 5471 | static_noinline yyjson_doc *read_root_single(u8 *hdr, |
| 5472 | u8 *cur, |
| 5473 | u8 *end, |
| 5474 | yyjson_alc alc, |
| 5475 | yyjson_read_flag flg, |
| 5476 | yyjson_read_err *err) { |
| 5477 | |
| 5478 | #define has_flag(_flag) unlikely((flg & YYJSON_READ_##_flag) != 0) |
| 5479 | |
| 5480 | #define return_err(_pos, _code, _msg) do { \ |
| 5481 | if (is_truncated_end(hdr, _pos, end, YYJSON_READ_ERROR_##_code, flg)) { \ |
| 5482 | err->pos = (usize)(end - hdr); \ |
| 5483 | err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \ |
| 5484 | err->msg = "unexpected end of data"; \ |
| 5485 | } else { \ |
| 5486 | err->pos = (usize)(_pos - hdr); \ |
| 5487 | err->code = YYJSON_READ_ERROR_##_code; \ |
| 5488 | err->msg = _msg; \ |
| 5489 | } \ |
| 5490 | if (val_hdr) alc.free(alc.ctx, (void *)val_hdr); \ |
| 5491 | return NULL; \ |
| 5492 | } while (false) |
| 5493 | |
| 5494 | usize hdr_len; /* value count used by doc */ |
| 5495 | usize alc_num; /* value count capacity */ |
| 5496 | yyjson_val *val_hdr; /* the head of allocated values */ |
| 5497 | yyjson_val *val; /* current value */ |
| 5498 | yyjson_doc *doc; /* the JSON document, equals to val_hdr */ |
| 5499 | const char *msg; /* error message */ |
| 5500 | |
| 5501 | bool raw; /* read number as raw */ |
| 5502 | bool inv; /* allow invalid unicode */ |
| 5503 | u8 *raw_end; /* raw end for null-terminator */ |
| 5504 | u8 **pre; /* previous raw end pointer */ |
| 5505 | |
| 5506 | hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val); |
| 5507 | hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0; |
| 5508 | alc_num = hdr_len + 1; /* single value */ |
| 5509 | |
| 5510 | val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_num * sizeof(yyjson_val)); |
| 5511 | if (unlikely(!val_hdr)) goto fail_alloc; |
| 5512 | val = val_hdr + hdr_len; |
| 5513 | raw = (flg & (YYJSON_READ_NUMBER_AS_RAW | YYJSON_READ_BIGNUM_AS_RAW)) != 0; |
| 5514 | inv = (flg & YYJSON_READ_ALLOW_INVALID_UNICODE) != 0; |
| 5515 | raw_end = NULL; |
| 5516 | pre = raw ? &raw_end : NULL; |
| 5517 | |
| 5518 | if (char_is_number(*cur)) { |
| 5519 | if (likely(read_number(&cur, pre, flg, val, &msg))) goto doc_end; |
| 5520 | goto fail_number; |
| 5521 | } |
| 5522 | if (*cur == '"') { |
| 5523 | if (likely(read_string(&cur, end, inv, val, &msg))) goto doc_end; |
| 5524 | goto fail_string; |
| 5525 | } |
| 5526 | if (*cur == 't') { |
| 5527 | if (likely(read_true(&cur, val))) goto doc_end; |
| 5528 | goto fail_literal; |
| 5529 | } |
| 5530 | if (*cur == 'f') { |
| 5531 | if (likely(read_false(&cur, val))) goto doc_end; |
| 5532 | goto fail_literal; |
| 5533 | } |
| 5534 | if (*cur == 'n') { |
| 5535 | if (likely(read_null(&cur, val))) goto doc_end; |
| 5536 | if (unlikely(flg & YYJSON_READ_ALLOW_INF_AND_NAN)) { |
| 5537 | if (read_nan(false, &cur, pre, val)) goto doc_end; |
| 5538 | } |
| 5539 | goto fail_literal; |
| 5540 | } |
| 5541 | if (unlikely(flg & YYJSON_READ_ALLOW_INF_AND_NAN)) { |
| 5542 | if (read_inf_or_nan(false, &cur, pre, val)) goto doc_end; |
| 5543 | } |
| 5544 | goto fail_character; |
| 5545 | |
| 5546 | doc_end: |
| 5547 | /* check invalid contents after json document */ |
| 5548 | if (unlikely(cur < end) && !has_flag(STOP_WHEN_DONE)) { |
| 5549 | if (has_flag(ALLOW_COMMENTS)) { |
| 5550 | if (!skip_spaces_and_comments(&cur)) { |
| 5551 | if (byte_match_2(cur, "/*" )) goto fail_comment; |
| 5552 | } |
| 5553 | } else { |
| 5554 | while (char_is_space(*cur)) cur++; |
| 5555 | } |
| 5556 | if (unlikely(cur < end)) goto fail_garbage; |
| 5557 | } |
| 5558 | |
| 5559 | if (pre && *pre) **pre = '\0'; |
| 5560 | doc = (yyjson_doc *)val_hdr; |
| 5561 | doc->root = val_hdr + hdr_len; |
| 5562 | doc->alc = alc; |
| 5563 | doc->dat_read = (usize)(cur - hdr); |
| 5564 | doc->val_read = 1; |
| 5565 | doc->str_pool = has_flag(INSITU) ? NULL : (char *)hdr; |
| 5566 | return doc; |
| 5567 | |
| 5568 | fail_string: |
| 5569 | return_err(cur, INVALID_STRING, msg); |
| 5570 | fail_number: |
| 5571 | return_err(cur, INVALID_NUMBER, msg); |
| 5572 | fail_alloc: |
| 5573 | return_err(cur, MEMORY_ALLOCATION, "memory allocation failed" ); |
| 5574 | fail_literal: |
| 5575 | return_err(cur, LITERAL, "invalid literal" ); |
| 5576 | : |
| 5577 | return_err(cur, INVALID_COMMENT, "unclosed multiline comment" ); |
| 5578 | fail_character: |
| 5579 | return_err(cur, UNEXPECTED_CHARACTER, "unexpected character" ); |
| 5580 | fail_garbage: |
| 5581 | return_err(cur, UNEXPECTED_CONTENT, "unexpected content after document" ); |
| 5582 | |
| 5583 | #undef has_flag |
| 5584 | #undef return_err |
| 5585 | } |
| 5586 | |
| 5587 | /** Read JSON document (accept all style, but optimized for minify). */ |
| 5588 | static_inline yyjson_doc *read_root_minify(u8 *hdr, |
| 5589 | u8 *cur, |
| 5590 | u8 *end, |
| 5591 | yyjson_alc alc, |
| 5592 | yyjson_read_flag flg, |
| 5593 | yyjson_read_err *err) { |
| 5594 | |
| 5595 | #define has_flag(_flag) unlikely((flg & YYJSON_READ_##_flag) != 0) |
| 5596 | |
| 5597 | #define return_err(_pos, _code, _msg) do { \ |
| 5598 | if (is_truncated_end(hdr, _pos, end, YYJSON_READ_ERROR_##_code, flg)) { \ |
| 5599 | err->pos = (usize)(end - hdr); \ |
| 5600 | err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \ |
| 5601 | err->msg = "unexpected end of data"; \ |
| 5602 | } else { \ |
| 5603 | err->pos = (usize)(_pos - hdr); \ |
| 5604 | err->code = YYJSON_READ_ERROR_##_code; \ |
| 5605 | err->msg = _msg; \ |
| 5606 | } \ |
| 5607 | if (val_hdr) alc.free(alc.ctx, (void *)val_hdr); \ |
| 5608 | return NULL; \ |
| 5609 | } while (false) |
| 5610 | |
| 5611 | #define val_incr() do { \ |
| 5612 | val++; \ |
| 5613 | if (unlikely(val >= val_end)) { \ |
| 5614 | usize alc_old = alc_len; \ |
| 5615 | alc_len += alc_len / 2; \ |
| 5616 | if ((alc_len >= alc_max)) goto fail_alloc; \ |
| 5617 | val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \ |
| 5618 | alc_old * sizeof(yyjson_val), \ |
| 5619 | alc_len * sizeof(yyjson_val)); \ |
| 5620 | if ((!val_tmp)) goto fail_alloc; \ |
| 5621 | val = val_tmp + (usize)(val - val_hdr); \ |
| 5622 | ctn = val_tmp + (usize)(ctn - val_hdr); \ |
| 5623 | val_hdr = val_tmp; \ |
| 5624 | val_end = val_tmp + (alc_len - 2); \ |
| 5625 | } \ |
| 5626 | } while (false) |
| 5627 | |
| 5628 | usize dat_len; /* data length in bytes, hint for allocator */ |
| 5629 | usize hdr_len; /* value count used by yyjson_doc */ |
| 5630 | usize alc_len; /* value count allocated */ |
| 5631 | usize alc_max; /* maximum value count for allocator */ |
| 5632 | usize ctn_len; /* the number of elements in current container */ |
| 5633 | yyjson_val *val_hdr; /* the head of allocated values */ |
| 5634 | yyjson_val *val_end; /* the end of allocated values */ |
| 5635 | yyjson_val *val_tmp; /* temporary pointer for realloc */ |
| 5636 | yyjson_val *val; /* current JSON value */ |
| 5637 | yyjson_val *ctn; /* current container */ |
| 5638 | yyjson_val *ctn_parent; /* parent of current container */ |
| 5639 | yyjson_doc *doc; /* the JSON document, equals to val_hdr */ |
| 5640 | const char *msg; /* error message */ |
| 5641 | |
| 5642 | bool raw; /* read number as raw */ |
| 5643 | bool inv; /* allow invalid unicode */ |
| 5644 | u8 *raw_end; /* raw end for null-terminator */ |
| 5645 | u8 **pre; /* previous raw end pointer */ |
| 5646 | |
| 5647 | dat_len = has_flag(STOP_WHEN_DONE) ? 256 : (usize)(end - cur); |
| 5648 | hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val); |
| 5649 | hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0; |
| 5650 | alc_max = USIZE_MAX / sizeof(yyjson_val); |
| 5651 | alc_len = hdr_len + (dat_len / YYJSON_READER_ESTIMATED_MINIFY_RATIO) + 4; |
| 5652 | alc_len = yyjson_min(alc_len, alc_max); |
| 5653 | |
| 5654 | val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_len * sizeof(yyjson_val)); |
| 5655 | if (unlikely(!val_hdr)) goto fail_alloc; |
| 5656 | val_end = val_hdr + (alc_len - 2); /* padding for key-value pair reading */ |
| 5657 | val = val_hdr + hdr_len; |
| 5658 | ctn = val; |
| 5659 | ctn_len = 0; |
| 5660 | raw = (flg & (YYJSON_READ_NUMBER_AS_RAW | YYJSON_READ_BIGNUM_AS_RAW)) != 0; |
| 5661 | inv = (flg & YYJSON_READ_ALLOW_INVALID_UNICODE) != 0; |
| 5662 | raw_end = NULL; |
| 5663 | pre = raw ? &raw_end : NULL; |
| 5664 | |
| 5665 | if (*cur++ == '{') { |
| 5666 | ctn->tag = YYJSON_TYPE_OBJ; |
| 5667 | ctn->uni.ofs = 0; |
| 5668 | goto obj_key_begin; |
| 5669 | } else { |
| 5670 | ctn->tag = YYJSON_TYPE_ARR; |
| 5671 | ctn->uni.ofs = 0; |
| 5672 | goto arr_val_begin; |
| 5673 | } |
| 5674 | |
| 5675 | arr_begin: |
| 5676 | /* save current container */ |
| 5677 | ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) | |
| 5678 | (ctn->tag & YYJSON_TAG_MASK); |
| 5679 | |
| 5680 | /* create a new array value, save parent container offset */ |
| 5681 | val_incr(); |
| 5682 | val->tag = YYJSON_TYPE_ARR; |
| 5683 | val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn); |
| 5684 | |
| 5685 | /* push the new array value as current container */ |
| 5686 | ctn = val; |
| 5687 | ctn_len = 0; |
| 5688 | |
| 5689 | arr_val_begin: |
| 5690 | if (*cur == '{') { |
| 5691 | cur++; |
| 5692 | goto obj_begin; |
| 5693 | } |
| 5694 | if (*cur == '[') { |
| 5695 | cur++; |
| 5696 | goto arr_begin; |
| 5697 | } |
| 5698 | if (char_is_number(*cur)) { |
| 5699 | val_incr(); |
| 5700 | ctn_len++; |
| 5701 | if (likely(read_number(&cur, pre, flg, val, &msg))) goto arr_val_end; |
| 5702 | goto fail_number; |
| 5703 | } |
| 5704 | if (*cur == '"') { |
| 5705 | val_incr(); |
| 5706 | ctn_len++; |
| 5707 | if (likely(read_string(&cur, end, inv, val, &msg))) goto arr_val_end; |
| 5708 | goto fail_string; |
| 5709 | } |
| 5710 | if (*cur == 't') { |
| 5711 | val_incr(); |
| 5712 | ctn_len++; |
| 5713 | if (likely(read_true(&cur, val))) goto arr_val_end; |
| 5714 | goto fail_literal; |
| 5715 | } |
| 5716 | if (*cur == 'f') { |
| 5717 | val_incr(); |
| 5718 | ctn_len++; |
| 5719 | if (likely(read_false(&cur, val))) goto arr_val_end; |
| 5720 | goto fail_literal; |
| 5721 | } |
| 5722 | if (*cur == 'n') { |
| 5723 | val_incr(); |
| 5724 | ctn_len++; |
| 5725 | if (likely(read_null(&cur, val))) goto arr_val_end; |
| 5726 | if (unlikely(flg & YYJSON_READ_ALLOW_INF_AND_NAN)) { |
| 5727 | if (read_nan(false, &cur, pre, val)) goto arr_val_end; |
| 5728 | } |
| 5729 | goto fail_literal; |
| 5730 | } |
| 5731 | if (*cur == ']') { |
| 5732 | cur++; |
| 5733 | if (likely(ctn_len == 0)) goto arr_end; |
| 5734 | if (has_flag(ALLOW_TRAILING_COMMAS)) goto arr_end; |
| 5735 | while (*cur != ',') cur--; |
| 5736 | goto fail_trailing_comma; |
| 5737 | } |
| 5738 | if (char_is_space(*cur)) { |
| 5739 | while (char_is_space(*++cur)); |
| 5740 | goto arr_val_begin; |
| 5741 | } |
| 5742 | if (unlikely(flg & YYJSON_READ_ALLOW_INF_AND_NAN) && |
| 5743 | (*cur == 'i' || *cur == 'I' || *cur == 'N')) { |
| 5744 | val_incr(); |
| 5745 | ctn_len++; |
| 5746 | if (read_inf_or_nan(false, &cur, pre, val)) goto arr_val_end; |
| 5747 | goto fail_character; |
| 5748 | } |
| 5749 | if (has_flag(ALLOW_COMMENTS)) { |
| 5750 | if (skip_spaces_and_comments(&cur)) goto arr_val_begin; |
| 5751 | if (byte_match_2(cur, "/*" )) goto fail_comment; |
| 5752 | } |
| 5753 | goto fail_character; |
| 5754 | |
| 5755 | arr_val_end: |
| 5756 | if (*cur == ',') { |
| 5757 | cur++; |
| 5758 | goto arr_val_begin; |
| 5759 | } |
| 5760 | if (*cur == ']') { |
| 5761 | cur++; |
| 5762 | goto arr_end; |
| 5763 | } |
| 5764 | if (char_is_space(*cur)) { |
| 5765 | while (char_is_space(*++cur)); |
| 5766 | goto arr_val_end; |
| 5767 | } |
| 5768 | if (has_flag(ALLOW_COMMENTS)) { |
| 5769 | if (skip_spaces_and_comments(&cur)) goto arr_val_end; |
| 5770 | if (byte_match_2(cur, "/*" )) goto fail_comment; |
| 5771 | } |
| 5772 | goto fail_character; |
| 5773 | |
| 5774 | arr_end: |
| 5775 | /* get parent container */ |
| 5776 | ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs); |
| 5777 | |
| 5778 | /* save the next sibling value offset */ |
| 5779 | ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val); |
| 5780 | ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR; |
| 5781 | if (unlikely(ctn == ctn_parent)) goto doc_end; |
| 5782 | |
| 5783 | /* pop parent as current container */ |
| 5784 | ctn = ctn_parent; |
| 5785 | ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT); |
| 5786 | if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) { |
| 5787 | goto obj_val_end; |
| 5788 | } else { |
| 5789 | goto arr_val_end; |
| 5790 | } |
| 5791 | |
| 5792 | obj_begin: |
| 5793 | /* push container */ |
| 5794 | ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) | |
| 5795 | (ctn->tag & YYJSON_TAG_MASK); |
| 5796 | val_incr(); |
| 5797 | val->tag = YYJSON_TYPE_OBJ; |
| 5798 | /* offset to the parent */ |
| 5799 | val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn); |
| 5800 | ctn = val; |
| 5801 | ctn_len = 0; |
| 5802 | |
| 5803 | obj_key_begin: |
| 5804 | if (likely(*cur == '"')) { |
| 5805 | val_incr(); |
| 5806 | ctn_len++; |
| 5807 | if (likely(read_string(&cur, end, inv, val, &msg))) goto obj_key_end; |
| 5808 | goto fail_string; |
| 5809 | } |
| 5810 | if (likely(*cur == '}')) { |
| 5811 | cur++; |
| 5812 | if (likely(ctn_len == 0)) goto obj_end; |
| 5813 | if (has_flag(ALLOW_TRAILING_COMMAS)) goto obj_end; |
| 5814 | while (*cur != ',') cur--; |
| 5815 | goto fail_trailing_comma; |
| 5816 | } |
| 5817 | if (char_is_space(*cur)) { |
| 5818 | while (char_is_space(*++cur)); |
| 5819 | goto obj_key_begin; |
| 5820 | } |
| 5821 | if (has_flag(ALLOW_COMMENTS)) { |
| 5822 | if (skip_spaces_and_comments(&cur)) goto obj_key_begin; |
| 5823 | if (byte_match_2(cur, "/*" )) goto fail_comment; |
| 5824 | } |
| 5825 | goto fail_character; |
| 5826 | |
| 5827 | obj_key_end: |
| 5828 | if (*cur == ':') { |
| 5829 | cur++; |
| 5830 | goto obj_val_begin; |
| 5831 | } |
| 5832 | if (char_is_space(*cur)) { |
| 5833 | while (char_is_space(*++cur)); |
| 5834 | goto obj_key_end; |
| 5835 | } |
| 5836 | if (has_flag(ALLOW_COMMENTS)) { |
| 5837 | if (skip_spaces_and_comments(&cur)) goto obj_key_end; |
| 5838 | if (byte_match_2(cur, "/*" )) goto fail_comment; |
| 5839 | } |
| 5840 | goto fail_character; |
| 5841 | |
| 5842 | obj_val_begin: |
| 5843 | if (*cur == '"') { |
| 5844 | val++; |
| 5845 | ctn_len++; |
| 5846 | if (likely(read_string(&cur, end, inv, val, &msg))) goto obj_val_end; |
| 5847 | goto fail_string; |
| 5848 | } |
| 5849 | if (char_is_number(*cur)) { |
| 5850 | val++; |
| 5851 | ctn_len++; |
| 5852 | if (likely(read_number(&cur, pre, flg, val, &msg))) goto obj_val_end; |
| 5853 | goto fail_number; |
| 5854 | } |
| 5855 | if (*cur == '{') { |
| 5856 | cur++; |
| 5857 | goto obj_begin; |
| 5858 | } |
| 5859 | if (*cur == '[') { |
| 5860 | cur++; |
| 5861 | goto arr_begin; |
| 5862 | } |
| 5863 | if (*cur == 't') { |
| 5864 | val++; |
| 5865 | ctn_len++; |
| 5866 | if (likely(read_true(&cur, val))) goto obj_val_end; |
| 5867 | goto fail_literal; |
| 5868 | } |
| 5869 | if (*cur == 'f') { |
| 5870 | val++; |
| 5871 | ctn_len++; |
| 5872 | if (likely(read_false(&cur, val))) goto obj_val_end; |
| 5873 | goto fail_literal; |
| 5874 | } |
| 5875 | if (*cur == 'n') { |
| 5876 | val++; |
| 5877 | ctn_len++; |
| 5878 | if (likely(read_null(&cur, val))) goto obj_val_end; |
| 5879 | if (unlikely(flg & YYJSON_READ_ALLOW_INF_AND_NAN)) { |
| 5880 | if (read_nan(false, &cur, pre, val)) goto obj_val_end; |
| 5881 | } |
| 5882 | goto fail_literal; |
| 5883 | } |
| 5884 | if (char_is_space(*cur)) { |
| 5885 | while (char_is_space(*++cur)); |
| 5886 | goto obj_val_begin; |
| 5887 | } |
| 5888 | if (unlikely(flg & YYJSON_READ_ALLOW_INF_AND_NAN) && |
| 5889 | (*cur == 'i' || *cur == 'I' || *cur == 'N')) { |
| 5890 | val++; |
| 5891 | ctn_len++; |
| 5892 | if (read_inf_or_nan(false, &cur, pre, val)) goto obj_val_end; |
| 5893 | goto fail_character; |
| 5894 | } |
| 5895 | if (has_flag(ALLOW_COMMENTS)) { |
| 5896 | if (skip_spaces_and_comments(&cur)) goto obj_val_begin; |
| 5897 | if (byte_match_2(cur, "/*" )) goto fail_comment; |
| 5898 | } |
| 5899 | goto fail_character; |
| 5900 | |
| 5901 | obj_val_end: |
| 5902 | if (likely(*cur == ',')) { |
| 5903 | cur++; |
| 5904 | goto obj_key_begin; |
| 5905 | } |
| 5906 | if (likely(*cur == '}')) { |
| 5907 | cur++; |
| 5908 | goto obj_end; |
| 5909 | } |
| 5910 | if (char_is_space(*cur)) { |
| 5911 | while (char_is_space(*++cur)); |
| 5912 | goto obj_val_end; |
| 5913 | } |
| 5914 | if (has_flag(ALLOW_COMMENTS)) { |
| 5915 | if (skip_spaces_and_comments(&cur)) goto obj_val_end; |
| 5916 | if (byte_match_2(cur, "/*" )) goto fail_comment; |
| 5917 | } |
| 5918 | goto fail_character; |
| 5919 | |
| 5920 | obj_end: |
| 5921 | /* pop container */ |
| 5922 | ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs); |
| 5923 | /* point to the next value */ |
| 5924 | ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val); |
| 5925 | ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ; |
| 5926 | if (unlikely(ctn == ctn_parent)) goto doc_end; |
| 5927 | ctn = ctn_parent; |
| 5928 | ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT); |
| 5929 | if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) { |
| 5930 | goto obj_val_end; |
| 5931 | } else { |
| 5932 | goto arr_val_end; |
| 5933 | } |
| 5934 | |
| 5935 | doc_end: |
| 5936 | /* check invalid contents after json document */ |
| 5937 | if (unlikely(cur < end) && !has_flag(STOP_WHEN_DONE)) { |
| 5938 | if (has_flag(ALLOW_COMMENTS)) { |
| 5939 | skip_spaces_and_comments(&cur); |
| 5940 | if (byte_match_2(cur, "/*" )) goto fail_comment; |
| 5941 | } |
| 5942 | else while (char_is_space(*cur)) cur++; |
| 5943 | if (unlikely(cur < end)) goto fail_garbage; |
| 5944 | } |
| 5945 | |
| 5946 | if (pre && *pre) **pre = '\0'; |
| 5947 | doc = (yyjson_doc *)val_hdr; |
| 5948 | doc->root = val_hdr + hdr_len; |
| 5949 | doc->alc = alc; |
| 5950 | doc->dat_read = (usize)(cur - hdr); |
| 5951 | doc->val_read = (usize)((val - doc->root) + 1); |
| 5952 | doc->str_pool = has_flag(INSITU) ? NULL : (char *)hdr; |
| 5953 | return doc; |
| 5954 | |
| 5955 | fail_string: |
| 5956 | return_err(cur, INVALID_STRING, msg); |
| 5957 | fail_number: |
| 5958 | return_err(cur, INVALID_NUMBER, msg); |
| 5959 | fail_alloc: |
| 5960 | return_err(cur, MEMORY_ALLOCATION, "memory allocation failed" ); |
| 5961 | fail_trailing_comma: |
| 5962 | return_err(cur, JSON_STRUCTURE, "trailing comma is not allowed" ); |
| 5963 | fail_literal: |
| 5964 | return_err(cur, LITERAL, "invalid literal" ); |
| 5965 | : |
| 5966 | return_err(cur, INVALID_COMMENT, "unclosed multiline comment" ); |
| 5967 | fail_character: |
| 5968 | return_err(cur, UNEXPECTED_CHARACTER, "unexpected character" ); |
| 5969 | fail_garbage: |
| 5970 | return_err(cur, UNEXPECTED_CONTENT, "unexpected content after document" ); |
| 5971 | |
| 5972 | #undef has_flag |
| 5973 | #undef val_incr |
| 5974 | #undef return_err |
| 5975 | } |
| 5976 | |
| 5977 | /** Read JSON document (accept all style, but optimized for pretty). */ |
| 5978 | static_inline yyjson_doc *read_root_pretty(u8 *hdr, |
| 5979 | u8 *cur, |
| 5980 | u8 *end, |
| 5981 | yyjson_alc alc, |
| 5982 | yyjson_read_flag flg, |
| 5983 | yyjson_read_err *err) { |
| 5984 | |
| 5985 | #define has_flag(_flag) unlikely((flg & YYJSON_READ_##_flag) != 0) |
| 5986 | |
| 5987 | #define return_err(_pos, _code, _msg) do { \ |
| 5988 | if (is_truncated_end(hdr, _pos, end, YYJSON_READ_ERROR_##_code, flg)) { \ |
| 5989 | err->pos = (usize)(end - hdr); \ |
| 5990 | err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \ |
| 5991 | err->msg = "unexpected end of data"; \ |
| 5992 | } else { \ |
| 5993 | err->pos = (usize)(_pos - hdr); \ |
| 5994 | err->code = YYJSON_READ_ERROR_##_code; \ |
| 5995 | err->msg = _msg; \ |
| 5996 | } \ |
| 5997 | if (val_hdr) alc.free(alc.ctx, (void *)val_hdr); \ |
| 5998 | return NULL; \ |
| 5999 | } while (false) |
| 6000 | |
| 6001 | #define val_incr() do { \ |
| 6002 | val++; \ |
| 6003 | if (unlikely(val >= val_end)) { \ |
| 6004 | usize alc_old = alc_len; \ |
| 6005 | alc_len += alc_len / 2; \ |
| 6006 | if ((alc_len >= alc_max)) goto fail_alloc; \ |
| 6007 | val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \ |
| 6008 | alc_old * sizeof(yyjson_val), \ |
| 6009 | alc_len * sizeof(yyjson_val)); \ |
| 6010 | if ((!val_tmp)) goto fail_alloc; \ |
| 6011 | val = val_tmp + (usize)(val - val_hdr); \ |
| 6012 | ctn = val_tmp + (usize)(ctn - val_hdr); \ |
| 6013 | val_hdr = val_tmp; \ |
| 6014 | val_end = val_tmp + (alc_len - 2); \ |
| 6015 | } \ |
| 6016 | } while (false) |
| 6017 | |
| 6018 | usize dat_len; /* data length in bytes, hint for allocator */ |
| 6019 | usize hdr_len; /* value count used by yyjson_doc */ |
| 6020 | usize alc_len; /* value count allocated */ |
| 6021 | usize alc_max; /* maximum value count for allocator */ |
| 6022 | usize ctn_len; /* the number of elements in current container */ |
| 6023 | yyjson_val *val_hdr; /* the head of allocated values */ |
| 6024 | yyjson_val *val_end; /* the end of allocated values */ |
| 6025 | yyjson_val *val_tmp; /* temporary pointer for realloc */ |
| 6026 | yyjson_val *val; /* current JSON value */ |
| 6027 | yyjson_val *ctn; /* current container */ |
| 6028 | yyjson_val *ctn_parent; /* parent of current container */ |
| 6029 | yyjson_doc *doc; /* the JSON document, equals to val_hdr */ |
| 6030 | const char *msg; /* error message */ |
| 6031 | |
| 6032 | bool raw; /* read number as raw */ |
| 6033 | bool inv; /* allow invalid unicode */ |
| 6034 | u8 *raw_end; /* raw end for null-terminator */ |
| 6035 | u8 **pre; /* previous raw end pointer */ |
| 6036 | |
| 6037 | dat_len = has_flag(STOP_WHEN_DONE) ? 256 : (usize)(end - cur); |
| 6038 | hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val); |
| 6039 | hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0; |
| 6040 | alc_max = USIZE_MAX / sizeof(yyjson_val); |
| 6041 | alc_len = hdr_len + (dat_len / YYJSON_READER_ESTIMATED_PRETTY_RATIO) + 4; |
| 6042 | alc_len = yyjson_min(alc_len, alc_max); |
| 6043 | |
| 6044 | val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_len * sizeof(yyjson_val)); |
| 6045 | if (unlikely(!val_hdr)) goto fail_alloc; |
| 6046 | val_end = val_hdr + (alc_len - 2); /* padding for key-value pair reading */ |
| 6047 | val = val_hdr + hdr_len; |
| 6048 | ctn = val; |
| 6049 | ctn_len = 0; |
| 6050 | raw = (flg & (YYJSON_READ_NUMBER_AS_RAW | YYJSON_READ_BIGNUM_AS_RAW)) != 0; |
| 6051 | inv = (flg & YYJSON_READ_ALLOW_INVALID_UNICODE) != 0; |
| 6052 | raw_end = NULL; |
| 6053 | pre = raw ? &raw_end : NULL; |
| 6054 | |
| 6055 | if (*cur++ == '{') { |
| 6056 | ctn->tag = YYJSON_TYPE_OBJ; |
| 6057 | ctn->uni.ofs = 0; |
| 6058 | if (*cur == '\n') cur++; |
| 6059 | goto obj_key_begin; |
| 6060 | } else { |
| 6061 | ctn->tag = YYJSON_TYPE_ARR; |
| 6062 | ctn->uni.ofs = 0; |
| 6063 | if (*cur == '\n') cur++; |
| 6064 | goto arr_val_begin; |
| 6065 | } |
| 6066 | |
| 6067 | arr_begin: |
| 6068 | /* save current container */ |
| 6069 | ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) | |
| 6070 | (ctn->tag & YYJSON_TAG_MASK); |
| 6071 | |
| 6072 | /* create a new array value, save parent container offset */ |
| 6073 | val_incr(); |
| 6074 | val->tag = YYJSON_TYPE_ARR; |
| 6075 | val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn); |
| 6076 | |
| 6077 | /* push the new array value as current container */ |
| 6078 | ctn = val; |
| 6079 | ctn_len = 0; |
| 6080 | if (*cur == '\n') cur++; |
| 6081 | |
| 6082 | arr_val_begin: |
| 6083 | #if YYJSON_IS_REAL_GCC |
| 6084 | while (true) repeat16({ |
| 6085 | if (byte_match_2(cur, " " )) cur += 2; |
| 6086 | else break; |
| 6087 | }) |
| 6088 | #else |
| 6089 | while (true) repeat16({ |
| 6090 | if (likely(byte_match_2(cur, " " ))) cur += 2; |
| 6091 | else break; |
| 6092 | }) |
| 6093 | #endif |
| 6094 | |
| 6095 | if (*cur == '{') { |
| 6096 | cur++; |
| 6097 | goto obj_begin; |
| 6098 | } |
| 6099 | if (*cur == '[') { |
| 6100 | cur++; |
| 6101 | goto arr_begin; |
| 6102 | } |
| 6103 | if (char_is_number(*cur)) { |
| 6104 | val_incr(); |
| 6105 | ctn_len++; |
| 6106 | if (likely(read_number(&cur, pre, flg, val, &msg))) goto arr_val_end; |
| 6107 | goto fail_number; |
| 6108 | } |
| 6109 | if (*cur == '"') { |
| 6110 | val_incr(); |
| 6111 | ctn_len++; |
| 6112 | if (likely(read_string(&cur, end, inv, val, &msg))) goto arr_val_end; |
| 6113 | goto fail_string; |
| 6114 | } |
| 6115 | if (*cur == 't') { |
| 6116 | val_incr(); |
| 6117 | ctn_len++; |
| 6118 | if (likely(read_true(&cur, val))) goto arr_val_end; |
| 6119 | goto fail_literal; |
| 6120 | } |
| 6121 | if (*cur == 'f') { |
| 6122 | val_incr(); |
| 6123 | ctn_len++; |
| 6124 | if (likely(read_false(&cur, val))) goto arr_val_end; |
| 6125 | goto fail_literal; |
| 6126 | } |
| 6127 | if (*cur == 'n') { |
| 6128 | val_incr(); |
| 6129 | ctn_len++; |
| 6130 | if (likely(read_null(&cur, val))) goto arr_val_end; |
| 6131 | if (unlikely(flg & YYJSON_READ_ALLOW_INF_AND_NAN)) { |
| 6132 | if (read_nan(false, &cur, pre, val)) goto arr_val_end; |
| 6133 | } |
| 6134 | goto fail_literal; |
| 6135 | } |
| 6136 | if (*cur == ']') { |
| 6137 | cur++; |
| 6138 | if (likely(ctn_len == 0)) goto arr_end; |
| 6139 | if (has_flag(ALLOW_TRAILING_COMMAS)) goto arr_end; |
| 6140 | while (*cur != ',') cur--; |
| 6141 | goto fail_trailing_comma; |
| 6142 | } |
| 6143 | if (char_is_space(*cur)) { |
| 6144 | while (char_is_space(*++cur)); |
| 6145 | goto arr_val_begin; |
| 6146 | } |
| 6147 | if (unlikely(flg & YYJSON_READ_ALLOW_INF_AND_NAN) && |
| 6148 | (*cur == 'i' || *cur == 'I' || *cur == 'N')) { |
| 6149 | val_incr(); |
| 6150 | ctn_len++; |
| 6151 | if (read_inf_or_nan(false, &cur, pre, val)) goto arr_val_end; |
| 6152 | goto fail_character; |
| 6153 | } |
| 6154 | if (has_flag(ALLOW_COMMENTS)) { |
| 6155 | if (skip_spaces_and_comments(&cur)) goto arr_val_begin; |
| 6156 | if (byte_match_2(cur, "/*" )) goto fail_comment; |
| 6157 | } |
| 6158 | goto fail_character; |
| 6159 | |
| 6160 | arr_val_end: |
| 6161 | if (byte_match_2(cur, ",\n" )) { |
| 6162 | cur += 2; |
| 6163 | goto arr_val_begin; |
| 6164 | } |
| 6165 | if (*cur == ',') { |
| 6166 | cur++; |
| 6167 | goto arr_val_begin; |
| 6168 | } |
| 6169 | if (*cur == ']') { |
| 6170 | cur++; |
| 6171 | goto arr_end; |
| 6172 | } |
| 6173 | if (char_is_space(*cur)) { |
| 6174 | while (char_is_space(*++cur)); |
| 6175 | goto arr_val_end; |
| 6176 | } |
| 6177 | if (has_flag(ALLOW_COMMENTS)) { |
| 6178 | if (skip_spaces_and_comments(&cur)) goto arr_val_end; |
| 6179 | if (byte_match_2(cur, "/*" )) goto fail_comment; |
| 6180 | } |
| 6181 | goto fail_character; |
| 6182 | |
| 6183 | arr_end: |
| 6184 | /* get parent container */ |
| 6185 | ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs); |
| 6186 | |
| 6187 | /* save the next sibling value offset */ |
| 6188 | ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val); |
| 6189 | ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR; |
| 6190 | if (unlikely(ctn == ctn_parent)) goto doc_end; |
| 6191 | |
| 6192 | /* pop parent as current container */ |
| 6193 | ctn = ctn_parent; |
| 6194 | ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT); |
| 6195 | if (*cur == '\n') cur++; |
| 6196 | if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) { |
| 6197 | goto obj_val_end; |
| 6198 | } else { |
| 6199 | goto arr_val_end; |
| 6200 | } |
| 6201 | |
| 6202 | obj_begin: |
| 6203 | /* push container */ |
| 6204 | ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) | |
| 6205 | (ctn->tag & YYJSON_TAG_MASK); |
| 6206 | val_incr(); |
| 6207 | val->tag = YYJSON_TYPE_OBJ; |
| 6208 | /* offset to the parent */ |
| 6209 | val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn); |
| 6210 | ctn = val; |
| 6211 | ctn_len = 0; |
| 6212 | if (*cur == '\n') cur++; |
| 6213 | |
| 6214 | obj_key_begin: |
| 6215 | #if YYJSON_IS_REAL_GCC |
| 6216 | while (true) repeat16({ |
| 6217 | if (byte_match_2(cur, " " )) cur += 2; |
| 6218 | else break; |
| 6219 | }) |
| 6220 | #else |
| 6221 | while (true) repeat16({ |
| 6222 | if (likely(byte_match_2(cur, " " ))) cur += 2; |
| 6223 | else break; |
| 6224 | }) |
| 6225 | #endif |
| 6226 | if (likely(*cur == '"')) { |
| 6227 | val_incr(); |
| 6228 | ctn_len++; |
| 6229 | if (likely(read_string(&cur, end, inv, val, &msg))) goto obj_key_end; |
| 6230 | goto fail_string; |
| 6231 | } |
| 6232 | if (likely(*cur == '}')) { |
| 6233 | cur++; |
| 6234 | if (likely(ctn_len == 0)) goto obj_end; |
| 6235 | if (has_flag(ALLOW_TRAILING_COMMAS)) goto obj_end; |
| 6236 | while (*cur != ',') cur--; |
| 6237 | goto fail_trailing_comma; |
| 6238 | } |
| 6239 | if (char_is_space(*cur)) { |
| 6240 | while (char_is_space(*++cur)); |
| 6241 | goto obj_key_begin; |
| 6242 | } |
| 6243 | if (has_flag(ALLOW_COMMENTS)) { |
| 6244 | if (skip_spaces_and_comments(&cur)) goto obj_key_begin; |
| 6245 | if (byte_match_2(cur, "/*" )) goto fail_comment; |
| 6246 | } |
| 6247 | goto fail_character; |
| 6248 | |
| 6249 | obj_key_end: |
| 6250 | if (byte_match_2(cur, ": " )) { |
| 6251 | cur += 2; |
| 6252 | goto obj_val_begin; |
| 6253 | } |
| 6254 | if (*cur == ':') { |
| 6255 | cur++; |
| 6256 | goto obj_val_begin; |
| 6257 | } |
| 6258 | if (char_is_space(*cur)) { |
| 6259 | while (char_is_space(*++cur)); |
| 6260 | goto obj_key_end; |
| 6261 | } |
| 6262 | if (has_flag(ALLOW_COMMENTS)) { |
| 6263 | if (skip_spaces_and_comments(&cur)) goto obj_key_end; |
| 6264 | if (byte_match_2(cur, "/*" )) goto fail_comment; |
| 6265 | } |
| 6266 | goto fail_character; |
| 6267 | |
| 6268 | obj_val_begin: |
| 6269 | if (*cur == '"') { |
| 6270 | val++; |
| 6271 | ctn_len++; |
| 6272 | if (likely(read_string(&cur, end, inv, val, &msg))) goto obj_val_end; |
| 6273 | goto fail_string; |
| 6274 | } |
| 6275 | if (char_is_number(*cur)) { |
| 6276 | val++; |
| 6277 | ctn_len++; |
| 6278 | if (likely(read_number(&cur, pre, flg, val, &msg))) goto obj_val_end; |
| 6279 | goto fail_number; |
| 6280 | } |
| 6281 | if (*cur == '{') { |
| 6282 | cur++; |
| 6283 | goto obj_begin; |
| 6284 | } |
| 6285 | if (*cur == '[') { |
| 6286 | cur++; |
| 6287 | goto arr_begin; |
| 6288 | } |
| 6289 | if (*cur == 't') { |
| 6290 | val++; |
| 6291 | ctn_len++; |
| 6292 | if (likely(read_true(&cur, val))) goto obj_val_end; |
| 6293 | goto fail_literal; |
| 6294 | } |
| 6295 | if (*cur == 'f') { |
| 6296 | val++; |
| 6297 | ctn_len++; |
| 6298 | if (likely(read_false(&cur, val))) goto obj_val_end; |
| 6299 | goto fail_literal; |
| 6300 | } |
| 6301 | if (*cur == 'n') { |
| 6302 | val++; |
| 6303 | ctn_len++; |
| 6304 | if (likely(read_null(&cur, val))) goto obj_val_end; |
| 6305 | if (unlikely(flg & YYJSON_READ_ALLOW_INF_AND_NAN)) { |
| 6306 | if (read_nan(false, &cur, pre, val)) goto obj_val_end; |
| 6307 | } |
| 6308 | goto fail_literal; |
| 6309 | } |
| 6310 | if (char_is_space(*cur)) { |
| 6311 | while (char_is_space(*++cur)); |
| 6312 | goto obj_val_begin; |
| 6313 | } |
| 6314 | if (unlikely(flg & YYJSON_READ_ALLOW_INF_AND_NAN) && |
| 6315 | (*cur == 'i' || *cur == 'I' || *cur == 'N')) { |
| 6316 | val++; |
| 6317 | ctn_len++; |
| 6318 | if (read_inf_or_nan(false, &cur, pre, val)) goto obj_val_end; |
| 6319 | goto fail_character; |
| 6320 | } |
| 6321 | if (has_flag(ALLOW_COMMENTS)) { |
| 6322 | if (skip_spaces_and_comments(&cur)) goto obj_val_begin; |
| 6323 | if (byte_match_2(cur, "/*" )) goto fail_comment; |
| 6324 | } |
| 6325 | goto fail_character; |
| 6326 | |
| 6327 | obj_val_end: |
| 6328 | if (byte_match_2(cur, ",\n" )) { |
| 6329 | cur += 2; |
| 6330 | goto obj_key_begin; |
| 6331 | } |
| 6332 | if (likely(*cur == ',')) { |
| 6333 | cur++; |
| 6334 | goto obj_key_begin; |
| 6335 | } |
| 6336 | if (likely(*cur == '}')) { |
| 6337 | cur++; |
| 6338 | goto obj_end; |
| 6339 | } |
| 6340 | if (char_is_space(*cur)) { |
| 6341 | while (char_is_space(*++cur)); |
| 6342 | goto obj_val_end; |
| 6343 | } |
| 6344 | if (has_flag(ALLOW_COMMENTS)) { |
| 6345 | if (skip_spaces_and_comments(&cur)) goto obj_val_end; |
| 6346 | if (byte_match_2(cur, "/*" )) goto fail_comment; |
| 6347 | } |
| 6348 | goto fail_character; |
| 6349 | |
| 6350 | obj_end: |
| 6351 | /* pop container */ |
| 6352 | ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs); |
| 6353 | /* point to the next value */ |
| 6354 | ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val); |
| 6355 | ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ; |
| 6356 | if (unlikely(ctn == ctn_parent)) goto doc_end; |
| 6357 | ctn = ctn_parent; |
| 6358 | ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT); |
| 6359 | if (*cur == '\n') cur++; |
| 6360 | if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) { |
| 6361 | goto obj_val_end; |
| 6362 | } else { |
| 6363 | goto arr_val_end; |
| 6364 | } |
| 6365 | |
| 6366 | doc_end: |
| 6367 | /* check invalid contents after json document */ |
| 6368 | if (unlikely(cur < end) && !has_flag(STOP_WHEN_DONE)) { |
| 6369 | if (has_flag(ALLOW_COMMENTS)) { |
| 6370 | skip_spaces_and_comments(&cur); |
| 6371 | if (byte_match_2(cur, "/*" )) goto fail_comment; |
| 6372 | } |
| 6373 | else while (char_is_space(*cur)) cur++; |
| 6374 | if (unlikely(cur < end)) goto fail_garbage; |
| 6375 | } |
| 6376 | |
| 6377 | if (pre && *pre) **pre = '\0'; |
| 6378 | doc = (yyjson_doc *)val_hdr; |
| 6379 | doc->root = val_hdr + hdr_len; |
| 6380 | doc->alc = alc; |
| 6381 | doc->dat_read = (usize)(cur - hdr); |
| 6382 | doc->val_read = (usize)((val - val_hdr)) - hdr_len + 1; |
| 6383 | doc->str_pool = has_flag(INSITU) ? NULL : (char *)hdr; |
| 6384 | return doc; |
| 6385 | |
| 6386 | fail_string: |
| 6387 | return_err(cur, INVALID_STRING, msg); |
| 6388 | fail_number: |
| 6389 | return_err(cur, INVALID_NUMBER, msg); |
| 6390 | fail_alloc: |
| 6391 | return_err(cur, MEMORY_ALLOCATION, "memory allocation failed" ); |
| 6392 | fail_trailing_comma: |
| 6393 | return_err(cur, JSON_STRUCTURE, "trailing comma is not allowed" ); |
| 6394 | fail_literal: |
| 6395 | return_err(cur, LITERAL, "invalid literal" ); |
| 6396 | : |
| 6397 | return_err(cur, INVALID_COMMENT, "unclosed multiline comment" ); |
| 6398 | fail_character: |
| 6399 | return_err(cur, UNEXPECTED_CHARACTER, "unexpected character" ); |
| 6400 | fail_garbage: |
| 6401 | return_err(cur, UNEXPECTED_CONTENT, "unexpected content after document" ); |
| 6402 | |
| 6403 | #undef has_flag |
| 6404 | #undef val_incr |
| 6405 | #undef return_err |
| 6406 | } |
| 6407 | |
| 6408 | |
| 6409 | |
| 6410 | /*============================================================================== |
| 6411 | * JSON Reader Entrance |
| 6412 | *============================================================================*/ |
| 6413 | |
| 6414 | yyjson_doc *yyjson_read_opts(char *dat, |
| 6415 | usize len, |
| 6416 | yyjson_read_flag flg, |
| 6417 | const yyjson_alc *alc_ptr, |
| 6418 | yyjson_read_err *err) { |
| 6419 | |
| 6420 | #define has_flag(_flag) unlikely((flg & YYJSON_READ_##_flag) != 0) |
| 6421 | |
| 6422 | #define return_err(_pos, _code, _msg) do { \ |
| 6423 | err->pos = (usize)(_pos); \ |
| 6424 | err->msg = _msg; \ |
| 6425 | err->code = YYJSON_READ_ERROR_##_code; \ |
| 6426 | if (!has_flag(INSITU) && hdr) alc.free(alc.ctx, (void *)hdr); \ |
| 6427 | return NULL; \ |
| 6428 | } while (false) |
| 6429 | |
| 6430 | yyjson_read_err dummy_err; |
| 6431 | yyjson_alc alc; |
| 6432 | yyjson_doc *doc; |
| 6433 | u8 *hdr = NULL, *end, *cur; |
| 6434 | |
| 6435 | #if YYJSON_DISABLE_NON_STANDARD |
| 6436 | flg &= ~YYJSON_READ_ALLOW_TRAILING_COMMAS; |
| 6437 | flg &= ~YYJSON_READ_ALLOW_COMMENTS; |
| 6438 | flg &= ~YYJSON_READ_ALLOW_INF_AND_NAN; |
| 6439 | flg &= ~YYJSON_READ_ALLOW_INVALID_UNICODE; |
| 6440 | #endif |
| 6441 | |
| 6442 | /* validate input parameters */ |
| 6443 | if (!err) err = &dummy_err; |
| 6444 | if (likely(!alc_ptr)) { |
| 6445 | alc = YYJSON_DEFAULT_ALC; |
| 6446 | } else { |
| 6447 | alc = *alc_ptr; |
| 6448 | } |
| 6449 | if (unlikely(!dat)) { |
| 6450 | return_err(0, INVALID_PARAMETER, "input data is NULL" ); |
| 6451 | } |
| 6452 | if (unlikely(!len)) { |
| 6453 | return_err(0, INVALID_PARAMETER, "input length is 0" ); |
| 6454 | } |
| 6455 | |
| 6456 | /* add 4-byte zero padding for input data if necessary */ |
| 6457 | if (has_flag(INSITU)) { |
| 6458 | hdr = (u8 *)dat; |
| 6459 | end = (u8 *)dat + len; |
| 6460 | cur = (u8 *)dat; |
| 6461 | } else { |
| 6462 | if (unlikely(len >= USIZE_MAX - YYJSON_PADDING_SIZE)) { |
| 6463 | return_err(0, MEMORY_ALLOCATION, "memory allocation failed" ); |
| 6464 | } |
| 6465 | hdr = (u8 *)alc.malloc(alc.ctx, len + YYJSON_PADDING_SIZE); |
| 6466 | if (unlikely(!hdr)) { |
| 6467 | return_err(0, MEMORY_ALLOCATION, "memory allocation failed" ); |
| 6468 | } |
| 6469 | end = hdr + len; |
| 6470 | cur = hdr; |
| 6471 | memcpy(hdr, dat, len); |
| 6472 | memset(end, 0, YYJSON_PADDING_SIZE); |
| 6473 | } |
| 6474 | |
| 6475 | /* skip empty contents before json document */ |
| 6476 | if (unlikely(char_is_space_or_comment(*cur))) { |
| 6477 | if (has_flag(ALLOW_COMMENTS)) { |
| 6478 | if (!skip_spaces_and_comments(&cur)) { |
| 6479 | return_err(cur - hdr, INVALID_COMMENT, |
| 6480 | "unclosed multiline comment" ); |
| 6481 | } |
| 6482 | } else { |
| 6483 | if (likely(char_is_space(*cur))) { |
| 6484 | while (char_is_space(*++cur)); |
| 6485 | } |
| 6486 | } |
| 6487 | if (unlikely(cur >= end)) { |
| 6488 | return_err(0, EMPTY_CONTENT, "input data is empty" ); |
| 6489 | } |
| 6490 | } |
| 6491 | |
| 6492 | /* read json document */ |
| 6493 | if (likely(char_is_container(*cur))) { |
| 6494 | if (char_is_space(cur[1]) && char_is_space(cur[2])) { |
| 6495 | doc = read_root_pretty(hdr, cur, end, alc, flg, err); |
| 6496 | } else { |
| 6497 | doc = read_root_minify(hdr, cur, end, alc, flg, err); |
| 6498 | } |
| 6499 | } else { |
| 6500 | doc = read_root_single(hdr, cur, end, alc, flg, err); |
| 6501 | } |
| 6502 | |
| 6503 | /* check result */ |
| 6504 | if (likely(doc)) { |
| 6505 | memset(err, 0, sizeof(yyjson_read_err)); |
| 6506 | } else { |
| 6507 | /* RFC 8259: JSON text MUST be encoded using UTF-8 */ |
| 6508 | if (err->pos == 0 && err->code != YYJSON_READ_ERROR_MEMORY_ALLOCATION) { |
| 6509 | if ((hdr[0] == 0xEF && hdr[1] == 0xBB && hdr[2] == 0xBF)) { |
| 6510 | err->msg = "byte order mark (BOM) is not supported" ; |
| 6511 | } else if (len >= 4 && |
| 6512 | ((hdr[0] == 0x00 && hdr[1] == 0x00 && |
| 6513 | hdr[2] == 0xFE && hdr[3] == 0xFF) || |
| 6514 | (hdr[0] == 0xFF && hdr[1] == 0xFE && |
| 6515 | hdr[2] == 0x00 && hdr[3] == 0x00))) { |
| 6516 | err->msg = "UTF-32 encoding is not supported" ; |
| 6517 | } else if (len >= 2 && |
| 6518 | ((hdr[0] == 0xFE && hdr[1] == 0xFF) || |
| 6519 | (hdr[0] == 0xFF && hdr[1] == 0xFE))) { |
| 6520 | err->msg = "UTF-16 encoding is not supported" ; |
| 6521 | } |
| 6522 | } |
| 6523 | if (!has_flag(INSITU)) alc.free(alc.ctx, (void *)hdr); |
| 6524 | } |
| 6525 | return doc; |
| 6526 | |
| 6527 | #undef has_flag |
| 6528 | #undef return_err |
| 6529 | } |
| 6530 | |
| 6531 | yyjson_doc *yyjson_read_file(const char *path, |
| 6532 | yyjson_read_flag flg, |
| 6533 | const yyjson_alc *alc_ptr, |
| 6534 | yyjson_read_err *err) { |
| 6535 | #define return_err(_code, _msg) do { \ |
| 6536 | err->pos = 0; \ |
| 6537 | err->msg = _msg; \ |
| 6538 | err->code = YYJSON_READ_ERROR_##_code; \ |
| 6539 | return NULL; \ |
| 6540 | } while (false) |
| 6541 | |
| 6542 | yyjson_read_err dummy_err; |
| 6543 | yyjson_doc *doc; |
| 6544 | FILE *file; |
| 6545 | |
| 6546 | if (!err) err = &dummy_err; |
| 6547 | if (unlikely(!path)) return_err(INVALID_PARAMETER, "input path is NULL" ); |
| 6548 | |
| 6549 | file = fopen_readonly(path); |
| 6550 | if (unlikely(!file)) return_err(FILE_OPEN, "file opening failed" ); |
| 6551 | |
| 6552 | doc = yyjson_read_fp(file, flg, alc_ptr, err); |
| 6553 | fclose(file); |
| 6554 | return doc; |
| 6555 | |
| 6556 | #undef return_err |
| 6557 | } |
| 6558 | |
| 6559 | yyjson_doc *yyjson_read_fp(FILE *file, |
| 6560 | yyjson_read_flag flg, |
| 6561 | const yyjson_alc *alc_ptr, |
| 6562 | yyjson_read_err *err) { |
| 6563 | #define return_err(_code, _msg) do { \ |
| 6564 | err->pos = 0; \ |
| 6565 | err->msg = _msg; \ |
| 6566 | err->code = YYJSON_READ_ERROR_##_code; \ |
| 6567 | if (buf) alc.free(alc.ctx, buf); \ |
| 6568 | return NULL; \ |
| 6569 | } while (false) |
| 6570 | |
| 6571 | yyjson_read_err dummy_err; |
| 6572 | yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC; |
| 6573 | yyjson_doc *doc; |
| 6574 | |
| 6575 | long file_size = 0, file_pos; |
| 6576 | void *buf = NULL; |
| 6577 | usize buf_size = 0; |
| 6578 | |
| 6579 | /* validate input parameters */ |
| 6580 | if (!err) err = &dummy_err; |
| 6581 | if (unlikely(!file)) return_err(INVALID_PARAMETER, "input file is NULL" ); |
| 6582 | |
| 6583 | /* get current position */ |
| 6584 | file_pos = ftell(file); |
| 6585 | if (file_pos != -1) { |
| 6586 | /* get total file size, may fail */ |
| 6587 | if (fseek(file, 0, SEEK_END) == 0) file_size = ftell(file); |
| 6588 | /* reset to original position, may fail */ |
| 6589 | if (fseek(file, file_pos, SEEK_SET) != 0) file_size = 0; |
| 6590 | /* get file size from current postion to end */ |
| 6591 | if (file_size > 0) file_size -= file_pos; |
| 6592 | } |
| 6593 | |
| 6594 | /* read file */ |
| 6595 | if (file_size > 0) { |
| 6596 | /* read the entire file in one call */ |
| 6597 | buf_size = (usize)file_size + YYJSON_PADDING_SIZE; |
| 6598 | buf = alc.malloc(alc.ctx, buf_size); |
| 6599 | if (buf == NULL) { |
| 6600 | return_err(MEMORY_ALLOCATION, "fail to alloc memory" ); |
| 6601 | } |
| 6602 | if (fread_safe(buf, (usize)file_size, file) != (usize)file_size) { |
| 6603 | return_err(FILE_READ, "file reading failed" ); |
| 6604 | } |
| 6605 | } else { |
| 6606 | /* failed to get file size, read it as a stream */ |
| 6607 | usize chunk_min = (usize)64; |
| 6608 | usize chunk_max = (usize)512 * 1024 * 1024; |
| 6609 | usize chunk_now = chunk_min; |
| 6610 | usize read_size; |
| 6611 | void *tmp; |
| 6612 | |
| 6613 | buf_size = YYJSON_PADDING_SIZE; |
| 6614 | while (true) { |
| 6615 | if (buf_size + chunk_now < buf_size) { /* overflow */ |
| 6616 | return_err(MEMORY_ALLOCATION, "fail to alloc memory" ); |
| 6617 | } |
| 6618 | buf_size += chunk_now; |
| 6619 | if (!buf) { |
| 6620 | buf = alc.malloc(alc.ctx, buf_size); |
| 6621 | if (!buf) return_err(MEMORY_ALLOCATION, "fail to alloc memory" ); |
| 6622 | } else { |
| 6623 | tmp = alc.realloc(alc.ctx, buf, buf_size - chunk_now, buf_size); |
| 6624 | if (!tmp) return_err(MEMORY_ALLOCATION, "fail to alloc memory" ); |
| 6625 | buf = tmp; |
| 6626 | } |
| 6627 | tmp = ((u8 *)buf) + buf_size - YYJSON_PADDING_SIZE - chunk_now; |
| 6628 | read_size = fread_safe(tmp, chunk_now, file); |
| 6629 | file_size += (long)read_size; |
| 6630 | if (read_size != chunk_now) break; |
| 6631 | |
| 6632 | chunk_now *= 2; |
| 6633 | if (chunk_now > chunk_max) chunk_now = chunk_max; |
| 6634 | } |
| 6635 | } |
| 6636 | |
| 6637 | /* read JSON */ |
| 6638 | memset((u8 *)buf + file_size, 0, YYJSON_PADDING_SIZE); |
| 6639 | flg |= YYJSON_READ_INSITU; |
| 6640 | doc = yyjson_read_opts((char *)buf, (usize)file_size, flg, &alc, err); |
| 6641 | if (doc) { |
| 6642 | doc->str_pool = (char *)buf; |
| 6643 | return doc; |
| 6644 | } else { |
| 6645 | alc.free(alc.ctx, buf); |
| 6646 | return NULL; |
| 6647 | } |
| 6648 | |
| 6649 | #undef return_err |
| 6650 | } |
| 6651 | |
| 6652 | const char *yyjson_read_number(const char *dat, |
| 6653 | yyjson_val *val, |
| 6654 | yyjson_read_flag flg, |
| 6655 | const yyjson_alc *alc, |
| 6656 | yyjson_read_err *err) { |
| 6657 | #define return_err(_pos, _code, _msg) do { \ |
| 6658 | err->pos = _pos > hdr ? (usize)(_pos - hdr) : 0; \ |
| 6659 | err->msg = _msg; \ |
| 6660 | err->code = YYJSON_READ_ERROR_##_code; \ |
| 6661 | return NULL; \ |
| 6662 | } while (false) |
| 6663 | |
| 6664 | u8 *hdr = constcast(u8 *)dat, *cur = hdr; |
| 6665 | bool raw; /* read number as raw */ |
| 6666 | u8 *raw_end; /* raw end for null-terminator */ |
| 6667 | u8 **pre; /* previous raw end pointer */ |
| 6668 | const char *msg; |
| 6669 | yyjson_read_err dummy_err; |
| 6670 | |
| 6671 | #if !YYJSON_HAS_IEEE_754 || YYJSON_DISABLE_FAST_FP_CONV |
| 6672 | u8 buf[128]; |
| 6673 | usize dat_len; |
| 6674 | #endif |
| 6675 | |
| 6676 | if (!err) err = &dummy_err; |
| 6677 | if (unlikely(!dat)) { |
| 6678 | return_err(cur, INVALID_PARAMETER, "input data is NULL" ); |
| 6679 | } |
| 6680 | if (unlikely(!val)) { |
| 6681 | return_err(cur, INVALID_PARAMETER, "output value is NULL" ); |
| 6682 | } |
| 6683 | |
| 6684 | #if !YYJSON_HAS_IEEE_754 || YYJSON_DISABLE_FAST_FP_CONV |
| 6685 | if (!alc) alc = &YYJSON_DEFAULT_ALC; |
| 6686 | dat_len = strlen(dat); |
| 6687 | if (dat_len < sizeof(buf)) { |
| 6688 | memcpy(buf, dat, dat_len + 1); |
| 6689 | hdr = buf; |
| 6690 | cur = hdr; |
| 6691 | } else { |
| 6692 | hdr = (u8 *)alc->malloc(alc->ctx, dat_len + 1); |
| 6693 | cur = hdr; |
| 6694 | if (unlikely(!hdr)) { |
| 6695 | return_err(cur, MEMORY_ALLOCATION, "memory allocation failed" ); |
| 6696 | } |
| 6697 | memcpy(hdr, dat, dat_len + 1); |
| 6698 | } |
| 6699 | hdr[dat_len] = 0; |
| 6700 | #endif |
| 6701 | |
| 6702 | #if YYJSON_DISABLE_NON_STANDARD |
| 6703 | flg &= ~YYJSON_READ_ALLOW_INF_AND_NAN; |
| 6704 | #endif |
| 6705 | |
| 6706 | raw = (flg & (YYJSON_READ_NUMBER_AS_RAW | YYJSON_READ_BIGNUM_AS_RAW)) != 0; |
| 6707 | raw_end = NULL; |
| 6708 | pre = raw ? &raw_end : NULL; |
| 6709 | |
| 6710 | #if !YYJSON_HAS_IEEE_754 || YYJSON_DISABLE_FAST_FP_CONV |
| 6711 | if (!read_number(&cur, pre, flg, val, &msg)) { |
| 6712 | if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr); |
| 6713 | return_err(cur, INVALID_NUMBER, msg); |
| 6714 | } |
| 6715 | if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr); |
| 6716 | if (yyjson_is_raw(val)) val->uni.str = dat; |
| 6717 | return dat + (cur - hdr); |
| 6718 | #else |
| 6719 | if (!read_number(&cur, pre, flg, val, &msg)) { |
| 6720 | return_err(cur, INVALID_NUMBER, msg); |
| 6721 | } |
| 6722 | return (const char *)cur; |
| 6723 | #endif |
| 6724 | |
| 6725 | #undef return_err |
| 6726 | } |
| 6727 | |
| 6728 | #endif /* YYJSON_DISABLE_READER */ |
| 6729 | |
| 6730 | |
| 6731 | |
| 6732 | #if !YYJSON_DISABLE_WRITER |
| 6733 | |
| 6734 | /*============================================================================== |
| 6735 | * Integer Writer |
| 6736 | * |
| 6737 | * The maximum value of uint32_t is 4294967295 (10 digits), |
| 6738 | * these digits are named as 'aabbccddee' here. |
| 6739 | * |
| 6740 | * Although most compilers may convert the "division by constant value" into |
| 6741 | * "multiply and shift", manual conversion can still help some compilers |
| 6742 | * generate fewer and better instructions. |
| 6743 | * |
| 6744 | * Reference: |
| 6745 | * Division by Invariant Integers using Multiplication, 1994. |
| 6746 | * https://gmplib.org/~tege/divcnst-pldi94.pdf |
| 6747 | * Improved division by invariant integers, 2011. |
| 6748 | * https://gmplib.org/~tege/division-paper.pdf |
| 6749 | *============================================================================*/ |
| 6750 | |
| 6751 | /** Digit table from 00 to 99. */ |
| 6752 | yyjson_align(2) |
| 6753 | static const char digit_table[200] = { |
| 6754 | '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', |
| 6755 | '0', '5', '0', '6', '0', '7', '0', '8', '0', '9', |
| 6756 | '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', |
| 6757 | '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', |
| 6758 | '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', |
| 6759 | '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', |
| 6760 | '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', |
| 6761 | '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', |
| 6762 | '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', |
| 6763 | '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', |
| 6764 | '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', |
| 6765 | '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', |
| 6766 | '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', |
| 6767 | '6', '5', '6', '6', '6', '7', '6', '8', '6', '9', |
| 6768 | '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', |
| 6769 | '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', |
| 6770 | '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', |
| 6771 | '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', |
| 6772 | '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', |
| 6773 | '9', '5', '9', '6', '9', '7', '9', '8', '9', '9' |
| 6774 | }; |
| 6775 | |
| 6776 | static_inline u8 *write_u32_len_8(u32 val, u8 *buf) { |
| 6777 | u32 aa, bb, cc, dd, aabb, ccdd; /* 8 digits: aabbccdd */ |
| 6778 | aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */ |
| 6779 | ccdd = val - aabb * 10000; /* (val % 10000) */ |
| 6780 | aa = (aabb * 5243) >> 19; /* (aabb / 100) */ |
| 6781 | cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */ |
| 6782 | bb = aabb - aa * 100; /* (aabb % 100) */ |
| 6783 | dd = ccdd - cc * 100; /* (ccdd % 100) */ |
| 6784 | byte_copy_2(buf + 0, digit_table + aa * 2); |
| 6785 | byte_copy_2(buf + 2, digit_table + bb * 2); |
| 6786 | byte_copy_2(buf + 4, digit_table + cc * 2); |
| 6787 | byte_copy_2(buf + 6, digit_table + dd * 2); |
| 6788 | return buf + 8; |
| 6789 | } |
| 6790 | |
| 6791 | static_inline u8 *write_u32_len_4(u32 val, u8 *buf) { |
| 6792 | u32 aa, bb; /* 4 digits: aabb */ |
| 6793 | aa = (val * 5243) >> 19; /* (val / 100) */ |
| 6794 | bb = val - aa * 100; /* (val % 100) */ |
| 6795 | byte_copy_2(buf + 0, digit_table + aa * 2); |
| 6796 | byte_copy_2(buf + 2, digit_table + bb * 2); |
| 6797 | return buf + 4; |
| 6798 | } |
| 6799 | |
| 6800 | static_inline u8 *write_u32_len_1_8(u32 val, u8 *buf) { |
| 6801 | u32 aa, bb, cc, dd, aabb, bbcc, ccdd, lz; |
| 6802 | |
| 6803 | if (val < 100) { /* 1-2 digits: aa */ |
| 6804 | lz = val < 10; /* leading zero: 0 or 1 */ |
| 6805 | byte_copy_2(buf + 0, digit_table + val * 2 + lz); |
| 6806 | buf -= lz; |
| 6807 | return buf + 2; |
| 6808 | |
| 6809 | } else if (val < 10000) { /* 3-4 digits: aabb */ |
| 6810 | aa = (val * 5243) >> 19; /* (val / 100) */ |
| 6811 | bb = val - aa * 100; /* (val % 100) */ |
| 6812 | lz = aa < 10; /* leading zero: 0 or 1 */ |
| 6813 | byte_copy_2(buf + 0, digit_table + aa * 2 + lz); |
| 6814 | buf -= lz; |
| 6815 | byte_copy_2(buf + 2, digit_table + bb * 2); |
| 6816 | return buf + 4; |
| 6817 | |
| 6818 | } else if (val < 1000000) { /* 5-6 digits: aabbcc */ |
| 6819 | aa = (u32)(((u64)val * 429497) >> 32); /* (val / 10000) */ |
| 6820 | bbcc = val - aa * 10000; /* (val % 10000) */ |
| 6821 | bb = (bbcc * 5243) >> 19; /* (bbcc / 100) */ |
| 6822 | cc = bbcc - bb * 100; /* (bbcc % 100) */ |
| 6823 | lz = aa < 10; /* leading zero: 0 or 1 */ |
| 6824 | byte_copy_2(buf + 0, digit_table + aa * 2 + lz); |
| 6825 | buf -= lz; |
| 6826 | byte_copy_2(buf + 2, digit_table + bb * 2); |
| 6827 | byte_copy_2(buf + 4, digit_table + cc * 2); |
| 6828 | return buf + 6; |
| 6829 | |
| 6830 | } else { /* 7-8 digits: aabbccdd */ |
| 6831 | aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */ |
| 6832 | ccdd = val - aabb * 10000; /* (val % 10000) */ |
| 6833 | aa = (aabb * 5243) >> 19; /* (aabb / 100) */ |
| 6834 | cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */ |
| 6835 | bb = aabb - aa * 100; /* (aabb % 100) */ |
| 6836 | dd = ccdd - cc * 100; /* (ccdd % 100) */ |
| 6837 | lz = aa < 10; /* leading zero: 0 or 1 */ |
| 6838 | byte_copy_2(buf + 0, digit_table + aa * 2 + lz); |
| 6839 | buf -= lz; |
| 6840 | byte_copy_2(buf + 2, digit_table + bb * 2); |
| 6841 | byte_copy_2(buf + 4, digit_table + cc * 2); |
| 6842 | byte_copy_2(buf + 6, digit_table + dd * 2); |
| 6843 | return buf + 8; |
| 6844 | } |
| 6845 | } |
| 6846 | |
| 6847 | static_inline u8 *write_u64_len_5_8(u32 val, u8 *buf) { |
| 6848 | u32 aa, bb, cc, dd, aabb, bbcc, ccdd, lz; |
| 6849 | |
| 6850 | if (val < 1000000) { /* 5-6 digits: aabbcc */ |
| 6851 | aa = (u32)(((u64)val * 429497) >> 32); /* (val / 10000) */ |
| 6852 | bbcc = val - aa * 10000; /* (val % 10000) */ |
| 6853 | bb = (bbcc * 5243) >> 19; /* (bbcc / 100) */ |
| 6854 | cc = bbcc - bb * 100; /* (bbcc % 100) */ |
| 6855 | lz = aa < 10; /* leading zero: 0 or 1 */ |
| 6856 | byte_copy_2(buf + 0, digit_table + aa * 2 + lz); |
| 6857 | buf -= lz; |
| 6858 | byte_copy_2(buf + 2, digit_table + bb * 2); |
| 6859 | byte_copy_2(buf + 4, digit_table + cc * 2); |
| 6860 | return buf + 6; |
| 6861 | |
| 6862 | } else { /* 7-8 digits: aabbccdd */ |
| 6863 | aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */ |
| 6864 | ccdd = val - aabb * 10000; /* (val % 10000) */ |
| 6865 | aa = (aabb * 5243) >> 19; /* (aabb / 100) */ |
| 6866 | cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */ |
| 6867 | bb = aabb - aa * 100; /* (aabb % 100) */ |
| 6868 | dd = ccdd - cc * 100; /* (ccdd % 100) */ |
| 6869 | lz = aa < 10; /* leading zero: 0 or 1 */ |
| 6870 | byte_copy_2(buf + 0, digit_table + aa * 2 + lz); |
| 6871 | buf -= lz; |
| 6872 | byte_copy_2(buf + 2, digit_table + bb * 2); |
| 6873 | byte_copy_2(buf + 4, digit_table + cc * 2); |
| 6874 | byte_copy_2(buf + 6, digit_table + dd * 2); |
| 6875 | return buf + 8; |
| 6876 | } |
| 6877 | } |
| 6878 | |
| 6879 | static_inline u8 *write_u64(u64 val, u8 *buf) { |
| 6880 | u64 tmp, hgh; |
| 6881 | u32 mid, low; |
| 6882 | |
| 6883 | if (val < 100000000) { /* 1-8 digits */ |
| 6884 | buf = write_u32_len_1_8((u32)val, buf); |
| 6885 | return buf; |
| 6886 | |
| 6887 | } else if (val < (u64)100000000 * 100000000) { /* 9-16 digits */ |
| 6888 | hgh = val / 100000000; /* (val / 100000000) */ |
| 6889 | low = (u32)(val - hgh * 100000000); /* (val % 100000000) */ |
| 6890 | buf = write_u32_len_1_8((u32)hgh, buf); |
| 6891 | buf = write_u32_len_8(low, buf); |
| 6892 | return buf; |
| 6893 | |
| 6894 | } else { /* 17-20 digits */ |
| 6895 | tmp = val / 100000000; /* (val / 100000000) */ |
| 6896 | low = (u32)(val - tmp * 100000000); /* (val % 100000000) */ |
| 6897 | hgh = (u32)(tmp / 10000); /* (tmp / 10000) */ |
| 6898 | mid = (u32)(tmp - hgh * 10000); /* (tmp % 10000) */ |
| 6899 | buf = write_u64_len_5_8((u32)hgh, buf); |
| 6900 | buf = write_u32_len_4(mid, buf); |
| 6901 | buf = write_u32_len_8(low, buf); |
| 6902 | return buf; |
| 6903 | } |
| 6904 | } |
| 6905 | |
| 6906 | |
| 6907 | |
| 6908 | /*============================================================================== |
| 6909 | * Number Writer |
| 6910 | *============================================================================*/ |
| 6911 | |
| 6912 | #if YYJSON_HAS_IEEE_754 && !YYJSON_DISABLE_FAST_FP_CONV /* FP_WRITER */ |
| 6913 | |
| 6914 | /** Trailing zero count table for number 0 to 99. |
| 6915 | (generate with misc/make_tables.c) */ |
| 6916 | static const u8 dec_trailing_zero_table[] = { |
| 6917 | 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 6918 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 6919 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 6920 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 6921 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 6922 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 6923 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 6924 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 6925 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 6926 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
| 6927 | }; |
| 6928 | |
| 6929 | /** Write an unsigned integer with a length of 1 to 16. */ |
| 6930 | static_inline u8 *write_u64_len_1_to_16(u64 val, u8 *buf) { |
| 6931 | u64 hgh; |
| 6932 | u32 low; |
| 6933 | if (val < 100000000) { /* 1-8 digits */ |
| 6934 | buf = write_u32_len_1_8((u32)val, buf); |
| 6935 | return buf; |
| 6936 | } else { /* 9-16 digits */ |
| 6937 | hgh = val / 100000000; /* (val / 100000000) */ |
| 6938 | low = (u32)(val - hgh * 100000000); /* (val % 100000000) */ |
| 6939 | buf = write_u32_len_1_8((u32)hgh, buf); |
| 6940 | buf = write_u32_len_8(low, buf); |
| 6941 | return buf; |
| 6942 | } |
| 6943 | } |
| 6944 | |
| 6945 | /** Write an unsigned integer with a length of 1 to 17. */ |
| 6946 | static_inline u8 *write_u64_len_1_to_17(u64 val, u8 *buf) { |
| 6947 | u64 hgh; |
| 6948 | u32 mid, low, one; |
| 6949 | if (val >= (u64)100000000 * 10000000) { /* len: 16 to 17 */ |
| 6950 | hgh = val / 100000000; /* (val / 100000000) */ |
| 6951 | low = (u32)(val - hgh * 100000000); /* (val % 100000000) */ |
| 6952 | one = (u32)(hgh / 100000000); /* (hgh / 100000000) */ |
| 6953 | mid = (u32)(hgh - (u64)one * 100000000); /* (hgh % 100000000) */ |
| 6954 | *buf = (u8)((u8)one + (u8)'0'); |
| 6955 | buf += one > 0; |
| 6956 | buf = write_u32_len_8(mid, buf); |
| 6957 | buf = write_u32_len_8(low, buf); |
| 6958 | return buf; |
| 6959 | } else if (val >= (u64)100000000){ /* len: 9 to 15 */ |
| 6960 | hgh = val / 100000000; /* (val / 100000000) */ |
| 6961 | low = (u32)(val - hgh * 100000000); /* (val % 100000000) */ |
| 6962 | buf = write_u32_len_1_8((u32)hgh, buf); |
| 6963 | buf = write_u32_len_8(low, buf); |
| 6964 | return buf; |
| 6965 | } else { /* len: 1 to 8 */ |
| 6966 | buf = write_u32_len_1_8((u32)val, buf); |
| 6967 | return buf; |
| 6968 | } |
| 6969 | } |
| 6970 | |
| 6971 | /** |
| 6972 | Write an unsigned integer with a length of 15 to 17 with trailing zero trimmed. |
| 6973 | These digits are named as "aabbccddeeffgghhii" here. |
| 6974 | For example, input 1234567890123000, output "1234567890123". |
| 6975 | */ |
| 6976 | static_inline u8 *write_u64_len_15_to_17_trim(u8 *buf, u64 sig) { |
| 6977 | bool lz; /* leading zero */ |
| 6978 | u32 tz1, tz2, tz; /* trailing zero */ |
| 6979 | |
| 6980 | u32 abbccddee = (u32)(sig / 100000000); |
| 6981 | u32 ffgghhii = (u32)(sig - (u64)abbccddee * 100000000); |
| 6982 | u32 abbcc = abbccddee / 10000; /* (abbccddee / 10000) */ |
| 6983 | u32 ddee = abbccddee - abbcc * 10000; /* (abbccddee % 10000) */ |
| 6984 | u32 abb = (u32)(((u64)abbcc * 167773) >> 24); /* (abbcc / 100) */ |
| 6985 | u32 a = (abb * 41) >> 12; /* (abb / 100) */ |
| 6986 | u32 bb = abb - a * 100; /* (abb % 100) */ |
| 6987 | u32 cc = abbcc - abb * 100; /* (abbcc % 100) */ |
| 6988 | |
| 6989 | /* write abbcc */ |
| 6990 | buf[0] = (u8)(a + '0'); |
| 6991 | buf += a > 0; |
| 6992 | lz = bb < 10 && a == 0; |
| 6993 | byte_copy_2(buf + 0, digit_table + bb * 2 + lz); |
| 6994 | buf -= lz; |
| 6995 | byte_copy_2(buf + 2, digit_table + cc * 2); |
| 6996 | |
| 6997 | if (ffgghhii) { |
| 6998 | u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */ |
| 6999 | u32 ee = ddee - dd * 100; /* (ddee % 100) */ |
| 7000 | u32 ffgg = (u32)(((u64)ffgghhii * 109951163) >> 40); /* (val / 10000) */ |
| 7001 | u32 hhii = ffgghhii - ffgg * 10000; /* (val % 10000) */ |
| 7002 | u32 ff = (ffgg * 5243) >> 19; /* (aabb / 100) */ |
| 7003 | u32 gg = ffgg - ff * 100; /* (aabb % 100) */ |
| 7004 | byte_copy_2(buf + 4, digit_table + dd * 2); |
| 7005 | byte_copy_2(buf + 6, digit_table + ee * 2); |
| 7006 | byte_copy_2(buf + 8, digit_table + ff * 2); |
| 7007 | byte_copy_2(buf + 10, digit_table + gg * 2); |
| 7008 | if (hhii) { |
| 7009 | u32 hh = (hhii * 5243) >> 19; /* (ccdd / 100) */ |
| 7010 | u32 ii = hhii - hh * 100; /* (ccdd % 100) */ |
| 7011 | byte_copy_2(buf + 12, digit_table + hh * 2); |
| 7012 | byte_copy_2(buf + 14, digit_table + ii * 2); |
| 7013 | tz1 = dec_trailing_zero_table[hh]; |
| 7014 | tz2 = dec_trailing_zero_table[ii]; |
| 7015 | tz = ii ? tz2 : (tz1 + 2); |
| 7016 | buf += 16 - tz; |
| 7017 | return buf; |
| 7018 | } else { |
| 7019 | tz1 = dec_trailing_zero_table[ff]; |
| 7020 | tz2 = dec_trailing_zero_table[gg]; |
| 7021 | tz = gg ? tz2 : (tz1 + 2); |
| 7022 | buf += 12 - tz; |
| 7023 | return buf; |
| 7024 | } |
| 7025 | } else { |
| 7026 | if (ddee) { |
| 7027 | u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */ |
| 7028 | u32 ee = ddee - dd * 100; /* (ddee % 100) */ |
| 7029 | byte_copy_2(buf + 4, digit_table + dd * 2); |
| 7030 | byte_copy_2(buf + 6, digit_table + ee * 2); |
| 7031 | tz1 = dec_trailing_zero_table[dd]; |
| 7032 | tz2 = dec_trailing_zero_table[ee]; |
| 7033 | tz = ee ? tz2 : (tz1 + 2); |
| 7034 | buf += 8 - tz; |
| 7035 | return buf; |
| 7036 | } else { |
| 7037 | tz1 = dec_trailing_zero_table[bb]; |
| 7038 | tz2 = dec_trailing_zero_table[cc]; |
| 7039 | tz = cc ? tz2 : (tz1 + tz2); |
| 7040 | buf += 4 - tz; |
| 7041 | return buf; |
| 7042 | } |
| 7043 | } |
| 7044 | } |
| 7045 | |
| 7046 | /** Write a signed integer in the range -324 to 308. */ |
| 7047 | static_inline u8 *write_f64_exp(i32 exp, u8 *buf) { |
| 7048 | buf[0] = '-'; |
| 7049 | buf += exp < 0; |
| 7050 | exp = exp < 0 ? -exp : exp; |
| 7051 | if (exp < 100) { |
| 7052 | u32 lz = exp < 10; |
| 7053 | byte_copy_2(buf + 0, digit_table + (u32)exp * 2 + lz); |
| 7054 | return buf + 2 - lz; |
| 7055 | } else { |
| 7056 | u32 hi = ((u32)exp * 656) >> 16; /* exp / 100 */ |
| 7057 | u32 lo = (u32)exp - hi * 100; /* exp % 100 */ |
| 7058 | buf[0] = (u8)((u8)hi + (u8)'0'); |
| 7059 | byte_copy_2(buf + 1, digit_table + lo * 2); |
| 7060 | return buf + 3; |
| 7061 | } |
| 7062 | } |
| 7063 | |
| 7064 | /** Multiplies 128-bit integer and returns highest 64-bit rounded value. */ |
| 7065 | static_inline u64 round_to_odd(u64 hi, u64 lo, u64 cp) { |
| 7066 | u64 x_hi, x_lo, y_hi, y_lo; |
| 7067 | u128_mul(cp, lo, &x_hi, &x_lo); |
| 7068 | u128_mul_add(cp, hi, x_hi, &y_hi, &y_lo); |
| 7069 | return y_hi | (y_lo > 1); |
| 7070 | } |
| 7071 | |
| 7072 | /** |
| 7073 | Convert double number from binary to decimal. |
| 7074 | The output significand is shortest decimal but may have trailing zeros. |
| 7075 | |
| 7076 | This function use the Schubfach algorithm: |
| 7077 | Raffaello Giulietti, The Schubfach way to render doubles (5th version), 2022. |
| 7078 | https://drive.google.com/file/d/1gp5xv4CAa78SVgCeWfGqqI4FfYYYuNFb |
| 7079 | https://mail.openjdk.java.net/pipermail/core-libs-dev/2021-November/083536.html |
| 7080 | https://github.com/openjdk/jdk/pull/3402 (Java implementation) |
| 7081 | https://github.com/abolz/Drachennest (C++ implementation) |
| 7082 | |
| 7083 | See also: |
| 7084 | Dragonbox: A New Floating-Point Binary-to-Decimal Conversion Algorithm, 2022. |
| 7085 | https://github.com/jk-jeon/dragonbox/blob/master/other_files/Dragonbox.pdf |
| 7086 | https://github.com/jk-jeon/dragonbox |
| 7087 | |
| 7088 | @param sig_raw The raw value of significand in IEEE 754 format. |
| 7089 | @param exp_raw The raw value of exponent in IEEE 754 format. |
| 7090 | @param sig_bin The decoded value of significand in binary. |
| 7091 | @param exp_bin The decoded value of exponent in binary. |
| 7092 | @param sig_dec The output value of significand in decimal. |
| 7093 | @param exp_dec The output value of exponent in decimal. |
| 7094 | @warning The input double number should not be 0, inf, nan. |
| 7095 | */ |
| 7096 | static_inline void f64_bin_to_dec(u64 sig_raw, u32 exp_raw, |
| 7097 | u64 sig_bin, i32 exp_bin, |
| 7098 | u64 *sig_dec, i32 *exp_dec) { |
| 7099 | |
| 7100 | bool is_even, regular_spacing, u_inside, w_inside, round_up; |
| 7101 | u64 s, sp, cb, cbl, cbr, vb, vbl, vbr, pow10hi, pow10lo, upper, lower, mid; |
| 7102 | i32 k, h, exp10; |
| 7103 | |
| 7104 | is_even = !(sig_bin & 1); |
| 7105 | regular_spacing = (sig_raw == 0 && exp_raw > 1); |
| 7106 | |
| 7107 | cbl = 4 * sig_bin - 2 + regular_spacing; |
| 7108 | cb = 4 * sig_bin; |
| 7109 | cbr = 4 * sig_bin + 2; |
| 7110 | |
| 7111 | /* exp_bin: [-1074, 971] */ |
| 7112 | /* k = regular_spacing ? floor(log10(pow(2, exp_bin))) */ |
| 7113 | /* : floor(log10(pow(2, exp_bin) * 3.0 / 4.0)) */ |
| 7114 | /* = regular_spacing ? floor(exp_bin * log10(2)) */ |
| 7115 | /* : floor(exp_bin * log10(2) + log10(3.0 / 4.0)) */ |
| 7116 | k = (i32)(exp_bin * 315653 - (regular_spacing ? 131237 : 0)) >> 20; |
| 7117 | |
| 7118 | /* k: [-324, 292] */ |
| 7119 | /* h = exp_bin + floor(log2(pow(10, e))) */ |
| 7120 | /* = exp_bin + floor(log2(10) * e) */ |
| 7121 | exp10 = -k; |
| 7122 | h = exp_bin + ((exp10 * 217707) >> 16) + 1; |
| 7123 | |
| 7124 | pow10_table_get_sig(exp10, &pow10hi, &pow10lo); |
| 7125 | pow10lo += (exp10 < POW10_SIG_TABLE_MIN_EXACT_EXP || |
| 7126 | exp10 > POW10_SIG_TABLE_MAX_EXACT_EXP); |
| 7127 | vbl = round_to_odd(pow10hi, pow10lo, cbl << h); |
| 7128 | vb = round_to_odd(pow10hi, pow10lo, cb << h); |
| 7129 | vbr = round_to_odd(pow10hi, pow10lo, cbr << h); |
| 7130 | |
| 7131 | lower = vbl + !is_even; |
| 7132 | upper = vbr - !is_even; |
| 7133 | |
| 7134 | s = vb / 4; |
| 7135 | if (s >= 10) { |
| 7136 | sp = s / 10; |
| 7137 | u_inside = (lower <= 40 * sp); |
| 7138 | w_inside = (upper >= 40 * sp + 40); |
| 7139 | if (u_inside != w_inside) { |
| 7140 | *sig_dec = sp + w_inside; |
| 7141 | *exp_dec = k + 1; |
| 7142 | return; |
| 7143 | } |
| 7144 | } |
| 7145 | |
| 7146 | u_inside = (lower <= 4 * s); |
| 7147 | w_inside = (upper >= 4 * s + 4); |
| 7148 | |
| 7149 | mid = 4 * s + 2; |
| 7150 | round_up = (vb > mid) || (vb == mid && (s & 1) != 0); |
| 7151 | |
| 7152 | *sig_dec = s + ((u_inside != w_inside) ? w_inside : round_up); |
| 7153 | *exp_dec = k; |
| 7154 | } |
| 7155 | |
| 7156 | /** |
| 7157 | Write a double number (requires 32 bytes buffer). |
| 7158 | |
| 7159 | We follows the ECMAScript specification to print floating point numbers, |
| 7160 | but with the following changes: |
| 7161 | 1. Keep the negative sign of 0.0 to preserve input information. |
| 7162 | 2. Keep decimal point to indicate the number is floating point. |
| 7163 | 3. Remove positive sign of exponent part. |
| 7164 | */ |
| 7165 | static_inline u8 *write_f64_raw(u8 *buf, u64 raw, yyjson_write_flag flg) { |
| 7166 | u64 sig_bin, sig_dec, sig_raw; |
| 7167 | i32 exp_bin, exp_dec, sig_len, dot_pos, i, max; |
| 7168 | u32 exp_raw, hi, lo; |
| 7169 | u8 *hdr, *num_hdr, *num_end, *dot_end; |
| 7170 | bool sign; |
| 7171 | |
| 7172 | /* decode raw bytes from IEEE-754 double format. */ |
| 7173 | sign = (bool)(raw >> (F64_BITS - 1)); |
| 7174 | sig_raw = raw & F64_SIG_MASK; |
| 7175 | exp_raw = (u32)((raw & F64_EXP_MASK) >> F64_SIG_BITS); |
| 7176 | |
| 7177 | /* return inf and nan */ |
| 7178 | if (unlikely(exp_raw == ((u32)1 << F64_EXP_BITS) - 1)) { |
| 7179 | if (flg & YYJSON_WRITE_INF_AND_NAN_AS_NULL) { |
| 7180 | byte_copy_4(buf, "null" ); |
| 7181 | return buf + 4; |
| 7182 | } else if (flg & YYJSON_WRITE_ALLOW_INF_AND_NAN) { |
| 7183 | if (sig_raw == 0) { |
| 7184 | buf[0] = '-'; |
| 7185 | buf += sign; |
| 7186 | byte_copy_8(buf, "Infinity" ); |
| 7187 | buf += 8; |
| 7188 | return buf; |
| 7189 | } else { |
| 7190 | byte_copy_4(buf, "NaN" ); |
| 7191 | return buf + 3; |
| 7192 | } |
| 7193 | } else { |
| 7194 | return NULL; |
| 7195 | } |
| 7196 | } |
| 7197 | |
| 7198 | /* add sign for all finite double value, including 0.0 and inf */ |
| 7199 | buf[0] = '-'; |
| 7200 | buf += sign; |
| 7201 | hdr = buf; |
| 7202 | |
| 7203 | /* return zero */ |
| 7204 | if ((raw << 1) == 0) { |
| 7205 | byte_copy_4(buf, "0.0" ); |
| 7206 | buf += 3; |
| 7207 | return buf; |
| 7208 | } |
| 7209 | |
| 7210 | if (likely(exp_raw != 0)) { |
| 7211 | /* normal number */ |
| 7212 | sig_bin = sig_raw | ((u64)1 << F64_SIG_BITS); |
| 7213 | exp_bin = (i32)exp_raw - F64_EXP_BIAS - F64_SIG_BITS; |
| 7214 | |
| 7215 | /* fast path for small integer number without fraction */ |
| 7216 | if (-F64_SIG_BITS <= exp_bin && exp_bin <= 0) { |
| 7217 | if (u64_tz_bits(sig_bin) >= (u32)-exp_bin) { |
| 7218 | /* number is integer in range 1 to 0x1FFFFFFFFFFFFF */ |
| 7219 | sig_dec = sig_bin >> -exp_bin; |
| 7220 | buf = write_u64_len_1_to_16(sig_dec, buf); |
| 7221 | byte_copy_2(buf, ".0" ); |
| 7222 | buf += 2; |
| 7223 | return buf; |
| 7224 | } |
| 7225 | } |
| 7226 | |
| 7227 | /* binary to decimal */ |
| 7228 | f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec); |
| 7229 | |
| 7230 | /* the sig length is 15 to 17 */ |
| 7231 | sig_len = 17; |
| 7232 | sig_len -= (sig_dec < (u64)100000000 * 100000000); |
| 7233 | sig_len -= (sig_dec < (u64)100000000 * 10000000); |
| 7234 | |
| 7235 | /* the decimal point position relative to the first digit */ |
| 7236 | dot_pos = sig_len + exp_dec; |
| 7237 | |
| 7238 | if (-6 < dot_pos && dot_pos <= 21) { |
| 7239 | /* no need to write exponent part */ |
| 7240 | if (dot_pos <= 0) { |
| 7241 | /* dot before first digit */ |
| 7242 | /* such as 0.1234, 0.000001234 */ |
| 7243 | num_hdr = hdr + (2 - dot_pos); |
| 7244 | num_end = write_u64_len_15_to_17_trim(num_hdr, sig_dec); |
| 7245 | hdr[0] = '0'; |
| 7246 | hdr[1] = '.'; |
| 7247 | hdr += 2; |
| 7248 | max = -dot_pos; |
| 7249 | for (i = 0; i < max; i++) hdr[i] = '0'; |
| 7250 | return num_end; |
| 7251 | } else { |
| 7252 | /* dot after first digit */ |
| 7253 | /* such as 1.234, 1234.0, 123400000000000000000.0 */ |
| 7254 | memset(hdr + 0, '0', 8); |
| 7255 | memset(hdr + 8, '0', 8); |
| 7256 | memset(hdr + 16, '0', 8); |
| 7257 | num_hdr = hdr + 1; |
| 7258 | num_end = write_u64_len_15_to_17_trim(num_hdr, sig_dec); |
| 7259 | for (i = 0; i < dot_pos; i++) hdr[i] = hdr[i + 1]; |
| 7260 | hdr[dot_pos] = '.'; |
| 7261 | dot_end = hdr + dot_pos + 2; |
| 7262 | return dot_end < num_end ? num_end : dot_end; |
| 7263 | } |
| 7264 | } else { |
| 7265 | /* write with scientific notation */ |
| 7266 | /* such as 1.234e56 */ |
| 7267 | u8 *end = write_u64_len_15_to_17_trim(buf + 1, sig_dec); |
| 7268 | end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */ |
| 7269 | exp_dec += sig_len - 1; |
| 7270 | hdr[0] = hdr[1]; |
| 7271 | hdr[1] = '.'; |
| 7272 | end[0] = 'e'; |
| 7273 | buf = write_f64_exp(exp_dec, end + 1); |
| 7274 | return buf; |
| 7275 | } |
| 7276 | |
| 7277 | } else { |
| 7278 | /* subnormal number */ |
| 7279 | sig_bin = sig_raw; |
| 7280 | exp_bin = 1 - F64_EXP_BIAS - F64_SIG_BITS; |
| 7281 | |
| 7282 | /* binary to decimal */ |
| 7283 | f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec); |
| 7284 | |
| 7285 | /* write significand part */ |
| 7286 | buf = write_u64_len_1_to_17(sig_dec, buf + 1); |
| 7287 | hdr[0] = hdr[1]; |
| 7288 | hdr[1] = '.'; |
| 7289 | do { |
| 7290 | buf--; |
| 7291 | exp_dec++; |
| 7292 | } while (*buf == '0'); |
| 7293 | exp_dec += (i32)(buf - hdr - 2); |
| 7294 | buf += (*buf != '.'); |
| 7295 | buf[0] = 'e'; |
| 7296 | buf++; |
| 7297 | |
| 7298 | /* write exponent part */ |
| 7299 | buf[0] = '-'; |
| 7300 | buf++; |
| 7301 | exp_dec = -exp_dec; |
| 7302 | hi = ((u32)exp_dec * 656) >> 16; /* exp / 100 */ |
| 7303 | lo = (u32)exp_dec - hi * 100; /* exp % 100 */ |
| 7304 | buf[0] = (u8)((u8)hi + (u8)'0'); |
| 7305 | byte_copy_2(buf + 1, digit_table + lo * 2); |
| 7306 | buf += 3; |
| 7307 | return buf; |
| 7308 | } |
| 7309 | } |
| 7310 | |
| 7311 | #else /* FP_WRITER */ |
| 7312 | |
| 7313 | /** Write a double number (requires 32 bytes buffer). */ |
| 7314 | static_inline u8 *write_f64_raw(u8 *buf, u64 raw, yyjson_write_flag flg) { |
| 7315 | /* |
| 7316 | For IEEE 754, `DBL_DECIMAL_DIG` is 17 for round-trip. |
| 7317 | For non-IEEE formats, 17 is used to avoid buffer overflow, |
| 7318 | round-trip is not guaranteed. |
| 7319 | */ |
| 7320 | #if defined(DBL_DECIMAL_DIG) && DBL_DECIMAL_DIG != 17 |
| 7321 | int dig = DBL_DECIMAL_DIG > 17 ? 17 : DBL_DECIMAL_DIG; |
| 7322 | #else |
| 7323 | int dig = 17; |
| 7324 | #endif |
| 7325 | |
| 7326 | /* |
| 7327 | The snprintf() function is locale-dependent. For currently known locales, |
| 7328 | (en, zh, ja, ko, am, he, hi) use '.' as the decimal point, while other |
| 7329 | locales use ',' as the decimal point. we need to replace ',' with '.' |
| 7330 | to avoid the locale setting. |
| 7331 | */ |
| 7332 | f64 val = f64_from_raw(raw); |
| 7333 | #if YYJSON_MSC_VER >= 1400 |
| 7334 | int len = sprintf_s((char *)buf, 32, "%.*g" , dig, val); |
| 7335 | #elif defined(snprintf) || (YYJSON_STDC_VER >= 199901L) |
| 7336 | int len = snprintf((char *)buf, 32, "%.*g" , dig, val); |
| 7337 | #else |
| 7338 | int len = sprintf((char *)buf, "%.*g" , dig, val); |
| 7339 | #endif |
| 7340 | |
| 7341 | u8 *cur = buf; |
| 7342 | if (unlikely(len < 1)) return NULL; |
| 7343 | cur += (*cur == '-'); |
| 7344 | if (unlikely(!digi_is_digit(*cur))) { |
| 7345 | /* nan, inf, or bad output */ |
| 7346 | if (flg & YYJSON_WRITE_INF_AND_NAN_AS_NULL) { |
| 7347 | byte_copy_4(buf, "null" ); |
| 7348 | return buf + 4; |
| 7349 | } else if (flg & YYJSON_WRITE_ALLOW_INF_AND_NAN) { |
| 7350 | if (*cur == 'i') { |
| 7351 | byte_copy_8(cur, "Infinity" ); |
| 7352 | cur += 8; |
| 7353 | return cur; |
| 7354 | } else if (*cur == 'n') { |
| 7355 | byte_copy_4(buf, "NaN" ); |
| 7356 | return buf + 3; |
| 7357 | } |
| 7358 | } |
| 7359 | return NULL; |
| 7360 | } else { |
| 7361 | /* finite number */ |
| 7362 | int i = 0; |
| 7363 | bool fp = false; |
| 7364 | for (; i < len; i++) { |
| 7365 | if (buf[i] == ',') buf[i] = '.'; |
| 7366 | if (digi_is_fp((u8)buf[i])) fp = true; |
| 7367 | } |
| 7368 | if (!fp) { |
| 7369 | buf[len++] = '.'; |
| 7370 | buf[len++] = '0'; |
| 7371 | } |
| 7372 | } |
| 7373 | return buf + len; |
| 7374 | } |
| 7375 | |
| 7376 | #endif /* FP_WRITER */ |
| 7377 | |
| 7378 | /** Write a JSON number (requires 32 bytes buffer). */ |
| 7379 | static_inline u8 *write_number(u8 *cur, yyjson_val *val, |
| 7380 | yyjson_write_flag flg) { |
| 7381 | if (val->tag & YYJSON_SUBTYPE_REAL) { |
| 7382 | u64 raw = val->uni.u64; |
| 7383 | return write_f64_raw(cur, raw, flg); |
| 7384 | } else { |
| 7385 | u64 pos = val->uni.u64; |
| 7386 | u64 neg = ~pos + 1; |
| 7387 | usize sgn = ((val->tag & YYJSON_SUBTYPE_SINT) > 0) & ((i64)pos < 0); |
| 7388 | *cur = '-'; |
| 7389 | return write_u64(sgn ? neg : pos, cur + sgn); |
| 7390 | } |
| 7391 | } |
| 7392 | |
| 7393 | |
| 7394 | |
| 7395 | /*============================================================================== |
| 7396 | * String Writer |
| 7397 | *============================================================================*/ |
| 7398 | |
| 7399 | /** Character encode type, if (type > CHAR_ENC_ERR_1) bytes = type / 2; */ |
| 7400 | typedef u8 char_enc_type; |
| 7401 | #define CHAR_ENC_CPY_1 0 /* 1-byte UTF-8, copy. */ |
| 7402 | #define CHAR_ENC_ERR_1 1 /* 1-byte UTF-8, error. */ |
| 7403 | #define CHAR_ENC_ESC_A 2 /* 1-byte ASCII, escaped as '\x'. */ |
| 7404 | #define CHAR_ENC_ESC_1 3 /* 1-byte UTF-8, escaped as '\uXXXX'. */ |
| 7405 | #define CHAR_ENC_CPY_2 4 /* 2-byte UTF-8, copy. */ |
| 7406 | #define CHAR_ENC_ESC_2 5 /* 2-byte UTF-8, escaped as '\uXXXX'. */ |
| 7407 | #define CHAR_ENC_CPY_3 6 /* 3-byte UTF-8, copy. */ |
| 7408 | #define CHAR_ENC_ESC_3 7 /* 3-byte UTF-8, escaped as '\uXXXX'. */ |
| 7409 | #define CHAR_ENC_CPY_4 8 /* 4-byte UTF-8, copy. */ |
| 7410 | #define CHAR_ENC_ESC_4 9 /* 4-byte UTF-8, escaped as '\uXXXX\uXXXX'. */ |
| 7411 | |
| 7412 | /** Character encode type table: don't escape unicode, don't escape '/'. |
| 7413 | (generate with misc/make_tables.c) */ |
| 7414 | static const char_enc_type enc_table_cpy[256] = { |
| 7415 | 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3, |
| 7416 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
| 7417 | 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 7418 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 7419 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 7420 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, |
| 7421 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 7422 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 7423 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 7424 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 7425 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 7426 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 7427 | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, |
| 7428 | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, |
| 7429 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
| 7430 | 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1 |
| 7431 | }; |
| 7432 | |
| 7433 | /** Character encode type table: don't escape unicode, escape '/'. |
| 7434 | (generate with misc/make_tables.c) */ |
| 7435 | static const char_enc_type enc_table_cpy_slash[256] = { |
| 7436 | 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3, |
| 7437 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
| 7438 | 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, |
| 7439 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 7440 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 7441 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, |
| 7442 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 7443 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 7444 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 7445 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 7446 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 7447 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 7448 | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, |
| 7449 | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, |
| 7450 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
| 7451 | 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1 |
| 7452 | }; |
| 7453 | |
| 7454 | /** Character encode type table: escape unicode, don't escape '/'. |
| 7455 | (generate with misc/make_tables.c) */ |
| 7456 | static const char_enc_type enc_table_esc[256] = { |
| 7457 | 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3, |
| 7458 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
| 7459 | 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 7460 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 7461 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 7462 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, |
| 7463 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 7464 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 7465 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 7466 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 7467 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 7468 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 7469 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
| 7470 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
| 7471 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
| 7472 | 9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1 |
| 7473 | }; |
| 7474 | |
| 7475 | /** Character encode type table: escape unicode, escape '/'. |
| 7476 | (generate with misc/make_tables.c) */ |
| 7477 | static const char_enc_type enc_table_esc_slash[256] = { |
| 7478 | 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3, |
| 7479 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
| 7480 | 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, |
| 7481 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 7482 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 7483 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, |
| 7484 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 7485 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 7486 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 7487 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 7488 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 7489 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 7490 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
| 7491 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
| 7492 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
| 7493 | 9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1 |
| 7494 | }; |
| 7495 | |
| 7496 | /** Escaped hex character table: ["00" "01" "02" ... "FD" "FE" "FF"]. |
| 7497 | (generate with misc/make_tables.c) */ |
| 7498 | yyjson_align(2) |
| 7499 | static const u8 esc_hex_char_table[512] = { |
| 7500 | '0', '0', '0', '1', '0', '2', '0', '3', |
| 7501 | '0', '4', '0', '5', '0', '6', '0', '7', |
| 7502 | '0', '8', '0', '9', '0', 'A', '0', 'B', |
| 7503 | '0', 'C', '0', 'D', '0', 'E', '0', 'F', |
| 7504 | '1', '0', '1', '1', '1', '2', '1', '3', |
| 7505 | '1', '4', '1', '5', '1', '6', '1', '7', |
| 7506 | '1', '8', '1', '9', '1', 'A', '1', 'B', |
| 7507 | '1', 'C', '1', 'D', '1', 'E', '1', 'F', |
| 7508 | '2', '0', '2', '1', '2', '2', '2', '3', |
| 7509 | '2', '4', '2', '5', '2', '6', '2', '7', |
| 7510 | '2', '8', '2', '9', '2', 'A', '2', 'B', |
| 7511 | '2', 'C', '2', 'D', '2', 'E', '2', 'F', |
| 7512 | '3', '0', '3', '1', '3', '2', '3', '3', |
| 7513 | '3', '4', '3', '5', '3', '6', '3', '7', |
| 7514 | '3', '8', '3', '9', '3', 'A', '3', 'B', |
| 7515 | '3', 'C', '3', 'D', '3', 'E', '3', 'F', |
| 7516 | '4', '0', '4', '1', '4', '2', '4', '3', |
| 7517 | '4', '4', '4', '5', '4', '6', '4', '7', |
| 7518 | '4', '8', '4', '9', '4', 'A', '4', 'B', |
| 7519 | '4', 'C', '4', 'D', '4', 'E', '4', 'F', |
| 7520 | '5', '0', '5', '1', '5', '2', '5', '3', |
| 7521 | '5', '4', '5', '5', '5', '6', '5', '7', |
| 7522 | '5', '8', '5', '9', '5', 'A', '5', 'B', |
| 7523 | '5', 'C', '5', 'D', '5', 'E', '5', 'F', |
| 7524 | '6', '0', '6', '1', '6', '2', '6', '3', |
| 7525 | '6', '4', '6', '5', '6', '6', '6', '7', |
| 7526 | '6', '8', '6', '9', '6', 'A', '6', 'B', |
| 7527 | '6', 'C', '6', 'D', '6', 'E', '6', 'F', |
| 7528 | '7', '0', '7', '1', '7', '2', '7', '3', |
| 7529 | '7', '4', '7', '5', '7', '6', '7', '7', |
| 7530 | '7', '8', '7', '9', '7', 'A', '7', 'B', |
| 7531 | '7', 'C', '7', 'D', '7', 'E', '7', 'F', |
| 7532 | '8', '0', '8', '1', '8', '2', '8', '3', |
| 7533 | '8', '4', '8', '5', '8', '6', '8', '7', |
| 7534 | '8', '8', '8', '9', '8', 'A', '8', 'B', |
| 7535 | '8', 'C', '8', 'D', '8', 'E', '8', 'F', |
| 7536 | '9', '0', '9', '1', '9', '2', '9', '3', |
| 7537 | '9', '4', '9', '5', '9', '6', '9', '7', |
| 7538 | '9', '8', '9', '9', '9', 'A', '9', 'B', |
| 7539 | '9', 'C', '9', 'D', '9', 'E', '9', 'F', |
| 7540 | 'A', '0', 'A', '1', 'A', '2', 'A', '3', |
| 7541 | 'A', '4', 'A', '5', 'A', '6', 'A', '7', |
| 7542 | 'A', '8', 'A', '9', 'A', 'A', 'A', 'B', |
| 7543 | 'A', 'C', 'A', 'D', 'A', 'E', 'A', 'F', |
| 7544 | 'B', '0', 'B', '1', 'B', '2', 'B', '3', |
| 7545 | 'B', '4', 'B', '5', 'B', '6', 'B', '7', |
| 7546 | 'B', '8', 'B', '9', 'B', 'A', 'B', 'B', |
| 7547 | 'B', 'C', 'B', 'D', 'B', 'E', 'B', 'F', |
| 7548 | 'C', '0', 'C', '1', 'C', '2', 'C', '3', |
| 7549 | 'C', '4', 'C', '5', 'C', '6', 'C', '7', |
| 7550 | 'C', '8', 'C', '9', 'C', 'A', 'C', 'B', |
| 7551 | 'C', 'C', 'C', 'D', 'C', 'E', 'C', 'F', |
| 7552 | 'D', '0', 'D', '1', 'D', '2', 'D', '3', |
| 7553 | 'D', '4', 'D', '5', 'D', '6', 'D', '7', |
| 7554 | 'D', '8', 'D', '9', 'D', 'A', 'D', 'B', |
| 7555 | 'D', 'C', 'D', 'D', 'D', 'E', 'D', 'F', |
| 7556 | 'E', '0', 'E', '1', 'E', '2', 'E', '3', |
| 7557 | 'E', '4', 'E', '5', 'E', '6', 'E', '7', |
| 7558 | 'E', '8', 'E', '9', 'E', 'A', 'E', 'B', |
| 7559 | 'E', 'C', 'E', 'D', 'E', 'E', 'E', 'F', |
| 7560 | 'F', '0', 'F', '1', 'F', '2', 'F', '3', |
| 7561 | 'F', '4', 'F', '5', 'F', '6', 'F', '7', |
| 7562 | 'F', '8', 'F', '9', 'F', 'A', 'F', 'B', |
| 7563 | 'F', 'C', 'F', 'D', 'F', 'E', 'F', 'F' |
| 7564 | }; |
| 7565 | |
| 7566 | /** Escaped single character table. (generate with misc/make_tables.c) */ |
| 7567 | yyjson_align(2) |
| 7568 | static const u8 esc_single_char_table[512] = { |
| 7569 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7570 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7571 | '\\', 'b', '\\', 't', '\\', 'n', ' ', ' ', |
| 7572 | '\\', 'f', '\\', 'r', ' ', ' ', ' ', ' ', |
| 7573 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7574 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7575 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7576 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7577 | ' ', ' ', ' ', ' ', '\\', '"', ' ', ' ', |
| 7578 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7579 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7580 | ' ', ' ', ' ', ' ', ' ', ' ', '\\', '/', |
| 7581 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7582 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7583 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7584 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7585 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7586 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7587 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7588 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7589 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7590 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7591 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7592 | '\\', '\\', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7593 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7594 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7595 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7596 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7597 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7598 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7599 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7600 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7601 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7602 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7603 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7604 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7605 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7606 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7607 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7608 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7609 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7610 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7611 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7612 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7613 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7614 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7615 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7616 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7617 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7618 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7619 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7620 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7621 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7622 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7623 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7624 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7625 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7626 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7627 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7628 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7629 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7630 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7631 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
| 7632 | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' |
| 7633 | }; |
| 7634 | |
| 7635 | /** Returns the encode table with options. */ |
| 7636 | static_inline const char_enc_type *get_enc_table_with_flag( |
| 7637 | yyjson_read_flag flg) { |
| 7638 | if (unlikely(flg & YYJSON_WRITE_ESCAPE_UNICODE)) { |
| 7639 | if (unlikely(flg & YYJSON_WRITE_ESCAPE_SLASHES)) { |
| 7640 | return enc_table_esc_slash; |
| 7641 | } else { |
| 7642 | return enc_table_esc; |
| 7643 | } |
| 7644 | } else { |
| 7645 | if (unlikely(flg & YYJSON_WRITE_ESCAPE_SLASHES)) { |
| 7646 | return enc_table_cpy_slash; |
| 7647 | } else { |
| 7648 | return enc_table_cpy; |
| 7649 | } |
| 7650 | } |
| 7651 | } |
| 7652 | |
| 7653 | /** Write raw string. */ |
| 7654 | static_inline u8 *write_raw(u8 *cur, const u8 *raw, usize raw_len) { |
| 7655 | memcpy(cur, raw, raw_len); |
| 7656 | return cur + raw_len; |
| 7657 | } |
| 7658 | |
| 7659 | /** |
| 7660 | Write string no-escape. |
| 7661 | @param cur Buffer cursor. |
| 7662 | @param str A UTF-8 string, null-terminator is not required. |
| 7663 | @param str_len Length of string in bytes. |
| 7664 | @return The buffer cursor after string. |
| 7665 | */ |
| 7666 | static_inline u8 *write_string_noesc(u8 *cur, const u8 *str, usize str_len) { |
| 7667 | *cur++ = '"'; |
| 7668 | while (str_len >= 16) { |
| 7669 | byte_copy_16(cur, str); |
| 7670 | cur += 16; |
| 7671 | str += 16; |
| 7672 | str_len -= 16; |
| 7673 | } |
| 7674 | while (str_len >= 4) { |
| 7675 | byte_copy_4(cur, str); |
| 7676 | cur += 4; |
| 7677 | str += 4; |
| 7678 | str_len -= 4; |
| 7679 | } |
| 7680 | while (str_len) { |
| 7681 | *cur++ = *str++; |
| 7682 | str_len -= 1; |
| 7683 | } |
| 7684 | *cur++ = '"'; |
| 7685 | return cur; |
| 7686 | } |
| 7687 | |
| 7688 | /** |
| 7689 | Write UTF-8 string (requires len * 6 + 2 bytes buffer). |
| 7690 | @param cur Buffer cursor. |
| 7691 | @param esc Escape unicode. |
| 7692 | @param inv Allow invalid unicode. |
| 7693 | @param str A UTF-8 string, null-terminator is not required. |
| 7694 | @param str_len Length of string in bytes. |
| 7695 | @param enc_table Encode type table for character. |
| 7696 | @return The buffer cursor after string, or NULL on invalid unicode. |
| 7697 | */ |
| 7698 | static_inline u8 *write_string(u8 *cur, bool esc, bool inv, |
| 7699 | const u8 *str, usize str_len, |
| 7700 | const char_enc_type *enc_table) { |
| 7701 | |
| 7702 | /* UTF-8 character mask and pattern, see `read_string()` for details. */ |
| 7703 | #if YYJSON_ENDIAN == YYJSON_BIG_ENDIAN |
| 7704 | const u16 b2_mask = 0xE0C0UL; |
| 7705 | const u16 b2_patt = 0xC080UL; |
| 7706 | const u16 b2_requ = 0x1E00UL; |
| 7707 | const u32 b3_mask = 0xF0C0C000UL; |
| 7708 | const u32 b3_patt = 0xE0808000UL; |
| 7709 | const u32 b3_requ = 0x0F200000UL; |
| 7710 | const u32 b3_erro = 0x0D200000UL; |
| 7711 | const u32 b4_mask = 0xF8C0C0C0UL; |
| 7712 | const u32 b4_patt = 0xF0808080UL; |
| 7713 | const u32 b4_requ = 0x07300000UL; |
| 7714 | const u32 b4_err0 = 0x04000000UL; |
| 7715 | const u32 b4_err1 = 0x03300000UL; |
| 7716 | #elif YYJSON_ENDIAN == YYJSON_LITTLE_ENDIAN |
| 7717 | const u16 b2_mask = 0xC0E0UL; |
| 7718 | const u16 b2_patt = 0x80C0UL; |
| 7719 | const u16 b2_requ = 0x001EUL; |
| 7720 | const u32 b3_mask = 0x00C0C0F0UL; |
| 7721 | const u32 b3_patt = 0x008080E0UL; |
| 7722 | const u32 b3_requ = 0x0000200FUL; |
| 7723 | const u32 b3_erro = 0x0000200DUL; |
| 7724 | const u32 b4_mask = 0xC0C0C0F8UL; |
| 7725 | const u32 b4_patt = 0x808080F0UL; |
| 7726 | const u32 b4_requ = 0x00003007UL; |
| 7727 | const u32 b4_err0 = 0x00000004UL; |
| 7728 | const u32 b4_err1 = 0x00003003UL; |
| 7729 | #else |
| 7730 | v16_uni b2_mask_uni = {{ 0xE0, 0xC0 }}; |
| 7731 | v16_uni b2_patt_uni = {{ 0xC0, 0x80 }}; |
| 7732 | v16_uni b2_requ_uni = {{ 0x1E, 0x00 }}; |
| 7733 | v32_uni b3_mask_uni = {{ 0xF0, 0xC0, 0xC0, 0x00 }}; |
| 7734 | v32_uni b3_patt_uni = {{ 0xE0, 0x80, 0x80, 0x00 }}; |
| 7735 | v32_uni b3_requ_uni = {{ 0x0F, 0x20, 0x00, 0x00 }}; |
| 7736 | v32_uni b3_erro_uni = {{ 0x0D, 0x20, 0x00, 0x00 }}; |
| 7737 | v32_uni b4_mask_uni = {{ 0xF8, 0xC0, 0xC0, 0xC0 }}; |
| 7738 | v32_uni b4_patt_uni = {{ 0xF0, 0x80, 0x80, 0x80 }}; |
| 7739 | v32_uni b4_requ_uni = {{ 0x07, 0x30, 0x00, 0x00 }}; |
| 7740 | v32_uni b4_err0_uni = {{ 0x04, 0x00, 0x00, 0x00 }}; |
| 7741 | v32_uni b4_err1_uni = {{ 0x03, 0x30, 0x00, 0x00 }}; |
| 7742 | u16 b2_mask = b2_mask_uni.u; |
| 7743 | u16 b2_patt = b2_patt_uni.u; |
| 7744 | u16 b2_requ = b2_requ_uni.u; |
| 7745 | u32 b3_mask = b3_mask_uni.u; |
| 7746 | u32 b3_patt = b3_patt_uni.u; |
| 7747 | u32 b3_requ = b3_requ_uni.u; |
| 7748 | u32 b3_erro = b3_erro_uni.u; |
| 7749 | u32 b4_mask = b4_mask_uni.u; |
| 7750 | u32 b4_patt = b4_patt_uni.u; |
| 7751 | u32 b4_requ = b4_requ_uni.u; |
| 7752 | u32 b4_err0 = b4_err0_uni.u; |
| 7753 | u32 b4_err1 = b4_err1_uni.u; |
| 7754 | #endif |
| 7755 | |
| 7756 | #define is_valid_seq_2(uni) ( \ |
| 7757 | ((uni & b2_mask) == b2_patt) && \ |
| 7758 | ((uni & b2_requ)) \ |
| 7759 | ) |
| 7760 | |
| 7761 | #define is_valid_seq_3(uni) ( \ |
| 7762 | ((uni & b3_mask) == b3_patt) && \ |
| 7763 | ((tmp = (uni & b3_requ))) && \ |
| 7764 | ((tmp != b3_erro)) \ |
| 7765 | ) |
| 7766 | |
| 7767 | #define is_valid_seq_4(uni) ( \ |
| 7768 | ((uni & b4_mask) == b4_patt) && \ |
| 7769 | ((tmp = (uni & b4_requ))) && \ |
| 7770 | ((tmp & b4_err0) == 0 || (tmp & b4_err1) == 0) \ |
| 7771 | ) |
| 7772 | |
| 7773 | /* The replacement character U+FFFD, used to indicate invalid character. */ |
| 7774 | const v32 rep = { 'F', 'F', 'F', 'D' }; |
| 7775 | const v32 pre = { '\\', 'u', '0', '0' }; |
| 7776 | |
| 7777 | const u8 *src = str; |
| 7778 | const u8 *end = str + str_len; |
| 7779 | *cur++ = '"'; |
| 7780 | |
| 7781 | copy_ascii: |
| 7782 | /* |
| 7783 | Copy continuous ASCII, loop unrolling, same as the following code: |
| 7784 | |
| 7785 | while (end > src) ( |
| 7786 | if (unlikely(enc_table[*src])) break; |
| 7787 | *cur++ = *src++; |
| 7788 | ); |
| 7789 | */ |
| 7790 | #define expr_jump(i) \ |
| 7791 | if (unlikely(enc_table[src[i]])) goto stop_char_##i; |
| 7792 | |
| 7793 | #define expr_stop(i) \ |
| 7794 | stop_char_##i: \ |
| 7795 | memcpy(cur, src, i); \ |
| 7796 | cur += i; src += i; goto copy_utf8; |
| 7797 | |
| 7798 | while (end - src >= 16) { |
| 7799 | repeat16_incr(expr_jump) |
| 7800 | byte_copy_16(cur, src); |
| 7801 | cur += 16; src += 16; |
| 7802 | } |
| 7803 | |
| 7804 | while (end - src >= 4) { |
| 7805 | repeat4_incr(expr_jump) |
| 7806 | byte_copy_4(cur, src); |
| 7807 | cur += 4; src += 4; |
| 7808 | } |
| 7809 | |
| 7810 | while (end > src) { |
| 7811 | expr_jump(0) |
| 7812 | *cur++ = *src++; |
| 7813 | } |
| 7814 | |
| 7815 | *cur++ = '"'; |
| 7816 | return cur; |
| 7817 | |
| 7818 | repeat16_incr(expr_stop) |
| 7819 | |
| 7820 | #undef expr_jump |
| 7821 | #undef expr_stop |
| 7822 | |
| 7823 | copy_utf8: |
| 7824 | if (unlikely(src + 4 > end)) { |
| 7825 | if (end == src) goto copy_end; |
| 7826 | if (end - src < enc_table[*src] / 2) goto err_one; |
| 7827 | } |
| 7828 | switch (enc_table[*src]) { |
| 7829 | case CHAR_ENC_CPY_1: { |
| 7830 | *cur++ = *src++; |
| 7831 | goto copy_ascii; |
| 7832 | } |
| 7833 | case CHAR_ENC_CPY_2: { |
| 7834 | u16 v; |
| 7835 | v = byte_load_2(src); |
| 7836 | if (unlikely(!is_valid_seq_2(v))) goto err_cpy; |
| 7837 | |
| 7838 | byte_copy_2(cur, src); |
| 7839 | cur += 2; |
| 7840 | src += 2; |
| 7841 | goto copy_utf8; |
| 7842 | } |
| 7843 | case CHAR_ENC_CPY_3: { |
| 7844 | u32 v, tmp; |
| 7845 | if (likely(src + 4 <= end)) { |
| 7846 | v = byte_load_4(src); |
| 7847 | if (unlikely(!is_valid_seq_3(v))) goto err_cpy; |
| 7848 | byte_copy_4(cur, src); |
| 7849 | } else { |
| 7850 | v = byte_load_3(src); |
| 7851 | if (unlikely(!is_valid_seq_3(v))) goto err_cpy; |
| 7852 | byte_copy_4(cur, &v); |
| 7853 | } |
| 7854 | cur += 3; |
| 7855 | src += 3; |
| 7856 | goto copy_utf8; |
| 7857 | } |
| 7858 | case CHAR_ENC_CPY_4: { |
| 7859 | u32 v, tmp; |
| 7860 | v = byte_load_4(src); |
| 7861 | if (unlikely(!is_valid_seq_4(v))) goto err_cpy; |
| 7862 | |
| 7863 | byte_copy_4(cur, src); |
| 7864 | cur += 4; |
| 7865 | src += 4; |
| 7866 | goto copy_utf8; |
| 7867 | } |
| 7868 | case CHAR_ENC_ESC_A: { |
| 7869 | byte_copy_2(cur, &esc_single_char_table[*src * 2]); |
| 7870 | cur += 2; |
| 7871 | src += 1; |
| 7872 | goto copy_utf8; |
| 7873 | } |
| 7874 | case CHAR_ENC_ESC_1: { |
| 7875 | byte_copy_4(cur + 0, &pre); |
| 7876 | byte_copy_2(cur + 4, &esc_hex_char_table[*src * 2]); |
| 7877 | cur += 6; |
| 7878 | src += 1; |
| 7879 | goto copy_utf8; |
| 7880 | } |
| 7881 | case CHAR_ENC_ESC_2: { |
| 7882 | u16 u, v; |
| 7883 | v = byte_load_2(src); |
| 7884 | if (unlikely(!is_valid_seq_2(v))) goto err_esc; |
| 7885 | |
| 7886 | u = (u16)(((u16)(src[0] & 0x1F) << 6) | |
| 7887 | ((u16)(src[1] & 0x3F) << 0)); |
| 7888 | byte_copy_2(cur + 0, &pre); |
| 7889 | byte_copy_2(cur + 2, &esc_hex_char_table[(u >> 8) * 2]); |
| 7890 | byte_copy_2(cur + 4, &esc_hex_char_table[(u & 0xFF) * 2]); |
| 7891 | cur += 6; |
| 7892 | src += 2; |
| 7893 | goto copy_utf8; |
| 7894 | } |
| 7895 | case CHAR_ENC_ESC_3: { |
| 7896 | u16 u; |
| 7897 | u32 v, tmp; |
| 7898 | v = byte_load_3(src); |
| 7899 | if (unlikely(!is_valid_seq_3(v))) goto err_esc; |
| 7900 | |
| 7901 | u = (u16)(((u16)(src[0] & 0x0F) << 12) | |
| 7902 | ((u16)(src[1] & 0x3F) << 6) | |
| 7903 | ((u16)(src[2] & 0x3F) << 0)); |
| 7904 | byte_copy_2(cur + 0, &pre); |
| 7905 | byte_copy_2(cur + 2, &esc_hex_char_table[(u >> 8) * 2]); |
| 7906 | byte_copy_2(cur + 4, &esc_hex_char_table[(u & 0xFF) * 2]); |
| 7907 | cur += 6; |
| 7908 | src += 3; |
| 7909 | goto copy_utf8; |
| 7910 | } |
| 7911 | case CHAR_ENC_ESC_4: { |
| 7912 | u32 hi, lo, u, v, tmp; |
| 7913 | v = byte_load_4(src); |
| 7914 | if (unlikely(!is_valid_seq_4(v))) goto err_esc; |
| 7915 | |
| 7916 | u = ((u32)(src[0] & 0x07) << 18) | |
| 7917 | ((u32)(src[1] & 0x3F) << 12) | |
| 7918 | ((u32)(src[2] & 0x3F) << 6) | |
| 7919 | ((u32)(src[3] & 0x3F) << 0); |
| 7920 | u -= 0x10000; |
| 7921 | hi = (u >> 10) + 0xD800; |
| 7922 | lo = (u & 0x3FF) + 0xDC00; |
| 7923 | byte_copy_2(cur + 0, &pre); |
| 7924 | byte_copy_2(cur + 2, &esc_hex_char_table[(hi >> 8) * 2]); |
| 7925 | byte_copy_2(cur + 4, &esc_hex_char_table[(hi & 0xFF) * 2]); |
| 7926 | byte_copy_2(cur + 6, &pre); |
| 7927 | byte_copy_2(cur + 8, &esc_hex_char_table[(lo >> 8) * 2]); |
| 7928 | byte_copy_2(cur + 10, &esc_hex_char_table[(lo & 0xFF) * 2]); |
| 7929 | cur += 12; |
| 7930 | src += 4; |
| 7931 | goto copy_utf8; |
| 7932 | } |
| 7933 | case CHAR_ENC_ERR_1: { |
| 7934 | goto err_one; |
| 7935 | } |
| 7936 | default: break; |
| 7937 | } |
| 7938 | |
| 7939 | copy_end: |
| 7940 | *cur++ = '"'; |
| 7941 | return cur; |
| 7942 | |
| 7943 | err_one: |
| 7944 | if (esc) goto err_esc; |
| 7945 | else goto err_cpy; |
| 7946 | |
| 7947 | err_cpy: |
| 7948 | if (!inv) return NULL; |
| 7949 | *cur++ = *src++; |
| 7950 | goto copy_utf8; |
| 7951 | |
| 7952 | err_esc: |
| 7953 | if (!inv) return NULL; |
| 7954 | byte_copy_2(cur + 0, &pre); |
| 7955 | byte_copy_4(cur + 2, &rep); |
| 7956 | cur += 6; |
| 7957 | src += 1; |
| 7958 | goto copy_utf8; |
| 7959 | |
| 7960 | #undef is_valid_seq_2 |
| 7961 | #undef is_valid_seq_3 |
| 7962 | #undef is_valid_seq_4 |
| 7963 | } |
| 7964 | |
| 7965 | |
| 7966 | |
| 7967 | /*============================================================================== |
| 7968 | * Writer Utilities |
| 7969 | *============================================================================*/ |
| 7970 | |
| 7971 | /** Write null (requires 8 bytes buffer). */ |
| 7972 | static_inline u8 *write_null(u8 *cur) { |
| 7973 | v64 v = { 'n', 'u', 'l', 'l', ',', '\n', 0, 0 }; |
| 7974 | byte_copy_8(cur, &v); |
| 7975 | return cur + 4; |
| 7976 | } |
| 7977 | |
| 7978 | /** Write bool (requires 8 bytes buffer). */ |
| 7979 | static_inline u8 *write_bool(u8 *cur, bool val) { |
| 7980 | v64 v0 = { 'f', 'a', 'l', 's', 'e', ',', '\n', 0 }; |
| 7981 | v64 v1 = { 't', 'r', 'u', 'e', ',', '\n', 0, 0 }; |
| 7982 | if (val) { |
| 7983 | byte_copy_8(cur, &v1); |
| 7984 | } else { |
| 7985 | byte_copy_8(cur, &v0); |
| 7986 | } |
| 7987 | return cur + 5 - val; |
| 7988 | } |
| 7989 | |
| 7990 | /** Write indent (requires level x 4 bytes buffer). |
| 7991 | Param spaces should not larger than 4. */ |
| 7992 | static_inline u8 *write_indent(u8 *cur, usize level, usize spaces) { |
| 7993 | while (level-- > 0) { |
| 7994 | byte_copy_4(cur, " " ); |
| 7995 | cur += spaces; |
| 7996 | } |
| 7997 | return cur; |
| 7998 | } |
| 7999 | |
| 8000 | /** Write data to file pointer. */ |
| 8001 | static bool write_dat_to_fp(FILE *fp, u8 *dat, usize len, |
| 8002 | yyjson_write_err *err) { |
| 8003 | if (fwrite(dat, len, 1, fp) != 1) { |
| 8004 | err->msg = "file writing failed" ; |
| 8005 | err->code = YYJSON_WRITE_ERROR_FILE_WRITE; |
| 8006 | return false; |
| 8007 | } |
| 8008 | return true; |
| 8009 | } |
| 8010 | |
| 8011 | /** Write data to file. */ |
| 8012 | static bool write_dat_to_file(const char *path, u8 *dat, usize len, |
| 8013 | yyjson_write_err *err) { |
| 8014 | |
| 8015 | #define return_err(_code, _msg) do { \ |
| 8016 | err->msg = _msg; \ |
| 8017 | err->code = YYJSON_WRITE_ERROR_##_code; \ |
| 8018 | if (file) fclose(file); \ |
| 8019 | return false; \ |
| 8020 | } while (false) |
| 8021 | |
| 8022 | FILE *file = fopen_writeonly(path); |
| 8023 | if (file == NULL) { |
| 8024 | return_err(FILE_OPEN, "file opening failed" ); |
| 8025 | } |
| 8026 | if (fwrite(dat, len, 1, file) != 1) { |
| 8027 | return_err(FILE_WRITE, "file writing failed" ); |
| 8028 | } |
| 8029 | if (fclose(file) != 0) { |
| 8030 | file = NULL; |
| 8031 | return_err(FILE_WRITE, "file closing failed" ); |
| 8032 | } |
| 8033 | return true; |
| 8034 | |
| 8035 | #undef return_err |
| 8036 | } |
| 8037 | |
| 8038 | |
| 8039 | |
| 8040 | /*============================================================================== |
| 8041 | * JSON Writer Implementation |
| 8042 | *============================================================================*/ |
| 8043 | |
| 8044 | typedef struct yyjson_write_ctx { |
| 8045 | usize tag; |
| 8046 | } yyjson_write_ctx; |
| 8047 | |
| 8048 | static_inline void yyjson_write_ctx_set(yyjson_write_ctx *ctx, |
| 8049 | usize size, bool is_obj) { |
| 8050 | ctx->tag = (size << 1) | (usize)is_obj; |
| 8051 | } |
| 8052 | |
| 8053 | static_inline void yyjson_write_ctx_get(yyjson_write_ctx *ctx, |
| 8054 | usize *size, bool *is_obj) { |
| 8055 | usize tag = ctx->tag; |
| 8056 | *size = tag >> 1; |
| 8057 | *is_obj = (bool)(tag & 1); |
| 8058 | } |
| 8059 | |
| 8060 | /** Write single JSON value. */ |
| 8061 | static_inline u8 *yyjson_write_single(yyjson_val *val, |
| 8062 | yyjson_write_flag flg, |
| 8063 | yyjson_alc alc, |
| 8064 | usize *dat_len, |
| 8065 | yyjson_write_err *err) { |
| 8066 | |
| 8067 | #define return_err(_code, _msg) do { \ |
| 8068 | if (hdr) alc.free(alc.ctx, (void *)hdr); \ |
| 8069 | *dat_len = 0; \ |
| 8070 | err->code = YYJSON_WRITE_ERROR_##_code; \ |
| 8071 | err->msg = _msg; \ |
| 8072 | return NULL; \ |
| 8073 | } while (false) |
| 8074 | |
| 8075 | #define incr_len(_len) do { \ |
| 8076 | hdr = (u8 *)alc.malloc(alc.ctx, _len); \ |
| 8077 | if (!hdr) goto fail_alloc; \ |
| 8078 | cur = hdr; \ |
| 8079 | } while (false) |
| 8080 | |
| 8081 | #define check_str_len(_len) do { \ |
| 8082 | if ((USIZE_MAX < U64_MAX) && (_len >= (USIZE_MAX - 16) / 6)) \ |
| 8083 | goto fail_alloc; \ |
| 8084 | } while (false) |
| 8085 | |
| 8086 | u8 *hdr = NULL, *cur; |
| 8087 | usize str_len; |
| 8088 | const u8 *str_ptr; |
| 8089 | const char_enc_type *enc_table = get_enc_table_with_flag(flg); |
| 8090 | bool cpy = (enc_table == enc_table_cpy); |
| 8091 | bool esc = (flg & YYJSON_WRITE_ESCAPE_UNICODE) != 0; |
| 8092 | bool inv = (flg & YYJSON_WRITE_ALLOW_INVALID_UNICODE) != 0; |
| 8093 | |
| 8094 | switch (unsafe_yyjson_get_type(val)) { |
| 8095 | case YYJSON_TYPE_RAW: |
| 8096 | str_len = unsafe_yyjson_get_len(val); |
| 8097 | str_ptr = (const u8 *)unsafe_yyjson_get_str(val); |
| 8098 | check_str_len(str_len); |
| 8099 | incr_len(str_len + 1); |
| 8100 | cur = write_raw(cur, str_ptr, str_len); |
| 8101 | break; |
| 8102 | |
| 8103 | case YYJSON_TYPE_STR: |
| 8104 | str_len = unsafe_yyjson_get_len(val); |
| 8105 | str_ptr = (const u8 *)unsafe_yyjson_get_str(val); |
| 8106 | check_str_len(str_len); |
| 8107 | incr_len(str_len * 6 + 4); |
| 8108 | if (likely(cpy) && unsafe_yyjson_get_subtype(val)) { |
| 8109 | cur = write_string_noesc(cur, str_ptr, str_len); |
| 8110 | } else { |
| 8111 | cur = write_string(cur, esc, inv, str_ptr, str_len, enc_table); |
| 8112 | if (unlikely(!cur)) goto fail_str; |
| 8113 | } |
| 8114 | break; |
| 8115 | |
| 8116 | case YYJSON_TYPE_NUM: |
| 8117 | incr_len(32); |
| 8118 | cur = write_number(cur, val, flg); |
| 8119 | if (unlikely(!cur)) goto fail_num; |
| 8120 | break; |
| 8121 | |
| 8122 | case YYJSON_TYPE_BOOL: |
| 8123 | incr_len(8); |
| 8124 | cur = write_bool(cur, unsafe_yyjson_get_bool(val)); |
| 8125 | break; |
| 8126 | |
| 8127 | case YYJSON_TYPE_NULL: |
| 8128 | incr_len(8); |
| 8129 | cur = write_null(cur); |
| 8130 | break; |
| 8131 | |
| 8132 | case YYJSON_TYPE_ARR: |
| 8133 | incr_len(4); |
| 8134 | byte_copy_2(cur, "[]" ); |
| 8135 | cur += 2; |
| 8136 | break; |
| 8137 | |
| 8138 | case YYJSON_TYPE_OBJ: |
| 8139 | incr_len(4); |
| 8140 | byte_copy_2(cur, "{}" ); |
| 8141 | cur += 2; |
| 8142 | break; |
| 8143 | |
| 8144 | default: |
| 8145 | goto fail_type; |
| 8146 | } |
| 8147 | |
| 8148 | *cur = '\0'; |
| 8149 | *dat_len = (usize)(cur - hdr); |
| 8150 | memset(err, 0, sizeof(yyjson_write_err)); |
| 8151 | return hdr; |
| 8152 | |
| 8153 | fail_alloc: |
| 8154 | return_err(MEMORY_ALLOCATION, "memory allocation failed" ); |
| 8155 | fail_type: |
| 8156 | return_err(INVALID_VALUE_TYPE, "invalid JSON value type" ); |
| 8157 | fail_num: |
| 8158 | return_err(NAN_OR_INF, "nan or inf number is not allowed" ); |
| 8159 | fail_str: |
| 8160 | return_err(INVALID_STRING, "invalid utf-8 encoding in string" ); |
| 8161 | |
| 8162 | #undef return_err |
| 8163 | #undef check_str_len |
| 8164 | #undef incr_len |
| 8165 | } |
| 8166 | |
| 8167 | /** Write JSON document minify. |
| 8168 | The root of this document should be a non-empty container. */ |
| 8169 | static_inline u8 *yyjson_write_minify(const yyjson_val *root, |
| 8170 | const yyjson_write_flag flg, |
| 8171 | const yyjson_alc alc, |
| 8172 | usize *dat_len, |
| 8173 | yyjson_write_err *err) { |
| 8174 | |
| 8175 | #define return_err(_code, _msg) do { \ |
| 8176 | *dat_len = 0; \ |
| 8177 | err->code = YYJSON_WRITE_ERROR_##_code; \ |
| 8178 | err->msg = _msg; \ |
| 8179 | if (hdr) alc.free(alc.ctx, hdr); \ |
| 8180 | return NULL; \ |
| 8181 | } while (false) |
| 8182 | |
| 8183 | #define incr_len(_len) do { \ |
| 8184 | ext_len = (usize)(_len); \ |
| 8185 | if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \ |
| 8186 | alc_inc = yyjson_max(alc_len / 2, ext_len); \ |
| 8187 | alc_inc = size_align_up(alc_inc, sizeof(yyjson_write_ctx)); \ |
| 8188 | if (size_add_is_overflow(alc_len, alc_inc)) goto fail_alloc; \ |
| 8189 | alc_len += alc_inc; \ |
| 8190 | tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \ |
| 8191 | if (unlikely(!tmp)) goto fail_alloc; \ |
| 8192 | ctx_len = (usize)(end - (u8 *)ctx); \ |
| 8193 | ctx_tmp = (yyjson_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \ |
| 8194 | memmove((void *)ctx_tmp, (void *)(tmp + ((u8 *)ctx - hdr)), ctx_len); \ |
| 8195 | ctx = ctx_tmp; \ |
| 8196 | cur = tmp + (cur - hdr); \ |
| 8197 | end = tmp + alc_len; \ |
| 8198 | hdr = tmp; \ |
| 8199 | } \ |
| 8200 | } while (false) |
| 8201 | |
| 8202 | #define check_str_len(_len) do { \ |
| 8203 | if ((USIZE_MAX < U64_MAX) && (_len >= (USIZE_MAX - 16) / 6)) \ |
| 8204 | goto fail_alloc; \ |
| 8205 | } while (false) |
| 8206 | |
| 8207 | yyjson_val *val; |
| 8208 | yyjson_type val_type; |
| 8209 | usize ctn_len, ctn_len_tmp; |
| 8210 | bool ctn_obj, ctn_obj_tmp, is_key; |
| 8211 | u8 *hdr, *cur, *end, *tmp; |
| 8212 | yyjson_write_ctx *ctx, *ctx_tmp; |
| 8213 | usize alc_len, alc_inc, ctx_len, ext_len, str_len; |
| 8214 | const u8 *str_ptr; |
| 8215 | const char_enc_type *enc_table = get_enc_table_with_flag(flg); |
| 8216 | bool cpy = (enc_table == enc_table_cpy); |
| 8217 | bool esc = (flg & YYJSON_WRITE_ESCAPE_UNICODE) != 0; |
| 8218 | bool inv = (flg & YYJSON_WRITE_ALLOW_INVALID_UNICODE) != 0; |
| 8219 | |
| 8220 | alc_len = root->uni.ofs / sizeof(yyjson_val); |
| 8221 | alc_len = alc_len * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64; |
| 8222 | alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx)); |
| 8223 | hdr = (u8 *)alc.malloc(alc.ctx, alc_len); |
| 8224 | if (!hdr) goto fail_alloc; |
| 8225 | cur = hdr; |
| 8226 | end = hdr + alc_len; |
| 8227 | ctx = (yyjson_write_ctx *)(void *)end; |
| 8228 | |
| 8229 | doc_begin: |
| 8230 | val = constcast(yyjson_val *)root; |
| 8231 | val_type = unsafe_yyjson_get_type(val); |
| 8232 | ctn_obj = (val_type == YYJSON_TYPE_OBJ); |
| 8233 | ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj; |
| 8234 | *cur++ = (u8)('[' | ((u8)ctn_obj << 5)); |
| 8235 | val++; |
| 8236 | |
| 8237 | val_begin: |
| 8238 | val_type = unsafe_yyjson_get_type(val); |
| 8239 | if (val_type == YYJSON_TYPE_STR) { |
| 8240 | is_key = ((u8)ctn_obj & (u8)~ctn_len); |
| 8241 | str_len = unsafe_yyjson_get_len(val); |
| 8242 | str_ptr = (const u8 *)unsafe_yyjson_get_str(val); |
| 8243 | check_str_len(str_len); |
| 8244 | incr_len(str_len * 6 + 16); |
| 8245 | if (likely(cpy) && unsafe_yyjson_get_subtype(val)) { |
| 8246 | cur = write_string_noesc(cur, str_ptr, str_len); |
| 8247 | } else { |
| 8248 | cur = write_string(cur, esc, inv, str_ptr, str_len, enc_table); |
| 8249 | if (unlikely(!cur)) goto fail_str; |
| 8250 | } |
| 8251 | *cur++ = is_key ? ':' : ','; |
| 8252 | goto val_end; |
| 8253 | } |
| 8254 | if (val_type == YYJSON_TYPE_NUM) { |
| 8255 | incr_len(32); |
| 8256 | cur = write_number(cur, val, flg); |
| 8257 | if (unlikely(!cur)) goto fail_num; |
| 8258 | *cur++ = ','; |
| 8259 | goto val_end; |
| 8260 | } |
| 8261 | if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) == |
| 8262 | (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) { |
| 8263 | ctn_len_tmp = unsafe_yyjson_get_len(val); |
| 8264 | ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ); |
| 8265 | incr_len(16); |
| 8266 | if (unlikely(ctn_len_tmp == 0)) { |
| 8267 | /* write empty container */ |
| 8268 | *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5)); |
| 8269 | *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5)); |
| 8270 | *cur++ = ','; |
| 8271 | goto val_end; |
| 8272 | } else { |
| 8273 | /* push context, setup new container */ |
| 8274 | yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj); |
| 8275 | ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp; |
| 8276 | ctn_obj = ctn_obj_tmp; |
| 8277 | *cur++ = (u8)('[' | ((u8)ctn_obj << 5)); |
| 8278 | val++; |
| 8279 | goto val_begin; |
| 8280 | } |
| 8281 | } |
| 8282 | if (val_type == YYJSON_TYPE_BOOL) { |
| 8283 | incr_len(16); |
| 8284 | cur = write_bool(cur, unsafe_yyjson_get_bool(val)); |
| 8285 | cur++; |
| 8286 | goto val_end; |
| 8287 | } |
| 8288 | if (val_type == YYJSON_TYPE_NULL) { |
| 8289 | incr_len(16); |
| 8290 | cur = write_null(cur); |
| 8291 | cur++; |
| 8292 | goto val_end; |
| 8293 | } |
| 8294 | if (val_type == YYJSON_TYPE_RAW) { |
| 8295 | str_len = unsafe_yyjson_get_len(val); |
| 8296 | str_ptr = (const u8 *)unsafe_yyjson_get_str(val); |
| 8297 | check_str_len(str_len); |
| 8298 | incr_len(str_len + 2); |
| 8299 | cur = write_raw(cur, str_ptr, str_len); |
| 8300 | *cur++ = ','; |
| 8301 | goto val_end; |
| 8302 | } |
| 8303 | goto fail_type; |
| 8304 | |
| 8305 | val_end: |
| 8306 | val++; |
| 8307 | ctn_len--; |
| 8308 | if (unlikely(ctn_len == 0)) goto ctn_end; |
| 8309 | goto val_begin; |
| 8310 | |
| 8311 | ctn_end: |
| 8312 | cur--; |
| 8313 | *cur++ = (u8)(']' | ((u8)ctn_obj << 5)); |
| 8314 | *cur++ = ','; |
| 8315 | if (unlikely((u8 *)ctx >= end)) goto doc_end; |
| 8316 | yyjson_write_ctx_get(ctx++, &ctn_len, &ctn_obj); |
| 8317 | ctn_len--; |
| 8318 | if (likely(ctn_len > 0)) { |
| 8319 | goto val_begin; |
| 8320 | } else { |
| 8321 | goto ctn_end; |
| 8322 | } |
| 8323 | |
| 8324 | doc_end: |
| 8325 | *--cur = '\0'; |
| 8326 | *dat_len = (usize)(cur - hdr); |
| 8327 | memset(err, 0, sizeof(yyjson_write_err)); |
| 8328 | return hdr; |
| 8329 | |
| 8330 | fail_alloc: |
| 8331 | return_err(MEMORY_ALLOCATION, "memory allocation failed" ); |
| 8332 | fail_type: |
| 8333 | return_err(INVALID_VALUE_TYPE, "invalid JSON value type" ); |
| 8334 | fail_num: |
| 8335 | return_err(NAN_OR_INF, "nan or inf number is not allowed" ); |
| 8336 | fail_str: |
| 8337 | return_err(INVALID_STRING, "invalid utf-8 encoding in string" ); |
| 8338 | |
| 8339 | #undef return_err |
| 8340 | #undef incr_len |
| 8341 | #undef check_str_len |
| 8342 | } |
| 8343 | |
| 8344 | /** Write JSON document pretty. |
| 8345 | The root of this document should be a non-empty container. */ |
| 8346 | static_inline u8 *yyjson_write_pretty(const yyjson_val *root, |
| 8347 | const yyjson_write_flag flg, |
| 8348 | const yyjson_alc alc, |
| 8349 | usize *dat_len, |
| 8350 | yyjson_write_err *err) { |
| 8351 | |
| 8352 | #define return_err(_code, _msg) do { \ |
| 8353 | *dat_len = 0; \ |
| 8354 | err->code = YYJSON_WRITE_ERROR_##_code; \ |
| 8355 | err->msg = _msg; \ |
| 8356 | if (hdr) alc.free(alc.ctx, hdr); \ |
| 8357 | return NULL; \ |
| 8358 | } while (false) |
| 8359 | |
| 8360 | #define incr_len(_len) do { \ |
| 8361 | ext_len = (usize)(_len); \ |
| 8362 | if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \ |
| 8363 | alc_inc = yyjson_max(alc_len / 2, ext_len); \ |
| 8364 | alc_inc = size_align_up(alc_inc, sizeof(yyjson_write_ctx)); \ |
| 8365 | if (size_add_is_overflow(alc_len, alc_inc)) goto fail_alloc; \ |
| 8366 | alc_len += alc_inc; \ |
| 8367 | tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \ |
| 8368 | if (unlikely(!tmp)) goto fail_alloc; \ |
| 8369 | ctx_len = (usize)(end - (u8 *)ctx); \ |
| 8370 | ctx_tmp = (yyjson_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \ |
| 8371 | memmove((void *)ctx_tmp, (void *)(tmp + ((u8 *)ctx - hdr)), ctx_len); \ |
| 8372 | ctx = ctx_tmp; \ |
| 8373 | cur = tmp + (cur - hdr); \ |
| 8374 | end = tmp + alc_len; \ |
| 8375 | hdr = tmp; \ |
| 8376 | } \ |
| 8377 | } while (false) |
| 8378 | |
| 8379 | #define check_str_len(_len) do { \ |
| 8380 | if ((USIZE_MAX < U64_MAX) && (_len >= (USIZE_MAX - 16) / 6)) \ |
| 8381 | goto fail_alloc; \ |
| 8382 | } while (false) |
| 8383 | |
| 8384 | yyjson_val *val; |
| 8385 | yyjson_type val_type; |
| 8386 | usize ctn_len, ctn_len_tmp; |
| 8387 | bool ctn_obj, ctn_obj_tmp, is_key, no_indent; |
| 8388 | u8 *hdr, *cur, *end, *tmp; |
| 8389 | yyjson_write_ctx *ctx, *ctx_tmp; |
| 8390 | usize alc_len, alc_inc, ctx_len, ext_len, str_len, level; |
| 8391 | const u8 *str_ptr; |
| 8392 | const char_enc_type *enc_table = get_enc_table_with_flag(flg); |
| 8393 | bool cpy = (enc_table == enc_table_cpy); |
| 8394 | bool esc = (flg & YYJSON_WRITE_ESCAPE_UNICODE) != 0; |
| 8395 | bool inv = (flg & YYJSON_WRITE_ALLOW_INVALID_UNICODE) != 0; |
| 8396 | usize spaces = (flg & YYJSON_WRITE_PRETTY_TWO_SPACES) ? 2 : 4; |
| 8397 | |
| 8398 | alc_len = root->uni.ofs / sizeof(yyjson_val); |
| 8399 | alc_len = alc_len * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64; |
| 8400 | alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx)); |
| 8401 | hdr = (u8 *)alc.malloc(alc.ctx, alc_len); |
| 8402 | if (!hdr) goto fail_alloc; |
| 8403 | cur = hdr; |
| 8404 | end = hdr + alc_len; |
| 8405 | ctx = (yyjson_write_ctx *)(void *)end; |
| 8406 | |
| 8407 | doc_begin: |
| 8408 | val = constcast(yyjson_val *)root; |
| 8409 | val_type = unsafe_yyjson_get_type(val); |
| 8410 | ctn_obj = (val_type == YYJSON_TYPE_OBJ); |
| 8411 | ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj; |
| 8412 | *cur++ = (u8)('[' | ((u8)ctn_obj << 5)); |
| 8413 | *cur++ = '\n'; |
| 8414 | val++; |
| 8415 | level = 1; |
| 8416 | |
| 8417 | val_begin: |
| 8418 | val_type = unsafe_yyjson_get_type(val); |
| 8419 | if (val_type == YYJSON_TYPE_STR) { |
| 8420 | is_key = (bool)((u8)ctn_obj & (u8)~ctn_len); |
| 8421 | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
| 8422 | str_len = unsafe_yyjson_get_len(val); |
| 8423 | str_ptr = (const u8 *)unsafe_yyjson_get_str(val); |
| 8424 | check_str_len(str_len); |
| 8425 | incr_len(str_len * 6 + 16 + (no_indent ? 0 : level * 4)); |
| 8426 | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
| 8427 | if (likely(cpy) && unsafe_yyjson_get_subtype(val)) { |
| 8428 | cur = write_string_noesc(cur, str_ptr, str_len); |
| 8429 | } else { |
| 8430 | cur = write_string(cur, esc, inv, str_ptr, str_len, enc_table); |
| 8431 | if (unlikely(!cur)) goto fail_str; |
| 8432 | } |
| 8433 | *cur++ = is_key ? ':' : ','; |
| 8434 | *cur++ = is_key ? ' ' : '\n'; |
| 8435 | goto val_end; |
| 8436 | } |
| 8437 | if (val_type == YYJSON_TYPE_NUM) { |
| 8438 | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
| 8439 | incr_len(32 + (no_indent ? 0 : level * 4)); |
| 8440 | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
| 8441 | cur = write_number(cur, val, flg); |
| 8442 | if (unlikely(!cur)) goto fail_num; |
| 8443 | *cur++ = ','; |
| 8444 | *cur++ = '\n'; |
| 8445 | goto val_end; |
| 8446 | } |
| 8447 | if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) == |
| 8448 | (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) { |
| 8449 | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
| 8450 | ctn_len_tmp = unsafe_yyjson_get_len(val); |
| 8451 | ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ); |
| 8452 | if (unlikely(ctn_len_tmp == 0)) { |
| 8453 | /* write empty container */ |
| 8454 | incr_len(16 + (no_indent ? 0 : level * 4)); |
| 8455 | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
| 8456 | *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5)); |
| 8457 | *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5)); |
| 8458 | *cur++ = ','; |
| 8459 | *cur++ = '\n'; |
| 8460 | goto val_end; |
| 8461 | } else { |
| 8462 | /* push context, setup new container */ |
| 8463 | incr_len(32 + (no_indent ? 0 : level * 4)); |
| 8464 | yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj); |
| 8465 | ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp; |
| 8466 | ctn_obj = ctn_obj_tmp; |
| 8467 | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
| 8468 | level++; |
| 8469 | *cur++ = (u8)('[' | ((u8)ctn_obj << 5)); |
| 8470 | *cur++ = '\n'; |
| 8471 | val++; |
| 8472 | goto val_begin; |
| 8473 | } |
| 8474 | } |
| 8475 | if (val_type == YYJSON_TYPE_BOOL) { |
| 8476 | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
| 8477 | incr_len(16 + (no_indent ? 0 : level * 4)); |
| 8478 | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
| 8479 | cur = write_bool(cur, unsafe_yyjson_get_bool(val)); |
| 8480 | cur += 2; |
| 8481 | goto val_end; |
| 8482 | } |
| 8483 | if (val_type == YYJSON_TYPE_NULL) { |
| 8484 | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
| 8485 | incr_len(16 + (no_indent ? 0 : level * 4)); |
| 8486 | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
| 8487 | cur = write_null(cur); |
| 8488 | cur += 2; |
| 8489 | goto val_end; |
| 8490 | } |
| 8491 | if (val_type == YYJSON_TYPE_RAW) { |
| 8492 | str_len = unsafe_yyjson_get_len(val); |
| 8493 | str_ptr = (const u8 *)unsafe_yyjson_get_str(val); |
| 8494 | check_str_len(str_len); |
| 8495 | incr_len(str_len + 3); |
| 8496 | cur = write_raw(cur, str_ptr, str_len); |
| 8497 | *cur++ = ','; |
| 8498 | *cur++ = '\n'; |
| 8499 | goto val_end; |
| 8500 | } |
| 8501 | goto fail_type; |
| 8502 | |
| 8503 | val_end: |
| 8504 | val++; |
| 8505 | ctn_len--; |
| 8506 | if (unlikely(ctn_len == 0)) goto ctn_end; |
| 8507 | goto val_begin; |
| 8508 | |
| 8509 | ctn_end: |
| 8510 | cur -= 2; |
| 8511 | *cur++ = '\n'; |
| 8512 | incr_len(level * 4); |
| 8513 | cur = write_indent(cur, --level, spaces); |
| 8514 | *cur++ = (u8)(']' | ((u8)ctn_obj << 5)); |
| 8515 | if (unlikely((u8 *)ctx >= end)) goto doc_end; |
| 8516 | yyjson_write_ctx_get(ctx++, &ctn_len, &ctn_obj); |
| 8517 | ctn_len--; |
| 8518 | *cur++ = ','; |
| 8519 | *cur++ = '\n'; |
| 8520 | if (likely(ctn_len > 0)) { |
| 8521 | goto val_begin; |
| 8522 | } else { |
| 8523 | goto ctn_end; |
| 8524 | } |
| 8525 | |
| 8526 | doc_end: |
| 8527 | *cur = '\0'; |
| 8528 | *dat_len = (usize)(cur - hdr); |
| 8529 | memset(err, 0, sizeof(yyjson_write_err)); |
| 8530 | return hdr; |
| 8531 | |
| 8532 | fail_alloc: |
| 8533 | return_err(MEMORY_ALLOCATION, "memory allocation failed" ); |
| 8534 | fail_type: |
| 8535 | return_err(INVALID_VALUE_TYPE, "invalid JSON value type" ); |
| 8536 | fail_num: |
| 8537 | return_err(NAN_OR_INF, "nan or inf number is not allowed" ); |
| 8538 | fail_str: |
| 8539 | return_err(INVALID_STRING, "invalid utf-8 encoding in string" ); |
| 8540 | |
| 8541 | #undef return_err |
| 8542 | #undef incr_len |
| 8543 | #undef check_str_len |
| 8544 | } |
| 8545 | |
| 8546 | char *yyjson_val_write_opts(const yyjson_val *val, |
| 8547 | yyjson_write_flag flg, |
| 8548 | const yyjson_alc *alc_ptr, |
| 8549 | usize *dat_len, |
| 8550 | yyjson_write_err *err) { |
| 8551 | yyjson_write_err dummy_err; |
| 8552 | usize dummy_dat_len; |
| 8553 | yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC; |
| 8554 | yyjson_val *root = constcast(yyjson_val *)val; |
| 8555 | |
| 8556 | err = err ? err : &dummy_err; |
| 8557 | dat_len = dat_len ? dat_len : &dummy_dat_len; |
| 8558 | |
| 8559 | #if YYJSON_DISABLE_NON_STANDARD |
| 8560 | flg &= ~YYJSON_WRITE_ALLOW_INF_AND_NAN; |
| 8561 | flg &= ~YYJSON_WRITE_ALLOW_INVALID_UNICODE; |
| 8562 | #endif |
| 8563 | |
| 8564 | if (unlikely(!root)) { |
| 8565 | *dat_len = 0; |
| 8566 | err->msg = "input JSON is NULL" ; |
| 8567 | err->code = YYJSON_READ_ERROR_INVALID_PARAMETER; |
| 8568 | return NULL; |
| 8569 | } |
| 8570 | |
| 8571 | if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) { |
| 8572 | return (char *)yyjson_write_single(root, flg, alc, dat_len, err); |
| 8573 | } else if (flg & (YYJSON_WRITE_PRETTY | YYJSON_WRITE_PRETTY_TWO_SPACES)) { |
| 8574 | return (char *)yyjson_write_pretty(root, flg, alc, dat_len, err); |
| 8575 | } else { |
| 8576 | return (char *)yyjson_write_minify(root, flg, alc, dat_len, err); |
| 8577 | } |
| 8578 | } |
| 8579 | |
| 8580 | char *yyjson_write_opts(const yyjson_doc *doc, |
| 8581 | yyjson_write_flag flg, |
| 8582 | const yyjson_alc *alc_ptr, |
| 8583 | usize *dat_len, |
| 8584 | yyjson_write_err *err) { |
| 8585 | yyjson_val *root = doc ? doc->root : NULL; |
| 8586 | return yyjson_val_write_opts(root, flg, alc_ptr, dat_len, err); |
| 8587 | } |
| 8588 | |
| 8589 | bool yyjson_val_write_file(const char *path, |
| 8590 | const yyjson_val *val, |
| 8591 | yyjson_write_flag flg, |
| 8592 | const yyjson_alc *alc_ptr, |
| 8593 | yyjson_write_err *err) { |
| 8594 | yyjson_write_err dummy_err; |
| 8595 | u8 *dat; |
| 8596 | usize dat_len = 0; |
| 8597 | yyjson_val *root = constcast(yyjson_val *)val; |
| 8598 | bool suc; |
| 8599 | |
| 8600 | alc_ptr = alc_ptr ? alc_ptr : &YYJSON_DEFAULT_ALC; |
| 8601 | err = err ? err : &dummy_err; |
| 8602 | if (unlikely(!path || !*path)) { |
| 8603 | err->msg = "input path is invalid" ; |
| 8604 | err->code = YYJSON_READ_ERROR_INVALID_PARAMETER; |
| 8605 | return false; |
| 8606 | } |
| 8607 | |
| 8608 | dat = (u8 *)yyjson_val_write_opts(root, flg, alc_ptr, &dat_len, err); |
| 8609 | if (unlikely(!dat)) return false; |
| 8610 | suc = write_dat_to_file(path, dat, dat_len, err); |
| 8611 | alc_ptr->free(alc_ptr->ctx, dat); |
| 8612 | return suc; |
| 8613 | } |
| 8614 | |
| 8615 | bool yyjson_val_write_fp(FILE *fp, |
| 8616 | const yyjson_val *val, |
| 8617 | yyjson_write_flag flg, |
| 8618 | const yyjson_alc *alc_ptr, |
| 8619 | yyjson_write_err *err) { |
| 8620 | yyjson_write_err dummy_err; |
| 8621 | u8 *dat; |
| 8622 | usize dat_len = 0; |
| 8623 | yyjson_val *root = constcast(yyjson_val *)val; |
| 8624 | bool suc; |
| 8625 | |
| 8626 | alc_ptr = alc_ptr ? alc_ptr : &YYJSON_DEFAULT_ALC; |
| 8627 | err = err ? err : &dummy_err; |
| 8628 | if (unlikely(!fp)) { |
| 8629 | err->msg = "input fp is invalid" ; |
| 8630 | err->code = YYJSON_READ_ERROR_INVALID_PARAMETER; |
| 8631 | return false; |
| 8632 | } |
| 8633 | |
| 8634 | dat = (u8 *)yyjson_val_write_opts(root, flg, alc_ptr, &dat_len, err); |
| 8635 | if (unlikely(!dat)) return false; |
| 8636 | suc = write_dat_to_fp(fp, dat, dat_len, err); |
| 8637 | alc_ptr->free(alc_ptr->ctx, dat); |
| 8638 | return suc; |
| 8639 | } |
| 8640 | |
| 8641 | bool yyjson_write_file(const char *path, |
| 8642 | const yyjson_doc *doc, |
| 8643 | yyjson_write_flag flg, |
| 8644 | const yyjson_alc *alc_ptr, |
| 8645 | yyjson_write_err *err) { |
| 8646 | yyjson_val *root = doc ? doc->root : NULL; |
| 8647 | return yyjson_val_write_file(path, root, flg, alc_ptr, err); |
| 8648 | } |
| 8649 | |
| 8650 | bool yyjson_write_fp(FILE *fp, |
| 8651 | const yyjson_doc *doc, |
| 8652 | yyjson_write_flag flg, |
| 8653 | const yyjson_alc *alc_ptr, |
| 8654 | yyjson_write_err *err) { |
| 8655 | yyjson_val *root = doc ? doc->root : NULL; |
| 8656 | return yyjson_val_write_fp(fp, root, flg, alc_ptr, err); |
| 8657 | } |
| 8658 | |
| 8659 | |
| 8660 | |
| 8661 | /*============================================================================== |
| 8662 | * Mutable JSON Writer Implementation |
| 8663 | *============================================================================*/ |
| 8664 | |
| 8665 | typedef struct yyjson_mut_write_ctx { |
| 8666 | usize tag; |
| 8667 | yyjson_mut_val *ctn; |
| 8668 | } yyjson_mut_write_ctx; |
| 8669 | |
| 8670 | static_inline void yyjson_mut_write_ctx_set(yyjson_mut_write_ctx *ctx, |
| 8671 | yyjson_mut_val *ctn, |
| 8672 | usize size, bool is_obj) { |
| 8673 | ctx->tag = (size << 1) | (usize)is_obj; |
| 8674 | ctx->ctn = ctn; |
| 8675 | } |
| 8676 | |
| 8677 | static_inline void yyjson_mut_write_ctx_get(yyjson_mut_write_ctx *ctx, |
| 8678 | yyjson_mut_val **ctn, |
| 8679 | usize *size, bool *is_obj) { |
| 8680 | usize tag = ctx->tag; |
| 8681 | *size = tag >> 1; |
| 8682 | *is_obj = (bool)(tag & 1); |
| 8683 | *ctn = ctx->ctn; |
| 8684 | } |
| 8685 | |
| 8686 | /** Get the estimated number of values for the mutable JSON document. */ |
| 8687 | static_inline usize yyjson_mut_doc_estimated_val_num( |
| 8688 | const yyjson_mut_doc *doc) { |
| 8689 | usize sum = 0; |
| 8690 | yyjson_val_chunk *chunk = doc->val_pool.chunks; |
| 8691 | while (chunk) { |
| 8692 | sum += chunk->chunk_size / sizeof(yyjson_mut_val) - 1; |
| 8693 | if (chunk == doc->val_pool.chunks) { |
| 8694 | sum -= (usize)(doc->val_pool.end - doc->val_pool.cur); |
| 8695 | } |
| 8696 | chunk = chunk->next; |
| 8697 | } |
| 8698 | return sum; |
| 8699 | } |
| 8700 | |
| 8701 | /** Write single JSON value. */ |
| 8702 | static_inline u8 *yyjson_mut_write_single(yyjson_mut_val *val, |
| 8703 | yyjson_write_flag flg, |
| 8704 | yyjson_alc alc, |
| 8705 | usize *dat_len, |
| 8706 | yyjson_write_err *err) { |
| 8707 | return yyjson_write_single((yyjson_val *)val, flg, alc, dat_len, err); |
| 8708 | } |
| 8709 | |
| 8710 | /** Write JSON document minify. |
| 8711 | The root of this document should be a non-empty container. */ |
| 8712 | static_inline u8 *yyjson_mut_write_minify(const yyjson_mut_val *root, |
| 8713 | usize estimated_val_num, |
| 8714 | yyjson_write_flag flg, |
| 8715 | yyjson_alc alc, |
| 8716 | usize *dat_len, |
| 8717 | yyjson_write_err *err) { |
| 8718 | |
| 8719 | #define return_err(_code, _msg) do { \ |
| 8720 | *dat_len = 0; \ |
| 8721 | err->code = YYJSON_WRITE_ERROR_##_code; \ |
| 8722 | err->msg = _msg; \ |
| 8723 | if (hdr) alc.free(alc.ctx, hdr); \ |
| 8724 | return NULL; \ |
| 8725 | } while (false) |
| 8726 | |
| 8727 | #define incr_len(_len) do { \ |
| 8728 | ext_len = (usize)(_len); \ |
| 8729 | if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \ |
| 8730 | alc_inc = yyjson_max(alc_len / 2, ext_len); \ |
| 8731 | alc_inc = size_align_up(alc_inc, sizeof(yyjson_mut_write_ctx)); \ |
| 8732 | if (size_add_is_overflow(alc_len, alc_inc)) goto fail_alloc; \ |
| 8733 | alc_len += alc_inc; \ |
| 8734 | tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \ |
| 8735 | if (unlikely(!tmp)) goto fail_alloc; \ |
| 8736 | ctx_len = (usize)(end - (u8 *)ctx); \ |
| 8737 | ctx_tmp = (yyjson_mut_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \ |
| 8738 | memmove((void *)ctx_tmp, (void *)(tmp + ((u8 *)ctx - hdr)), ctx_len); \ |
| 8739 | ctx = ctx_tmp; \ |
| 8740 | cur = tmp + (cur - hdr); \ |
| 8741 | end = tmp + alc_len; \ |
| 8742 | hdr = tmp; \ |
| 8743 | } \ |
| 8744 | } while (false) |
| 8745 | |
| 8746 | #define check_str_len(_len) do { \ |
| 8747 | if ((USIZE_MAX < U64_MAX) && (_len >= (USIZE_MAX - 16) / 6)) \ |
| 8748 | goto fail_alloc; \ |
| 8749 | } while (false) |
| 8750 | |
| 8751 | yyjson_mut_val *val, *ctn; |
| 8752 | yyjson_type val_type; |
| 8753 | usize ctn_len, ctn_len_tmp; |
| 8754 | bool ctn_obj, ctn_obj_tmp, is_key; |
| 8755 | u8 *hdr, *cur, *end, *tmp; |
| 8756 | yyjson_mut_write_ctx *ctx, *ctx_tmp; |
| 8757 | usize alc_len, alc_inc, ctx_len, ext_len, str_len; |
| 8758 | const u8 *str_ptr; |
| 8759 | const char_enc_type *enc_table = get_enc_table_with_flag(flg); |
| 8760 | bool cpy = (enc_table == enc_table_cpy); |
| 8761 | bool esc = (flg & YYJSON_WRITE_ESCAPE_UNICODE) != 0; |
| 8762 | bool inv = (flg & YYJSON_WRITE_ALLOW_INVALID_UNICODE) != 0; |
| 8763 | |
| 8764 | alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64; |
| 8765 | alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx)); |
| 8766 | hdr = (u8 *)alc.malloc(alc.ctx, alc_len); |
| 8767 | if (!hdr) goto fail_alloc; |
| 8768 | cur = hdr; |
| 8769 | end = hdr + alc_len; |
| 8770 | ctx = (yyjson_mut_write_ctx *)(void *)end; |
| 8771 | |
| 8772 | doc_begin: |
| 8773 | val = constcast(yyjson_mut_val *)root; |
| 8774 | val_type = unsafe_yyjson_get_type(val); |
| 8775 | ctn_obj = (val_type == YYJSON_TYPE_OBJ); |
| 8776 | ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj; |
| 8777 | *cur++ = (u8)('[' | ((u8)ctn_obj << 5)); |
| 8778 | ctn = val; |
| 8779 | val = (yyjson_mut_val *)val->uni.ptr; /* tail */ |
| 8780 | val = ctn_obj ? val->next->next : val->next; |
| 8781 | |
| 8782 | val_begin: |
| 8783 | val_type = unsafe_yyjson_get_type(val); |
| 8784 | if (val_type == YYJSON_TYPE_STR) { |
| 8785 | is_key = ((u8)ctn_obj & (u8)~ctn_len); |
| 8786 | str_len = unsafe_yyjson_get_len(val); |
| 8787 | str_ptr = (const u8 *)unsafe_yyjson_get_str(val); |
| 8788 | check_str_len(str_len); |
| 8789 | incr_len(str_len * 6 + 16); |
| 8790 | if (likely(cpy) && unsafe_yyjson_get_subtype(val)) { |
| 8791 | cur = write_string_noesc(cur, str_ptr, str_len); |
| 8792 | } else { |
| 8793 | cur = write_string(cur, esc, inv, str_ptr, str_len, enc_table); |
| 8794 | if (unlikely(!cur)) goto fail_str; |
| 8795 | } |
| 8796 | *cur++ = is_key ? ':' : ','; |
| 8797 | goto val_end; |
| 8798 | } |
| 8799 | if (val_type == YYJSON_TYPE_NUM) { |
| 8800 | incr_len(32); |
| 8801 | cur = write_number(cur, (yyjson_val *)val, flg); |
| 8802 | if (unlikely(!cur)) goto fail_num; |
| 8803 | *cur++ = ','; |
| 8804 | goto val_end; |
| 8805 | } |
| 8806 | if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) == |
| 8807 | (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) { |
| 8808 | ctn_len_tmp = unsafe_yyjson_get_len(val); |
| 8809 | ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ); |
| 8810 | incr_len(16); |
| 8811 | if (unlikely(ctn_len_tmp == 0)) { |
| 8812 | /* write empty container */ |
| 8813 | *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5)); |
| 8814 | *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5)); |
| 8815 | *cur++ = ','; |
| 8816 | goto val_end; |
| 8817 | } else { |
| 8818 | /* push context, setup new container */ |
| 8819 | yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj); |
| 8820 | ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp; |
| 8821 | ctn_obj = ctn_obj_tmp; |
| 8822 | *cur++ = (u8)('[' | ((u8)ctn_obj << 5)); |
| 8823 | ctn = val; |
| 8824 | val = (yyjson_mut_val *)ctn->uni.ptr; /* tail */ |
| 8825 | val = ctn_obj ? val->next->next : val->next; |
| 8826 | goto val_begin; |
| 8827 | } |
| 8828 | } |
| 8829 | if (val_type == YYJSON_TYPE_BOOL) { |
| 8830 | incr_len(16); |
| 8831 | cur = write_bool(cur, unsafe_yyjson_get_bool(val)); |
| 8832 | cur++; |
| 8833 | goto val_end; |
| 8834 | } |
| 8835 | if (val_type == YYJSON_TYPE_NULL) { |
| 8836 | incr_len(16); |
| 8837 | cur = write_null(cur); |
| 8838 | cur++; |
| 8839 | goto val_end; |
| 8840 | } |
| 8841 | if (val_type == YYJSON_TYPE_RAW) { |
| 8842 | str_len = unsafe_yyjson_get_len(val); |
| 8843 | str_ptr = (const u8 *)unsafe_yyjson_get_str(val); |
| 8844 | check_str_len(str_len); |
| 8845 | incr_len(str_len + 2); |
| 8846 | cur = write_raw(cur, str_ptr, str_len); |
| 8847 | *cur++ = ','; |
| 8848 | goto val_end; |
| 8849 | } |
| 8850 | goto fail_type; |
| 8851 | |
| 8852 | val_end: |
| 8853 | ctn_len--; |
| 8854 | if (unlikely(ctn_len == 0)) goto ctn_end; |
| 8855 | val = val->next; |
| 8856 | goto val_begin; |
| 8857 | |
| 8858 | ctn_end: |
| 8859 | cur--; |
| 8860 | *cur++ = (u8)(']' | ((u8)ctn_obj << 5)); |
| 8861 | *cur++ = ','; |
| 8862 | if (unlikely((u8 *)ctx >= end)) goto doc_end; |
| 8863 | val = ctn->next; |
| 8864 | yyjson_mut_write_ctx_get(ctx++, &ctn, &ctn_len, &ctn_obj); |
| 8865 | ctn_len--; |
| 8866 | if (likely(ctn_len > 0)) { |
| 8867 | goto val_begin; |
| 8868 | } else { |
| 8869 | goto ctn_end; |
| 8870 | } |
| 8871 | |
| 8872 | doc_end: |
| 8873 | *--cur = '\0'; |
| 8874 | *dat_len = (usize)(cur - hdr); |
| 8875 | err->code = YYJSON_WRITE_SUCCESS; |
| 8876 | err->msg = "success" ; |
| 8877 | return hdr; |
| 8878 | |
| 8879 | fail_alloc: |
| 8880 | return_err(MEMORY_ALLOCATION, "memory allocation failed" ); |
| 8881 | fail_type: |
| 8882 | return_err(INVALID_VALUE_TYPE, "invalid JSON value type" ); |
| 8883 | fail_num: |
| 8884 | return_err(NAN_OR_INF, "nan or inf number is not allowed" ); |
| 8885 | fail_str: |
| 8886 | return_err(INVALID_STRING, "invalid utf-8 encoding in string" ); |
| 8887 | |
| 8888 | #undef return_err |
| 8889 | #undef incr_len |
| 8890 | #undef check_str_len |
| 8891 | } |
| 8892 | |
| 8893 | /** Write JSON document pretty. |
| 8894 | The root of this document should be a non-empty container. */ |
| 8895 | static_inline u8 *yyjson_mut_write_pretty(const yyjson_mut_val *root, |
| 8896 | usize estimated_val_num, |
| 8897 | yyjson_write_flag flg, |
| 8898 | yyjson_alc alc, |
| 8899 | usize *dat_len, |
| 8900 | yyjson_write_err *err) { |
| 8901 | |
| 8902 | #define return_err(_code, _msg) do { \ |
| 8903 | *dat_len = 0; \ |
| 8904 | err->code = YYJSON_WRITE_ERROR_##_code; \ |
| 8905 | err->msg = _msg; \ |
| 8906 | if (hdr) alc.free(alc.ctx, hdr); \ |
| 8907 | return NULL; \ |
| 8908 | } while (false) |
| 8909 | |
| 8910 | #define incr_len(_len) do { \ |
| 8911 | ext_len = (usize)(_len); \ |
| 8912 | if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \ |
| 8913 | alc_inc = yyjson_max(alc_len / 2, ext_len); \ |
| 8914 | alc_inc = size_align_up(alc_inc, sizeof(yyjson_mut_write_ctx)); \ |
| 8915 | if (size_add_is_overflow(alc_len, alc_inc)) goto fail_alloc; \ |
| 8916 | alc_len += alc_inc; \ |
| 8917 | tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \ |
| 8918 | if (unlikely(!tmp)) goto fail_alloc; \ |
| 8919 | ctx_len = (usize)(end - (u8 *)ctx); \ |
| 8920 | ctx_tmp = (yyjson_mut_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \ |
| 8921 | memmove((void *)ctx_tmp, (void *)(tmp + ((u8 *)ctx - hdr)), ctx_len); \ |
| 8922 | ctx = ctx_tmp; \ |
| 8923 | cur = tmp + (cur - hdr); \ |
| 8924 | end = tmp + alc_len; \ |
| 8925 | hdr = tmp; \ |
| 8926 | } \ |
| 8927 | } while (false) |
| 8928 | |
| 8929 | #define check_str_len(_len) do { \ |
| 8930 | if ((USIZE_MAX < U64_MAX) && (_len >= (USIZE_MAX - 16) / 6)) \ |
| 8931 | goto fail_alloc; \ |
| 8932 | } while (false) |
| 8933 | |
| 8934 | yyjson_mut_val *val, *ctn; |
| 8935 | yyjson_type val_type; |
| 8936 | usize ctn_len, ctn_len_tmp; |
| 8937 | bool ctn_obj, ctn_obj_tmp, is_key, no_indent; |
| 8938 | u8 *hdr, *cur, *end, *tmp; |
| 8939 | yyjson_mut_write_ctx *ctx, *ctx_tmp; |
| 8940 | usize alc_len, alc_inc, ctx_len, ext_len, str_len, level; |
| 8941 | const u8 *str_ptr; |
| 8942 | const char_enc_type *enc_table = get_enc_table_with_flag(flg); |
| 8943 | bool cpy = (enc_table == enc_table_cpy); |
| 8944 | bool esc = (flg & YYJSON_WRITE_ESCAPE_UNICODE) != 0; |
| 8945 | bool inv = (flg & YYJSON_WRITE_ALLOW_INVALID_UNICODE) != 0; |
| 8946 | usize spaces = (flg & YYJSON_WRITE_PRETTY_TWO_SPACES) ? 2 : 4; |
| 8947 | |
| 8948 | alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64; |
| 8949 | alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx)); |
| 8950 | hdr = (u8 *)alc.malloc(alc.ctx, alc_len); |
| 8951 | if (!hdr) goto fail_alloc; |
| 8952 | cur = hdr; |
| 8953 | end = hdr + alc_len; |
| 8954 | ctx = (yyjson_mut_write_ctx *)(void *)end; |
| 8955 | |
| 8956 | doc_begin: |
| 8957 | val = constcast(yyjson_mut_val *)root; |
| 8958 | val_type = unsafe_yyjson_get_type(val); |
| 8959 | ctn_obj = (val_type == YYJSON_TYPE_OBJ); |
| 8960 | ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj; |
| 8961 | *cur++ = (u8)('[' | ((u8)ctn_obj << 5)); |
| 8962 | *cur++ = '\n'; |
| 8963 | ctn = val; |
| 8964 | val = (yyjson_mut_val *)val->uni.ptr; /* tail */ |
| 8965 | val = ctn_obj ? val->next->next : val->next; |
| 8966 | level = 1; |
| 8967 | |
| 8968 | val_begin: |
| 8969 | val_type = unsafe_yyjson_get_type(val); |
| 8970 | if (val_type == YYJSON_TYPE_STR) { |
| 8971 | is_key = (bool)((u8)ctn_obj & (u8)~ctn_len); |
| 8972 | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
| 8973 | str_len = unsafe_yyjson_get_len(val); |
| 8974 | str_ptr = (const u8 *)unsafe_yyjson_get_str(val); |
| 8975 | check_str_len(str_len); |
| 8976 | incr_len(str_len * 6 + 16 + (no_indent ? 0 : level * 4)); |
| 8977 | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
| 8978 | if (likely(cpy) && unsafe_yyjson_get_subtype(val)) { |
| 8979 | cur = write_string_noesc(cur, str_ptr, str_len); |
| 8980 | } else { |
| 8981 | cur = write_string(cur, esc, inv, str_ptr, str_len, enc_table); |
| 8982 | if (unlikely(!cur)) goto fail_str; |
| 8983 | } |
| 8984 | *cur++ = is_key ? ':' : ','; |
| 8985 | *cur++ = is_key ? ' ' : '\n'; |
| 8986 | goto val_end; |
| 8987 | } |
| 8988 | if (val_type == YYJSON_TYPE_NUM) { |
| 8989 | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
| 8990 | incr_len(32 + (no_indent ? 0 : level * 4)); |
| 8991 | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
| 8992 | cur = write_number(cur, (yyjson_val *)val, flg); |
| 8993 | if (unlikely(!cur)) goto fail_num; |
| 8994 | *cur++ = ','; |
| 8995 | *cur++ = '\n'; |
| 8996 | goto val_end; |
| 8997 | } |
| 8998 | if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) == |
| 8999 | (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) { |
| 9000 | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
| 9001 | ctn_len_tmp = unsafe_yyjson_get_len(val); |
| 9002 | ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ); |
| 9003 | if (unlikely(ctn_len_tmp == 0)) { |
| 9004 | /* write empty container */ |
| 9005 | incr_len(16 + (no_indent ? 0 : level * 4)); |
| 9006 | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
| 9007 | *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5)); |
| 9008 | *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5)); |
| 9009 | *cur++ = ','; |
| 9010 | *cur++ = '\n'; |
| 9011 | goto val_end; |
| 9012 | } else { |
| 9013 | /* push context, setup new container */ |
| 9014 | incr_len(32 + (no_indent ? 0 : level * 4)); |
| 9015 | yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj); |
| 9016 | ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp; |
| 9017 | ctn_obj = ctn_obj_tmp; |
| 9018 | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
| 9019 | level++; |
| 9020 | *cur++ = (u8)('[' | ((u8)ctn_obj << 5)); |
| 9021 | *cur++ = '\n'; |
| 9022 | ctn = val; |
| 9023 | val = (yyjson_mut_val *)ctn->uni.ptr; /* tail */ |
| 9024 | val = ctn_obj ? val->next->next : val->next; |
| 9025 | goto val_begin; |
| 9026 | } |
| 9027 | } |
| 9028 | if (val_type == YYJSON_TYPE_BOOL) { |
| 9029 | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
| 9030 | incr_len(16 + (no_indent ? 0 : level * 4)); |
| 9031 | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
| 9032 | cur = write_bool(cur, unsafe_yyjson_get_bool(val)); |
| 9033 | cur += 2; |
| 9034 | goto val_end; |
| 9035 | } |
| 9036 | if (val_type == YYJSON_TYPE_NULL) { |
| 9037 | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
| 9038 | incr_len(16 + (no_indent ? 0 : level * 4)); |
| 9039 | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
| 9040 | cur = write_null(cur); |
| 9041 | cur += 2; |
| 9042 | goto val_end; |
| 9043 | } |
| 9044 | if (val_type == YYJSON_TYPE_RAW) { |
| 9045 | str_len = unsafe_yyjson_get_len(val); |
| 9046 | str_ptr = (const u8 *)unsafe_yyjson_get_str(val); |
| 9047 | check_str_len(str_len); |
| 9048 | incr_len(str_len + 3); |
| 9049 | cur = write_raw(cur, str_ptr, str_len); |
| 9050 | *cur++ = ','; |
| 9051 | *cur++ = '\n'; |
| 9052 | goto val_end; |
| 9053 | } |
| 9054 | goto fail_type; |
| 9055 | |
| 9056 | val_end: |
| 9057 | ctn_len--; |
| 9058 | if (unlikely(ctn_len == 0)) goto ctn_end; |
| 9059 | val = val->next; |
| 9060 | goto val_begin; |
| 9061 | |
| 9062 | ctn_end: |
| 9063 | cur -= 2; |
| 9064 | *cur++ = '\n'; |
| 9065 | incr_len(level * 4); |
| 9066 | cur = write_indent(cur, --level, spaces); |
| 9067 | *cur++ = (u8)(']' | ((u8)ctn_obj << 5)); |
| 9068 | if (unlikely((u8 *)ctx >= end)) goto doc_end; |
| 9069 | val = ctn->next; |
| 9070 | yyjson_mut_write_ctx_get(ctx++, &ctn, &ctn_len, &ctn_obj); |
| 9071 | ctn_len--; |
| 9072 | *cur++ = ','; |
| 9073 | *cur++ = '\n'; |
| 9074 | if (likely(ctn_len > 0)) { |
| 9075 | goto val_begin; |
| 9076 | } else { |
| 9077 | goto ctn_end; |
| 9078 | } |
| 9079 | |
| 9080 | doc_end: |
| 9081 | *cur = '\0'; |
| 9082 | *dat_len = (usize)(cur - hdr); |
| 9083 | err->code = YYJSON_WRITE_SUCCESS; |
| 9084 | err->msg = "success" ; |
| 9085 | return hdr; |
| 9086 | |
| 9087 | fail_alloc: |
| 9088 | return_err(MEMORY_ALLOCATION, "memory allocation failed" ); |
| 9089 | fail_type: |
| 9090 | return_err(INVALID_VALUE_TYPE, "invalid JSON value type" ); |
| 9091 | fail_num: |
| 9092 | return_err(NAN_OR_INF, "nan or inf number is not allowed" ); |
| 9093 | fail_str: |
| 9094 | return_err(INVALID_STRING, "invalid utf-8 encoding in string" ); |
| 9095 | |
| 9096 | #undef return_err |
| 9097 | #undef incr_len |
| 9098 | #undef check_str_len |
| 9099 | } |
| 9100 | |
| 9101 | static char *yyjson_mut_write_opts_impl(const yyjson_mut_val *val, |
| 9102 | usize estimated_val_num, |
| 9103 | yyjson_write_flag flg, |
| 9104 | const yyjson_alc *alc_ptr, |
| 9105 | usize *dat_len, |
| 9106 | yyjson_write_err *err) { |
| 9107 | yyjson_write_err dummy_err; |
| 9108 | usize dummy_dat_len; |
| 9109 | yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC; |
| 9110 | yyjson_mut_val *root = constcast(yyjson_mut_val *)val; |
| 9111 | |
| 9112 | err = err ? err : &dummy_err; |
| 9113 | dat_len = dat_len ? dat_len : &dummy_dat_len; |
| 9114 | |
| 9115 | #if YYJSON_DISABLE_NON_STANDARD |
| 9116 | flg &= ~YYJSON_WRITE_ALLOW_INF_AND_NAN; |
| 9117 | flg &= ~YYJSON_WRITE_ALLOW_INVALID_UNICODE; |
| 9118 | #endif |
| 9119 | |
| 9120 | if (unlikely(!root)) { |
| 9121 | *dat_len = 0; |
| 9122 | err->msg = "input JSON is NULL" ; |
| 9123 | err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER; |
| 9124 | return NULL; |
| 9125 | } |
| 9126 | |
| 9127 | if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) { |
| 9128 | return (char *)yyjson_mut_write_single(root, flg, alc, dat_len, err); |
| 9129 | } else if (flg & (YYJSON_WRITE_PRETTY | YYJSON_WRITE_PRETTY_TWO_SPACES)) { |
| 9130 | return (char *)yyjson_mut_write_pretty(root, estimated_val_num, |
| 9131 | flg, alc, dat_len, err); |
| 9132 | } else { |
| 9133 | return (char *)yyjson_mut_write_minify(root, estimated_val_num, |
| 9134 | flg, alc, dat_len, err); |
| 9135 | } |
| 9136 | } |
| 9137 | |
| 9138 | char *yyjson_mut_val_write_opts(const yyjson_mut_val *val, |
| 9139 | yyjson_write_flag flg, |
| 9140 | const yyjson_alc *alc_ptr, |
| 9141 | usize *dat_len, |
| 9142 | yyjson_write_err *err) { |
| 9143 | return yyjson_mut_write_opts_impl(val, 0, flg, alc_ptr, dat_len, err); |
| 9144 | } |
| 9145 | |
| 9146 | char *yyjson_mut_write_opts(const yyjson_mut_doc *doc, |
| 9147 | yyjson_write_flag flg, |
| 9148 | const yyjson_alc *alc_ptr, |
| 9149 | usize *dat_len, |
| 9150 | yyjson_write_err *err) { |
| 9151 | yyjson_mut_val *root; |
| 9152 | usize estimated_val_num; |
| 9153 | if (likely(doc)) { |
| 9154 | root = doc->root; |
| 9155 | estimated_val_num = yyjson_mut_doc_estimated_val_num(doc); |
| 9156 | } else { |
| 9157 | root = NULL; |
| 9158 | estimated_val_num = 0; |
| 9159 | } |
| 9160 | return yyjson_mut_write_opts_impl(root, estimated_val_num, |
| 9161 | flg, alc_ptr, dat_len, err); |
| 9162 | } |
| 9163 | |
| 9164 | bool yyjson_mut_val_write_file(const char *path, |
| 9165 | const yyjson_mut_val *val, |
| 9166 | yyjson_write_flag flg, |
| 9167 | const yyjson_alc *alc_ptr, |
| 9168 | yyjson_write_err *err) { |
| 9169 | yyjson_write_err dummy_err; |
| 9170 | u8 *dat; |
| 9171 | usize dat_len = 0; |
| 9172 | yyjson_mut_val *root = constcast(yyjson_mut_val *)val; |
| 9173 | bool suc; |
| 9174 | |
| 9175 | alc_ptr = alc_ptr ? alc_ptr : &YYJSON_DEFAULT_ALC; |
| 9176 | err = err ? err : &dummy_err; |
| 9177 | if (unlikely(!path || !*path)) { |
| 9178 | err->msg = "input path is invalid" ; |
| 9179 | err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER; |
| 9180 | return false; |
| 9181 | } |
| 9182 | |
| 9183 | dat = (u8 *)yyjson_mut_val_write_opts(root, flg, alc_ptr, &dat_len, err); |
| 9184 | if (unlikely(!dat)) return false; |
| 9185 | suc = write_dat_to_file(path, dat, dat_len, err); |
| 9186 | alc_ptr->free(alc_ptr->ctx, dat); |
| 9187 | return suc; |
| 9188 | } |
| 9189 | |
| 9190 | bool yyjson_mut_val_write_fp(FILE *fp, |
| 9191 | const yyjson_mut_val *val, |
| 9192 | yyjson_write_flag flg, |
| 9193 | const yyjson_alc *alc_ptr, |
| 9194 | yyjson_write_err *err) { |
| 9195 | yyjson_write_err dummy_err; |
| 9196 | u8 *dat; |
| 9197 | usize dat_len = 0; |
| 9198 | yyjson_mut_val *root = constcast(yyjson_mut_val *)val; |
| 9199 | bool suc; |
| 9200 | |
| 9201 | alc_ptr = alc_ptr ? alc_ptr : &YYJSON_DEFAULT_ALC; |
| 9202 | err = err ? err : &dummy_err; |
| 9203 | if (unlikely(!fp)) { |
| 9204 | err->msg = "input fp is invalid" ; |
| 9205 | err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER; |
| 9206 | return false; |
| 9207 | } |
| 9208 | |
| 9209 | dat = (u8 *)yyjson_mut_val_write_opts(root, flg, alc_ptr, &dat_len, err); |
| 9210 | if (unlikely(!dat)) return false; |
| 9211 | suc = write_dat_to_fp(fp, dat, dat_len, err); |
| 9212 | alc_ptr->free(alc_ptr->ctx, dat); |
| 9213 | return suc; |
| 9214 | } |
| 9215 | |
| 9216 | bool yyjson_mut_write_file(const char *path, |
| 9217 | const yyjson_mut_doc *doc, |
| 9218 | yyjson_write_flag flg, |
| 9219 | const yyjson_alc *alc_ptr, |
| 9220 | yyjson_write_err *err) { |
| 9221 | yyjson_mut_val *root = doc ? doc->root : NULL; |
| 9222 | return yyjson_mut_val_write_file(path, root, flg, alc_ptr, err); |
| 9223 | } |
| 9224 | |
| 9225 | bool yyjson_mut_write_fp(FILE *fp, |
| 9226 | const yyjson_mut_doc *doc, |
| 9227 | yyjson_write_flag flg, |
| 9228 | const yyjson_alc *alc_ptr, |
| 9229 | yyjson_write_err *err) { |
| 9230 | yyjson_mut_val *root = doc ? doc->root : NULL; |
| 9231 | return yyjson_mut_val_write_fp(fp, root, flg, alc_ptr, err); |
| 9232 | } |
| 9233 | |
| 9234 | #endif /* YYJSON_DISABLE_WRITER */ |
| 9235 | |
| 9236 | |
| 9237 | |
| 9238 | /*============================================================================== |
| 9239 | * Compiler Hint End |
| 9240 | *============================================================================*/ |
| 9241 | |
| 9242 | #if defined(__clang__) |
| 9243 | # pragma clang diagnostic pop |
| 9244 | #elif defined(__GNUC__) |
| 9245 | # if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) |
| 9246 | # pragma GCC diagnostic pop |
| 9247 | # endif |
| 9248 | #elif defined(_MSC_VER) |
| 9249 | # pragma warning(pop) |
| 9250 | #endif /* warning suppress end */ |
| 9251 | |