Line | Count | Source |
1 | | /*============================================================================== |
2 | | Copyright (c) 2020 YaoYuan <ibireme@gmail.com> |
3 | | |
4 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
5 | | of this software and associated documentation files (the "Software"), to deal |
6 | | in the Software without restriction, including without limitation the rights |
7 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
8 | | copies of the Software, and to permit persons to whom the Software is |
9 | | furnished to do so, subject to the following conditions: |
10 | | |
11 | | The above copyright notice and this permission notice shall be included in all |
12 | | copies or substantial portions of the Software. |
13 | | |
14 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
17 | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
18 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
19 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
20 | | SOFTWARE. |
21 | | *============================================================================*/ |
22 | | |
23 | | #include "yyjson.h" |
24 | | |
25 | | |
26 | | |
27 | | /*============================================================================== |
28 | | * MARK: - Warning Suppress (Private) |
29 | | *============================================================================*/ |
30 | | |
31 | | #if defined(__clang__) |
32 | | # pragma clang diagnostic ignored "-Wunused-function" |
33 | | # pragma clang diagnostic ignored "-Wunused-parameter" |
34 | | # pragma clang diagnostic ignored "-Wunused-label" |
35 | | # pragma clang diagnostic ignored "-Wunused-macros" |
36 | | # pragma clang diagnostic ignored "-Wunused-variable" |
37 | | #elif YYJSON_IS_REAL_GCC && yyjson_gcc_available(4, 2, 0) |
38 | | # pragma GCC diagnostic ignored "-Wunused-function" |
39 | | # pragma GCC diagnostic ignored "-Wunused-parameter" |
40 | | # pragma GCC diagnostic ignored "-Wunused-label" |
41 | | # pragma GCC diagnostic ignored "-Wunused-macros" |
42 | | # pragma GCC diagnostic ignored "-Wunused-variable" |
43 | | #elif defined(_MSC_VER) |
44 | | # pragma warning(disable:4100) /* unreferenced formal parameter */ |
45 | | # pragma warning(disable:4101) /* unreferenced variable */ |
46 | | # pragma warning(disable:4102) /* unreferenced label */ |
47 | | # pragma warning(disable:4127) /* conditional expression is constant */ |
48 | | # pragma warning(disable:4702) /* unreachable code */ |
49 | | # pragma warning(disable:4706) /* assignment within conditional expression */ |
50 | | #endif |
51 | | |
52 | | |
53 | | |
54 | | /*============================================================================== |
55 | | * MARK: - Version (Public) |
56 | | *============================================================================*/ |
57 | | |
58 | 0 | uint32_t yyjson_version(void) { |
59 | 0 | return YYJSON_VERSION_HEX; |
60 | 0 | } |
61 | | |
62 | | |
63 | | |
64 | | /*============================================================================== |
65 | | * MARK: - Flags (Private) |
66 | | *============================================================================*/ |
67 | | |
68 | | /* msvc intrinsic */ |
69 | | #if YYJSON_MSC_VER >= 1400 |
70 | | # include <intrin.h> |
71 | | # if defined(_M_AMD64) || defined(_M_ARM64) |
72 | | # define MSC_HAS_BIT_SCAN_64 1 |
73 | | # pragma intrinsic(_BitScanForward64) |
74 | | # pragma intrinsic(_BitScanReverse64) |
75 | | # else |
76 | | # define MSC_HAS_BIT_SCAN_64 0 |
77 | | # endif |
78 | | # if defined(_M_AMD64) || defined(_M_ARM64) || \ |
79 | | defined(_M_IX86) || defined(_M_ARM) |
80 | | # define MSC_HAS_BIT_SCAN 1 |
81 | | # pragma intrinsic(_BitScanForward) |
82 | | # pragma intrinsic(_BitScanReverse) |
83 | | # else |
84 | | # define MSC_HAS_BIT_SCAN 0 |
85 | | # endif |
86 | | # if defined(_M_AMD64) |
87 | | # define MSC_HAS_UMUL128 1 |
88 | | # pragma intrinsic(_umul128) |
89 | | # else |
90 | | # define MSC_HAS_UMUL128 0 |
91 | | # endif |
92 | | #else |
93 | | # define MSC_HAS_BIT_SCAN_64 0 |
94 | | # define MSC_HAS_BIT_SCAN 0 |
95 | | # define MSC_HAS_UMUL128 0 |
96 | | #endif |
97 | | |
98 | | /* gcc builtin */ |
99 | | #if yyjson_has_builtin(__builtin_clzll) || yyjson_gcc_available(3, 4, 0) |
100 | | # define GCC_HAS_CLZLL 1 |
101 | | #else |
102 | | # define GCC_HAS_CLZLL 0 |
103 | | #endif |
104 | | |
105 | | #if yyjson_has_builtin(__builtin_ctzll) || yyjson_gcc_available(3, 4, 0) |
106 | | # define GCC_HAS_CTZLL 1 |
107 | | #else |
108 | | # define GCC_HAS_CTZLL 0 |
109 | | #endif |
110 | | |
111 | | /* int128 type */ |
112 | | #ifndef YYJSON_HAS_INT128 |
113 | | # if defined(__SIZEOF_INT128__) && (__SIZEOF_INT128__ == 16) && \ |
114 | | (defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER)) && \ |
115 | | (!defined(__EMSCRIPTEN__) && !defined(__wasm__)) |
116 | | # define YYJSON_HAS_INT128 1 |
117 | | # else |
118 | | # define YYJSON_HAS_INT128 0 |
119 | | # endif |
120 | | #endif |
121 | | |
122 | | /* IEEE 754 floating-point binary representation */ |
123 | | #ifndef YYJSON_HAS_IEEE_754 |
124 | | # if defined(__STDC_IEC_559__) || defined(__STDC_IEC_60559_BFP__) |
125 | | # define YYJSON_HAS_IEEE_754 1 |
126 | | # elif FLT_RADIX == 2 && \ |
127 | | FLT_MANT_DIG == 24 && FLT_DIG == 6 && \ |
128 | | FLT_MIN_EXP == -125 && FLT_MAX_EXP == 128 && \ |
129 | | FLT_MIN_10_EXP == -37 && FLT_MAX_10_EXP == 38 && \ |
130 | | DBL_MANT_DIG == 53 && DBL_DIG == 15 && \ |
131 | | DBL_MIN_EXP == -1021 && DBL_MAX_EXP == 1024 && \ |
132 | | DBL_MIN_10_EXP == -307 && DBL_MAX_10_EXP == 308 |
133 | | # define YYJSON_HAS_IEEE_754 1 |
134 | | # else |
135 | | # define YYJSON_HAS_IEEE_754 0 |
136 | | # undef YYJSON_DISABLE_FAST_FP_CONV |
137 | | # define YYJSON_DISABLE_FAST_FP_CONV 1 |
138 | | # endif |
139 | | #endif |
140 | | |
141 | | #if YYJSON_DISABLE_FAST_FP_CONV && YYJSON_FREESTANDING |
142 | | # error DISABLE_FAST_FP_CONV and FREESTANDING cannot be used together |
143 | | #endif |
144 | | |
145 | | /* Inf and NaN */ |
146 | | #ifndef INFINITY |
147 | | # ifndef HUGE_VAL |
148 | | # define INFINITY ((double)(1.0 / 0.0)) |
149 | | # else |
150 | | # define INFINITY HUGE_VAL |
151 | | # endif |
152 | | #endif |
153 | | #ifndef NAN |
154 | | # define NAN ((double)(0.0 / 0.0)) |
155 | | #endif |
156 | | |
157 | | /* |
158 | | Correct rounding in double number computations. |
159 | | |
160 | | On the x86 architecture, some compilers may use x87 FPU instructions for |
161 | | floating-point arithmetic. The x87 FPU loads all floating-point numbers as |
162 | | 80-bit double-extended precision internally, then rounds the result to the |
163 | | original precision, which may produce inaccurate results. For a more detailed |
164 | | explanation, see the paper: https://arxiv.org/abs/cs/0701192 |
165 | | |
166 | | Here are some examples of double precision calculation error: |
167 | | |
168 | | 2877.0 / 1e6 == 0.002877, but x87 returns 0.0028770000000000002 |
169 | | 43683.0 * 1e21 == 4.3683e25, but x87 returns 4.3683000000000004e25 |
170 | | |
171 | | Here are some examples of compiler flags to generate x87 instructions on x86: |
172 | | |
173 | | clang -m32 -mno-sse |
174 | | gcc/icc -m32 -mfpmath=387 |
175 | | msvc /arch:SSE or /arch:IA32 |
176 | | |
177 | | If we are sure that there's no similar error described above, we can define the |
178 | | YYJSON_DOUBLE_MATH_CORRECT as 1 to enable the fast path calculation. This is |
179 | | not an accurate detection; it just tries to avoid the error at compile-time. |
180 | | An accurate detection can be done at run-time: |
181 | | |
182 | | bool is_double_math_correct(void) { |
183 | | volatile double r = 43683.0; |
184 | | r *= 1e21; |
185 | | return r == 4.3683e25; |
186 | | } |
187 | | |
188 | | See also: utils.h in https://github.com/google/double-conversion/ |
189 | | */ |
190 | | #if !defined(FLT_EVAL_METHOD) && defined(__FLT_EVAL_METHOD__) |
191 | | # define FLT_EVAL_METHOD __FLT_EVAL_METHOD__ |
192 | | #endif |
193 | | |
194 | | #if defined(FLT_EVAL_METHOD) && FLT_EVAL_METHOD != 0 && FLT_EVAL_METHOD != 1 |
195 | | # define YYJSON_DOUBLE_MATH_CORRECT 0 |
196 | | #elif defined(i386) || defined(__i386) || defined(__i386__) || \ |
197 | | defined(_X86_) || defined(__X86__) || defined(_M_IX86) || \ |
198 | | defined(__I86__) || defined(__IA32__) || defined(__THW_INTEL) |
199 | | # if (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP == 2) || \ |
200 | | (defined(__SSE2_MATH__) && __SSE2_MATH__) |
201 | | # define YYJSON_DOUBLE_MATH_CORRECT 1 |
202 | | # else |
203 | | # define YYJSON_DOUBLE_MATH_CORRECT 0 |
204 | | # endif |
205 | | #elif defined(__mc68000__) || defined(__pnacl__) || defined(__native_client__) |
206 | | # define YYJSON_DOUBLE_MATH_CORRECT 0 |
207 | | #else |
208 | | # define YYJSON_DOUBLE_MATH_CORRECT 1 |
209 | | #endif |
210 | | |
211 | | /* |
212 | | Detect the endianness at compile-time. |
213 | | YYJSON_ENDIAN == YYJSON_BIG_ENDIAN |
214 | | YYJSON_ENDIAN == YYJSON_LITTLE_ENDIAN |
215 | | */ |
216 | | #define YYJSON_BIG_ENDIAN 4321 |
217 | | #define YYJSON_LITTLE_ENDIAN 1234 |
218 | | |
219 | | #if yyjson_has_include(<sys/types.h>) |
220 | | # include <sys/types.h> /* POSIX */ |
221 | | #endif |
222 | | #if yyjson_has_include(<endian.h>) |
223 | | # include <endian.h> /* Linux */ |
224 | | #elif yyjson_has_include(<sys/endian.h>) |
225 | | # include <sys/endian.h> /* BSD, Android */ |
226 | | #elif yyjson_has_include(<machine/endian.h>) |
227 | | # include <machine/endian.h> /* BSD, Darwin */ |
228 | | #endif |
229 | | |
230 | | #if defined(BYTE_ORDER) && BYTE_ORDER |
231 | | # if defined(BIG_ENDIAN) && (BYTE_ORDER == BIG_ENDIAN) |
232 | | # define YYJSON_ENDIAN YYJSON_BIG_ENDIAN |
233 | | # elif defined(LITTLE_ENDIAN) && (BYTE_ORDER == LITTLE_ENDIAN) |
234 | | # define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN |
235 | | # endif |
236 | | #elif defined(__BYTE_ORDER) && __BYTE_ORDER |
237 | | # if defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN) |
238 | | # define YYJSON_ENDIAN YYJSON_BIG_ENDIAN |
239 | | # elif defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN) |
240 | | # define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN |
241 | | # endif |
242 | | #elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ |
243 | | # if defined(__ORDER_BIG_ENDIAN__) && \ |
244 | | (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) |
245 | | # define YYJSON_ENDIAN YYJSON_BIG_ENDIAN |
246 | | # elif defined(__ORDER_LITTLE_ENDIAN__) && \ |
247 | | (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) |
248 | | # define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN |
249 | | # endif |
250 | | #elif (defined(__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__ == 1) || \ |
251 | | defined(__i386) || defined(__i386__) || \ |
252 | | defined(_X86_) || defined(__X86__) || \ |
253 | | defined(_M_IX86) || defined(__THW_INTEL__) || \ |
254 | | defined(__x86_64) || defined(__x86_64__) || \ |
255 | | defined(__amd64) || defined(__amd64__) || \ |
256 | | defined(_M_AMD64) || defined(_M_X64) || \ |
257 | | defined(_M_ARM) || defined(_M_ARM64) || \ |
258 | | defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \ |
259 | | defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || \ |
260 | | defined(__EMSCRIPTEN__) || defined(__wasm__) || \ |
261 | | defined(__loongarch__) |
262 | | # define YYJSON_ENDIAN YYJSON_LITTLE_ENDIAN |
263 | | #elif (defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ == 1) || \ |
264 | | defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \ |
265 | | defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) || \ |
266 | | defined(__or1k__) || defined(__OR1K__) |
267 | | # define YYJSON_ENDIAN YYJSON_BIG_ENDIAN |
268 | | #else |
269 | | # define YYJSON_ENDIAN 0 /* unknown endian, detect at run-time */ |
270 | | #endif |
271 | | |
272 | | /* |
273 | | This macro controls how yyjson handles unaligned memory accesses. |
274 | | |
275 | | By default, yyjson uses `memcpy()` for memory copying. This allows the compiler |
276 | | to optimize the code and emit unaligned memory access instructions when |
277 | | supported by the target architecture. |
278 | | |
279 | | However, on some older compilers or architectures where `memcpy()` is not |
280 | | well-optimized and may result in unnecessary function calls, defining this |
281 | | macro as 1 may help. In such cases, yyjson switches to manual byte-by-byte |
282 | | access, which can potentially improve performance. |
283 | | |
284 | | An example of the generated assembly code for ARM can be found here: |
285 | | https://godbolt.org/z/334jjhxPT |
286 | | |
287 | | This flag is already enabled for common architectures in the following code, |
288 | | so manual configuration is usually unnecessary. If unsure, you can check the |
289 | | generated assembly or run benchmarks to make an informed decision. |
290 | | */ |
291 | | #ifndef YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
292 | | # if defined(__ia64) || defined(_IA64) || defined(__IA64__) || \ |
293 | | defined(__ia64__) || defined(_M_IA64) || defined(__itanium__) |
294 | | # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* Itanium */ |
295 | | # elif (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) && \ |
296 | | (defined(__GNUC__) || defined(__clang__)) && \ |
297 | | (!defined(__ARM_FEATURE_UNALIGNED) || !__ARM_FEATURE_UNALIGNED) |
298 | | # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* ARM */ |
299 | | # elif defined(__sparc) || defined(__sparc__) |
300 | | # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* SPARC */ |
301 | | # elif defined(__mips) || defined(__mips__) || defined(__MIPS__) |
302 | | # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* MIPS */ |
303 | | # elif defined(__m68k__) || defined(M68000) |
304 | | # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 1 /* M68K */ |
305 | | # else |
306 | | # define YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS 0 |
307 | | # endif |
308 | | #endif |
309 | | |
310 | | /* |
311 | | Estimated initial ratio of the JSON data (data_size / value_count). |
312 | | For example: |
313 | | |
314 | | data: {"id":12345678,"name":"Harry"} |
315 | | data_size: 30 |
316 | | value_count: 5 |
317 | | ratio: 6 |
318 | | |
319 | | yyjson uses dynamic memory with a growth factor of 1.5 when reading and writing |
320 | | JSON, the ratios below are used to determine the initial memory size. |
321 | | |
322 | | A too large ratio will waste memory, and a too small ratio will cause multiple |
323 | | memory growths and degrade performance. Currently, these ratios are generated |
324 | | with some commonly used JSON datasets. |
325 | | */ |
326 | 31.5k | #define YYJSON_READER_ESTIMATED_PRETTY_RATIO 16 |
327 | 51.1k | #define YYJSON_READER_ESTIMATED_MINIFY_RATIO 6 |
328 | 5.11k | #define YYJSON_WRITER_ESTIMATED_PRETTY_RATIO 32 |
329 | 11.1k | #define YYJSON_WRITER_ESTIMATED_MINIFY_RATIO 18 |
330 | | |
331 | | /* The initial and maximum size of the memory pool's chunk in yyjson_mut_doc. */ |
332 | 30.5k | #define YYJSON_MUT_DOC_STR_POOL_INIT_SIZE 0x100 |
333 | 30.5k | #define YYJSON_MUT_DOC_STR_POOL_MAX_SIZE 0x10000000 |
334 | 30.5k | #define YYJSON_MUT_DOC_VAL_POOL_INIT_SIZE (0x10 * sizeof(yyjson_mut_val)) |
335 | 30.5k | #define YYJSON_MUT_DOC_VAL_POOL_MAX_SIZE (0x1000000 * sizeof(yyjson_mut_val)) |
336 | | |
337 | | /* The minimum size of the dynamic allocator's chunk. */ |
338 | 0 | #define YYJSON_ALC_DYN_MIN_SIZE 0x1000 |
339 | | |
340 | | /* Default value for compile-time options. */ |
341 | | |
342 | | #ifndef YYJSON_READER_DEPTH_LIMIT |
343 | | #define YYJSON_READER_DEPTH_LIMIT 0 |
344 | | #endif |
345 | | |
346 | | /*============================================================================== |
347 | | * MARK: - Macros (Private) |
348 | | *============================================================================*/ |
349 | | |
350 | | /* Macros used for loop unrolling and other purposes. */ |
351 | | #define repeat2(x) { x x } |
352 | | #define repeat4(x) { x x x x } |
353 | | #define repeat8(x) { x x x x x x x x } |
354 | 2.44M | #define repeat16(x) { x x x x x x x x x x x x x x x x } |
355 | | |
356 | | #define repeat2_incr(x) { x(0) x(1) } |
357 | 21.2M | #define repeat4_incr(x) { x(0) x(1) x(2) x(3) } |
358 | | #define repeat8_incr(x) { x(0) x(1) x(2) x(3) x(4) x(5) x(6) x(7) } |
359 | 57.4M | #define repeat16_incr(x) { x(0) x(1) x(2) x(3) x(4) x(5) x(6) x(7) \ |
360 | 15.7M | x(8) x(9) x(10) x(11) x(12) x(13) x(14) x(15) } |
361 | 4.98M | #define repeat_in_1_18(x) { x(1) x(2) x(3) x(4) x(5) x(6) x(7) x(8) \ |
362 | 1.23M | x(9) x(10) x(11) x(12) x(13) x(14) x(15) x(16) \ |
363 | 316k | x(17) x(18) } |
364 | | |
365 | | /* Macros used to provide branch prediction information for compiler. */ |
366 | | #undef likely |
367 | 185M | #define likely(x) yyjson_likely(x) |
368 | | #undef unlikely |
369 | 4.63G | #define unlikely(x) yyjson_unlikely(x) |
370 | | |
371 | | /* Macros used to provide inline information for compiler. */ |
372 | | #undef static_inline |
373 | | #define static_inline static yyjson_inline |
374 | | #undef static_noinline |
375 | | #define static_noinline static yyjson_noinline |
376 | | |
377 | | /* Macros for min and max. */ |
378 | | #undef yyjson_min |
379 | 148k | #define yyjson_min(x, y) ((x) < (y) ? (x) : (y)) |
380 | | #undef yyjson_max |
381 | 3.73M | #define yyjson_max(x, y) ((x) > (y) ? (x) : (y)) |
382 | | |
383 | | /* Used to write u64 literal for C89 which doesn't support "ULL" suffix. */ |
384 | | #undef U64 |
385 | 9.34M | #define U64(hi, lo) ((((u64)hi##UL) << 32U) + lo##UL) |
386 | | #undef U32 |
387 | 0 | #define U32(hi) ((u32)(hi##UL)) |
388 | | |
389 | | /* Used to cast away (remove) const qualifier. */ |
390 | 233k | #define constcast yyjson_constcast |
391 | | |
392 | | /* |
393 | | Compiler barriers for single variables. |
394 | | |
395 | | These macros inform GCC that a read or write access to the given memory |
396 | | location will occur, preventing certain compiler optimizations or reordering |
397 | | around the access to 'val'. They do not emit any actual instructions. |
398 | | |
399 | | This is useful when GCC's default optimization strategies are suboptimal and |
400 | | precise control over memory access patterns is required. |
401 | | These barriers are not needed when using Clang or MSVC. |
402 | | */ |
403 | | #if YYJSON_IS_REAL_GCC |
404 | | # define gcc_load_barrier(val) __asm__ volatile(""::"m"(val)) |
405 | | # define gcc_store_barrier(val) __asm__ volatile("":"=m"(val)) |
406 | | # define gcc_full_barrier(val) __asm__ volatile("":"=m"(val):"m"(val)) |
407 | | #else |
408 | | # define gcc_load_barrier(val) |
409 | | # define gcc_store_barrier(val) |
410 | | # define gcc_full_barrier(val) |
411 | | #endif |
412 | | |
413 | | |
414 | | |
415 | | /*============================================================================== |
416 | | * MARK: - Constants (Private) |
417 | | *============================================================================*/ |
418 | | |
419 | | /* Common error messages. */ |
420 | | #define MSG_FOPEN "failed to open file" |
421 | | #define MSG_FREAD "failed to read file" |
422 | | #define MSG_FWRITE "failed to write file" |
423 | | #define MSG_FCLOSE "failed to close file" |
424 | | #define MSG_MALLOC "failed to allocate memory" |
425 | | #define MSG_CHAR_T "invalid literal, expected 'true'" |
426 | | #define MSG_CHAR_F "invalid literal, expected 'false'" |
427 | | #define MSG_CHAR_N "invalid literal, expected 'null'" |
428 | | #define MSG_CHAR "unexpected character, expected a JSON value" |
429 | | #define MSG_ARR_END "unexpected character, expected ',' or ']'" |
430 | | #define MSG_OBJ_KEY "unexpected character, expected a string key" |
431 | | #define MSG_OBJ_SEP "unexpected character, expected ':' after key" |
432 | | #define MSG_OBJ_END "unexpected character, expected ',' or '}'" |
433 | | #define MSG_GARBAGE "unexpected content after document" |
434 | 41.0k | #define MSG_NOT_END "unexpected end of data" |
435 | | #define MSG_COMMENT "unclosed multiline comment" |
436 | | #define MSG_COMMA "trailing comma is not allowed" |
437 | | #define MSG_NAN_INF "nan or inf number is not allowed" |
438 | | #define MSG_ERR_TYPE "invalid JSON value type" |
439 | 11 | #define MSG_ERR_BOM "UTF-8 byte order mark (BOM) is not supported" |
440 | | #define MSG_ERR_UTF8 "invalid utf-8 encoding in string" |
441 | 48 | #define MSG_ERR_UTF16 "UTF-16 encoding is not supported" |
442 | 21 | #define MSG_ERR_UTF32 "UTF-32 encoding is not supported" |
443 | | #define MSG_DEPTH "depth limit exceeded" |
444 | | |
445 | | /* U64 constant values */ |
446 | | #undef U64_MAX |
447 | 34.8k | #define U64_MAX U64(0xFFFFFFFF, 0xFFFFFFFF) |
448 | | #undef I64_MAX |
449 | | #define I64_MAX U64(0x7FFFFFFF, 0xFFFFFFFF) |
450 | | #undef USIZE_MAX |
451 | 170k | #define USIZE_MAX ((usize)(~(usize)0)) |
452 | | |
453 | | /* Maximum number of digits for reading u32/u64/usize safety (not overflow). */ |
454 | | #undef U32_SAFE_DIG |
455 | | #define U32_SAFE_DIG 9 /* u32 max is 4294967295, 10 digits */ |
456 | | #undef U64_SAFE_DIG |
457 | 11.0M | #define U64_SAFE_DIG 19 /* u64 max is 18446744073709551615, 20 digits */ |
458 | | #undef USIZE_SAFE_DIG |
459 | | #define USIZE_SAFE_DIG (sizeof(usize) == 8 ? U64_SAFE_DIG : U32_SAFE_DIG) |
460 | | |
461 | | /* Inf bits (positive) */ |
462 | 7.88k | #define F64_BITS_INF U64(0x7FF00000, 0x00000000) |
463 | | |
464 | | /* NaN bits (quiet NaN, no payload, no sign) */ |
465 | | #if defined(__hppa__) || (defined(__mips__) && !defined(__mips_nan2008)) |
466 | | #define F64_BITS_NAN U64(0x7FF7FFFF, 0xFFFFFFFF) |
467 | | #else |
468 | 6.43k | #define F64_BITS_NAN U64(0x7FF80000, 0x00000000) |
469 | | #endif |
470 | | |
471 | | /* maximum significant digits count in decimal when reading double number */ |
472 | 53.1k | #define F64_MAX_DEC_DIG 768 |
473 | | |
474 | | /* maximum decimal power of double number (1.7976931348623157e308) */ |
475 | | #define F64_MAX_DEC_EXP 308 |
476 | | |
477 | | /* minimum decimal power of double number (4.9406564584124654e-324) */ |
478 | | #define F64_MIN_DEC_EXP (-324) |
479 | | |
480 | | /* maximum binary power of double number */ |
481 | | #define F64_MAX_BIN_EXP 1024 |
482 | | |
483 | | /* minimum binary power of double number */ |
484 | 30.2k | #define F64_MIN_BIN_EXP (-1021) |
485 | | |
486 | | /* float/double number bits */ |
487 | 0 | #define F32_BITS 32 |
488 | 4.95M | #define F64_BITS 64 |
489 | | |
490 | | /* float/double number exponent part bits */ |
491 | | #define F32_EXP_BITS 8 |
492 | | #define F64_EXP_BITS 11 |
493 | | |
494 | | /* float/double number significand part bits */ |
495 | 0 | #define F32_SIG_BITS 23 |
496 | 17.0M | #define F64_SIG_BITS 52 |
497 | | |
498 | | /* float/double number significand part bits (with 1 hidden bit) */ |
499 | | #define F32_SIG_FULL_BITS 24 |
500 | 699k | #define F64_SIG_FULL_BITS 53 |
501 | | |
502 | | /* float/double number significand bit mask */ |
503 | 0 | #define F32_SIG_MASK U32(0x007FFFFF) |
504 | 4.72M | #define F64_SIG_MASK U64(0x000FFFFF, 0xFFFFFFFF) |
505 | | |
506 | | /* float/double number exponent bit mask */ |
507 | 0 | #define F32_EXP_MASK U32(0x7F800000) |
508 | 4.56M | #define F64_EXP_MASK U64(0x7FF00000, 0x00000000) |
509 | | |
510 | | /* float/double number exponent bias */ |
511 | 0 | #define F32_EXP_BIAS 127 |
512 | 4.89M | #define F64_EXP_BIAS 1023 |
513 | | |
514 | | /* float/double number significant digits count in decimal */ |
515 | | #define F32_DEC_DIG 9 |
516 | | #define F64_DEC_DIG 17 |
517 | | |
518 | | /* buffer length required for float/double number writer */ |
519 | | #define FP_BUF_LEN 40 |
520 | | |
521 | | /* maximum length of a number in incremental parsing */ |
522 | | #define INCR_NUM_MAX_LEN 1024 |
523 | | |
524 | | |
525 | | |
526 | | /*============================================================================== |
527 | | * MARK: - Types (Private) |
528 | | *============================================================================*/ |
529 | | |
530 | | /** Type aliases for primitive types. */ |
531 | | typedef float f32; |
532 | | typedef double f64; |
533 | | typedef int8_t i8; |
534 | | typedef uint8_t u8; |
535 | | typedef int16_t i16; |
536 | | typedef uint16_t u16; |
537 | | typedef int32_t i32; |
538 | | typedef uint32_t u32; |
539 | | typedef int64_t i64; |
540 | | typedef uint64_t u64; |
541 | | typedef size_t usize; |
542 | | |
543 | | /** 128-bit integer, used by floating-point number reader and writer. */ |
544 | | #if YYJSON_HAS_INT128 |
545 | | __extension__ typedef __int128 i128; |
546 | | __extension__ typedef unsigned __int128 u128; |
547 | | #endif |
548 | | |
549 | | /** 16/32/64-bit vector */ |
550 | | typedef struct v16 { char c[2]; } v16; |
551 | | typedef struct v32 { char c[4]; } v32; |
552 | | typedef struct v64 { char c[8]; } v64; |
553 | | |
554 | | /** 16/32/64-bit vector union */ |
555 | | typedef union v16_uni { v16 v; u16 u; } v16_uni; |
556 | | typedef union v32_uni { v32 v; u32 u; } v32_uni; |
557 | | typedef union v64_uni { v64 v; u64 u; } v64_uni; |
558 | | |
559 | | |
560 | | |
561 | | /*============================================================================== |
562 | | * MARK: - Load/Store Utils (Private) |
563 | | *============================================================================*/ |
564 | | |
565 | | #define byte_move_idx(x) ((char *)dst)[x] = ((const char *)src)[x]; |
566 | | #define byte_move_src(x) ((char *)tmp)[x] = ((const char *)src)[x]; |
567 | | #define byte_move_dst(x) ((char *)dst)[x] = ((const char *)tmp)[x]; |
568 | | |
569 | | /** Same as `memcpy(dst, src, 2)`, no overlap. */ |
570 | 759M | static_inline void byte_copy_2(void *dst, const void *src) { |
571 | 759M | #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
572 | 759M | memcpy(dst, src, 2); |
573 | | #else |
574 | | repeat2_incr(byte_move_idx) |
575 | | #endif |
576 | 759M | } |
577 | | |
578 | | /** Same as `memcpy(dst, src, 4)`, no overlap. */ |
579 | 7.88G | static_inline void byte_copy_4(void *dst, const void *src) { |
580 | 7.88G | #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
581 | 7.88G | memcpy(dst, src, 4); |
582 | | #else |
583 | | repeat4_incr(byte_move_idx) |
584 | | #endif |
585 | 7.88G | } |
586 | | |
587 | | /** Same as `memcpy(dst, src, 8)`, no overlap. */ |
588 | 672k | static_inline void byte_copy_8(void *dst, const void *src) { |
589 | 672k | #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
590 | 672k | memcpy(dst, src, 8); |
591 | | #else |
592 | | repeat8_incr(byte_move_idx) |
593 | | #endif |
594 | 672k | } |
595 | | |
596 | | /** Same as `memcpy(dst, src, 16)`, no overlap. */ |
597 | 30.4M | static_inline void byte_copy_16(void *dst, const void *src) { |
598 | 30.4M | #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
599 | 30.4M | memcpy(dst, src, 16); |
600 | | #else |
601 | | repeat16_incr(byte_move_idx) |
602 | | #endif |
603 | 30.4M | } |
604 | | |
605 | | /** Same as `memmove(dst, src, 2)`, allows overlap. */ |
606 | 870k | static_inline void byte_move_2(void *dst, const void *src) { |
607 | 870k | #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
608 | 870k | u16 tmp; |
609 | 870k | memcpy(&tmp, src, 2); |
610 | 870k | memcpy(dst, &tmp, 2); |
611 | | #else |
612 | | char tmp[2]; |
613 | | repeat2_incr(byte_move_src) |
614 | | repeat2_incr(byte_move_dst) |
615 | | #endif |
616 | 870k | } |
617 | | |
618 | | /** Same as `memmove(dst, src, 4)`, allows overlap. */ |
619 | 616k | static_inline void byte_move_4(void *dst, const void *src) { |
620 | 616k | #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
621 | 616k | u32 tmp; |
622 | 616k | memcpy(&tmp, src, 4); |
623 | 616k | memcpy(dst, &tmp, 4); |
624 | | #else |
625 | | char tmp[4]; |
626 | | repeat4_incr(byte_move_src) |
627 | | repeat4_incr(byte_move_dst) |
628 | | #endif |
629 | 616k | } |
630 | | |
631 | | /** Same as `memmove(dst, src, 8)`, allows overlap. */ |
632 | 660k | static_inline void byte_move_8(void *dst, const void *src) { |
633 | 660k | #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
634 | 660k | u64 tmp; |
635 | 660k | memcpy(&tmp, src, 8); |
636 | 660k | memcpy(dst, &tmp, 8); |
637 | | #else |
638 | | char tmp[8]; |
639 | | repeat8_incr(byte_move_src) |
640 | | repeat8_incr(byte_move_dst) |
641 | | #endif |
642 | 660k | } |
643 | | |
644 | | /** Same as `memmove(dst, src, 16)`, allows overlap. */ |
645 | 2.58M | static_inline void byte_move_16(void *dst, const void *src) { |
646 | 2.58M | #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
647 | 2.58M | char *pdst = (char *)dst; |
648 | 2.58M | const char *psrc = (const char *)src; |
649 | 2.58M | u64 tmp1, tmp2; |
650 | 2.58M | memcpy(&tmp1, psrc, 8); |
651 | 2.58M | memcpy(&tmp2, psrc + 8, 8); |
652 | 2.58M | memcpy(pdst, &tmp1, 8); |
653 | 2.58M | memcpy(pdst + 8, &tmp2, 8); |
654 | | #else |
655 | | char tmp[16]; |
656 | | repeat16_incr(byte_move_src) |
657 | | repeat16_incr(byte_move_dst) |
658 | | #endif |
659 | 2.58M | } |
660 | | |
661 | | /** Same as `memmove(dst, src, n)`, but only `dst <= src` and `n <= 16`. */ |
662 | 1.82M | static_inline void byte_move_forward(void *dst, void *src, usize n) { |
663 | 1.82M | char *d = (char *)dst, *s = (char *)src; |
664 | 1.82M | n += (n % 2); /* round up to even */ |
665 | 1.82M | if (n == 16) { byte_move_16(d, s); return; } |
666 | 1.71M | if (n >= 8) { byte_move_8(d, s); n -= 8; d += 8; s += 8; } |
667 | 1.71M | if (n >= 4) { byte_move_4(d, s); n -= 4; d += 4; s += 4; } |
668 | 1.71M | if (n >= 2) { byte_move_2(d, s); } |
669 | 1.71M | } |
670 | | |
671 | | /** Same as `memcmp(buf, pat, 2) == 0`. */ |
672 | 2.96M | static_inline bool byte_match_2(void *buf, const char *pat) { |
673 | 2.96M | #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
674 | 2.96M | v16_uni u1, u2; |
675 | 2.96M | memcpy(&u1, buf, 2); |
676 | 2.96M | memcpy(&u2, pat, 2); |
677 | 2.96M | return u1.u == u2.u; |
678 | | #else |
679 | | return ((char *)buf)[0] == ((const char *)pat)[0] && |
680 | | ((char *)buf)[1] == ((const char *)pat)[1]; |
681 | | #endif |
682 | 2.96M | } |
683 | | |
684 | | /** Same as `memcmp(buf, pat, 4) == 0`. */ |
685 | 253k | static_inline bool byte_match_4(void *buf, const char *pat) { |
686 | 253k | #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
687 | 253k | v32_uni u1, u2; |
688 | 253k | memcpy(&u1, buf, 4); |
689 | 253k | memcpy(&u2, pat, 4); |
690 | 253k | return u1.u == u2.u; |
691 | | #else |
692 | | return ((char *)buf)[0] == ((const char *)pat)[0] && |
693 | | ((char *)buf)[1] == ((const char *)pat)[1] && |
694 | | ((char *)buf)[2] == ((const char *)pat)[2] && |
695 | | ((char *)buf)[3] == ((const char *)pat)[3]; |
696 | | #endif |
697 | 253k | } |
698 | | |
699 | | /** Loads 2 bytes from `src` as a u16 (native-endian). */ |
700 | 1.44M | static_inline u16 byte_load_2(const void *src) { |
701 | 1.44M | v16_uni uni; |
702 | 1.44M | #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
703 | 1.44M | memcpy(&uni, src, 2); |
704 | | #else |
705 | | uni.v.c[0] = ((const char *)src)[0]; |
706 | | uni.v.c[1] = ((const char *)src)[1]; |
707 | | #endif |
708 | 1.44M | return uni.u; |
709 | 1.44M | } |
710 | | |
711 | | /** Loads 3 bytes from `src` as a u32 (native-endian). */ |
712 | 60.8k | static_inline u32 byte_load_3(const void *src) { |
713 | 60.8k | v32_uni uni; |
714 | 60.8k | #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
715 | 60.8k | memcpy(&uni, src, 2); |
716 | 60.8k | uni.v.c[2] = ((const char *)src)[2]; |
717 | 60.8k | uni.v.c[3] = 0; |
718 | | #else |
719 | | uni.v.c[0] = ((const char *)src)[0]; |
720 | | uni.v.c[1] = ((const char *)src)[1]; |
721 | | uni.v.c[2] = ((const char *)src)[2]; |
722 | | uni.v.c[3] = 0; |
723 | | #endif |
724 | 60.8k | return uni.u; |
725 | 60.8k | } |
726 | | |
727 | | /** Loads 4 bytes from `src` as a u32 (native-endian). */ |
728 | 5.68M | static_inline u32 byte_load_4(const void *src) { |
729 | 5.68M | v32_uni uni; |
730 | 5.68M | #if !YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS |
731 | 5.68M | memcpy(&uni, src, 4); |
732 | | #else |
733 | | uni.v.c[0] = ((const char *)src)[0]; |
734 | | uni.v.c[1] = ((const char *)src)[1]; |
735 | | uni.v.c[2] = ((const char *)src)[2]; |
736 | | uni.v.c[3] = ((const char *)src)[3]; |
737 | | #endif |
738 | 5.68M | return uni.u; |
739 | 5.68M | } |
740 | | |
741 | | |
742 | | |
743 | | /*============================================================================== |
744 | | * MARK: - Character Utils (Private) |
745 | | * These lookup tables were generated by `misc/make_tables.c`. |
746 | | *============================================================================*/ |
747 | | |
748 | | /* char_table1 */ |
749 | 32.2M | #define CHAR_TYPE_ASCII (1 << 0) /* Except: ["\], [0x00-0x1F, 0x80-0xFF] */ |
750 | 490k | #define CHAR_TYPE_ASCII_SQ (1 << 1) /* Except: ['\], [0x00-0x1F, 0x80-0xFF] */ |
751 | 4.72M | #define CHAR_TYPE_SPACE (1 << 2) /* Whitespace: [ \t\n\r] */ |
752 | 4.87M | #define CHAR_TYPE_SPACE_EXT (1 << 3) /* Whitespace: [ \t\n\r\v\f], JSON5 */ |
753 | 4.49M | #define CHAR_TYPE_NUM (1 << 4) /* Number: [.-+0-9] */ |
754 | 995k | #define CHAR_TYPE_COMMENT (1 << 5) /* Comment: [/] */ |
755 | | |
756 | | /* char_table2 */ |
757 | 22.6k | #define CHAR_TYPE_EOL (1 << 0) /* End of line: [\r\n] */ |
758 | 34.7k | #define CHAR_TYPE_EOL_EXT (1 << 1) /* End of line: [\r\n], JSON5 */ |
759 | 25.5k | #define CHAR_TYPE_ID_START (1 << 2) /* ID start: [_$A-Za-z\], U+0080+ */ |
760 | 28.1k | #define CHAR_TYPE_ID_NEXT (1 << 3) /* ID next: [_$A-Za-z0-9\], U+0080+ */ |
761 | 216k | #define CHAR_TYPE_ID_ASCII (1 << 4) /* ID next ASCII: [_$A-Za-z0-9] */ |
762 | | |
763 | | /* char_table3 */ |
764 | 241k | #define CHAR_TYPE_SIGN (1 << 0) /* [-+] */ |
765 | 11.2M | #define CHAR_TYPE_DIGIT (1 << 1) /* [0-9] */ |
766 | 3.44M | #define CHAR_TYPE_NONZERO (1 << 2) /* [1-9] */ |
767 | 4.72M | #define CHAR_TYPE_EXP (1 << 3) /* [eE] */ |
768 | 3.63M | #define CHAR_TYPE_DOT (1 << 4) /* [.] */ |
769 | | |
770 | | static const u8 char_table1[256] = { |
771 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
772 | | 0x00, 0x0C, 0x0C, 0x08, 0x08, 0x0C, 0x00, 0x00, |
773 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
774 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
775 | | 0x0F, 0x03, 0x02, 0x03, 0x03, 0x03, 0x03, 0x01, |
776 | | 0x03, 0x03, 0x03, 0x13, 0x03, 0x13, 0x13, 0x23, |
777 | | 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, |
778 | | 0x13, 0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, |
779 | | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, |
780 | | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, |
781 | | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, |
782 | | 0x03, 0x03, 0x03, 0x03, 0x00, 0x03, 0x03, 0x03, |
783 | | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, |
784 | | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, |
785 | | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, |
786 | | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, |
787 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
788 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
789 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
790 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
791 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
792 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
793 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
794 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
795 | | 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, |
796 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
797 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
798 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
799 | | 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, |
800 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, |
801 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
802 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
803 | | }; |
804 | | |
805 | | static const u8 char_table2[256] = { |
806 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
807 | | 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, |
808 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
809 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
810 | | 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, |
811 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
812 | | 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, |
813 | | 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
814 | | 0x00, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, |
815 | | 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, |
816 | | 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, |
817 | | 0x1C, 0x1C, 0x1C, 0x00, 0x0C, 0x00, 0x00, 0x1C, |
818 | | 0x00, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, |
819 | | 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, |
820 | | 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, |
821 | | 0x1C, 0x1C, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, |
822 | | 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
823 | | 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
824 | | 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
825 | | 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
826 | | 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
827 | | 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
828 | | 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
829 | | 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
830 | | 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
831 | | 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
832 | | 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
833 | | 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
834 | | 0x0C, 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
835 | | 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
836 | | 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
837 | | 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C |
838 | | }; |
839 | | |
840 | | static const u8 char_table3[256] = { |
841 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
842 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
843 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
844 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
845 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
846 | | 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x10, 0x00, |
847 | | 0x02, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, |
848 | | 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
849 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, |
850 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
851 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
852 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
853 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, |
854 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
855 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
856 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
857 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
858 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
859 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
860 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
861 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
862 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
863 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
864 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
865 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
866 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
867 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
868 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
869 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
870 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
871 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
872 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
873 | | }; |
874 | | |
875 | | /** Match a whitespace: [ \t\n\r]. */ |
876 | 4.72M | static_inline bool char_is_space(u8 c) { |
877 | 4.72M | return !!(char_table1[c] & CHAR_TYPE_SPACE); |
878 | 4.72M | } |
879 | | |
880 | | /** Match an extended whitespace: [ \t\n\r\\v\\f], JSON5 whitespace. */ |
881 | 3.88M | static_inline bool char_is_space_ext(u8 c) { |
882 | 3.88M | return !!(char_table1[c] & CHAR_TYPE_SPACE_EXT); |
883 | 3.88M | } |
884 | | |
885 | | /** Match a JSON number: [.-+0-9]. */ |
886 | 4.49M | static_inline bool char_is_num(u8 c) { |
887 | 4.49M | return !!(char_table1[c] & CHAR_TYPE_NUM); |
888 | 4.49M | } |
889 | | |
890 | | /** Match an ASCII character in string: ["\], [0x00-0x1F, 0x80-0xFF]. */ |
891 | 32.2M | static_inline bool char_is_ascii_skip(u8 c) { |
892 | 32.2M | return !!(char_table1[c] & CHAR_TYPE_ASCII); |
893 | 32.2M | } |
894 | | |
895 | | /** Match an ASCII character single-quoted: ['\], [0x00-0x1F, 0x80-0xFF]. */ |
896 | 490k | static_inline bool char_is_ascii_skip_sq(u8 c) { |
897 | 490k | return !!(char_table1[c] & CHAR_TYPE_ASCII_SQ); |
898 | 490k | } |
899 | | |
900 | | /** Match a trivia character: extended whitespace or comment. */ |
901 | 995k | static_inline bool char_is_trivia(u8 c) { |
902 | 995k | return !!(char_table1[c] & (CHAR_TYPE_SPACE_EXT | CHAR_TYPE_COMMENT)); |
903 | 995k | } |
904 | | |
905 | | /** Match a line end character: [\r\n]. */ |
906 | 22.6k | static_inline bool char_is_eol(u8 c) { |
907 | 22.6k | return !!(char_table2[c] & CHAR_TYPE_EOL); |
908 | 22.6k | } |
909 | | |
910 | | /** Match an extended line end character: [\r\n], JSON5 line terminator. */ |
911 | 34.7k | static_inline bool char_is_eol_ext(u8 c) { |
912 | 34.7k | return !!(char_table2[c] & CHAR_TYPE_EOL_EXT); |
913 | 34.7k | } |
914 | | |
915 | | /** Match an identifier name start: [_$A-Za-z\], U+0080+. */ |
916 | 25.5k | static_inline bool char_is_id_start(u8 c) { |
917 | 25.5k | return !!(char_table2[c] & CHAR_TYPE_ID_START); |
918 | 25.5k | } |
919 | | |
920 | | /** Match an identifier name next: [_$A-Za-z0-9\], U+0080+. */ |
921 | 28.1k | static_inline bool char_is_id_next(u8 c) { |
922 | 28.1k | return !!(char_table2[c] & CHAR_TYPE_ID_NEXT); |
923 | 28.1k | } |
924 | | |
925 | | /** Match an identifier name ASCII: [_$A-Za-z0-9]. */ |
926 | 216k | static_inline bool char_is_id_ascii(u8 c) { |
927 | 216k | return !!(char_table2[c] & CHAR_TYPE_ID_ASCII); |
928 | 216k | } |
929 | | |
930 | | /** Match a sign: [+-] */ |
931 | 241k | static_inline bool char_is_sign(u8 d) { |
932 | 241k | return !!(char_table3[d] & CHAR_TYPE_SIGN); |
933 | 241k | } |
934 | | |
935 | | /** Match a non-zero digit: [1-9] */ |
936 | 3.44M | static_inline bool char_is_nonzero(u8 d) { |
937 | 3.44M | return !!(char_table3[d] & CHAR_TYPE_NONZERO); |
938 | 3.44M | } |
939 | | |
940 | | /** Match a digit: [0-9] */ |
941 | 10.9M | static_inline bool char_is_digit(u8 d) { |
942 | 10.9M | return !!(char_table3[d] & CHAR_TYPE_DIGIT); |
943 | 10.9M | } |
944 | | |
945 | | /** Match an exponent character: [eE]. */ |
946 | 1.09M | static_inline bool char_is_exp(u8 d) { |
947 | 1.09M | return !!(char_table3[d] & CHAR_TYPE_EXP); |
948 | 1.09M | } |
949 | | |
950 | | /** Match a floating point indicator: [.eE]. */ |
951 | 3.31M | static_inline bool char_is_fp(u8 d) { |
952 | 3.31M | return !!(char_table3[d] & (CHAR_TYPE_DOT | CHAR_TYPE_EXP)); |
953 | 3.31M | } |
954 | | |
955 | | /** Match a digit or floating point indicator: [0-9.eE]. */ |
956 | 315k | static_inline bool char_is_digit_or_fp(u8 d) { |
957 | 315k | return !!(char_table3[d] & (CHAR_TYPE_DIGIT | CHAR_TYPE_DOT | |
958 | 315k | CHAR_TYPE_EXP)); |
959 | 315k | } |
960 | | |
961 | | /** Match a JSON container: `{` or `[`. */ |
962 | 266k | static_inline bool char_is_ctn(u8 c) { |
963 | 266k | return (c & 0xDF) == 0x5B; /* '[': 0x5B, '{': 0x7B */ |
964 | 266k | } |
965 | | |
966 | | /** Convert ASCII letter to lowercase; valid only for [A-Za-z]. */ |
967 | 86.0k | static_inline u8 char_to_lower(u8 c) { |
968 | 86.0k | return c | 0x20; |
969 | 86.0k | } |
970 | | |
971 | | /** Match UTF-8 byte order mask. */ |
972 | 8.58k | static_inline bool is_utf8_bom(const u8 *cur) { |
973 | 8.58k | return byte_load_3(cur) == byte_load_3("\xEF\xBB\xBF"); |
974 | 8.58k | } |
975 | | |
976 | | /** Match UTF-16 byte order mask. */ |
977 | 7.78k | static_inline bool is_utf16_bom(const u8 *cur) { |
978 | 7.78k | return byte_load_2(cur) == byte_load_2("\xFE\xFF") || |
979 | 7.75k | byte_load_2(cur) == byte_load_2("\xFF\xFE"); |
980 | 7.78k | } |
981 | | |
982 | | /** Match UTF-32 byte order mask, need length check to avoid zero padding. */ |
983 | 3.22k | static_inline bool is_utf32_bom(const u8 *cur) { |
984 | 3.22k | return byte_load_4(cur) == byte_load_4("\x00\x00\xFE\xFF") || |
985 | 3.20k | byte_load_4(cur) == byte_load_4("\xFF\xFE\x00\x00"); |
986 | 3.22k | } |
987 | | |
988 | | /** Get the extended line end length. Used with `char_is_eol_ext`. */ |
989 | 1.90k | static_inline usize ext_eol_len(const u8 *cur) { |
990 | 1.90k | if (cur[0] < 0x80) return 1; |
991 | 899 | if (cur[1] == 0x80 && (cur[2] == 0xA8 || cur[2] == 0xA9)) return 3; |
992 | 493 | return 0; |
993 | 899 | } |
994 | | |
995 | | /** Get the extended whitespace length. Used with `char_is_space_ext`. */ |
996 | 2.01M | static_inline usize ext_space_len(const u8 *cur) { |
997 | 2.01M | if (cur[0] < 0x80) { |
998 | 2.00M | return 1; |
999 | 2.00M | } else if (byte_load_2(cur) == byte_load_2("\xC2\xA0")) { |
1000 | 934 | return 2; |
1001 | 15.3k | } else if (byte_load_2(cur) == byte_load_2("\xE2\x80")) { |
1002 | 7.57k | if (cur[2] >= 0x80 && cur[2] <= 0x8A) return 3; |
1003 | 5.22k | if (cur[2] == 0xA8 || cur[2] == 0xA9 || cur[2] == 0xAF) return 3; |
1004 | 7.76k | } else { |
1005 | 7.76k | u32 uni = byte_load_3(cur); |
1006 | 7.76k | if (uni == byte_load_3("\xE1\x9A\x80") || |
1007 | 6.42k | uni == byte_load_3("\xE2\x81\x9F") || |
1008 | 4.48k | uni == byte_load_3("\xE3\x80\x80") || |
1009 | 4.68k | uni == byte_load_3("\xEF\xBB\xBF")) return 3; |
1010 | 7.76k | } |
1011 | 3.84k | return 0; |
1012 | 2.01M | } |
1013 | | |
1014 | | |
1015 | | |
1016 | | /*============================================================================== |
1017 | | * MARK: - Hex Character Reader (Private) |
1018 | | * This function is used by JSON reader to read escaped characters. |
1019 | | *============================================================================*/ |
1020 | | |
1021 | | /** |
1022 | | This table is used to convert a 4-hex-character sequence to a number. |
1023 | | A valid hex character [0-9A-Fa-f] is mapped to its raw value [0x00, 0x0F]; |
1024 | | an invalid hex character is mapped to [0xF0]. |
1025 | | (generated with misc/make_tables.c) |
1026 | | */ |
1027 | | static const u8 hex_conv_table[256] = { |
1028 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1029 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1030 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1031 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1032 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1033 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1034 | | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
1035 | | 0x08, 0x09, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1036 | | 0xF0, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF0, |
1037 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1038 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1039 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1040 | | 0xF0, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF0, |
1041 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1042 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1043 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1044 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1045 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1046 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1047 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1048 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1049 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1050 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1051 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1052 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1053 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1054 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1055 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1056 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1057 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1058 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, |
1059 | | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0 |
1060 | | }; |
1061 | | |
1062 | | /** Load 4 hex characters to `u16`, return true on valid input. */ |
1063 | 38.6k | static_inline bool hex_load_4(const u8 *src, u16 *dst) { |
1064 | 38.6k | u16 c0 = hex_conv_table[src[0]]; |
1065 | 38.6k | u16 c1 = hex_conv_table[src[1]]; |
1066 | 38.6k | u16 c2 = hex_conv_table[src[2]]; |
1067 | 38.6k | u16 c3 = hex_conv_table[src[3]]; |
1068 | 38.6k | u16 t0 = (u16)((c0 << 8) | c2); |
1069 | 38.6k | u16 t1 = (u16)((c1 << 8) | c3); |
1070 | 38.6k | *dst = (u16)((t0 << 4) | t1); |
1071 | 38.6k | return ((t0 | t1) & (u16)0xF0F0) == 0; |
1072 | 38.6k | } |
1073 | | |
1074 | | /** Load 2 hex characters to `u8`, return true on valid input. */ |
1075 | 2.96k | static_inline bool hex_load_2(const u8 *src, u8 *dst) { |
1076 | 2.96k | u8 c0 = hex_conv_table[src[0]]; |
1077 | 2.96k | u8 c1 = hex_conv_table[src[1]]; |
1078 | 2.96k | *dst = (u8)((c0 << 4) | c1); |
1079 | 2.96k | return ((c0 | c1) & 0xF0) == 0; |
1080 | 2.96k | } |
1081 | | |
1082 | | /** Match a hexadecimal numeric character: [0-9a-fA-F]. */ |
1083 | 780 | static_inline bool char_is_hex(u8 c) { |
1084 | 780 | return hex_conv_table[c] != 0xF0; |
1085 | 780 | } |
1086 | | |
1087 | | |
1088 | | |
1089 | | /*============================================================================== |
1090 | | * MARK: - UTF8 Validation (Private) |
1091 | | * Each Unicode code point is encoded using 1 to 4 bytes in UTF-8. |
1092 | | * Validation is performed using a 4-byte mask and pattern-based approach, |
1093 | | * which requires the input data to be padded with four zero bytes at the end. |
1094 | | *============================================================================*/ |
1095 | | |
1096 | | /* Macro for concatenating four u8 into a u32 and keeping the byte order. */ |
1097 | | #if YYJSON_ENDIAN == YYJSON_LITTLE_ENDIAN |
1098 | | # define utf8_seq_def(name, a, b, c, d) \ |
1099 | | static const u32 utf8_seq_##name = 0x##d##c##b##a##UL; |
1100 | 20.9M | # define utf8_seq(name) utf8_seq_##name |
1101 | | #elif YYJSON_ENDIAN == YYJSON_BIG_ENDIAN |
1102 | | # define utf8_seq_def(name, a, b, c, d) \ |
1103 | | static const u32 utf8_seq_##name = 0x##a##b##c##d##UL; |
1104 | | # define utf8_seq(name) utf8_seq_##name |
1105 | | #else |
1106 | | # define utf8_seq_def(name, a, b, c, d) \ |
1107 | | static const v32_uni utf8_uni_##name = {{ 0x##a, 0x##b, 0x##c, 0x##d }}; |
1108 | | # define utf8_seq(name) utf8_uni_##name.u |
1109 | | #endif |
1110 | | |
1111 | | /* |
1112 | | 1-byte sequence (U+0000 to U+007F) |
1113 | | bit min [.......0] (U+0000) |
1114 | | bit max [.1111111] (U+007F) |
1115 | | bit mask [x.......] (80) |
1116 | | bit pattern [0.......] (00) |
1117 | | */ |
1118 | | utf8_seq_def(b1_mask, 80, 00, 00, 00) |
1119 | | utf8_seq_def(b1_patt, 00, 00, 00, 00) |
1120 | 1.99M | #define is_utf8_seq1(uni) ( \ |
1121 | 1.99M | ((uni & utf8_seq(b1_mask)) == utf8_seq(b1_patt)) ) |
1122 | | |
1123 | | /* |
1124 | | 2-byte sequence (U+0080 to U+07FF) |
1125 | | bit min [......10 ..000000] (U+0080) |
1126 | | bit max [...11111 ..111111] (U+07FF) |
1127 | | bit mask [xxx..... xx......] (E0 C0) |
1128 | | bit pattern [110..... 10......] (C0 80) |
1129 | | bit require [...xxxx. ........] (1E 00) |
1130 | | */ |
1131 | | utf8_seq_def(b2_mask, E0, C0, 00, 00) |
1132 | | utf8_seq_def(b2_patt, C0, 80, 00, 00) |
1133 | | utf8_seq_def(b2_requ, 1E, 00, 00, 00) |
1134 | 3.44M | #define is_utf8_seq2(uni) ( \ |
1135 | 3.44M | ((uni & utf8_seq(b2_mask)) == utf8_seq(b2_patt)) && \ |
1136 | 3.44M | ((uni & utf8_seq(b2_requ))) ) |
1137 | | |
1138 | | /* |
1139 | | 3-byte sequence (U+0800 to U+FFFF) |
1140 | | bit min [........ ..100000 ..000000] (U+0800) |
1141 | | bit max [....1111 ..111111 ..111111] (U+FFFF) |
1142 | | bit mask [xxxx.... xx...... xx......] (F0 C0 C0) |
1143 | | bit pattern [1110.... 10...... 10......] (E0 80 80) |
1144 | | bit require [....xxxx ..x..... ........] (0F 20 00) |
1145 | | |
1146 | | 3-byte invalid sequence, reserved for surrogate halves (U+D800 to U+DFFF) |
1147 | | bit min [....1101 ..100000 ..000000] (U+D800) |
1148 | | bit max [....1101 ..111111 ..111111] (U+DFFF) |
1149 | | bit mask [....xxxx ..x..... ........] (0F 20 00) |
1150 | | bit pattern [....1101 ..1..... ........] (0D 20 00) |
1151 | | */ |
1152 | | utf8_seq_def(b3_mask, F0, C0, C0, 00) |
1153 | | utf8_seq_def(b3_patt, E0, 80, 80, 00) |
1154 | | utf8_seq_def(b3_requ, 0F, 20, 00, 00) |
1155 | | utf8_seq_def(b3_erro, 0D, 20, 00, 00) |
1156 | 2.04M | #define is_utf8_seq3(uni) ( \ |
1157 | 2.04M | ((uni & utf8_seq(b3_mask)) == utf8_seq(b3_patt)) && \ |
1158 | 2.04M | ((tmp = (uni & utf8_seq(b3_requ)))) && \ |
1159 | 2.04M | ((tmp != utf8_seq(b3_erro))) ) |
1160 | | |
1161 | | /* |
1162 | | 4-byte sequence (U+10000 to U+10FFFF) |
1163 | | bit min [........ ...10000 ..000000 ..000000] (U+10000) |
1164 | | bit max [.....100 ..001111 ..111111 ..111111] (U+10FFFF) |
1165 | | bit mask [xxxxx... xx...... xx...... xx......] (F8 C0 C0 C0) |
1166 | | bit pattern [11110... 10...... 10...... 10......] (F0 80 80 80) |
1167 | | bit require [.....xxx ..xx.... ........ ........] (07 30 00 00) |
1168 | | bit require 1 [.....x.. ........ ........ ........] (04 00 00 00) |
1169 | | bit require 2 [......xx ..xx.... ........ ........] (03 30 00 00) |
1170 | | */ |
1171 | | utf8_seq_def(b4_mask, F8, C0, C0, C0) |
1172 | | utf8_seq_def(b4_patt, F0, 80, 80, 80) |
1173 | | utf8_seq_def(b4_requ, 07, 30, 00, 00) |
1174 | | utf8_seq_def(b4_req1, 04, 00, 00, 00) |
1175 | | utf8_seq_def(b4_req2, 03, 30, 00, 00) |
1176 | 2.05M | #define is_utf8_seq4(uni) ( \ |
1177 | 2.05M | ((uni & utf8_seq(b4_mask)) == utf8_seq(b4_patt)) && \ |
1178 | 2.05M | ((tmp = (uni & utf8_seq(b4_requ)))) && \ |
1179 | 2.05M | ((tmp & utf8_seq(b4_req1)) == 0 || (tmp & utf8_seq(b4_req2)) == 0) ) |
1180 | | |
1181 | | |
1182 | | |
1183 | | /*============================================================================== |
1184 | | * MARK: - Power10 Lookup Table (Private) |
1185 | | * These data are used by the floating-point number reader and writer. |
1186 | | *============================================================================*/ |
1187 | | |
1188 | | #if !YYJSON_DISABLE_FAST_FP_CONV |
1189 | | |
1190 | | /** Maximum pow10 exponent that can be represented exactly as a float64. */ |
1191 | 2.90M | #define F64_POW10_MAX_EXACT_EXP 22 |
1192 | | |
1193 | | #if YYJSON_DOUBLE_MATH_CORRECT |
1194 | | /** Cached pow10 table. */ |
1195 | | static const f64 f64_pow10_table[F64_POW10_MAX_EXACT_EXP + 1] = { |
1196 | | 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, |
1197 | | 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22 |
1198 | | }; |
1199 | | #endif |
1200 | | |
1201 | | /** Maximum pow10 exponent that can be represented exactly as a uint64. */ |
1202 | 3.14M | #define U64_POW10_MAX_EXACT_EXP 19 |
1203 | | |
1204 | | /** Table: [ 10^0, ..., 10^19 ] (generated with misc/make_tables.c) */ |
1205 | | static const u64 u64_pow10_table[U64_POW10_MAX_EXACT_EXP + 1] = { |
1206 | | U64(0x00000000, 0x00000001), U64(0x00000000, 0x0000000A), |
1207 | | U64(0x00000000, 0x00000064), U64(0x00000000, 0x000003E8), |
1208 | | U64(0x00000000, 0x00002710), U64(0x00000000, 0x000186A0), |
1209 | | U64(0x00000000, 0x000F4240), U64(0x00000000, 0x00989680), |
1210 | | U64(0x00000000, 0x05F5E100), U64(0x00000000, 0x3B9ACA00), |
1211 | | U64(0x00000002, 0x540BE400), U64(0x00000017, 0x4876E800), |
1212 | | U64(0x000000E8, 0xD4A51000), U64(0x00000918, 0x4E72A000), |
1213 | | U64(0x00005AF3, 0x107A4000), U64(0x00038D7E, 0xA4C68000), |
1214 | | U64(0x002386F2, 0x6FC10000), U64(0x01634578, 0x5D8A0000), |
1215 | | U64(0x0DE0B6B3, 0xA7640000), U64(0x8AC72304, 0x89E80000) |
1216 | | }; |
1217 | | |
1218 | | /** Minimum decimal exponent in pow10_sig_table. */ |
1219 | 4.44M | #define POW10_SIG_TABLE_MIN_EXP -343 |
1220 | | |
1221 | | /** Maximum decimal exponent in pow10_sig_table. */ |
1222 | | #define POW10_SIG_TABLE_MAX_EXP 324 |
1223 | | |
1224 | | /** Minimum exact decimal exponent in pow10_sig_table */ |
1225 | | #define POW10_SIG_TABLE_MIN_EXACT_EXP 0 |
1226 | | |
1227 | | /** Maximum exact decimal exponent in pow10_sig_table */ |
1228 | | #define POW10_SIG_TABLE_MAX_EXACT_EXP 55 |
1229 | | |
1230 | | /** Normalized significant 128 bits of pow10, not rounded up (size: 10.4KB). |
1231 | | This lookup table is used by both the double number reader and writer. |
1232 | | (generated with misc/make_tables.c) */ |
1233 | | static const u64 pow10_sig_table[] = { |
1234 | | U64(0xBF29DCAB, 0xA82FDEAE), U64(0x7432EE87, 0x3880FC33), /* ~= 10^-343 */ |
1235 | | U64(0xEEF453D6, 0x923BD65A), U64(0x113FAA29, 0x06A13B3F), /* ~= 10^-342 */ |
1236 | | U64(0x9558B466, 0x1B6565F8), U64(0x4AC7CA59, 0xA424C507), /* ~= 10^-341 */ |
1237 | | U64(0xBAAEE17F, 0xA23EBF76), U64(0x5D79BCF0, 0x0D2DF649), /* ~= 10^-340 */ |
1238 | | U64(0xE95A99DF, 0x8ACE6F53), U64(0xF4D82C2C, 0x107973DC), /* ~= 10^-339 */ |
1239 | | U64(0x91D8A02B, 0xB6C10594), U64(0x79071B9B, 0x8A4BE869), /* ~= 10^-338 */ |
1240 | | U64(0xB64EC836, 0xA47146F9), U64(0x9748E282, 0x6CDEE284), /* ~= 10^-337 */ |
1241 | | U64(0xE3E27A44, 0x4D8D98B7), U64(0xFD1B1B23, 0x08169B25), /* ~= 10^-336 */ |
1242 | | U64(0x8E6D8C6A, 0xB0787F72), U64(0xFE30F0F5, 0xE50E20F7), /* ~= 10^-335 */ |
1243 | | U64(0xB208EF85, 0x5C969F4F), U64(0xBDBD2D33, 0x5E51A935), /* ~= 10^-334 */ |
1244 | | U64(0xDE8B2B66, 0xB3BC4723), U64(0xAD2C7880, 0x35E61382), /* ~= 10^-333 */ |
1245 | | U64(0x8B16FB20, 0x3055AC76), U64(0x4C3BCB50, 0x21AFCC31), /* ~= 10^-332 */ |
1246 | | U64(0xADDCB9E8, 0x3C6B1793), U64(0xDF4ABE24, 0x2A1BBF3D), /* ~= 10^-331 */ |
1247 | | U64(0xD953E862, 0x4B85DD78), U64(0xD71D6DAD, 0x34A2AF0D), /* ~= 10^-330 */ |
1248 | | U64(0x87D4713D, 0x6F33AA6B), U64(0x8672648C, 0x40E5AD68), /* ~= 10^-329 */ |
1249 | | U64(0xA9C98D8C, 0xCB009506), U64(0x680EFDAF, 0x511F18C2), /* ~= 10^-328 */ |
1250 | | U64(0xD43BF0EF, 0xFDC0BA48), U64(0x0212BD1B, 0x2566DEF2), /* ~= 10^-327 */ |
1251 | | U64(0x84A57695, 0xFE98746D), U64(0x014BB630, 0xF7604B57), /* ~= 10^-326 */ |
1252 | | U64(0xA5CED43B, 0x7E3E9188), U64(0x419EA3BD, 0x35385E2D), /* ~= 10^-325 */ |
1253 | | U64(0xCF42894A, 0x5DCE35EA), U64(0x52064CAC, 0x828675B9), /* ~= 10^-324 */ |
1254 | | U64(0x818995CE, 0x7AA0E1B2), U64(0x7343EFEB, 0xD1940993), /* ~= 10^-323 */ |
1255 | | U64(0xA1EBFB42, 0x19491A1F), U64(0x1014EBE6, 0xC5F90BF8), /* ~= 10^-322 */ |
1256 | | U64(0xCA66FA12, 0x9F9B60A6), U64(0xD41A26E0, 0x77774EF6), /* ~= 10^-321 */ |
1257 | | U64(0xFD00B897, 0x478238D0), U64(0x8920B098, 0x955522B4), /* ~= 10^-320 */ |
1258 | | U64(0x9E20735E, 0x8CB16382), U64(0x55B46E5F, 0x5D5535B0), /* ~= 10^-319 */ |
1259 | | U64(0xC5A89036, 0x2FDDBC62), U64(0xEB2189F7, 0x34AA831D), /* ~= 10^-318 */ |
1260 | | U64(0xF712B443, 0xBBD52B7B), U64(0xA5E9EC75, 0x01D523E4), /* ~= 10^-317 */ |
1261 | | U64(0x9A6BB0AA, 0x55653B2D), U64(0x47B233C9, 0x2125366E), /* ~= 10^-316 */ |
1262 | | U64(0xC1069CD4, 0xEABE89F8), U64(0x999EC0BB, 0x696E840A), /* ~= 10^-315 */ |
1263 | | U64(0xF148440A, 0x256E2C76), U64(0xC00670EA, 0x43CA250D), /* ~= 10^-314 */ |
1264 | | U64(0x96CD2A86, 0x5764DBCA), U64(0x38040692, 0x6A5E5728), /* ~= 10^-313 */ |
1265 | | U64(0xBC807527, 0xED3E12BC), U64(0xC6050837, 0x04F5ECF2), /* ~= 10^-312 */ |
1266 | | U64(0xEBA09271, 0xE88D976B), U64(0xF7864A44, 0xC633682E), /* ~= 10^-311 */ |
1267 | | U64(0x93445B87, 0x31587EA3), U64(0x7AB3EE6A, 0xFBE0211D), /* ~= 10^-310 */ |
1268 | | U64(0xB8157268, 0xFDAE9E4C), U64(0x5960EA05, 0xBAD82964), /* ~= 10^-309 */ |
1269 | | U64(0xE61ACF03, 0x3D1A45DF), U64(0x6FB92487, 0x298E33BD), /* ~= 10^-308 */ |
1270 | | U64(0x8FD0C162, 0x06306BAB), U64(0xA5D3B6D4, 0x79F8E056), /* ~= 10^-307 */ |
1271 | | U64(0xB3C4F1BA, 0x87BC8696), U64(0x8F48A489, 0x9877186C), /* ~= 10^-306 */ |
1272 | | U64(0xE0B62E29, 0x29ABA83C), U64(0x331ACDAB, 0xFE94DE87), /* ~= 10^-305 */ |
1273 | | U64(0x8C71DCD9, 0xBA0B4925), U64(0x9FF0C08B, 0x7F1D0B14), /* ~= 10^-304 */ |
1274 | | U64(0xAF8E5410, 0x288E1B6F), U64(0x07ECF0AE, 0x5EE44DD9), /* ~= 10^-303 */ |
1275 | | U64(0xDB71E914, 0x32B1A24A), U64(0xC9E82CD9, 0xF69D6150), /* ~= 10^-302 */ |
1276 | | U64(0x892731AC, 0x9FAF056E), U64(0xBE311C08, 0x3A225CD2), /* ~= 10^-301 */ |
1277 | | U64(0xAB70FE17, 0xC79AC6CA), U64(0x6DBD630A, 0x48AAF406), /* ~= 10^-300 */ |
1278 | | U64(0xD64D3D9D, 0xB981787D), U64(0x092CBBCC, 0xDAD5B108), /* ~= 10^-299 */ |
1279 | | U64(0x85F04682, 0x93F0EB4E), U64(0x25BBF560, 0x08C58EA5), /* ~= 10^-298 */ |
1280 | | U64(0xA76C5823, 0x38ED2621), U64(0xAF2AF2B8, 0x0AF6F24E), /* ~= 10^-297 */ |
1281 | | U64(0xD1476E2C, 0x07286FAA), U64(0x1AF5AF66, 0x0DB4AEE1), /* ~= 10^-296 */ |
1282 | | U64(0x82CCA4DB, 0x847945CA), U64(0x50D98D9F, 0xC890ED4D), /* ~= 10^-295 */ |
1283 | | U64(0xA37FCE12, 0x6597973C), U64(0xE50FF107, 0xBAB528A0), /* ~= 10^-294 */ |
1284 | | U64(0xCC5FC196, 0xFEFD7D0C), U64(0x1E53ED49, 0xA96272C8), /* ~= 10^-293 */ |
1285 | | U64(0xFF77B1FC, 0xBEBCDC4F), U64(0x25E8E89C, 0x13BB0F7A), /* ~= 10^-292 */ |
1286 | | U64(0x9FAACF3D, 0xF73609B1), U64(0x77B19161, 0x8C54E9AC), /* ~= 10^-291 */ |
1287 | | U64(0xC795830D, 0x75038C1D), U64(0xD59DF5B9, 0xEF6A2417), /* ~= 10^-290 */ |
1288 | | U64(0xF97AE3D0, 0xD2446F25), U64(0x4B057328, 0x6B44AD1D), /* ~= 10^-289 */ |
1289 | | U64(0x9BECCE62, 0x836AC577), U64(0x4EE367F9, 0x430AEC32), /* ~= 10^-288 */ |
1290 | | U64(0xC2E801FB, 0x244576D5), U64(0x229C41F7, 0x93CDA73F), /* ~= 10^-287 */ |
1291 | | U64(0xF3A20279, 0xED56D48A), U64(0x6B435275, 0x78C1110F), /* ~= 10^-286 */ |
1292 | | U64(0x9845418C, 0x345644D6), U64(0x830A1389, 0x6B78AAA9), /* ~= 10^-285 */ |
1293 | | U64(0xBE5691EF, 0x416BD60C), U64(0x23CC986B, 0xC656D553), /* ~= 10^-284 */ |
1294 | | U64(0xEDEC366B, 0x11C6CB8F), U64(0x2CBFBE86, 0xB7EC8AA8), /* ~= 10^-283 */ |
1295 | | U64(0x94B3A202, 0xEB1C3F39), U64(0x7BF7D714, 0x32F3D6A9), /* ~= 10^-282 */ |
1296 | | U64(0xB9E08A83, 0xA5E34F07), U64(0xDAF5CCD9, 0x3FB0CC53), /* ~= 10^-281 */ |
1297 | | U64(0xE858AD24, 0x8F5C22C9), U64(0xD1B3400F, 0x8F9CFF68), /* ~= 10^-280 */ |
1298 | | U64(0x91376C36, 0xD99995BE), U64(0x23100809, 0xB9C21FA1), /* ~= 10^-279 */ |
1299 | | U64(0xB5854744, 0x8FFFFB2D), U64(0xABD40A0C, 0x2832A78A), /* ~= 10^-278 */ |
1300 | | U64(0xE2E69915, 0xB3FFF9F9), U64(0x16C90C8F, 0x323F516C), /* ~= 10^-277 */ |
1301 | | U64(0x8DD01FAD, 0x907FFC3B), U64(0xAE3DA7D9, 0x7F6792E3), /* ~= 10^-276 */ |
1302 | | U64(0xB1442798, 0xF49FFB4A), U64(0x99CD11CF, 0xDF41779C), /* ~= 10^-275 */ |
1303 | | U64(0xDD95317F, 0x31C7FA1D), U64(0x40405643, 0xD711D583), /* ~= 10^-274 */ |
1304 | | U64(0x8A7D3EEF, 0x7F1CFC52), U64(0x482835EA, 0x666B2572), /* ~= 10^-273 */ |
1305 | | U64(0xAD1C8EAB, 0x5EE43B66), U64(0xDA324365, 0x0005EECF), /* ~= 10^-272 */ |
1306 | | U64(0xD863B256, 0x369D4A40), U64(0x90BED43E, 0x40076A82), /* ~= 10^-271 */ |
1307 | | U64(0x873E4F75, 0xE2224E68), U64(0x5A7744A6, 0xE804A291), /* ~= 10^-270 */ |
1308 | | U64(0xA90DE353, 0x5AAAE202), U64(0x711515D0, 0xA205CB36), /* ~= 10^-269 */ |
1309 | | U64(0xD3515C28, 0x31559A83), U64(0x0D5A5B44, 0xCA873E03), /* ~= 10^-268 */ |
1310 | | U64(0x8412D999, 0x1ED58091), U64(0xE858790A, 0xFE9486C2), /* ~= 10^-267 */ |
1311 | | U64(0xA5178FFF, 0x668AE0B6), U64(0x626E974D, 0xBE39A872), /* ~= 10^-266 */ |
1312 | | U64(0xCE5D73FF, 0x402D98E3), U64(0xFB0A3D21, 0x2DC8128F), /* ~= 10^-265 */ |
1313 | | U64(0x80FA687F, 0x881C7F8E), U64(0x7CE66634, 0xBC9D0B99), /* ~= 10^-264 */ |
1314 | | U64(0xA139029F, 0x6A239F72), U64(0x1C1FFFC1, 0xEBC44E80), /* ~= 10^-263 */ |
1315 | | U64(0xC9874347, 0x44AC874E), U64(0xA327FFB2, 0x66B56220), /* ~= 10^-262 */ |
1316 | | U64(0xFBE91419, 0x15D7A922), U64(0x4BF1FF9F, 0x0062BAA8), /* ~= 10^-261 */ |
1317 | | U64(0x9D71AC8F, 0xADA6C9B5), U64(0x6F773FC3, 0x603DB4A9), /* ~= 10^-260 */ |
1318 | | U64(0xC4CE17B3, 0x99107C22), U64(0xCB550FB4, 0x384D21D3), /* ~= 10^-259 */ |
1319 | | U64(0xF6019DA0, 0x7F549B2B), U64(0x7E2A53A1, 0x46606A48), /* ~= 10^-258 */ |
1320 | | U64(0x99C10284, 0x4F94E0FB), U64(0x2EDA7444, 0xCBFC426D), /* ~= 10^-257 */ |
1321 | | U64(0xC0314325, 0x637A1939), U64(0xFA911155, 0xFEFB5308), /* ~= 10^-256 */ |
1322 | | U64(0xF03D93EE, 0xBC589F88), U64(0x793555AB, 0x7EBA27CA), /* ~= 10^-255 */ |
1323 | | U64(0x96267C75, 0x35B763B5), U64(0x4BC1558B, 0x2F3458DE), /* ~= 10^-254 */ |
1324 | | U64(0xBBB01B92, 0x83253CA2), U64(0x9EB1AAED, 0xFB016F16), /* ~= 10^-253 */ |
1325 | | U64(0xEA9C2277, 0x23EE8BCB), U64(0x465E15A9, 0x79C1CADC), /* ~= 10^-252 */ |
1326 | | U64(0x92A1958A, 0x7675175F), U64(0x0BFACD89, 0xEC191EC9), /* ~= 10^-251 */ |
1327 | | U64(0xB749FAED, 0x14125D36), U64(0xCEF980EC, 0x671F667B), /* ~= 10^-250 */ |
1328 | | U64(0xE51C79A8, 0x5916F484), U64(0x82B7E127, 0x80E7401A), /* ~= 10^-249 */ |
1329 | | U64(0x8F31CC09, 0x37AE58D2), U64(0xD1B2ECB8, 0xB0908810), /* ~= 10^-248 */ |
1330 | | U64(0xB2FE3F0B, 0x8599EF07), U64(0x861FA7E6, 0xDCB4AA15), /* ~= 10^-247 */ |
1331 | | U64(0xDFBDCECE, 0x67006AC9), U64(0x67A791E0, 0x93E1D49A), /* ~= 10^-246 */ |
1332 | | U64(0x8BD6A141, 0x006042BD), U64(0xE0C8BB2C, 0x5C6D24E0), /* ~= 10^-245 */ |
1333 | | U64(0xAECC4991, 0x4078536D), U64(0x58FAE9F7, 0x73886E18), /* ~= 10^-244 */ |
1334 | | U64(0xDA7F5BF5, 0x90966848), U64(0xAF39A475, 0x506A899E), /* ~= 10^-243 */ |
1335 | | U64(0x888F9979, 0x7A5E012D), U64(0x6D8406C9, 0x52429603), /* ~= 10^-242 */ |
1336 | | U64(0xAAB37FD7, 0xD8F58178), U64(0xC8E5087B, 0xA6D33B83), /* ~= 10^-241 */ |
1337 | | U64(0xD5605FCD, 0xCF32E1D6), U64(0xFB1E4A9A, 0x90880A64), /* ~= 10^-240 */ |
1338 | | U64(0x855C3BE0, 0xA17FCD26), U64(0x5CF2EEA0, 0x9A55067F), /* ~= 10^-239 */ |
1339 | | U64(0xA6B34AD8, 0xC9DFC06F), U64(0xF42FAA48, 0xC0EA481E), /* ~= 10^-238 */ |
1340 | | U64(0xD0601D8E, 0xFC57B08B), U64(0xF13B94DA, 0xF124DA26), /* ~= 10^-237 */ |
1341 | | U64(0x823C1279, 0x5DB6CE57), U64(0x76C53D08, 0xD6B70858), /* ~= 10^-236 */ |
1342 | | U64(0xA2CB1717, 0xB52481ED), U64(0x54768C4B, 0x0C64CA6E), /* ~= 10^-235 */ |
1343 | | U64(0xCB7DDCDD, 0xA26DA268), U64(0xA9942F5D, 0xCF7DFD09), /* ~= 10^-234 */ |
1344 | | U64(0xFE5D5415, 0x0B090B02), U64(0xD3F93B35, 0x435D7C4C), /* ~= 10^-233 */ |
1345 | | U64(0x9EFA548D, 0x26E5A6E1), U64(0xC47BC501, 0x4A1A6DAF), /* ~= 10^-232 */ |
1346 | | U64(0xC6B8E9B0, 0x709F109A), U64(0x359AB641, 0x9CA1091B), /* ~= 10^-231 */ |
1347 | | U64(0xF867241C, 0x8CC6D4C0), U64(0xC30163D2, 0x03C94B62), /* ~= 10^-230 */ |
1348 | | U64(0x9B407691, 0xD7FC44F8), U64(0x79E0DE63, 0x425DCF1D), /* ~= 10^-229 */ |
1349 | | U64(0xC2109436, 0x4DFB5636), U64(0x985915FC, 0x12F542E4), /* ~= 10^-228 */ |
1350 | | U64(0xF294B943, 0xE17A2BC4), U64(0x3E6F5B7B, 0x17B2939D), /* ~= 10^-227 */ |
1351 | | U64(0x979CF3CA, 0x6CEC5B5A), U64(0xA705992C, 0xEECF9C42), /* ~= 10^-226 */ |
1352 | | U64(0xBD8430BD, 0x08277231), U64(0x50C6FF78, 0x2A838353), /* ~= 10^-225 */ |
1353 | | U64(0xECE53CEC, 0x4A314EBD), U64(0xA4F8BF56, 0x35246428), /* ~= 10^-224 */ |
1354 | | U64(0x940F4613, 0xAE5ED136), U64(0x871B7795, 0xE136BE99), /* ~= 10^-223 */ |
1355 | | U64(0xB9131798, 0x99F68584), U64(0x28E2557B, 0x59846E3F), /* ~= 10^-222 */ |
1356 | | U64(0xE757DD7E, 0xC07426E5), U64(0x331AEADA, 0x2FE589CF), /* ~= 10^-221 */ |
1357 | | U64(0x9096EA6F, 0x3848984F), U64(0x3FF0D2C8, 0x5DEF7621), /* ~= 10^-220 */ |
1358 | | U64(0xB4BCA50B, 0x065ABE63), U64(0x0FED077A, 0x756B53A9), /* ~= 10^-219 */ |
1359 | | U64(0xE1EBCE4D, 0xC7F16DFB), U64(0xD3E84959, 0x12C62894), /* ~= 10^-218 */ |
1360 | | U64(0x8D3360F0, 0x9CF6E4BD), U64(0x64712DD7, 0xABBBD95C), /* ~= 10^-217 */ |
1361 | | U64(0xB080392C, 0xC4349DEC), U64(0xBD8D794D, 0x96AACFB3), /* ~= 10^-216 */ |
1362 | | U64(0xDCA04777, 0xF541C567), U64(0xECF0D7A0, 0xFC5583A0), /* ~= 10^-215 */ |
1363 | | U64(0x89E42CAA, 0xF9491B60), U64(0xF41686C4, 0x9DB57244), /* ~= 10^-214 */ |
1364 | | U64(0xAC5D37D5, 0xB79B6239), U64(0x311C2875, 0xC522CED5), /* ~= 10^-213 */ |
1365 | | U64(0xD77485CB, 0x25823AC7), U64(0x7D633293, 0x366B828B), /* ~= 10^-212 */ |
1366 | | U64(0x86A8D39E, 0xF77164BC), U64(0xAE5DFF9C, 0x02033197), /* ~= 10^-211 */ |
1367 | | U64(0xA8530886, 0xB54DBDEB), U64(0xD9F57F83, 0x0283FDFC), /* ~= 10^-210 */ |
1368 | | U64(0xD267CAA8, 0x62A12D66), U64(0xD072DF63, 0xC324FD7B), /* ~= 10^-209 */ |
1369 | | U64(0x8380DEA9, 0x3DA4BC60), U64(0x4247CB9E, 0x59F71E6D), /* ~= 10^-208 */ |
1370 | | U64(0xA4611653, 0x8D0DEB78), U64(0x52D9BE85, 0xF074E608), /* ~= 10^-207 */ |
1371 | | U64(0xCD795BE8, 0x70516656), U64(0x67902E27, 0x6C921F8B), /* ~= 10^-206 */ |
1372 | | U64(0x806BD971, 0x4632DFF6), U64(0x00BA1CD8, 0xA3DB53B6), /* ~= 10^-205 */ |
1373 | | U64(0xA086CFCD, 0x97BF97F3), U64(0x80E8A40E, 0xCCD228A4), /* ~= 10^-204 */ |
1374 | | U64(0xC8A883C0, 0xFDAF7DF0), U64(0x6122CD12, 0x8006B2CD), /* ~= 10^-203 */ |
1375 | | U64(0xFAD2A4B1, 0x3D1B5D6C), U64(0x796B8057, 0x20085F81), /* ~= 10^-202 */ |
1376 | | U64(0x9CC3A6EE, 0xC6311A63), U64(0xCBE33036, 0x74053BB0), /* ~= 10^-201 */ |
1377 | | U64(0xC3F490AA, 0x77BD60FC), U64(0xBEDBFC44, 0x11068A9C), /* ~= 10^-200 */ |
1378 | | U64(0xF4F1B4D5, 0x15ACB93B), U64(0xEE92FB55, 0x15482D44), /* ~= 10^-199 */ |
1379 | | U64(0x99171105, 0x2D8BF3C5), U64(0x751BDD15, 0x2D4D1C4A), /* ~= 10^-198 */ |
1380 | | U64(0xBF5CD546, 0x78EEF0B6), U64(0xD262D45A, 0x78A0635D), /* ~= 10^-197 */ |
1381 | | U64(0xEF340A98, 0x172AACE4), U64(0x86FB8971, 0x16C87C34), /* ~= 10^-196 */ |
1382 | | U64(0x9580869F, 0x0E7AAC0E), U64(0xD45D35E6, 0xAE3D4DA0), /* ~= 10^-195 */ |
1383 | | U64(0xBAE0A846, 0xD2195712), U64(0x89748360, 0x59CCA109), /* ~= 10^-194 */ |
1384 | | U64(0xE998D258, 0x869FACD7), U64(0x2BD1A438, 0x703FC94B), /* ~= 10^-193 */ |
1385 | | U64(0x91FF8377, 0x5423CC06), U64(0x7B6306A3, 0x4627DDCF), /* ~= 10^-192 */ |
1386 | | U64(0xB67F6455, 0x292CBF08), U64(0x1A3BC84C, 0x17B1D542), /* ~= 10^-191 */ |
1387 | | U64(0xE41F3D6A, 0x7377EECA), U64(0x20CABA5F, 0x1D9E4A93), /* ~= 10^-190 */ |
1388 | | U64(0x8E938662, 0x882AF53E), U64(0x547EB47B, 0x7282EE9C), /* ~= 10^-189 */ |
1389 | | U64(0xB23867FB, 0x2A35B28D), U64(0xE99E619A, 0x4F23AA43), /* ~= 10^-188 */ |
1390 | | U64(0xDEC681F9, 0xF4C31F31), U64(0x6405FA00, 0xE2EC94D4), /* ~= 10^-187 */ |
1391 | | U64(0x8B3C113C, 0x38F9F37E), U64(0xDE83BC40, 0x8DD3DD04), /* ~= 10^-186 */ |
1392 | | U64(0xAE0B158B, 0x4738705E), U64(0x9624AB50, 0xB148D445), /* ~= 10^-185 */ |
1393 | | U64(0xD98DDAEE, 0x19068C76), U64(0x3BADD624, 0xDD9B0957), /* ~= 10^-184 */ |
1394 | | U64(0x87F8A8D4, 0xCFA417C9), U64(0xE54CA5D7, 0x0A80E5D6), /* ~= 10^-183 */ |
1395 | | U64(0xA9F6D30A, 0x038D1DBC), U64(0x5E9FCF4C, 0xCD211F4C), /* ~= 10^-182 */ |
1396 | | U64(0xD47487CC, 0x8470652B), U64(0x7647C320, 0x0069671F), /* ~= 10^-181 */ |
1397 | | U64(0x84C8D4DF, 0xD2C63F3B), U64(0x29ECD9F4, 0x0041E073), /* ~= 10^-180 */ |
1398 | | U64(0xA5FB0A17, 0xC777CF09), U64(0xF4681071, 0x00525890), /* ~= 10^-179 */ |
1399 | | U64(0xCF79CC9D, 0xB955C2CC), U64(0x7182148D, 0x4066EEB4), /* ~= 10^-178 */ |
1400 | | U64(0x81AC1FE2, 0x93D599BF), U64(0xC6F14CD8, 0x48405530), /* ~= 10^-177 */ |
1401 | | U64(0xA21727DB, 0x38CB002F), U64(0xB8ADA00E, 0x5A506A7C), /* ~= 10^-176 */ |
1402 | | U64(0xCA9CF1D2, 0x06FDC03B), U64(0xA6D90811, 0xF0E4851C), /* ~= 10^-175 */ |
1403 | | U64(0xFD442E46, 0x88BD304A), U64(0x908F4A16, 0x6D1DA663), /* ~= 10^-174 */ |
1404 | | U64(0x9E4A9CEC, 0x15763E2E), U64(0x9A598E4E, 0x043287FE), /* ~= 10^-173 */ |
1405 | | U64(0xC5DD4427, 0x1AD3CDBA), U64(0x40EFF1E1, 0x853F29FD), /* ~= 10^-172 */ |
1406 | | U64(0xF7549530, 0xE188C128), U64(0xD12BEE59, 0xE68EF47C), /* ~= 10^-171 */ |
1407 | | U64(0x9A94DD3E, 0x8CF578B9), U64(0x82BB74F8, 0x301958CE), /* ~= 10^-170 */ |
1408 | | U64(0xC13A148E, 0x3032D6E7), U64(0xE36A5236, 0x3C1FAF01), /* ~= 10^-169 */ |
1409 | | U64(0xF18899B1, 0xBC3F8CA1), U64(0xDC44E6C3, 0xCB279AC1), /* ~= 10^-168 */ |
1410 | | U64(0x96F5600F, 0x15A7B7E5), U64(0x29AB103A, 0x5EF8C0B9), /* ~= 10^-167 */ |
1411 | | U64(0xBCB2B812, 0xDB11A5DE), U64(0x7415D448, 0xF6B6F0E7), /* ~= 10^-166 */ |
1412 | | U64(0xEBDF6617, 0x91D60F56), U64(0x111B495B, 0x3464AD21), /* ~= 10^-165 */ |
1413 | | U64(0x936B9FCE, 0xBB25C995), U64(0xCAB10DD9, 0x00BEEC34), /* ~= 10^-164 */ |
1414 | | U64(0xB84687C2, 0x69EF3BFB), U64(0x3D5D514F, 0x40EEA742), /* ~= 10^-163 */ |
1415 | | U64(0xE65829B3, 0x046B0AFA), U64(0x0CB4A5A3, 0x112A5112), /* ~= 10^-162 */ |
1416 | | U64(0x8FF71A0F, 0xE2C2E6DC), U64(0x47F0E785, 0xEABA72AB), /* ~= 10^-161 */ |
1417 | | U64(0xB3F4E093, 0xDB73A093), U64(0x59ED2167, 0x65690F56), /* ~= 10^-160 */ |
1418 | | U64(0xE0F218B8, 0xD25088B8), U64(0x306869C1, 0x3EC3532C), /* ~= 10^-159 */ |
1419 | | U64(0x8C974F73, 0x83725573), U64(0x1E414218, 0xC73A13FB), /* ~= 10^-158 */ |
1420 | | U64(0xAFBD2350, 0x644EEACF), U64(0xE5D1929E, 0xF90898FA), /* ~= 10^-157 */ |
1421 | | U64(0xDBAC6C24, 0x7D62A583), U64(0xDF45F746, 0xB74ABF39), /* ~= 10^-156 */ |
1422 | | U64(0x894BC396, 0xCE5DA772), U64(0x6B8BBA8C, 0x328EB783), /* ~= 10^-155 */ |
1423 | | U64(0xAB9EB47C, 0x81F5114F), U64(0x066EA92F, 0x3F326564), /* ~= 10^-154 */ |
1424 | | U64(0xD686619B, 0xA27255A2), U64(0xC80A537B, 0x0EFEFEBD), /* ~= 10^-153 */ |
1425 | | U64(0x8613FD01, 0x45877585), U64(0xBD06742C, 0xE95F5F36), /* ~= 10^-152 */ |
1426 | | U64(0xA798FC41, 0x96E952E7), U64(0x2C481138, 0x23B73704), /* ~= 10^-151 */ |
1427 | | U64(0xD17F3B51, 0xFCA3A7A0), U64(0xF75A1586, 0x2CA504C5), /* ~= 10^-150 */ |
1428 | | U64(0x82EF8513, 0x3DE648C4), U64(0x9A984D73, 0xDBE722FB), /* ~= 10^-149 */ |
1429 | | U64(0xA3AB6658, 0x0D5FDAF5), U64(0xC13E60D0, 0xD2E0EBBA), /* ~= 10^-148 */ |
1430 | | U64(0xCC963FEE, 0x10B7D1B3), U64(0x318DF905, 0x079926A8), /* ~= 10^-147 */ |
1431 | | U64(0xFFBBCFE9, 0x94E5C61F), U64(0xFDF17746, 0x497F7052), /* ~= 10^-146 */ |
1432 | | U64(0x9FD561F1, 0xFD0F9BD3), U64(0xFEB6EA8B, 0xEDEFA633), /* ~= 10^-145 */ |
1433 | | U64(0xC7CABA6E, 0x7C5382C8), U64(0xFE64A52E, 0xE96B8FC0), /* ~= 10^-144 */ |
1434 | | U64(0xF9BD690A, 0x1B68637B), U64(0x3DFDCE7A, 0xA3C673B0), /* ~= 10^-143 */ |
1435 | | U64(0x9C1661A6, 0x51213E2D), U64(0x06BEA10C, 0xA65C084E), /* ~= 10^-142 */ |
1436 | | U64(0xC31BFA0F, 0xE5698DB8), U64(0x486E494F, 0xCFF30A62), /* ~= 10^-141 */ |
1437 | | U64(0xF3E2F893, 0xDEC3F126), U64(0x5A89DBA3, 0xC3EFCCFA), /* ~= 10^-140 */ |
1438 | | U64(0x986DDB5C, 0x6B3A76B7), U64(0xF8962946, 0x5A75E01C), /* ~= 10^-139 */ |
1439 | | U64(0xBE895233, 0x86091465), U64(0xF6BBB397, 0xF1135823), /* ~= 10^-138 */ |
1440 | | U64(0xEE2BA6C0, 0x678B597F), U64(0x746AA07D, 0xED582E2C), /* ~= 10^-137 */ |
1441 | | U64(0x94DB4838, 0x40B717EF), U64(0xA8C2A44E, 0xB4571CDC), /* ~= 10^-136 */ |
1442 | | U64(0xBA121A46, 0x50E4DDEB), U64(0x92F34D62, 0x616CE413), /* ~= 10^-135 */ |
1443 | | U64(0xE896A0D7, 0xE51E1566), U64(0x77B020BA, 0xF9C81D17), /* ~= 10^-134 */ |
1444 | | U64(0x915E2486, 0xEF32CD60), U64(0x0ACE1474, 0xDC1D122E), /* ~= 10^-133 */ |
1445 | | U64(0xB5B5ADA8, 0xAAFF80B8), U64(0x0D819992, 0x132456BA), /* ~= 10^-132 */ |
1446 | | U64(0xE3231912, 0xD5BF60E6), U64(0x10E1FFF6, 0x97ED6C69), /* ~= 10^-131 */ |
1447 | | U64(0x8DF5EFAB, 0xC5979C8F), U64(0xCA8D3FFA, 0x1EF463C1), /* ~= 10^-130 */ |
1448 | | U64(0xB1736B96, 0xB6FD83B3), U64(0xBD308FF8, 0xA6B17CB2), /* ~= 10^-129 */ |
1449 | | U64(0xDDD0467C, 0x64BCE4A0), U64(0xAC7CB3F6, 0xD05DDBDE), /* ~= 10^-128 */ |
1450 | | U64(0x8AA22C0D, 0xBEF60EE4), U64(0x6BCDF07A, 0x423AA96B), /* ~= 10^-127 */ |
1451 | | U64(0xAD4AB711, 0x2EB3929D), U64(0x86C16C98, 0xD2C953C6), /* ~= 10^-126 */ |
1452 | | U64(0xD89D64D5, 0x7A607744), U64(0xE871C7BF, 0x077BA8B7), /* ~= 10^-125 */ |
1453 | | U64(0x87625F05, 0x6C7C4A8B), U64(0x11471CD7, 0x64AD4972), /* ~= 10^-124 */ |
1454 | | U64(0xA93AF6C6, 0xC79B5D2D), U64(0xD598E40D, 0x3DD89BCF), /* ~= 10^-123 */ |
1455 | | U64(0xD389B478, 0x79823479), U64(0x4AFF1D10, 0x8D4EC2C3), /* ~= 10^-122 */ |
1456 | | U64(0x843610CB, 0x4BF160CB), U64(0xCEDF722A, 0x585139BA), /* ~= 10^-121 */ |
1457 | | U64(0xA54394FE, 0x1EEDB8FE), U64(0xC2974EB4, 0xEE658828), /* ~= 10^-120 */ |
1458 | | U64(0xCE947A3D, 0xA6A9273E), U64(0x733D2262, 0x29FEEA32), /* ~= 10^-119 */ |
1459 | | U64(0x811CCC66, 0x8829B887), U64(0x0806357D, 0x5A3F525F), /* ~= 10^-118 */ |
1460 | | U64(0xA163FF80, 0x2A3426A8), U64(0xCA07C2DC, 0xB0CF26F7), /* ~= 10^-117 */ |
1461 | | U64(0xC9BCFF60, 0x34C13052), U64(0xFC89B393, 0xDD02F0B5), /* ~= 10^-116 */ |
1462 | | U64(0xFC2C3F38, 0x41F17C67), U64(0xBBAC2078, 0xD443ACE2), /* ~= 10^-115 */ |
1463 | | U64(0x9D9BA783, 0x2936EDC0), U64(0xD54B944B, 0x84AA4C0D), /* ~= 10^-114 */ |
1464 | | U64(0xC5029163, 0xF384A931), U64(0x0A9E795E, 0x65D4DF11), /* ~= 10^-113 */ |
1465 | | U64(0xF64335BC, 0xF065D37D), U64(0x4D4617B5, 0xFF4A16D5), /* ~= 10^-112 */ |
1466 | | U64(0x99EA0196, 0x163FA42E), U64(0x504BCED1, 0xBF8E4E45), /* ~= 10^-111 */ |
1467 | | U64(0xC06481FB, 0x9BCF8D39), U64(0xE45EC286, 0x2F71E1D6), /* ~= 10^-110 */ |
1468 | | U64(0xF07DA27A, 0x82C37088), U64(0x5D767327, 0xBB4E5A4C), /* ~= 10^-109 */ |
1469 | | U64(0x964E858C, 0x91BA2655), U64(0x3A6A07F8, 0xD510F86F), /* ~= 10^-108 */ |
1470 | | U64(0xBBE226EF, 0xB628AFEA), U64(0x890489F7, 0x0A55368B), /* ~= 10^-107 */ |
1471 | | U64(0xEADAB0AB, 0xA3B2DBE5), U64(0x2B45AC74, 0xCCEA842E), /* ~= 10^-106 */ |
1472 | | U64(0x92C8AE6B, 0x464FC96F), U64(0x3B0B8BC9, 0x0012929D), /* ~= 10^-105 */ |
1473 | | U64(0xB77ADA06, 0x17E3BBCB), U64(0x09CE6EBB, 0x40173744), /* ~= 10^-104 */ |
1474 | | U64(0xE5599087, 0x9DDCAABD), U64(0xCC420A6A, 0x101D0515), /* ~= 10^-103 */ |
1475 | | U64(0x8F57FA54, 0xC2A9EAB6), U64(0x9FA94682, 0x4A12232D), /* ~= 10^-102 */ |
1476 | | U64(0xB32DF8E9, 0xF3546564), U64(0x47939822, 0xDC96ABF9), /* ~= 10^-101 */ |
1477 | | U64(0xDFF97724, 0x70297EBD), U64(0x59787E2B, 0x93BC56F7), /* ~= 10^-100 */ |
1478 | | U64(0x8BFBEA76, 0xC619EF36), U64(0x57EB4EDB, 0x3C55B65A), /* ~= 10^-99 */ |
1479 | | U64(0xAEFAE514, 0x77A06B03), U64(0xEDE62292, 0x0B6B23F1), /* ~= 10^-98 */ |
1480 | | U64(0xDAB99E59, 0x958885C4), U64(0xE95FAB36, 0x8E45ECED), /* ~= 10^-97 */ |
1481 | | U64(0x88B402F7, 0xFD75539B), U64(0x11DBCB02, 0x18EBB414), /* ~= 10^-96 */ |
1482 | | U64(0xAAE103B5, 0xFCD2A881), U64(0xD652BDC2, 0x9F26A119), /* ~= 10^-95 */ |
1483 | | U64(0xD59944A3, 0x7C0752A2), U64(0x4BE76D33, 0x46F0495F), /* ~= 10^-94 */ |
1484 | | U64(0x857FCAE6, 0x2D8493A5), U64(0x6F70A440, 0x0C562DDB), /* ~= 10^-93 */ |
1485 | | U64(0xA6DFBD9F, 0xB8E5B88E), U64(0xCB4CCD50, 0x0F6BB952), /* ~= 10^-92 */ |
1486 | | U64(0xD097AD07, 0xA71F26B2), U64(0x7E2000A4, 0x1346A7A7), /* ~= 10^-91 */ |
1487 | | U64(0x825ECC24, 0xC873782F), U64(0x8ED40066, 0x8C0C28C8), /* ~= 10^-90 */ |
1488 | | U64(0xA2F67F2D, 0xFA90563B), U64(0x72890080, 0x2F0F32FA), /* ~= 10^-89 */ |
1489 | | U64(0xCBB41EF9, 0x79346BCA), U64(0x4F2B40A0, 0x3AD2FFB9), /* ~= 10^-88 */ |
1490 | | U64(0xFEA126B7, 0xD78186BC), U64(0xE2F610C8, 0x4987BFA8), /* ~= 10^-87 */ |
1491 | | U64(0x9F24B832, 0xE6B0F436), U64(0x0DD9CA7D, 0x2DF4D7C9), /* ~= 10^-86 */ |
1492 | | U64(0xC6EDE63F, 0xA05D3143), U64(0x91503D1C, 0x79720DBB), /* ~= 10^-85 */ |
1493 | | U64(0xF8A95FCF, 0x88747D94), U64(0x75A44C63, 0x97CE912A), /* ~= 10^-84 */ |
1494 | | U64(0x9B69DBE1, 0xB548CE7C), U64(0xC986AFBE, 0x3EE11ABA), /* ~= 10^-83 */ |
1495 | | U64(0xC24452DA, 0x229B021B), U64(0xFBE85BAD, 0xCE996168), /* ~= 10^-82 */ |
1496 | | U64(0xF2D56790, 0xAB41C2A2), U64(0xFAE27299, 0x423FB9C3), /* ~= 10^-81 */ |
1497 | | U64(0x97C560BA, 0x6B0919A5), U64(0xDCCD879F, 0xC967D41A), /* ~= 10^-80 */ |
1498 | | U64(0xBDB6B8E9, 0x05CB600F), U64(0x5400E987, 0xBBC1C920), /* ~= 10^-79 */ |
1499 | | U64(0xED246723, 0x473E3813), U64(0x290123E9, 0xAAB23B68), /* ~= 10^-78 */ |
1500 | | U64(0x9436C076, 0x0C86E30B), U64(0xF9A0B672, 0x0AAF6521), /* ~= 10^-77 */ |
1501 | | U64(0xB9447093, 0x8FA89BCE), U64(0xF808E40E, 0x8D5B3E69), /* ~= 10^-76 */ |
1502 | | U64(0xE7958CB8, 0x7392C2C2), U64(0xB60B1D12, 0x30B20E04), /* ~= 10^-75 */ |
1503 | | U64(0x90BD77F3, 0x483BB9B9), U64(0xB1C6F22B, 0x5E6F48C2), /* ~= 10^-74 */ |
1504 | | U64(0xB4ECD5F0, 0x1A4AA828), U64(0x1E38AEB6, 0x360B1AF3), /* ~= 10^-73 */ |
1505 | | U64(0xE2280B6C, 0x20DD5232), U64(0x25C6DA63, 0xC38DE1B0), /* ~= 10^-72 */ |
1506 | | U64(0x8D590723, 0x948A535F), U64(0x579C487E, 0x5A38AD0E), /* ~= 10^-71 */ |
1507 | | U64(0xB0AF48EC, 0x79ACE837), U64(0x2D835A9D, 0xF0C6D851), /* ~= 10^-70 */ |
1508 | | U64(0xDCDB1B27, 0x98182244), U64(0xF8E43145, 0x6CF88E65), /* ~= 10^-69 */ |
1509 | | U64(0x8A08F0F8, 0xBF0F156B), U64(0x1B8E9ECB, 0x641B58FF), /* ~= 10^-68 */ |
1510 | | U64(0xAC8B2D36, 0xEED2DAC5), U64(0xE272467E, 0x3D222F3F), /* ~= 10^-67 */ |
1511 | | U64(0xD7ADF884, 0xAA879177), U64(0x5B0ED81D, 0xCC6ABB0F), /* ~= 10^-66 */ |
1512 | | U64(0x86CCBB52, 0xEA94BAEA), U64(0x98E94712, 0x9FC2B4E9), /* ~= 10^-65 */ |
1513 | | U64(0xA87FEA27, 0xA539E9A5), U64(0x3F2398D7, 0x47B36224), /* ~= 10^-64 */ |
1514 | | U64(0xD29FE4B1, 0x8E88640E), U64(0x8EEC7F0D, 0x19A03AAD), /* ~= 10^-63 */ |
1515 | | U64(0x83A3EEEE, 0xF9153E89), U64(0x1953CF68, 0x300424AC), /* ~= 10^-62 */ |
1516 | | U64(0xA48CEAAA, 0xB75A8E2B), U64(0x5FA8C342, 0x3C052DD7), /* ~= 10^-61 */ |
1517 | | U64(0xCDB02555, 0x653131B6), U64(0x3792F412, 0xCB06794D), /* ~= 10^-60 */ |
1518 | | U64(0x808E1755, 0x5F3EBF11), U64(0xE2BBD88B, 0xBEE40BD0), /* ~= 10^-59 */ |
1519 | | U64(0xA0B19D2A, 0xB70E6ED6), U64(0x5B6ACEAE, 0xAE9D0EC4), /* ~= 10^-58 */ |
1520 | | U64(0xC8DE0475, 0x64D20A8B), U64(0xF245825A, 0x5A445275), /* ~= 10^-57 */ |
1521 | | U64(0xFB158592, 0xBE068D2E), U64(0xEED6E2F0, 0xF0D56712), /* ~= 10^-56 */ |
1522 | | U64(0x9CED737B, 0xB6C4183D), U64(0x55464DD6, 0x9685606B), /* ~= 10^-55 */ |
1523 | | U64(0xC428D05A, 0xA4751E4C), U64(0xAA97E14C, 0x3C26B886), /* ~= 10^-54 */ |
1524 | | U64(0xF5330471, 0x4D9265DF), U64(0xD53DD99F, 0x4B3066A8), /* ~= 10^-53 */ |
1525 | | U64(0x993FE2C6, 0xD07B7FAB), U64(0xE546A803, 0x8EFE4029), /* ~= 10^-52 */ |
1526 | | U64(0xBF8FDB78, 0x849A5F96), U64(0xDE985204, 0x72BDD033), /* ~= 10^-51 */ |
1527 | | U64(0xEF73D256, 0xA5C0F77C), U64(0x963E6685, 0x8F6D4440), /* ~= 10^-50 */ |
1528 | | U64(0x95A86376, 0x27989AAD), U64(0xDDE70013, 0x79A44AA8), /* ~= 10^-49 */ |
1529 | | U64(0xBB127C53, 0xB17EC159), U64(0x5560C018, 0x580D5D52), /* ~= 10^-48 */ |
1530 | | U64(0xE9D71B68, 0x9DDE71AF), U64(0xAAB8F01E, 0x6E10B4A6), /* ~= 10^-47 */ |
1531 | | U64(0x92267121, 0x62AB070D), U64(0xCAB39613, 0x04CA70E8), /* ~= 10^-46 */ |
1532 | | U64(0xB6B00D69, 0xBB55C8D1), U64(0x3D607B97, 0xC5FD0D22), /* ~= 10^-45 */ |
1533 | | U64(0xE45C10C4, 0x2A2B3B05), U64(0x8CB89A7D, 0xB77C506A), /* ~= 10^-44 */ |
1534 | | U64(0x8EB98A7A, 0x9A5B04E3), U64(0x77F3608E, 0x92ADB242), /* ~= 10^-43 */ |
1535 | | U64(0xB267ED19, 0x40F1C61C), U64(0x55F038B2, 0x37591ED3), /* ~= 10^-42 */ |
1536 | | U64(0xDF01E85F, 0x912E37A3), U64(0x6B6C46DE, 0xC52F6688), /* ~= 10^-41 */ |
1537 | | U64(0x8B61313B, 0xBABCE2C6), U64(0x2323AC4B, 0x3B3DA015), /* ~= 10^-40 */ |
1538 | | U64(0xAE397D8A, 0xA96C1B77), U64(0xABEC975E, 0x0A0D081A), /* ~= 10^-39 */ |
1539 | | U64(0xD9C7DCED, 0x53C72255), U64(0x96E7BD35, 0x8C904A21), /* ~= 10^-38 */ |
1540 | | U64(0x881CEA14, 0x545C7575), U64(0x7E50D641, 0x77DA2E54), /* ~= 10^-37 */ |
1541 | | U64(0xAA242499, 0x697392D2), U64(0xDDE50BD1, 0xD5D0B9E9), /* ~= 10^-36 */ |
1542 | | U64(0xD4AD2DBF, 0xC3D07787), U64(0x955E4EC6, 0x4B44E864), /* ~= 10^-35 */ |
1543 | | U64(0x84EC3C97, 0xDA624AB4), U64(0xBD5AF13B, 0xEF0B113E), /* ~= 10^-34 */ |
1544 | | U64(0xA6274BBD, 0xD0FADD61), U64(0xECB1AD8A, 0xEACDD58E), /* ~= 10^-33 */ |
1545 | | U64(0xCFB11EAD, 0x453994BA), U64(0x67DE18ED, 0xA5814AF2), /* ~= 10^-32 */ |
1546 | | U64(0x81CEB32C, 0x4B43FCF4), U64(0x80EACF94, 0x8770CED7), /* ~= 10^-31 */ |
1547 | | U64(0xA2425FF7, 0x5E14FC31), U64(0xA1258379, 0xA94D028D), /* ~= 10^-30 */ |
1548 | | U64(0xCAD2F7F5, 0x359A3B3E), U64(0x096EE458, 0x13A04330), /* ~= 10^-29 */ |
1549 | | U64(0xFD87B5F2, 0x8300CA0D), U64(0x8BCA9D6E, 0x188853FC), /* ~= 10^-28 */ |
1550 | | U64(0x9E74D1B7, 0x91E07E48), U64(0x775EA264, 0xCF55347D), /* ~= 10^-27 */ |
1551 | | U64(0xC6120625, 0x76589DDA), U64(0x95364AFE, 0x032A819D), /* ~= 10^-26 */ |
1552 | | U64(0xF79687AE, 0xD3EEC551), U64(0x3A83DDBD, 0x83F52204), /* ~= 10^-25 */ |
1553 | | U64(0x9ABE14CD, 0x44753B52), U64(0xC4926A96, 0x72793542), /* ~= 10^-24 */ |
1554 | | U64(0xC16D9A00, 0x95928A27), U64(0x75B7053C, 0x0F178293), /* ~= 10^-23 */ |
1555 | | U64(0xF1C90080, 0xBAF72CB1), U64(0x5324C68B, 0x12DD6338), /* ~= 10^-22 */ |
1556 | | U64(0x971DA050, 0x74DA7BEE), U64(0xD3F6FC16, 0xEBCA5E03), /* ~= 10^-21 */ |
1557 | | U64(0xBCE50864, 0x92111AEA), U64(0x88F4BB1C, 0xA6BCF584), /* ~= 10^-20 */ |
1558 | | U64(0xEC1E4A7D, 0xB69561A5), U64(0x2B31E9E3, 0xD06C32E5), /* ~= 10^-19 */ |
1559 | | U64(0x9392EE8E, 0x921D5D07), U64(0x3AFF322E, 0x62439FCF), /* ~= 10^-18 */ |
1560 | | U64(0xB877AA32, 0x36A4B449), U64(0x09BEFEB9, 0xFAD487C2), /* ~= 10^-17 */ |
1561 | | U64(0xE69594BE, 0xC44DE15B), U64(0x4C2EBE68, 0x7989A9B3), /* ~= 10^-16 */ |
1562 | | U64(0x901D7CF7, 0x3AB0ACD9), U64(0x0F9D3701, 0x4BF60A10), /* ~= 10^-15 */ |
1563 | | U64(0xB424DC35, 0x095CD80F), U64(0x538484C1, 0x9EF38C94), /* ~= 10^-14 */ |
1564 | | U64(0xE12E1342, 0x4BB40E13), U64(0x2865A5F2, 0x06B06FB9), /* ~= 10^-13 */ |
1565 | | U64(0x8CBCCC09, 0x6F5088CB), U64(0xF93F87B7, 0x442E45D3), /* ~= 10^-12 */ |
1566 | | U64(0xAFEBFF0B, 0xCB24AAFE), U64(0xF78F69A5, 0x1539D748), /* ~= 10^-11 */ |
1567 | | U64(0xDBE6FECE, 0xBDEDD5BE), U64(0xB573440E, 0x5A884D1B), /* ~= 10^-10 */ |
1568 | | U64(0x89705F41, 0x36B4A597), U64(0x31680A88, 0xF8953030), /* ~= 10^-9 */ |
1569 | | U64(0xABCC7711, 0x8461CEFC), U64(0xFDC20D2B, 0x36BA7C3D), /* ~= 10^-8 */ |
1570 | | U64(0xD6BF94D5, 0xE57A42BC), U64(0x3D329076, 0x04691B4C), /* ~= 10^-7 */ |
1571 | | U64(0x8637BD05, 0xAF6C69B5), U64(0xA63F9A49, 0xC2C1B10F), /* ~= 10^-6 */ |
1572 | | U64(0xA7C5AC47, 0x1B478423), U64(0x0FCF80DC, 0x33721D53), /* ~= 10^-5 */ |
1573 | | U64(0xD1B71758, 0xE219652B), U64(0xD3C36113, 0x404EA4A8), /* ~= 10^-4 */ |
1574 | | U64(0x83126E97, 0x8D4FDF3B), U64(0x645A1CAC, 0x083126E9), /* ~= 10^-3 */ |
1575 | | U64(0xA3D70A3D, 0x70A3D70A), U64(0x3D70A3D7, 0x0A3D70A3), /* ~= 10^-2 */ |
1576 | | U64(0xCCCCCCCC, 0xCCCCCCCC), U64(0xCCCCCCCC, 0xCCCCCCCC), /* ~= 10^-1 */ |
1577 | | U64(0x80000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^0 */ |
1578 | | U64(0xA0000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^1 */ |
1579 | | U64(0xC8000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^2 */ |
1580 | | U64(0xFA000000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^3 */ |
1581 | | U64(0x9C400000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^4 */ |
1582 | | U64(0xC3500000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^5 */ |
1583 | | U64(0xF4240000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^6 */ |
1584 | | U64(0x98968000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^7 */ |
1585 | | U64(0xBEBC2000, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^8 */ |
1586 | | U64(0xEE6B2800, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^9 */ |
1587 | | U64(0x9502F900, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^10 */ |
1588 | | U64(0xBA43B740, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^11 */ |
1589 | | U64(0xE8D4A510, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^12 */ |
1590 | | U64(0x9184E72A, 0x00000000), U64(0x00000000, 0x00000000), /* == 10^13 */ |
1591 | | U64(0xB5E620F4, 0x80000000), U64(0x00000000, 0x00000000), /* == 10^14 */ |
1592 | | U64(0xE35FA931, 0xA0000000), U64(0x00000000, 0x00000000), /* == 10^15 */ |
1593 | | U64(0x8E1BC9BF, 0x04000000), U64(0x00000000, 0x00000000), /* == 10^16 */ |
1594 | | U64(0xB1A2BC2E, 0xC5000000), U64(0x00000000, 0x00000000), /* == 10^17 */ |
1595 | | U64(0xDE0B6B3A, 0x76400000), U64(0x00000000, 0x00000000), /* == 10^18 */ |
1596 | | U64(0x8AC72304, 0x89E80000), U64(0x00000000, 0x00000000), /* == 10^19 */ |
1597 | | U64(0xAD78EBC5, 0xAC620000), U64(0x00000000, 0x00000000), /* == 10^20 */ |
1598 | | U64(0xD8D726B7, 0x177A8000), U64(0x00000000, 0x00000000), /* == 10^21 */ |
1599 | | U64(0x87867832, 0x6EAC9000), U64(0x00000000, 0x00000000), /* == 10^22 */ |
1600 | | U64(0xA968163F, 0x0A57B400), U64(0x00000000, 0x00000000), /* == 10^23 */ |
1601 | | U64(0xD3C21BCE, 0xCCEDA100), U64(0x00000000, 0x00000000), /* == 10^24 */ |
1602 | | U64(0x84595161, 0x401484A0), U64(0x00000000, 0x00000000), /* == 10^25 */ |
1603 | | U64(0xA56FA5B9, 0x9019A5C8), U64(0x00000000, 0x00000000), /* == 10^26 */ |
1604 | | U64(0xCECB8F27, 0xF4200F3A), U64(0x00000000, 0x00000000), /* == 10^27 */ |
1605 | | U64(0x813F3978, 0xF8940984), U64(0x40000000, 0x00000000), /* == 10^28 */ |
1606 | | U64(0xA18F07D7, 0x36B90BE5), U64(0x50000000, 0x00000000), /* == 10^29 */ |
1607 | | U64(0xC9F2C9CD, 0x04674EDE), U64(0xA4000000, 0x00000000), /* == 10^30 */ |
1608 | | U64(0xFC6F7C40, 0x45812296), U64(0x4D000000, 0x00000000), /* == 10^31 */ |
1609 | | U64(0x9DC5ADA8, 0x2B70B59D), U64(0xF0200000, 0x00000000), /* == 10^32 */ |
1610 | | U64(0xC5371912, 0x364CE305), U64(0x6C280000, 0x00000000), /* == 10^33 */ |
1611 | | U64(0xF684DF56, 0xC3E01BC6), U64(0xC7320000, 0x00000000), /* == 10^34 */ |
1612 | | U64(0x9A130B96, 0x3A6C115C), U64(0x3C7F4000, 0x00000000), /* == 10^35 */ |
1613 | | U64(0xC097CE7B, 0xC90715B3), U64(0x4B9F1000, 0x00000000), /* == 10^36 */ |
1614 | | U64(0xF0BDC21A, 0xBB48DB20), U64(0x1E86D400, 0x00000000), /* == 10^37 */ |
1615 | | U64(0x96769950, 0xB50D88F4), U64(0x13144480, 0x00000000), /* == 10^38 */ |
1616 | | U64(0xBC143FA4, 0xE250EB31), U64(0x17D955A0, 0x00000000), /* == 10^39 */ |
1617 | | U64(0xEB194F8E, 0x1AE525FD), U64(0x5DCFAB08, 0x00000000), /* == 10^40 */ |
1618 | | U64(0x92EFD1B8, 0xD0CF37BE), U64(0x5AA1CAE5, 0x00000000), /* == 10^41 */ |
1619 | | U64(0xB7ABC627, 0x050305AD), U64(0xF14A3D9E, 0x40000000), /* == 10^42 */ |
1620 | | U64(0xE596B7B0, 0xC643C719), U64(0x6D9CCD05, 0xD0000000), /* == 10^43 */ |
1621 | | U64(0x8F7E32CE, 0x7BEA5C6F), U64(0xE4820023, 0xA2000000), /* == 10^44 */ |
1622 | | U64(0xB35DBF82, 0x1AE4F38B), U64(0xDDA2802C, 0x8A800000), /* == 10^45 */ |
1623 | | U64(0xE0352F62, 0xA19E306E), U64(0xD50B2037, 0xAD200000), /* == 10^46 */ |
1624 | | U64(0x8C213D9D, 0xA502DE45), U64(0x4526F422, 0xCC340000), /* == 10^47 */ |
1625 | | U64(0xAF298D05, 0x0E4395D6), U64(0x9670B12B, 0x7F410000), /* == 10^48 */ |
1626 | | U64(0xDAF3F046, 0x51D47B4C), U64(0x3C0CDD76, 0x5F114000), /* == 10^49 */ |
1627 | | U64(0x88D8762B, 0xF324CD0F), U64(0xA5880A69, 0xFB6AC800), /* == 10^50 */ |
1628 | | U64(0xAB0E93B6, 0xEFEE0053), U64(0x8EEA0D04, 0x7A457A00), /* == 10^51 */ |
1629 | | U64(0xD5D238A4, 0xABE98068), U64(0x72A49045, 0x98D6D880), /* == 10^52 */ |
1630 | | U64(0x85A36366, 0xEB71F041), U64(0x47A6DA2B, 0x7F864750), /* == 10^53 */ |
1631 | | U64(0xA70C3C40, 0xA64E6C51), U64(0x999090B6, 0x5F67D924), /* == 10^54 */ |
1632 | | U64(0xD0CF4B50, 0xCFE20765), U64(0xFFF4B4E3, 0xF741CF6D), /* == 10^55 */ |
1633 | | U64(0x82818F12, 0x81ED449F), U64(0xBFF8F10E, 0x7A8921A4), /* ~= 10^56 */ |
1634 | | U64(0xA321F2D7, 0x226895C7), U64(0xAFF72D52, 0x192B6A0D), /* ~= 10^57 */ |
1635 | | U64(0xCBEA6F8C, 0xEB02BB39), U64(0x9BF4F8A6, 0x9F764490), /* ~= 10^58 */ |
1636 | | U64(0xFEE50B70, 0x25C36A08), U64(0x02F236D0, 0x4753D5B4), /* ~= 10^59 */ |
1637 | | U64(0x9F4F2726, 0x179A2245), U64(0x01D76242, 0x2C946590), /* ~= 10^60 */ |
1638 | | U64(0xC722F0EF, 0x9D80AAD6), U64(0x424D3AD2, 0xB7B97EF5), /* ~= 10^61 */ |
1639 | | U64(0xF8EBAD2B, 0x84E0D58B), U64(0xD2E08987, 0x65A7DEB2), /* ~= 10^62 */ |
1640 | | U64(0x9B934C3B, 0x330C8577), U64(0x63CC55F4, 0x9F88EB2F), /* ~= 10^63 */ |
1641 | | U64(0xC2781F49, 0xFFCFA6D5), U64(0x3CBF6B71, 0xC76B25FB), /* ~= 10^64 */ |
1642 | | U64(0xF316271C, 0x7FC3908A), U64(0x8BEF464E, 0x3945EF7A), /* ~= 10^65 */ |
1643 | | U64(0x97EDD871, 0xCFDA3A56), U64(0x97758BF0, 0xE3CBB5AC), /* ~= 10^66 */ |
1644 | | U64(0xBDE94E8E, 0x43D0C8EC), U64(0x3D52EEED, 0x1CBEA317), /* ~= 10^67 */ |
1645 | | U64(0xED63A231, 0xD4C4FB27), U64(0x4CA7AAA8, 0x63EE4BDD), /* ~= 10^68 */ |
1646 | | U64(0x945E455F, 0x24FB1CF8), U64(0x8FE8CAA9, 0x3E74EF6A), /* ~= 10^69 */ |
1647 | | U64(0xB975D6B6, 0xEE39E436), U64(0xB3E2FD53, 0x8E122B44), /* ~= 10^70 */ |
1648 | | U64(0xE7D34C64, 0xA9C85D44), U64(0x60DBBCA8, 0x7196B616), /* ~= 10^71 */ |
1649 | | U64(0x90E40FBE, 0xEA1D3A4A), U64(0xBC8955E9, 0x46FE31CD), /* ~= 10^72 */ |
1650 | | U64(0xB51D13AE, 0xA4A488DD), U64(0x6BABAB63, 0x98BDBE41), /* ~= 10^73 */ |
1651 | | U64(0xE264589A, 0x4DCDAB14), U64(0xC696963C, 0x7EED2DD1), /* ~= 10^74 */ |
1652 | | U64(0x8D7EB760, 0x70A08AEC), U64(0xFC1E1DE5, 0xCF543CA2), /* ~= 10^75 */ |
1653 | | U64(0xB0DE6538, 0x8CC8ADA8), U64(0x3B25A55F, 0x43294BCB), /* ~= 10^76 */ |
1654 | | U64(0xDD15FE86, 0xAFFAD912), U64(0x49EF0EB7, 0x13F39EBE), /* ~= 10^77 */ |
1655 | | U64(0x8A2DBF14, 0x2DFCC7AB), U64(0x6E356932, 0x6C784337), /* ~= 10^78 */ |
1656 | | U64(0xACB92ED9, 0x397BF996), U64(0x49C2C37F, 0x07965404), /* ~= 10^79 */ |
1657 | | U64(0xD7E77A8F, 0x87DAF7FB), U64(0xDC33745E, 0xC97BE906), /* ~= 10^80 */ |
1658 | | U64(0x86F0AC99, 0xB4E8DAFD), U64(0x69A028BB, 0x3DED71A3), /* ~= 10^81 */ |
1659 | | U64(0xA8ACD7C0, 0x222311BC), U64(0xC40832EA, 0x0D68CE0C), /* ~= 10^82 */ |
1660 | | U64(0xD2D80DB0, 0x2AABD62B), U64(0xF50A3FA4, 0x90C30190), /* ~= 10^83 */ |
1661 | | U64(0x83C7088E, 0x1AAB65DB), U64(0x792667C6, 0xDA79E0FA), /* ~= 10^84 */ |
1662 | | U64(0xA4B8CAB1, 0xA1563F52), U64(0x577001B8, 0x91185938), /* ~= 10^85 */ |
1663 | | U64(0xCDE6FD5E, 0x09ABCF26), U64(0xED4C0226, 0xB55E6F86), /* ~= 10^86 */ |
1664 | | U64(0x80B05E5A, 0xC60B6178), U64(0x544F8158, 0x315B05B4), /* ~= 10^87 */ |
1665 | | U64(0xA0DC75F1, 0x778E39D6), U64(0x696361AE, 0x3DB1C721), /* ~= 10^88 */ |
1666 | | U64(0xC913936D, 0xD571C84C), U64(0x03BC3A19, 0xCD1E38E9), /* ~= 10^89 */ |
1667 | | U64(0xFB587849, 0x4ACE3A5F), U64(0x04AB48A0, 0x4065C723), /* ~= 10^90 */ |
1668 | | U64(0x9D174B2D, 0xCEC0E47B), U64(0x62EB0D64, 0x283F9C76), /* ~= 10^91 */ |
1669 | | U64(0xC45D1DF9, 0x42711D9A), U64(0x3BA5D0BD, 0x324F8394), /* ~= 10^92 */ |
1670 | | U64(0xF5746577, 0x930D6500), U64(0xCA8F44EC, 0x7EE36479), /* ~= 10^93 */ |
1671 | | U64(0x9968BF6A, 0xBBE85F20), U64(0x7E998B13, 0xCF4E1ECB), /* ~= 10^94 */ |
1672 | | U64(0xBFC2EF45, 0x6AE276E8), U64(0x9E3FEDD8, 0xC321A67E), /* ~= 10^95 */ |
1673 | | U64(0xEFB3AB16, 0xC59B14A2), U64(0xC5CFE94E, 0xF3EA101E), /* ~= 10^96 */ |
1674 | | U64(0x95D04AEE, 0x3B80ECE5), U64(0xBBA1F1D1, 0x58724A12), /* ~= 10^97 */ |
1675 | | U64(0xBB445DA9, 0xCA61281F), U64(0x2A8A6E45, 0xAE8EDC97), /* ~= 10^98 */ |
1676 | | U64(0xEA157514, 0x3CF97226), U64(0xF52D09D7, 0x1A3293BD), /* ~= 10^99 */ |
1677 | | U64(0x924D692C, 0xA61BE758), U64(0x593C2626, 0x705F9C56), /* ~= 10^100 */ |
1678 | | U64(0xB6E0C377, 0xCFA2E12E), U64(0x6F8B2FB0, 0x0C77836C), /* ~= 10^101 */ |
1679 | | U64(0xE498F455, 0xC38B997A), U64(0x0B6DFB9C, 0x0F956447), /* ~= 10^102 */ |
1680 | | U64(0x8EDF98B5, 0x9A373FEC), U64(0x4724BD41, 0x89BD5EAC), /* ~= 10^103 */ |
1681 | | U64(0xB2977EE3, 0x00C50FE7), U64(0x58EDEC91, 0xEC2CB657), /* ~= 10^104 */ |
1682 | | U64(0xDF3D5E9B, 0xC0F653E1), U64(0x2F2967B6, 0x6737E3ED), /* ~= 10^105 */ |
1683 | | U64(0x8B865B21, 0x5899F46C), U64(0xBD79E0D2, 0x0082EE74), /* ~= 10^106 */ |
1684 | | U64(0xAE67F1E9, 0xAEC07187), U64(0xECD85906, 0x80A3AA11), /* ~= 10^107 */ |
1685 | | U64(0xDA01EE64, 0x1A708DE9), U64(0xE80E6F48, 0x20CC9495), /* ~= 10^108 */ |
1686 | | U64(0x884134FE, 0x908658B2), U64(0x3109058D, 0x147FDCDD), /* ~= 10^109 */ |
1687 | | U64(0xAA51823E, 0x34A7EEDE), U64(0xBD4B46F0, 0x599FD415), /* ~= 10^110 */ |
1688 | | U64(0xD4E5E2CD, 0xC1D1EA96), U64(0x6C9E18AC, 0x7007C91A), /* ~= 10^111 */ |
1689 | | U64(0x850FADC0, 0x9923329E), U64(0x03E2CF6B, 0xC604DDB0), /* ~= 10^112 */ |
1690 | | U64(0xA6539930, 0xBF6BFF45), U64(0x84DB8346, 0xB786151C), /* ~= 10^113 */ |
1691 | | U64(0xCFE87F7C, 0xEF46FF16), U64(0xE6126418, 0x65679A63), /* ~= 10^114 */ |
1692 | | U64(0x81F14FAE, 0x158C5F6E), U64(0x4FCB7E8F, 0x3F60C07E), /* ~= 10^115 */ |
1693 | | U64(0xA26DA399, 0x9AEF7749), U64(0xE3BE5E33, 0x0F38F09D), /* ~= 10^116 */ |
1694 | | U64(0xCB090C80, 0x01AB551C), U64(0x5CADF5BF, 0xD3072CC5), /* ~= 10^117 */ |
1695 | | U64(0xFDCB4FA0, 0x02162A63), U64(0x73D9732F, 0xC7C8F7F6), /* ~= 10^118 */ |
1696 | | U64(0x9E9F11C4, 0x014DDA7E), U64(0x2867E7FD, 0xDCDD9AFA), /* ~= 10^119 */ |
1697 | | U64(0xC646D635, 0x01A1511D), U64(0xB281E1FD, 0x541501B8), /* ~= 10^120 */ |
1698 | | U64(0xF7D88BC2, 0x4209A565), U64(0x1F225A7C, 0xA91A4226), /* ~= 10^121 */ |
1699 | | U64(0x9AE75759, 0x6946075F), U64(0x3375788D, 0xE9B06958), /* ~= 10^122 */ |
1700 | | U64(0xC1A12D2F, 0xC3978937), U64(0x0052D6B1, 0x641C83AE), /* ~= 10^123 */ |
1701 | | U64(0xF209787B, 0xB47D6B84), U64(0xC0678C5D, 0xBD23A49A), /* ~= 10^124 */ |
1702 | | U64(0x9745EB4D, 0x50CE6332), U64(0xF840B7BA, 0x963646E0), /* ~= 10^125 */ |
1703 | | U64(0xBD176620, 0xA501FBFF), U64(0xB650E5A9, 0x3BC3D898), /* ~= 10^126 */ |
1704 | | U64(0xEC5D3FA8, 0xCE427AFF), U64(0xA3E51F13, 0x8AB4CEBE), /* ~= 10^127 */ |
1705 | | U64(0x93BA47C9, 0x80E98CDF), U64(0xC66F336C, 0x36B10137), /* ~= 10^128 */ |
1706 | | U64(0xB8A8D9BB, 0xE123F017), U64(0xB80B0047, 0x445D4184), /* ~= 10^129 */ |
1707 | | U64(0xE6D3102A, 0xD96CEC1D), U64(0xA60DC059, 0x157491E5), /* ~= 10^130 */ |
1708 | | U64(0x9043EA1A, 0xC7E41392), U64(0x87C89837, 0xAD68DB2F), /* ~= 10^131 */ |
1709 | | U64(0xB454E4A1, 0x79DD1877), U64(0x29BABE45, 0x98C311FB), /* ~= 10^132 */ |
1710 | | U64(0xE16A1DC9, 0xD8545E94), U64(0xF4296DD6, 0xFEF3D67A), /* ~= 10^133 */ |
1711 | | U64(0x8CE2529E, 0x2734BB1D), U64(0x1899E4A6, 0x5F58660C), /* ~= 10^134 */ |
1712 | | U64(0xB01AE745, 0xB101E9E4), U64(0x5EC05DCF, 0xF72E7F8F), /* ~= 10^135 */ |
1713 | | U64(0xDC21A117, 0x1D42645D), U64(0x76707543, 0xF4FA1F73), /* ~= 10^136 */ |
1714 | | U64(0x899504AE, 0x72497EBA), U64(0x6A06494A, 0x791C53A8), /* ~= 10^137 */ |
1715 | | U64(0xABFA45DA, 0x0EDBDE69), U64(0x0487DB9D, 0x17636892), /* ~= 10^138 */ |
1716 | | U64(0xD6F8D750, 0x9292D603), U64(0x45A9D284, 0x5D3C42B6), /* ~= 10^139 */ |
1717 | | U64(0x865B8692, 0x5B9BC5C2), U64(0x0B8A2392, 0xBA45A9B2), /* ~= 10^140 */ |
1718 | | U64(0xA7F26836, 0xF282B732), U64(0x8E6CAC77, 0x68D7141E), /* ~= 10^141 */ |
1719 | | U64(0xD1EF0244, 0xAF2364FF), U64(0x3207D795, 0x430CD926), /* ~= 10^142 */ |
1720 | | U64(0x8335616A, 0xED761F1F), U64(0x7F44E6BD, 0x49E807B8), /* ~= 10^143 */ |
1721 | | U64(0xA402B9C5, 0xA8D3A6E7), U64(0x5F16206C, 0x9C6209A6), /* ~= 10^144 */ |
1722 | | U64(0xCD036837, 0x130890A1), U64(0x36DBA887, 0xC37A8C0F), /* ~= 10^145 */ |
1723 | | U64(0x80222122, 0x6BE55A64), U64(0xC2494954, 0xDA2C9789), /* ~= 10^146 */ |
1724 | | U64(0xA02AA96B, 0x06DEB0FD), U64(0xF2DB9BAA, 0x10B7BD6C), /* ~= 10^147 */ |
1725 | | U64(0xC83553C5, 0xC8965D3D), U64(0x6F928294, 0x94E5ACC7), /* ~= 10^148 */ |
1726 | | U64(0xFA42A8B7, 0x3ABBF48C), U64(0xCB772339, 0xBA1F17F9), /* ~= 10^149 */ |
1727 | | U64(0x9C69A972, 0x84B578D7), U64(0xFF2A7604, 0x14536EFB), /* ~= 10^150 */ |
1728 | | U64(0xC38413CF, 0x25E2D70D), U64(0xFEF51385, 0x19684ABA), /* ~= 10^151 */ |
1729 | | U64(0xF46518C2, 0xEF5B8CD1), U64(0x7EB25866, 0x5FC25D69), /* ~= 10^152 */ |
1730 | | U64(0x98BF2F79, 0xD5993802), U64(0xEF2F773F, 0xFBD97A61), /* ~= 10^153 */ |
1731 | | U64(0xBEEEFB58, 0x4AFF8603), U64(0xAAFB550F, 0xFACFD8FA), /* ~= 10^154 */ |
1732 | | U64(0xEEAABA2E, 0x5DBF6784), U64(0x95BA2A53, 0xF983CF38), /* ~= 10^155 */ |
1733 | | U64(0x952AB45C, 0xFA97A0B2), U64(0xDD945A74, 0x7BF26183), /* ~= 10^156 */ |
1734 | | U64(0xBA756174, 0x393D88DF), U64(0x94F97111, 0x9AEEF9E4), /* ~= 10^157 */ |
1735 | | U64(0xE912B9D1, 0x478CEB17), U64(0x7A37CD56, 0x01AAB85D), /* ~= 10^158 */ |
1736 | | U64(0x91ABB422, 0xCCB812EE), U64(0xAC62E055, 0xC10AB33A), /* ~= 10^159 */ |
1737 | | U64(0xB616A12B, 0x7FE617AA), U64(0x577B986B, 0x314D6009), /* ~= 10^160 */ |
1738 | | U64(0xE39C4976, 0x5FDF9D94), U64(0xED5A7E85, 0xFDA0B80B), /* ~= 10^161 */ |
1739 | | U64(0x8E41ADE9, 0xFBEBC27D), U64(0x14588F13, 0xBE847307), /* ~= 10^162 */ |
1740 | | U64(0xB1D21964, 0x7AE6B31C), U64(0x596EB2D8, 0xAE258FC8), /* ~= 10^163 */ |
1741 | | U64(0xDE469FBD, 0x99A05FE3), U64(0x6FCA5F8E, 0xD9AEF3BB), /* ~= 10^164 */ |
1742 | | U64(0x8AEC23D6, 0x80043BEE), U64(0x25DE7BB9, 0x480D5854), /* ~= 10^165 */ |
1743 | | U64(0xADA72CCC, 0x20054AE9), U64(0xAF561AA7, 0x9A10AE6A), /* ~= 10^166 */ |
1744 | | U64(0xD910F7FF, 0x28069DA4), U64(0x1B2BA151, 0x8094DA04), /* ~= 10^167 */ |
1745 | | U64(0x87AA9AFF, 0x79042286), U64(0x90FB44D2, 0xF05D0842), /* ~= 10^168 */ |
1746 | | U64(0xA99541BF, 0x57452B28), U64(0x353A1607, 0xAC744A53), /* ~= 10^169 */ |
1747 | | U64(0xD3FA922F, 0x2D1675F2), U64(0x42889B89, 0x97915CE8), /* ~= 10^170 */ |
1748 | | U64(0x847C9B5D, 0x7C2E09B7), U64(0x69956135, 0xFEBADA11), /* ~= 10^171 */ |
1749 | | U64(0xA59BC234, 0xDB398C25), U64(0x43FAB983, 0x7E699095), /* ~= 10^172 */ |
1750 | | U64(0xCF02B2C2, 0x1207EF2E), U64(0x94F967E4, 0x5E03F4BB), /* ~= 10^173 */ |
1751 | | U64(0x8161AFB9, 0x4B44F57D), U64(0x1D1BE0EE, 0xBAC278F5), /* ~= 10^174 */ |
1752 | | U64(0xA1BA1BA7, 0x9E1632DC), U64(0x6462D92A, 0x69731732), /* ~= 10^175 */ |
1753 | | U64(0xCA28A291, 0x859BBF93), U64(0x7D7B8F75, 0x03CFDCFE), /* ~= 10^176 */ |
1754 | | U64(0xFCB2CB35, 0xE702AF78), U64(0x5CDA7352, 0x44C3D43E), /* ~= 10^177 */ |
1755 | | U64(0x9DEFBF01, 0xB061ADAB), U64(0x3A088813, 0x6AFA64A7), /* ~= 10^178 */ |
1756 | | U64(0xC56BAEC2, 0x1C7A1916), U64(0x088AAA18, 0x45B8FDD0), /* ~= 10^179 */ |
1757 | | U64(0xF6C69A72, 0xA3989F5B), U64(0x8AAD549E, 0x57273D45), /* ~= 10^180 */ |
1758 | | U64(0x9A3C2087, 0xA63F6399), U64(0x36AC54E2, 0xF678864B), /* ~= 10^181 */ |
1759 | | U64(0xC0CB28A9, 0x8FCF3C7F), U64(0x84576A1B, 0xB416A7DD), /* ~= 10^182 */ |
1760 | | U64(0xF0FDF2D3, 0xF3C30B9F), U64(0x656D44A2, 0xA11C51D5), /* ~= 10^183 */ |
1761 | | U64(0x969EB7C4, 0x7859E743), U64(0x9F644AE5, 0xA4B1B325), /* ~= 10^184 */ |
1762 | | U64(0xBC4665B5, 0x96706114), U64(0x873D5D9F, 0x0DDE1FEE), /* ~= 10^185 */ |
1763 | | U64(0xEB57FF22, 0xFC0C7959), U64(0xA90CB506, 0xD155A7EA), /* ~= 10^186 */ |
1764 | | U64(0x9316FF75, 0xDD87CBD8), U64(0x09A7F124, 0x42D588F2), /* ~= 10^187 */ |
1765 | | U64(0xB7DCBF53, 0x54E9BECE), U64(0x0C11ED6D, 0x538AEB2F), /* ~= 10^188 */ |
1766 | | U64(0xE5D3EF28, 0x2A242E81), U64(0x8F1668C8, 0xA86DA5FA), /* ~= 10^189 */ |
1767 | | U64(0x8FA47579, 0x1A569D10), U64(0xF96E017D, 0x694487BC), /* ~= 10^190 */ |
1768 | | U64(0xB38D92D7, 0x60EC4455), U64(0x37C981DC, 0xC395A9AC), /* ~= 10^191 */ |
1769 | | U64(0xE070F78D, 0x3927556A), U64(0x85BBE253, 0xF47B1417), /* ~= 10^192 */ |
1770 | | U64(0x8C469AB8, 0x43B89562), U64(0x93956D74, 0x78CCEC8E), /* ~= 10^193 */ |
1771 | | U64(0xAF584166, 0x54A6BABB), U64(0x387AC8D1, 0x970027B2), /* ~= 10^194 */ |
1772 | | U64(0xDB2E51BF, 0xE9D0696A), U64(0x06997B05, 0xFCC0319E), /* ~= 10^195 */ |
1773 | | U64(0x88FCF317, 0xF22241E2), U64(0x441FECE3, 0xBDF81F03), /* ~= 10^196 */ |
1774 | | U64(0xAB3C2FDD, 0xEEAAD25A), U64(0xD527E81C, 0xAD7626C3), /* ~= 10^197 */ |
1775 | | U64(0xD60B3BD5, 0x6A5586F1), U64(0x8A71E223, 0xD8D3B074), /* ~= 10^198 */ |
1776 | | U64(0x85C70565, 0x62757456), U64(0xF6872D56, 0x67844E49), /* ~= 10^199 */ |
1777 | | U64(0xA738C6BE, 0xBB12D16C), U64(0xB428F8AC, 0x016561DB), /* ~= 10^200 */ |
1778 | | U64(0xD106F86E, 0x69D785C7), U64(0xE13336D7, 0x01BEBA52), /* ~= 10^201 */ |
1779 | | U64(0x82A45B45, 0x0226B39C), U64(0xECC00246, 0x61173473), /* ~= 10^202 */ |
1780 | | U64(0xA34D7216, 0x42B06084), U64(0x27F002D7, 0xF95D0190), /* ~= 10^203 */ |
1781 | | U64(0xCC20CE9B, 0xD35C78A5), U64(0x31EC038D, 0xF7B441F4), /* ~= 10^204 */ |
1782 | | U64(0xFF290242, 0xC83396CE), U64(0x7E670471, 0x75A15271), /* ~= 10^205 */ |
1783 | | U64(0x9F79A169, 0xBD203E41), U64(0x0F0062C6, 0xE984D386), /* ~= 10^206 */ |
1784 | | U64(0xC75809C4, 0x2C684DD1), U64(0x52C07B78, 0xA3E60868), /* ~= 10^207 */ |
1785 | | U64(0xF92E0C35, 0x37826145), U64(0xA7709A56, 0xCCDF8A82), /* ~= 10^208 */ |
1786 | | U64(0x9BBCC7A1, 0x42B17CCB), U64(0x88A66076, 0x400BB691), /* ~= 10^209 */ |
1787 | | U64(0xC2ABF989, 0x935DDBFE), U64(0x6ACFF893, 0xD00EA435), /* ~= 10^210 */ |
1788 | | U64(0xF356F7EB, 0xF83552FE), U64(0x0583F6B8, 0xC4124D43), /* ~= 10^211 */ |
1789 | | U64(0x98165AF3, 0x7B2153DE), U64(0xC3727A33, 0x7A8B704A), /* ~= 10^212 */ |
1790 | | U64(0xBE1BF1B0, 0x59E9A8D6), U64(0x744F18C0, 0x592E4C5C), /* ~= 10^213 */ |
1791 | | U64(0xEDA2EE1C, 0x7064130C), U64(0x1162DEF0, 0x6F79DF73), /* ~= 10^214 */ |
1792 | | U64(0x9485D4D1, 0xC63E8BE7), U64(0x8ADDCB56, 0x45AC2BA8), /* ~= 10^215 */ |
1793 | | U64(0xB9A74A06, 0x37CE2EE1), U64(0x6D953E2B, 0xD7173692), /* ~= 10^216 */ |
1794 | | U64(0xE8111C87, 0xC5C1BA99), U64(0xC8FA8DB6, 0xCCDD0437), /* ~= 10^217 */ |
1795 | | U64(0x910AB1D4, 0xDB9914A0), U64(0x1D9C9892, 0x400A22A2), /* ~= 10^218 */ |
1796 | | U64(0xB54D5E4A, 0x127F59C8), U64(0x2503BEB6, 0xD00CAB4B), /* ~= 10^219 */ |
1797 | | U64(0xE2A0B5DC, 0x971F303A), U64(0x2E44AE64, 0x840FD61D), /* ~= 10^220 */ |
1798 | | U64(0x8DA471A9, 0xDE737E24), U64(0x5CEAECFE, 0xD289E5D2), /* ~= 10^221 */ |
1799 | | U64(0xB10D8E14, 0x56105DAD), U64(0x7425A83E, 0x872C5F47), /* ~= 10^222 */ |
1800 | | U64(0xDD50F199, 0x6B947518), U64(0xD12F124E, 0x28F77719), /* ~= 10^223 */ |
1801 | | U64(0x8A5296FF, 0xE33CC92F), U64(0x82BD6B70, 0xD99AAA6F), /* ~= 10^224 */ |
1802 | | U64(0xACE73CBF, 0xDC0BFB7B), U64(0x636CC64D, 0x1001550B), /* ~= 10^225 */ |
1803 | | U64(0xD8210BEF, 0xD30EFA5A), U64(0x3C47F7E0, 0x5401AA4E), /* ~= 10^226 */ |
1804 | | U64(0x8714A775, 0xE3E95C78), U64(0x65ACFAEC, 0x34810A71), /* ~= 10^227 */ |
1805 | | U64(0xA8D9D153, 0x5CE3B396), U64(0x7F1839A7, 0x41A14D0D), /* ~= 10^228 */ |
1806 | | U64(0xD31045A8, 0x341CA07C), U64(0x1EDE4811, 0x1209A050), /* ~= 10^229 */ |
1807 | | U64(0x83EA2B89, 0x2091E44D), U64(0x934AED0A, 0xAB460432), /* ~= 10^230 */ |
1808 | | U64(0xA4E4B66B, 0x68B65D60), U64(0xF81DA84D, 0x5617853F), /* ~= 10^231 */ |
1809 | | U64(0xCE1DE406, 0x42E3F4B9), U64(0x36251260, 0xAB9D668E), /* ~= 10^232 */ |
1810 | | U64(0x80D2AE83, 0xE9CE78F3), U64(0xC1D72B7C, 0x6B426019), /* ~= 10^233 */ |
1811 | | U64(0xA1075A24, 0xE4421730), U64(0xB24CF65B, 0x8612F81F), /* ~= 10^234 */ |
1812 | | U64(0xC94930AE, 0x1D529CFC), U64(0xDEE033F2, 0x6797B627), /* ~= 10^235 */ |
1813 | | U64(0xFB9B7CD9, 0xA4A7443C), U64(0x169840EF, 0x017DA3B1), /* ~= 10^236 */ |
1814 | | U64(0x9D412E08, 0x06E88AA5), U64(0x8E1F2895, 0x60EE864E), /* ~= 10^237 */ |
1815 | | U64(0xC491798A, 0x08A2AD4E), U64(0xF1A6F2BA, 0xB92A27E2), /* ~= 10^238 */ |
1816 | | U64(0xF5B5D7EC, 0x8ACB58A2), U64(0xAE10AF69, 0x6774B1DB), /* ~= 10^239 */ |
1817 | | U64(0x9991A6F3, 0xD6BF1765), U64(0xACCA6DA1, 0xE0A8EF29), /* ~= 10^240 */ |
1818 | | U64(0xBFF610B0, 0xCC6EDD3F), U64(0x17FD090A, 0x58D32AF3), /* ~= 10^241 */ |
1819 | | U64(0xEFF394DC, 0xFF8A948E), U64(0xDDFC4B4C, 0xEF07F5B0), /* ~= 10^242 */ |
1820 | | U64(0x95F83D0A, 0x1FB69CD9), U64(0x4ABDAF10, 0x1564F98E), /* ~= 10^243 */ |
1821 | | U64(0xBB764C4C, 0xA7A4440F), U64(0x9D6D1AD4, 0x1ABE37F1), /* ~= 10^244 */ |
1822 | | U64(0xEA53DF5F, 0xD18D5513), U64(0x84C86189, 0x216DC5ED), /* ~= 10^245 */ |
1823 | | U64(0x92746B9B, 0xE2F8552C), U64(0x32FD3CF5, 0xB4E49BB4), /* ~= 10^246 */ |
1824 | | U64(0xB7118682, 0xDBB66A77), U64(0x3FBC8C33, 0x221DC2A1), /* ~= 10^247 */ |
1825 | | U64(0xE4D5E823, 0x92A40515), U64(0x0FABAF3F, 0xEAA5334A), /* ~= 10^248 */ |
1826 | | U64(0x8F05B116, 0x3BA6832D), U64(0x29CB4D87, 0xF2A7400E), /* ~= 10^249 */ |
1827 | | U64(0xB2C71D5B, 0xCA9023F8), U64(0x743E20E9, 0xEF511012), /* ~= 10^250 */ |
1828 | | U64(0xDF78E4B2, 0xBD342CF6), U64(0x914DA924, 0x6B255416), /* ~= 10^251 */ |
1829 | | U64(0x8BAB8EEF, 0xB6409C1A), U64(0x1AD089B6, 0xC2F7548E), /* ~= 10^252 */ |
1830 | | U64(0xAE9672AB, 0xA3D0C320), U64(0xA184AC24, 0x73B529B1), /* ~= 10^253 */ |
1831 | | U64(0xDA3C0F56, 0x8CC4F3E8), U64(0xC9E5D72D, 0x90A2741E), /* ~= 10^254 */ |
1832 | | U64(0x88658996, 0x17FB1871), U64(0x7E2FA67C, 0x7A658892), /* ~= 10^255 */ |
1833 | | U64(0xAA7EEBFB, 0x9DF9DE8D), U64(0xDDBB901B, 0x98FEEAB7), /* ~= 10^256 */ |
1834 | | U64(0xD51EA6FA, 0x85785631), U64(0x552A7422, 0x7F3EA565), /* ~= 10^257 */ |
1835 | | U64(0x8533285C, 0x936B35DE), U64(0xD53A8895, 0x8F87275F), /* ~= 10^258 */ |
1836 | | U64(0xA67FF273, 0xB8460356), U64(0x8A892ABA, 0xF368F137), /* ~= 10^259 */ |
1837 | | U64(0xD01FEF10, 0xA657842C), U64(0x2D2B7569, 0xB0432D85), /* ~= 10^260 */ |
1838 | | U64(0x8213F56A, 0x67F6B29B), U64(0x9C3B2962, 0x0E29FC73), /* ~= 10^261 */ |
1839 | | U64(0xA298F2C5, 0x01F45F42), U64(0x8349F3BA, 0x91B47B8F), /* ~= 10^262 */ |
1840 | | U64(0xCB3F2F76, 0x42717713), U64(0x241C70A9, 0x36219A73), /* ~= 10^263 */ |
1841 | | U64(0xFE0EFB53, 0xD30DD4D7), U64(0xED238CD3, 0x83AA0110), /* ~= 10^264 */ |
1842 | | U64(0x9EC95D14, 0x63E8A506), U64(0xF4363804, 0x324A40AA), /* ~= 10^265 */ |
1843 | | U64(0xC67BB459, 0x7CE2CE48), U64(0xB143C605, 0x3EDCD0D5), /* ~= 10^266 */ |
1844 | | U64(0xF81AA16F, 0xDC1B81DA), U64(0xDD94B786, 0x8E94050A), /* ~= 10^267 */ |
1845 | | U64(0x9B10A4E5, 0xE9913128), U64(0xCA7CF2B4, 0x191C8326), /* ~= 10^268 */ |
1846 | | U64(0xC1D4CE1F, 0x63F57D72), U64(0xFD1C2F61, 0x1F63A3F0), /* ~= 10^269 */ |
1847 | | U64(0xF24A01A7, 0x3CF2DCCF), U64(0xBC633B39, 0x673C8CEC), /* ~= 10^270 */ |
1848 | | U64(0x976E4108, 0x8617CA01), U64(0xD5BE0503, 0xE085D813), /* ~= 10^271 */ |
1849 | | U64(0xBD49D14A, 0xA79DBC82), U64(0x4B2D8644, 0xD8A74E18), /* ~= 10^272 */ |
1850 | | U64(0xEC9C459D, 0x51852BA2), U64(0xDDF8E7D6, 0x0ED1219E), /* ~= 10^273 */ |
1851 | | U64(0x93E1AB82, 0x52F33B45), U64(0xCABB90E5, 0xC942B503), /* ~= 10^274 */ |
1852 | | U64(0xB8DA1662, 0xE7B00A17), U64(0x3D6A751F, 0x3B936243), /* ~= 10^275 */ |
1853 | | U64(0xE7109BFB, 0xA19C0C9D), U64(0x0CC51267, 0x0A783AD4), /* ~= 10^276 */ |
1854 | | U64(0x906A617D, 0x450187E2), U64(0x27FB2B80, 0x668B24C5), /* ~= 10^277 */ |
1855 | | U64(0xB484F9DC, 0x9641E9DA), U64(0xB1F9F660, 0x802DEDF6), /* ~= 10^278 */ |
1856 | | U64(0xE1A63853, 0xBBD26451), U64(0x5E7873F8, 0xA0396973), /* ~= 10^279 */ |
1857 | | U64(0x8D07E334, 0x55637EB2), U64(0xDB0B487B, 0x6423E1E8), /* ~= 10^280 */ |
1858 | | U64(0xB049DC01, 0x6ABC5E5F), U64(0x91CE1A9A, 0x3D2CDA62), /* ~= 10^281 */ |
1859 | | U64(0xDC5C5301, 0xC56B75F7), U64(0x7641A140, 0xCC7810FB), /* ~= 10^282 */ |
1860 | | U64(0x89B9B3E1, 0x1B6329BA), U64(0xA9E904C8, 0x7FCB0A9D), /* ~= 10^283 */ |
1861 | | U64(0xAC2820D9, 0x623BF429), U64(0x546345FA, 0x9FBDCD44), /* ~= 10^284 */ |
1862 | | U64(0xD732290F, 0xBACAF133), U64(0xA97C1779, 0x47AD4095), /* ~= 10^285 */ |
1863 | | U64(0x867F59A9, 0xD4BED6C0), U64(0x49ED8EAB, 0xCCCC485D), /* ~= 10^286 */ |
1864 | | U64(0xA81F3014, 0x49EE8C70), U64(0x5C68F256, 0xBFFF5A74), /* ~= 10^287 */ |
1865 | | U64(0xD226FC19, 0x5C6A2F8C), U64(0x73832EEC, 0x6FFF3111), /* ~= 10^288 */ |
1866 | | U64(0x83585D8F, 0xD9C25DB7), U64(0xC831FD53, 0xC5FF7EAB), /* ~= 10^289 */ |
1867 | | U64(0xA42E74F3, 0xD032F525), U64(0xBA3E7CA8, 0xB77F5E55), /* ~= 10^290 */ |
1868 | | U64(0xCD3A1230, 0xC43FB26F), U64(0x28CE1BD2, 0xE55F35EB), /* ~= 10^291 */ |
1869 | | U64(0x80444B5E, 0x7AA7CF85), U64(0x7980D163, 0xCF5B81B3), /* ~= 10^292 */ |
1870 | | U64(0xA0555E36, 0x1951C366), U64(0xD7E105BC, 0xC332621F), /* ~= 10^293 */ |
1871 | | U64(0xC86AB5C3, 0x9FA63440), U64(0x8DD9472B, 0xF3FEFAA7), /* ~= 10^294 */ |
1872 | | U64(0xFA856334, 0x878FC150), U64(0xB14F98F6, 0xF0FEB951), /* ~= 10^295 */ |
1873 | | U64(0x9C935E00, 0xD4B9D8D2), U64(0x6ED1BF9A, 0x569F33D3), /* ~= 10^296 */ |
1874 | | U64(0xC3B83581, 0x09E84F07), U64(0x0A862F80, 0xEC4700C8), /* ~= 10^297 */ |
1875 | | U64(0xF4A642E1, 0x4C6262C8), U64(0xCD27BB61, 0x2758C0FA), /* ~= 10^298 */ |
1876 | | U64(0x98E7E9CC, 0xCFBD7DBD), U64(0x8038D51C, 0xB897789C), /* ~= 10^299 */ |
1877 | | U64(0xBF21E440, 0x03ACDD2C), U64(0xE0470A63, 0xE6BD56C3), /* ~= 10^300 */ |
1878 | | U64(0xEEEA5D50, 0x04981478), U64(0x1858CCFC, 0xE06CAC74), /* ~= 10^301 */ |
1879 | | U64(0x95527A52, 0x02DF0CCB), U64(0x0F37801E, 0x0C43EBC8), /* ~= 10^302 */ |
1880 | | U64(0xBAA718E6, 0x8396CFFD), U64(0xD3056025, 0x8F54E6BA), /* ~= 10^303 */ |
1881 | | U64(0xE950DF20, 0x247C83FD), U64(0x47C6B82E, 0xF32A2069), /* ~= 10^304 */ |
1882 | | U64(0x91D28B74, 0x16CDD27E), U64(0x4CDC331D, 0x57FA5441), /* ~= 10^305 */ |
1883 | | U64(0xB6472E51, 0x1C81471D), U64(0xE0133FE4, 0xADF8E952), /* ~= 10^306 */ |
1884 | | U64(0xE3D8F9E5, 0x63A198E5), U64(0x58180FDD, 0xD97723A6), /* ~= 10^307 */ |
1885 | | U64(0x8E679C2F, 0x5E44FF8F), U64(0x570F09EA, 0xA7EA7648), /* ~= 10^308 */ |
1886 | | U64(0xB201833B, 0x35D63F73), U64(0x2CD2CC65, 0x51E513DA), /* ~= 10^309 */ |
1887 | | U64(0xDE81E40A, 0x034BCF4F), U64(0xF8077F7E, 0xA65E58D1), /* ~= 10^310 */ |
1888 | | U64(0x8B112E86, 0x420F6191), U64(0xFB04AFAF, 0x27FAF782), /* ~= 10^311 */ |
1889 | | U64(0xADD57A27, 0xD29339F6), U64(0x79C5DB9A, 0xF1F9B563), /* ~= 10^312 */ |
1890 | | U64(0xD94AD8B1, 0xC7380874), U64(0x18375281, 0xAE7822BC), /* ~= 10^313 */ |
1891 | | U64(0x87CEC76F, 0x1C830548), U64(0x8F229391, 0x0D0B15B5), /* ~= 10^314 */ |
1892 | | U64(0xA9C2794A, 0xE3A3C69A), U64(0xB2EB3875, 0x504DDB22), /* ~= 10^315 */ |
1893 | | U64(0xD433179D, 0x9C8CB841), U64(0x5FA60692, 0xA46151EB), /* ~= 10^316 */ |
1894 | | U64(0x849FEEC2, 0x81D7F328), U64(0xDBC7C41B, 0xA6BCD333), /* ~= 10^317 */ |
1895 | | U64(0xA5C7EA73, 0x224DEFF3), U64(0x12B9B522, 0x906C0800), /* ~= 10^318 */ |
1896 | | U64(0xCF39E50F, 0xEAE16BEF), U64(0xD768226B, 0x34870A00), /* ~= 10^319 */ |
1897 | | U64(0x81842F29, 0xF2CCE375), U64(0xE6A11583, 0x00D46640), /* ~= 10^320 */ |
1898 | | U64(0xA1E53AF4, 0x6F801C53), U64(0x60495AE3, 0xC1097FD0), /* ~= 10^321 */ |
1899 | | U64(0xCA5E89B1, 0x8B602368), U64(0x385BB19C, 0xB14BDFC4), /* ~= 10^322 */ |
1900 | | U64(0xFCF62C1D, 0xEE382C42), U64(0x46729E03, 0xDD9ED7B5), /* ~= 10^323 */ |
1901 | | U64(0x9E19DB92, 0xB4E31BA9), U64(0x6C07A2C2, 0x6A8346D1) /* ~= 10^324 */ |
1902 | | }; |
1903 | | |
1904 | | /** |
1905 | | Get the cached pow10 value from `pow10_sig_table`. |
1906 | | @param exp10 The exponent of pow(10, e). This value must be in the range |
1907 | | `POW10_SIG_TABLE_MIN_EXP` to `POW10_SIG_TABLE_MAX_EXP`. |
1908 | | @param hi The highest 64 bits of pow(10, e). |
1909 | | @param lo The lower 64 bits after `hi`. |
1910 | | */ |
1911 | 4.44M | static_inline void pow10_table_get_sig(i32 exp10, u64 *hi, u64 *lo) { |
1912 | 4.44M | i32 idx = exp10 - (POW10_SIG_TABLE_MIN_EXP); |
1913 | 4.44M | *hi = pow10_sig_table[idx * 2]; |
1914 | 4.44M | *lo = pow10_sig_table[idx * 2 + 1]; |
1915 | 4.44M | } |
1916 | | |
1917 | | /** |
1918 | | Get the exponent (base 2) for the highest 64-bit significand in |
1919 | | `pow10_sig_table`. |
1920 | | */ |
1921 | 290k | static_inline void pow10_table_get_exp(i32 exp10, i32 *exp2) { |
1922 | | /* e2 = floor(log2(pow(10, e))) - 64 + 1 */ |
1923 | | /* = floor(e * log2(10) - 63) */ |
1924 | 290k | *exp2 = (exp10 * 217706 - 4128768) >> 16; |
1925 | 290k | } |
1926 | | |
1927 | | #endif |
1928 | | |
1929 | | |
1930 | | |
1931 | | /*============================================================================== |
1932 | | * MARK: - Number and Bit Utils (Private) |
1933 | | *============================================================================*/ |
1934 | | |
1935 | | /** Convert bits to double. */ |
1936 | 0 | static_inline f64 f64_from_bits(u64 u) { |
1937 | 0 | f64 f; |
1938 | 0 | memcpy(&f, &u, sizeof(u)); |
1939 | 0 | return f; |
1940 | 0 | } |
1941 | | |
1942 | | /** Convert double to bits. */ |
1943 | 0 | static_inline u64 f64_to_bits(f64 f) { |
1944 | 0 | u64 u; |
1945 | 0 | memcpy(&u, &f, sizeof(u)); |
1946 | 0 | return u; |
1947 | 0 | } |
1948 | | |
1949 | | /** Convert float to bits. */ |
1950 | 0 | static_inline u32 f32_to_bits(f32 f) { |
1951 | 0 | u32 u; |
1952 | 0 | memcpy(&u, &f, sizeof(u)); |
1953 | 0 | return u; |
1954 | 0 | } |
1955 | | |
1956 | | /** Get 'infinity' bits with sign. */ |
1957 | 6.75k | static_inline u64 f64_bits_inf(bool sign) { |
1958 | 6.75k | #if YYJSON_HAS_IEEE_754 |
1959 | 6.75k | return F64_BITS_INF | ((u64)sign << 63); |
1960 | | #else |
1961 | | return f64_to_bits(sign ? (f64)-INFINITY : (f64)INFINITY); |
1962 | | #endif |
1963 | 6.75k | } |
1964 | | |
1965 | | /** Returns whether the double value is infinity (not NaN). */ |
1966 | 0 | static_inline bool f64_is_inf(f64 val) { |
1967 | 0 | #if YYJSON_HAS_IEEE_754 |
1968 | 0 | return (f64_to_bits(val) & F64_EXP_MASK) == F64_BITS_INF; |
1969 | 0 | #else |
1970 | 0 | return val >= (f64)INFINITY || val <= (f64)-INFINITY; |
1971 | 0 | #endif |
1972 | 0 | } |
1973 | | |
1974 | | /** Get 'nan' bits with sign. */ |
1975 | 6.43k | static_inline u64 f64_bits_nan(bool sign) { |
1976 | 6.43k | #if YYJSON_HAS_IEEE_754 |
1977 | 6.43k | return F64_BITS_NAN | ((u64)sign << 63); |
1978 | | #else |
1979 | | return f64_to_bits(sign ? (f64)-NAN : (f64)NAN); |
1980 | | #endif |
1981 | 6.43k | } |
1982 | | |
1983 | | /** Casting double to float, allow overflow. */ |
1984 | | #if yyjson_has_attribute(no_sanitize) |
1985 | | __attribute__((no_sanitize("undefined"))) |
1986 | | #elif yyjson_gcc_available(4, 9, 0) |
1987 | | __attribute__((__no_sanitize_undefined__)) |
1988 | | #endif |
1989 | 0 | static_inline f32 f64_to_f32(f64 val) { |
1990 | 0 | return (f32)val; |
1991 | 0 | } |
1992 | | |
1993 | | /** Returns the number of leading 0-bits in value (input should not be 0). */ |
1994 | 681k | static_inline u32 u64_lz_bits(u64 v) { |
1995 | 681k | #if GCC_HAS_CLZLL |
1996 | 681k | return (u32)__builtin_clzll(v); |
1997 | | #elif MSC_HAS_BIT_SCAN_64 |
1998 | | unsigned long r; |
1999 | | _BitScanReverse64(&r, v); |
2000 | | return (u32)63 - (u32)r; |
2001 | | #elif MSC_HAS_BIT_SCAN |
2002 | | unsigned long hi, lo; |
2003 | | bool hi_set = _BitScanReverse(&hi, (u32)(v >> 32)) != 0; |
2004 | | _BitScanReverse(&lo, (u32)v); |
2005 | | hi |= 32; |
2006 | | return (u32)63 - (u32)(hi_set ? hi : lo); |
2007 | | #else |
2008 | | /* branchless, use De Bruijn sequence */ |
2009 | | /* see: https://www.chessprogramming.org/BitScan */ |
2010 | | const u8 table[64] = { |
2011 | | 63, 16, 62, 7, 15, 36, 61, 3, 6, 14, 22, 26, 35, 47, 60, 2, |
2012 | | 9, 5, 28, 11, 13, 21, 42, 19, 25, 31, 34, 40, 46, 52, 59, 1, |
2013 | | 17, 8, 37, 4, 23, 27, 48, 10, 29, 12, 43, 20, 32, 41, 53, 18, |
2014 | | 38, 24, 49, 30, 44, 33, 54, 39, 50, 45, 55, 51, 56, 57, 58, 0 |
2015 | | }; |
2016 | | v |= v >> 1; |
2017 | | v |= v >> 2; |
2018 | | v |= v >> 4; |
2019 | | v |= v >> 8; |
2020 | | v |= v >> 16; |
2021 | | v |= v >> 32; |
2022 | | return table[(v * U64(0x03F79D71, 0xB4CB0A89)) >> 58]; |
2023 | | #endif |
2024 | 681k | } |
2025 | | |
2026 | | /** Returns the number of trailing 0-bits in value (input should not be 0). */ |
2027 | 2.01M | static_inline u32 u64_tz_bits(u64 v) { |
2028 | 2.01M | #if GCC_HAS_CTZLL |
2029 | 2.01M | return (u32)__builtin_ctzll(v); |
2030 | | #elif MSC_HAS_BIT_SCAN_64 |
2031 | | unsigned long r; |
2032 | | _BitScanForward64(&r, v); |
2033 | | return (u32)r; |
2034 | | #elif MSC_HAS_BIT_SCAN |
2035 | | unsigned long lo, hi; |
2036 | | bool lo_set = _BitScanForward(&lo, (u32)(v)) != 0; |
2037 | | _BitScanForward(&hi, (u32)(v >> 32)); |
2038 | | hi += 32; |
2039 | | return lo_set ? lo : hi; |
2040 | | #else |
2041 | | /* branchless, use De Bruijn sequence */ |
2042 | | /* see: https://www.chessprogramming.org/BitScan */ |
2043 | | const u8 table[64] = { |
2044 | | 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, |
2045 | | 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, |
2046 | | 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, |
2047 | | 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 |
2048 | | }; |
2049 | | return table[((v & (~v + 1)) * U64(0x022FDD63, 0xCC95386D)) >> 58]; |
2050 | | #endif |
2051 | 2.01M | } |
2052 | | |
2053 | | /** Multiplies two 64-bit unsigned integers (a * b), |
2054 | | returns the 128-bit result as 'hi' and 'lo'. */ |
2055 | 5.18M | static_inline void u128_mul(u64 a, u64 b, u64 *hi, u64 *lo) { |
2056 | 5.18M | #if YYJSON_HAS_INT128 |
2057 | 5.18M | u128 m = (u128)a * b; |
2058 | 5.18M | *hi = (u64)(m >> 64); |
2059 | 5.18M | *lo = (u64)(m); |
2060 | | #elif MSC_HAS_UMUL128 |
2061 | | *lo = _umul128(a, b, hi); |
2062 | | #else |
2063 | | u32 a0 = (u32)(a), a1 = (u32)(a >> 32); |
2064 | | u32 b0 = (u32)(b), b1 = (u32)(b >> 32); |
2065 | | u64 p00 = (u64)a0 * b0, p01 = (u64)a0 * b1; |
2066 | | u64 p10 = (u64)a1 * b0, p11 = (u64)a1 * b1; |
2067 | | u64 m0 = p01 + (p00 >> 32); |
2068 | | u32 m00 = (u32)(m0), m01 = (u32)(m0 >> 32); |
2069 | | u64 m1 = p10 + m00; |
2070 | | u32 m10 = (u32)(m1), m11 = (u32)(m1 >> 32); |
2071 | | *hi = p11 + m01 + m11; |
2072 | | *lo = ((u64)m10 << 32) | (u32)p00; |
2073 | | #endif |
2074 | 5.18M | } |
2075 | | |
2076 | | /** Multiplies two 64-bit unsigned integers and add a value (a * b + c), |
2077 | | returns the 128-bit result as 'hi' and 'lo'. */ |
2078 | 15.2M | static_inline void u128_mul_add(u64 a, u64 b, u64 c, u64 *hi, u64 *lo) { |
2079 | 15.2M | #if YYJSON_HAS_INT128 |
2080 | 15.2M | u128 m = (u128)a * b + c; |
2081 | 15.2M | *hi = (u64)(m >> 64); |
2082 | 15.2M | *lo = (u64)(m); |
2083 | | #else |
2084 | | u64 h, l, t; |
2085 | | u128_mul(a, b, &h, &l); |
2086 | | t = l + c; |
2087 | | h += (u64)(((t < l) | (t < c))); |
2088 | | *hi = h; |
2089 | | *lo = t; |
2090 | | #endif |
2091 | 15.2M | } |
2092 | | |
2093 | | |
2094 | | |
2095 | | /*============================================================================== |
2096 | | * MARK: - File Utils (Private) |
2097 | | * These functions are used to read and write JSON files. |
2098 | | *============================================================================*/ |
2099 | | |
2100 | | #if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE |
2101 | | |
2102 | | #define YYJSON_FOPEN_E |
2103 | | #if !defined(_MSC_VER) && defined(__GLIBC__) && defined(__GLIBC_PREREQ) |
2104 | | # if __GLIBC_PREREQ(2, 7) |
2105 | | # undef YYJSON_FOPEN_E |
2106 | 0 | # define YYJSON_FOPEN_E "e" /* glibc extension to enable O_CLOEXEC */ |
2107 | | # endif |
2108 | | #endif |
2109 | | |
2110 | 0 | static_inline FILE *fopen_safe(const char *path, const char *mode) { |
2111 | | #if YYJSON_MSC_VER >= 1400 |
2112 | | FILE *file = NULL; |
2113 | | if (fopen_s(&file, path, mode) != 0) return NULL; |
2114 | | return file; |
2115 | | #else |
2116 | 0 | return fopen(path, mode); |
2117 | 0 | #endif |
2118 | 0 | } |
2119 | | |
2120 | 0 | static_inline FILE *fopen_readonly(const char *path) { |
2121 | 0 | return fopen_safe(path, "rb" YYJSON_FOPEN_E); |
2122 | 0 | } |
2123 | | |
2124 | 0 | static_inline FILE *fopen_writeonly(const char *path) { |
2125 | 0 | return fopen_safe(path, "wb" YYJSON_FOPEN_E); |
2126 | 0 | } |
2127 | | |
2128 | 0 | static_inline usize fread_safe(void *buf, usize size, FILE *file) { |
2129 | | #if YYJSON_MSC_VER >= 1400 |
2130 | | return fread_s(buf, size, 1, size, file); |
2131 | | #else |
2132 | 0 | return fread(buf, 1, size, file); |
2133 | 0 | #endif |
2134 | 0 | } |
2135 | | |
2136 | | #endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */ |
2137 | | |
2138 | | |
2139 | | |
2140 | | /*============================================================================== |
2141 | | * MARK: - Size Utils (Private) |
2142 | | * These functions are used for memory allocation. |
2143 | | *============================================================================*/ |
2144 | | |
2145 | | /** Returns whether the size is overflow after increment. */ |
2146 | 0 | static_inline bool size_add_is_overflow(usize size, usize add) { |
2147 | 0 | return size > (size + add); |
2148 | 0 | } |
2149 | | |
2150 | | /** Returns whether the size is power of 2 (size should not be 0). */ |
2151 | 36.5k | static_inline bool size_is_pow2(usize size) { |
2152 | 36.5k | return (size & (size - 1)) == 0; |
2153 | 36.5k | } |
2154 | | |
2155 | | /** Align size upwards (may overflow). */ |
2156 | 36.5k | static_inline usize size_align_up(usize size, usize align) { |
2157 | 36.5k | if (size_is_pow2(align)) { |
2158 | 36.5k | return (size + (align - 1)) & ~(align - 1); |
2159 | 36.5k | } else { |
2160 | 0 | return size + align - (size + align - 1) % align - 1; |
2161 | 0 | } |
2162 | 36.5k | } |
2163 | | |
2164 | | /** Align size downwards. */ |
2165 | 0 | static_inline usize size_align_down(usize size, usize align) { |
2166 | 0 | if (size_is_pow2(align)) { |
2167 | 0 | return size & ~(align - 1); |
2168 | 0 | } else { |
2169 | 0 | return size - (size % align); |
2170 | 0 | } |
2171 | 0 | } |
2172 | | |
2173 | | /** Align address upwards (may overflow). */ |
2174 | 0 | static_inline void *mem_align_up(void *mem, usize align) { |
2175 | 0 | usize size; |
2176 | 0 | memcpy(&size, &mem, sizeof(usize)); |
2177 | 0 | size = size_align_up(size, align); |
2178 | 0 | memcpy(&mem, &size, sizeof(usize)); |
2179 | 0 | return mem; |
2180 | 0 | } |
2181 | | |
2182 | | |
2183 | | |
2184 | | /*============================================================================== |
2185 | | * MARK: - Null Memory Allocator (Private) |
2186 | | * This allocator is just a placeholder to ensure that the internal |
2187 | | * malloc/realloc/free function pointers are not null. |
2188 | | *============================================================================*/ |
2189 | | |
2190 | 0 | static void *null_malloc(void *ctx, usize size) { |
2191 | 0 | return NULL; |
2192 | 0 | } |
2193 | | |
2194 | 0 | static void *null_realloc(void *ctx, void *ptr, usize old_size, usize size) { |
2195 | 0 | return NULL; |
2196 | 0 | } |
2197 | | |
2198 | 0 | static void null_free(void *ctx, void *ptr) { |
2199 | 0 | return; |
2200 | 0 | } |
2201 | | |
2202 | | static const yyjson_alc YYJSON_NULL_ALC = { |
2203 | | null_malloc, null_realloc, null_free, NULL |
2204 | | }; |
2205 | | |
2206 | | |
2207 | | |
2208 | | /*============================================================================== |
2209 | | * MARK: - Default Memory Allocator (Private) |
2210 | | * This is a simple libc memory allocator wrapper. |
2211 | | *============================================================================*/ |
2212 | | |
2213 | | #if defined(YYJSON_CUSTOM_ALC) |
2214 | | |
2215 | | /* user-provided via macro */ |
2216 | | extern const yyjson_alc YYJSON_CUSTOM_ALC; |
2217 | | #define YYJSON_DEFAULT_ALC YYJSON_CUSTOM_ALC |
2218 | | |
2219 | | #elif YYJSON_FREESTANDING |
2220 | | |
2221 | | /* null allocator */ |
2222 | | static const yyjson_alc YYJSON_DEFAULT_ALC = { |
2223 | | null_malloc, null_realloc, null_free, NULL |
2224 | | }; |
2225 | | |
2226 | | #else /* YYJSON_FREESTANDING */ |
2227 | | |
2228 | | /* default libc allocator */ |
2229 | 0 | static void *default_malloc(void *ctx, usize size) { |
2230 | 0 | return malloc(size); |
2231 | 0 | } |
2232 | 0 | static void *default_realloc(void *ctx, void *ptr, usize old_size, usize size) { |
2233 | 0 | return realloc(ptr, size); |
2234 | 0 | } |
2235 | 0 | static void default_free(void *ctx, void *ptr) { |
2236 | 0 | free(ptr); |
2237 | 0 | } |
2238 | | static const yyjson_alc YYJSON_DEFAULT_ALC = { |
2239 | | default_malloc, default_realloc, default_free, NULL |
2240 | | }; |
2241 | | |
2242 | | #endif /* YYJSON_FREESTANDING */ |
2243 | | |
2244 | | |
2245 | | |
2246 | | /*============================================================================== |
2247 | | * MARK: - Pool Memory Allocator (Public) |
2248 | | * This allocator is initialized with a fixed-size buffer. |
2249 | | * The buffer is split into multiple memory chunks for memory allocation. |
2250 | | *============================================================================*/ |
2251 | | |
2252 | | /** memory chunk header */ |
2253 | | typedef struct pool_chunk { |
2254 | | usize size; /* chunk memory size, including chunk header */ |
2255 | | struct pool_chunk *next; /* linked list, nullable */ |
2256 | | /* char mem[]; flexible array member */ |
2257 | | } pool_chunk; |
2258 | | |
2259 | | /** allocator ctx header */ |
2260 | | typedef struct pool_ctx { |
2261 | | usize size; /* total memory size, including ctx header */ |
2262 | | pool_chunk *free_list; /* linked list, nullable */ |
2263 | | /* pool_chunk chunks[]; flexible array member */ |
2264 | | } pool_ctx; |
2265 | | |
2266 | | /** align up the input size to chunk size */ |
2267 | 0 | static_inline void pool_size_align(usize *size) { |
2268 | 0 | *size = size_align_up(*size, sizeof(pool_chunk)) + sizeof(pool_chunk); |
2269 | 0 | } |
2270 | | |
2271 | 0 | static void *pool_malloc(void *ctx_ptr, usize size) { |
2272 | | /* assert(size != 0) */ |
2273 | 0 | pool_ctx *ctx = (pool_ctx *)ctx_ptr; |
2274 | 0 | pool_chunk *next, *prev = NULL, *cur = ctx->free_list; |
2275 | |
|
2276 | 0 | if (unlikely(size >= ctx->size)) return NULL; |
2277 | 0 | pool_size_align(&size); |
2278 | |
|
2279 | 0 | while (cur) { |
2280 | 0 | if (cur->size < size) { |
2281 | | /* not enough space, try next chunk */ |
2282 | 0 | prev = cur; |
2283 | 0 | cur = cur->next; |
2284 | 0 | continue; |
2285 | 0 | } |
2286 | 0 | if (cur->size >= size + sizeof(pool_chunk) * 2) { |
2287 | | /* too much space, split this chunk */ |
2288 | 0 | next = (pool_chunk *)(void *)((u8 *)cur + size); |
2289 | 0 | next->size = cur->size - size; |
2290 | 0 | next->next = cur->next; |
2291 | 0 | cur->size = size; |
2292 | 0 | } else { |
2293 | | /* just enough space, use whole chunk */ |
2294 | 0 | next = cur->next; |
2295 | 0 | } |
2296 | 0 | if (prev) prev->next = next; |
2297 | 0 | else ctx->free_list = next; |
2298 | 0 | return (void *)(cur + 1); |
2299 | 0 | } |
2300 | 0 | return NULL; |
2301 | 0 | } |
2302 | | |
2303 | 0 | static void pool_free(void *ctx_ptr, void *ptr) { |
2304 | | /* assert(ptr != NULL) */ |
2305 | 0 | pool_ctx *ctx = (pool_ctx *)ctx_ptr; |
2306 | 0 | pool_chunk *cur = ((pool_chunk *)ptr) - 1; |
2307 | 0 | pool_chunk *prev = NULL, *next = ctx->free_list; |
2308 | |
|
2309 | 0 | while (next && next < cur) { |
2310 | 0 | prev = next; |
2311 | 0 | next = next->next; |
2312 | 0 | } |
2313 | 0 | if (prev) prev->next = cur; |
2314 | 0 | else ctx->free_list = cur; |
2315 | 0 | cur->next = next; |
2316 | |
|
2317 | 0 | if (next && ((u8 *)cur + cur->size) == (u8 *)next) { |
2318 | | /* merge cur to higher chunk */ |
2319 | 0 | cur->size += next->size; |
2320 | 0 | cur->next = next->next; |
2321 | 0 | } |
2322 | 0 | if (prev && ((u8 *)prev + prev->size) == (u8 *)cur) { |
2323 | | /* merge cur to lower chunk */ |
2324 | 0 | prev->size += cur->size; |
2325 | 0 | prev->next = cur->next; |
2326 | 0 | } |
2327 | 0 | } |
2328 | | |
2329 | | static void *pool_realloc(void *ctx_ptr, void *ptr, |
2330 | 0 | usize old_size, usize size) { |
2331 | | /* assert(ptr != NULL && size != 0 && old_size < size) */ |
2332 | 0 | pool_ctx *ctx = (pool_ctx *)ctx_ptr; |
2333 | 0 | pool_chunk *cur = ((pool_chunk *)ptr) - 1, *prev, *next, *tmp; |
2334 | | |
2335 | | /* check size */ |
2336 | 0 | if (unlikely(size >= ctx->size)) return NULL; |
2337 | 0 | pool_size_align(&old_size); |
2338 | 0 | pool_size_align(&size); |
2339 | 0 | if (unlikely(old_size == size)) return ptr; |
2340 | | |
2341 | | /* find next and prev chunk */ |
2342 | 0 | prev = NULL; |
2343 | 0 | next = ctx->free_list; |
2344 | 0 | while (next && next < cur) { |
2345 | 0 | prev = next; |
2346 | 0 | next = next->next; |
2347 | 0 | } |
2348 | |
|
2349 | 0 | if ((u8 *)cur + cur->size == (u8 *)next && cur->size + next->size >= size) { |
2350 | | /* merge to higher chunk if they are contiguous */ |
2351 | 0 | usize free_size = cur->size + next->size - size; |
2352 | 0 | if (free_size > sizeof(pool_chunk) * 2) { |
2353 | 0 | tmp = (pool_chunk *)(void *)((u8 *)cur + size); |
2354 | 0 | if (prev) prev->next = tmp; |
2355 | 0 | else ctx->free_list = tmp; |
2356 | 0 | tmp->next = next->next; |
2357 | 0 | tmp->size = free_size; |
2358 | 0 | cur->size = size; |
2359 | 0 | } else { |
2360 | 0 | if (prev) prev->next = next->next; |
2361 | 0 | else ctx->free_list = next->next; |
2362 | 0 | cur->size += next->size; |
2363 | 0 | } |
2364 | 0 | return ptr; |
2365 | 0 | } else { |
2366 | | /* fallback to malloc and memcpy */ |
2367 | 0 | void *new_ptr = pool_malloc(ctx_ptr, size - sizeof(pool_chunk)); |
2368 | 0 | if (new_ptr) { |
2369 | 0 | memcpy(new_ptr, ptr, cur->size - sizeof(pool_chunk)); |
2370 | 0 | pool_free(ctx_ptr, ptr); |
2371 | 0 | } |
2372 | 0 | return new_ptr; |
2373 | 0 | } |
2374 | 0 | } |
2375 | | |
2376 | 0 | bool yyjson_alc_pool_init(yyjson_alc *alc, void *buf, usize size) { |
2377 | 0 | pool_chunk *chunk; |
2378 | 0 | pool_ctx *ctx; |
2379 | |
|
2380 | 0 | if (unlikely(!alc)) return false; |
2381 | 0 | *alc = YYJSON_NULL_ALC; |
2382 | 0 | if (size < sizeof(pool_ctx) * 4) return false; |
2383 | 0 | ctx = (pool_ctx *)mem_align_up(buf, sizeof(pool_ctx)); |
2384 | 0 | if (unlikely(!ctx)) return false; |
2385 | 0 | size -= (usize)((u8 *)ctx - (u8 *)buf); |
2386 | 0 | size = size_align_down(size, sizeof(pool_ctx)); |
2387 | |
|
2388 | 0 | chunk = (pool_chunk *)(ctx + 1); |
2389 | 0 | chunk->size = size - sizeof(pool_ctx); |
2390 | 0 | chunk->next = NULL; |
2391 | 0 | ctx->size = size; |
2392 | 0 | ctx->free_list = chunk; |
2393 | |
|
2394 | 0 | alc->malloc = pool_malloc; |
2395 | 0 | alc->realloc = pool_realloc; |
2396 | 0 | alc->free = pool_free; |
2397 | 0 | alc->ctx = (void *)ctx; |
2398 | 0 | return true; |
2399 | 0 | } |
2400 | | |
2401 | | |
2402 | | |
2403 | | /*============================================================================== |
2404 | | * MARK: - Dynamic Memory Allocator (Public) |
2405 | | * This allocator allocates memory on demand and does not immediately release |
2406 | | * unused memory. Instead, it places the unused memory into a freelist for |
2407 | | * potential reuse in the future. It is only when the entire allocator is |
2408 | | * destroyed that all previously allocated memory is released at once. |
2409 | | *============================================================================*/ |
2410 | | |
2411 | | /** memory chunk header */ |
2412 | | typedef struct dyn_chunk { |
2413 | | usize size; /* chunk size, including header */ |
2414 | | struct dyn_chunk *next; |
2415 | | /* char mem[]; flexible array member */ |
2416 | | } dyn_chunk; |
2417 | | |
2418 | | /** allocator ctx header */ |
2419 | | typedef struct { |
2420 | | dyn_chunk free_list; /* dummy header, sorted from small to large */ |
2421 | | dyn_chunk used_list; /* dummy header */ |
2422 | | } dyn_ctx; |
2423 | | |
2424 | | /** align up the input size to chunk size */ |
2425 | 0 | static_inline bool dyn_size_align(usize *size) { |
2426 | 0 | usize alc_size = *size + sizeof(dyn_chunk); |
2427 | 0 | alc_size = size_align_up(alc_size, YYJSON_ALC_DYN_MIN_SIZE); |
2428 | 0 | if (unlikely(alc_size < *size)) return false; /* overflow */ |
2429 | 0 | *size = alc_size; |
2430 | 0 | return true; |
2431 | 0 | } |
2432 | | |
2433 | | /** remove a chunk from list (the chunk must already be in the list) */ |
2434 | 0 | static_inline void dyn_chunk_list_remove(dyn_chunk *list, dyn_chunk *chunk) { |
2435 | 0 | dyn_chunk *prev = list, *cur; |
2436 | 0 | for (cur = prev->next; cur; cur = cur->next) { |
2437 | 0 | if (cur == chunk) { |
2438 | 0 | prev->next = cur->next; |
2439 | 0 | cur->next = NULL; |
2440 | 0 | return; |
2441 | 0 | } |
2442 | 0 | prev = cur; |
2443 | 0 | } |
2444 | 0 | } |
2445 | | |
2446 | | /** add a chunk to list header (the chunk must not be in the list) */ |
2447 | 0 | static_inline void dyn_chunk_list_add(dyn_chunk *list, dyn_chunk *chunk) { |
2448 | 0 | chunk->next = list->next; |
2449 | 0 | list->next = chunk; |
2450 | 0 | } |
2451 | | |
2452 | 0 | static void *dyn_malloc(void *ctx_ptr, usize size) { |
2453 | | /* assert(size != 0) */ |
2454 | 0 | const yyjson_alc def = YYJSON_DEFAULT_ALC; |
2455 | 0 | dyn_ctx *ctx = (dyn_ctx *)ctx_ptr; |
2456 | 0 | dyn_chunk *chunk, *prev; |
2457 | 0 | if (unlikely(!dyn_size_align(&size))) return NULL; |
2458 | | |
2459 | | /* freelist is empty, create new chunk */ |
2460 | 0 | if (!ctx->free_list.next) { |
2461 | 0 | chunk = (dyn_chunk *)def.malloc(def.ctx, size); |
2462 | 0 | if (unlikely(!chunk)) return NULL; |
2463 | 0 | chunk->size = size; |
2464 | 0 | chunk->next = NULL; |
2465 | 0 | dyn_chunk_list_add(&ctx->used_list, chunk); |
2466 | 0 | return (void *)(chunk + 1); |
2467 | 0 | } |
2468 | | |
2469 | | /* find a large enough chunk, or resize the largest chunk */ |
2470 | 0 | prev = &ctx->free_list; |
2471 | 0 | while (true) { |
2472 | 0 | chunk = prev->next; |
2473 | 0 | if (chunk->size >= size) { /* enough size, reuse this chunk */ |
2474 | 0 | prev->next = chunk->next; |
2475 | 0 | dyn_chunk_list_add(&ctx->used_list, chunk); |
2476 | 0 | return (void *)(chunk + 1); |
2477 | 0 | } |
2478 | 0 | if (!chunk->next) { /* resize the largest chunk */ |
2479 | 0 | chunk = (dyn_chunk *)def.realloc(def.ctx, chunk, chunk->size, size); |
2480 | 0 | if (unlikely(!chunk)) return NULL; |
2481 | 0 | prev->next = NULL; |
2482 | 0 | chunk->size = size; |
2483 | 0 | dyn_chunk_list_add(&ctx->used_list, chunk); |
2484 | 0 | return (void *)(chunk + 1); |
2485 | 0 | } |
2486 | 0 | prev = chunk; |
2487 | 0 | } |
2488 | 0 | } |
2489 | | |
2490 | | static void *dyn_realloc(void *ctx_ptr, void *ptr, |
2491 | 0 | usize old_size, usize size) { |
2492 | | /* assert(ptr != NULL && size != 0 && old_size < size) */ |
2493 | 0 | const yyjson_alc def = YYJSON_DEFAULT_ALC; |
2494 | 0 | dyn_ctx *ctx = (dyn_ctx *)ctx_ptr; |
2495 | 0 | dyn_chunk *new_chunk, *chunk = (dyn_chunk *)ptr - 1; |
2496 | 0 | if (unlikely(!dyn_size_align(&size))) return NULL; |
2497 | 0 | if (chunk->size >= size) return ptr; |
2498 | | |
2499 | 0 | dyn_chunk_list_remove(&ctx->used_list, chunk); |
2500 | 0 | new_chunk = (dyn_chunk *)def.realloc(def.ctx, chunk, chunk->size, size); |
2501 | 0 | if (likely(new_chunk)) { |
2502 | 0 | new_chunk->size = size; |
2503 | 0 | chunk = new_chunk; |
2504 | 0 | } |
2505 | 0 | dyn_chunk_list_add(&ctx->used_list, chunk); |
2506 | 0 | return new_chunk ? (void *)(new_chunk + 1) : NULL; |
2507 | 0 | } |
2508 | | |
2509 | 0 | static void dyn_free(void *ctx_ptr, void *ptr) { |
2510 | | /* assert(ptr != NULL) */ |
2511 | 0 | dyn_ctx *ctx = (dyn_ctx *)ctx_ptr; |
2512 | 0 | dyn_chunk *chunk = (dyn_chunk *)ptr - 1, *prev; |
2513 | |
|
2514 | 0 | dyn_chunk_list_remove(&ctx->used_list, chunk); |
2515 | 0 | for (prev = &ctx->free_list; prev; prev = prev->next) { |
2516 | 0 | if (!prev->next || prev->next->size >= chunk->size) { |
2517 | 0 | chunk->next = prev->next; |
2518 | 0 | prev->next = chunk; |
2519 | 0 | break; |
2520 | 0 | } |
2521 | 0 | } |
2522 | 0 | } |
2523 | | |
2524 | 0 | yyjson_alc *yyjson_alc_dyn_new(void) { |
2525 | 0 | const yyjson_alc def = YYJSON_DEFAULT_ALC; |
2526 | 0 | usize hdr_len = sizeof(yyjson_alc) + sizeof(dyn_ctx); |
2527 | 0 | yyjson_alc *alc; |
2528 | 0 | dyn_ctx *ctx; |
2529 | 0 | alc = (yyjson_alc *)def.malloc(def.ctx, hdr_len); |
2530 | 0 | if (unlikely(!alc)) return NULL; |
2531 | 0 | ctx = (dyn_ctx *)(void *)(alc + 1); |
2532 | 0 | alc->malloc = dyn_malloc; |
2533 | 0 | alc->realloc = dyn_realloc; |
2534 | 0 | alc->free = dyn_free; |
2535 | 0 | alc->ctx = alc + 1; |
2536 | 0 | memset(ctx, 0, sizeof(*ctx)); |
2537 | 0 | return alc; |
2538 | 0 | } |
2539 | | |
2540 | 0 | void yyjson_alc_dyn_free(yyjson_alc *alc) { |
2541 | 0 | const yyjson_alc def = YYJSON_DEFAULT_ALC; |
2542 | 0 | dyn_ctx *ctx; |
2543 | 0 | dyn_chunk *chunk, *next; |
2544 | 0 | if (unlikely(!alc)) return; |
2545 | 0 | ctx = (dyn_ctx *)(void *)(alc + 1); |
2546 | 0 | for (chunk = ctx->free_list.next; chunk; chunk = next) { |
2547 | 0 | next = chunk->next; |
2548 | 0 | def.free(def.ctx, chunk); |
2549 | 0 | } |
2550 | 0 | for (chunk = ctx->used_list.next; chunk; chunk = next) { |
2551 | 0 | next = chunk->next; |
2552 | 0 | def.free(def.ctx, chunk); |
2553 | 0 | } |
2554 | 0 | def.free(def.ctx, alc); |
2555 | 0 | } |
2556 | | |
2557 | | |
2558 | | |
2559 | | /*============================================================================== |
2560 | | * MARK: - JSON Struct Utils (Public) |
2561 | | * These functions are used for creating, copying, releasing, and comparing |
2562 | | * JSON documents and values. They are widely used throughout this library. |
2563 | | *============================================================================*/ |
2564 | | |
2565 | | static_inline void unsafe_yyjson_str_pool_release(yyjson_str_pool *pool, |
2566 | 30.5k | yyjson_alc *alc) { |
2567 | 30.5k | yyjson_str_chunk *chunk = pool->chunks, *next; |
2568 | 51.0k | while (chunk) { |
2569 | 20.4k | next = chunk->next; |
2570 | 20.4k | alc->free(alc->ctx, chunk); |
2571 | 20.4k | chunk = next; |
2572 | 20.4k | } |
2573 | 30.5k | } |
2574 | | |
2575 | | static_inline void unsafe_yyjson_val_pool_release(yyjson_val_pool *pool, |
2576 | 30.5k | yyjson_alc *alc) { |
2577 | 30.5k | yyjson_val_chunk *chunk = pool->chunks, *next; |
2578 | 76.2k | while (chunk) { |
2579 | 45.7k | next = chunk->next; |
2580 | 45.7k | alc->free(alc->ctx, chunk); |
2581 | 45.7k | chunk = next; |
2582 | 45.7k | } |
2583 | 30.5k | } |
2584 | | |
2585 | | bool unsafe_yyjson_str_pool_grow(yyjson_str_pool *pool, |
2586 | 20.5k | const yyjson_alc *alc, usize len) { |
2587 | 20.5k | yyjson_str_chunk *chunk; |
2588 | 20.5k | usize size, max_len; |
2589 | | |
2590 | | /* create a new chunk */ |
2591 | 20.5k | max_len = USIZE_MAX - sizeof(yyjson_str_chunk); |
2592 | 20.5k | if (unlikely(len > max_len)) return false; |
2593 | 20.5k | size = len + sizeof(yyjson_str_chunk); |
2594 | 20.5k | size = yyjson_max(pool->chunk_size, size); |
2595 | 20.5k | chunk = (yyjson_str_chunk *)alc->malloc(alc->ctx, size); |
2596 | 20.5k | if (unlikely(!chunk)) return false; |
2597 | | |
2598 | | /* insert the new chunk as the head of the linked list */ |
2599 | 20.4k | chunk->next = pool->chunks; |
2600 | 20.4k | chunk->chunk_size = size; |
2601 | 20.4k | pool->chunks = chunk; |
2602 | 20.4k | pool->cur = (char *)chunk + sizeof(yyjson_str_chunk); |
2603 | 20.4k | pool->end = (char *)chunk + size; |
2604 | | |
2605 | | /* the next chunk is twice the size of the current one */ |
2606 | 20.4k | size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max); |
2607 | 20.4k | if (size < pool->chunk_size) size = pool->chunk_size_max; /* overflow */ |
2608 | 20.4k | pool->chunk_size = size; |
2609 | 20.4k | return true; |
2610 | 20.5k | } |
2611 | | |
2612 | | bool unsafe_yyjson_val_pool_grow(yyjson_val_pool *pool, |
2613 | 45.8k | const yyjson_alc *alc, usize count) { |
2614 | 45.8k | yyjson_val_chunk *chunk; |
2615 | 45.8k | usize size, max_count; |
2616 | | |
2617 | | /* create a new chunk */ |
2618 | 45.8k | max_count = USIZE_MAX / sizeof(yyjson_mut_val) - 1; |
2619 | 45.8k | if (unlikely(count > max_count)) return false; |
2620 | 45.8k | size = (count + 1) * sizeof(yyjson_mut_val); |
2621 | 45.8k | size = yyjson_max(pool->chunk_size, size); |
2622 | 45.8k | chunk = (yyjson_val_chunk *)alc->malloc(alc->ctx, size); |
2623 | 45.8k | if (unlikely(!chunk)) return false; |
2624 | | |
2625 | | /* insert the new chunk as the head of the linked list */ |
2626 | 45.7k | chunk->next = pool->chunks; |
2627 | 45.7k | chunk->chunk_size = size; |
2628 | 45.7k | pool->chunks = chunk; |
2629 | 45.7k | pool->cur = (yyjson_mut_val *)(void *)((u8 *)chunk) + 1; |
2630 | 45.7k | pool->end = (yyjson_mut_val *)(void *)((u8 *)chunk + size); |
2631 | | |
2632 | | /* the next chunk is twice the size of the current one */ |
2633 | 45.7k | size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max); |
2634 | 45.7k | if (size < pool->chunk_size) size = pool->chunk_size_max; /* overflow */ |
2635 | 45.7k | pool->chunk_size = size; |
2636 | 45.7k | return true; |
2637 | 45.8k | } |
2638 | | |
2639 | 0 | bool yyjson_mut_doc_set_str_pool_size(yyjson_mut_doc *doc, size_t len) { |
2640 | 0 | usize max_size = USIZE_MAX - sizeof(yyjson_str_chunk); |
2641 | 0 | if (!doc || !len || len > max_size) return false; |
2642 | 0 | doc->str_pool.chunk_size = len + sizeof(yyjson_str_chunk); |
2643 | 0 | return true; |
2644 | 0 | } |
2645 | | |
2646 | 0 | bool yyjson_mut_doc_set_val_pool_size(yyjson_mut_doc *doc, size_t count) { |
2647 | 0 | usize max_count = USIZE_MAX / sizeof(yyjson_mut_val) - 1; |
2648 | 0 | if (!doc || !count || count > max_count) return false; |
2649 | 0 | doc->val_pool.chunk_size = (count + 1) * sizeof(yyjson_mut_val); |
2650 | 0 | return true; |
2651 | 0 | } |
2652 | | |
2653 | 68.8k | void yyjson_mut_doc_free(yyjson_mut_doc *doc) { |
2654 | 68.8k | if (doc) { |
2655 | 30.5k | yyjson_alc alc = doc->alc; |
2656 | 30.5k | memset(&doc->alc, 0, sizeof(alc)); |
2657 | 30.5k | unsafe_yyjson_str_pool_release(&doc->str_pool, &alc); |
2658 | 30.5k | unsafe_yyjson_val_pool_release(&doc->val_pool, &alc); |
2659 | 30.5k | alc.free(alc.ctx, doc); |
2660 | 30.5k | } |
2661 | 68.8k | } |
2662 | | |
2663 | 30.5k | yyjson_mut_doc *yyjson_mut_doc_new(const yyjson_alc *alc) { |
2664 | 30.5k | yyjson_mut_doc *doc; |
2665 | 30.5k | if (!alc) alc = &YYJSON_DEFAULT_ALC; |
2666 | 30.5k | doc = (yyjson_mut_doc *)alc->malloc(alc->ctx, sizeof(yyjson_mut_doc)); |
2667 | 30.5k | if (!doc) return NULL; |
2668 | 30.5k | memset(doc, 0, sizeof(yyjson_mut_doc)); |
2669 | | |
2670 | 30.5k | doc->alc = *alc; |
2671 | 30.5k | doc->str_pool.chunk_size = YYJSON_MUT_DOC_STR_POOL_INIT_SIZE; |
2672 | 30.5k | doc->str_pool.chunk_size_max = YYJSON_MUT_DOC_STR_POOL_MAX_SIZE; |
2673 | 30.5k | doc->val_pool.chunk_size = YYJSON_MUT_DOC_VAL_POOL_INIT_SIZE; |
2674 | 30.5k | doc->val_pool.chunk_size_max = YYJSON_MUT_DOC_VAL_POOL_MAX_SIZE; |
2675 | 30.5k | return doc; |
2676 | 30.5k | } |
2677 | | |
2678 | | yyjson_mut_doc *yyjson_doc_mut_copy(const yyjson_doc *doc, |
2679 | 49.2k | const yyjson_alc *alc) { |
2680 | 49.2k | yyjson_mut_doc *m_doc; |
2681 | 49.2k | yyjson_mut_val *m_val; |
2682 | | |
2683 | 49.2k | if (!doc || !doc->root) return NULL; |
2684 | 11.0k | m_doc = yyjson_mut_doc_new(alc); |
2685 | 11.0k | if (!m_doc) return NULL; |
2686 | 11.0k | m_val = yyjson_val_mut_copy(m_doc, doc->root); |
2687 | 11.0k | if (!m_val) { |
2688 | 0 | yyjson_mut_doc_free(m_doc); |
2689 | 0 | return NULL; |
2690 | 0 | } |
2691 | 11.0k | yyjson_mut_doc_set_root(m_doc, m_val); |
2692 | 11.0k | return m_doc; |
2693 | 11.0k | } |
2694 | | |
2695 | | yyjson_mut_doc *yyjson_mut_doc_mut_copy(const yyjson_mut_doc *doc, |
2696 | 0 | const yyjson_alc *alc) { |
2697 | 0 | yyjson_mut_doc *m_doc; |
2698 | 0 | yyjson_mut_val *m_val; |
2699 | |
|
2700 | 0 | if (!doc) return NULL; |
2701 | 0 | if (!doc->root) return yyjson_mut_doc_new(alc); |
2702 | | |
2703 | 0 | m_doc = yyjson_mut_doc_new(alc); |
2704 | 0 | if (!m_doc) return NULL; |
2705 | 0 | m_val = yyjson_mut_val_mut_copy(m_doc, doc->root); |
2706 | 0 | if (!m_val) { |
2707 | 0 | yyjson_mut_doc_free(m_doc); |
2708 | 0 | return NULL; |
2709 | 0 | } |
2710 | 0 | yyjson_mut_doc_set_root(m_doc, m_val); |
2711 | 0 | return m_doc; |
2712 | 0 | } |
2713 | | |
2714 | | yyjson_mut_val *yyjson_val_mut_copy(yyjson_mut_doc *m_doc, |
2715 | 75.3k | const yyjson_val *i_vals) { |
2716 | | /* |
2717 | | The immutable object or array stores all sub-values in a contiguous memory, |
2718 | | We copy them to another contiguous memory as mutable values, |
2719 | | then reconnect the mutable values with the original relationship. |
2720 | | */ |
2721 | 75.3k | usize i_vals_len; |
2722 | 75.3k | yyjson_mut_val *m_vals, *m_val; |
2723 | 75.3k | yyjson_val *i_val, *i_end; |
2724 | | |
2725 | 75.3k | if (!m_doc || !i_vals) return NULL; |
2726 | 75.3k | i_end = unsafe_yyjson_get_next(i_vals); |
2727 | 75.3k | i_vals_len = (usize)(unsafe_yyjson_get_next(i_vals) - i_vals); |
2728 | 75.3k | m_vals = unsafe_yyjson_mut_val(m_doc, i_vals_len); |
2729 | 75.3k | if (!m_vals) return NULL; |
2730 | 75.3k | i_val = constcast(yyjson_val *)i_vals; |
2731 | 75.3k | m_val = m_vals; |
2732 | | |
2733 | 4.20M | for (; i_val < i_end; i_val++, m_val++) { |
2734 | 4.12M | yyjson_type type = unsafe_yyjson_get_type(i_val); |
2735 | 4.12M | m_val->tag = i_val->tag; |
2736 | 4.12M | m_val->uni.u64 = i_val->uni.u64; |
2737 | 4.12M | if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) { |
2738 | 255k | const char *str = i_val->uni.str; |
2739 | 255k | usize str_len = unsafe_yyjson_get_len(i_val); |
2740 | 255k | m_val->uni.str = unsafe_yyjson_mut_strncpy(m_doc, str, str_len); |
2741 | 255k | if (!m_val->uni.str) return NULL; |
2742 | 3.87M | } else if (type == YYJSON_TYPE_ARR) { |
2743 | 1.01M | usize len = unsafe_yyjson_get_len(i_val); |
2744 | 1.01M | if (len > 0) { |
2745 | 670k | yyjson_val *ii_val = i_val + 1, *ii_next; |
2746 | 670k | yyjson_mut_val *mm_val = m_val + 1, *mm_ctn = m_val, *mm_next; |
2747 | 3.76M | while (len-- > 1) { |
2748 | 3.09M | ii_next = unsafe_yyjson_get_next(ii_val); |
2749 | 3.09M | mm_next = mm_val + (ii_next - ii_val); |
2750 | 3.09M | mm_val->next = mm_next; |
2751 | 3.09M | ii_val = ii_next; |
2752 | 3.09M | mm_val = mm_next; |
2753 | 3.09M | } |
2754 | 670k | mm_val->next = mm_ctn + 1; |
2755 | 670k | mm_ctn->uni.ptr = mm_val; |
2756 | 670k | } |
2757 | 2.85M | } else if (type == YYJSON_TYPE_OBJ) { |
2758 | 55.3k | usize len = unsafe_yyjson_get_len(i_val); |
2759 | 55.3k | if (len > 0) { |
2760 | 33.3k | yyjson_val *ii_key = i_val + 1, *ii_nextkey; |
2761 | 33.3k | yyjson_mut_val *mm_key = m_val + 1, *mm_ctn = m_val; |
2762 | 33.3k | yyjson_mut_val *mm_nextkey; |
2763 | 142k | while (len-- > 1) { |
2764 | 109k | ii_nextkey = unsafe_yyjson_get_next(ii_key + 1); |
2765 | 109k | mm_nextkey = mm_key + (ii_nextkey - ii_key); |
2766 | 109k | mm_key->next = mm_key + 1; |
2767 | 109k | mm_key->next->next = mm_nextkey; |
2768 | 109k | ii_key = ii_nextkey; |
2769 | 109k | mm_key = mm_nextkey; |
2770 | 109k | } |
2771 | 33.3k | mm_key->next = mm_key + 1; |
2772 | 33.3k | mm_key->next->next = mm_ctn + 1; |
2773 | 33.3k | mm_ctn->uni.ptr = mm_key; |
2774 | 33.3k | } |
2775 | 55.3k | } |
2776 | 4.12M | } |
2777 | 75.3k | return m_vals; |
2778 | 75.3k | } |
2779 | | |
2780 | | static yyjson_mut_val *unsafe_yyjson_mut_val_mut_copy( |
2781 | 3.06G | yyjson_mut_doc *m_doc, const yyjson_mut_val *m_vals) { |
2782 | | /* |
2783 | | The mutable object or array stores all sub-values in a circular linked |
2784 | | list, so we can traverse them in the same loop. The traversal starts from |
2785 | | the last item, continues with the first item in a list, and ends with the |
2786 | | second to last item, which needs to be linked to the last item to close the |
2787 | | circle. |
2788 | | */ |
2789 | 3.06G | yyjson_mut_val *m_val = unsafe_yyjson_mut_val(m_doc, 1); |
2790 | 3.06G | if (unlikely(!m_val)) return NULL; |
2791 | 3.06G | m_val->tag = m_vals->tag; |
2792 | | |
2793 | 3.06G | switch (unsafe_yyjson_get_type(m_vals)) { |
2794 | 693M | case YYJSON_TYPE_OBJ: |
2795 | 998M | case YYJSON_TYPE_ARR: |
2796 | 998M | if (unsafe_yyjson_get_len(m_vals) > 0) { |
2797 | 907M | yyjson_mut_val *last = (yyjson_mut_val *)m_vals->uni.ptr; |
2798 | 907M | yyjson_mut_val *next = last->next, *prev; |
2799 | 907M | prev = unsafe_yyjson_mut_val_mut_copy(m_doc, last); |
2800 | 907M | if (!prev) return NULL; |
2801 | 907M | m_val->uni.ptr = (void *)prev; |
2802 | 3.06G | while (next != last) { |
2803 | 2.16G | prev->next = unsafe_yyjson_mut_val_mut_copy(m_doc, next); |
2804 | 2.16G | if (!prev->next) return NULL; |
2805 | 2.16G | prev = prev->next; |
2806 | 2.16G | next = next->next; |
2807 | 2.16G | } |
2808 | 907M | prev->next = (yyjson_mut_val *)m_val->uni.ptr; |
2809 | 907M | } |
2810 | 998M | break; |
2811 | 998M | case YYJSON_TYPE_RAW: |
2812 | 800M | case YYJSON_TYPE_STR: { |
2813 | 800M | const char *str = m_vals->uni.str; |
2814 | 800M | usize str_len = unsafe_yyjson_get_len(m_vals); |
2815 | 800M | m_val->uni.str = unsafe_yyjson_mut_strncpy(m_doc, str, str_len); |
2816 | 800M | if (!m_val->uni.str) return NULL; |
2817 | 800M | break; |
2818 | 800M | } |
2819 | 1.26G | default: |
2820 | 1.26G | m_val->uni = m_vals->uni; |
2821 | 1.26G | break; |
2822 | 3.06G | } |
2823 | 3.06G | return m_val; |
2824 | 3.06G | } |
2825 | | |
2826 | | yyjson_mut_val *yyjson_mut_val_mut_copy(yyjson_mut_doc *doc, |
2827 | 59.3k | const yyjson_mut_val *val) { |
2828 | 59.3k | if (doc && val) return unsafe_yyjson_mut_val_mut_copy(doc, val); |
2829 | 0 | return NULL; |
2830 | 59.3k | } |
2831 | | |
2832 | | /* Count the number of values and the total length of the strings. */ |
2833 | | static void yyjson_mut_stat(const yyjson_mut_val *val, |
2834 | 0 | usize *val_sum, usize *str_sum) { |
2835 | 0 | yyjson_type type = unsafe_yyjson_get_type(val); |
2836 | 0 | *val_sum += 1; |
2837 | 0 | if (type == YYJSON_TYPE_ARR || type == YYJSON_TYPE_OBJ) { |
2838 | 0 | yyjson_mut_val *child = (yyjson_mut_val *)val->uni.ptr; |
2839 | 0 | usize len = unsafe_yyjson_get_len(val), i; |
2840 | 0 | len <<= (u8)(type == YYJSON_TYPE_OBJ); |
2841 | 0 | *val_sum += len; |
2842 | 0 | for (i = 0; i < len; i++) { |
2843 | 0 | yyjson_type stype = unsafe_yyjson_get_type(child); |
2844 | 0 | if (stype == YYJSON_TYPE_STR || stype == YYJSON_TYPE_RAW) { |
2845 | 0 | *str_sum += unsafe_yyjson_get_len(child) + 1; |
2846 | 0 | } else if (stype == YYJSON_TYPE_ARR || stype == YYJSON_TYPE_OBJ) { |
2847 | 0 | yyjson_mut_stat(child, val_sum, str_sum); |
2848 | 0 | *val_sum -= 1; |
2849 | 0 | } |
2850 | 0 | child = child->next; |
2851 | 0 | } |
2852 | 0 | } else if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) { |
2853 | 0 | *str_sum += unsafe_yyjson_get_len(val) + 1; |
2854 | 0 | } |
2855 | 0 | } |
2856 | | |
2857 | | /* Copy mutable values to immutable value pool. */ |
2858 | | static usize yyjson_imut_copy(yyjson_val **val_ptr, char **buf_ptr, |
2859 | 0 | const yyjson_mut_val *mval) { |
2860 | 0 | yyjson_val *val = *val_ptr; |
2861 | 0 | yyjson_type type = unsafe_yyjson_get_type(mval); |
2862 | 0 | if (type == YYJSON_TYPE_ARR || type == YYJSON_TYPE_OBJ) { |
2863 | 0 | yyjson_mut_val *child = (yyjson_mut_val *)mval->uni.ptr; |
2864 | 0 | usize len = unsafe_yyjson_get_len(mval), i; |
2865 | 0 | usize val_sum = 1; |
2866 | 0 | if (type == YYJSON_TYPE_OBJ) { |
2867 | 0 | if (len) child = child->next->next; |
2868 | 0 | len <<= 1; |
2869 | 0 | } else { |
2870 | 0 | if (len) child = child->next; |
2871 | 0 | } |
2872 | 0 | *val_ptr = val + 1; |
2873 | 0 | for (i = 0; i < len; i++) { |
2874 | 0 | val_sum += yyjson_imut_copy(val_ptr, buf_ptr, child); |
2875 | 0 | child = child->next; |
2876 | 0 | } |
2877 | 0 | val->tag = mval->tag; |
2878 | 0 | val->uni.ofs = val_sum * sizeof(yyjson_val); |
2879 | 0 | return val_sum; |
2880 | 0 | } else if (type == YYJSON_TYPE_STR || type == YYJSON_TYPE_RAW) { |
2881 | 0 | char *buf = *buf_ptr; |
2882 | 0 | usize len = unsafe_yyjson_get_len(mval); |
2883 | 0 | memcpy((void *)buf, (const void *)mval->uni.str, len); |
2884 | 0 | buf[len] = '\0'; |
2885 | 0 | val->tag = mval->tag; |
2886 | 0 | val->uni.str = buf; |
2887 | 0 | *val_ptr = val + 1; |
2888 | 0 | *buf_ptr = buf + len + 1; |
2889 | 0 | return 1; |
2890 | 0 | } else { |
2891 | 0 | val->tag = mval->tag; |
2892 | 0 | val->uni = mval->uni; |
2893 | 0 | *val_ptr = val + 1; |
2894 | 0 | return 1; |
2895 | 0 | } |
2896 | 0 | } |
2897 | | |
2898 | | yyjson_doc *yyjson_mut_doc_imut_copy(const yyjson_mut_doc *mdoc, |
2899 | 0 | const yyjson_alc *alc) { |
2900 | 0 | if (!mdoc) return NULL; |
2901 | 0 | return yyjson_mut_val_imut_copy(mdoc->root, alc); |
2902 | 0 | } |
2903 | | |
2904 | | yyjson_doc *yyjson_mut_val_imut_copy(const yyjson_mut_val *mval, |
2905 | 0 | const yyjson_alc *alc) { |
2906 | 0 | usize val_num = 0, str_sum = 0, hdr_size, buf_size; |
2907 | 0 | yyjson_doc *doc = NULL; |
2908 | 0 | yyjson_val *val_hdr = NULL; |
2909 | | |
2910 | | /* This value should be NULL here. Setting a non-null value suppresses |
2911 | | warning from the clang analyzer. */ |
2912 | 0 | char *str_hdr = (char *)(void *)&str_sum; |
2913 | 0 | if (!mval) return NULL; |
2914 | 0 | if (!alc) alc = &YYJSON_DEFAULT_ALC; |
2915 | | |
2916 | | /* traverse the input value to get pool size */ |
2917 | 0 | yyjson_mut_stat(mval, &val_num, &str_sum); |
2918 | | |
2919 | | /* create doc and val pool */ |
2920 | 0 | hdr_size = size_align_up(sizeof(yyjson_doc), sizeof(yyjson_val)); |
2921 | 0 | buf_size = hdr_size + val_num * sizeof(yyjson_val); |
2922 | 0 | doc = (yyjson_doc *)alc->malloc(alc->ctx, buf_size); |
2923 | 0 | if (!doc) return NULL; |
2924 | 0 | memset(doc, 0, sizeof(yyjson_doc)); |
2925 | 0 | val_hdr = (yyjson_val *)(void *)((char *)(void *)doc + hdr_size); |
2926 | 0 | doc->root = val_hdr; |
2927 | 0 | doc->alc = *alc; |
2928 | | |
2929 | | /* create str pool */ |
2930 | 0 | if (str_sum > 0) { |
2931 | 0 | str_hdr = (char *)alc->malloc(alc->ctx, str_sum); |
2932 | 0 | doc->str_pool = str_hdr; |
2933 | 0 | if (!str_hdr) { |
2934 | 0 | alc->free(alc->ctx, (void *)doc); |
2935 | 0 | return NULL; |
2936 | 0 | } |
2937 | 0 | } |
2938 | | |
2939 | | /* copy vals and strs */ |
2940 | 0 | doc->val_read = yyjson_imut_copy(&val_hdr, &str_hdr, mval); |
2941 | 0 | doc->dat_read = str_sum + 1; |
2942 | 0 | return doc; |
2943 | 0 | } |
2944 | | |
2945 | 1.97k | static_inline bool unsafe_yyjson_num_equals(const void *lhs, const void *rhs) { |
2946 | 1.97k | const yyjson_val_uni *luni = &((const yyjson_val *)lhs)->uni; |
2947 | 1.97k | const yyjson_val_uni *runi = &((const yyjson_val *)rhs)->uni; |
2948 | 1.97k | yyjson_subtype lt = unsafe_yyjson_get_subtype(lhs); |
2949 | 1.97k | yyjson_subtype rt = unsafe_yyjson_get_subtype(rhs); |
2950 | 1.97k | if (lt == rt) return luni->u64 == runi->u64; |
2951 | 482 | if (lt == YYJSON_SUBTYPE_SINT && rt == YYJSON_SUBTYPE_UINT) { |
2952 | 286 | return luni->i64 >= 0 && luni->u64 == runi->u64; |
2953 | 286 | } |
2954 | 196 | if (lt == YYJSON_SUBTYPE_UINT && rt == YYJSON_SUBTYPE_SINT) { |
2955 | 188 | return runi->i64 >= 0 && luni->u64 == runi->u64; |
2956 | 188 | } |
2957 | 8 | return false; |
2958 | 196 | } |
2959 | | |
2960 | 274 | static_inline bool unsafe_yyjson_str_equals(const void *lhs, const void *rhs) { |
2961 | 274 | usize len = unsafe_yyjson_get_len(lhs); |
2962 | 274 | if (len != unsafe_yyjson_get_len(rhs)) return false; |
2963 | 256 | return !memcmp(unsafe_yyjson_get_str(lhs), |
2964 | 256 | unsafe_yyjson_get_str(rhs), len); |
2965 | 274 | } |
2966 | | |
2967 | 0 | bool unsafe_yyjson_equals(const yyjson_val *lhs, const yyjson_val *rhs) { |
2968 | 0 | yyjson_type type = unsafe_yyjson_get_type(lhs); |
2969 | 0 | if (type != unsafe_yyjson_get_type(rhs)) return false; |
2970 | | |
2971 | 0 | switch (type) { |
2972 | 0 | case YYJSON_TYPE_OBJ: { |
2973 | 0 | usize len = unsafe_yyjson_get_len(lhs); |
2974 | 0 | if (len != unsafe_yyjson_get_len(rhs)) return false; |
2975 | 0 | if (len > 0) { |
2976 | 0 | yyjson_obj_iter iter; |
2977 | 0 | yyjson_obj_iter_init(rhs, &iter); |
2978 | 0 | lhs = unsafe_yyjson_get_first(lhs); |
2979 | 0 | while (len-- > 0) { |
2980 | 0 | rhs = yyjson_obj_iter_getn(&iter, lhs->uni.str, |
2981 | 0 | unsafe_yyjson_get_len(lhs)); |
2982 | 0 | if (!rhs) return false; |
2983 | 0 | if (!unsafe_yyjson_equals(lhs + 1, rhs)) return false; |
2984 | 0 | lhs = unsafe_yyjson_get_next(lhs + 1); |
2985 | 0 | } |
2986 | 0 | } |
2987 | | /* yyjson allows duplicate keys, so the check may be inaccurate */ |
2988 | 0 | return true; |
2989 | 0 | } |
2990 | | |
2991 | 0 | case YYJSON_TYPE_ARR: { |
2992 | 0 | usize len = unsafe_yyjson_get_len(lhs); |
2993 | 0 | if (len != unsafe_yyjson_get_len(rhs)) return false; |
2994 | 0 | if (len > 0) { |
2995 | 0 | lhs = unsafe_yyjson_get_first(lhs); |
2996 | 0 | rhs = unsafe_yyjson_get_first(rhs); |
2997 | 0 | while (len-- > 0) { |
2998 | 0 | if (!unsafe_yyjson_equals(lhs, rhs)) return false; |
2999 | 0 | lhs = unsafe_yyjson_get_next(lhs); |
3000 | 0 | rhs = unsafe_yyjson_get_next(rhs); |
3001 | 0 | } |
3002 | 0 | } |
3003 | 0 | return true; |
3004 | 0 | } |
3005 | | |
3006 | 0 | case YYJSON_TYPE_NUM: |
3007 | 0 | return unsafe_yyjson_num_equals(lhs, rhs); |
3008 | | |
3009 | 0 | case YYJSON_TYPE_RAW: |
3010 | 0 | case YYJSON_TYPE_STR: |
3011 | 0 | return unsafe_yyjson_str_equals(lhs, rhs); |
3012 | | |
3013 | 0 | case YYJSON_TYPE_NULL: |
3014 | 0 | case YYJSON_TYPE_BOOL: |
3015 | 0 | return lhs->tag == rhs->tag; |
3016 | | |
3017 | 0 | default: |
3018 | 0 | return false; |
3019 | 0 | } |
3020 | 0 | } |
3021 | | |
3022 | | bool unsafe_yyjson_mut_equals(const yyjson_mut_val *lhs, |
3023 | 3.76k | const yyjson_mut_val *rhs) { |
3024 | 3.76k | yyjson_type type = unsafe_yyjson_get_type(lhs); |
3025 | 3.76k | if (type != unsafe_yyjson_get_type(rhs)) return false; |
3026 | | |
3027 | 3.75k | switch (type) { |
3028 | 831 | case YYJSON_TYPE_OBJ: { |
3029 | 831 | usize len = unsafe_yyjson_get_len(lhs); |
3030 | 831 | if (len != unsafe_yyjson_get_len(rhs)) return false; |
3031 | 820 | if (len > 0) { |
3032 | 758 | yyjson_mut_obj_iter iter; |
3033 | 758 | yyjson_mut_obj_iter_init(constcast(yyjson_mut_val *)rhs, &iter); |
3034 | 758 | lhs = (yyjson_mut_val *)lhs->uni.ptr; |
3035 | 2.41k | while (len-- > 0) { |
3036 | 1.90k | rhs = yyjson_mut_obj_iter_getn(&iter, lhs->uni.str, |
3037 | 1.90k | unsafe_yyjson_get_len(lhs)); |
3038 | 1.90k | if (!rhs) return false; |
3039 | 1.76k | if (!unsafe_yyjson_mut_equals(lhs->next, rhs)) return false; |
3040 | 1.65k | lhs = lhs->next->next; |
3041 | 1.65k | } |
3042 | 758 | } |
3043 | | /* yyjson allows duplicate keys, so the check may be inaccurate */ |
3044 | 567 | return true; |
3045 | 820 | } |
3046 | | |
3047 | 482 | case YYJSON_TYPE_ARR: { |
3048 | 482 | usize len = unsafe_yyjson_get_len(lhs); |
3049 | 482 | if (len != unsafe_yyjson_get_len(rhs)) return false; |
3050 | 454 | if (len > 0) { |
3051 | 174 | lhs = (yyjson_mut_val *)lhs->uni.ptr; |
3052 | 174 | rhs = (yyjson_mut_val *)rhs->uni.ptr; |
3053 | 696 | while (len-- > 0) { |
3054 | 532 | if (!unsafe_yyjson_mut_equals(lhs, rhs)) return false; |
3055 | 522 | lhs = lhs->next; |
3056 | 522 | rhs = rhs->next; |
3057 | 522 | } |
3058 | 174 | } |
3059 | 444 | return true; |
3060 | 454 | } |
3061 | | |
3062 | 1.97k | case YYJSON_TYPE_NUM: |
3063 | 1.97k | return unsafe_yyjson_num_equals(lhs, rhs); |
3064 | | |
3065 | 0 | case YYJSON_TYPE_RAW: |
3066 | 274 | case YYJSON_TYPE_STR: |
3067 | 274 | return unsafe_yyjson_str_equals(lhs, rhs); |
3068 | | |
3069 | 72 | case YYJSON_TYPE_NULL: |
3070 | 196 | case YYJSON_TYPE_BOOL: |
3071 | 196 | return lhs->tag == rhs->tag; |
3072 | | |
3073 | 0 | default: |
3074 | 0 | return false; |
3075 | 3.75k | } |
3076 | 3.75k | } |
3077 | | |
3078 | | bool yyjson_locate_pos(const char *str, size_t len, size_t pos, |
3079 | 0 | size_t *line, size_t *col, size_t *chr) { |
3080 | 0 | usize line_sum = 0, line_pos = 0, chr_sum = 0; |
3081 | 0 | const u8 *cur = (const u8 *)str; |
3082 | 0 | const u8 *end = cur + pos; |
3083 | |
|
3084 | 0 | if (!str || pos > len) { |
3085 | 0 | if (line) *line = 0; |
3086 | 0 | if (col) *col = 0; |
3087 | 0 | if (chr) *chr = 0; |
3088 | 0 | return false; |
3089 | 0 | } |
3090 | | |
3091 | 0 | if (pos >= 3 && is_utf8_bom(cur)) cur += 3; /* don't count BOM */ |
3092 | 0 | while (cur < end) { |
3093 | 0 | u8 c = *cur; |
3094 | 0 | chr_sum += 1; |
3095 | 0 | if (likely(c < 0x80)) { /* 0xxxxxxx (0x00-0x7F) ASCII */ |
3096 | 0 | if (c == '\n') { |
3097 | 0 | line_sum += 1; |
3098 | 0 | line_pos = chr_sum; |
3099 | 0 | } |
3100 | 0 | cur += 1; |
3101 | 0 | } |
3102 | 0 | else if (c < 0xC0) cur += 1; /* 10xxxxxx (0x80-0xBF) Invalid */ |
3103 | 0 | else if (c < 0xE0) cur += 2; /* 110xxxxx (0xC0-0xDF) 2-byte UTF-8 */ |
3104 | 0 | else if (c < 0xF0) cur += 3; /* 1110xxxx (0xE0-0xEF) 3-byte UTF-8 */ |
3105 | 0 | else if (c < 0xF8) cur += 4; /* 11110xxx (0xF0-0xF7) 4-byte UTF-8 */ |
3106 | 0 | else cur += 1; /* 11111xxx (0xF8-0xFF) Invalid */ |
3107 | 0 | } |
3108 | 0 | if (line) *line = line_sum + 1; |
3109 | 0 | if (col) *col = chr_sum - line_pos + 1; |
3110 | 0 | if (chr) *chr = chr_sum; |
3111 | 0 | return true; |
3112 | 0 | } |
3113 | | |
3114 | | |
3115 | | |
3116 | | #if !YYJSON_DISABLE_READER /* reader begin */ |
3117 | | |
3118 | | /* Check read flag, avoids `always false` warning when disabled. */ |
3119 | 3.86M | #define has_flg(_flg) unlikely(has_rflag(flg, YYJSON_READ_##_flg, 0)) |
3120 | 6.16M | #define has_allow(_flg) unlikely(has_rflag(flg, YYJSON_READ_ALLOW_##_flg, 1)) |
3121 | | #define YYJSON_READ_ALLOW_TRIVIA (YYJSON_READ_ALLOW_COMMENTS | \ |
3122 | | YYJSON_READ_ALLOW_EXT_WHITESPACE) |
3123 | | static_inline bool has_rflag(yyjson_read_flag flg, yyjson_read_flag chk, |
3124 | 10.0M | bool non_standard) { |
3125 | | #if YYJSON_DISABLE_NON_STANDARD |
3126 | | if (non_standard) return false; |
3127 | | #endif |
3128 | 10.0M | return (flg & chk) != 0; |
3129 | 10.0M | } |
3130 | | |
3131 | | |
3132 | | |
3133 | | /*============================================================================== |
3134 | | * MARK: - JSON Reader Utils (Private) |
3135 | | * These functions are used by JSON reader to read literals and comments. |
3136 | | *============================================================================*/ |
3137 | | |
3138 | | /** Read `true` literal, `*ptr[0]` should be `t`. */ |
3139 | 46.1k | static_inline bool read_true(u8 **ptr, yyjson_val *val) { |
3140 | 46.1k | u8 *cur = *ptr; |
3141 | 46.1k | if (likely(byte_match_4(cur, "true"))) { |
3142 | 45.2k | val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_TRUE; |
3143 | 45.2k | *ptr = cur + 4; |
3144 | 45.2k | return true; |
3145 | 45.2k | } |
3146 | 854 | return false; |
3147 | 46.1k | } |
3148 | | |
3149 | | /** Read `false` literal, `*ptr[0]` should be `f`. */ |
3150 | 51.4k | static_inline bool read_false(u8 **ptr, yyjson_val *val) { |
3151 | 51.4k | u8 *cur = *ptr; |
3152 | 51.4k | if (likely(byte_match_4(cur + 1, "alse"))) { |
3153 | 50.3k | val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_FALSE; |
3154 | 50.3k | *ptr = cur + 5; |
3155 | 50.3k | return true; |
3156 | 50.3k | } |
3157 | 1.02k | return false; |
3158 | 51.4k | } |
3159 | | |
3160 | | /** Read `null` literal, `*ptr[0]` should be `n`. */ |
3161 | 155k | static_inline bool read_null(u8 **ptr, yyjson_val *val) { |
3162 | 155k | u8 *cur = *ptr; |
3163 | 155k | if (likely(byte_match_4(cur, "null"))) { |
3164 | 153k | val->tag = YYJSON_TYPE_NULL; |
3165 | 153k | *ptr = cur + 4; |
3166 | 153k | return true; |
3167 | 153k | } |
3168 | 2.14k | return false; |
3169 | 155k | } |
3170 | | |
3171 | | /** Read `Inf` or `Infinity` literal (ignoring case). */ |
3172 | | static_inline bool read_inf(u8 **ptr, u8 **pre, |
3173 | 13.2k | yyjson_read_flag flg, yyjson_val *val) { |
3174 | 13.2k | u8 *hdr = *ptr; |
3175 | 13.2k | u8 *cur = *ptr; |
3176 | 13.2k | u8 **end = ptr; |
3177 | 13.2k | bool sign = (*cur == '-'); |
3178 | 13.2k | if (*cur == '+' && !has_allow(EXT_NUMBER)) return false; |
3179 | 13.2k | cur += char_is_sign(*cur); |
3180 | 13.2k | if (char_to_lower(cur[0]) == 'i' && |
3181 | 6.98k | char_to_lower(cur[1]) == 'n' && |
3182 | 6.89k | char_to_lower(cur[2]) == 'f') { |
3183 | 6.84k | if (char_to_lower(cur[3]) == 'i') { |
3184 | 2.79k | if (char_to_lower(cur[4]) == 'n' && |
3185 | 2.77k | char_to_lower(cur[5]) == 'i' && |
3186 | 2.74k | char_to_lower(cur[6]) == 't' && |
3187 | 2.72k | char_to_lower(cur[7]) == 'y') { |
3188 | 2.69k | cur += 8; |
3189 | 2.69k | } else { |
3190 | 91 | return false; |
3191 | 91 | } |
3192 | 4.05k | } else { |
3193 | 4.05k | cur += 3; |
3194 | 4.05k | } |
3195 | 6.75k | *end = cur; |
3196 | 6.75k | if (has_flg(NUMBER_AS_RAW)) { |
3197 | 0 | **pre = '\0'; /* add null-terminator for previous raw string */ |
3198 | 0 | *pre = cur; /* save end position for current raw string */ |
3199 | 0 | val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; |
3200 | 0 | val->uni.str = (const char *)hdr; |
3201 | 6.75k | } else { |
3202 | 6.75k | val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; |
3203 | 6.75k | val->uni.u64 = f64_bits_inf(sign); |
3204 | 6.75k | } |
3205 | 6.75k | return true; |
3206 | 6.84k | } |
3207 | 6.38k | return false; |
3208 | 13.2k | } |
3209 | | |
3210 | | /** Read `NaN` literal (ignoring case). */ |
3211 | | static_inline bool read_nan(u8 **ptr, u8 **pre, |
3212 | 8.05k | yyjson_read_flag flg, yyjson_val *val) { |
3213 | 8.05k | u8 *hdr = *ptr; |
3214 | 8.05k | u8 *cur = *ptr; |
3215 | 8.05k | u8 **end = ptr; |
3216 | 8.05k | bool sign = (*cur == '-'); |
3217 | 8.05k | if (*cur == '+' && !has_allow(EXT_NUMBER)) return false; |
3218 | 8.05k | cur += char_is_sign(*cur); |
3219 | 8.05k | if (char_to_lower(cur[0]) == 'n' && |
3220 | 6.72k | char_to_lower(cur[1]) == 'a' && |
3221 | 6.47k | char_to_lower(cur[2]) == 'n') { |
3222 | 6.43k | cur += 3; |
3223 | 6.43k | *end = cur; |
3224 | 6.43k | if (has_flg(NUMBER_AS_RAW)) { |
3225 | 0 | **pre = '\0'; /* add null-terminator for previous raw string */ |
3226 | 0 | *pre = cur; /* save end position for current raw string */ |
3227 | 0 | val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; |
3228 | 0 | val->uni.str = (const char *)hdr; |
3229 | 6.43k | } else { |
3230 | 6.43k | val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; |
3231 | 6.43k | val->uni.u64 = f64_bits_nan(sign); |
3232 | 6.43k | } |
3233 | 6.43k | return true; |
3234 | 6.43k | } |
3235 | 1.61k | return false; |
3236 | 8.05k | } |
3237 | | |
3238 | | /** Read `Inf`, `Infinity` or `NaN` literal (ignoring case). */ |
3239 | | static_inline bool read_inf_or_nan(u8 **ptr, u8 **pre, |
3240 | 13.2k | yyjson_read_flag flg, yyjson_val *val) { |
3241 | 13.2k | if (read_inf(ptr, pre, flg, val)) return true; |
3242 | 6.47k | if (read_nan(ptr, pre, flg, val)) return true; |
3243 | 1.40k | return false; |
3244 | 6.47k | } |
3245 | | |
3246 | | /** Read a JSON number as raw string. */ |
3247 | | static_noinline bool read_num_raw(u8 **ptr, u8 **pre, yyjson_read_flag flg, |
3248 | 0 | yyjson_val *val, const char **msg) { |
3249 | 0 | #define return_err(_pos, _msg) do { \ |
3250 | 0 | *msg = _msg; *end = _pos; return false; \ |
3251 | 0 | } while (false) |
3252 | |
|
3253 | 0 | #define return_raw() do { \ |
3254 | 0 | val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \ |
3255 | 0 | val->uni.str = (const char *)hdr; \ |
3256 | 0 | **pre = '\0'; *pre = cur; *end = cur; return true; \ |
3257 | 0 | } while (false) |
3258 | |
|
3259 | 0 | u8 *hdr = *ptr; |
3260 | 0 | u8 *cur = *ptr; |
3261 | 0 | u8 **end = ptr; |
3262 | | |
3263 | | /* skip sign */ |
3264 | 0 | cur += (*cur == '-'); |
3265 | | |
3266 | | /* read first digit, check leading zero */ |
3267 | 0 | while (unlikely(!char_is_digit(*cur))) { |
3268 | 0 | if (has_allow(EXT_NUMBER)) { |
3269 | 0 | if (*cur == '+' && cur == hdr) { /* leading `+` sign */ |
3270 | 0 | cur++; |
3271 | 0 | continue; |
3272 | 0 | } |
3273 | 0 | if (*cur == '.' && char_is_digit(cur[1])) { /* e.g. '.123' */ |
3274 | 0 | goto read_double; |
3275 | 0 | } |
3276 | 0 | } |
3277 | 0 | if (has_allow(INF_AND_NAN)) { |
3278 | 0 | if (read_inf_or_nan(ptr, pre, flg, val)) return true; |
3279 | 0 | } |
3280 | 0 | return_err(cur, "no digit after sign"); |
3281 | 0 | } |
3282 | | |
3283 | | /* read integral part */ |
3284 | 0 | if (*cur == '0') { |
3285 | 0 | cur++; |
3286 | 0 | if (unlikely(char_is_digit(*cur))) { |
3287 | 0 | return_err(cur - 1, "number with leading zero is not allowed"); |
3288 | 0 | } |
3289 | 0 | if (!char_is_fp(*cur)) { |
3290 | 0 | if (has_allow(EXT_NUMBER) && char_to_lower(*cur) == 'x') { /* hex */ |
3291 | 0 | if (!char_is_hex(*++cur)) return_err(cur, "invalid hex number"); |
3292 | 0 | while(char_is_hex(*cur)) cur++; |
3293 | 0 | } |
3294 | 0 | return_raw(); |
3295 | 0 | } |
3296 | 0 | } else { |
3297 | 0 | while (char_is_digit(*cur)) cur++; |
3298 | 0 | if (!char_is_fp(*cur)) return_raw(); |
3299 | 0 | } |
3300 | | |
3301 | 0 | read_double: |
3302 | | /* read fraction part */ |
3303 | 0 | if (*cur == '.') { |
3304 | 0 | cur++; |
3305 | 0 | if (!char_is_digit(*cur)) { |
3306 | 0 | if (has_allow(EXT_NUMBER)) { |
3307 | 0 | if (!char_is_exp(*cur)) return_raw(); |
3308 | 0 | } else { |
3309 | 0 | return_err(cur, "no digit after decimal point"); |
3310 | 0 | } |
3311 | 0 | } |
3312 | 0 | while (char_is_digit(*cur)) cur++; |
3313 | 0 | } |
3314 | | |
3315 | | /* read exponent part */ |
3316 | 0 | if (char_is_exp(*cur)) { |
3317 | 0 | cur += 1 + char_is_sign(cur[1]); |
3318 | 0 | if (!char_is_digit(*cur++)) { |
3319 | 0 | return_err(cur, "no digit after exponent sign"); |
3320 | 0 | } |
3321 | 0 | while (char_is_digit(*cur)) cur++; |
3322 | 0 | } |
3323 | | |
3324 | 0 | return_raw(); |
3325 | |
|
3326 | 0 | #undef return_err |
3327 | 0 | #undef return_raw |
3328 | 0 | } |
3329 | | |
3330 | | /** Read a hex number. */ |
3331 | | static_noinline bool read_num_hex(u8 **ptr, u8 **pre, yyjson_read_flag flg, |
3332 | 8.82k | yyjson_val *val, const char **msg) { |
3333 | 8.82k | u8 *hdr = *ptr; |
3334 | 8.82k | u8 *cur = *ptr; |
3335 | 8.82k | u8 **end = ptr; |
3336 | 8.82k | u64 sig = 0, i = 0; |
3337 | 8.82k | bool sign; |
3338 | | |
3339 | | /* skip sign and '0x' */ |
3340 | 8.82k | sign = (*cur == '-'); |
3341 | 8.82k | cur += (*cur == '-' || *cur == '+') + 2; |
3342 | | |
3343 | | /* read hex */ |
3344 | 75.7k | for(; i < 16; i++) { |
3345 | 75.1k | u8 c = hex_conv_table[cur[i]]; |
3346 | 75.1k | if (c == 0xF0) break; |
3347 | 66.9k | sig <<= 4; |
3348 | 66.9k | sig |= c; |
3349 | 66.9k | } |
3350 | | |
3351 | | /* check error */ |
3352 | 8.82k | if (unlikely(i == 0)) { |
3353 | 12 | *msg = "invalid hex number"; |
3354 | 12 | return false; |
3355 | 12 | } |
3356 | | |
3357 | | /* check overflow */ |
3358 | 8.81k | if (unlikely(i == 16)) { |
3359 | 637 | if (char_is_hex(cur[16]) || (sign && sig > ((u64)1 << 63))) { |
3360 | 4 | if (!has_flg(BIGNUM_AS_RAW)) { |
3361 | 4 | *msg = "hex number overflow"; |
3362 | 4 | return false; |
3363 | 4 | } |
3364 | 0 | cur += 16; |
3365 | 0 | while (char_is_hex(*cur)) cur++; |
3366 | 0 | **pre = '\0'; |
3367 | 0 | val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; |
3368 | 0 | val->uni.str = (const char *)hdr; |
3369 | 0 | *pre = cur; *end = cur; |
3370 | 0 | return true; |
3371 | 4 | } |
3372 | 637 | } |
3373 | | |
3374 | 8.81k | val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); |
3375 | 8.81k | val->uni.u64 = (u64)(sign ? (u64)(~(sig) + 1) : (u64)(sig)); |
3376 | 8.81k | *end = cur + i; |
3377 | 8.81k | return true; |
3378 | 8.81k | } |
3379 | | |
3380 | | /** |
3381 | | Skip trivia (whitespace and comments). |
3382 | | This function should be used only when `char_is_trivia()` returns true. |
3383 | | @param ptr (inout) Input current position, output end position. |
3384 | | @param eof JSON end position. |
3385 | | @param flg JSON read flags. |
3386 | | @return true if at least one character was skipped. |
3387 | | false if no characters were skipped, |
3388 | | or if a multi-line comment is unterminated; |
3389 | | in the latter case, `ptr` will be set to `eof`. |
3390 | | */ |
3391 | 936k | static_noinline bool skip_trivia(u8 **ptr, u8 *eof, yyjson_read_flag flg) { |
3392 | 936k | u8 *hdr = *ptr, *cur = *ptr; |
3393 | 936k | usize len; |
3394 | | |
3395 | 1.88M | while (cur < eof) { |
3396 | 1.87M | u8 *loop_begin = cur; |
3397 | | |
3398 | | /* skip standard whitespace */ |
3399 | 1.89M | while(char_is_space(*cur)) cur++; |
3400 | | |
3401 | | /* skip extended whitespace */ |
3402 | 1.87M | if (has_allow(EXT_WHITESPACE)) { |
3403 | 3.86M | while (char_is_space_ext(*cur)) { |
3404 | 2.01M | cur += (len = ext_space_len(cur)); |
3405 | 2.01M | if (!len) break; |
3406 | 2.01M | } |
3407 | 1.85M | } |
3408 | | |
3409 | | /* skip comment, do not validate encoding */ |
3410 | 1.87M | if (has_allow(COMMENTS) && cur[0] == '/') { |
3411 | 12.7k | if (cur[1] == '/') { /* single-line comment */ |
3412 | 8.20k | cur += 2; |
3413 | 8.20k | if (has_allow(EXT_WHITESPACE)) { |
3414 | 34.8k | while (cur < eof) { |
3415 | 34.7k | if (char_is_eol_ext(*cur)) { |
3416 | 1.90k | cur += (len = ext_eol_len(cur)); |
3417 | 1.90k | if (len) break; |
3418 | 1.90k | } |
3419 | 33.3k | cur++; |
3420 | 33.3k | } |
3421 | 6.73k | } else { |
3422 | 23.0k | while (cur < eof && !char_is_eol(*cur)) cur++; |
3423 | 6.73k | } |
3424 | 8.20k | } else if (cur[1] == '*') { /* multi-line comment */ |
3425 | 4.17k | cur += 2; |
3426 | 24.2k | while (!byte_match_2(cur, "*/") && cur < eof) cur++; |
3427 | 4.17k | if (cur == eof) { |
3428 | 186 | *ptr = eof; |
3429 | 186 | return false; /* unclosed comment */ |
3430 | 186 | } |
3431 | 3.98k | cur += 2; |
3432 | 3.98k | } |
3433 | 12.7k | } |
3434 | 1.87M | if (cur == loop_begin) break; |
3435 | 1.87M | } |
3436 | 936k | *ptr = cur; |
3437 | 936k | return cur > hdr; |
3438 | 936k | } |
3439 | | |
3440 | | /** |
3441 | | Check truncated UTF-8 character. |
3442 | | Return true if `cur` starts a valid UTF-8 sequence that is truncated. |
3443 | | */ |
3444 | 2.37k | static bool is_truncated_utf8(u8 *cur, u8 *eof) { |
3445 | 2.37k | u8 c0, c1, c2; |
3446 | 2.37k | usize len = (usize)(eof - cur); |
3447 | 2.37k | if (cur >= eof || len >= 4) return false; |
3448 | 1.53k | c0 = cur[0]; c1 = cur[1]; c2 = cur[2]; |
3449 | | /* 1-byte UTF-8, not truncated */ |
3450 | 1.53k | if (c0 < 0x80) return false; |
3451 | 1.37k | if (len == 1) { |
3452 | | /* 2-byte UTF-8, truncated */ |
3453 | 591 | if ((c0 & 0xE0) == 0xC0 && (c0 & 0x1E) != 0x00) return true; |
3454 | | /* 3-byte UTF-8, truncated */ |
3455 | 445 | if ((c0 & 0xF0) == 0xE0) return true; |
3456 | | /* 4-byte UTF-8, truncated */ |
3457 | 351 | if ((c0 & 0xF8) == 0xF0 && (c0 & 0x07) <= 0x04) return true; |
3458 | 779 | } else if (len == 2) { |
3459 | | /* 3-byte UTF-8, truncated */ |
3460 | 389 | if ((c0 & 0xF0) == 0xE0 && (c1 & 0xC0) == 0x80) { |
3461 | 75 | u8 t = (u8)(((c0 & 0x0F) << 1) | ((c1 & 0x20) >> 5)); |
3462 | 75 | return 0x01 <= t && t != 0x1B; |
3463 | 75 | } |
3464 | | /* 4-byte UTF-8, truncated */ |
3465 | 314 | if ((c0 & 0xF8) == 0xF0 && (c1 & 0xC0) == 0x80) { |
3466 | 29 | u8 t = (u8)(((c0 & 0x07) << 2) | ((c1 & 0x30) >> 4)); |
3467 | 29 | return 0x01 <= t && t <= 0x10; |
3468 | 29 | } |
3469 | 390 | } else if (len == 3) { |
3470 | | /* 4 bytes UTF-8, truncated */ |
3471 | 390 | if ((c0 & 0xF8) == 0xF0 && (c1 & 0xC0) == 0x80 && (c2 & 0xC0) == 0x80) { |
3472 | 15 | u8 t = (u8)(((c0 & 0x07) << 2) | ((c1 & 0x30) >> 4)); |
3473 | 15 | return 0x01 <= t && t <= 0x10; |
3474 | 15 | } |
3475 | 390 | } |
3476 | 982 | return false; |
3477 | 1.37k | } |
3478 | | |
3479 | | /** |
3480 | | Check truncated string. |
3481 | | Returns true if `cur` match `str` but is truncated. |
3482 | | The `str` should be lowercase ASCII letters. |
3483 | | */ |
3484 | | static bool is_truncated_str(u8 *cur, u8 *eof, const char *str, |
3485 | 15.9k | bool case_sensitive) { |
3486 | 15.9k | usize len = strlen(str); |
3487 | 15.9k | if (cur + len <= eof || eof <= cur) return false; |
3488 | 8.97k | if (case_sensitive) { |
3489 | 3.93k | return memcmp(cur, str, (usize)(eof - cur)) == 0; |
3490 | 3.93k | } |
3491 | 5.70k | for (; cur < eof; cur++, str++) { |
3492 | 5.54k | if (char_to_lower(*cur) != *(const u8 *)str) return false; |
3493 | 5.54k | } |
3494 | 153 | return true; |
3495 | 5.04k | } |
3496 | | |
3497 | | /** |
3498 | | Check truncated JSON on parsing errors. |
3499 | | Returns true if the input is valid but truncated. |
3500 | | */ |
3501 | | static_noinline bool is_truncated_end(u8 *hdr, u8 *cur, u8 *eof, |
3502 | | yyjson_read_code code, |
3503 | 80.2k | yyjson_read_flag flg) { |
3504 | 80.2k | if (cur >= eof) return true; |
3505 | 40.7k | if (code == YYJSON_READ_ERROR_LITERAL) { |
3506 | 2.66k | if (is_truncated_str(cur, eof, "true", true) || |
3507 | 2.55k | is_truncated_str(cur, eof, "false", true) || |
3508 | 2.42k | is_truncated_str(cur, eof, "null", true)) { |
3509 | 349 | return true; |
3510 | 349 | } |
3511 | 2.66k | } |
3512 | 40.3k | if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER || |
3513 | 14.4k | code == YYJSON_READ_ERROR_INVALID_NUMBER || |
3514 | 32.1k | code == YYJSON_READ_ERROR_LITERAL) { |
3515 | 32.1k | if (has_allow(INF_AND_NAN)) { |
3516 | 4.04k | if (*cur == '-') cur++; |
3517 | 4.04k | if (is_truncated_str(cur, eof, "infinity", false) || |
3518 | 3.94k | is_truncated_str(cur, eof, "nan", false)) { |
3519 | 153 | return true; |
3520 | 153 | } |
3521 | 4.04k | } |
3522 | 32.1k | } |
3523 | 40.2k | if (code == YYJSON_READ_ERROR_UNEXPECTED_CONTENT) { |
3524 | 2.65k | if (has_allow(INF_AND_NAN)) { |
3525 | 332 | if (hdr + 3 <= cur && |
3526 | 311 | is_truncated_str(cur - 3, eof, "infinity", false)) { |
3527 | 0 | return true; /* e.g. infin would be read as inf + in */ |
3528 | 0 | } |
3529 | 332 | } |
3530 | 2.65k | } |
3531 | 40.2k | if (code == YYJSON_READ_ERROR_INVALID_STRING) { |
3532 | 5.32k | usize len = (usize)(eof - cur); |
3533 | | |
3534 | | /* unicode escape sequence */ |
3535 | 5.32k | if (*cur == '\\') { |
3536 | 2.95k | if (len == 1) return true; |
3537 | 2.79k | if (len <= 5) { |
3538 | 891 | if (*++cur != 'u') return false; |
3539 | 247 | for (++cur; cur < eof; cur++) { |
3540 | 124 | if (!char_is_hex(*cur)) return false; |
3541 | 124 | } |
3542 | 123 | return true; |
3543 | 1.90k | } else if (len <= 11) { |
3544 | | /* incomplete surrogate pair? */ |
3545 | 966 | u16 hi; |
3546 | 966 | if (*++cur != 'u') return false; |
3547 | 631 | if (!hex_load_4(++cur, &hi)) return false; |
3548 | 601 | if ((hi & 0xF800) != 0xD800) return false; |
3549 | 601 | cur += 4; |
3550 | 601 | if (cur >= eof) return true; |
3551 | | /* valid low surrogate is DC00...DFFF */ |
3552 | 511 | if (*cur != '\\') return false; |
3553 | 223 | if (++cur >= eof) return true; |
3554 | 214 | if (*cur != 'u') return false; |
3555 | 160 | if (++cur >= eof) return true; |
3556 | 113 | if (*cur != 'd' && *cur != 'D') return false; |
3557 | 97 | if (++cur >= eof) return true; |
3558 | 77 | if ((*cur < 'c' || *cur > 'f') && (*cur < 'C' || *cur > 'F')) |
3559 | 34 | return false; |
3560 | 43 | if (++cur >= eof) return true; |
3561 | 19 | if (!char_is_hex(*cur)) return false; |
3562 | 5 | return true; |
3563 | 19 | } |
3564 | 937 | return false; |
3565 | 2.79k | } |
3566 | | |
3567 | | /* 2 to 4 bytes UTF-8 */ |
3568 | 2.37k | if (is_truncated_utf8(cur, eof)) { |
3569 | 360 | return true; |
3570 | 360 | } |
3571 | 2.37k | } |
3572 | 36.9k | if (has_allow(COMMENTS)) { |
3573 | 25.1k | if (code == YYJSON_READ_ERROR_INVALID_COMMENT) { |
3574 | | /* unclosed multiline comment */ |
3575 | 0 | return true; |
3576 | 0 | } |
3577 | 25.1k | if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER && |
3578 | 17.6k | *cur == '/' && cur + 1 == eof) { |
3579 | | /* truncated beginning of comment */ |
3580 | 133 | return true; |
3581 | 133 | } |
3582 | 25.1k | } |
3583 | 36.7k | if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER && |
3584 | 25.6k | has_allow(BOM)) { |
3585 | | /* truncated UTF-8 BOM */ |
3586 | 0 | usize len = (usize)(eof - cur); |
3587 | 0 | if (cur == hdr && len < 3 && !memcmp(hdr, "\xEF\xBB\xBF", len)) { |
3588 | 0 | return true; |
3589 | 0 | } |
3590 | 0 | } |
3591 | 36.7k | return false; |
3592 | 36.7k | } |
3593 | | |
3594 | | |
3595 | | |
3596 | | #if !YYJSON_DISABLE_FAST_FP_CONV /* FP_READER */ |
3597 | | |
3598 | | /*============================================================================== |
3599 | | * MARK: - BigInt For Floating Point Number Reader (Private) |
3600 | | * |
3601 | | * The bigint algorithm is used by floating-point number reader to get correctly |
3602 | | * rounded result for numbers with lots of digits. This part of code is rarely |
3603 | | * used for common numbers. |
3604 | | *============================================================================*/ |
3605 | | |
3606 | | /** Unsigned arbitrarily large integer */ |
3607 | | typedef struct bigint { |
3608 | | u32 used; /* used chunks count, should not be 0 */ |
3609 | | u64 bits[64]; /* chunks (58 is enough here) */ |
3610 | | } bigint; |
3611 | | |
3612 | | /** |
3613 | | Evaluate 'big += val'. |
3614 | | @param big A big number (can be 0). |
3615 | | @param val An unsigned integer (can be 0). |
3616 | | */ |
3617 | 322k | static_inline void bigint_add_u64(bigint *big, u64 val) { |
3618 | 322k | u32 idx, max; |
3619 | 322k | u64 num = big->bits[0]; |
3620 | 322k | u64 add = num + val; |
3621 | 322k | big->bits[0] = add; |
3622 | 322k | if (likely((add >= num) || (add >= val))) return; |
3623 | 17.1k | for ((void)(idx = 1), max = big->used; idx < max; idx++) { |
3624 | 15.7k | if (likely(big->bits[idx] != U64_MAX)) { |
3625 | 14.7k | big->bits[idx] += 1; |
3626 | 14.7k | return; |
3627 | 14.7k | } |
3628 | 942 | big->bits[idx] = 0; |
3629 | 942 | } |
3630 | 1.43k | big->bits[big->used++] = 1; |
3631 | 1.43k | } |
3632 | | |
3633 | | /** |
3634 | | Evaluate 'big *= val'. |
3635 | | @param big A big number (can be 0). |
3636 | | @param val An unsigned integer (cannot be 0). |
3637 | | */ |
3638 | 1.03M | static_inline void bigint_mul_u64(bigint *big, u64 val) { |
3639 | 1.03M | u32 idx = 0, max = big->used; |
3640 | 1.03M | u64 hi, lo, carry = 0; |
3641 | 3.35M | for (; idx < max; idx++) { |
3642 | 3.35M | if (big->bits[idx]) break; |
3643 | 3.35M | } |
3644 | 11.3M | for (; idx < max; idx++) { |
3645 | 10.3M | u128_mul_add(big->bits[idx], val, carry, &hi, &lo); |
3646 | 10.3M | big->bits[idx] = lo; |
3647 | 10.3M | carry = hi; |
3648 | 10.3M | } |
3649 | 1.03M | if (carry) big->bits[big->used++] = carry; |
3650 | 1.03M | } |
3651 | | |
3652 | | /** |
3653 | | Evaluate 'big *= 2^exp'. |
3654 | | @param big A big number (can be 0). |
3655 | | @param exp An exponent integer (can be 0). |
3656 | | */ |
3657 | 81.7k | static_inline void bigint_mul_pow2(bigint *big, u32 exp) { |
3658 | 81.7k | u32 shft = exp % 64; |
3659 | 81.7k | u32 move = exp / 64; |
3660 | 81.7k | u32 idx = big->used; |
3661 | 81.7k | if (unlikely(shft == 0)) { |
3662 | 87.5k | for (; idx > 0; idx--) { |
3663 | 65.2k | big->bits[idx + move - 1] = big->bits[idx - 1]; |
3664 | 65.2k | } |
3665 | 22.2k | big->used += move; |
3666 | 100k | while (move) big->bits[--move] = 0; |
3667 | 59.4k | } else { |
3668 | 59.4k | big->bits[idx] = 0; |
3669 | 356k | for (; idx > 0; idx--) { |
3670 | 296k | u64 num = big->bits[idx] << shft; |
3671 | 296k | num |= big->bits[idx - 1] >> (64 - shft); |
3672 | 296k | big->bits[idx + move] = num; |
3673 | 296k | } |
3674 | 59.4k | big->bits[move] = big->bits[0] << shft; |
3675 | 59.4k | big->used += move + (big->bits[big->used + move] > 0); |
3676 | 363k | while (move) big->bits[--move] = 0; |
3677 | 59.4k | } |
3678 | 81.7k | } |
3679 | | |
3680 | | /** |
3681 | | Evaluate 'big *= 10^exp'. |
3682 | | @param big A big number (can be 0). |
3683 | | @param exp An exponent integer (cannot be 0). |
3684 | | */ |
3685 | 403k | static_inline void bigint_mul_pow10(bigint *big, i32 exp) { |
3686 | 1.31M | for (; exp >= U64_POW10_MAX_EXACT_EXP; exp -= U64_POW10_MAX_EXACT_EXP) { |
3687 | 912k | bigint_mul_u64(big, u64_pow10_table[U64_POW10_MAX_EXACT_EXP]); |
3688 | 912k | } |
3689 | 403k | if (exp) { |
3690 | 118k | bigint_mul_u64(big, u64_pow10_table[exp]); |
3691 | 118k | } |
3692 | 403k | } |
3693 | | |
3694 | | /** |
3695 | | Compare two bigint. |
3696 | | @return -1 if 'a < b', +1 if 'a > b', 0 if 'a == b'. |
3697 | | */ |
3698 | 81.7k | static_inline i32 bigint_cmp(bigint *a, bigint *b) { |
3699 | 81.7k | u32 idx = a->used; |
3700 | 81.7k | if (a->used < b->used) return -1; |
3701 | 80.2k | if (a->used > b->used) return +1; |
3702 | 167k | while (idx-- > 0) { |
3703 | 149k | u64 av = a->bits[idx]; |
3704 | 149k | u64 bv = b->bits[idx]; |
3705 | 149k | if (av < bv) return -1; |
3706 | 115k | if (av > bv) return +1; |
3707 | 115k | } |
3708 | 17.2k | return 0; |
3709 | 79.9k | } |
3710 | | |
3711 | | /** |
3712 | | Evaluate 'big = val'. |
3713 | | @param big A big number (can be 0). |
3714 | | @param val An unsigned integer (can be 0). |
3715 | | */ |
3716 | 113k | static_inline void bigint_set_u64(bigint *big, u64 val) { |
3717 | 113k | big->used = 1; |
3718 | 113k | big->bits[0] = val; |
3719 | 113k | } |
3720 | | |
3721 | | /** Set a bigint with floating point number string. */ |
3722 | | static_noinline void bigint_set_buf(bigint *big, u64 sig, i32 *exp, |
3723 | 81.7k | u8 *sig_cut, u8 *sig_end, u8 *dot_pos) { |
3724 | | |
3725 | 81.7k | if (unlikely(!sig_cut)) { |
3726 | | /* no digit cut, set significant part only */ |
3727 | 31.3k | bigint_set_u64(big, sig); |
3728 | 31.3k | return; |
3729 | | |
3730 | 50.4k | } else { |
3731 | | /* some digits were cut, read them from 'sig_cut' to 'sig_end' */ |
3732 | 50.4k | u8 *hdr = sig_cut; |
3733 | 50.4k | u8 *cur = hdr; |
3734 | 50.4k | u32 len = 0; |
3735 | 50.4k | u64 val = 0; |
3736 | 50.4k | bool dig_big_cut = false; |
3737 | 50.4k | bool has_dot = (hdr < dot_pos) & (dot_pos < sig_end); |
3738 | 50.4k | u32 dig_len_total = U64_SAFE_DIG + (u32)(sig_end - hdr) - has_dot; |
3739 | | |
3740 | 50.4k | sig -= (*sig_cut >= '5'); /* sig was rounded before */ |
3741 | 50.4k | if (dig_len_total > F64_MAX_DEC_DIG) { |
3742 | 1.38k | dig_big_cut = true; |
3743 | 1.38k | sig_end -= dig_len_total - (F64_MAX_DEC_DIG + 1); |
3744 | 1.38k | sig_end -= (dot_pos + 1 == sig_end); |
3745 | 1.38k | dig_len_total = (F64_MAX_DEC_DIG + 1); |
3746 | 1.38k | } |
3747 | 50.4k | *exp -= (i32)dig_len_total - U64_SAFE_DIG; |
3748 | | |
3749 | 50.4k | big->used = 1; |
3750 | 50.4k | big->bits[0] = sig; |
3751 | 5.54M | while (cur < sig_end) { |
3752 | 5.49M | if (likely(cur != dot_pos)) { |
3753 | 5.47M | val = val * 10 + (u8)(*cur++ - '0'); |
3754 | 5.47M | len++; |
3755 | 5.47M | if (unlikely(cur == sig_end && dig_big_cut)) { |
3756 | | /* The last digit must be non-zero, */ |
3757 | | /* set it to '1' for correct rounding. */ |
3758 | 1.38k | val = val - (val % 10) + 1; |
3759 | 1.38k | } |
3760 | 5.47M | if (len == U64_SAFE_DIG || cur == sig_end) { |
3761 | 322k | bigint_mul_pow10(big, (i32)len); |
3762 | 322k | bigint_add_u64(big, val); |
3763 | 322k | val = 0; |
3764 | 322k | len = 0; |
3765 | 322k | } |
3766 | 5.47M | } else { |
3767 | 12.5k | cur++; |
3768 | 12.5k | } |
3769 | 5.49M | } |
3770 | 50.4k | } |
3771 | 81.7k | } |
3772 | | |
3773 | | |
3774 | | |
3775 | | /*============================================================================== |
3776 | | * MARK: - Diy Floating Point (Private) |
3777 | | *============================================================================*/ |
3778 | | |
3779 | | /** "Do It Yourself Floating Point" struct. */ |
3780 | | typedef struct diy_fp { |
3781 | | u64 sig; /* significand */ |
3782 | | i32 exp; /* exponent, base 2 */ |
3783 | | i32 pad; /* padding, useless */ |
3784 | | } diy_fp; |
3785 | | |
3786 | | /** Get cached rounded diy_fp for pow(10, e). The input value must be in the |
3787 | | range [POW10_SIG_TABLE_MIN_EXP, POW10_SIG_TABLE_MAX_EXP]. */ |
3788 | 195k | static_inline diy_fp diy_fp_get_cached_pow10(i32 exp10) { |
3789 | 195k | diy_fp fp; |
3790 | 195k | u64 sig_ext; |
3791 | 195k | pow10_table_get_sig(exp10, &fp.sig, &sig_ext); |
3792 | 195k | pow10_table_get_exp(exp10, &fp.exp); |
3793 | 195k | fp.sig += (sig_ext >> 63); |
3794 | 195k | return fp; |
3795 | 195k | } |
3796 | | |
3797 | | /** Returns fp * fp2. */ |
3798 | 195k | static_inline diy_fp diy_fp_mul(diy_fp fp, diy_fp fp2) { |
3799 | 195k | u64 hi, lo; |
3800 | 195k | u128_mul(fp.sig, fp2.sig, &hi, &lo); |
3801 | 195k | fp.sig = hi + (lo >> 63); |
3802 | 195k | fp.exp += fp2.exp + 64; |
3803 | 195k | return fp; |
3804 | 195k | } |
3805 | | |
3806 | | /** Convert diy_fp to IEEE-754 raw value. */ |
3807 | 195k | static_inline u64 diy_fp_to_ieee_raw(diy_fp fp) { |
3808 | 195k | u64 sig = fp.sig; |
3809 | 195k | i32 exp = fp.exp; |
3810 | 195k | u32 lz_bits; |
3811 | 195k | if (unlikely(fp.sig == 0)) return 0; |
3812 | | |
3813 | 195k | lz_bits = u64_lz_bits(sig); |
3814 | 195k | sig <<= lz_bits; |
3815 | 195k | sig >>= F64_BITS - F64_SIG_FULL_BITS; |
3816 | 195k | exp -= (i32)lz_bits; |
3817 | 195k | exp += F64_BITS - F64_SIG_FULL_BITS; |
3818 | 195k | exp += F64_SIG_BITS; |
3819 | | |
3820 | 195k | if (unlikely(exp >= F64_MAX_BIN_EXP)) { |
3821 | | /* overflow */ |
3822 | 1.12k | return F64_BITS_INF; |
3823 | 194k | } else if (likely(exp >= F64_MIN_BIN_EXP - 1)) { |
3824 | | /* normal */ |
3825 | 159k | exp += F64_EXP_BIAS; |
3826 | 159k | return ((u64)exp << F64_SIG_BITS) | (sig & F64_SIG_MASK); |
3827 | 159k | } else if (likely(exp >= F64_MIN_BIN_EXP - F64_SIG_FULL_BITS)) { |
3828 | | /* subnormal */ |
3829 | 30.2k | return sig >> (F64_MIN_BIN_EXP - exp - 1); |
3830 | 30.2k | } else { |
3831 | | /* underflow */ |
3832 | 5.01k | return 0; |
3833 | 5.01k | } |
3834 | 195k | } |
3835 | | |
3836 | | |
3837 | | |
3838 | | /*============================================================================== |
3839 | | * MARK: - Number Reader (Private) |
3840 | | *============================================================================*/ |
3841 | | |
3842 | | /** |
3843 | | Read a JSON number. |
3844 | | |
3845 | | 1. This function assume that the floating-point number is in IEEE-754 format. |
3846 | | 2. This function support uint64/int64/double number. If an integer number |
3847 | | cannot fit in uint64/int64, it will returns as a double number. If a double |
3848 | | number is infinite, the return value is based on flag. |
3849 | | 3. This function (with inline attribute) may generate a lot of instructions. |
3850 | | */ |
3851 | | static_inline bool read_num(u8 **ptr, u8 **pre, yyjson_read_flag flg, |
3852 | 3.43M | yyjson_val *val, const char **msg) { |
3853 | 3.43M | #define return_err(_pos, _msg) do { \ |
3854 | 6.45k | *msg = _msg; \ |
3855 | 6.45k | *end = _pos; \ |
3856 | 6.45k | return false; \ |
3857 | 6.45k | } while (false) |
3858 | | |
3859 | 3.43M | #define return_0() do { \ |
3860 | 27.0k | val->tag = YYJSON_TYPE_NUM | (u8)((u8)sign << 3); \ |
3861 | 27.0k | val->uni.u64 = 0; \ |
3862 | 27.0k | *end = cur; return true; \ |
3863 | 27.0k | } while (false) |
3864 | | |
3865 | 3.43M | #define return_i64(_v) do { \ |
3866 | 2.24M | val->tag = YYJSON_TYPE_NUM | (u8)((u8)sign << 3); \ |
3867 | 2.24M | val->uni.u64 = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \ |
3868 | 2.24M | *end = cur; return true; \ |
3869 | 2.24M | } while (false) |
3870 | | |
3871 | 3.43M | #define return_f64(_v) do { \ |
3872 | 837k | val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \ |
3873 | 837k | val->uni.f64 = sign ? -(f64)(_v) : (f64)(_v); \ |
3874 | 837k | *end = cur; return true; \ |
3875 | 837k | } while (false) |
3876 | | |
3877 | 3.43M | #define return_f64_bin(_v) do { \ |
3878 | 303k | val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \ |
3879 | 303k | val->uni.u64 = ((u64)sign << 63) | (u64)(_v); \ |
3880 | 303k | *end = cur; return true; \ |
3881 | 303k | } while (false) |
3882 | | |
3883 | 3.43M | #define return_inf() do { \ |
3884 | 5.89k | if (has_flg(BIGNUM_AS_RAW)) return_raw(); \ |
3885 | 5.89k | if (has_allow(INF_AND_NAN)) return_f64_bin(F64_BITS_INF); \ |
3886 | 5.89k | else return_err(hdr, "number is infinity when parsed as double"); \ |
3887 | 5.89k | } while (false) |
3888 | | |
3889 | 3.43M | #define return_raw() do { \ |
3890 | 0 | **pre = '\0'; /* add null-terminator for previous raw string */ \ |
3891 | 0 | val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \ |
3892 | 0 | val->uni.str = (const char *)hdr; \ |
3893 | 0 | *pre = cur; *end = cur; return true; \ |
3894 | 0 | } while (false) |
3895 | | |
3896 | 3.43M | u8 *sig_cut = NULL; /* significant part cutting position for long number */ |
3897 | 3.43M | u8 *sig_end = NULL; /* significant part ending position */ |
3898 | 3.43M | u8 *dot_pos = NULL; /* decimal point position */ |
3899 | | |
3900 | 3.43M | u64 sig = 0; /* significant part of the number */ |
3901 | 3.43M | i32 exp = 0; /* exponent part of the number */ |
3902 | | |
3903 | 3.43M | bool exp_sign; /* temporary exponent sign from literal part */ |
3904 | 3.43M | i64 exp_sig = 0; /* temporary exponent number from significant part */ |
3905 | 3.43M | i64 exp_lit = 0; /* temporary exponent number from exponent literal part */ |
3906 | 3.43M | u64 num; /* temporary number for reading */ |
3907 | 3.43M | u8 *tmp; /* temporary cursor for reading */ |
3908 | | |
3909 | 3.43M | u8 *hdr = *ptr; |
3910 | 3.43M | u8 *cur = *ptr; |
3911 | 3.43M | u8 **end = ptr; |
3912 | 3.43M | bool sign; |
3913 | | |
3914 | | /* read number as raw string if has `YYJSON_READ_NUMBER_AS_RAW` flag */ |
3915 | 3.43M | if (has_flg(NUMBER_AS_RAW)) { |
3916 | 0 | return read_num_raw(ptr, pre, flg, val, msg); |
3917 | 0 | } |
3918 | | |
3919 | 3.43M | sign = (*hdr == '-'); |
3920 | 3.43M | cur += sign; |
3921 | | |
3922 | | /* begin with a leading zero or non-digit */ |
3923 | 3.43M | while (unlikely(!char_is_nonzero(*cur))) { /* 0 or non-digit char */ |
3924 | 84.7k | if (unlikely(*cur != '0')) { /* non-digit char */ |
3925 | 18.1k | if (has_allow(EXT_NUMBER)) { |
3926 | 16.6k | if (*cur == '+' && cur == hdr) { /* leading `+` sign */ |
3927 | 5.56k | cur++; |
3928 | 5.56k | continue; |
3929 | 5.56k | } |
3930 | 11.1k | if (*cur == '.' && char_is_digit(cur[1])) { /* e.g. '.123' */ |
3931 | 4.88k | goto leading_dot; |
3932 | 4.88k | } |
3933 | 11.1k | } |
3934 | 7.67k | if (has_allow(INF_AND_NAN)) { |
3935 | 6.23k | if (read_inf_or_nan(ptr, pre, flg, val)) return true; |
3936 | 6.23k | } |
3937 | 1.73k | return_err(cur, "no digit after sign"); |
3938 | 1.73k | } |
3939 | | /* begin with 0 */ |
3940 | 66.6k | if (likely(!char_is_digit_or_fp(*++cur))) { |
3941 | 35.9k | if (has_allow(EXT_NUMBER) && char_to_lower(*cur) == 'x') { /* hex */ |
3942 | 8.82k | return read_num_hex(ptr, pre, flg, val, msg); |
3943 | 8.82k | } |
3944 | 27.0k | return_0(); |
3945 | 27.0k | } |
3946 | 30.7k | if (likely(*cur == '.')) { |
3947 | 31.1k | leading_dot: |
3948 | 31.1k | dot_pos = cur++; |
3949 | 31.1k | if (unlikely(!char_is_digit(*cur))) { |
3950 | 2.38k | if (has_allow(EXT_NUMBER)) { |
3951 | 2.23k | if (char_is_exp(*cur)) { |
3952 | 1.27k | goto digi_exp_more; |
3953 | 1.27k | } else { |
3954 | 960 | return_f64_bin(0); |
3955 | 960 | } |
3956 | 2.23k | } |
3957 | 148 | return_err(cur, "no digit after decimal point"); |
3958 | 148 | } |
3959 | 9.56M | while (unlikely(*cur == '0')) cur++; |
3960 | 28.7k | if (likely(char_is_digit(*cur))) { |
3961 | | /* first non-zero digit after decimal point */ |
3962 | 24.4k | sig = (u64)(*cur - '0'); /* read first digit */ |
3963 | 24.4k | cur--; |
3964 | 24.4k | goto digi_frac_1; /* continue read fraction part */ |
3965 | 24.4k | } |
3966 | 28.7k | } |
3967 | 8.81k | if (unlikely(char_is_digit(*cur))) { |
3968 | 242 | return_err(cur - 1, "number with leading zero is not allowed"); |
3969 | 242 | } |
3970 | 8.57k | if (unlikely(char_is_exp(*cur))) { /* 0 with any exponent is still 0 */ |
3971 | 4.35k | cur += (usize)1 + char_is_sign(cur[1]); |
3972 | 4.35k | if (unlikely(!char_is_digit(*cur))) { |
3973 | 114 | return_err(cur, "no digit after exponent sign"); |
3974 | 114 | } |
3975 | 11.3k | while (char_is_digit(*++cur)); |
3976 | 4.24k | } |
3977 | 8.45k | return_f64_bin(0); |
3978 | 8.45k | } |
3979 | | |
3980 | | /* begin with non-zero digit */ |
3981 | 3.35M | sig = (u64)(*cur - '0'); |
3982 | | |
3983 | | /* |
3984 | | Read integral part, same as the following code. |
3985 | | |
3986 | | for (int i = 1; i <= 18; i++) { |
3987 | | num = cur[i] - '0'; |
3988 | | if (num <= 9) sig = num + sig * 10; |
3989 | | else goto digi_sepr_i; |
3990 | | } |
3991 | | */ |
3992 | 3.35M | #define expr_intg(i) \ |
3993 | 17.3M | if (likely((num = (u64)(cur[i] - (u8)'0')) <= 9)) sig = num + sig * 10; \ |
3994 | 17.3M | else { goto digi_sepr_##i; } |
3995 | 17.3M | repeat_in_1_18(expr_intg) |
3996 | 140k | #undef expr_intg |
3997 | | |
3998 | | |
3999 | 140k | cur += 19; /* skip continuous 19 digits */ |
4000 | 140k | if (!char_is_digit_or_fp(*cur)) { |
4001 | | /* this number is an integer consisting of 19 digits */ |
4002 | 18.7k | if (sign && (sig > ((u64)1 << 63))) { /* overflow */ |
4003 | 2.64k | if (has_flg(BIGNUM_AS_RAW)) return_raw(); |
4004 | 2.64k | return_f64(unsafe_yyjson_u64_to_f64(sig)); |
4005 | 2.64k | } |
4006 | 16.0k | return_i64(sig); |
4007 | 16.0k | } |
4008 | 121k | goto digi_intg_more; /* read more digits in integral part */ |
4009 | | |
4010 | | |
4011 | | /* process first non-digit character */ |
4012 | 121k | #define expr_sepr(i) \ |
4013 | 3.21M | digi_sepr_##i: \ |
4014 | 3.21M | if (likely(!char_is_fp(cur[i]))) { cur += i; return_i64(sig); } \ |
4015 | 3.21M | dot_pos = cur + i; \ |
4016 | 991k | if (likely(cur[i] == '.')) goto digi_frac_##i; \ |
4017 | 991k | cur += i; sig_end = cur; goto digi_exp_more; |
4018 | 4.20M | repeat_in_1_18(expr_sepr) |
4019 | 0 | #undef expr_sepr |
4020 | | |
4021 | | |
4022 | | /* read fraction part */ |
4023 | 0 | #define expr_frac(i) \ |
4024 | 3.82M | digi_frac_##i: \ |
4025 | 3.82M | if (likely((num = (u64)(cur[i + 1] - (u8)'0')) <= 9)) \ |
4026 | 3.82M | sig = num + sig * 10; \ |
4027 | 3.82M | else { goto digi_stop_##i; } |
4028 | 3.82M | repeat_in_1_18(expr_frac) |
4029 | 38.6k | #undef expr_frac |
4030 | | |
4031 | 38.6k | cur += 20; /* skip 19 digits and 1 decimal point */ |
4032 | 38.6k | if (!char_is_digit(*cur)) goto digi_frac_end; /* fraction part end */ |
4033 | 30.6k | goto digi_frac_more; /* read more digits in fraction part */ |
4034 | | |
4035 | | |
4036 | | /* significant part end */ |
4037 | 30.6k | #define expr_stop(i) \ |
4038 | 825k | digi_stop_##i: \ |
4039 | 825k | cur += i + 1; \ |
4040 | 825k | goto digi_frac_end; |
4041 | 825k | repeat_in_1_18(expr_stop) |
4042 | 0 | #undef expr_stop |
4043 | | |
4044 | | |
4045 | | /* read more digits in integral part */ |
4046 | 121k | digi_intg_more: |
4047 | 121k | if (char_is_digit(*cur)) { |
4048 | 108k | if (!char_is_digit_or_fp(cur[1])) { |
4049 | | /* this number is an integer consisting of 20 digits */ |
4050 | 17.3k | num = (u64)(*cur - '0'); |
4051 | 17.3k | if ((sig < (U64_MAX / 10)) || |
4052 | 12.2k | (sig == (U64_MAX / 10) && num <= (U64_MAX % 10))) { |
4053 | 8.22k | sig = num + sig * 10; |
4054 | 8.22k | cur++; |
4055 | | /* convert to double if overflow */ |
4056 | 8.22k | if (sign) { |
4057 | 2.93k | if (has_flg(BIGNUM_AS_RAW)) return_raw(); |
4058 | 2.93k | return_f64(unsafe_yyjson_u64_to_f64(sig)); |
4059 | 2.93k | } |
4060 | 5.29k | return_i64(sig); |
4061 | 5.29k | } |
4062 | 17.3k | } |
4063 | 108k | } |
4064 | | |
4065 | 113k | if (char_is_exp(*cur)) { |
4066 | 6.40k | dot_pos = cur; |
4067 | 6.40k | goto digi_exp_more; |
4068 | 6.40k | } |
4069 | | |
4070 | 106k | if (*cur == '.') { |
4071 | 6.59k | dot_pos = cur++; |
4072 | 6.59k | if (unlikely(!char_is_digit(*cur))) { |
4073 | 831 | if (has_allow(EXT_NUMBER)) { |
4074 | 781 | goto digi_frac_end; |
4075 | 781 | } |
4076 | 50 | return_err(cur, "no digit after decimal point"); |
4077 | 50 | } |
4078 | 6.59k | } |
4079 | | |
4080 | | |
4081 | | /* read more digits in fraction part */ |
4082 | 136k | digi_frac_more: |
4083 | 136k | sig_cut = cur; /* too large to fit in u64, excess digits need to be cut */ |
4084 | 136k | sig += (*cur >= '5'); /* round */ |
4085 | 3.54M | while (char_is_digit(*++cur)); |
4086 | 136k | if (!dot_pos) { |
4087 | 100k | if (!char_is_fp(*cur) && has_flg(BIGNUM_AS_RAW)) { |
4088 | 0 | return_raw(); /* it's a large integer */ |
4089 | 0 | } |
4090 | 100k | dot_pos = cur; |
4091 | 100k | if (*cur == '.') { |
4092 | 18.3k | if (unlikely(!char_is_digit(*++cur))) { |
4093 | 2.56k | if (!has_allow(EXT_NUMBER)) { |
4094 | 96 | return_err(cur, "no digit after decimal point"); |
4095 | 96 | } |
4096 | 2.56k | } |
4097 | 2.99M | while (char_is_digit(*cur)) cur++; |
4098 | 18.2k | } |
4099 | 100k | } |
4100 | 136k | exp_sig = (i64)(dot_pos - sig_cut); |
4101 | 136k | exp_sig += (dot_pos < sig_cut); |
4102 | | |
4103 | | /* ignore trailing zeros */ |
4104 | 136k | tmp = cur - 1; |
4105 | 667k | while ((*tmp == '0' || *tmp == '.') && tmp > hdr) tmp--; |
4106 | 136k | if (tmp < sig_cut) { |
4107 | 8.87k | sig_cut = NULL; |
4108 | 127k | } else { |
4109 | 127k | sig_end = cur; |
4110 | 127k | } |
4111 | | |
4112 | 136k | if (char_is_exp(*cur)) goto digi_exp_more; |
4113 | 106k | goto digi_exp_finish; |
4114 | | |
4115 | | |
4116 | | /* fraction part end */ |
4117 | 833k | digi_frac_end: |
4118 | 833k | if (unlikely(dot_pos + 1 == cur)) { |
4119 | 41.2k | if (!has_allow(EXT_NUMBER)) { |
4120 | 1.40k | return_err(cur, "no digit after decimal point"); |
4121 | 1.40k | } |
4122 | 41.2k | } |
4123 | 832k | sig_end = cur; |
4124 | 832k | exp_sig = -(i64)((u64)(cur - dot_pos) - 1); |
4125 | 832k | if (likely(!char_is_exp(*cur))) { |
4126 | 806k | if (unlikely(exp_sig < F64_MIN_DEC_EXP - 19)) { |
4127 | 1.69k | return_f64_bin(0); /* underflow */ |
4128 | 1.69k | } |
4129 | 804k | exp = (i32)exp_sig; |
4130 | 804k | goto digi_finish; |
4131 | 806k | } else { |
4132 | 26.1k | goto digi_exp_more; |
4133 | 26.1k | } |
4134 | | |
4135 | | |
4136 | | /* read exponent part */ |
4137 | 216k | digi_exp_more: |
4138 | 216k | exp_sign = (*++cur == '-'); |
4139 | 216k | cur += char_is_sign(*cur); |
4140 | 216k | if (unlikely(!char_is_digit(*cur))) { |
4141 | 1.70k | return_err(cur, "no digit after exponent sign"); |
4142 | 1.70k | } |
4143 | 249k | while (*cur == '0') cur++; |
4144 | | |
4145 | | /* read exponent literal */ |
4146 | 214k | tmp = cur; |
4147 | 3.92M | while (char_is_digit(*cur)) { |
4148 | 3.71M | exp_lit = (i64)((u8)(*cur++ - '0') + (u64)exp_lit * 10); |
4149 | 3.71M | } |
4150 | 214k | if (unlikely(cur - tmp >= U64_SAFE_DIG)) { |
4151 | 4.31k | if (exp_sign) { |
4152 | 3.56k | return_f64_bin(0); /* underflow */ |
4153 | 3.56k | } else { |
4154 | 747 | return_inf(); /* overflow */ |
4155 | 747 | } |
4156 | 4.31k | } |
4157 | 210k | exp_sig += exp_sign ? -exp_lit : exp_lit; |
4158 | | |
4159 | | |
4160 | | /* validate exponent value */ |
4161 | 316k | digi_exp_finish: |
4162 | 316k | if (unlikely(exp_sig < F64_MIN_DEC_EXP - 19)) { |
4163 | 15.3k | return_f64_bin(0); /* underflow */ |
4164 | 15.3k | } |
4165 | 301k | if (unlikely(exp_sig > F64_MAX_DEC_EXP)) { |
4166 | 3.41k | return_inf(); /* overflow */ |
4167 | 3.41k | } |
4168 | 297k | exp = (i32)exp_sig; |
4169 | | |
4170 | | |
4171 | | /* all digit read finished */ |
4172 | 1.10M | digi_finish: |
4173 | | |
4174 | | /* |
4175 | | Fast path 1: |
4176 | | |
4177 | | 1. The floating-point number calculation should be accurate, see the |
4178 | | comments of macro `YYJSON_DOUBLE_MATH_CORRECT`. |
4179 | | 2. Correct rounding should be performed (fegetround() == FE_TONEAREST). |
4180 | | 3. The input to floating-point calculations does not lose precision, |
4181 | | which means: 64 - leading_zero(input) - trailing_zero(input) < 53. |
4182 | | |
4183 | | We don't check all available inputs here, because that would make the code |
4184 | | more complicated, and not friendly to branch predictor. |
4185 | | */ |
4186 | 1.10M | #if YYJSON_DOUBLE_MATH_CORRECT |
4187 | 1.10M | if (sig < ((u64)1 << 53) && |
4188 | 924k | exp >= -F64_POW10_MAX_EXACT_EXP && |
4189 | 882k | exp <= +F64_POW10_MAX_EXACT_EXP) { |
4190 | 831k | f64 dbl = (f64)sig; |
4191 | 831k | if (exp < 0) { |
4192 | 746k | dbl /= f64_pow10_table[-exp]; |
4193 | 746k | } else { |
4194 | 85.1k | dbl *= f64_pow10_table[+exp]; |
4195 | 85.1k | } |
4196 | 831k | return_f64(dbl); |
4197 | 831k | } |
4198 | 270k | #endif |
4199 | 270k | if (unlikely(sig == 0)) return_f64_bin(0); |
4200 | | |
4201 | | /* |
4202 | | Fast path 2: |
4203 | | |
4204 | | To keep it simple, we only accept normal number here, |
4205 | | let the slow path handle subnormal and infinite numbers. |
4206 | | */ |
4207 | 269k | if (likely(!sig_cut && |
4208 | 269k | exp > -F64_MAX_DEC_EXP + 1 && |
4209 | 269k | exp < +F64_MAX_DEC_EXP - 20)) { |
4210 | | /* |
4211 | | The result value is exactly equal to (sig * 10^exp), |
4212 | | the exponent part (10^exp) can be converted to (sig2 * 2^exp2). |
4213 | | |
4214 | | The sig2 can be an infinite length number, only the highest 128 bits |
4215 | | is cached in the pow10_sig_table. |
4216 | | |
4217 | | Now we have these bits: |
4218 | | sig1 (normalized 64bit) : aaaaaaaa |
4219 | | sig2 (higher 64bit) : bbbbbbbb |
4220 | | sig2_ext (lower 64bit) : cccccccc |
4221 | | sig2_cut (extra unknown bits) : dddddddddddd.... |
4222 | | |
4223 | | And the calculation process is: |
4224 | | ---------------------------------------- |
4225 | | aaaaaaaa * |
4226 | | bbbbbbbbccccccccdddddddddddd.... |
4227 | | ---------------------------------------- |
4228 | | abababababababab + |
4229 | | acacacacacacacac + |
4230 | | adadadadadadadadadad.... |
4231 | | ---------------------------------------- |
4232 | | [hi____][lo____] + |
4233 | | [hi2___][lo2___] + |
4234 | | [unknown___________....] |
4235 | | ---------------------------------------- |
4236 | | |
4237 | | The addition with carry may affect higher bits, but if there is a 0 |
4238 | | in higher bits, the bits higher than 0 will not be affected. |
4239 | | |
4240 | | `lo2` + `unknown` may get a carry bit and may affect `hi2`, the max |
4241 | | value of `hi2` is 0xFFFFFFFFFFFFFFFE, so `hi2` will not overflow. |
4242 | | |
4243 | | `lo` + `hi2` may also get a carry bit and may affect `hi`, but only |
4244 | | the highest significant 53 bits of `hi` is needed. If there is a 0 |
4245 | | in the lower bits of `hi`, then all the following bits can be dropped. |
4246 | | |
4247 | | To convert the result to IEEE-754 double number, we need to perform |
4248 | | correct rounding: |
4249 | | 1. if bit 54 is 0, round down, |
4250 | | 2. if bit 54 is 1 and any bit beyond bit 54 is 1, round up, |
4251 | | 3. if bit 54 is 1 and all bits beyond bit 54 are 0, round to even, |
4252 | | as the extra bits is unknown, this case will not be handled here. |
4253 | | */ |
4254 | | |
4255 | 94.4k | u64 raw; |
4256 | 94.4k | u64 sig1, sig2, sig2_ext, hi, lo, hi2, lo2, add, bits; |
4257 | 94.4k | i32 exp2; |
4258 | 94.4k | u32 lz; |
4259 | 94.4k | bool exact = false, carry, round_up; |
4260 | | |
4261 | | /* convert (10^exp) to (sig2 * 2^exp2) */ |
4262 | 94.4k | pow10_table_get_sig(exp, &sig2, &sig2_ext); |
4263 | 94.4k | pow10_table_get_exp(exp, &exp2); |
4264 | | |
4265 | | /* normalize and multiply */ |
4266 | 94.4k | lz = u64_lz_bits(sig); |
4267 | 94.4k | sig1 = sig << lz; |
4268 | 94.4k | exp2 -= (i32)lz; |
4269 | 94.4k | u128_mul(sig1, sig2, &hi, &lo); |
4270 | | |
4271 | | /* |
4272 | | The `hi` is in range [0x4000000000000000, 0xFFFFFFFFFFFFFFFE], |
4273 | | To get normalized value, `hi` should be shifted to the left by 0 or 1. |
4274 | | |
4275 | | The highest significant 53 bits is used by IEEE-754 double number, |
4276 | | and the bit 54 is used to detect rounding direction. |
4277 | | |
4278 | | The lowest (64 - 54 - 1) bits is used to check whether it contains 0. |
4279 | | */ |
4280 | 94.4k | bits = hi & (((u64)1 << (64 - 54 - 1)) - 1); |
4281 | 94.4k | if (bits - 1 < (((u64)1 << (64 - 54 - 1)) - 2)) { |
4282 | | /* |
4283 | | (bits != 0 && bits != 0x1FF) => (bits - 1 < 0x1FF - 1) |
4284 | | The `bits` is not zero, so we don't need to check `round to even` |
4285 | | case. The `bits` contains bit `0`, so we can drop the extra bits |
4286 | | after `0`. |
4287 | | */ |
4288 | 65.1k | exact = true; |
4289 | | |
4290 | 65.1k | } else { |
4291 | | /* |
4292 | | (bits == 0 || bits == 0x1FF) |
4293 | | The `bits` is filled with all `0` or all `1`, so we need to check |
4294 | | lower bits with another 64-bit multiplication. |
4295 | | */ |
4296 | 29.2k | u128_mul(sig1, sig2_ext, &hi2, &lo2); |
4297 | | |
4298 | 29.2k | add = lo + hi2; |
4299 | 29.2k | if (add + 1 > (u64)1) { |
4300 | | /* |
4301 | | (add != 0 && add != U64_MAX) => (add + 1 > 1) |
4302 | | The `add` is not zero, so we don't need to check `round to |
4303 | | even` case. The `add` contains bit `0`, so we can drop the |
4304 | | extra bits after `0`. The `hi` cannot be U64_MAX, so it will |
4305 | | not overflow. |
4306 | | */ |
4307 | 8.76k | carry = add < lo || add < hi2; |
4308 | 8.76k | hi += carry; |
4309 | 8.76k | exact = true; |
4310 | 8.76k | } |
4311 | 29.2k | } |
4312 | | |
4313 | 94.4k | if (exact) { |
4314 | | /* normalize */ |
4315 | 73.9k | lz = hi < ((u64)1 << 63); |
4316 | 73.9k | hi <<= lz; |
4317 | 73.9k | exp2 -= (i32)lz; |
4318 | 73.9k | exp2 += 64; |
4319 | | |
4320 | | /* test the bit 54 and get rounding direction */ |
4321 | 73.9k | round_up = (hi & ((u64)1 << (64 - 54))) > (u64)0; |
4322 | 73.9k | hi += (round_up ? ((u64)1 << (64 - 54)) : (u64)0); |
4323 | | |
4324 | | /* test overflow */ |
4325 | 73.9k | if (hi < ((u64)1 << (64 - 54))) { |
4326 | 3.87k | hi = ((u64)1 << 63); |
4327 | 3.87k | exp2 += 1; |
4328 | 3.87k | } |
4329 | | |
4330 | | /* This is a normal number, convert it to IEEE-754 format. */ |
4331 | 73.9k | hi >>= F64_BITS - F64_SIG_FULL_BITS; |
4332 | 73.9k | exp2 += F64_BITS - F64_SIG_FULL_BITS + F64_SIG_BITS; |
4333 | 73.9k | exp2 += F64_EXP_BIAS; |
4334 | 73.9k | raw = ((u64)exp2 << F64_SIG_BITS) | (hi & F64_SIG_MASK); |
4335 | 73.9k | return_f64_bin(raw); |
4336 | 73.9k | } |
4337 | 94.4k | } |
4338 | | |
4339 | | /* |
4340 | | Slow path: read double number exactly with diyfp. |
4341 | | 1. Use cached diyfp to get an approximation value. |
4342 | | 2. Use bigcomp to check the approximation value if needed. |
4343 | | |
4344 | | This algorithm refers to google's double-conversion project: |
4345 | | https://github.com/google/double-conversion |
4346 | | */ |
4347 | 195k | { |
4348 | 195k | const i32 ERR_ULP_LOG = 3; |
4349 | 195k | const i32 ERR_ULP = 1 << ERR_ULP_LOG; |
4350 | 195k | const i32 ERR_CACHED_POW = ERR_ULP / 2; |
4351 | 195k | const i32 ERR_MUL_FIXED = ERR_ULP / 2; |
4352 | 195k | const i32 DIY_SIG_BITS = 64; |
4353 | 195k | const i32 EXP_BIAS = F64_EXP_BIAS + F64_SIG_BITS; |
4354 | 195k | const i32 EXP_SUBNORMAL = -EXP_BIAS + 1; |
4355 | | |
4356 | 195k | u64 fp_err; |
4357 | 195k | u32 bits; |
4358 | 195k | i32 order_of_magnitude; |
4359 | 195k | i32 effective_significand_size; |
4360 | 195k | i32 precision_digits_count; |
4361 | 195k | u64 precision_bits; |
4362 | 195k | u64 half_way; |
4363 | | |
4364 | 195k | u64 raw; |
4365 | 195k | diy_fp fp, fp_upper; |
4366 | 195k | bigint big_full, big_comp; |
4367 | 195k | i32 cmp; |
4368 | | |
4369 | 195k | fp.sig = sig; |
4370 | 195k | fp.exp = 0; |
4371 | 195k | fp_err = sig_cut ? (u64)(ERR_ULP / 2) : (u64)0; |
4372 | | |
4373 | | /* normalize */ |
4374 | 195k | bits = u64_lz_bits(fp.sig); |
4375 | 195k | fp.sig <<= bits; |
4376 | 195k | fp.exp -= (i32)bits; |
4377 | 195k | fp_err <<= bits; |
4378 | | |
4379 | | /* multiply and add error */ |
4380 | 195k | fp = diy_fp_mul(fp, diy_fp_get_cached_pow10(exp)); |
4381 | 195k | fp_err += (u64)ERR_CACHED_POW + (fp_err != 0) + (u64)ERR_MUL_FIXED; |
4382 | | |
4383 | | /* normalize */ |
4384 | 195k | bits = u64_lz_bits(fp.sig); |
4385 | 195k | fp.sig <<= bits; |
4386 | 195k | fp.exp -= (i32)bits; |
4387 | 195k | fp_err <<= bits; |
4388 | | |
4389 | | /* effective significand */ |
4390 | 195k | order_of_magnitude = DIY_SIG_BITS + fp.exp; |
4391 | 195k | if (likely(order_of_magnitude >= EXP_SUBNORMAL + F64_SIG_FULL_BITS)) { |
4392 | 160k | effective_significand_size = F64_SIG_FULL_BITS; |
4393 | 160k | } else if (order_of_magnitude <= EXP_SUBNORMAL) { |
4394 | 5.33k | effective_significand_size = 0; |
4395 | 29.9k | } else { |
4396 | 29.9k | effective_significand_size = order_of_magnitude - EXP_SUBNORMAL; |
4397 | 29.9k | } |
4398 | | |
4399 | | /* precision digits count */ |
4400 | 195k | precision_digits_count = DIY_SIG_BITS - effective_significand_size; |
4401 | 195k | if (unlikely(precision_digits_count + ERR_ULP_LOG >= DIY_SIG_BITS)) { |
4402 | 8.72k | i32 shr = (precision_digits_count + ERR_ULP_LOG) - DIY_SIG_BITS + 1; |
4403 | 8.72k | fp.sig >>= shr; |
4404 | 8.72k | fp.exp += shr; |
4405 | 8.72k | fp_err = (fp_err >> shr) + 1 + (u32)ERR_ULP; |
4406 | 8.72k | precision_digits_count -= shr; |
4407 | 8.72k | } |
4408 | | |
4409 | | /* half way */ |
4410 | 195k | precision_bits = fp.sig & (((u64)1 << precision_digits_count) - 1); |
4411 | 195k | precision_bits *= (u32)ERR_ULP; |
4412 | 195k | half_way = (u64)1 << (precision_digits_count - 1); |
4413 | 195k | half_way *= (u32)ERR_ULP; |
4414 | | |
4415 | | /* rounding */ |
4416 | 195k | fp.sig >>= precision_digits_count; |
4417 | 195k | fp.sig += (precision_bits >= half_way + fp_err); |
4418 | 195k | fp.exp += precision_digits_count; |
4419 | | |
4420 | | /* get IEEE double raw value */ |
4421 | 195k | raw = diy_fp_to_ieee_raw(fp); |
4422 | 195k | if (unlikely(raw == F64_BITS_INF)) return_inf(); |
4423 | 194k | if (likely(precision_bits <= half_way - fp_err || |
4424 | 194k | precision_bits >= half_way + fp_err)) { |
4425 | 112k | return_f64_bin(raw); /* number is accurate */ |
4426 | 112k | } |
4427 | | /* now the number is the correct value, or the next lower value */ |
4428 | | |
4429 | | /* upper boundary */ |
4430 | 81.7k | if (raw & F64_EXP_MASK) { |
4431 | 75.0k | fp_upper.sig = (raw & F64_SIG_MASK) + ((u64)1 << F64_SIG_BITS); |
4432 | 75.0k | fp_upper.exp = (i32)((raw & F64_EXP_MASK) >> F64_SIG_BITS); |
4433 | 75.0k | } else { |
4434 | 6.72k | fp_upper.sig = (raw & F64_SIG_MASK); |
4435 | 6.72k | fp_upper.exp = 1; |
4436 | 6.72k | } |
4437 | 81.7k | fp_upper.exp -= F64_EXP_BIAS + F64_SIG_BITS; |
4438 | 81.7k | fp_upper.sig <<= 1; |
4439 | 81.7k | fp_upper.exp -= 1; |
4440 | 81.7k | fp_upper.sig += 1; /* add half ulp */ |
4441 | | |
4442 | | /* compare with bigint */ |
4443 | 81.7k | bigint_set_buf(&big_full, sig, &exp, sig_cut, sig_end, dot_pos); |
4444 | 81.7k | bigint_set_u64(&big_comp, fp_upper.sig); |
4445 | 81.7k | if (exp >= 0) { |
4446 | 36.8k | bigint_mul_pow10(&big_full, +exp); |
4447 | 44.9k | } else { |
4448 | 44.9k | bigint_mul_pow10(&big_comp, -exp); |
4449 | 44.9k | } |
4450 | 81.7k | if (fp_upper.exp > 0) { |
4451 | 47.6k | bigint_mul_pow2(&big_comp, (u32)+fp_upper.exp); |
4452 | 47.6k | } else { |
4453 | 34.1k | bigint_mul_pow2(&big_full, (u32)-fp_upper.exp); |
4454 | 34.1k | } |
4455 | 81.7k | cmp = bigint_cmp(&big_full, &big_comp); |
4456 | 81.7k | if (likely(cmp != 0)) { |
4457 | | /* round down or round up */ |
4458 | 64.4k | raw += (cmp > 0); |
4459 | 64.4k | } else { |
4460 | | /* falls midway, round to even */ |
4461 | 17.2k | raw += (raw & 1); |
4462 | 17.2k | } |
4463 | | |
4464 | 81.7k | if (unlikely(raw == F64_BITS_INF)) return_inf(); |
4465 | 81.1k | return_f64_bin(raw); |
4466 | 81.1k | } |
4467 | | |
4468 | 81.1k | #undef return_err |
4469 | 81.1k | #undef return_inf |
4470 | 81.1k | #undef return_0 |
4471 | 81.1k | #undef return_i64 |
4472 | 81.1k | #undef return_f64 |
4473 | 81.1k | #undef return_f64_bin |
4474 | 81.1k | #undef return_raw |
4475 | 81.1k | } |
4476 | | |
4477 | | |
4478 | | |
4479 | | #else /* FP_READER */ |
4480 | | |
4481 | | /** |
4482 | | Read a JSON number. |
4483 | | This is a fallback function if the custom number reader is disabled. |
4484 | | This function use libc's strtod() to read floating-point number. |
4485 | | */ |
4486 | | static_inline bool read_num(u8 **ptr, u8 **pre, yyjson_read_flag flg, |
4487 | | yyjson_val *val, const char **msg) { |
4488 | | #define return_err(_pos, _msg) do { \ |
4489 | | *msg = _msg; \ |
4490 | | *end = _pos; \ |
4491 | | return false; \ |
4492 | | } while (false) |
4493 | | |
4494 | | #define return_0() do { \ |
4495 | | val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); \ |
4496 | | val->uni.u64 = 0; \ |
4497 | | *end = cur; return true; \ |
4498 | | } while (false) |
4499 | | |
4500 | | #define return_i64(_v) do { \ |
4501 | | val->tag = YYJSON_TYPE_NUM | (u64)((u8)sign << 3); \ |
4502 | | val->uni.u64 = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \ |
4503 | | *end = cur; return true; \ |
4504 | | } while (false) |
4505 | | |
4506 | | #define return_f64(_v) do { \ |
4507 | | val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \ |
4508 | | val->uni.f64 = sign ? -(f64)(_v) : (f64)(_v); \ |
4509 | | *end = cur; return true; \ |
4510 | | } while (false) |
4511 | | |
4512 | | #define return_f64_bin(_v) do { \ |
4513 | | val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; \ |
4514 | | val->uni.u64 = ((u64)sign << 63) | (u64)(_v); \ |
4515 | | *end = cur; return true; \ |
4516 | | } while (false) |
4517 | | |
4518 | | #define return_inf() do { \ |
4519 | | if (has_flg(BIGNUM_AS_RAW)) return_raw(); \ |
4520 | | if (has_allow(INF_AND_NAN)) return_f64_bin(F64_BITS_INF); \ |
4521 | | else return_err(hdr, "number is infinity when parsed as double"); \ |
4522 | | } while (false) |
4523 | | |
4524 | | #define return_raw() do { \ |
4525 | | val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \ |
4526 | | val->uni.str = (const char *)hdr; \ |
4527 | | **pre = '\0'; *pre = cur; *end = cur; return true; \ |
4528 | | } while (false) |
4529 | | |
4530 | | u64 sig, num; |
4531 | | u8 *hdr = *ptr; |
4532 | | u8 *cur = *ptr; |
4533 | | u8 **end = ptr; |
4534 | | u8 *dot = NULL; |
4535 | | u8 *f64_end = NULL; |
4536 | | bool sign; |
4537 | | |
4538 | | /* read number as raw string if has `YYJSON_READ_NUMBER_AS_RAW` flag */ |
4539 | | if (has_flg(NUMBER_AS_RAW)) { |
4540 | | return read_num_raw(ptr, pre, flg, val, msg); |
4541 | | } |
4542 | | |
4543 | | sign = (*hdr == '-'); |
4544 | | cur += sign; |
4545 | | sig = (u8)(*cur - '0'); |
4546 | | |
4547 | | /* read first digit, check leading zero */ |
4548 | | while (unlikely(!char_is_digit(*cur))) { |
4549 | | if (has_allow(EXT_NUMBER)) { |
4550 | | if (*cur == '+' && cur == hdr) { /* leading `+` sign */ |
4551 | | cur++; |
4552 | | sig = (u8)(*cur - '0'); |
4553 | | continue; |
4554 | | } |
4555 | | if (*cur == '.' && char_is_num(cur[1])) { /* no integer part */ |
4556 | | goto read_double; /* e.g. '.123' */ |
4557 | | } |
4558 | | } |
4559 | | if (has_allow(INF_AND_NAN)) { |
4560 | | if (read_inf_or_nan(ptr, pre, flg, val)) return true; |
4561 | | } |
4562 | | return_err(cur, "no digit after sign"); |
4563 | | } |
4564 | | if (*cur == '0') { |
4565 | | cur++; |
4566 | | if (unlikely(char_is_digit(*cur))) { |
4567 | | return_err(cur - 1, "number with leading zero is not allowed"); |
4568 | | } |
4569 | | if (!char_is_fp(*cur)) { |
4570 | | if (has_allow(EXT_NUMBER) && |
4571 | | (*cur == 'x' || *cur == 'X')) { /* hex integer */ |
4572 | | return read_num_hex(ptr, pre, flg, val, msg); |
4573 | | } |
4574 | | return_0(); |
4575 | | } |
4576 | | goto read_double; |
4577 | | } |
4578 | | |
4579 | | /* read continuous digits, up to 19 characters */ |
4580 | | #define expr_intg(i) \ |
4581 | | if (likely((num = (u64)(cur[i] - (u8)'0')) <= 9)) sig = num + sig * 10; \ |
4582 | | else { cur += i; goto intg_end; } |
4583 | | repeat_in_1_18(expr_intg) |
4584 | | #undef expr_intg |
4585 | | |
4586 | | /* here are 19 continuous digits, skip them */ |
4587 | | cur += 19; |
4588 | | if (char_is_digit(cur[0]) && !char_is_digit_or_fp(cur[1])) { |
4589 | | /* this number is an integer consisting of 20 digits */ |
4590 | | num = (u8)(*cur - '0'); |
4591 | | if ((sig < (U64_MAX / 10)) || |
4592 | | (sig == (U64_MAX / 10) && num <= (U64_MAX % 10))) { |
4593 | | sig = num + sig * 10; |
4594 | | cur++; |
4595 | | if (sign) { |
4596 | | if (has_flg(BIGNUM_AS_RAW)) return_raw(); |
4597 | | return_f64(unsafe_yyjson_u64_to_f64(sig)); |
4598 | | } |
4599 | | return_i64(sig); |
4600 | | } |
4601 | | } |
4602 | | |
4603 | | intg_end: |
4604 | | /* continuous digits ended */ |
4605 | | if (!char_is_digit_or_fp(*cur)) { |
4606 | | /* this number is an integer consisting of 1 to 19 digits */ |
4607 | | if (sign && (sig > ((u64)1 << 63))) { |
4608 | | if (has_flg(BIGNUM_AS_RAW)) return_raw(); |
4609 | | return_f64(unsafe_yyjson_u64_to_f64(sig)); |
4610 | | } |
4611 | | return_i64(sig); |
4612 | | } |
4613 | | |
4614 | | read_double: |
4615 | | /* this number should be read as double */ |
4616 | | while (char_is_digit(*cur)) cur++; |
4617 | | if (!char_is_fp(*cur) && has_flg(BIGNUM_AS_RAW)) { |
4618 | | return_raw(); /* it's a large integer */ |
4619 | | } |
4620 | | while (*cur == '.') { |
4621 | | /* skip fraction part */ |
4622 | | dot = cur; |
4623 | | cur++; |
4624 | | if (!char_is_digit(*cur)) { |
4625 | | if (has_allow(EXT_NUMBER)) { |
4626 | | break; |
4627 | | } else { |
4628 | | return_err(cur, "no digit after decimal point"); |
4629 | | } |
4630 | | } |
4631 | | cur++; |
4632 | | while (char_is_digit(*cur)) cur++; |
4633 | | break; |
4634 | | } |
4635 | | if (char_is_exp(*cur)) { |
4636 | | /* skip exponent part */ |
4637 | | cur += 1 + char_is_sign(cur[1]); |
4638 | | if (!char_is_digit(*cur)) { |
4639 | | return_err(cur, "no digit after exponent sign"); |
4640 | | } |
4641 | | cur++; |
4642 | | while (char_is_digit(*cur)) cur++; |
4643 | | } |
4644 | | |
4645 | | /* |
4646 | | libc's strtod() is used to parse the floating-point number. |
4647 | | |
4648 | | Note that the decimal point character used by strtod() is locale-dependent, |
4649 | | and the rounding direction may affected by fesetround(). |
4650 | | |
4651 | | For currently known locales, (en, zh, ja, ko, am, he, hi) use '.' as the |
4652 | | decimal point, while other locales use ',' as the decimal point. |
4653 | | |
4654 | | Here strtod() is called twice for different locales, but if another thread |
4655 | | happens calls setlocale() between two strtod(), parsing may still fail. |
4656 | | */ |
4657 | | val->uni.f64 = strtod((const char *)hdr, (char **)&f64_end); |
4658 | | if (unlikely(f64_end != cur)) { |
4659 | | /* replace '.' with ',' for locale */ |
4660 | | bool cut = (*cur == ','); |
4661 | | if (cut) *cur = ' '; |
4662 | | if (dot) *dot = ','; |
4663 | | val->uni.f64 = strtod((const char *)hdr, (char **)&f64_end); |
4664 | | /* restore ',' to '.' */ |
4665 | | if (cut) *cur = ','; |
4666 | | if (dot) *dot = '.'; |
4667 | | if (unlikely(f64_end != cur)) { |
4668 | | return_err(hdr, "strtod() failed to parse the number"); |
4669 | | } |
4670 | | } |
4671 | | if (unlikely(f64_is_inf(val->uni.f64))) { |
4672 | | return_inf(); |
4673 | | } |
4674 | | val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; |
4675 | | *end = cur; |
4676 | | return true; |
4677 | | |
4678 | | #undef return_err |
4679 | | #undef return_0 |
4680 | | #undef return_i64 |
4681 | | #undef return_f64 |
4682 | | #undef return_f64_bin |
4683 | | #undef return_inf |
4684 | | #undef return_raw |
4685 | | } |
4686 | | |
4687 | | #endif /* FP_READER */ |
4688 | | |
4689 | | |
4690 | | |
4691 | | /*============================================================================== |
4692 | | * MARK: - String Reader (Private) |
4693 | | *============================================================================*/ |
4694 | | |
4695 | | /** Read unicode escape sequence. */ |
4696 | 31.3k | static_inline bool read_uni_esc(u8 **src_ptr, u8 **dst_ptr, const char **msg) { |
4697 | 31.3k | #define return_err(_end, _msg) *msg = _msg; *src_ptr = _end; return false |
4698 | | |
4699 | 31.3k | u8 *src = *src_ptr; |
4700 | 31.3k | u8 *dst = *dst_ptr; |
4701 | 31.3k | u16 hi, lo; |
4702 | 31.3k | u32 uni; |
4703 | | |
4704 | 31.3k | src += 2; /* skip `\u` */ |
4705 | 31.3k | if (unlikely(!hex_load_4(src, &hi))) { |
4706 | 214 | return_err(src - 2, "invalid escaped sequence in string"); |
4707 | 214 | } |
4708 | 31.1k | src += 4; /* skip hex */ |
4709 | 31.1k | if (likely((hi & 0xF800) != 0xD800)) { |
4710 | | /* a BMP character */ |
4711 | 23.9k | if (hi >= 0x800) { |
4712 | 8.83k | *dst++ = (u8)(0xE0 | (hi >> 12)); |
4713 | 8.83k | *dst++ = (u8)(0x80 | ((hi >> 6) & 0x3F)); |
4714 | 8.83k | *dst++ = (u8)(0x80 | (hi & 0x3F)); |
4715 | 15.1k | } else if (hi >= 0x80) { |
4716 | 6.93k | *dst++ = (u8)(0xC0 | (hi >> 6)); |
4717 | 6.93k | *dst++ = (u8)(0x80 | (hi & 0x3F)); |
4718 | 8.21k | } else { |
4719 | 8.21k | *dst++ = (u8)hi; |
4720 | 8.21k | } |
4721 | 23.9k | } else { |
4722 | | /* a non-BMP character, represented as a surrogate pair */ |
4723 | 7.17k | if (unlikely((hi & 0xFC00) != 0xD800)) { |
4724 | 98 | return_err(src - 6, "invalid high surrogate in string"); |
4725 | 98 | } |
4726 | 7.07k | if (unlikely(!byte_match_2(src, "\\u"))) { |
4727 | 399 | return_err(src - 6, "no low surrogate in string"); |
4728 | 399 | } |
4729 | 6.67k | if (unlikely(!hex_load_4(src + 2, &lo))) { |
4730 | 155 | return_err(src - 6, "invalid escape in string"); |
4731 | 155 | } |
4732 | 6.52k | if (unlikely((lo & 0xFC00) != 0xDC00)) { |
4733 | 150 | return_err(src - 6, "invalid low surrogate in string"); |
4734 | 150 | } |
4735 | 6.37k | uni = ((((u32)hi - 0xD800) << 10) | |
4736 | 6.37k | ((u32)lo - 0xDC00)) + 0x10000; |
4737 | 6.37k | *dst++ = (u8)(0xF0 | (uni >> 18)); |
4738 | 6.37k | *dst++ = (u8)(0x80 | ((uni >> 12) & 0x3F)); |
4739 | 6.37k | *dst++ = (u8)(0x80 | ((uni >> 6) & 0x3F)); |
4740 | 6.37k | *dst++ = (u8)(0x80 | (uni & 0x3F)); |
4741 | 6.37k | src += 6; |
4742 | 6.37k | } |
4743 | 30.3k | *src_ptr = src; |
4744 | 30.3k | *dst_ptr = dst; |
4745 | 30.3k | return true; |
4746 | 31.1k | #undef return_err |
4747 | 31.1k | } |
4748 | | |
4749 | | /** |
4750 | | Read a JSON string. |
4751 | | @param quo The quote character (single quote or double quote). |
4752 | | @param ptr The head pointer of string before quote (inout). |
4753 | | @param eof JSON end position. |
4754 | | @param flg JSON read flag. |
4755 | | @param val The string value to be written. |
4756 | | @param msg The error message pointer. |
4757 | | @param con Continuation for incremental parsing. |
4758 | | @return Whether success. |
4759 | | */ |
4760 | | static_inline bool read_str_opt(u8 quo, u8 **ptr, u8 *eof, yyjson_read_flag flg, |
4761 | 524k | yyjson_val *val, const char **msg, u8 *con[2]) { |
4762 | | /* |
4763 | | GCC may sometimes load variables into registers too early, causing |
4764 | | unnecessary instructions and performance degradation. This inline assembly |
4765 | | serves as a hint to GCC: 'This variable will be modified, so avoid loading |
4766 | | it too early.' Other compilers like MSVC, Clang, and ICC can generate the |
4767 | | expected instructions without needing this hint. |
4768 | | |
4769 | | Check out this example: https://godbolt.org/z/YG6a5W5Ec |
4770 | | */ |
4771 | 524k | #define return_err(_end, _msg) do { \ |
4772 | 18.9k | *msg = _msg; \ |
4773 | 18.9k | *end = _end; \ |
4774 | 18.9k | if (con) { con[0] = _end; con[1] = dst; } \ |
4775 | 18.9k | return false; \ |
4776 | 18.9k | } while (false) |
4777 | | |
4778 | 524k | u8 *hdr = *ptr + 1; |
4779 | 524k | u8 **end = ptr; |
4780 | 524k | u8 *src = hdr, *dst = NULL, *pos; |
4781 | 524k | u32 uni, tmp; |
4782 | | |
4783 | | /* Resume incremental parsing. */ |
4784 | 524k | if (con && unlikely(con[0])) { |
4785 | 0 | src = con[0]; |
4786 | 0 | dst = con[1]; |
4787 | 0 | if (dst) goto copy_ascii; |
4788 | 0 | } |
4789 | | |
4790 | 1.51M | skip_ascii: |
4791 | | /* |
4792 | | Most strings have no escaped characters, so we can jump them quickly. |
4793 | | |
4794 | | We want to make loop unrolling, as shown in the following code. Some |
4795 | | compiler may not generate instructions as expected, so we rewrite it with |
4796 | | explicit goto statements. We hope the compiler can generate instructions |
4797 | | like this: https://godbolt.org/z/8vjsYq |
4798 | | |
4799 | | while (true) repeat16({ |
4800 | | if (likely((char_is_ascii_skip(*src)))) src++; |
4801 | | else break; |
4802 | | }) |
4803 | | */ |
4804 | 1.51M | if (quo == '"') { |
4805 | 1.50M | #define expr_jump(i) \ |
4806 | 10.6M | if (likely(char_is_ascii_skip(src[i]))) {} \ |
4807 | 10.6M | else goto skip_ascii_stop##i; |
4808 | | |
4809 | 1.50M | #define expr_stop(i) \ |
4810 | 1.50M | skip_ascii_stop##i: \ |
4811 | 1.20M | src += i; \ |
4812 | 1.20M | goto skip_ascii_end; |
4813 | | |
4814 | 10.6M | repeat16_incr(expr_jump) |
4815 | 292k | src += 16; |
4816 | 292k | goto skip_ascii; |
4817 | 1.20M | repeat16_incr(expr_stop) |
4818 | |
|
4819 | 0 | #undef expr_jump |
4820 | 0 | #undef expr_stop |
4821 | 10.0k | } else { |
4822 | 10.0k | #define expr_jump(i) \ |
4823 | 45.4k | if (likely(char_is_ascii_skip_sq(src[i]))) {} \ |
4824 | 45.4k | else goto skip_ascii_stop_sq##i; |
4825 | | |
4826 | 10.0k | #define expr_stop(i) \ |
4827 | 10.0k | skip_ascii_stop_sq##i: \ |
4828 | 9.74k | src += i; \ |
4829 | 9.74k | goto skip_ascii_end; |
4830 | | |
4831 | 45.4k | repeat16_incr(expr_jump) |
4832 | 332 | src += 16; |
4833 | 332 | goto skip_ascii; |
4834 | 9.74k | repeat16_incr(expr_stop) |
4835 | |
|
4836 | 0 | #undef expr_jump |
4837 | 0 | #undef expr_stop |
4838 | 0 | } |
4839 | | |
4840 | 1.21M | skip_ascii_end: |
4841 | 1.21M | gcc_store_barrier(*src); |
4842 | 1.21M | if (likely(*src == quo)) { |
4843 | 433k | val->tag = ((u64)(src - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR | |
4844 | 433k | (quo == '"' ? YYJSON_SUBTYPE_NOESC : 0); |
4845 | 433k | val->uni.str = (const char *)hdr; |
4846 | 433k | *src = '\0'; |
4847 | 433k | *end = src + 1; |
4848 | 433k | if (con) con[0] = con[1] = NULL; |
4849 | 433k | return true; |
4850 | 433k | } |
4851 | | |
4852 | 786k | skip_utf8: |
4853 | 786k | if (*src & 0x80) { /* non-ASCII character */ |
4854 | | /* |
4855 | | Non-ASCII character appears here, which means that the text is likely |
4856 | | to be written in non-English or emoticons. According to some common |
4857 | | data set statistics, byte sequences of the same length may appear |
4858 | | consecutively. We process the byte sequences of the same length in each |
4859 | | loop, which is more friendly to branch prediction. |
4860 | | */ |
4861 | 696k | pos = src; |
4862 | | #if YYJSON_DISABLE_UTF8_VALIDATION |
4863 | | while (true) repeat8({ |
4864 | | if (likely((*src & 0xF0) == 0xE0)) src += 3; |
4865 | | else break; |
4866 | | }) |
4867 | | if (*src < 0x80) goto skip_ascii; |
4868 | | while (true) repeat8({ |
4869 | | if (likely((*src & 0xE0) == 0xC0)) src += 2; |
4870 | | else break; |
4871 | | }) |
4872 | | while (true) repeat8({ |
4873 | | if (likely((*src & 0xF8) == 0xF0)) src += 4; |
4874 | | else break; |
4875 | | }) |
4876 | | #else |
4877 | 696k | uni = byte_load_4(src); |
4878 | 715k | while (is_utf8_seq3(uni)) { |
4879 | 18.4k | src += 3; |
4880 | 18.4k | uni = byte_load_4(src); |
4881 | 18.4k | } |
4882 | 696k | if (is_utf8_seq1(uni)) goto skip_ascii; |
4883 | 1.10M | while (is_utf8_seq2(uni)) { |
4884 | 420k | src += 2; |
4885 | 420k | uni = byte_load_4(src); |
4886 | 420k | } |
4887 | 718k | while (is_utf8_seq4(uni)) { |
4888 | 31.5k | src += 4; |
4889 | 31.5k | uni = byte_load_4(src); |
4890 | 31.5k | } |
4891 | 687k | #endif |
4892 | 687k | if (unlikely(pos == src)) { |
4893 | 269k | if (has_allow(INVALID_UNICODE)) ++src; |
4894 | 965 | else return_err(src, "invalid UTF-8 encoding in string"); |
4895 | 269k | } |
4896 | 686k | goto skip_ascii; |
4897 | 687k | } |
4898 | | |
4899 | | /* The escape character appears, we need to copy it. */ |
4900 | 89.8k | dst = src; |
4901 | 602k | copy_escape: |
4902 | 602k | if (likely(*src == '\\')) { |
4903 | 227k | switch (*++src) { |
4904 | 7.91k | case '"': *dst++ = '"'; src++; break; |
4905 | 13.6k | case '\\': *dst++ = '\\'; src++; break; |
4906 | 6.08k | case '/': *dst++ = '/'; src++; break; |
4907 | 50.2k | case 'b': *dst++ = '\b'; src++; break; |
4908 | 19.0k | case 'f': *dst++ = '\f'; src++; break; |
4909 | 20.1k | case 'n': *dst++ = '\n'; src++; break; |
4910 | 26.6k | case 'r': *dst++ = '\r'; src++; break; |
4911 | 18.5k | case 't': *dst++ = '\t'; src++; break; |
4912 | 27.8k | case 'u': |
4913 | 27.8k | src--; |
4914 | 27.8k | if (!read_uni_esc(&src, &dst, msg)) return_err(src, *msg); |
4915 | 26.8k | break; |
4916 | 37.8k | default: { |
4917 | 37.8k | if (has_allow(EXT_ESCAPE)) { |
4918 | | /* read extended escape (non-standard) */ |
4919 | 36.1k | switch (*src) { |
4920 | 2.49k | case '\'': *dst++ = '\''; src++; break; |
4921 | 2.46k | case 'a': *dst++ = '\a'; src++; break; |
4922 | 2.16k | case 'v': *dst++ = '\v'; src++; break; |
4923 | 1.97k | case '?': *dst++ = '\?'; src++; break; |
4924 | 3.01k | case 'e': *dst++ = 0x1B; src++; break; |
4925 | 2.90k | case '0': |
4926 | 2.90k | if (!char_is_digit(src[1])) { |
4927 | 2.89k | *dst++ = '\0'; src++; break; |
4928 | 2.89k | } |
4929 | 12 | return_err(src - 1, "octal escape is not allowed"); |
4930 | 35 | case '1': case '2': case '3': case '4': |
4931 | 74 | case '5': case '6': case '7': case '8': case '9': |
4932 | 74 | return_err(src - 1, "invalid number escape"); |
4933 | 2.96k | case 'x': { |
4934 | 2.96k | u8 c; |
4935 | 2.96k | if (hex_load_2(src + 1, &c)) { |
4936 | 2.93k | src += 3; |
4937 | 2.93k | if (c <= 0x7F) { /* 1-byte ASCII */ |
4938 | 1.72k | *dst++ = c; |
4939 | 1.72k | } else { /* 2-byte UTF-8 */ |
4940 | 1.21k | *dst++ = (u8)(0xC0 | (c >> 6)); |
4941 | 1.21k | *dst++ = (u8)(0x80 | (c & 0x3F)); |
4942 | 1.21k | } |
4943 | 2.93k | break; |
4944 | 2.93k | } |
4945 | 30 | return_err(src - 1, "invalid hex escape"); |
4946 | 30 | } |
4947 | 2.00k | case '\n': src++; break; |
4948 | 1.97k | case '\r': src++; src += (*src == '\n'); break; |
4949 | 6.23k | case 0xE2: /* Line terminator: U+2028, U+2029 */ |
4950 | 6.23k | if ((src[1] == 0x80 && src[2] == 0xA8) || |
4951 | 4.45k | (src[1] == 0x80 && src[2] == 0xA9)) { |
4952 | 3.22k | src += 3; |
4953 | 3.22k | } |
4954 | 6.23k | break; |
4955 | 7.84k | default: |
4956 | 7.84k | break; /* skip */ |
4957 | 36.1k | } |
4958 | 36.1k | } else if (quo == '\'' && *src == '\'') { |
4959 | 0 | *dst++ = '\''; src++; break; |
4960 | 1.78k | } else { |
4961 | 1.78k | return_err(src - 1, "invalid escaped sequence in string"); |
4962 | 1.78k | } |
4963 | 37.8k | } |
4964 | 227k | } |
4965 | 374k | } else if (likely(*src == quo)) { |
4966 | 71.7k | val->tag = ((u64)(dst - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; |
4967 | 71.7k | val->uni.str = (const char *)hdr; |
4968 | 71.7k | *dst = '\0'; |
4969 | 71.7k | *end = src + 1; |
4970 | 71.7k | if (con) con[0] = con[1] = NULL; |
4971 | 71.7k | return true; |
4972 | 302k | } else { |
4973 | 302k | if (!has_allow(INVALID_UNICODE)) { |
4974 | 5.86k | return_err(src, "unexpected control character in string"); |
4975 | 5.86k | } |
4976 | 296k | if (src >= eof) return_err(src, "unclosed string"); |
4977 | 288k | *dst++ = *src++; |
4978 | 288k | } |
4979 | | |
4980 | 2.25M | copy_ascii: |
4981 | | /* |
4982 | | Copy continuous ASCII, loop unrolling, same as the following code: |
4983 | | |
4984 | | while (true) repeat16({ |
4985 | | if (char_is_ascii_skip(*src)) *dst++ = *src++; |
4986 | | else break; |
4987 | | }) |
4988 | | */ |
4989 | 2.25M | if (quo == '"') { |
4990 | 2.20M | #define expr_jump(i) \ |
4991 | 21.6M | if (likely((char_is_ascii_skip(src[i])))) {} \ |
4992 | 21.6M | else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; } |
4993 | 21.6M | repeat16_incr(expr_jump) |
4994 | 19.4M | #undef expr_jump |
4995 | 19.4M | } else { |
4996 | 47.2k | #define expr_jump(i) \ |
4997 | 444k | if (likely((char_is_ascii_skip_sq(src[i])))) {} \ |
4998 | 444k | else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; } |
4999 | 444k | repeat16_incr(expr_jump) |
5000 | 397k | #undef expr_jump |
5001 | 397k | } |
5002 | | |
5003 | 655k | byte_move_16(dst, src); |
5004 | 655k | dst += 16; src += 16; |
5005 | 655k | goto copy_ascii; |
5006 | | |
5007 | | /* |
5008 | | The memory is copied forward since `dst < src`. |
5009 | | So it's safe to move one extra byte to reduce instruction count. |
5010 | | */ |
5011 | 0 | #define expr_jump(i) \ |
5012 | 1.81M | copy_ascii_stop_##i: \ |
5013 | 1.81M | byte_move_forward(dst, src, i); \ |
5014 | 1.81M | dst += i; src += i; \ |
5015 | 1.81M | goto copy_utf8; |
5016 | 1.81M | repeat16_incr(expr_jump) |
5017 | 0 | #undef expr_jump |
5018 | | |
5019 | 1.81M | copy_utf8: |
5020 | 1.81M | if (*src & 0x80) { /* non-ASCII character */ |
5021 | 1.30M | pos = src; |
5022 | 1.30M | uni = byte_load_4(src); |
5023 | | #if YYJSON_DISABLE_UTF8_VALIDATION |
5024 | | while (true) repeat4({ |
5025 | | if ((uni & utf8_seq(b3_mask)) == utf8_seq(b3_patt)) { |
5026 | | byte_copy_4(dst, &uni); |
5027 | | dst += 3; src += 3; |
5028 | | uni = byte_load_4(src); |
5029 | | } else break; |
5030 | | }) |
5031 | | if ((uni & utf8_seq(b1_mask)) == utf8_seq(b1_patt)) goto copy_ascii; |
5032 | | while (true) repeat4({ |
5033 | | if ((uni & utf8_seq(b2_mask)) == utf8_seq(b2_patt)) { |
5034 | | byte_copy_2(dst, &uni); |
5035 | | dst += 2; src += 2; |
5036 | | uni = byte_load_4(src); |
5037 | | } else break; |
5038 | | }) |
5039 | | while (true) repeat4({ |
5040 | | if ((uni & utf8_seq(b4_mask)) == utf8_seq(b4_patt)) { |
5041 | | byte_copy_4(dst, &uni); |
5042 | | dst += 4; src += 4; |
5043 | | uni = byte_load_4(src); |
5044 | | } else break; |
5045 | | }) |
5046 | | #else |
5047 | 1.32M | while (is_utf8_seq3(uni)) { |
5048 | 26.5k | byte_copy_4(dst, &uni); |
5049 | 26.5k | dst += 3; src += 3; |
5050 | 26.5k | uni = byte_load_4(src); |
5051 | 26.5k | } |
5052 | 1.30M | if (is_utf8_seq1(uni)) goto copy_ascii; |
5053 | 2.32M | while (is_utf8_seq2(uni)) { |
5054 | 1.03M | byte_copy_2(dst, &uni); |
5055 | 1.03M | dst += 2; src += 2; |
5056 | 1.03M | uni = byte_load_4(src); |
5057 | 1.03M | } |
5058 | 1.33M | while (is_utf8_seq4(uni)) { |
5059 | 48.5k | byte_copy_4(dst, &uni); |
5060 | 48.5k | dst += 4; src += 4; |
5061 | 48.5k | uni = byte_load_4(src); |
5062 | 48.5k | } |
5063 | 1.28M | #endif |
5064 | 1.28M | if (unlikely(pos == src)) { |
5065 | 215k | if (!has_allow(INVALID_UNICODE)) { |
5066 | 814 | return_err(src, MSG_ERR_UTF8); |
5067 | 814 | } |
5068 | 214k | goto copy_ascii_stop_1; |
5069 | 215k | } |
5070 | 1.07M | goto copy_ascii; |
5071 | 1.28M | } |
5072 | 512k | goto copy_escape; |
5073 | | |
5074 | 1.81M | #undef return_err |
5075 | 1.81M | } |
5076 | | |
5077 | | static_inline bool read_str(u8 **ptr, u8 *eof, yyjson_read_flag flg, |
5078 | 518k | yyjson_val *val, const char **msg) { |
5079 | 518k | return read_str_opt('\"', ptr, eof, flg, val, msg, NULL); |
5080 | 518k | } |
5081 | | |
5082 | | static_inline bool read_str_con(u8 **ptr, u8 *eof, yyjson_read_flag flg, |
5083 | 0 | yyjson_val *val, const char **msg, u8 **con) { |
5084 | 0 | return read_str_opt('\"', ptr, eof, flg, val, msg, con); |
5085 | 0 | } |
5086 | | |
5087 | | static_noinline bool read_str_sq(u8 **ptr, u8 *eof, yyjson_read_flag flg, |
5088 | 5.31k | yyjson_val *val, const char **msg) { |
5089 | 5.31k | return read_str_opt('\'', ptr, eof, flg, val, msg, NULL); |
5090 | 5.31k | } |
5091 | | |
5092 | | /** Read unquoted key (identifier name). */ |
5093 | | static_noinline bool read_str_id(u8 **ptr, u8 *eof, yyjson_read_flag flg, |
5094 | 23.8k | u8 **pre, yyjson_val *val, const char **msg) { |
5095 | 23.8k | #define return_err(_end, _msg) do { \ |
5096 | 429 | *msg = _msg; \ |
5097 | 429 | *end = _end; \ |
5098 | 429 | return false; \ |
5099 | 429 | } while (false) |
5100 | | |
5101 | 23.8k | #define return_suc(_str_end, _cur_end) do { \ |
5102 | 23.3k | val->tag = ((u64)(_str_end - hdr) << YYJSON_TAG_BIT) | \ |
5103 | 23.3k | (u64)(YYJSON_TYPE_STR); \ |
5104 | 23.3k | val->uni.str = (const char *)hdr; \ |
5105 | 23.3k | *pre = _str_end; *end = _cur_end; \ |
5106 | 23.3k | return true; \ |
5107 | 23.3k | } while (false) |
5108 | | |
5109 | 23.8k | u8 *hdr = *ptr; |
5110 | 23.8k | u8 **end = ptr; |
5111 | 23.8k | u8 *src = hdr, *dst = NULL; |
5112 | 23.8k | u32 uni, tmp; |
5113 | | |
5114 | | /* add null-terminator for previous raw string */ |
5115 | 23.8k | **pre = '\0'; |
5116 | | |
5117 | 28.1k | skip_ascii: |
5118 | 28.1k | #define expr_jump(i) \ |
5119 | 137k | if (likely(char_is_id_ascii(src[i]))) {} \ |
5120 | 137k | else goto skip_ascii_stop##i; |
5121 | | |
5122 | 28.1k | #define expr_stop(i) \ |
5123 | 28.1k | skip_ascii_stop##i: \ |
5124 | 27.2k | src += i; \ |
5125 | 27.2k | goto skip_ascii_end; |
5126 | | |
5127 | 137k | repeat16_incr(expr_jump) |
5128 | 830 | src += 16; |
5129 | 830 | goto skip_ascii; |
5130 | 27.2k | repeat16_incr(expr_stop) |
5131 | | |
5132 | 0 | #undef expr_jump |
5133 | 0 | #undef expr_stop |
5134 | | |
5135 | 27.2k | skip_ascii_end: |
5136 | 27.2k | gcc_store_barrier(*src); |
5137 | 27.2k | if (likely(!char_is_id_next(*src))) { |
5138 | 17.4k | return_suc(src, src); |
5139 | 17.4k | } |
5140 | | |
5141 | 9.87k | skip_utf8: |
5142 | 14.7k | while (*src >= 0x80) { |
5143 | 8.52k | if (has_allow(EXT_WHITESPACE)) { |
5144 | 8.52k | if (char_is_space_ext(*src) && ext_space_len(src)) { |
5145 | 3.38k | return_suc(src, src); |
5146 | 3.38k | } |
5147 | 8.52k | } |
5148 | 5.13k | uni = byte_load_4(src); |
5149 | 5.13k | if (is_utf8_seq2(uni)) { |
5150 | 3.53k | src += 2; |
5151 | 3.53k | } else if (is_utf8_seq3(uni)) { |
5152 | 860 | src += 3; |
5153 | 860 | } else if (is_utf8_seq4(uni)) { |
5154 | 523 | src += 4; |
5155 | 523 | } else { |
5156 | 217 | #if !YYJSON_DISABLE_UTF8_VALIDATION |
5157 | 217 | if (!has_allow(INVALID_UNICODE)) return_err(src, MSG_ERR_UTF8); |
5158 | 0 | #endif |
5159 | 0 | src += 1; |
5160 | 0 | } |
5161 | 5.13k | } |
5162 | 6.27k | if (char_is_id_ascii(*src)) goto skip_ascii; |
5163 | | |
5164 | | /* The escape character appears, we need to copy it. */ |
5165 | 2.78k | dst = src; |
5166 | 4.39k | copy_escape: |
5167 | 4.39k | if (byte_match_2(src, "\\u")) { |
5168 | 3.53k | if (!read_uni_esc(&src, &dst, msg)) return_err(src, *msg); |
5169 | 3.53k | } else { |
5170 | 855 | if (!char_is_id_next(*src)) return_suc(dst, src); |
5171 | 38 | return_err(src, "unexpected character in key"); |
5172 | 38 | } |
5173 | | |
5174 | 10.8k | copy_ascii: |
5175 | | /* |
5176 | | Copy continuous ASCII, loop unrolling, same as the following code: |
5177 | | |
5178 | | while (true) repeat16({ |
5179 | | if (char_is_ascii_skip(*src)) *dst++ = *src++; |
5180 | | else break; |
5181 | | }) |
5182 | | */ |
5183 | 10.8k | #define expr_jump(i) \ |
5184 | 63.3k | if (likely((char_is_id_ascii(src[i])))) {} \ |
5185 | 63.3k | else { gcc_store_barrier(src[i]); goto copy_ascii_stop_##i; } |
5186 | 63.3k | repeat16_incr(expr_jump) |
5187 | 367 | #undef expr_jump |
5188 | | |
5189 | 367 | byte_move_16(dst, src); |
5190 | 367 | dst += 16; src += 16; |
5191 | 367 | goto copy_ascii; |
5192 | | |
5193 | 0 | #define expr_jump(i) \ |
5194 | 10.5k | copy_ascii_stop_##i: \ |
5195 | 10.5k | byte_move_forward(dst, src, i); \ |
5196 | 10.5k | dst += i; src += i; \ |
5197 | 10.5k | goto copy_utf8; |
5198 | 10.5k | repeat16_incr(expr_jump) |
5199 | 0 | #undef expr_jump |
5200 | | |
5201 | 10.5k | copy_utf8: |
5202 | 18.4k | while (*src >= 0x80) { /* non-ASCII character */ |
5203 | 9.79k | if (has_allow(EXT_WHITESPACE)) { |
5204 | 9.79k | if (char_is_space_ext(*src) && ext_space_len(src)) { |
5205 | 1.75k | return_suc(dst, src); |
5206 | 1.75k | } |
5207 | 9.79k | } |
5208 | 8.03k | uni = byte_load_4(src); |
5209 | 8.03k | if (is_utf8_seq2(uni)) { |
5210 | 6.97k | byte_copy_2(dst, &uni); |
5211 | 6.97k | dst += 2; src += 2; |
5212 | 6.97k | } else if (is_utf8_seq3(uni)) { |
5213 | 550 | byte_copy_4(dst, &uni); |
5214 | 550 | dst += 3; src += 3; |
5215 | 550 | } else if (is_utf8_seq4(uni)) { |
5216 | 388 | byte_copy_4(dst, &uni); |
5217 | 388 | dst += 4; src += 4; |
5218 | 388 | } else { |
5219 | 123 | #if !YYJSON_DISABLE_UTF8_VALIDATION |
5220 | 123 | if (!has_allow(INVALID_UNICODE)) return_err(src, MSG_ERR_UTF8); |
5221 | 0 | #endif |
5222 | 0 | *dst = *src; |
5223 | 0 | dst += 1; src += 1; |
5224 | 0 | } |
5225 | 8.03k | } |
5226 | 8.62k | if (char_is_id_ascii(*src)) goto copy_ascii; |
5227 | 1.60k | goto copy_escape; |
5228 | | |
5229 | 8.62k | #undef return_err |
5230 | 8.62k | #undef return_suc |
5231 | 8.62k | } |
5232 | | |
5233 | | |
5234 | | |
5235 | | /*============================================================================== |
5236 | | * MARK: - JSON Reader Implementation (Private) |
5237 | | * |
5238 | | * We use goto statements to build the finite state machine (FSM). |
5239 | | * The FSM's state was held by program counter (PC) and the 'goto' make the |
5240 | | * state transitions. |
5241 | | *============================================================================*/ |
5242 | | |
5243 | | /** Read single value JSON document. */ |
5244 | | static_noinline yyjson_doc *read_root_single(u8 *hdr, u8 *cur, u8 *eof, |
5245 | | yyjson_alc alc, |
5246 | | yyjson_read_flag flg, |
5247 | 32.1k | yyjson_read_err *err) { |
5248 | 32.1k | #define return_err(_pos, _code, _msg) do { \ |
5249 | 15.6k | if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \ |
5250 | 3.17k | err->pos = (usize)(eof - hdr); \ |
5251 | 3.17k | err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \ |
5252 | 3.17k | err->msg = MSG_NOT_END; \ |
5253 | 12.4k | } else { \ |
5254 | 12.4k | err->pos = (usize)(_pos - hdr); \ |
5255 | 12.4k | err->code = YYJSON_READ_ERROR_##_code; \ |
5256 | 12.4k | err->msg = _msg; \ |
5257 | 12.4k | } \ |
5258 | 15.6k | if (val_hdr) alc.free(alc.ctx, val_hdr); \ |
5259 | 15.6k | return NULL; \ |
5260 | 15.6k | } while (false) |
5261 | | |
5262 | 32.1k | usize hdr_len; /* value count used by doc */ |
5263 | 32.1k | usize alc_num; /* value count capacity */ |
5264 | 32.1k | yyjson_val *val_hdr; /* the head of allocated values */ |
5265 | 32.1k | yyjson_val *val; /* current value */ |
5266 | 32.1k | yyjson_doc *doc; /* the JSON document, equals to val_hdr */ |
5267 | 32.1k | const char *msg; /* error message */ |
5268 | | |
5269 | 32.1k | u8 raw_end[1]; /* raw end for null-terminator */ |
5270 | 32.1k | u8 *raw_ptr = raw_end; |
5271 | 32.1k | u8 **pre = &raw_ptr; /* previous raw end pointer */ |
5272 | | |
5273 | 32.1k | hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val); |
5274 | 32.1k | hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0; |
5275 | 32.1k | alc_num = hdr_len + 1; /* single value */ |
5276 | | |
5277 | 32.1k | val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_num * sizeof(yyjson_val)); |
5278 | 32.1k | if (unlikely(!val_hdr)) goto fail_alloc; |
5279 | 32.1k | val = val_hdr + hdr_len; |
5280 | | |
5281 | 32.1k | if (char_is_num(*cur)) { |
5282 | 18.8k | if (likely(read_num(&cur, pre, flg, val, &msg))) goto doc_end; |
5283 | 1.41k | goto fail_number; |
5284 | 18.8k | } |
5285 | 13.3k | if (*cur == '"') { |
5286 | 4.17k | if (likely(read_str(&cur, eof, flg, val, &msg))) goto doc_end; |
5287 | 2.86k | goto fail_string; |
5288 | 4.17k | } |
5289 | 9.13k | if (*cur == 't') { |
5290 | 352 | if (likely(read_true(&cur, val))) goto doc_end; |
5291 | 339 | goto fail_literal_true; |
5292 | 352 | } |
5293 | 8.78k | if (*cur == 'f') { |
5294 | 443 | if (likely(read_false(&cur, val))) goto doc_end; |
5295 | 368 | goto fail_literal_false; |
5296 | 443 | } |
5297 | 8.34k | if (*cur == 'n') { |
5298 | 218 | if (likely(read_null(&cur, val))) goto doc_end; |
5299 | 206 | if (has_allow(INF_AND_NAN)) { |
5300 | 42 | if (read_nan(&cur, pre, flg, val)) goto doc_end; |
5301 | 42 | } |
5302 | 203 | goto fail_literal_null; |
5303 | 206 | } |
5304 | 8.12k | if (has_allow(INF_AND_NAN)) { |
5305 | 964 | if (read_inf_or_nan(&cur, pre, flg, val)) goto doc_end; |
5306 | 964 | } |
5307 | 8.11k | if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') { |
5308 | 711 | if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto doc_end; |
5309 | 653 | goto fail_string; |
5310 | 711 | } |
5311 | 7.40k | goto fail_character; |
5312 | | |
5313 | 18.9k | doc_end: |
5314 | | /* check invalid contents after json document */ |
5315 | 18.9k | if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) { |
5316 | 3.61k | while (char_is_space(*cur)) cur++; |
5317 | 2.71k | if (has_allow(TRIVIA) && char_is_trivia(*cur)) { |
5318 | 107 | if (!skip_trivia(&cur, eof, flg) && cur == eof) { |
5319 | 9 | goto fail_comment; |
5320 | 9 | } |
5321 | 107 | } |
5322 | 2.70k | if (unlikely(cur < eof)) goto fail_garbage; |
5323 | 2.70k | } |
5324 | | |
5325 | 16.4k | **pre = '\0'; |
5326 | 16.4k | doc = (yyjson_doc *)val_hdr; |
5327 | 16.4k | doc->root = val_hdr + hdr_len; |
5328 | 16.4k | doc->alc = alc; |
5329 | 16.4k | doc->dat_read = (usize)(cur - hdr); |
5330 | 16.4k | doc->val_read = 1; |
5331 | 16.4k | doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr; |
5332 | 16.4k | return doc; |
5333 | | |
5334 | 3.51k | fail_string: return_err(cur, INVALID_STRING, msg); |
5335 | 1.41k | fail_number: return_err(cur, INVALID_NUMBER, msg); |
5336 | 0 | fail_alloc: return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC); |
5337 | 339 | fail_literal_true: return_err(cur, LITERAL, MSG_CHAR_T); |
5338 | 368 | fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F); |
5339 | 203 | fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N); |
5340 | 7.40k | fail_character: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR); |
5341 | 9 | fail_comment: return_err(cur, INVALID_COMMENT, MSG_COMMENT); |
5342 | 2.41k | fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE); |
5343 | 0 | fail_depth: return_err(cur, DEPTH, MSG_DEPTH); |
5344 | |
|
5345 | 0 | #undef return_err |
5346 | 0 | } |
5347 | | |
5348 | | /** Read JSON document (accept all style, but optimized for minify). */ |
5349 | | static_inline yyjson_doc *read_root_minify(u8 *hdr, u8 *cur, u8 *eof, |
5350 | | yyjson_alc alc, |
5351 | | yyjson_read_flag flg, |
5352 | 51.1k | yyjson_read_err *err) { |
5353 | 51.1k | #define return_err(_pos, _code, _msg) do { \ |
5354 | 33.4k | if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \ |
5355 | 19.0k | err->pos = (usize)(eof - hdr); \ |
5356 | 19.0k | err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \ |
5357 | 19.0k | err->msg = MSG_NOT_END; \ |
5358 | 19.0k | } else { \ |
5359 | 14.3k | err->pos = (usize)(_pos - hdr); \ |
5360 | 14.3k | err->code = YYJSON_READ_ERROR_##_code; \ |
5361 | 14.3k | err->msg = _msg; \ |
5362 | 14.3k | } \ |
5363 | 33.4k | if (val_hdr) alc.free(alc.ctx, val_hdr); \ |
5364 | 33.4k | return NULL; \ |
5365 | 33.4k | } while (false) |
5366 | | |
5367 | 4.11M | #define val_incr() do { \ |
5368 | 4.11M | val++; \ |
5369 | 4.11M | if (unlikely(val >= val_end)) { \ |
5370 | 6.37k | usize alc_old = alc_len; \ |
5371 | 6.37k | usize val_ofs = (usize)(val - val_hdr); \ |
5372 | 6.37k | usize ctn_ofs = (usize)(ctn - val_hdr); \ |
5373 | 6.37k | alc_len += alc_len / 2; \ |
5374 | 6.37k | if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \ |
5375 | 6.37k | val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \ |
5376 | 6.37k | alc_old * sizeof(yyjson_val), \ |
5377 | 6.37k | alc_len * sizeof(yyjson_val)); \ |
5378 | 6.37k | if ((!val_tmp)) goto fail_alloc; \ |
5379 | 6.37k | val = val_tmp + val_ofs; \ |
5380 | 6.37k | ctn = val_tmp + ctn_ofs; \ |
5381 | 6.37k | val_hdr = val_tmp; \ |
5382 | 6.37k | val_end = val_tmp + (alc_len - 2); \ |
5383 | 6.37k | } \ |
5384 | 4.11M | } while (false) |
5385 | | |
5386 | 51.1k | usize dat_len; /* data length in bytes, hint for allocator */ |
5387 | 51.1k | usize hdr_len; /* value count used by yyjson_doc */ |
5388 | 51.1k | usize alc_len; /* value count allocated */ |
5389 | 51.1k | usize alc_max; /* maximum value count for allocator */ |
5390 | 51.1k | usize ctn_len; /* the number of elements in current container */ |
5391 | 51.1k | yyjson_val *val_hdr; /* the head of allocated values */ |
5392 | 51.1k | yyjson_val *val_end; /* the end of allocated values */ |
5393 | 51.1k | yyjson_val *val_tmp; /* temporary pointer for realloc */ |
5394 | 51.1k | yyjson_val *val; /* current JSON value */ |
5395 | 51.1k | yyjson_val *ctn; /* current container */ |
5396 | 51.1k | yyjson_val *ctn_parent; /* parent of current container */ |
5397 | 51.1k | yyjson_doc *doc; /* the JSON document, equals to val_hdr */ |
5398 | 51.1k | const char *msg; /* error message */ |
5399 | | |
5400 | 51.1k | u8 raw_end[1]; /* raw end for null-terminator */ |
5401 | 51.1k | u8 *raw_ptr = raw_end; |
5402 | 51.1k | u8 **pre = &raw_ptr; /* previous raw end pointer */ |
5403 | | |
5404 | | #if YYJSON_READER_DEPTH_LIMIT |
5405 | | u32 container_depth = 0; /* current array/object depth */ |
5406 | | #endif |
5407 | | |
5408 | 51.1k | dat_len = has_flg(STOP_WHEN_DONE) ? 256 : (usize)(eof - cur); |
5409 | 51.1k | hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val); |
5410 | 51.1k | hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0; |
5411 | 51.1k | alc_max = USIZE_MAX / sizeof(yyjson_val); |
5412 | 51.1k | alc_len = hdr_len + (dat_len / YYJSON_READER_ESTIMATED_MINIFY_RATIO) + 4; |
5413 | 51.1k | alc_len = yyjson_min(alc_len, alc_max); |
5414 | | |
5415 | 51.1k | val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_len * sizeof(yyjson_val)); |
5416 | 51.1k | if (unlikely(!val_hdr)) goto fail_alloc; |
5417 | 51.1k | val_end = val_hdr + (alc_len - 2); /* padding for key-value pair reading */ |
5418 | 51.1k | val = val_hdr + hdr_len; |
5419 | 51.1k | ctn = val; |
5420 | 51.1k | ctn_len = 0; |
5421 | | |
5422 | 51.1k | if (*cur++ == '{') { |
5423 | 19.0k | ctn->tag = YYJSON_TYPE_OBJ; |
5424 | 19.0k | ctn->uni.ofs = 0; |
5425 | 19.0k | goto obj_key_begin; |
5426 | 32.0k | } else { |
5427 | 32.0k | ctn->tag = YYJSON_TYPE_ARR; |
5428 | 32.0k | ctn->uni.ofs = 0; |
5429 | 32.0k | goto arr_val_begin; |
5430 | 32.0k | } |
5431 | | |
5432 | 1.07M | arr_begin: |
5433 | | #if YYJSON_READER_DEPTH_LIMIT |
5434 | | container_depth++; |
5435 | | if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) { |
5436 | | goto fail_depth; |
5437 | | } |
5438 | | #endif |
5439 | | /* save current container */ |
5440 | 1.07M | ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) | |
5441 | 1.07M | (ctn->tag & YYJSON_TAG_MASK); |
5442 | | |
5443 | | /* create a new array value, save parent container offset */ |
5444 | 1.07M | val_incr(); |
5445 | 1.07M | val->tag = YYJSON_TYPE_ARR; |
5446 | 1.07M | val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn); |
5447 | | |
5448 | | /* push the new array value as current container */ |
5449 | 1.07M | ctn = val; |
5450 | 1.07M | ctn_len = 0; |
5451 | | |
5452 | 4.28M | arr_val_begin: |
5453 | 4.28M | if (*cur == '{') { |
5454 | 30.6k | cur++; |
5455 | 30.6k | goto obj_begin; |
5456 | 30.6k | } |
5457 | 4.25M | if (*cur == '[') { |
5458 | 1.06M | cur++; |
5459 | 1.06M | goto arr_begin; |
5460 | 1.06M | } |
5461 | 3.19M | if (char_is_num(*cur)) { |
5462 | 2.49M | val_incr(); |
5463 | 2.49M | ctn_len++; |
5464 | 2.49M | if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_end; |
5465 | 1.58k | goto fail_number; |
5466 | 2.49M | } |
5467 | 693k | if (*cur == '"') { |
5468 | 32.5k | val_incr(); |
5469 | 32.5k | ctn_len++; |
5470 | 32.5k | if (likely(read_str(&cur, eof, flg, val, &msg))) goto arr_val_end; |
5471 | 2.68k | goto fail_string; |
5472 | 32.5k | } |
5473 | 661k | if (*cur == 't') { |
5474 | 12.4k | val_incr(); |
5475 | 12.4k | ctn_len++; |
5476 | 12.4k | if (likely(read_true(&cur, val))) goto arr_val_end; |
5477 | 182 | goto fail_literal_true; |
5478 | 12.4k | } |
5479 | 648k | if (*cur == 'f') { |
5480 | 18.3k | val_incr(); |
5481 | 18.3k | ctn_len++; |
5482 | 18.3k | if (likely(read_false(&cur, val))) goto arr_val_end; |
5483 | 237 | goto fail_literal_false; |
5484 | 18.3k | } |
5485 | 630k | if (*cur == 'n') { |
5486 | 137k | val_incr(); |
5487 | 137k | ctn_len++; |
5488 | 137k | if (likely(read_null(&cur, val))) goto arr_val_end; |
5489 | 509 | if (has_allow(INF_AND_NAN)) { |
5490 | 384 | if (read_nan(&cur, pre, flg, val)) goto arr_val_end; |
5491 | 384 | } |
5492 | 169 | goto fail_literal_null; |
5493 | 509 | } |
5494 | 492k | if (*cur == ']') { |
5495 | 352k | cur++; |
5496 | 352k | if (likely(ctn_len == 0)) goto arr_end; |
5497 | 823 | if (has_allow(TRAILING_COMMAS)) goto arr_end; |
5498 | 772 | do { cur--; } while (*cur != ','); |
5499 | 92 | goto fail_trailing_comma; |
5500 | 823 | } |
5501 | 140k | if (char_is_space(*cur)) { |
5502 | 284k | while (char_is_space(*++cur)); |
5503 | 91.0k | goto arr_val_begin; |
5504 | 91.0k | } |
5505 | 49.5k | if (has_allow(INF_AND_NAN) && |
5506 | 46.2k | (*cur == 'i' || *cur == 'I' || *cur == 'N')) { |
5507 | 1.09k | val_incr(); |
5508 | 1.09k | ctn_len++; |
5509 | 1.09k | if (read_inf_or_nan(&cur, pre, flg, val)) goto arr_val_end; |
5510 | 49 | goto fail_character_val; |
5511 | 1.09k | } |
5512 | 48.4k | if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') { |
5513 | 2.35k | val_incr(); |
5514 | 2.35k | ctn_len++; |
5515 | 2.35k | if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto arr_val_end; |
5516 | 22 | goto fail_string; |
5517 | 2.35k | } |
5518 | 46.0k | if (has_allow(TRIVIA) && char_is_trivia(*cur)) { |
5519 | 43.7k | if (skip_trivia(&cur, eof, flg)) goto arr_val_begin; |
5520 | 74 | if (cur == eof) goto fail_comment; |
5521 | 74 | } |
5522 | 2.37k | goto fail_character_val; |
5523 | | |
5524 | 4.79M | arr_val_end: |
5525 | 4.79M | if (*cur == ',') { |
5526 | 3.04M | cur++; |
5527 | 3.04M | goto arr_val_begin; |
5528 | 3.04M | } |
5529 | 1.75M | if (*cur == ']') { |
5530 | 661k | cur++; |
5531 | 661k | goto arr_end; |
5532 | 661k | } |
5533 | 1.09M | if (char_is_space(*cur)) { |
5534 | 352k | while (char_is_space(*++cur)); |
5535 | 289k | goto arr_val_end; |
5536 | 289k | } |
5537 | 800k | if (has_allow(TRIVIA) && char_is_trivia(*cur)) { |
5538 | 792k | if (skip_trivia(&cur, eof, flg)) goto arr_val_end; |
5539 | 73 | if (cur == eof) goto fail_comment; |
5540 | 73 | } |
5541 | 7.88k | goto fail_character_arr_end; |
5542 | | |
5543 | 1.01M | arr_end: |
5544 | | #if YYJSON_READER_DEPTH_LIMIT |
5545 | | container_depth--; |
5546 | | #endif |
5547 | | /* get parent container */ |
5548 | 1.01M | ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs); |
5549 | | |
5550 | | /* save the next sibling value offset */ |
5551 | 1.01M | ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val); |
5552 | 1.01M | ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR; |
5553 | 1.01M | if (unlikely(ctn == ctn_parent)) goto doc_end; |
5554 | | |
5555 | | /* pop parent as current container */ |
5556 | 998k | ctn = ctn_parent; |
5557 | 998k | ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT); |
5558 | 998k | if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) { |
5559 | 5.94k | goto obj_val_end; |
5560 | 992k | } else { |
5561 | 992k | goto arr_val_end; |
5562 | 992k | } |
5563 | | |
5564 | 60.0k | obj_begin: |
5565 | | #if YYJSON_READER_DEPTH_LIMIT |
5566 | | container_depth++; |
5567 | | if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) { |
5568 | | goto fail_depth; |
5569 | | } |
5570 | | #endif |
5571 | | /* push container */ |
5572 | 60.0k | ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) | |
5573 | 60.0k | (ctn->tag & YYJSON_TAG_MASK); |
5574 | 60.0k | val_incr(); |
5575 | 60.0k | val->tag = YYJSON_TYPE_OBJ; |
5576 | | /* offset to the parent */ |
5577 | 60.0k | val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn); |
5578 | 60.0k | ctn = val; |
5579 | 60.0k | ctn_len = 0; |
5580 | | |
5581 | 319k | obj_key_begin: |
5582 | 319k | if (likely(*cur == '"')) { |
5583 | 259k | val_incr(); |
5584 | 259k | ctn_len++; |
5585 | 259k | if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_key_end; |
5586 | 2.82k | goto fail_string; |
5587 | 259k | } |
5588 | 59.5k | if (likely(*cur == '}')) { |
5589 | 17.8k | cur++; |
5590 | 17.8k | if (likely(ctn_len == 0)) goto obj_end; |
5591 | 265 | if (has_allow(TRAILING_COMMAS)) goto obj_end; |
5592 | 760 | do { cur--; } while (*cur != ','); |
5593 | 37 | goto fail_trailing_comma; |
5594 | 265 | } |
5595 | 41.7k | if (char_is_space(*cur)) { |
5596 | 42.4k | while (char_is_space(*++cur)); |
5597 | 20.5k | goto obj_key_begin; |
5598 | 20.5k | } |
5599 | 21.2k | if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') { |
5600 | 704 | val_incr(); |
5601 | 704 | ctn_len++; |
5602 | 704 | if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_key_end; |
5603 | 22 | goto fail_string; |
5604 | 704 | } |
5605 | 20.4k | if (has_allow(UNQUOTED_KEY) && char_is_id_start(*cur)) { |
5606 | 15.1k | val_incr(); |
5607 | 15.1k | ctn_len++; |
5608 | 15.1k | if (read_str_id(&cur, eof, flg, pre, val, &msg)) goto obj_key_end; |
5609 | 356 | goto fail_string; |
5610 | 15.1k | } |
5611 | 5.30k | if (has_allow(TRIVIA) && char_is_trivia(*cur)) { |
5612 | 1.95k | if (skip_trivia(&cur, eof, flg)) goto obj_key_begin; |
5613 | 28 | if (cur == eof) goto fail_comment; |
5614 | 28 | } |
5615 | 3.36k | goto fail_character_obj_key; |
5616 | | |
5617 | 281k | obj_key_end: |
5618 | 281k | if (*cur == ':') { |
5619 | 271k | cur++; |
5620 | 271k | goto obj_val_begin; |
5621 | 271k | } |
5622 | 9.69k | if (char_is_space(*cur)) { |
5623 | 3.93k | while (char_is_space(*++cur)); |
5624 | 2.70k | goto obj_key_end; |
5625 | 2.70k | } |
5626 | 6.99k | if (has_allow(TRIVIA) && char_is_trivia(*cur)) { |
5627 | 6.07k | if (skip_trivia(&cur, eof, flg)) goto obj_key_end; |
5628 | 40 | if (cur == eof) goto fail_comment; |
5629 | 40 | } |
5630 | 955 | goto fail_character_obj_sep; |
5631 | | |
5632 | 286k | obj_val_begin: |
5633 | 286k | if (*cur == '"') { |
5634 | 59.0k | val++; |
5635 | 59.0k | ctn_len++; |
5636 | 59.0k | if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_val_end; |
5637 | 2.33k | goto fail_string; |
5638 | 59.0k | } |
5639 | 227k | if (char_is_num(*cur)) { |
5640 | 168k | val++; |
5641 | 168k | ctn_len++; |
5642 | 168k | if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_end; |
5643 | 1.04k | goto fail_number; |
5644 | 168k | } |
5645 | 59.5k | if (*cur == '{') { |
5646 | 29.3k | cur++; |
5647 | 29.3k | goto obj_begin; |
5648 | 29.3k | } |
5649 | 30.1k | if (*cur == '[') { |
5650 | 7.86k | cur++; |
5651 | 7.86k | goto arr_begin; |
5652 | 7.86k | } |
5653 | 22.3k | if (*cur == 't') { |
5654 | 1.99k | val++; |
5655 | 1.99k | ctn_len++; |
5656 | 1.99k | if (likely(read_true(&cur, val))) goto obj_val_end; |
5657 | 56 | goto fail_literal_true; |
5658 | 1.99k | } |
5659 | 20.3k | if (*cur == 'f') { |
5660 | 1.05k | val++; |
5661 | 1.05k | ctn_len++; |
5662 | 1.05k | if (likely(read_false(&cur, val))) goto obj_val_end; |
5663 | 111 | goto fail_literal_false; |
5664 | 1.05k | } |
5665 | 19.2k | if (*cur == 'n') { |
5666 | 1.57k | val++; |
5667 | 1.57k | ctn_len++; |
5668 | 1.57k | if (likely(read_null(&cur, val))) goto obj_val_end; |
5669 | 337 | if (has_allow(INF_AND_NAN)) { |
5670 | 269 | if (read_nan(&cur, pre, flg, val)) goto obj_val_end; |
5671 | 269 | } |
5672 | 111 | goto fail_literal_null; |
5673 | 337 | } |
5674 | 17.6k | if (char_is_space(*cur)) { |
5675 | 18.0k | while (char_is_space(*++cur)); |
5676 | 14.2k | goto obj_val_begin; |
5677 | 14.2k | } |
5678 | 3.45k | if (has_allow(INF_AND_NAN) && |
5679 | 2.39k | (*cur == 'i' || *cur == 'I' || *cur == 'N')) { |
5680 | 1.59k | val++; |
5681 | 1.59k | ctn_len++; |
5682 | 1.59k | if (read_inf_or_nan(&cur, pre, flg, val)) goto obj_val_end; |
5683 | 32 | goto fail_character_val; |
5684 | 1.59k | } |
5685 | 1.85k | if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') { |
5686 | 385 | val++; |
5687 | 385 | ctn_len++; |
5688 | 385 | if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_val_end; |
5689 | 4 | goto fail_string; |
5690 | 385 | } |
5691 | 1.46k | if (has_allow(TRIVIA) && char_is_trivia(*cur)) { |
5692 | 1.12k | if (skip_trivia(&cur, eof, flg)) goto obj_val_begin; |
5693 | 21 | if (cur == eof) goto fail_comment; |
5694 | 21 | } |
5695 | 362 | goto fail_character_val; |
5696 | | |
5697 | 267k | obj_val_end: |
5698 | 267k | if (likely(*cur == ',')) { |
5699 | 217k | cur++; |
5700 | 217k | goto obj_key_begin; |
5701 | 217k | } |
5702 | 49.5k | if (likely(*cur == '}')) { |
5703 | 31.3k | cur++; |
5704 | 31.3k | goto obj_end; |
5705 | 31.3k | } |
5706 | 18.2k | if (char_is_space(*cur)) { |
5707 | 13.5k | while (char_is_space(*++cur)); |
5708 | 10.4k | goto obj_val_end; |
5709 | 10.4k | } |
5710 | 7.76k | if (has_allow(TRIVIA) && char_is_trivia(*cur)) { |
5711 | 1.49k | if (skip_trivia(&cur, eof, flg)) goto obj_val_end; |
5712 | 63 | if (cur == eof) goto fail_comment; |
5713 | 63 | } |
5714 | 6.32k | goto fail_character_obj_end; |
5715 | | |
5716 | 49.0k | obj_end: |
5717 | | #if YYJSON_READER_DEPTH_LIMIT |
5718 | | container_depth--; |
5719 | | #endif |
5720 | | /* pop container */ |
5721 | 49.0k | ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs); |
5722 | | /* point to the next value */ |
5723 | 49.0k | ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val); |
5724 | 49.0k | ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ; |
5725 | 49.0k | if (unlikely(ctn == ctn_parent)) goto doc_end; |
5726 | 46.3k | ctn = ctn_parent; |
5727 | 46.3k | ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT); |
5728 | 46.3k | if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) { |
5729 | 19.2k | goto obj_val_end; |
5730 | 27.0k | } else { |
5731 | 27.0k | goto arr_val_end; |
5732 | 27.0k | } |
5733 | | |
5734 | 17.8k | doc_end: |
5735 | | /* check invalid contents after json document */ |
5736 | 17.8k | if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) { |
5737 | 1.26k | while (char_is_space(*cur)) cur++; |
5738 | 357 | if (has_allow(TRIVIA) && char_is_trivia(*cur)) { |
5739 | 44 | if (!skip_trivia(&cur, eof, flg) && cur == eof) { |
5740 | 7 | goto fail_comment; |
5741 | 7 | } |
5742 | 44 | } |
5743 | 350 | if (unlikely(cur < eof)) goto fail_garbage; |
5744 | 350 | } |
5745 | | |
5746 | 17.6k | **pre = '\0'; |
5747 | 17.6k | doc = (yyjson_doc *)val_hdr; |
5748 | 17.6k | doc->root = val_hdr + hdr_len; |
5749 | 17.6k | doc->alc = alc; |
5750 | 17.6k | doc->dat_read = (usize)(cur - hdr); |
5751 | 17.6k | doc->val_read = (usize)((val - doc->root) + 1); |
5752 | 17.6k | doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr; |
5753 | 17.6k | return doc; |
5754 | | |
5755 | 8.24k | fail_string: return_err(cur, INVALID_STRING, msg); |
5756 | 2.62k | fail_number: return_err(cur, INVALID_NUMBER, msg); |
5757 | 0 | fail_alloc: return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC); |
5758 | 129 | fail_trailing_comma: return_err(cur, JSON_STRUCTURE, MSG_COMMA); |
5759 | 238 | fail_literal_true: return_err(cur, LITERAL, MSG_CHAR_T); |
5760 | 348 | fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F); |
5761 | 280 | fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N); |
5762 | 2.82k | fail_character_val: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR); |
5763 | 7.88k | fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END); |
5764 | 3.36k | fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY); |
5765 | 955 | fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP); |
5766 | 6.32k | fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END); |
5767 | 60 | fail_comment: return_err(cur, INVALID_COMMENT, MSG_COMMENT); |
5768 | 180 | fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE); |
5769 | 0 | fail_depth: return_err(cur, DEPTH, MSG_DEPTH); |
5770 | |
|
5771 | 0 | #undef val_incr |
5772 | 0 | #undef return_err |
5773 | 0 | } |
5774 | | |
5775 | | /** Read JSON document (accept all style, but optimized for pretty). */ |
5776 | | static_inline yyjson_doc *read_root_pretty(u8 *hdr, u8 *cur, u8 *eof, |
5777 | | yyjson_alc alc, |
5778 | | yyjson_read_flag flg, |
5779 | 31.5k | yyjson_read_err *err) { |
5780 | 31.5k | #define return_err(_pos, _code, _msg) do { \ |
5781 | 31.1k | if (is_truncated_end(hdr, _pos, eof, YYJSON_READ_ERROR_##_code, flg)) { \ |
5782 | 18.7k | err->pos = (usize)(eof - hdr); \ |
5783 | 18.7k | err->code = YYJSON_READ_ERROR_UNEXPECTED_END; \ |
5784 | 18.7k | err->msg = MSG_NOT_END; \ |
5785 | 18.7k | } else { \ |
5786 | 12.4k | err->pos = (usize)(_pos - hdr); \ |
5787 | 12.4k | err->code = YYJSON_READ_ERROR_##_code; \ |
5788 | 12.4k | err->msg = _msg; \ |
5789 | 12.4k | } \ |
5790 | 31.1k | if (val_hdr) alc.free(alc.ctx, val_hdr); \ |
5791 | 31.1k | return NULL; \ |
5792 | 31.1k | } while (false) |
5793 | | |
5794 | 1.03M | #define val_incr() do { \ |
5795 | 1.03M | val++; \ |
5796 | 1.03M | if (unlikely(val >= val_end)) { \ |
5797 | 11.1k | usize alc_old = alc_len; \ |
5798 | 11.1k | usize val_ofs = (usize)(val - val_hdr); \ |
5799 | 11.1k | usize ctn_ofs = (usize)(ctn - val_hdr); \ |
5800 | 11.1k | alc_len += alc_len / 2; \ |
5801 | 11.1k | if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \ |
5802 | 11.1k | val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \ |
5803 | 11.1k | alc_old * sizeof(yyjson_val), \ |
5804 | 11.1k | alc_len * sizeof(yyjson_val)); \ |
5805 | 11.1k | if ((!val_tmp)) goto fail_alloc; \ |
5806 | 11.1k | val = val_tmp + val_ofs; \ |
5807 | 11.1k | ctn = val_tmp + ctn_ofs; \ |
5808 | 11.1k | val_hdr = val_tmp; \ |
5809 | 11.1k | val_end = val_tmp + (alc_len - 2); \ |
5810 | 11.1k | } \ |
5811 | 1.03M | } while (false) |
5812 | | |
5813 | 31.5k | usize dat_len; /* data length in bytes, hint for allocator */ |
5814 | 31.5k | usize hdr_len; /* value count used by yyjson_doc */ |
5815 | 31.5k | usize alc_len; /* value count allocated */ |
5816 | 31.5k | usize alc_max; /* maximum value count for allocator */ |
5817 | 31.5k | usize ctn_len; /* the number of elements in current container */ |
5818 | 31.5k | yyjson_val *val_hdr; /* the head of allocated values */ |
5819 | 31.5k | yyjson_val *val_end; /* the end of allocated values */ |
5820 | 31.5k | yyjson_val *val_tmp; /* temporary pointer for realloc */ |
5821 | 31.5k | yyjson_val *val; /* current JSON value */ |
5822 | 31.5k | yyjson_val *ctn; /* current container */ |
5823 | 31.5k | yyjson_val *ctn_parent; /* parent of current container */ |
5824 | 31.5k | yyjson_doc *doc; /* the JSON document, equals to val_hdr */ |
5825 | 31.5k | const char *msg; /* error message */ |
5826 | | |
5827 | 31.5k | u8 raw_end[1]; /* raw end for null-terminator */ |
5828 | 31.5k | u8 *raw_ptr = raw_end; |
5829 | 31.5k | u8 **pre = &raw_ptr; /* previous raw end pointer */ |
5830 | | #if YYJSON_READER_DEPTH_LIMIT |
5831 | | u32 container_depth = 0; /* current array/object depth */ |
5832 | | #endif |
5833 | | |
5834 | 31.5k | dat_len = has_flg(STOP_WHEN_DONE) ? 256 : (usize)(eof - cur); |
5835 | 31.5k | hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val); |
5836 | 31.5k | hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0; |
5837 | 31.5k | alc_max = USIZE_MAX / sizeof(yyjson_val); |
5838 | 31.5k | alc_len = hdr_len + (dat_len / YYJSON_READER_ESTIMATED_PRETTY_RATIO) + 4; |
5839 | 31.5k | alc_len = yyjson_min(alc_len, alc_max); |
5840 | | |
5841 | 31.5k | val_hdr = (yyjson_val *)alc.malloc(alc.ctx, alc_len * sizeof(yyjson_val)); |
5842 | 31.5k | if (unlikely(!val_hdr)) goto fail_alloc; |
5843 | 31.5k | val_end = val_hdr + (alc_len - 2); /* padding for key-value pair reading */ |
5844 | 31.5k | val = val_hdr + hdr_len; |
5845 | 31.5k | ctn = val; |
5846 | 31.5k | ctn_len = 0; |
5847 | | |
5848 | 31.5k | if (*cur++ == '{') { |
5849 | 12.5k | ctn->tag = YYJSON_TYPE_OBJ; |
5850 | 12.5k | ctn->uni.ofs = 0; |
5851 | 12.5k | if (*cur == '\n') cur++; |
5852 | 12.5k | goto obj_key_begin; |
5853 | 19.0k | } else { |
5854 | 19.0k | ctn->tag = YYJSON_TYPE_ARR; |
5855 | 19.0k | ctn->uni.ofs = 0; |
5856 | 19.0k | if (*cur == '\n') cur++; |
5857 | 19.0k | goto arr_val_begin; |
5858 | 19.0k | } |
5859 | | |
5860 | 121k | arr_begin: |
5861 | | #if YYJSON_READER_DEPTH_LIMIT |
5862 | | container_depth++; |
5863 | | if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) { |
5864 | | goto fail_depth; |
5865 | | } |
5866 | | #endif |
5867 | | |
5868 | | /* save current container */ |
5869 | 121k | ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) | |
5870 | 121k | (ctn->tag & YYJSON_TAG_MASK); |
5871 | | |
5872 | | /* create a new array value, save parent container offset */ |
5873 | 121k | val_incr(); |
5874 | 121k | val->tag = YYJSON_TYPE_ARR; |
5875 | 121k | val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn); |
5876 | | |
5877 | | /* push the new array value as current container */ |
5878 | 121k | ctn = val; |
5879 | 121k | ctn_len = 0; |
5880 | 121k | if (*cur == '\n') cur++; |
5881 | | |
5882 | 1.01M | arr_val_begin: |
5883 | | #if YYJSON_IS_REAL_GCC |
5884 | | while (true) repeat16({ |
5885 | | if (byte_match_2(cur, " ")) cur += 2; |
5886 | | else break; |
5887 | | }) |
5888 | | #else |
5889 | 1.02M | while (true) repeat16({ |
5890 | 1.01M | if (likely(byte_match_2(cur, " "))) cur += 2; |
5891 | 1.01M | else break; |
5892 | 1.01M | }) |
5893 | 1.01M | #endif |
5894 | | |
5895 | 1.01M | if (*cur == '{') { |
5896 | 21.1k | cur++; |
5897 | 21.1k | goto obj_begin; |
5898 | 21.1k | } |
5899 | 997k | if (*cur == '[') { |
5900 | 117k | cur++; |
5901 | 117k | goto arr_begin; |
5902 | 117k | } |
5903 | 880k | if (char_is_num(*cur)) { |
5904 | 626k | val_incr(); |
5905 | 626k | ctn_len++; |
5906 | 626k | if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_end; |
5907 | 1.40k | goto fail_number; |
5908 | 626k | } |
5909 | 254k | if (*cur == '"') { |
5910 | 6.66k | val_incr(); |
5911 | 6.66k | ctn_len++; |
5912 | 6.66k | if (likely(read_str(&cur, eof, flg, val, &msg))) goto arr_val_end; |
5913 | 2.55k | goto fail_string; |
5914 | 6.66k | } |
5915 | 247k | if (*cur == 't') { |
5916 | 30.6k | val_incr(); |
5917 | 30.6k | ctn_len++; |
5918 | 30.6k | if (likely(read_true(&cur, val))) goto arr_val_end; |
5919 | 183 | goto fail_literal_true; |
5920 | 30.6k | } |
5921 | 216k | if (*cur == 'f') { |
5922 | 30.8k | val_incr(); |
5923 | 30.8k | ctn_len++; |
5924 | 30.8k | if (likely(read_false(&cur, val))) goto arr_val_end; |
5925 | 194 | goto fail_literal_false; |
5926 | 30.8k | } |
5927 | 185k | if (*cur == 'n') { |
5928 | 15.1k | val_incr(); |
5929 | 15.1k | ctn_len++; |
5930 | 15.1k | if (likely(read_null(&cur, val))) goto arr_val_end; |
5931 | 763 | if (has_allow(INF_AND_NAN)) { |
5932 | 617 | if (read_nan(&cur, pre, flg, val)) goto arr_val_end; |
5933 | 617 | } |
5934 | 192 | goto fail_literal_null; |
5935 | 763 | } |
5936 | 170k | if (*cur == ']') { |
5937 | 51.8k | cur++; |
5938 | 51.8k | if (likely(ctn_len == 0)) goto arr_end; |
5939 | 935 | if (has_allow(TRAILING_COMMAS)) goto arr_end; |
5940 | 770 | do { cur--; } while (*cur != ','); |
5941 | 46 | goto fail_trailing_comma; |
5942 | 935 | } |
5943 | 118k | if (char_is_space(*cur)) { |
5944 | 235k | while (char_is_space(*++cur)); |
5945 | 109k | goto arr_val_begin; |
5946 | 109k | } |
5947 | 9.80k | if (has_allow(INF_AND_NAN) && |
5948 | 7.49k | (*cur == 'i' || *cur == 'I' || *cur == 'N')) { |
5949 | 1.70k | val_incr(); |
5950 | 1.70k | ctn_len++; |
5951 | 1.70k | if (read_inf_or_nan(&cur, pre, flg, val)) goto arr_val_end; |
5952 | 48 | goto fail_character_val; |
5953 | 1.70k | } |
5954 | 8.10k | if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') { |
5955 | 378 | val_incr(); |
5956 | 378 | ctn_len++; |
5957 | 378 | if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto arr_val_end; |
5958 | 14 | goto fail_string; |
5959 | 378 | } |
5960 | 7.72k | if (has_allow(TRIVIA) && char_is_trivia(*cur)) { |
5961 | 5.52k | if (skip_trivia(&cur, eof, flg)) goto arr_val_begin; |
5962 | 39 | if (cur == eof) goto fail_comment; |
5963 | 39 | } |
5964 | 2.23k | goto fail_character_val; |
5965 | | |
5966 | 903k | arr_val_end: |
5967 | 903k | if (byte_match_2(cur, ",\n")) { |
5968 | 200k | cur += 2; |
5969 | 200k | goto arr_val_begin; |
5970 | 200k | } |
5971 | 703k | if (*cur == ',') { |
5972 | 563k | cur++; |
5973 | 563k | goto arr_val_begin; |
5974 | 563k | } |
5975 | 140k | if (*cur == ']') { |
5976 | 22.8k | cur++; |
5977 | 22.8k | goto arr_end; |
5978 | 22.8k | } |
5979 | 117k | if (char_is_space(*cur)) { |
5980 | 41.0k | while (char_is_space(*++cur)); |
5981 | 31.5k | goto arr_val_end; |
5982 | 31.5k | } |
5983 | 85.9k | if (has_allow(TRIVIA) && char_is_trivia(*cur)) { |
5984 | 78.5k | if (skip_trivia(&cur, eof, flg)) goto arr_val_end; |
5985 | 63 | if (cur == eof) goto fail_comment; |
5986 | 63 | } |
5987 | 7.49k | goto fail_character_arr_end; |
5988 | | |
5989 | 74.6k | arr_end: |
5990 | | #if YYJSON_READER_DEPTH_LIMIT |
5991 | | container_depth--; |
5992 | | #endif |
5993 | | /* get parent container */ |
5994 | 74.6k | ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs); |
5995 | | |
5996 | | /* save the next sibling value offset */ |
5997 | 74.6k | ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val); |
5998 | 74.6k | ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR; |
5999 | 74.6k | if (unlikely(ctn == ctn_parent)) goto doc_end; |
6000 | | |
6001 | | /* pop parent as current container */ |
6002 | 74.2k | ctn = ctn_parent; |
6003 | 74.2k | ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT); |
6004 | 74.2k | if (*cur == '\n') cur++; |
6005 | 74.2k | if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) { |
6006 | 1.68k | goto obj_val_end; |
6007 | 72.6k | } else { |
6008 | 72.6k | goto arr_val_end; |
6009 | 72.6k | } |
6010 | | |
6011 | 36.8k | obj_begin: |
6012 | | #if YYJSON_READER_DEPTH_LIMIT |
6013 | | container_depth++; |
6014 | | if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) { |
6015 | | goto fail_depth; |
6016 | | } |
6017 | | #endif |
6018 | | |
6019 | | /* push container */ |
6020 | 36.8k | ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) | |
6021 | 36.8k | (ctn->tag & YYJSON_TAG_MASK); |
6022 | 36.8k | val_incr(); |
6023 | 36.8k | val->tag = YYJSON_TYPE_OBJ; |
6024 | | /* offset to the parent */ |
6025 | 36.8k | val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn); |
6026 | 36.8k | ctn = val; |
6027 | 36.8k | ctn_len = 0; |
6028 | 36.8k | if (*cur == '\n') cur++; |
6029 | | |
6030 | 200k | obj_key_begin: |
6031 | | #if YYJSON_IS_REAL_GCC |
6032 | | while (true) repeat16({ |
6033 | | if (byte_match_2(cur, " ")) cur += 2; |
6034 | | else break; |
6035 | | }) |
6036 | | #else |
6037 | 202k | while (true) repeat16({ |
6038 | 200k | if (likely(byte_match_2(cur, " "))) cur += 2; |
6039 | 200k | else break; |
6040 | 200k | }) |
6041 | 200k | #endif |
6042 | 200k | if (likely(*cur == '"')) { |
6043 | 151k | val_incr(); |
6044 | 151k | ctn_len++; |
6045 | 151k | if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_key_end; |
6046 | 2.73k | goto fail_string; |
6047 | 151k | } |
6048 | 49.1k | if (likely(*cur == '}')) { |
6049 | 14.0k | cur++; |
6050 | 14.0k | if (likely(ctn_len == 0)) goto obj_end; |
6051 | 282 | if (has_allow(TRAILING_COMMAS)) goto obj_end; |
6052 | 512 | do { cur--; } while (*cur != ','); |
6053 | 30 | goto fail_trailing_comma; |
6054 | 282 | } |
6055 | 35.1k | if (char_is_space(*cur)) { |
6056 | 33.3k | while (char_is_space(*++cur)); |
6057 | 21.8k | goto obj_key_begin; |
6058 | 21.8k | } |
6059 | 13.3k | if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') { |
6060 | 464 | val_incr(); |
6061 | 464 | ctn_len++; |
6062 | 464 | if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_key_end; |
6063 | 19 | goto fail_string; |
6064 | 464 | } |
6065 | 12.8k | if (has_allow(UNQUOTED_KEY) && char_is_id_start(*cur)) { |
6066 | 8.60k | val_incr(); |
6067 | 8.60k | ctn_len++; |
6068 | 8.60k | if (read_str_id(&cur, eof, flg, pre, val, &msg)) goto obj_key_end; |
6069 | 73 | goto fail_string; |
6070 | 8.60k | } |
6071 | 4.26k | if (has_allow(TRIVIA) && char_is_trivia(*cur)) { |
6072 | 1.26k | if (skip_trivia(&cur, eof, flg)) goto obj_key_begin; |
6073 | 23 | if (cur == eof) goto fail_comment; |
6074 | 23 | } |
6075 | 3.01k | goto fail_character_obj_key; |
6076 | | |
6077 | 161k | obj_key_end: |
6078 | 161k | if (byte_match_2(cur, ": ")) { |
6079 | 15.6k | cur += 2; |
6080 | 15.6k | goto obj_val_begin; |
6081 | 15.6k | } |
6082 | 146k | if (*cur == ':') { |
6083 | 141k | cur++; |
6084 | 141k | goto obj_val_begin; |
6085 | 141k | } |
6086 | 4.48k | if (char_is_space(*cur)) { |
6087 | 3.77k | while (char_is_space(*++cur)); |
6088 | 2.83k | goto obj_key_end; |
6089 | 2.83k | } |
6090 | 1.65k | if (has_allow(TRIVIA) && char_is_trivia(*cur)) { |
6091 | 1.16k | if (skip_trivia(&cur, eof, flg)) goto obj_key_end; |
6092 | 22 | if (cur == eof) goto fail_comment; |
6093 | 22 | } |
6094 | 500 | goto fail_character_obj_sep; |
6095 | | |
6096 | 164k | obj_val_begin: |
6097 | 164k | if (*cur == '"') { |
6098 | 4.89k | val++; |
6099 | 4.89k | ctn_len++; |
6100 | 4.89k | if (likely(read_str(&cur, eof, flg, val, &msg))) goto obj_val_end; |
6101 | 2.26k | goto fail_string; |
6102 | 4.89k | } |
6103 | 159k | if (char_is_num(*cur)) { |
6104 | 128k | val++; |
6105 | 128k | ctn_len++; |
6106 | 128k | if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_end; |
6107 | 1.03k | goto fail_number; |
6108 | 128k | } |
6109 | 31.4k | if (*cur == '{') { |
6110 | 15.6k | cur++; |
6111 | 15.6k | goto obj_begin; |
6112 | 15.6k | } |
6113 | 15.7k | if (*cur == '[') { |
6114 | 4.14k | cur++; |
6115 | 4.14k | goto arr_begin; |
6116 | 4.14k | } |
6117 | 11.5k | if (*cur == 't') { |
6118 | 674 | val++; |
6119 | 674 | ctn_len++; |
6120 | 674 | if (likely(read_true(&cur, val))) goto obj_val_end; |
6121 | 94 | goto fail_literal_true; |
6122 | 674 | } |
6123 | 10.8k | if (*cur == 'f') { |
6124 | 717 | val++; |
6125 | 717 | ctn_len++; |
6126 | 717 | if (likely(read_false(&cur, val))) goto obj_val_end; |
6127 | 118 | goto fail_literal_false; |
6128 | 717 | } |
6129 | 10.1k | if (*cur == 'n') { |
6130 | 944 | val++; |
6131 | 944 | ctn_len++; |
6132 | 944 | if (likely(read_null(&cur, val))) goto obj_val_end; |
6133 | 334 | if (has_allow(INF_AND_NAN)) { |
6134 | 263 | if (read_nan(&cur, pre, flg, val)) goto obj_val_end; |
6135 | 263 | } |
6136 | 110 | goto fail_literal_null; |
6137 | 334 | } |
6138 | 9.22k | if (char_is_space(*cur)) { |
6139 | 9.69k | while (char_is_space(*++cur)); |
6140 | 6.06k | goto obj_val_begin; |
6141 | 6.06k | } |
6142 | 3.16k | if (has_allow(INF_AND_NAN) && |
6143 | 2.25k | (*cur == 'i' || *cur == 'I' || *cur == 'N')) { |
6144 | 1.63k | val++; |
6145 | 1.63k | ctn_len++; |
6146 | 1.63k | if (read_inf_or_nan(&cur, pre, flg, val)) goto obj_val_end; |
6147 | 27 | goto fail_character_val; |
6148 | 1.63k | } |
6149 | 1.53k | if (has_allow(SINGLE_QUOTED_STR) && *cur == '\'') { |
6150 | 321 | val++; |
6151 | 321 | ctn_len++; |
6152 | 321 | if (likely(read_str_sq(&cur, eof, flg, val, &msg))) goto obj_val_end; |
6153 | 9 | goto fail_string; |
6154 | 321 | } |
6155 | 1.21k | if (has_allow(TRIVIA) && char_is_trivia(*cur)) { |
6156 | 923 | if (skip_trivia(&cur, eof, flg)) goto obj_val_begin; |
6157 | 15 | if (cur == eof) goto fail_comment; |
6158 | 15 | } |
6159 | 295 | goto fail_character_val; |
6160 | | |
6161 | 144k | obj_val_end: |
6162 | 144k | if (byte_match_2(cur, ",\n")) { |
6163 | 7.49k | cur += 2; |
6164 | 7.49k | goto obj_key_begin; |
6165 | 7.49k | } |
6166 | 136k | if (likely(*cur == ',')) { |
6167 | 120k | cur++; |
6168 | 120k | goto obj_key_begin; |
6169 | 120k | } |
6170 | 16.0k | if (likely(*cur == '}')) { |
6171 | 1.42k | cur++; |
6172 | 1.42k | goto obj_end; |
6173 | 1.42k | } |
6174 | 14.6k | if (char_is_space(*cur)) { |
6175 | 9.63k | while (char_is_space(*++cur)); |
6176 | 7.20k | goto obj_val_end; |
6177 | 7.20k | } |
6178 | 7.40k | if (has_allow(TRIVIA) && char_is_trivia(*cur)) { |
6179 | 1.07k | if (skip_trivia(&cur, eof, flg)) goto obj_val_end; |
6180 | 64 | if (cur == eof) goto fail_comment; |
6181 | 64 | } |
6182 | 6.38k | goto fail_character_obj_end; |
6183 | | |
6184 | 15.4k | obj_end: |
6185 | | #if YYJSON_READER_DEPTH_LIMIT |
6186 | | container_depth--; |
6187 | | #endif |
6188 | | |
6189 | | /* pop container */ |
6190 | 15.4k | ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs); |
6191 | | /* point to the next value */ |
6192 | 15.4k | ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val); |
6193 | 15.4k | ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ; |
6194 | 15.4k | if (unlikely(ctn == ctn_parent)) goto doc_end; |
6195 | 15.3k | ctn = ctn_parent; |
6196 | 15.3k | ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT); |
6197 | 15.3k | if (*cur == '\n') cur++; |
6198 | 15.3k | if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) { |
6199 | 879 | goto obj_val_end; |
6200 | 14.4k | } else { |
6201 | 14.4k | goto arr_val_end; |
6202 | 14.4k | } |
6203 | | |
6204 | 471 | doc_end: |
6205 | | /* check invalid contents after json document */ |
6206 | 471 | if (unlikely(cur < eof) && !has_flg(STOP_WHEN_DONE)) { |
6207 | 803 | while (char_is_space(*cur)) cur++; |
6208 | 126 | if (has_allow(TRIVIA) && char_is_trivia(*cur)) { |
6209 | 26 | if (!skip_trivia(&cur, eof, flg) && cur == eof) { |
6210 | 7 | goto fail_comment; |
6211 | 7 | } |
6212 | 26 | } |
6213 | 119 | if (unlikely(cur < eof)) goto fail_garbage; |
6214 | 119 | } |
6215 | | |
6216 | 407 | **pre = '\0'; |
6217 | 407 | doc = (yyjson_doc *)val_hdr; |
6218 | 407 | doc->root = val_hdr + hdr_len; |
6219 | 407 | doc->alc = alc; |
6220 | 407 | doc->dat_read = (usize)(cur - hdr); |
6221 | 407 | doc->val_read = (usize)((val - doc->root) + 1); |
6222 | 407 | doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr; |
6223 | 407 | return doc; |
6224 | | |
6225 | 7.65k | fail_string: return_err(cur, INVALID_STRING, msg); |
6226 | 2.44k | fail_number: return_err(cur, INVALID_NUMBER, msg); |
6227 | 0 | fail_alloc: return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC); |
6228 | 76 | fail_trailing_comma: return_err(cur, JSON_STRUCTURE, MSG_COMMA); |
6229 | 277 | fail_literal_true: return_err(cur, LITERAL, MSG_CHAR_T); |
6230 | 312 | fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F); |
6231 | 302 | fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N); |
6232 | 2.60k | fail_character_val: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR); |
6233 | 7.49k | fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END); |
6234 | 3.01k | fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY); |
6235 | 500 | fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP); |
6236 | 6.38k | fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END); |
6237 | 54 | fail_comment: return_err(cur, INVALID_COMMENT, MSG_COMMENT); |
6238 | 57 | fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE); |
6239 | 0 | fail_depth: return_err(cur, DEPTH, MSG_DEPTH); |
6240 | |
|
6241 | 0 | #undef val_incr |
6242 | 0 | #undef return_err |
6243 | 0 | } |
6244 | | |
6245 | | |
6246 | | |
6247 | | /*============================================================================== |
6248 | | * MARK: - JSON Reader (Public) |
6249 | | *============================================================================*/ |
6250 | | |
6251 | | yyjson_doc *yyjson_read_opts(char *dat, usize len, |
6252 | | yyjson_read_flag flg, |
6253 | | const yyjson_alc *alc_ptr, |
6254 | 136k | yyjson_read_err *err) { |
6255 | 136k | #define return_err(_pos, _code, _msg) do { \ |
6256 | 21.5k | err->pos = (usize)(_pos); \ |
6257 | 21.5k | err->msg = _msg; \ |
6258 | 21.5k | err->code = YYJSON_READ_ERROR_##_code; \ |
6259 | 21.5k | if (!has_flg(INSITU) && hdr) alc.free(alc.ctx, (void *)hdr); \ |
6260 | 21.5k | return NULL; \ |
6261 | 21.5k | } while (false) |
6262 | | |
6263 | 136k | yyjson_read_err tmp_err; |
6264 | 136k | yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC; |
6265 | 136k | yyjson_doc *doc; |
6266 | 136k | u8 *hdr = NULL, *eof, *cur; |
6267 | | |
6268 | | /* validate input parameters */ |
6269 | 136k | if (!err) err = &tmp_err; |
6270 | 136k | if (unlikely(!dat)) return_err(0, INVALID_PARAMETER, "input data is NULL"); |
6271 | 136k | if (unlikely(!len)) return_err(0, INVALID_PARAMETER, "input length is 0"); |
6272 | | |
6273 | | /* add 4-byte zero padding for input data if necessary */ |
6274 | 115k | if (has_flg(INSITU)) { |
6275 | 0 | hdr = (u8 *)dat; |
6276 | 0 | eof = (u8 *)dat + len; |
6277 | 0 | cur = (u8 *)dat; |
6278 | 115k | } else { |
6279 | 115k | if (unlikely(len >= USIZE_MAX - YYJSON_PADDING_SIZE)) { |
6280 | 0 | return_err(0, MEMORY_ALLOCATION, MSG_MALLOC); |
6281 | 0 | } |
6282 | 115k | hdr = (u8 *)alc.malloc(alc.ctx, len + YYJSON_PADDING_SIZE); |
6283 | 115k | if (unlikely(!hdr)) { |
6284 | 0 | return_err(0, MEMORY_ALLOCATION, MSG_MALLOC); |
6285 | 0 | } |
6286 | 115k | eof = hdr + len; |
6287 | 115k | cur = hdr; |
6288 | 115k | memcpy(hdr, dat, len); |
6289 | 115k | } |
6290 | 115k | memset(eof, 0, YYJSON_PADDING_SIZE); |
6291 | | |
6292 | 115k | if (has_allow(BOM)) { |
6293 | 0 | if (len >= 3 && is_utf8_bom(cur)) cur += 3; |
6294 | 0 | } |
6295 | | |
6296 | | /* skip empty contents before json document */ |
6297 | 115k | if (unlikely(!char_is_ctn(*cur))) { |
6298 | 43.8k | while (char_is_space(*cur)) cur++; |
6299 | 35.6k | if (unlikely(!char_is_ctn(*cur))) { |
6300 | 33.1k | if (has_allow(TRIVIA) && char_is_trivia(*cur)) { |
6301 | 1.03k | if (!skip_trivia(&cur, eof, flg) && cur == eof) { |
6302 | 63 | return_err(cur - hdr, INVALID_COMMENT, MSG_COMMENT); |
6303 | 63 | } |
6304 | 1.03k | } |
6305 | 33.1k | } |
6306 | 35.5k | if (unlikely(cur >= eof)) { |
6307 | 611 | return_err(0, EMPTY_CONTENT, "input data is empty"); |
6308 | 611 | } |
6309 | 35.5k | } |
6310 | | |
6311 | | /* read json document */ |
6312 | 114k | if (likely(char_is_ctn(*cur))) { |
6313 | 82.6k | if (char_is_space(cur[1]) && char_is_space(cur[2])) { |
6314 | 31.5k | doc = read_root_pretty(hdr, cur, eof, alc, flg, err); |
6315 | 51.1k | } else { |
6316 | 51.1k | doc = read_root_minify(hdr, cur, eof, alc, flg, err); |
6317 | 51.1k | } |
6318 | 82.6k | } else { |
6319 | 32.1k | doc = read_root_single(hdr, cur, eof, alc, flg, err); |
6320 | 32.1k | } |
6321 | | |
6322 | | /* check result */ |
6323 | 114k | if (likely(doc)) { |
6324 | 34.5k | memset(err, 0, sizeof(yyjson_read_err)); |
6325 | 80.2k | } else { |
6326 | | /* RFC 8259: JSON text MUST be encoded using UTF-8 */ |
6327 | 80.2k | if (err->pos == 0 && err->code != YYJSON_READ_ERROR_MEMORY_ALLOCATION) { |
6328 | 8.58k | if (is_utf8_bom(hdr)) err->msg = MSG_ERR_BOM; |
6329 | 8.57k | else if (len >= 4 && is_utf32_bom(hdr)) err->msg = MSG_ERR_UTF32; |
6330 | 8.55k | else if (len >= 2 && is_utf16_bom(hdr)) err->msg = MSG_ERR_UTF16; |
6331 | 8.58k | } |
6332 | 80.2k | if (!has_flg(INSITU)) alc.free(alc.ctx, hdr); |
6333 | 80.2k | } |
6334 | 114k | return doc; |
6335 | | |
6336 | 115k | #undef return_err |
6337 | 115k | } |
6338 | | |
6339 | | #if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE |
6340 | | |
6341 | | yyjson_doc *yyjson_read_file(const char *path, |
6342 | | yyjson_read_flag flg, |
6343 | | const yyjson_alc *alc_ptr, |
6344 | 0 | yyjson_read_err *err) { |
6345 | 0 | #define return_err(_code, _msg) do { \ |
6346 | 0 | err->pos = 0; \ |
6347 | 0 | err->msg = _msg; \ |
6348 | 0 | err->code = YYJSON_READ_ERROR_##_code; \ |
6349 | 0 | return NULL; \ |
6350 | 0 | } while (false) |
6351 | |
|
6352 | 0 | yyjson_read_err tmp_err; |
6353 | 0 | yyjson_doc *doc; |
6354 | 0 | FILE *file; |
6355 | |
|
6356 | 0 | if (!err) err = &tmp_err; |
6357 | 0 | if (unlikely(!path)) return_err(INVALID_PARAMETER, "input path is NULL"); |
6358 | | |
6359 | 0 | file = fopen_readonly(path); |
6360 | 0 | if (unlikely(!file)) return_err(FILE_OPEN, MSG_FREAD); |
6361 | | |
6362 | 0 | doc = yyjson_read_fp(file, flg, alc_ptr, err); |
6363 | 0 | fclose(file); |
6364 | 0 | return doc; |
6365 | |
|
6366 | 0 | #undef return_err |
6367 | 0 | } |
6368 | | |
6369 | | yyjson_doc *yyjson_read_fp(FILE *file, |
6370 | | yyjson_read_flag flg, |
6371 | | const yyjson_alc *alc_ptr, |
6372 | 0 | yyjson_read_err *err) { |
6373 | 0 | #define return_err(_code, _msg) do { \ |
6374 | 0 | err->pos = 0; \ |
6375 | 0 | err->msg = _msg; \ |
6376 | 0 | err->code = YYJSON_READ_ERROR_##_code; \ |
6377 | 0 | if (buf) alc.free(alc.ctx, buf); \ |
6378 | 0 | return NULL; \ |
6379 | 0 | } while (false) |
6380 | |
|
6381 | 0 | yyjson_read_err tmp_err; |
6382 | 0 | yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC; |
6383 | 0 | yyjson_doc *doc; |
6384 | |
|
6385 | 0 | long file_size = 0, file_pos; |
6386 | 0 | void *buf = NULL; |
6387 | 0 | usize buf_size = 0; |
6388 | 0 | usize dat_size = 0; |
6389 | | |
6390 | | /* validate input parameters */ |
6391 | 0 | if (!err) err = &tmp_err; |
6392 | 0 | if (unlikely(!file)) return_err(INVALID_PARAMETER, "input file is NULL"); |
6393 | | |
6394 | | /* get current position */ |
6395 | 0 | file_pos = ftell(file); |
6396 | 0 | if (file_pos != -1) { |
6397 | | /* get total file size, may fail */ |
6398 | 0 | if (fseek(file, 0, SEEK_END) == 0) { |
6399 | 0 | file_size = ftell(file); |
6400 | 0 | if (file_size == -1) file_size = 0; |
6401 | 0 | } |
6402 | | /* reset to original position, may fail */ |
6403 | 0 | if (fseek(file, file_pos, SEEK_SET) != 0) file_size = 0; |
6404 | | /* get file size from current position to end */ |
6405 | 0 | if (file_size > 0) file_size -= file_pos; |
6406 | 0 | } |
6407 | | |
6408 | | /* read file */ |
6409 | 0 | if (file_size > 0) { |
6410 | | /* read the entire file in one call */ |
6411 | 0 | dat_size = (usize)file_size; |
6412 | 0 | buf_size = dat_size + YYJSON_PADDING_SIZE; |
6413 | 0 | buf = alc.malloc(alc.ctx, buf_size); |
6414 | 0 | if (buf == NULL) { |
6415 | 0 | return_err(MEMORY_ALLOCATION, MSG_MALLOC); |
6416 | 0 | } |
6417 | 0 | if (fread_safe(buf, dat_size, file) != dat_size) { |
6418 | 0 | return_err(FILE_READ, MSG_FREAD); |
6419 | 0 | } |
6420 | 0 | } else { |
6421 | | /* failed to get file size, read it as a stream */ |
6422 | 0 | usize chunk_min = (usize)64; |
6423 | 0 | usize chunk_max = (usize)512 * 1024 * 1024; |
6424 | 0 | usize chunk_now = chunk_min; |
6425 | 0 | usize read_size; |
6426 | 0 | void *tmp; |
6427 | |
|
6428 | 0 | buf_size = YYJSON_PADDING_SIZE; |
6429 | 0 | while (true) { |
6430 | 0 | if (buf_size + chunk_now < buf_size) { /* overflow */ |
6431 | 0 | return_err(MEMORY_ALLOCATION, MSG_MALLOC); |
6432 | 0 | } |
6433 | 0 | buf_size += chunk_now; |
6434 | 0 | if (!buf) { |
6435 | 0 | buf = alc.malloc(alc.ctx, buf_size); |
6436 | 0 | if (!buf) return_err(MEMORY_ALLOCATION, MSG_MALLOC); |
6437 | 0 | } else { |
6438 | 0 | tmp = alc.realloc(alc.ctx, buf, buf_size - chunk_now, buf_size); |
6439 | 0 | if (!tmp) return_err(MEMORY_ALLOCATION, MSG_MALLOC); |
6440 | 0 | buf = tmp; |
6441 | 0 | } |
6442 | 0 | tmp = ((u8 *)buf) + buf_size - YYJSON_PADDING_SIZE - chunk_now; |
6443 | 0 | read_size = fread_safe(tmp, chunk_now, file); |
6444 | 0 | dat_size += read_size; |
6445 | 0 | if (read_size != chunk_now) { |
6446 | 0 | if (ferror(file)) return_err(FILE_READ, MSG_FREAD); |
6447 | 0 | break; |
6448 | 0 | } |
6449 | | |
6450 | 0 | chunk_now *= 2; |
6451 | 0 | if (chunk_now > chunk_max) chunk_now = chunk_max; |
6452 | 0 | } |
6453 | 0 | } |
6454 | | |
6455 | | /* read JSON */ |
6456 | 0 | memset((u8 *)buf + dat_size, 0, YYJSON_PADDING_SIZE); |
6457 | 0 | flg |= YYJSON_READ_INSITU; |
6458 | 0 | doc = yyjson_read_opts((char *)buf, dat_size, flg, &alc, err); |
6459 | 0 | if (doc) { |
6460 | 0 | doc->str_pool = (char *)buf; |
6461 | 0 | return doc; |
6462 | 0 | } else { |
6463 | 0 | alc.free(alc.ctx, buf); |
6464 | 0 | return NULL; |
6465 | 0 | } |
6466 | |
|
6467 | 0 | #undef return_err |
6468 | 0 | } |
6469 | | |
6470 | | #endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */ |
6471 | | |
6472 | | const char *yyjson_read_number(const char *dat, |
6473 | | yyjson_val *val, |
6474 | | yyjson_read_flag flg, |
6475 | | const yyjson_alc *alc, |
6476 | 0 | yyjson_read_err *err) { |
6477 | 0 | #define return_err(_pos, _code, _msg) do { \ |
6478 | 0 | err->pos = _pos > hdr ? (usize)(_pos - hdr) : 0; \ |
6479 | 0 | err->msg = _msg; \ |
6480 | 0 | err->code = YYJSON_READ_ERROR_##_code; \ |
6481 | 0 | return NULL; \ |
6482 | 0 | } while (false) |
6483 | |
|
6484 | 0 | u8 *hdr = constcast(u8 *)dat, *cur = hdr; |
6485 | 0 | u8 raw_end[1]; /* raw end for null-terminator */ |
6486 | 0 | u8 *raw_ptr = raw_end; |
6487 | 0 | u8 **pre = &raw_ptr; /* previous raw end pointer */ |
6488 | 0 | const char *msg; |
6489 | 0 | yyjson_read_err tmp_err; |
6490 | |
|
6491 | | #if YYJSON_DISABLE_FAST_FP_CONV |
6492 | | u8 buf[128]; |
6493 | | usize dat_len; |
6494 | | #endif |
6495 | |
|
6496 | 0 | if (!err) err = &tmp_err; |
6497 | 0 | if (unlikely(!dat)) { |
6498 | 0 | return_err(cur, INVALID_PARAMETER, "input data is NULL"); |
6499 | 0 | } |
6500 | 0 | if (unlikely(!val)) { |
6501 | 0 | return_err(cur, INVALID_PARAMETER, "output value is NULL"); |
6502 | 0 | } |
6503 | | |
6504 | | #if YYJSON_DISABLE_FAST_FP_CONV |
6505 | | if (!alc) alc = &YYJSON_DEFAULT_ALC; |
6506 | | dat_len = strlen(dat); |
6507 | | if (dat_len < sizeof(buf)) { |
6508 | | memcpy(buf, dat, dat_len + 1); |
6509 | | hdr = buf; |
6510 | | cur = hdr; |
6511 | | } else { |
6512 | | hdr = (u8 *)alc->malloc(alc->ctx, dat_len + 1); |
6513 | | cur = hdr; |
6514 | | if (unlikely(!hdr)) { |
6515 | | return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC); |
6516 | | } |
6517 | | memcpy(hdr, dat, dat_len + 1); |
6518 | | } |
6519 | | hdr[dat_len] = 0; |
6520 | | #endif |
6521 | | |
6522 | | #if YYJSON_DISABLE_FAST_FP_CONV |
6523 | | if (!read_num(&cur, pre, flg, val, &msg)) { |
6524 | | if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr); |
6525 | | return_err(cur, INVALID_NUMBER, msg); |
6526 | | } |
6527 | | if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr); |
6528 | | if (yyjson_is_raw(val)) val->uni.str = dat; |
6529 | | return dat + (cur - hdr); |
6530 | | #else |
6531 | 0 | if (!read_num(&cur, pre, flg, val, &msg)) { |
6532 | 0 | return_err(cur, INVALID_NUMBER, msg); |
6533 | 0 | } |
6534 | 0 | return (const char *)cur; |
6535 | 0 | #endif |
6536 | |
|
6537 | 0 | #undef return_err |
6538 | 0 | } |
6539 | | |
6540 | | |
6541 | | |
6542 | | /*============================================================================== |
6543 | | * MARK: - Incremental JSON Reader (Public) |
6544 | | *============================================================================*/ |
6545 | | |
6546 | | #if !YYJSON_DISABLE_INCR_READER |
6547 | | |
6548 | | /* labels within yyjson_incr_read() to resume incremental parsing */ |
6549 | 0 | #define LABEL_doc_begin 0 |
6550 | 0 | #define LABEL_arr_val_begin 1 |
6551 | 0 | #define LABEL_arr_val_end 2 |
6552 | 0 | #define LABEL_obj_key_begin 3 |
6553 | 0 | #define LABEL_obj_key_end 4 |
6554 | 0 | #define LABEL_obj_val_begin 5 |
6555 | 0 | #define LABEL_obj_val_end 6 |
6556 | 0 | #define LABEL_doc_end 7 |
6557 | | |
6558 | | /** State for incremental JSON reader, opaque in the API. */ |
6559 | | struct yyjson_incr_state { |
6560 | | u32 label; /* current parser goto label */ |
6561 | | yyjson_alc alc; /* allocator */ |
6562 | | yyjson_read_flag flg; /* read flags */ |
6563 | | u8 *hdr; /* JSON data header */ |
6564 | | u8 *cur; /* current position in JSON data */ |
6565 | | usize buf_len; /* total buffer length (without padding) */ |
6566 | | usize hdr_len; /* value count used by yyjson_doc */ |
6567 | | usize alc_len; /* value count allocated */ |
6568 | | usize ctn_len; /* the number of elements in current container */ |
6569 | | #if YYJSON_READER_DEPTH_LIMIT |
6570 | | u32 ctn_depth; /* current array/object depth */ |
6571 | | #endif |
6572 | | yyjson_val *val_hdr; /* the head of allocated values */ |
6573 | | yyjson_val *val_end; /* the end of allocated values */ |
6574 | | yyjson_val *val; /* current JSON value */ |
6575 | | yyjson_val *ctn; /* current container */ |
6576 | | u8 *str_con[2]; /* string parser incremental state */ |
6577 | | u8 *raw_ptr; /* pending position for a deferred raw null-terminator */ |
6578 | | u8 raw_end[1]; /* dummy target for the first deferred null-terminator */ |
6579 | | }; |
6580 | | |
6581 | | yyjson_incr_state *yyjson_incr_new(char *buf, size_t buf_len, |
6582 | | yyjson_read_flag flg, |
6583 | 0 | const yyjson_alc *alc_ptr) { |
6584 | 0 | yyjson_incr_state *state = NULL; |
6585 | 0 | yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC; |
6586 | | |
6587 | | /* remove non-standard flags */ |
6588 | 0 | flg &= ~YYJSON_READ_JSON5; |
6589 | 0 | flg &= ~YYJSON_READ_ALLOW_BOM; |
6590 | 0 | flg &= ~YYJSON_READ_ALLOW_INVALID_UNICODE; |
6591 | |
|
6592 | 0 | if (unlikely(!buf)) return NULL; |
6593 | 0 | if (unlikely(buf_len >= USIZE_MAX - YYJSON_PADDING_SIZE)) return NULL; |
6594 | 0 | state = (yyjson_incr_state *)alc.malloc(alc.ctx, sizeof(*state)); |
6595 | 0 | if (!state) return NULL; |
6596 | 0 | memset(state, 0, sizeof(yyjson_incr_state)); |
6597 | 0 | state->alc = alc; |
6598 | 0 | state->flg = flg; |
6599 | 0 | state->buf_len = buf_len; |
6600 | | |
6601 | | /* add 4-byte zero padding for input data if necessary */ |
6602 | 0 | if (has_flg(INSITU)) { |
6603 | 0 | state->hdr = (u8 *)buf; |
6604 | 0 | } else { |
6605 | 0 | state->hdr = (u8 *)alc.malloc(alc.ctx, buf_len + YYJSON_PADDING_SIZE); |
6606 | 0 | if (unlikely(!state->hdr)) { |
6607 | 0 | alc.free(alc.ctx, state); |
6608 | 0 | return NULL; |
6609 | 0 | } |
6610 | 0 | memcpy(state->hdr, buf, buf_len); |
6611 | 0 | } |
6612 | 0 | memset(state->hdr + buf_len, 0, YYJSON_PADDING_SIZE); |
6613 | 0 | state->cur = state->hdr; |
6614 | 0 | state->raw_ptr = state->raw_end; |
6615 | 0 | state->label = LABEL_doc_begin; |
6616 | 0 | return state; |
6617 | 0 | } |
6618 | | |
6619 | 0 | void yyjson_incr_free(yyjson_incr_state *state) { |
6620 | 0 | if (state) { |
6621 | 0 | yyjson_alc alc = state->alc; |
6622 | 0 | memset(&state->alc, 0, sizeof(alc)); |
6623 | 0 | if (state->val_hdr) { |
6624 | 0 | alc.free(alc.ctx, (void *)state->val_hdr); |
6625 | 0 | } |
6626 | 0 | if (state->hdr && !(state->flg & YYJSON_READ_INSITU)) { |
6627 | 0 | alc.free(alc.ctx, state->hdr); |
6628 | 0 | } |
6629 | 0 | alc.free(alc.ctx, state); |
6630 | 0 | } |
6631 | 0 | } |
6632 | | |
6633 | | yyjson_doc *yyjson_incr_read(yyjson_incr_state *state, size_t len, |
6634 | 0 | yyjson_read_err *err) { |
6635 | 0 | #define return_err_inv_param(_msg) do { \ |
6636 | 0 | err->pos = 0; \ |
6637 | 0 | err->msg = _msg; \ |
6638 | 0 | err->code = YYJSON_READ_ERROR_INVALID_PARAMETER; \ |
6639 | 0 | return NULL; \ |
6640 | 0 | } while (false) |
6641 | |
|
6642 | 0 | #define return_err(_pos, _code, _msg) do { \ |
6643 | 0 | if (is_truncated_end(hdr, _pos, end, YYJSON_READ_ERROR_##_code, flg)) { \ |
6644 | 0 | goto unexpected_end; \ |
6645 | 0 | } else { \ |
6646 | 0 | err->pos = (usize)(_pos - hdr); \ |
6647 | 0 | err->code = YYJSON_READ_ERROR_##_code; \ |
6648 | 0 | err->msg = _msg; \ |
6649 | 0 | } \ |
6650 | 0 | return NULL; \ |
6651 | 0 | } while (false) |
6652 | |
|
6653 | 0 | #define val_incr() do { \ |
6654 | 0 | val++; \ |
6655 | 0 | if (unlikely(val >= val_end)) { \ |
6656 | 0 | usize alc_old = alc_len; \ |
6657 | 0 | alc_len += alc_len / 2; \ |
6658 | 0 | if ((sizeof(usize) < 8) && (alc_len >= alc_max)) goto fail_alloc; \ |
6659 | 0 | val_tmp = (yyjson_val *)alc.realloc(alc.ctx, (void *)val_hdr, \ |
6660 | 0 | alc_old * sizeof(yyjson_val), \ |
6661 | 0 | alc_len * sizeof(yyjson_val)); \ |
6662 | 0 | if ((!val_tmp)) goto fail_alloc; \ |
6663 | 0 | val = val_tmp + (usize)(val - val_hdr); \ |
6664 | 0 | ctn = val_tmp + (usize)(ctn - val_hdr); \ |
6665 | 0 | state->val = val_tmp + (usize)(state->val - val_hdr); \ |
6666 | 0 | state->val_hdr = val_hdr = val_tmp; \ |
6667 | 0 | val_end = val_tmp + (alc_len - 2); \ |
6668 | 0 | state->val_end = val_end; \ |
6669 | 0 | } \ |
6670 | 0 | } while (false) |
6671 | | |
6672 | | /* save position where it's possible to resume incremental parsing */ |
6673 | | #if YYJSON_READER_DEPTH_LIMIT |
6674 | | #define save_incr_depth() (state->ctn_depth = container_depth) |
6675 | | #else |
6676 | 0 | #define save_incr_depth() ((void)0) |
6677 | 0 | #endif |
6678 | 0 | #define save_incr_state(_label) do { \ |
6679 | 0 | state->label = LABEL_##_label; \ |
6680 | 0 | state->cur = cur; \ |
6681 | 0 | state->val = val; \ |
6682 | 0 | state->ctn_len = ctn_len; \ |
6683 | 0 | save_incr_depth(); \ |
6684 | 0 | state->hdr_len = hdr_len; \ |
6685 | 0 | state->raw_ptr = raw_ptr; \ |
6686 | 0 | if (unlikely(cur >= end)) goto unexpected_end; \ |
6687 | 0 | } while (false) |
6688 | |
|
6689 | 0 | #define check_maybe_truncated_number() do { \ |
6690 | 0 | if (unlikely(cur >= end)) { \ |
6691 | 0 | if (unlikely(cur > state->cur + INCR_NUM_MAX_LEN)) { \ |
6692 | 0 | msg = "number too long"; \ |
6693 | 0 | goto fail_number; \ |
6694 | 0 | } \ |
6695 | 0 | goto unexpected_end; \ |
6696 | 0 | } \ |
6697 | 0 | } while (false) |
6698 | |
|
6699 | 0 | u8 *hdr = NULL, *end = NULL, *cur = NULL; |
6700 | 0 | yyjson_read_flag flg; |
6701 | 0 | yyjson_alc alc; |
6702 | 0 | usize dat_len; /* data length in bytes, hint for allocator */ |
6703 | 0 | usize hdr_len; /* value count used by yyjson_doc */ |
6704 | 0 | usize alc_len; /* value count allocated */ |
6705 | 0 | usize alc_max; /* maximum value count for allocator */ |
6706 | 0 | usize ctn_len; /* the number of elements in current container */ |
6707 | 0 | yyjson_val *val_hdr; /* the head of allocated values */ |
6708 | 0 | yyjson_val *val_end; /* the end of allocated values */ |
6709 | 0 | yyjson_val *val_tmp; /* temporary pointer for realloc */ |
6710 | 0 | yyjson_val *val; /* current JSON value */ |
6711 | 0 | yyjson_val *ctn; /* current container */ |
6712 | 0 | yyjson_val *ctn_parent; /* parent of current container */ |
6713 | 0 | yyjson_doc *doc; /* the JSON document, equals to val_hdr */ |
6714 | 0 | const char *msg; /* error message */ |
6715 | |
|
6716 | 0 | yyjson_read_err tmp_err; |
6717 | 0 | u8 *raw_ptr; /* deferred raw null-terminator position, committed at save */ |
6718 | 0 | u8 **pre = &raw_ptr; /* previous raw end pointer */ |
6719 | 0 | u8 **con = NULL; /* for incremental string parsing */ |
6720 | 0 | u8 saved_end = '\0'; /* saved end char */ |
6721 | |
|
6722 | | #if YYJSON_READER_DEPTH_LIMIT |
6723 | | u32 container_depth = 0; /* current array/object depth */ |
6724 | | #endif |
6725 | | |
6726 | | /* validate input parameters */ |
6727 | 0 | if (!err) err = &tmp_err; |
6728 | 0 | if (unlikely(!state)) { |
6729 | 0 | return_err_inv_param("input state is NULL"); |
6730 | 0 | } |
6731 | 0 | if (unlikely(!len)) { |
6732 | 0 | return_err_inv_param("input length is 0"); |
6733 | 0 | } |
6734 | 0 | if (unlikely(len > state->buf_len)) { |
6735 | 0 | return_err_inv_param("length is greater than total input length"); |
6736 | 0 | } |
6737 | | |
6738 | | /* restore state saved from the previous call */ |
6739 | 0 | hdr = state->hdr; |
6740 | 0 | end = state->hdr + len; |
6741 | 0 | cur = state->cur; |
6742 | 0 | flg = state->flg; |
6743 | 0 | alc = state->alc; |
6744 | 0 | ctn_len = state->ctn_len; |
6745 | | #if YYJSON_READER_DEPTH_LIMIT |
6746 | | container_depth = state->ctn_depth; |
6747 | | #endif |
6748 | 0 | hdr_len = state->hdr_len; |
6749 | 0 | alc_len = state->alc_len; |
6750 | 0 | val = state->val; |
6751 | 0 | val_hdr = state->val_hdr; |
6752 | 0 | val_end = state->val_end; |
6753 | 0 | ctn = state->ctn; |
6754 | 0 | con = state->str_con; |
6755 | 0 | raw_ptr = state->raw_ptr; |
6756 | 0 | alc_max = USIZE_MAX / sizeof(yyjson_val); |
6757 | | |
6758 | | /* insert null terminator to make us stop at the specified end, even if |
6759 | | the data contains more valid JSON */ |
6760 | 0 | saved_end = *end; |
6761 | 0 | *end = '\0'; |
6762 | | |
6763 | | /* resume parsing from the last save point */ |
6764 | 0 | switch (state->label) { |
6765 | 0 | case LABEL_doc_begin: goto doc_begin; |
6766 | 0 | case LABEL_arr_val_begin: goto arr_val_begin; |
6767 | 0 | case LABEL_arr_val_end: goto arr_val_end; |
6768 | 0 | case LABEL_obj_key_begin: goto obj_key_begin; |
6769 | 0 | case LABEL_obj_key_end: goto obj_key_end; |
6770 | 0 | case LABEL_obj_val_begin: goto obj_val_begin; |
6771 | 0 | case LABEL_obj_val_end: goto obj_val_end; |
6772 | 0 | case LABEL_doc_end: goto doc_end; |
6773 | 0 | default: return_err_inv_param("invalid incremental state"); |
6774 | 0 | } |
6775 | | |
6776 | 0 | doc_begin: |
6777 | | /* skip empty contents before json document */ |
6778 | 0 | if (unlikely(!char_is_ctn(*cur))) { |
6779 | 0 | while (char_is_space(*cur)) cur++; |
6780 | 0 | if (unlikely(cur >= end)) goto unexpected_end; /* input data is empty */ |
6781 | 0 | } |
6782 | | |
6783 | | /* allocate memory for document */ |
6784 | 0 | if (!val_hdr) { |
6785 | 0 | hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val); |
6786 | 0 | hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0; |
6787 | 0 | if (likely(char_is_ctn(*cur))) { |
6788 | 0 | dat_len = has_flg(STOP_WHEN_DONE) ? 256 : state->buf_len; |
6789 | 0 | alc_len = hdr_len + |
6790 | 0 | (dat_len / YYJSON_READER_ESTIMATED_MINIFY_RATIO) + 4; |
6791 | 0 | alc_len = yyjson_min(alc_len, alc_max); |
6792 | 0 | } else { |
6793 | 0 | alc_len = hdr_len + 1; /* single value */ |
6794 | 0 | } |
6795 | 0 | val_hdr = (yyjson_val *)alc.malloc(alc.ctx, |
6796 | 0 | alc_len * sizeof(yyjson_val)); |
6797 | 0 | if (unlikely(!val_hdr)) goto fail_alloc; |
6798 | 0 | val_end = val_hdr + (alc_len - 2); /* padding for kv pair reading */ |
6799 | 0 | val = val_hdr + hdr_len; |
6800 | 0 | ctn = val; |
6801 | 0 | ctn_len = 0; |
6802 | 0 | state->val_hdr = val_hdr; |
6803 | 0 | state->val_end = val_end; |
6804 | 0 | save_incr_state(doc_begin); |
6805 | 0 | } |
6806 | | |
6807 | | /* read json document */ |
6808 | 0 | if (*cur == '{') { |
6809 | 0 | cur++; |
6810 | 0 | ctn->tag = YYJSON_TYPE_OBJ; |
6811 | 0 | ctn->uni.ofs = 0; |
6812 | 0 | goto obj_key_begin; |
6813 | 0 | } |
6814 | 0 | if (*cur == '[') { |
6815 | 0 | cur++; |
6816 | 0 | ctn->tag = YYJSON_TYPE_ARR; |
6817 | 0 | ctn->uni.ofs = 0; |
6818 | 0 | goto arr_val_begin; |
6819 | 0 | } |
6820 | 0 | if (char_is_num(*cur)) { |
6821 | 0 | if (likely(read_num(&cur, pre, flg, val, &msg))) { |
6822 | | /* a root number may continue with more digits in a later chunk */ |
6823 | 0 | if (unlikely(len < state->buf_len)) check_maybe_truncated_number(); |
6824 | 0 | goto doc_end; |
6825 | 0 | } |
6826 | 0 | goto fail_number; |
6827 | 0 | } |
6828 | 0 | if (*cur == '"') { |
6829 | 0 | if (likely(read_str_con(&cur, end, flg, val, &msg, con))) goto doc_end; |
6830 | 0 | goto fail_string; |
6831 | 0 | } |
6832 | 0 | if (*cur == 't') { |
6833 | 0 | if (likely(read_true(&cur, val))) goto doc_end; |
6834 | 0 | goto fail_literal_true; |
6835 | 0 | } |
6836 | 0 | if (*cur == 'f') { |
6837 | 0 | if (likely(read_false(&cur, val))) goto doc_end; |
6838 | 0 | goto fail_literal_false; |
6839 | 0 | } |
6840 | 0 | if (*cur == 'n') { |
6841 | 0 | if (likely(read_null(&cur, val))) goto doc_end; |
6842 | 0 | goto fail_literal_null; |
6843 | 0 | } |
6844 | | |
6845 | 0 | msg = "unexpected character, expected a valid root value"; |
6846 | 0 | if (cur == hdr) { |
6847 | | /* RFC 8259: JSON text MUST be encoded using UTF-8 */ |
6848 | 0 | if (is_utf8_bom(hdr)) msg = MSG_ERR_BOM; |
6849 | 0 | else if (len >= 4 && is_utf32_bom(hdr)) msg = MSG_ERR_UTF32; |
6850 | 0 | else if (len >= 2 && is_utf16_bom(hdr)) msg = MSG_ERR_UTF16; |
6851 | 0 | } |
6852 | 0 | return_err(cur, UNEXPECTED_CHARACTER, msg); |
6853 | | |
6854 | 0 | arr_begin: |
6855 | | #if YYJSON_READER_DEPTH_LIMIT |
6856 | | container_depth++; |
6857 | | if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) { |
6858 | | goto fail_depth; |
6859 | | } |
6860 | | #endif |
6861 | | |
6862 | | /* save current container */ |
6863 | 0 | ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) | |
6864 | 0 | (ctn->tag & YYJSON_TAG_MASK); |
6865 | | |
6866 | | /* create a new array value, save parent container offset */ |
6867 | 0 | val_incr(); |
6868 | 0 | val->tag = YYJSON_TYPE_ARR; |
6869 | 0 | val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn); |
6870 | | |
6871 | | /* push the new array value as current container */ |
6872 | 0 | ctn = val; |
6873 | 0 | ctn_len = 0; |
6874 | |
|
6875 | 0 | arr_val_begin: |
6876 | 0 | save_incr_state(arr_val_begin); |
6877 | 0 | arr_val_continue: |
6878 | 0 | if (*cur == '{') { |
6879 | 0 | cur++; |
6880 | 0 | goto obj_begin; |
6881 | 0 | } |
6882 | 0 | if (*cur == '[') { |
6883 | 0 | cur++; |
6884 | 0 | goto arr_begin; |
6885 | 0 | } |
6886 | 0 | if (char_is_num(*cur)) { |
6887 | 0 | val_incr(); |
6888 | 0 | ctn_len++; |
6889 | 0 | if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_maybe_end; |
6890 | 0 | goto fail_number; |
6891 | 0 | } |
6892 | 0 | if (*cur == '"') { |
6893 | 0 | val_incr(); |
6894 | 0 | ctn_len++; |
6895 | 0 | if (likely(read_str_con(&cur, end, flg, val, &msg, con))) |
6896 | 0 | goto arr_val_end; |
6897 | 0 | goto fail_string; |
6898 | 0 | } |
6899 | 0 | if (*cur == 't') { |
6900 | 0 | val_incr(); |
6901 | 0 | ctn_len++; |
6902 | 0 | if (likely(read_true(&cur, val))) goto arr_val_end; |
6903 | 0 | goto fail_literal_true; |
6904 | 0 | } |
6905 | 0 | if (*cur == 'f') { |
6906 | 0 | val_incr(); |
6907 | 0 | ctn_len++; |
6908 | 0 | if (likely(read_false(&cur, val))) goto arr_val_end; |
6909 | 0 | goto fail_literal_false; |
6910 | 0 | } |
6911 | 0 | if (*cur == 'n') { |
6912 | 0 | val_incr(); |
6913 | 0 | ctn_len++; |
6914 | 0 | if (likely(read_null(&cur, val))) goto arr_val_end; |
6915 | 0 | goto fail_literal_null; |
6916 | 0 | } |
6917 | 0 | if (*cur == ']') { |
6918 | 0 | cur++; |
6919 | 0 | if (likely(ctn_len == 0)) goto arr_end; |
6920 | 0 | do { cur--; } while (*cur != ','); |
6921 | 0 | goto fail_trailing_comma; |
6922 | 0 | } |
6923 | 0 | if (char_is_space(*cur)) { |
6924 | 0 | while (char_is_space(*++cur)); |
6925 | 0 | goto arr_val_continue; |
6926 | 0 | } |
6927 | 0 | goto fail_character_val; |
6928 | | |
6929 | 0 | arr_val_maybe_end: |
6930 | | /* if incremental parsing stops in the middle of a number, it may continue |
6931 | | with more digits, so arr val maybe didn't end yet */ |
6932 | 0 | check_maybe_truncated_number(); |
6933 | | |
6934 | 0 | arr_val_end: |
6935 | 0 | save_incr_state(arr_val_end); |
6936 | 0 | if (*cur == ',') { |
6937 | 0 | cur++; |
6938 | 0 | goto arr_val_begin; |
6939 | 0 | } |
6940 | 0 | if (*cur == ']') { |
6941 | 0 | cur++; |
6942 | 0 | goto arr_end; |
6943 | 0 | } |
6944 | 0 | if (char_is_space(*cur)) { |
6945 | 0 | while (char_is_space(*++cur)); |
6946 | 0 | goto arr_val_end; |
6947 | 0 | } |
6948 | 0 | goto fail_character_arr_end; |
6949 | | |
6950 | 0 | arr_end: |
6951 | | #if YYJSON_READER_DEPTH_LIMIT |
6952 | | container_depth--; |
6953 | | #endif |
6954 | | /* get parent container */ |
6955 | 0 | ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs); |
6956 | | |
6957 | | /* save the next sibling value offset */ |
6958 | 0 | ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val); |
6959 | 0 | ctn->tag = ((ctn_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR; |
6960 | 0 | if (unlikely(ctn == ctn_parent)) goto doc_end; |
6961 | | |
6962 | | /* pop parent as current container */ |
6963 | 0 | ctn = ctn_parent; |
6964 | 0 | ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT); |
6965 | 0 | if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) { |
6966 | 0 | goto obj_val_end; |
6967 | 0 | } else { |
6968 | 0 | goto arr_val_end; |
6969 | 0 | } |
6970 | | |
6971 | 0 | obj_begin: |
6972 | | #if YYJSON_READER_DEPTH_LIMIT |
6973 | | container_depth++; |
6974 | | if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) { |
6975 | | goto fail_depth; |
6976 | | } |
6977 | | #endif |
6978 | | |
6979 | | /* push container */ |
6980 | 0 | ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) | |
6981 | 0 | (ctn->tag & YYJSON_TAG_MASK); |
6982 | 0 | val_incr(); |
6983 | 0 | val->tag = YYJSON_TYPE_OBJ; |
6984 | | /* offset to the parent */ |
6985 | 0 | val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn); |
6986 | 0 | ctn = val; |
6987 | 0 | ctn_len = 0; |
6988 | |
|
6989 | 0 | obj_key_begin: |
6990 | 0 | save_incr_state(obj_key_begin); |
6991 | 0 | obj_key_continue: |
6992 | 0 | if (likely(*cur == '"')) { |
6993 | 0 | val_incr(); |
6994 | 0 | ctn_len++; |
6995 | 0 | if (likely(read_str_con(&cur, end, flg, val, &msg, con))) |
6996 | 0 | goto obj_key_end; |
6997 | 0 | goto fail_string; |
6998 | 0 | } |
6999 | 0 | if (likely(*cur == '}')) { |
7000 | 0 | cur++; |
7001 | 0 | if (likely(ctn_len == 0)) goto obj_end; |
7002 | 0 | do { cur--; } while (*cur != ','); |
7003 | 0 | goto fail_trailing_comma; |
7004 | 0 | } |
7005 | 0 | if (char_is_space(*cur)) { |
7006 | 0 | while (char_is_space(*++cur)); |
7007 | 0 | goto obj_key_continue; |
7008 | 0 | } |
7009 | 0 | goto fail_character_obj_key; |
7010 | | |
7011 | 0 | obj_key_end: |
7012 | 0 | save_incr_state(obj_key_end); |
7013 | 0 | if (*cur == ':') { |
7014 | 0 | cur++; |
7015 | 0 | goto obj_val_begin; |
7016 | 0 | } |
7017 | 0 | if (char_is_space(*cur)) { |
7018 | 0 | while (char_is_space(*++cur)); |
7019 | 0 | goto obj_key_end; |
7020 | 0 | } |
7021 | 0 | goto fail_character_obj_sep; |
7022 | | |
7023 | 0 | obj_val_begin: |
7024 | 0 | save_incr_state(obj_val_begin); |
7025 | 0 | obj_val_continue: |
7026 | 0 | if (*cur == '"') { |
7027 | 0 | val++; |
7028 | 0 | ctn_len++; |
7029 | 0 | if (likely(read_str_con(&cur, end, flg, val, &msg, con))) |
7030 | 0 | goto obj_val_end; |
7031 | 0 | goto fail_string; |
7032 | 0 | } |
7033 | 0 | if (char_is_num(*cur)) { |
7034 | 0 | val++; |
7035 | 0 | ctn_len++; |
7036 | 0 | if (likely(read_num(&cur, pre, flg, val, &msg))) goto obj_val_maybe_end; |
7037 | 0 | goto fail_number; |
7038 | 0 | } |
7039 | 0 | if (*cur == '{') { |
7040 | 0 | cur++; |
7041 | 0 | goto obj_begin; |
7042 | 0 | } |
7043 | 0 | if (*cur == '[') { |
7044 | 0 | cur++; |
7045 | 0 | goto arr_begin; |
7046 | 0 | } |
7047 | 0 | if (*cur == 't') { |
7048 | 0 | val++; |
7049 | 0 | ctn_len++; |
7050 | 0 | if (likely(read_true(&cur, val))) goto obj_val_end; |
7051 | 0 | goto fail_literal_true; |
7052 | 0 | } |
7053 | 0 | if (*cur == 'f') { |
7054 | 0 | val++; |
7055 | 0 | ctn_len++; |
7056 | 0 | if (likely(read_false(&cur, val))) goto obj_val_end; |
7057 | 0 | goto fail_literal_false; |
7058 | 0 | } |
7059 | 0 | if (*cur == 'n') { |
7060 | 0 | val++; |
7061 | 0 | ctn_len++; |
7062 | 0 | if (likely(read_null(&cur, val))) goto obj_val_end; |
7063 | 0 | goto fail_literal_null; |
7064 | 0 | } |
7065 | 0 | if (char_is_space(*cur)) { |
7066 | 0 | while (char_is_space(*++cur)); |
7067 | 0 | goto obj_val_continue; |
7068 | 0 | } |
7069 | 0 | goto fail_character_val; |
7070 | | |
7071 | 0 | obj_val_maybe_end: |
7072 | | /* if incremental parsing stops in the middle of a number, it may continue |
7073 | | with more digits, so obj val maybe didn't end yet */ |
7074 | 0 | check_maybe_truncated_number(); |
7075 | | |
7076 | 0 | obj_val_end: |
7077 | 0 | save_incr_state(obj_val_end); |
7078 | 0 | if (likely(*cur == ',')) { |
7079 | 0 | cur++; |
7080 | 0 | goto obj_key_begin; |
7081 | 0 | } |
7082 | 0 | if (likely(*cur == '}')) { |
7083 | 0 | cur++; |
7084 | 0 | goto obj_end; |
7085 | 0 | } |
7086 | 0 | if (char_is_space(*cur)) { |
7087 | 0 | while (char_is_space(*++cur)); |
7088 | 0 | goto obj_val_end; |
7089 | 0 | } |
7090 | 0 | goto fail_character_obj_end; |
7091 | | |
7092 | 0 | obj_end: |
7093 | | #if YYJSON_READER_DEPTH_LIMIT |
7094 | | container_depth--; |
7095 | | #endif |
7096 | | |
7097 | | /* pop container */ |
7098 | 0 | ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs); |
7099 | | /* point to the next value */ |
7100 | 0 | ctn->uni.ofs = (usize)((u8 *)val - (u8 *)ctn) + sizeof(yyjson_val); |
7101 | 0 | ctn->tag = (ctn_len << (YYJSON_TAG_BIT - 1)) | YYJSON_TYPE_OBJ; |
7102 | 0 | if (unlikely(ctn == ctn_parent)) goto doc_end; |
7103 | 0 | ctn = ctn_parent; |
7104 | 0 | ctn_len = (usize)(ctn->tag >> YYJSON_TAG_BIT); |
7105 | 0 | if ((ctn->tag & YYJSON_TYPE_MASK) == YYJSON_TYPE_OBJ) { |
7106 | 0 | goto obj_val_end; |
7107 | 0 | } else { |
7108 | 0 | goto arr_val_end; |
7109 | 0 | } |
7110 | | |
7111 | 0 | doc_end: |
7112 | | /* check invalid contents after json document */ |
7113 | 0 | if (unlikely(cur < end || len < state->buf_len) && |
7114 | 0 | !has_flg(STOP_WHEN_DONE)) { |
7115 | 0 | save_incr_state(doc_end); |
7116 | 0 | while (char_is_space(*cur)) cur++; |
7117 | 0 | if (unlikely(cur < end)) goto fail_garbage; |
7118 | | /* the document is complete for the bytes seen so far, but more input |
7119 | | is still pending; it may hold trailing content that has to be |
7120 | | rejected, so request the remaining data before finalizing */ |
7121 | 0 | if (unlikely(len < state->buf_len)) goto unexpected_end; |
7122 | 0 | } |
7123 | | |
7124 | 0 | **pre = '\0'; |
7125 | 0 | doc = (yyjson_doc *)val_hdr; |
7126 | 0 | doc->root = val_hdr + hdr_len; |
7127 | 0 | doc->alc = alc; |
7128 | 0 | doc->dat_read = (usize)(cur - hdr); |
7129 | 0 | doc->val_read = (usize)((val - doc->root) + 1); |
7130 | 0 | doc->str_pool = has_flg(INSITU) ? NULL : (char *)hdr; |
7131 | 0 | state->hdr = NULL; |
7132 | 0 | state->val_hdr = NULL; |
7133 | 0 | memset(err, 0, sizeof(yyjson_read_err)); |
7134 | 0 | return doc; |
7135 | | |
7136 | 0 | unexpected_end: |
7137 | 0 | err->pos = len; |
7138 | | /* if no more data, stop the incr read */ |
7139 | 0 | if (unlikely(len >= state->buf_len)) { |
7140 | 0 | err->code = YYJSON_READ_ERROR_UNEXPECTED_END; |
7141 | 0 | err->msg = MSG_NOT_END; |
7142 | 0 | return NULL; |
7143 | 0 | } |
7144 | | /* save parser state in extended error struct, in addition to what was |
7145 | | * stored in the last save_incr_state */ |
7146 | 0 | err->code = YYJSON_READ_ERROR_MORE; |
7147 | 0 | err->msg = "need more data"; |
7148 | 0 | state->val_end = val_end; |
7149 | 0 | state->ctn = ctn; |
7150 | 0 | state->alc_len = alc_len; |
7151 | | /* restore the end where we've inserted a null terminator */ |
7152 | 0 | *end = saved_end; |
7153 | 0 | return NULL; |
7154 | | |
7155 | 0 | fail_string: return_err(cur, INVALID_STRING, msg); |
7156 | 0 | fail_number: return_err(cur, INVALID_NUMBER, msg); |
7157 | 0 | fail_alloc: return_err(cur, MEMORY_ALLOCATION, MSG_MALLOC); |
7158 | 0 | fail_trailing_comma: return_err(cur, JSON_STRUCTURE, MSG_COMMA); |
7159 | 0 | fail_literal_true: return_err(cur, LITERAL, MSG_CHAR_T); |
7160 | 0 | fail_literal_false: return_err(cur, LITERAL, MSG_CHAR_F); |
7161 | 0 | fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N); |
7162 | 0 | fail_character_val: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR); |
7163 | 0 | fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END); |
7164 | 0 | fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY); |
7165 | 0 | fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP); |
7166 | 0 | fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END); |
7167 | 0 | fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE); |
7168 | 0 | fail_depth: return_err(cur, DEPTH, MSG_DEPTH); |
7169 | |
|
7170 | 0 | #undef val_incr |
7171 | 0 | #undef return_err |
7172 | 0 | #undef return_err_inv_param |
7173 | 0 | #undef save_incr_state |
7174 | 0 | #undef save_incr_depth |
7175 | 0 | #undef check_maybe_truncated_number |
7176 | 0 | } |
7177 | | |
7178 | | #endif /* YYJSON_DISABLE_INCR_READER */ |
7179 | | |
7180 | | #undef has_flg |
7181 | | #undef has_allow |
7182 | | #endif /* YYJSON_DISABLE_READER */ |
7183 | | |
7184 | | |
7185 | | |
7186 | | #if !YYJSON_DISABLE_WRITER /* writer begin */ |
7187 | | |
7188 | | /* Check write flag, avoids `always false` warning when disabled. */ |
7189 | 199k | #define has_flg(_flg) unlikely(has_wflag(flg, YYJSON_WRITE_##_flg, 0)) |
7190 | 40.8k | #define has_allow(_flg) unlikely(has_wflag(flg, YYJSON_WRITE_ALLOW_##_flg, 1)) |
7191 | | static_inline bool has_wflag(yyjson_write_flag flg, yyjson_write_flag chk, |
7192 | 240k | bool non_standard) { |
7193 | | #if YYJSON_DISABLE_NON_STANDARD |
7194 | | if (non_standard) return false; |
7195 | | #endif |
7196 | 240k | return (flg & chk) != 0; |
7197 | 240k | } |
7198 | | |
7199 | | /*============================================================================== |
7200 | | * MARK: - Integer Writer (Private) |
7201 | | * |
7202 | | * The maximum value of uint32_t is 4294967295 (10 digits), |
7203 | | * these digits are named as 'aabbccddee' here. |
7204 | | * |
7205 | | * Although most compilers may convert the "division by constant value" into |
7206 | | * "multiply and shift", manual conversion can still help some compilers |
7207 | | * generate fewer and better instructions. |
7208 | | * |
7209 | | * Reference: |
7210 | | * Division by Invariant Integers using Multiplication, 1994. |
7211 | | * https://gmplib.org/~tege/divcnst-pldi94.pdf |
7212 | | * Improved division by invariant integers, 2011. |
7213 | | * https://gmplib.org/~tege/division-paper.pdf |
7214 | | *============================================================================*/ |
7215 | | |
7216 | | /** Digit table from 00 to 99. */ |
7217 | | yyjson_align(2) |
7218 | | static const char digit_table[200] = { |
7219 | | '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', |
7220 | | '0', '5', '0', '6', '0', '7', '0', '8', '0', '9', |
7221 | | '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', |
7222 | | '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', |
7223 | | '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', |
7224 | | '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', |
7225 | | '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', |
7226 | | '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', |
7227 | | '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', |
7228 | | '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', |
7229 | | '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', |
7230 | | '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', |
7231 | | '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', |
7232 | | '6', '5', '6', '6', '6', '7', '6', '8', '6', '9', |
7233 | | '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', |
7234 | | '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', |
7235 | | '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', |
7236 | | '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', |
7237 | | '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', |
7238 | | '9', '5', '9', '6', '9', '7', '9', '8', '9', '9' |
7239 | | }; |
7240 | | |
7241 | 2.09M | static_inline u8 *write_u32_len_8(u32 val, u8 *buf) { |
7242 | 2.09M | u32 aa, bb, cc, dd, aabb, ccdd; /* 8 digits: aabbccdd */ |
7243 | 2.09M | aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */ |
7244 | 2.09M | ccdd = val - aabb * 10000; /* (val % 10000) */ |
7245 | 2.09M | aa = (aabb * 5243) >> 19; /* (aabb / 100) */ |
7246 | 2.09M | cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */ |
7247 | 2.09M | bb = aabb - aa * 100; /* (aabb % 100) */ |
7248 | 2.09M | dd = ccdd - cc * 100; /* (ccdd % 100) */ |
7249 | 2.09M | byte_copy_2(buf + 0, digit_table + aa * 2); |
7250 | 2.09M | byte_copy_2(buf + 2, digit_table + bb * 2); |
7251 | 2.09M | byte_copy_2(buf + 4, digit_table + cc * 2); |
7252 | 2.09M | byte_copy_2(buf + 6, digit_table + dd * 2); |
7253 | 2.09M | return buf + 8; |
7254 | 2.09M | } |
7255 | | |
7256 | 153k | static_inline u8 *write_u32_len_4(u32 val, u8 *buf) { |
7257 | 153k | u32 aa, bb; /* 4 digits: aabb */ |
7258 | 153k | aa = (val * 5243) >> 19; /* (val / 100) */ |
7259 | 153k | bb = val - aa * 100; /* (val % 100) */ |
7260 | 153k | byte_copy_2(buf + 0, digit_table + aa * 2); |
7261 | 153k | byte_copy_2(buf + 2, digit_table + bb * 2); |
7262 | 153k | return buf + 4; |
7263 | 153k | } |
7264 | | |
7265 | 84.6M | static_inline u8 *write_u32_len_1_to_8(u32 val, u8 *buf) { |
7266 | 84.6M | u32 aa, bb, cc, dd, aabb, bbcc, ccdd, lz; |
7267 | | |
7268 | 84.6M | if (val < 100) { /* 1-2 digits: aa */ |
7269 | 76.7M | lz = val < 10; /* leading zero: 0 or 1 */ |
7270 | 76.7M | byte_copy_2(buf + 0, digit_table + val * 2 + lz); |
7271 | 76.7M | buf -= lz; |
7272 | 76.7M | return buf + 2; |
7273 | | |
7274 | 76.7M | } else if (val < 10000) { /* 3-4 digits: aabb */ |
7275 | 4.07M | aa = (val * 5243) >> 19; /* (val / 100) */ |
7276 | 4.07M | bb = val - aa * 100; /* (val % 100) */ |
7277 | 4.07M | lz = aa < 10; /* leading zero: 0 or 1 */ |
7278 | 4.07M | byte_copy_2(buf + 0, digit_table + aa * 2 + lz); |
7279 | 4.07M | buf -= lz; |
7280 | 4.07M | byte_copy_2(buf + 2, digit_table + bb * 2); |
7281 | 4.07M | return buf + 4; |
7282 | | |
7283 | 4.07M | } else if (val < 1000000) { /* 5-6 digits: aabbcc */ |
7284 | 3.20M | aa = (u32)(((u64)val * 429497) >> 32); /* (val / 10000) */ |
7285 | 3.20M | bbcc = val - aa * 10000; /* (val % 10000) */ |
7286 | 3.20M | bb = (bbcc * 5243) >> 19; /* (bbcc / 100) */ |
7287 | 3.20M | cc = bbcc - bb * 100; /* (bbcc % 100) */ |
7288 | 3.20M | lz = aa < 10; /* leading zero: 0 or 1 */ |
7289 | 3.20M | byte_copy_2(buf + 0, digit_table + aa * 2 + lz); |
7290 | 3.20M | buf -= lz; |
7291 | 3.20M | byte_copy_2(buf + 2, digit_table + bb * 2); |
7292 | 3.20M | byte_copy_2(buf + 4, digit_table + cc * 2); |
7293 | 3.20M | return buf + 6; |
7294 | | |
7295 | 3.20M | } else { /* 7-8 digits: aabbccdd */ |
7296 | 615k | aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */ |
7297 | 615k | ccdd = val - aabb * 10000; /* (val % 10000) */ |
7298 | 615k | aa = (aabb * 5243) >> 19; /* (aabb / 100) */ |
7299 | 615k | cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */ |
7300 | 615k | bb = aabb - aa * 100; /* (aabb % 100) */ |
7301 | 615k | dd = ccdd - cc * 100; /* (ccdd % 100) */ |
7302 | 615k | lz = aa < 10; /* leading zero: 0 or 1 */ |
7303 | 615k | byte_copy_2(buf + 0, digit_table + aa * 2 + lz); |
7304 | 615k | buf -= lz; |
7305 | 615k | byte_copy_2(buf + 2, digit_table + bb * 2); |
7306 | 615k | byte_copy_2(buf + 4, digit_table + cc * 2); |
7307 | 615k | byte_copy_2(buf + 6, digit_table + dd * 2); |
7308 | 615k | return buf + 8; |
7309 | 615k | } |
7310 | 84.6M | } |
7311 | | |
7312 | 153k | static_inline u8 *write_u32_len_5_to_8(u32 val, u8 *buf) { |
7313 | 153k | u32 aa, bb, cc, dd, aabb, bbcc, ccdd, lz; |
7314 | | |
7315 | 153k | if (val < 1000000) { /* 5-6 digits: aabbcc */ |
7316 | 131k | aa = (u32)(((u64)val * 429497) >> 32); /* (val / 10000) */ |
7317 | 131k | bbcc = val - aa * 10000; /* (val % 10000) */ |
7318 | 131k | bb = (bbcc * 5243) >> 19; /* (bbcc / 100) */ |
7319 | 131k | cc = bbcc - bb * 100; /* (bbcc % 100) */ |
7320 | 131k | lz = aa < 10; /* leading zero: 0 or 1 */ |
7321 | 131k | byte_copy_2(buf + 0, digit_table + aa * 2 + lz); |
7322 | 131k | buf -= lz; |
7323 | 131k | byte_copy_2(buf + 2, digit_table + bb * 2); |
7324 | 131k | byte_copy_2(buf + 4, digit_table + cc * 2); |
7325 | 131k | return buf + 6; |
7326 | | |
7327 | 131k | } else { /* 7-8 digits: aabbccdd */ |
7328 | 21.6k | aabb = (u32)(((u64)val * 109951163) >> 40); /* (val / 10000) */ |
7329 | 21.6k | ccdd = val - aabb * 10000; /* (val % 10000) */ |
7330 | 21.6k | aa = (aabb * 5243) >> 19; /* (aabb / 100) */ |
7331 | 21.6k | cc = (ccdd * 5243) >> 19; /* (ccdd / 100) */ |
7332 | 21.6k | bb = aabb - aa * 100; /* (aabb % 100) */ |
7333 | 21.6k | dd = ccdd - cc * 100; /* (ccdd % 100) */ |
7334 | 21.6k | lz = aa < 10; /* leading zero: 0 or 1 */ |
7335 | 21.6k | byte_copy_2(buf + 0, digit_table + aa * 2 + lz); |
7336 | 21.6k | buf -= lz; |
7337 | 21.6k | byte_copy_2(buf + 2, digit_table + bb * 2); |
7338 | 21.6k | byte_copy_2(buf + 4, digit_table + cc * 2); |
7339 | 21.6k | byte_copy_2(buf + 6, digit_table + dd * 2); |
7340 | 21.6k | return buf + 8; |
7341 | 21.6k | } |
7342 | 153k | } |
7343 | | |
7344 | 83.5M | static_inline u8 *write_u64(u64 val, u8 *buf) { |
7345 | 83.5M | u64 tmp, hgh; |
7346 | 83.5M | u32 mid, low; |
7347 | | |
7348 | 83.5M | if (val < 100000000) { /* 1-8 digits */ |
7349 | 81.7M | buf = write_u32_len_1_to_8((u32)val, buf); |
7350 | 81.7M | return buf; |
7351 | | |
7352 | 81.7M | } else if (val < (u64)100000000 * 100000000) { /* 9-16 digits */ |
7353 | 1.60M | hgh = val / 100000000; /* (val / 100000000) */ |
7354 | 1.60M | low = (u32)(val - hgh * 100000000); /* (val % 100000000) */ |
7355 | 1.60M | buf = write_u32_len_1_to_8((u32)hgh, buf); |
7356 | 1.60M | buf = write_u32_len_8(low, buf); |
7357 | 1.60M | return buf; |
7358 | | |
7359 | 1.60M | } else { /* 17-20 digits */ |
7360 | 153k | tmp = val / 100000000; /* (val / 100000000) */ |
7361 | 153k | low = (u32)(val - tmp * 100000000); /* (val % 100000000) */ |
7362 | 153k | hgh = (u32)(tmp / 10000); /* (tmp / 10000) */ |
7363 | 153k | mid = (u32)(tmp - hgh * 10000); /* (tmp % 10000) */ |
7364 | 153k | buf = write_u32_len_5_to_8((u32)hgh, buf); |
7365 | 153k | buf = write_u32_len_4(mid, buf); |
7366 | 153k | buf = write_u32_len_8(low, buf); |
7367 | 153k | return buf; |
7368 | 153k | } |
7369 | 83.5M | } |
7370 | | |
7371 | | |
7372 | | |
7373 | | /*============================================================================== |
7374 | | * MARK: - Number Writer (Private) |
7375 | | *============================================================================*/ |
7376 | | |
7377 | | #if !YYJSON_DISABLE_FAST_FP_CONV /* FP_WRITER */ |
7378 | | |
7379 | | /** Trailing zero count table for number 0 to 99. |
7380 | | (generated with misc/make_tables.c) */ |
7381 | | static const u8 dec_trailing_zero_table[] = { |
7382 | | 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
7383 | | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
7384 | | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
7385 | | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
7386 | | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
7387 | | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
7388 | | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
7389 | | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
7390 | | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
7391 | | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
7392 | | }; |
7393 | | |
7394 | 588k | static_inline u8 *write_u64_len_1_to_16(u64 val, u8 *buf) { |
7395 | 588k | u64 hgh; |
7396 | 588k | u32 low; |
7397 | 588k | if (val < 100000000) { /* 1-8 digits */ |
7398 | 470k | buf = write_u32_len_1_to_8((u32)val, buf); |
7399 | 470k | return buf; |
7400 | 470k | } else { /* 9-16 digits */ |
7401 | 118k | hgh = val / 100000000; /* (val / 100000000) */ |
7402 | 118k | low = (u32)(val - hgh * 100000000); /* (val % 100000000) */ |
7403 | 118k | buf = write_u32_len_1_to_8((u32)hgh, buf); |
7404 | 118k | buf = write_u32_len_8(low, buf); |
7405 | 118k | return buf; |
7406 | 118k | } |
7407 | 588k | } |
7408 | | |
7409 | 710k | static_inline u8 *write_u64_len_1_to_17(u64 val, u8 *buf) { |
7410 | 710k | u64 hgh; |
7411 | 710k | u32 mid, low, one; |
7412 | 710k | if (val >= (u64)100000000 * 10000000) { /* len: 16 to 17 */ |
7413 | 5.38k | hgh = val / 100000000; /* (val / 100000000) */ |
7414 | 5.38k | low = (u32)(val - hgh * 100000000); /* (val % 100000000) */ |
7415 | 5.38k | one = (u32)(hgh / 100000000); /* (hgh / 100000000) */ |
7416 | 5.38k | mid = (u32)(hgh - (u64)one * 100000000); /* (hgh % 100000000) */ |
7417 | 5.38k | *buf = (u8)((u8)one + (u8)'0'); |
7418 | 5.38k | buf += one > 0; |
7419 | 5.38k | buf = write_u32_len_8(mid, buf); |
7420 | 5.38k | buf = write_u32_len_8(low, buf); |
7421 | 5.38k | return buf; |
7422 | 704k | } else if (val >= (u64)100000000){ /* len: 9 to 15 */ |
7423 | 206k | hgh = val / 100000000; /* (val / 100000000) */ |
7424 | 206k | low = (u32)(val - hgh * 100000000); /* (val % 100000000) */ |
7425 | 206k | buf = write_u32_len_1_to_8((u32)hgh, buf); |
7426 | 206k | buf = write_u32_len_8(low, buf); |
7427 | 206k | return buf; |
7428 | 498k | } else { /* len: 1 to 8 */ |
7429 | 498k | buf = write_u32_len_1_to_8((u32)val, buf); |
7430 | 498k | return buf; |
7431 | 498k | } |
7432 | 710k | } |
7433 | | |
7434 | | /** |
7435 | | Write an unsigned integer with a length of 7 to 9 with trailing zero trimmed. |
7436 | | These digits are named as "abbccddee" here. |
7437 | | For example, input 123456000, output "123456". |
7438 | | */ |
7439 | 0 | static_inline u8 *write_u32_len_7_to_9_trim(u32 val, u8 *buf) { |
7440 | 0 | bool lz; |
7441 | 0 | u32 tz, tz1, tz2; |
7442 | |
|
7443 | 0 | u32 abbcc = val / 10000; /* (abbccddee / 10000) */ |
7444 | 0 | u32 ddee = val - abbcc * 10000; /* (abbccddee % 10000) */ |
7445 | 0 | u32 abb = (u32)(((u64)abbcc * 167773) >> 24); /* (abbcc / 100) */ |
7446 | 0 | u32 a = (abb * 41) >> 12; /* (abb / 100) */ |
7447 | 0 | u32 bb = abb - a * 100; /* (abb % 100) */ |
7448 | 0 | u32 cc = abbcc - abb * 100; /* (abbcc % 100) */ |
7449 | | |
7450 | | /* write abbcc */ |
7451 | 0 | buf[0] = (u8)(a + '0'); |
7452 | 0 | buf += a > 0; |
7453 | 0 | lz = bb < 10 && a == 0; |
7454 | 0 | byte_copy_2(buf + 0, digit_table + bb * 2 + lz); |
7455 | 0 | buf -= lz; |
7456 | 0 | byte_copy_2(buf + 2, digit_table + cc * 2); |
7457 | |
|
7458 | 0 | if (ddee) { |
7459 | 0 | u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */ |
7460 | 0 | u32 ee = ddee - dd * 100; /* (ddee % 100) */ |
7461 | 0 | byte_copy_2(buf + 4, digit_table + dd * 2); |
7462 | 0 | byte_copy_2(buf + 6, digit_table + ee * 2); |
7463 | 0 | tz1 = dec_trailing_zero_table[dd]; |
7464 | 0 | tz2 = dec_trailing_zero_table[ee]; |
7465 | 0 | tz = ee ? tz2 : (tz1 + 2); |
7466 | 0 | buf += 8 - tz; |
7467 | 0 | return buf; |
7468 | 0 | } else { |
7469 | 0 | tz1 = dec_trailing_zero_table[bb]; |
7470 | 0 | tz2 = dec_trailing_zero_table[cc]; |
7471 | 0 | tz = cc ? tz2 : (tz1 + tz2); |
7472 | 0 | buf += 4 - tz; |
7473 | 0 | return buf; |
7474 | 0 | } |
7475 | 0 | } |
7476 | | |
7477 | | /** |
7478 | | Write an unsigned integer with a length of 16 or 17 with trailing zero trimmed. |
7479 | | These digits are named as "abbccddeeffgghhii" here. |
7480 | | For example, input 1234567890123000, output "1234567890123". |
7481 | | */ |
7482 | 3.08M | static_inline u8 *write_u64_len_16_to_17_trim(u64 val, u8 *buf) { |
7483 | 3.08M | u32 tz, tz1, tz2; |
7484 | | |
7485 | 3.08M | u32 abbccddee = (u32)(val / 100000000); |
7486 | 3.08M | u32 ffgghhii = (u32)(val - (u64)abbccddee * 100000000); |
7487 | 3.08M | u32 abbcc = abbccddee / 10000; |
7488 | 3.08M | u32 ddee = abbccddee - abbcc * 10000; |
7489 | 3.08M | u32 abb = (u32)(((u64)abbcc * 167773) >> 24); /* (abbcc / 100) */ |
7490 | 3.08M | u32 a = (abb * 41) >> 12; /* (abb / 100) */ |
7491 | 3.08M | u32 bb = abb - a * 100; /* (abb % 100) */ |
7492 | 3.08M | u32 cc = abbcc - abb * 100; /* (abbcc % 100) */ |
7493 | 3.08M | buf[0] = (u8)(a + '0'); |
7494 | 3.08M | buf += a > 0; |
7495 | 3.08M | byte_copy_2(buf + 0, digit_table + bb * 2); |
7496 | 3.08M | byte_copy_2(buf + 2, digit_table + cc * 2); |
7497 | | |
7498 | 3.08M | if (ffgghhii) { |
7499 | 1.28M | u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */ |
7500 | 1.28M | u32 ee = ddee - dd * 100; /* (ddee % 100) */ |
7501 | 1.28M | u32 ffgg = (u32)(((u64)ffgghhii * 109951163) >> 40); /* (val / 10000) */ |
7502 | 1.28M | u32 hhii = ffgghhii - ffgg * 10000; /* (val % 10000) */ |
7503 | 1.28M | u32 ff = (ffgg * 5243) >> 19; /* (aabb / 100) */ |
7504 | 1.28M | u32 gg = ffgg - ff * 100; /* (aabb % 100) */ |
7505 | 1.28M | byte_copy_2(buf + 4, digit_table + dd * 2); |
7506 | 1.28M | byte_copy_2(buf + 6, digit_table + ee * 2); |
7507 | 1.28M | byte_copy_2(buf + 8, digit_table + ff * 2); |
7508 | 1.28M | byte_copy_2(buf + 10, digit_table + gg * 2); |
7509 | 1.28M | if (hhii) { |
7510 | 821k | u32 hh = (hhii * 5243) >> 19; /* (ccdd / 100) */ |
7511 | 821k | u32 ii = hhii - hh * 100; /* (ccdd % 100) */ |
7512 | 821k | byte_copy_2(buf + 12, digit_table + hh * 2); |
7513 | 821k | byte_copy_2(buf + 14, digit_table + ii * 2); |
7514 | 821k | tz1 = dec_trailing_zero_table[hh]; |
7515 | 821k | tz2 = dec_trailing_zero_table[ii]; |
7516 | 821k | tz = ii ? tz2 : (tz1 + 2); |
7517 | 821k | return buf + 16 - tz; |
7518 | 821k | } else { |
7519 | 459k | tz1 = dec_trailing_zero_table[ff]; |
7520 | 459k | tz2 = dec_trailing_zero_table[gg]; |
7521 | 459k | tz = gg ? tz2 : (tz1 + 2); |
7522 | 459k | return buf + 12 - tz; |
7523 | 459k | } |
7524 | 1.80M | } else { |
7525 | 1.80M | if (ddee) { |
7526 | 891k | u32 dd = (ddee * 5243) >> 19; /* (ddee / 100) */ |
7527 | 891k | u32 ee = ddee - dd * 100; /* (ddee % 100) */ |
7528 | 891k | byte_copy_2(buf + 4, digit_table + dd * 2); |
7529 | 891k | byte_copy_2(buf + 6, digit_table + ee * 2); |
7530 | 891k | tz1 = dec_trailing_zero_table[dd]; |
7531 | 891k | tz2 = dec_trailing_zero_table[ee]; |
7532 | 891k | tz = ee ? tz2 : (tz1 + 2); |
7533 | 891k | return buf + 8 - tz; |
7534 | 914k | } else { |
7535 | 914k | tz1 = dec_trailing_zero_table[bb]; |
7536 | 914k | tz2 = dec_trailing_zero_table[cc]; |
7537 | 914k | tz = cc ? tz2 : (tz1 + tz2); |
7538 | 914k | return buf + 4 - tz; |
7539 | 914k | } |
7540 | 1.80M | } |
7541 | 3.08M | } |
7542 | | |
7543 | | /** Write exponent part in range `e-45` to `e38`. */ |
7544 | 0 | static_inline u8 *write_f32_exp(i32 exp, u8 *buf) { |
7545 | 0 | bool lz; |
7546 | 0 | byte_copy_2(buf, "e-"); |
7547 | 0 | buf += 2 - (exp >= 0); |
7548 | 0 | exp = exp < 0 ? -exp : exp; |
7549 | 0 | lz = exp < 10; |
7550 | 0 | byte_copy_2(buf + 0, digit_table + (u32)exp * 2 + lz); |
7551 | 0 | return buf + 2 - lz; |
7552 | 0 | } |
7553 | | |
7554 | | /** Write exponent part in range `e-324` to `e308`. */ |
7555 | 1.97M | static_inline u8 *write_f64_exp(i32 exp, u8 *buf) { |
7556 | 1.97M | byte_copy_2(buf, "e-"); |
7557 | 1.97M | buf += 2 - (exp >= 0); |
7558 | 1.97M | exp = exp < 0 ? -exp : exp; |
7559 | 1.97M | if (exp < 100) { |
7560 | 1.20M | bool lz = exp < 10; |
7561 | 1.20M | byte_copy_2(buf + 0, digit_table + (u32)exp * 2 + lz); |
7562 | 1.20M | return buf + 2 - lz; |
7563 | 1.20M | } else { |
7564 | 763k | u32 hi = ((u32)exp * 656) >> 16; /* exp / 100 */ |
7565 | 763k | u32 lo = (u32)exp - hi * 100; /* exp % 100 */ |
7566 | 763k | buf[0] = (u8)((u8)hi + (u8)'0'); |
7567 | 763k | byte_copy_2(buf + 1, digit_table + lo * 2); |
7568 | 763k | return buf + 3; |
7569 | 763k | } |
7570 | 1.97M | } |
7571 | | |
7572 | | /** Magic number for fast `divide by power of 10`. */ |
7573 | | typedef struct { |
7574 | | u64 p10, mul; |
7575 | | u32 shr1, shr2; |
7576 | | } div_pow10_magic; |
7577 | | |
7578 | | /** Generated with llvm, see https://github.com/llvm/llvm-project/ |
7579 | | blob/main/llvm/lib/Support/DivisionByConstantInfo.cpp */ |
7580 | | static const div_pow10_magic div_pow10_table[] = { |
7581 | | { U64(0x00000000, 0x00000001), U64(0x00000000, 0x00000000), 0, 0 }, |
7582 | | { U64(0x00000000, 0x0000000A), U64(0xCCCCCCCC, 0xCCCCCCCD), 0, 3 }, |
7583 | | { U64(0x00000000, 0x00000064), U64(0x28F5C28F, 0x5C28F5C3), 2, 2 }, |
7584 | | { U64(0x00000000, 0x000003E8), U64(0x20C49BA5, 0xE353F7CF), 3, 4 }, |
7585 | | { U64(0x00000000, 0x00002710), U64(0x346DC5D6, 0x3886594B), 0, 11 }, |
7586 | | { U64(0x00000000, 0x000186A0), U64(0x0A7C5AC4, 0x71B47843), 5, 7 }, |
7587 | | { U64(0x00000000, 0x000F4240), U64(0x431BDE82, 0xD7B634DB), 0, 18 }, |
7588 | | { U64(0x00000000, 0x00989680), U64(0xD6BF94D5, 0xE57A42BD), 0, 23 }, |
7589 | | { U64(0x00000000, 0x05F5E100), U64(0xABCC7711, 0x8461CEFD), 0, 26 }, |
7590 | | { U64(0x00000000, 0x3B9ACA00), U64(0x0044B82F, 0xA09B5A53), 9, 11 }, |
7591 | | { U64(0x00000002, 0x540BE400), U64(0xDBE6FECE, 0xBDEDD5BF), 0, 33 }, |
7592 | | { U64(0x00000017, 0x4876E800), U64(0xAFEBFF0B, 0xCB24AAFF), 0, 36 }, |
7593 | | { U64(0x000000E8, 0xD4A51000), U64(0x232F3302, 0x5BD42233), 0, 37 }, |
7594 | | { U64(0x00000918, 0x4E72A000), U64(0x384B84D0, 0x92ED0385), 0, 41 }, |
7595 | | { U64(0x00005AF3, 0x107A4000), U64(0x0B424DC3, 0x5095CD81), 0, 42 }, |
7596 | | { U64(0x00038D7E, 0xA4C68000), U64(0x00024075, 0xF3DCEAC3), 15, 20 }, |
7597 | | { U64(0x002386F2, 0x6FC10000), U64(0x39A5652F, 0xB1137857), 0, 51 }, |
7598 | | { U64(0x01634578, 0x5D8A0000), U64(0x00005C3B, 0xD5191B53), 17, 22 }, |
7599 | | { U64(0x0DE0B6B3, 0xA7640000), U64(0x000049C9, 0x7747490F), 18, 24 }, |
7600 | | { U64(0x8AC72304, 0x89E80000), U64(0x760F253E, 0xDB4AB0d3), 0, 62 }, |
7601 | | }; |
7602 | | |
7603 | | /** Divide a number by power of 10. */ |
7604 | 0 | static_inline void div_pow10(u64 num, u32 exp, u64 *div, u64 *mod, u64 *p10) { |
7605 | 0 | u64 hi, lo; |
7606 | 0 | div_pow10_magic m = div_pow10_table[exp]; |
7607 | 0 | u128_mul(num >> m.shr1, m.mul, &hi, &lo); |
7608 | 0 | *div = hi >> m.shr2; |
7609 | 0 | *mod = num - (*div * m.p10); |
7610 | 0 | *p10 = m.p10; |
7611 | 0 | } |
7612 | | |
7613 | | /** Multiplies 64-bit integer and returns highest 64-bit rounded value. */ |
7614 | 0 | static_inline u32 u64_round_to_odd(u64 u, u32 cp) { |
7615 | 0 | u64 hi, lo; |
7616 | 0 | u32 y_hi, y_lo; |
7617 | 0 | u128_mul(cp, u, &hi, &lo); |
7618 | 0 | y_hi = (u32)hi; |
7619 | 0 | y_lo = (u32)(lo >> 32); |
7620 | 0 | return y_hi | (y_lo > 1); |
7621 | 0 | } |
7622 | | |
7623 | | /** Multiplies 128-bit integer and returns highest 64-bit rounded value. */ |
7624 | 1.07M | static_inline u64 u128_round_to_odd(u64 hi, u64 lo, u64 cp) { |
7625 | 1.07M | u64 x_hi, x_lo, y_hi, y_lo; |
7626 | 1.07M | u128_mul(cp, lo, &x_hi, &x_lo); |
7627 | 1.07M | u128_mul_add(cp, hi, x_hi, &y_hi, &y_lo); |
7628 | 1.07M | return y_hi | (y_lo > 1); |
7629 | 1.07M | } |
7630 | | |
7631 | | /** Convert f32 from binary to decimal (shortest but may have trailing zeros). |
7632 | | The input should not be 0, inf or nan. */ |
7633 | | static_inline void f32_bin_to_dec(u32 sig_raw, u32 exp_raw, |
7634 | | u32 sig_bin, i32 exp_bin, |
7635 | 0 | u32 *sig_dec, i32 *exp_dec) { |
7636 | |
|
7637 | 0 | bool is_even, irregular, round_up, trim; |
7638 | 0 | bool u0_inside, u1_inside, w0_inside, w1_inside; |
7639 | 0 | u64 p10_hi, p10_lo, hi, lo; |
7640 | 0 | u32 s, sp, cb, cbl, cbr, vb, vbl, vbr, upper, lower, mid; |
7641 | 0 | i32 k, h; |
7642 | | |
7643 | | /* Fast path, see f64_bin_to_dec(). */ |
7644 | 0 | while (likely(sig_raw)) { |
7645 | 0 | u32 mod, dec, add_1, add_10, s_hi, s_lo; |
7646 | 0 | u32 c, half_ulp, t0, t1; |
7647 | | |
7648 | | /* k = floor(exp_bin * log10(2)); */ |
7649 | | /* h = exp_bin + floor(log2(10) * -k); (h = 0/1/2/3) */ |
7650 | 0 | k = (i32)(exp_bin * 315653) >> 20; |
7651 | 0 | h = exp_bin + ((-k * 217707) >> 16); |
7652 | 0 | pow10_table_get_sig(-k, &p10_hi, &p10_lo); |
7653 | | |
7654 | | /* sig_bin << (1/2/3/4) */ |
7655 | 0 | cb = sig_bin << (h + 1); |
7656 | 0 | u128_mul(cb, p10_hi, &hi, &lo); |
7657 | 0 | s_hi = (u32)(hi); |
7658 | 0 | s_lo = (u32)(lo >> 32); |
7659 | 0 | mod = s_hi % 10; |
7660 | 0 | dec = s_hi - mod; |
7661 | | |
7662 | | /* right shift 4 to fit in u32 */ |
7663 | 0 | c = (mod << (32 - 4)) | (s_lo >> 4); |
7664 | 0 | half_ulp = (u32)(p10_hi >> (32 + 4 - h)); |
7665 | | |
7666 | | /* check w1, u0, w0 range */ |
7667 | 0 | w1_inside = (s_lo >= ((u32)1 << 31)); |
7668 | 0 | if (unlikely(s_lo == ((u32)1 << 31))) break; |
7669 | 0 | u0_inside = (half_ulp >= c); |
7670 | 0 | if (unlikely(half_ulp == c)) break; |
7671 | 0 | t0 = (u32)10 << (32 - 4); |
7672 | 0 | t1 = c + half_ulp; |
7673 | 0 | w0_inside = (t1 >= t0); |
7674 | 0 | if (unlikely(t0 - t1 <= (u32)1)) break; |
7675 | | |
7676 | 0 | trim = (u0_inside | w0_inside); |
7677 | 0 | add_10 = (w0_inside ? 10 : 0); |
7678 | 0 | add_1 = mod + w1_inside; |
7679 | 0 | *sig_dec = dec + (trim ? add_10 : add_1); |
7680 | 0 | *exp_dec = k; |
7681 | 0 | return; |
7682 | 0 | } |
7683 | | |
7684 | | /* Schubfach algorithm, see f64_bin_to_dec(). */ |
7685 | 0 | irregular = (sig_raw == 0 && exp_raw > 1); |
7686 | 0 | is_even = !(sig_bin & 1); |
7687 | 0 | cbl = 4 * sig_bin - 2 + irregular; |
7688 | 0 | cb = 4 * sig_bin; |
7689 | 0 | cbr = 4 * sig_bin + 2; |
7690 | | |
7691 | | /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */ |
7692 | | /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */ |
7693 | 0 | k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20; |
7694 | 0 | h = exp_bin + ((-k * 217707) >> 16) + 1; |
7695 | 0 | pow10_table_get_sig(-k, &p10_hi, &p10_lo); |
7696 | 0 | p10_hi += 1; |
7697 | |
|
7698 | 0 | vbl = u64_round_to_odd(p10_hi, cbl << h); |
7699 | 0 | vb = u64_round_to_odd(p10_hi, cb << h); |
7700 | 0 | vbr = u64_round_to_odd(p10_hi, cbr << h); |
7701 | 0 | lower = vbl + !is_even; |
7702 | 0 | upper = vbr - !is_even; |
7703 | |
|
7704 | 0 | s = vb / 4; |
7705 | 0 | if (s >= 10) { |
7706 | 0 | sp = s / 10; |
7707 | 0 | u0_inside = (lower <= 40 * sp); |
7708 | 0 | w0_inside = (upper >= 40 * sp + 40); |
7709 | 0 | if (u0_inside != w0_inside) { |
7710 | 0 | *sig_dec = sp * 10 + (w0_inside ? 10 : 0); |
7711 | 0 | *exp_dec = k; |
7712 | 0 | return; |
7713 | 0 | } |
7714 | 0 | } |
7715 | 0 | u1_inside = (lower <= 4 * s); |
7716 | 0 | w1_inside = (upper >= 4 * s + 4); |
7717 | 0 | mid = 4 * s + 2; |
7718 | 0 | round_up = (vb > mid) || (vb == mid && (s & 1) != 0); |
7719 | 0 | *sig_dec = s + ((u1_inside != w1_inside) ? w1_inside : round_up); |
7720 | 0 | *exp_dec = k; |
7721 | 0 | } |
7722 | | |
7723 | | /** Convert f64 from binary to decimal (shortest but may have trailing zeros). |
7724 | | The input should not be 0, inf or nan. */ |
7725 | | static_inline void f64_bin_to_dec(u64 sig_raw, u32 exp_raw, |
7726 | | u64 sig_bin, i32 exp_bin, |
7727 | 3.79M | u64 *sig_dec, i32 *exp_dec) { |
7728 | | |
7729 | 3.79M | bool is_even, irregular, round_up, trim; |
7730 | 3.79M | bool u0_inside, u1_inside, w0_inside, w1_inside; |
7731 | 3.79M | u64 s, sp, cb, cbl, cbr, vb, vbl, vbr, p10_hi, p10_lo, upper, lower, mid; |
7732 | 3.79M | i32 k, h; |
7733 | | |
7734 | | /* |
7735 | | Fast path: |
7736 | | For regular spacing significand 'c', there are 4 candidates: |
7737 | | |
7738 | | u0 u1 c w1 w0 |
7739 | | ----|----|----|----|----|-*--|----|----|----|----|----|----|----|---- |
7740 | | 9 0 1 2 3 4 5 6 7 8 9 0 1 |
7741 | | |___________________|___________________| |
7742 | | 1ulp |
7743 | | |
7744 | | The `1ulp` is in the range [1.0, 10.0). |
7745 | | If (c - 0.5ulp < u0), trim the last digit and round down. |
7746 | | If (c + 0.5ulp > w0), trim the last digit and round up. |
7747 | | If (c - 0.5ulp < u1), round down. |
7748 | | If (c + 0.5ulp > w1), round up. |
7749 | | */ |
7750 | 3.79M | while (likely(sig_raw)) { |
7751 | 3.79M | u64 mod, dec, add_1, add_10, s_hi, s_lo; |
7752 | 3.79M | u64 c, half_ulp, t0, t1; |
7753 | | |
7754 | | /* k = floor(exp_bin * log10(2)); */ |
7755 | | /* h = exp_bin + floor(log2(10) * -k); (h = 0/1/2/3) */ |
7756 | 3.79M | k = (i32)(exp_bin * 315653) >> 20; |
7757 | 3.79M | h = exp_bin + ((-k * 217707) >> 16); |
7758 | 3.79M | pow10_table_get_sig(-k, &p10_hi, &p10_lo); |
7759 | | |
7760 | | /* sig_bin << (1/2/3/4) */ |
7761 | 3.79M | cb = sig_bin << (h + 1); |
7762 | 3.79M | u128_mul(cb, p10_lo, &s_hi, &s_lo); |
7763 | 3.79M | u128_mul_add(cb, p10_hi, s_hi, &s_hi, &s_lo); |
7764 | 3.79M | mod = s_hi % 10; |
7765 | 3.79M | dec = s_hi - mod; |
7766 | | |
7767 | | /* right shift 4 to fit in u64 */ |
7768 | 3.79M | c = (mod << (64 - 4)) | (s_lo >> 4); |
7769 | 3.79M | half_ulp = p10_hi >> (4 - h); |
7770 | | |
7771 | | /* check w1, u0, w0 range */ |
7772 | 3.79M | w1_inside = (s_lo >= ((u64)1 << 63)); |
7773 | 3.79M | if (unlikely(s_lo == ((u64)1 << 63))) break; |
7774 | 3.69M | u0_inside = (half_ulp >= c); |
7775 | 3.69M | if (unlikely(half_ulp == c)) break; |
7776 | 3.44M | t0 = ((u64)10 << (64 - 4)); |
7777 | 3.44M | t1 = c + half_ulp; |
7778 | 3.44M | w0_inside = (t1 >= t0); |
7779 | 3.44M | if (unlikely(t0 - t1 <= (u64)1)) break; |
7780 | | |
7781 | 3.43M | trim = (u0_inside | w0_inside); |
7782 | 3.43M | add_10 = (w0_inside ? 10 : 0); |
7783 | 3.43M | add_1 = mod + w1_inside; |
7784 | 3.43M | *sig_dec = dec + (trim ? add_10 : add_1); |
7785 | 3.43M | *exp_dec = k; |
7786 | 3.43M | return; |
7787 | 3.44M | } |
7788 | | |
7789 | | /* |
7790 | | Schubfach algorithm: |
7791 | | Raffaello Giulietti, The Schubfach way to render doubles, 2022. |
7792 | | https://drive.google.com/file/d/1gp5xv4CAa78SVgCeWfGqqI4FfYYYuNFb (Paper) |
7793 | | https://github.com/openjdk/jdk/pull/3402 (Java implementation) |
7794 | | https://github.com/abolz/Drachennest (C++ implementation) |
7795 | | */ |
7796 | 357k | irregular = (sig_raw == 0 && exp_raw > 1); |
7797 | 357k | is_even = !(sig_bin & 1); |
7798 | 357k | cbl = 4 * sig_bin - 2 + irregular; |
7799 | 357k | cb = 4 * sig_bin; |
7800 | 357k | cbr = 4 * sig_bin + 2; |
7801 | | |
7802 | | /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */ |
7803 | | /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */ |
7804 | 357k | k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20; |
7805 | 357k | h = exp_bin + ((-k * 217707) >> 16) + 1; |
7806 | 357k | pow10_table_get_sig(-k, &p10_hi, &p10_lo); |
7807 | 357k | p10_lo += 1; |
7808 | | |
7809 | 357k | vbl = u128_round_to_odd(p10_hi, p10_lo, cbl << h); |
7810 | 357k | vb = u128_round_to_odd(p10_hi, p10_lo, cb << h); |
7811 | 357k | vbr = u128_round_to_odd(p10_hi, p10_lo, cbr << h); |
7812 | 357k | lower = vbl + !is_even; |
7813 | 357k | upper = vbr - !is_even; |
7814 | | |
7815 | 357k | s = vb / 4; |
7816 | 357k | if (s >= 10) { |
7817 | 357k | sp = s / 10; |
7818 | 357k | u0_inside = (lower <= 40 * sp); |
7819 | 357k | w0_inside = (upper >= 40 * sp + 40); |
7820 | 357k | if (u0_inside != w0_inside) { |
7821 | 246k | *sig_dec = sp * 10 + (w0_inside ? 10 : 0); |
7822 | 246k | *exp_dec = k; |
7823 | 246k | return; |
7824 | 246k | } |
7825 | 357k | } |
7826 | 111k | u1_inside = (lower <= 4 * s); |
7827 | 111k | w1_inside = (upper >= 4 * s + 4); |
7828 | 111k | mid = 4 * s + 2; |
7829 | 111k | round_up = (vb > mid) || (vb == mid && (s & 1) != 0); |
7830 | 111k | *sig_dec = s + ((u1_inside != w1_inside) ? w1_inside : round_up); |
7831 | 111k | *exp_dec = k; |
7832 | 111k | } |
7833 | | |
7834 | | /** Convert f64 from binary to decimal (fast but not the shortest). |
7835 | | The input should not be 0, inf, nan. */ |
7836 | | static_inline void f64_bin_to_dec_fast(u64 sig_raw, u32 exp_raw, |
7837 | | u64 sig_bin, i32 exp_bin, |
7838 | | u64 *sig_dec, i32 *exp_dec, |
7839 | 0 | bool *round_up) { |
7840 | 0 | u64 cb, p10_hi, p10_lo, s_hi, s_lo; |
7841 | 0 | i32 k, h; |
7842 | 0 | bool irregular, u; |
7843 | |
|
7844 | 0 | irregular = (sig_raw == 0 && exp_raw > 1); |
7845 | | |
7846 | | /* k = floor(exp_bin * log10(2) + (irregular ? log10(3.0 / 4.0) : 0)); */ |
7847 | | /* h = exp_bin + floor(log2(10) * -k) + 1; (h = 1/2/3/4) */ |
7848 | 0 | k = (i32)(exp_bin * 315653 - (irregular ? 131237 : 0)) >> 20; |
7849 | 0 | h = exp_bin + ((-k * 217707) >> 16); |
7850 | 0 | pow10_table_get_sig(-k, &p10_hi, &p10_lo); |
7851 | | |
7852 | | /* sig_bin << (1/2/3/4) */ |
7853 | 0 | cb = sig_bin << (h + 1); |
7854 | 0 | u128_mul(cb, p10_lo, &s_hi, &s_lo); |
7855 | 0 | u128_mul_add(cb, p10_hi, s_hi, &s_hi, &s_lo); |
7856 | | |
7857 | | /* round up */ |
7858 | 0 | u = s_lo >= (irregular ? U64(0x55555555, 0x55555555) : ((u64)1 << 63)); |
7859 | |
|
7860 | 0 | *sig_dec = s_hi + u; |
7861 | 0 | *exp_dec = k; |
7862 | 0 | *round_up = u; |
7863 | 0 | return; |
7864 | 0 | } |
7865 | | |
7866 | | /** Write inf/nan if allowed. */ |
7867 | | static_inline u8 *write_inf_or_nan(u8 *buf, yyjson_write_flag flg, |
7868 | 2.51k | u64 sig_raw, bool sign) { |
7869 | 2.51k | if (has_flg(INF_AND_NAN_AS_NULL)) { |
7870 | 0 | byte_copy_4(buf, "null"); |
7871 | 0 | return buf + 4; |
7872 | 0 | } |
7873 | 2.51k | if (has_allow(INF_AND_NAN)) { |
7874 | 2.51k | if (sig_raw == 0) { |
7875 | 1.63k | buf[0] = '-'; |
7876 | 1.63k | buf += sign; |
7877 | 1.63k | byte_copy_8(buf, "Infinity"); |
7878 | 1.63k | return buf + 8; |
7879 | 1.63k | } else { |
7880 | 876 | byte_copy_4(buf, "NaN"); |
7881 | 876 | return buf + 3; |
7882 | 876 | } |
7883 | 2.51k | } |
7884 | 0 | return NULL; |
7885 | 2.51k | } |
7886 | | |
7887 | | /** |
7888 | | Write a float number (requires 40 bytes buffer). |
7889 | | We follow the ECMAScript specification for printing floating-point numbers, |
7890 | | similar to `Number.prototype.toString()`, but with the following changes: |
7891 | | 1. Keep the negative sign of `-0.0` to preserve input information. |
7892 | | 2. Keep the decimal point to indicate that the number is floating-point. |
7893 | | 3. Remove positive sign in the exponent part. |
7894 | | */ |
7895 | | static_noinline u8 *write_f32_raw(u8 *buf, u64 raw_f64, |
7896 | 0 | yyjson_write_flag flg) { |
7897 | 0 | u32 sig_bin, sig_dec, sig_raw; |
7898 | 0 | i32 exp_bin, exp_dec, sig_len, dot_ofs; |
7899 | 0 | u32 exp_raw, raw; |
7900 | 0 | u8 *end; |
7901 | 0 | bool sign; |
7902 | | |
7903 | | /* cast double to float */ |
7904 | 0 | raw = f32_to_bits(f64_to_f32(f64_from_bits(raw_f64))); |
7905 | | |
7906 | | /* decode raw bytes from IEEE-754 double format. */ |
7907 | 0 | sign = (bool)(raw >> (F32_BITS - 1)); |
7908 | 0 | sig_raw = raw & F32_SIG_MASK; |
7909 | 0 | exp_raw = (raw & F32_EXP_MASK) >> F32_SIG_BITS; |
7910 | | |
7911 | | /* return inf or nan */ |
7912 | 0 | if (unlikely(exp_raw == ((u32)1 << F32_EXP_BITS) - 1)) { |
7913 | 0 | return write_inf_or_nan(buf, flg, sig_raw, sign); |
7914 | 0 | } |
7915 | | |
7916 | | /* add sign for all finite number */ |
7917 | 0 | buf[0] = '-'; |
7918 | 0 | buf += sign; |
7919 | | |
7920 | | /* return zero */ |
7921 | 0 | if ((raw << 1) == 0) { |
7922 | 0 | byte_copy_4(buf, "0.0"); |
7923 | 0 | return buf + 3; |
7924 | 0 | } |
7925 | | |
7926 | 0 | if (likely(exp_raw != 0)) { |
7927 | | /* normal number */ |
7928 | 0 | sig_bin = sig_raw | ((u32)1 << F32_SIG_BITS); |
7929 | 0 | exp_bin = (i32)exp_raw - F32_EXP_BIAS - F32_SIG_BITS; |
7930 | | |
7931 | | /* fast path for small integer number without fraction */ |
7932 | 0 | if ((-F32_SIG_BITS <= exp_bin && exp_bin <= 0) && |
7933 | 0 | (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) { |
7934 | 0 | sig_dec = sig_bin >> -exp_bin; /* range: [1, 0xFFFFFF] */ |
7935 | 0 | buf = write_u32_len_1_to_8(sig_dec, buf); |
7936 | 0 | byte_copy_2(buf, ".0"); |
7937 | 0 | return buf + 2; |
7938 | 0 | } |
7939 | | |
7940 | | /* binary to decimal */ |
7941 | 0 | f32_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec); |
7942 | | |
7943 | | /* the sig length is 7 or 9 */ |
7944 | 0 | sig_len = 7 + (sig_dec >= (u32)10000000) + (sig_dec >= (u32)100000000); |
7945 | | |
7946 | | /* the decimal point offset relative to the first digit */ |
7947 | 0 | dot_ofs = sig_len + exp_dec; |
7948 | |
|
7949 | 0 | if (-6 < dot_ofs && dot_ofs <= 21) { |
7950 | 0 | i32 num_sep_pos, dot_set_pos, pre_ofs; |
7951 | 0 | u8 *num_hdr, *num_end, *num_sep, *dot_end; |
7952 | 0 | bool no_pre_zero; |
7953 | | |
7954 | | /* fill zeros */ |
7955 | 0 | memset(buf, '0', 32); |
7956 | | |
7957 | | /* not prefixed with zero, e.g. 1.234, 1234.0 */ |
7958 | 0 | no_pre_zero = (dot_ofs > 0); |
7959 | | |
7960 | | /* write the number as digits */ |
7961 | 0 | pre_ofs = no_pre_zero ? 0 : (2 - dot_ofs); |
7962 | 0 | num_hdr = buf + pre_ofs; |
7963 | 0 | num_end = write_u32_len_7_to_9_trim(sig_dec, num_hdr); |
7964 | | |
7965 | | /* separate these digits to leave a space for dot */ |
7966 | 0 | num_sep_pos = no_pre_zero ? dot_ofs : 0; |
7967 | 0 | num_sep = num_hdr + num_sep_pos; |
7968 | 0 | byte_move_8(num_sep + no_pre_zero, num_sep); |
7969 | 0 | num_end += no_pre_zero; |
7970 | | |
7971 | | /* write the dot */ |
7972 | 0 | dot_set_pos = yyjson_max(dot_ofs, 1); |
7973 | 0 | buf[dot_set_pos] = '.'; |
7974 | | |
7975 | | /* return the ending */ |
7976 | 0 | dot_end = buf + dot_ofs + 2; |
7977 | 0 | return yyjson_max(dot_end, num_end); |
7978 | |
|
7979 | 0 | } else { |
7980 | | /* write with scientific notation, e.g. 1.234e56 */ |
7981 | 0 | end = write_u32_len_7_to_9_trim(sig_dec, buf + 1); |
7982 | 0 | end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */ |
7983 | 0 | exp_dec += sig_len - 1; |
7984 | 0 | buf[0] = buf[1]; |
7985 | 0 | buf[1] = '.'; |
7986 | 0 | return write_f32_exp(exp_dec, end); |
7987 | 0 | } |
7988 | |
|
7989 | 0 | } else { |
7990 | | /* subnormal number */ |
7991 | 0 | sig_bin = sig_raw; |
7992 | 0 | exp_bin = 1 - F32_EXP_BIAS - F32_SIG_BITS; |
7993 | | |
7994 | | /* binary to decimal */ |
7995 | 0 | f32_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec); |
7996 | | |
7997 | | /* write significand part */ |
7998 | 0 | end = write_u32_len_1_to_8(sig_dec, buf + 1); |
7999 | 0 | buf[0] = buf[1]; |
8000 | 0 | buf[1] = '.'; |
8001 | 0 | exp_dec += (i32)(end - buf) - 2; |
8002 | | |
8003 | | /* trim trailing zeros */ |
8004 | 0 | end -= *(end - 1) == '0'; /* branchless for last zero */ |
8005 | 0 | end -= *(end - 1) == '0'; /* branchless for second last zero */ |
8006 | 0 | while (*(end - 1) == '0') end--; /* for unlikely more zeros */ |
8007 | 0 | end -= *(end - 1) == '.'; /* remove dot, e.g. 2.e-321 -> 2e-321 */ |
8008 | | |
8009 | | /* write exponent part */ |
8010 | 0 | return write_f32_exp(exp_dec, end); |
8011 | 0 | } |
8012 | 0 | } |
8013 | | |
8014 | | /** |
8015 | | Write a double number (requires 40 bytes buffer). |
8016 | | We follow the ECMAScript specification for printing floating-point numbers, |
8017 | | similar to `Number.prototype.toString()`, but with the following changes: |
8018 | | 1. Keep the negative sign of `-0.0` to preserve input information. |
8019 | | 2. Keep the decimal point to indicate that the number is floating-point. |
8020 | | 3. Remove positive sign in the exponent part. |
8021 | | */ |
8022 | 4.41M | static_noinline u8 *write_f64_raw(u8 *buf, u64 raw, yyjson_write_flag flg) { |
8023 | 4.41M | u64 sig_bin, sig_dec, sig_raw; |
8024 | 4.41M | i32 exp_bin, exp_dec, sig_len, dot_ofs; |
8025 | 4.41M | u32 exp_raw; |
8026 | 4.41M | u8 *end; |
8027 | 4.41M | bool sign; |
8028 | | |
8029 | | /* decode raw bytes from IEEE-754 double format. */ |
8030 | 4.41M | sign = (bool)(raw >> (F64_BITS - 1)); |
8031 | 4.41M | sig_raw = raw & F64_SIG_MASK; |
8032 | 4.41M | exp_raw = (u32)((raw & F64_EXP_MASK) >> F64_SIG_BITS); |
8033 | | |
8034 | | /* return inf or nan */ |
8035 | 4.41M | if (unlikely(exp_raw == ((u32)1 << F64_EXP_BITS) - 1)) { |
8036 | 2.51k | return write_inf_or_nan(buf, flg, sig_raw, sign); |
8037 | 2.51k | } |
8038 | | |
8039 | | /* add sign for all finite number */ |
8040 | 4.40M | buf[0] = '-'; |
8041 | 4.40M | buf += sign; |
8042 | | |
8043 | | /* return zero */ |
8044 | 4.40M | if ((raw << 1) == 0) { |
8045 | 24.0k | byte_copy_4(buf, "0.0"); |
8046 | 24.0k | return buf + 3; |
8047 | 24.0k | } |
8048 | | |
8049 | 4.38M | if (likely(exp_raw != 0)) { |
8050 | | /* normal number */ |
8051 | 3.67M | sig_bin = sig_raw | ((u64)1 << F64_SIG_BITS); |
8052 | 3.67M | exp_bin = (i32)exp_raw - F64_EXP_BIAS - F64_SIG_BITS; |
8053 | | |
8054 | | /* fast path for small integer number without fraction */ |
8055 | 3.67M | if ((-F64_SIG_BITS <= exp_bin && exp_bin <= 0) && |
8056 | 2.01M | (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) { |
8057 | 588k | sig_dec = sig_bin >> -exp_bin; /* range: [1, 0x1FFFFFFFFFFFFF] */ |
8058 | 588k | buf = write_u64_len_1_to_16(sig_dec, buf); |
8059 | 588k | byte_copy_2(buf, ".0"); |
8060 | 588k | return buf + 2; |
8061 | 588k | } |
8062 | | |
8063 | | /* binary to decimal */ |
8064 | 3.08M | f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec); |
8065 | | |
8066 | | /* the sig length is 16 or 17 */ |
8067 | 3.08M | sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000); |
8068 | | |
8069 | | /* the decimal point offset relative to the first digit */ |
8070 | 3.08M | dot_ofs = sig_len + exp_dec; |
8071 | | |
8072 | 3.08M | if (-6 < dot_ofs && dot_ofs <= 21) { |
8073 | 1.82M | i32 num_sep_pos, dot_set_pos, pre_ofs; |
8074 | 1.82M | u8 *num_hdr, *num_end, *num_sep, *dot_end; |
8075 | 1.82M | bool no_pre_zero; |
8076 | | |
8077 | | /* fill zeros */ |
8078 | 1.82M | memset(buf, '0', 32); |
8079 | | |
8080 | | /* not prefixed with zero, e.g. 1.234, 1234.0 */ |
8081 | 1.82M | no_pre_zero = (dot_ofs > 0); |
8082 | | |
8083 | | /* write the number as digits */ |
8084 | 1.82M | pre_ofs = no_pre_zero ? 0 : (2 - dot_ofs); |
8085 | 1.82M | num_hdr = buf + pre_ofs; |
8086 | 1.82M | num_end = write_u64_len_16_to_17_trim(sig_dec, num_hdr); |
8087 | | |
8088 | | /* separate these digits to leave a space for dot */ |
8089 | 1.82M | num_sep_pos = no_pre_zero ? dot_ofs : 0; |
8090 | 1.82M | num_sep = num_hdr + num_sep_pos; |
8091 | 1.82M | byte_move_16(num_sep + no_pre_zero, num_sep); |
8092 | 1.82M | num_end += no_pre_zero; |
8093 | | |
8094 | | /* write the dot */ |
8095 | 1.82M | dot_set_pos = yyjson_max(dot_ofs, 1); |
8096 | 1.82M | buf[dot_set_pos] = '.'; |
8097 | | |
8098 | | /* return the ending */ |
8099 | 1.82M | dot_end = buf + dot_ofs + 2; |
8100 | 1.82M | return yyjson_max(dot_end, num_end); |
8101 | | |
8102 | 1.82M | } else { |
8103 | | /* write with scientific notation, e.g. 1.234e56 */ |
8104 | 1.26M | end = write_u64_len_16_to_17_trim(sig_dec, buf + 1); |
8105 | 1.26M | end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */ |
8106 | 1.26M | exp_dec += sig_len - 1; |
8107 | 1.26M | buf[0] = buf[1]; |
8108 | 1.26M | buf[1] = '.'; |
8109 | 1.26M | return write_f64_exp(exp_dec, end); |
8110 | 1.26M | } |
8111 | | |
8112 | 3.08M | } else { |
8113 | | /* subnormal number */ |
8114 | 710k | sig_bin = sig_raw; |
8115 | 710k | exp_bin = 1 - F64_EXP_BIAS - F64_SIG_BITS; |
8116 | | |
8117 | | /* binary to decimal */ |
8118 | 710k | f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, &sig_dec, &exp_dec); |
8119 | | |
8120 | | /* write significand part */ |
8121 | 710k | end = write_u64_len_1_to_17(sig_dec, buf + 1); |
8122 | 710k | buf[0] = buf[1]; |
8123 | 710k | buf[1] = '.'; |
8124 | 710k | exp_dec += (i32)(end - buf) - 2; |
8125 | | |
8126 | | /* trim trailing zeros */ |
8127 | 710k | end -= *(end - 1) == '0'; /* branchless for last zero */ |
8128 | 710k | end -= *(end - 1) == '0'; /* branchless for second last zero */ |
8129 | 1.64M | while (*(end - 1) == '0') end--; /* for unlikely more zeros */ |
8130 | 710k | end -= *(end - 1) == '.'; /* remove dot, e.g. 2.e-321 -> 2e-321 */ |
8131 | | |
8132 | | /* write exponent part */ |
8133 | 710k | return write_f64_exp(exp_dec, end); |
8134 | 710k | } |
8135 | 4.38M | } |
8136 | | |
8137 | | /** |
8138 | | Write a double number using fixed-point notation (requires 40 bytes buffer). |
8139 | | |
8140 | | We follow the ECMAScript specification for printing floating-point numbers, |
8141 | | similar to `Number.prototype.toFixed(prec)`, but with the following changes: |
8142 | | 1. Keep the negative sign of `-0.0` to preserve input information. |
8143 | | 2. Keep the decimal point to indicate that the number is floating-point. |
8144 | | 3. Remove positive sign in the exponent part. |
8145 | | 4. Remove trailing zeros and reduce unnecessary precision. |
8146 | | */ |
8147 | | static_noinline u8 *write_f64_raw_fixed(u8 *buf, u64 raw, yyjson_write_flag flg, |
8148 | 0 | u32 prec) { |
8149 | 0 | u64 sig_bin, sig_dec, sig_raw; |
8150 | 0 | i32 exp_bin, exp_dec, sig_len, dot_ofs; |
8151 | 0 | u32 exp_raw; |
8152 | 0 | u8 *end; |
8153 | 0 | bool sign; |
8154 | | |
8155 | | /* decode raw bytes from IEEE-754 double format. */ |
8156 | 0 | sign = (bool)(raw >> (F64_BITS - 1)); |
8157 | 0 | sig_raw = raw & F64_SIG_MASK; |
8158 | 0 | exp_raw = (u32)((raw & F64_EXP_MASK) >> F64_SIG_BITS); |
8159 | | |
8160 | | /* return inf or nan */ |
8161 | 0 | if (unlikely(exp_raw == ((u32)1 << F64_EXP_BITS) - 1)) { |
8162 | 0 | return write_inf_or_nan(buf, flg, sig_raw, sign); |
8163 | 0 | } |
8164 | | |
8165 | | /* add sign for all finite number */ |
8166 | 0 | buf[0] = '-'; |
8167 | 0 | buf += sign; |
8168 | | |
8169 | | /* return zero */ |
8170 | 0 | if ((raw << 1) == 0) { |
8171 | 0 | byte_copy_4(buf, "0.0"); |
8172 | 0 | return buf + 3; |
8173 | 0 | } |
8174 | | |
8175 | 0 | if (likely(exp_raw != 0)) { |
8176 | | /* normal number */ |
8177 | 0 | sig_bin = sig_raw | ((u64)1 << F64_SIG_BITS); |
8178 | 0 | exp_bin = (i32)exp_raw - F64_EXP_BIAS - F64_SIG_BITS; |
8179 | | |
8180 | | /* fast path for small integer number without fraction */ |
8181 | 0 | if ((-F64_SIG_BITS <= exp_bin && exp_bin <= 0) && |
8182 | 0 | (u64_tz_bits(sig_bin) >= (u32)-exp_bin)) { |
8183 | 0 | sig_dec = sig_bin >> -exp_bin; /* range: [1, 0x1FFFFFFFFFFFFF] */ |
8184 | 0 | buf = write_u64_len_1_to_16(sig_dec, buf); |
8185 | 0 | byte_copy_2(buf, ".0"); |
8186 | 0 | return buf + 2; |
8187 | 0 | } |
8188 | | |
8189 | | /* only `fabs(num) < 1e21` are processed here. */ |
8190 | 0 | if ((raw << 1) < (U64(0x444B1AE4, 0xD6E2EF50) << 1)) { |
8191 | 0 | i32 num_sep_pos, dot_set_pos, pre_ofs; |
8192 | 0 | u8 *num_hdr, *num_end, *num_sep; |
8193 | 0 | bool round_up, no_pre_zero; |
8194 | | |
8195 | | /* binary to decimal */ |
8196 | 0 | f64_bin_to_dec_fast(sig_raw, exp_raw, sig_bin, exp_bin, |
8197 | 0 | &sig_dec, &exp_dec, &round_up); |
8198 | | |
8199 | | /* the sig length is 16 or 17 */ |
8200 | 0 | sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000); |
8201 | | |
8202 | | /* limit the length of digits after the decimal point */ |
8203 | 0 | if (exp_dec < -1) { |
8204 | 0 | i32 sig_len_cut = -exp_dec - (i32)prec; |
8205 | 0 | if (sig_len_cut > sig_len) { |
8206 | 0 | byte_copy_4(buf, "0.0"); |
8207 | 0 | return buf + 3; |
8208 | 0 | } |
8209 | 0 | if (sig_len_cut > 0) { |
8210 | 0 | u64 div, mod, p10; |
8211 | | |
8212 | | /* remove round up */ |
8213 | 0 | sig_dec -= round_up; |
8214 | 0 | sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000); |
8215 | | |
8216 | | /* cut off some digits */ |
8217 | 0 | div_pow10(sig_dec, (u32)sig_len_cut, &div, &mod, &p10); |
8218 | | |
8219 | | /* add round up */ |
8220 | 0 | sig_dec = div + (mod >= p10 / 2); |
8221 | | |
8222 | | /* update exp and sig length */ |
8223 | 0 | exp_dec += sig_len_cut; |
8224 | 0 | sig_len -= sig_len_cut; |
8225 | 0 | sig_len += (sig_len >= 0) && |
8226 | 0 | (sig_dec >= div_pow10_table[sig_len].p10); |
8227 | 0 | } |
8228 | 0 | if (sig_len <= 0) { |
8229 | 0 | byte_copy_4(buf, "0.0"); |
8230 | 0 | return buf + 3; |
8231 | 0 | } |
8232 | 0 | } |
8233 | | |
8234 | | /* fill zeros */ |
8235 | 0 | memset(buf, '0', 32); |
8236 | | |
8237 | | /* the decimal point offset relative to the first digit */ |
8238 | 0 | dot_ofs = sig_len + exp_dec; |
8239 | | |
8240 | | /* not prefixed with zero, e.g. 1.234, 1234.0 */ |
8241 | 0 | no_pre_zero = (dot_ofs > 0); |
8242 | | |
8243 | | /* write the number as digits */ |
8244 | 0 | pre_ofs = no_pre_zero ? 0 : (1 - dot_ofs); |
8245 | 0 | num_hdr = buf + pre_ofs; |
8246 | 0 | num_end = write_u64_len_1_to_17(sig_dec, num_hdr); |
8247 | | |
8248 | | /* separate these digits to leave a space for dot */ |
8249 | 0 | num_sep_pos = no_pre_zero ? dot_ofs : -dot_ofs; |
8250 | 0 | num_sep = buf + num_sep_pos; |
8251 | 0 | byte_move_16(num_sep + 1, num_sep); |
8252 | 0 | num_end += (exp_dec < 0); |
8253 | | |
8254 | | /* write the dot */ |
8255 | 0 | dot_set_pos = yyjson_max(dot_ofs, 1); |
8256 | 0 | buf[dot_set_pos] = '.'; |
8257 | | |
8258 | | /* remove trailing zeros */ |
8259 | 0 | buf += dot_set_pos + 2; |
8260 | 0 | buf = yyjson_max(buf, num_end); |
8261 | 0 | buf -= *(buf - 1) == '0'; /* branchless for last zero */ |
8262 | 0 | buf -= *(buf - 1) == '0'; /* branchless for second last zero */ |
8263 | 0 | while (*(buf - 1) == '0') buf--; /* for unlikely more zeros */ |
8264 | 0 | buf += *(buf - 1) == '.'; /* keep a zero after dot */ |
8265 | 0 | return buf; |
8266 | |
|
8267 | 0 | } else { |
8268 | | /* binary to decimal */ |
8269 | 0 | f64_bin_to_dec(sig_raw, exp_raw, sig_bin, exp_bin, |
8270 | 0 | &sig_dec, &exp_dec); |
8271 | | |
8272 | | /* the sig length is 16 or 17 */ |
8273 | 0 | sig_len = 16 + (sig_dec >= (u64)100000000 * 100000000); |
8274 | | |
8275 | | /* write with scientific notation, e.g. 1.234e56 */ |
8276 | 0 | end = write_u64_len_16_to_17_trim(sig_dec, buf + 1); |
8277 | 0 | end -= (end == buf + 2); /* remove '.0', e.g. 2.0e34 -> 2e34 */ |
8278 | 0 | exp_dec += sig_len - 1; |
8279 | 0 | buf[0] = buf[1]; |
8280 | 0 | buf[1] = '.'; |
8281 | 0 | return write_f64_exp(exp_dec, end); |
8282 | 0 | } |
8283 | 0 | } else { |
8284 | | /* subnormal number */ |
8285 | 0 | byte_copy_4(buf, "0.0"); |
8286 | 0 | return buf + 3; |
8287 | 0 | } |
8288 | 0 | } |
8289 | | |
8290 | | #else /* FP_WRITER */ |
8291 | | |
8292 | | #if YYJSON_MSC_VER >= 1400 |
8293 | | #define snprintf_num(buf, len, fmt, dig, val) \ |
8294 | | sprintf_s((char *)buf, len, fmt, dig, val) |
8295 | | #elif defined(snprintf) || (YYJSON_STDC_VER >= 199901L) |
8296 | | #define snprintf_num(buf, len, fmt, dig, val) \ |
8297 | | snprintf((char *)buf, len, fmt, dig, val) |
8298 | | #else |
8299 | | #define snprintf_num(buf, len, fmt, dig, val) \ |
8300 | | sprintf((char *)buf, fmt, dig, val) |
8301 | | #endif |
8302 | | |
8303 | | static_noinline u8 *write_fp_reformat(u8 *buf, int len, |
8304 | | yyjson_write_flag flg, bool fixed) { |
8305 | | u8 *cur = buf; |
8306 | | if (unlikely(len < 1)) return NULL; |
8307 | | cur += (*cur == '-'); |
8308 | | if (unlikely(!char_is_digit(*cur))) { |
8309 | | /* nan, inf, or bad output */ |
8310 | | if (has_flg(INF_AND_NAN_AS_NULL)) { |
8311 | | byte_copy_4(buf, "null"); |
8312 | | return buf + 4; |
8313 | | } else if (has_allow(INF_AND_NAN)) { |
8314 | | if (*cur == 'i') { |
8315 | | byte_copy_8(cur, "Infinity"); |
8316 | | return cur + 8; |
8317 | | } else if (*cur == 'n') { |
8318 | | byte_copy_4(buf, "NaN"); |
8319 | | return buf + 3; |
8320 | | } |
8321 | | } |
8322 | | return NULL; |
8323 | | } else { |
8324 | | /* finite number */ |
8325 | | u8 *end = buf + len, *dot = NULL, *exp = NULL; |
8326 | | |
8327 | | /* |
8328 | | The snprintf() function is locale-dependent. For currently known |
8329 | | locales, (en, zh, ja, ko, am, he, hi) use '.' as the decimal point, |
8330 | | while other locales use ',' as the decimal point. we need to replace |
8331 | | ',' with '.' to avoid the locale setting. |
8332 | | */ |
8333 | | for (; cur < end; cur++) { |
8334 | | switch (*cur) { |
8335 | | case ',': *cur = '.'; /* fallthrough */ |
8336 | | case '.': dot = cur; break; |
8337 | | case 'e': exp = cur; break; |
8338 | | default: break; |
8339 | | } |
8340 | | } |
8341 | | if (fixed) { |
8342 | | /* remove trailing zeros */ |
8343 | | while (*(end - 1) == '0') end--; |
8344 | | end += *(end - 1) == '.'; |
8345 | | } else { |
8346 | | if (!dot && !exp) { |
8347 | | /* add decimal point, e.g. 123 -> 123.0 */ |
8348 | | byte_copy_2(end, ".0"); |
8349 | | end += 2; |
8350 | | } else if (exp) { |
8351 | | cur = exp + 1; |
8352 | | /* remove positive sign in the exponent part */ |
8353 | | if (*cur == '+') { |
8354 | | memmove(cur, cur + 1, (usize)(end - cur - 1)); |
8355 | | end--; |
8356 | | } |
8357 | | cur += (*cur == '-'); |
8358 | | /* remove leading zeros in the exponent part */ |
8359 | | if (*cur == '0') { |
8360 | | u8 *hdr = cur++; |
8361 | | while (*cur == '0') cur++; |
8362 | | memmove(hdr, cur, (usize)(end - cur)); |
8363 | | end -= (usize)(cur - hdr); |
8364 | | } |
8365 | | } |
8366 | | } |
8367 | | return end; |
8368 | | } |
8369 | | } |
8370 | | |
8371 | | /** Write a double number (requires 40 bytes buffer). */ |
8372 | | static_noinline u8 *write_f64_raw(u8 *buf, u64 raw, yyjson_write_flag flg) { |
8373 | | #if defined(DBL_DECIMAL_DIG) && DBL_DECIMAL_DIG < F64_DEC_DIG |
8374 | | int dig = DBL_DECIMAL_DIG; |
8375 | | #else |
8376 | | int dig = F64_DEC_DIG; |
8377 | | #endif |
8378 | | f64 val = f64_from_bits(raw); |
8379 | | int len = snprintf_num(buf, FP_BUF_LEN, "%.*g", dig, val); |
8380 | | return write_fp_reformat(buf, len, flg, false); |
8381 | | } |
8382 | | |
8383 | | /** Write a double number (requires 40 bytes buffer). */ |
8384 | | static_noinline u8 *write_f32_raw(u8 *buf, u64 raw, yyjson_write_flag flg) { |
8385 | | #if defined(FLT_DECIMAL_DIG) && FLT_DECIMAL_DIG < F32_DEC_DIG |
8386 | | int dig = FLT_DECIMAL_DIG; |
8387 | | #else |
8388 | | int dig = F32_DEC_DIG; |
8389 | | #endif |
8390 | | f64 val = (f64)f64_to_f32(f64_from_bits(raw)); |
8391 | | int len = snprintf_num(buf, FP_BUF_LEN, "%.*g", dig, val); |
8392 | | return write_fp_reformat(buf, len, flg, false); |
8393 | | } |
8394 | | |
8395 | | /** Write a double number (requires 40 bytes buffer). */ |
8396 | | static_noinline u8 *write_f64_raw_fixed(u8 *buf, u64 raw, |
8397 | | yyjson_write_flag flg, u32 prec) { |
8398 | | f64 val = (f64)f64_from_bits(raw); |
8399 | | if (-1e21 < val && val < 1e21) { |
8400 | | int len = snprintf_num(buf, FP_BUF_LEN, "%.*f", (int)prec, val); |
8401 | | return write_fp_reformat(buf, len, flg, true); |
8402 | | } else { |
8403 | | return write_f64_raw(buf, raw, flg); |
8404 | | } |
8405 | | } |
8406 | | |
8407 | | #endif /* FP_WRITER */ |
8408 | | |
8409 | | /** Write a JSON number (requires 40 bytes buffer). */ |
8410 | 87.9M | static_inline u8 *write_num(u8 *cur, yyjson_val *val, yyjson_write_flag flg) { |
8411 | 87.9M | if (!(val->tag & YYJSON_SUBTYPE_REAL)) { |
8412 | 83.5M | u64 pos = val->uni.u64; |
8413 | 83.5M | u64 neg = ~pos + 1; |
8414 | 83.5M | usize sign = ((val->tag & YYJSON_SUBTYPE_SINT) > 0) & ((i64)pos < 0); |
8415 | 83.5M | *cur = '-'; |
8416 | 83.5M | return write_u64(sign ? neg : pos, cur + sign); |
8417 | 83.5M | } else { |
8418 | 4.41M | u64 raw = val->uni.u64; |
8419 | 4.41M | u32 val_fmt = (u32)(val->tag >> 32); |
8420 | 4.41M | u32 all_fmt = flg; |
8421 | 4.41M | u32 fmt = val_fmt | all_fmt; |
8422 | 4.41M | if (likely(!(fmt >> (32 - YYJSON_WRITE_FP_FLAG_BITS)))) { |
8423 | | /* double to shortest */ |
8424 | 4.41M | return write_f64_raw(cur, raw, flg); |
8425 | 4.41M | } else if (fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS)) { |
8426 | | /* double to fixed */ |
8427 | 0 | u32 val_prec = val_fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS); |
8428 | 0 | u32 all_prec = all_fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS); |
8429 | 0 | u32 prec = val_prec ? val_prec : all_prec; |
8430 | 0 | return write_f64_raw_fixed(cur, raw, flg, prec); |
8431 | 0 | } else { |
8432 | 0 | if (fmt & YYJSON_WRITE_FP_TO_FLOAT) { |
8433 | | /* float to shortest */ |
8434 | 0 | return write_f32_raw(cur, raw, flg); |
8435 | 0 | } else { |
8436 | | /* double to shortest */ |
8437 | 0 | return write_f64_raw(cur, raw, flg); |
8438 | 0 | } |
8439 | 0 | } |
8440 | 4.41M | } |
8441 | 87.9M | } |
8442 | | |
8443 | 0 | char *yyjson_write_number(const yyjson_val *val, char *buf) { |
8444 | 0 | if (unlikely(!val || !buf)) return NULL; |
8445 | 0 | switch (val->tag & YYJSON_TAG_MASK) { |
8446 | 0 | case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_UINT: { |
8447 | 0 | buf = (char *)write_u64(val->uni.u64, (u8 *)buf); |
8448 | 0 | *buf = '\0'; |
8449 | 0 | return buf; |
8450 | 0 | } |
8451 | 0 | case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_SINT: { |
8452 | 0 | u64 pos = val->uni.u64; |
8453 | 0 | u64 neg = ~pos + 1; |
8454 | 0 | usize sign = ((i64)pos < 0); |
8455 | 0 | *buf = '-'; |
8456 | 0 | buf = (char *)write_u64(sign ? neg : pos, (u8 *)buf + sign); |
8457 | 0 | *buf = '\0'; |
8458 | 0 | return buf; |
8459 | 0 | } |
8460 | 0 | case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL: { |
8461 | 0 | u64 raw = val->uni.u64; |
8462 | 0 | u32 fmt = (u32)(val->tag >> 32); |
8463 | 0 | u32 flg = YYJSON_WRITE_ALLOW_INF_AND_NAN; |
8464 | 0 | if (likely(!(fmt >> (32 - YYJSON_WRITE_FP_FLAG_BITS)))) { |
8465 | 0 | buf = (char *)write_f64_raw((u8 *)buf, raw, flg); |
8466 | 0 | } else if (fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS)) { |
8467 | 0 | u32 prec = fmt >> (32 - YYJSON_WRITE_FP_PREC_BITS); |
8468 | 0 | buf = (char *)write_f64_raw_fixed((u8 *)buf, raw, flg, prec); |
8469 | 0 | } else { |
8470 | 0 | if (fmt & YYJSON_WRITE_FP_TO_FLOAT) { |
8471 | 0 | buf = (char *)write_f32_raw((u8 *)buf, raw, flg); |
8472 | 0 | } else { |
8473 | 0 | buf = (char *)write_f64_raw((u8 *)buf, raw, flg); |
8474 | 0 | } |
8475 | 0 | } |
8476 | 0 | if (buf) *buf = '\0'; |
8477 | 0 | return buf; |
8478 | 0 | } |
8479 | 0 | default: return NULL; |
8480 | 0 | } |
8481 | 0 | } |
8482 | | |
8483 | | |
8484 | | |
8485 | | /*============================================================================== |
8486 | | * MARK: - String Writer (Private) |
8487 | | *============================================================================*/ |
8488 | | |
8489 | | /** Character encode type, if (type > CHAR_ENC_ERR_1) bytes = type / 2; */ |
8490 | | typedef u8 char_enc_type; |
8491 | 38.5M | #define CHAR_ENC_CPY_1 0 /* 1-byte UTF-8, copy. */ |
8492 | 863 | #define CHAR_ENC_ERR_1 1 /* 1-byte UTF-8, error. */ |
8493 | 137M | #define CHAR_ENC_ESC_A 2 /* 1-byte ASCII, escaped as '\x'. */ |
8494 | 487M | #define CHAR_ENC_ESC_1 3 /* 1-byte UTF-8, escaped as '\uXXXX'. */ |
8495 | 1.26M | #define CHAR_ENC_CPY_2 4 /* 2-byte UTF-8, copy. */ |
8496 | 1.35M | #define CHAR_ENC_ESC_2 5 /* 2-byte UTF-8, escaped as '\uXXXX'. */ |
8497 | 527k | #define CHAR_ENC_CPY_3 6 /* 3-byte UTF-8, copy. */ |
8498 | 12.2k | #define CHAR_ENC_ESC_3 7 /* 3-byte UTF-8, escaped as '\uXXXX'. */ |
8499 | 1.51M | #define CHAR_ENC_CPY_4 8 /* 4-byte UTF-8, copy. */ |
8500 | 39.4k | #define CHAR_ENC_ESC_4 9 /* 4-byte UTF-8, escaped as '\uXXXX\uXXXX'. */ |
8501 | | |
8502 | | /** Character encode type table: don't escape unicode, don't escape '/'. |
8503 | | (generated with misc/make_tables.c) */ |
8504 | | static const char_enc_type enc_table_cpy[256] = { |
8505 | | 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3, |
8506 | | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
8507 | | 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
8508 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
8509 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
8510 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, |
8511 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
8512 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
8513 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
8514 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
8515 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
8516 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
8517 | | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, |
8518 | | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, |
8519 | | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
8520 | | 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1 |
8521 | | }; |
8522 | | |
8523 | | /** Character encode type table: don't escape unicode, escape '/'. |
8524 | | (generated with misc/make_tables.c) */ |
8525 | | static const char_enc_type enc_table_cpy_slash[256] = { |
8526 | | 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3, |
8527 | | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
8528 | | 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, |
8529 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
8530 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
8531 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, |
8532 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
8533 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
8534 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
8535 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
8536 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
8537 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
8538 | | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, |
8539 | | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, |
8540 | | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
8541 | | 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1 |
8542 | | }; |
8543 | | |
8544 | | /** Character encode type table: escape unicode, don't escape '/'. |
8545 | | (generated with misc/make_tables.c) */ |
8546 | | static const char_enc_type enc_table_esc[256] = { |
8547 | | 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3, |
8548 | | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
8549 | | 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
8550 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
8551 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
8552 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, |
8553 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
8554 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
8555 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
8556 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
8557 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
8558 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
8559 | | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
8560 | | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
8561 | | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
8562 | | 9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1 |
8563 | | }; |
8564 | | |
8565 | | /** Character encode type table: escape unicode, escape '/'. |
8566 | | (generated with misc/make_tables.c) */ |
8567 | | static const char_enc_type enc_table_esc_slash[256] = { |
8568 | | 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3, |
8569 | | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
8570 | | 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, |
8571 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
8572 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
8573 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, |
8574 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
8575 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
8576 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
8577 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
8578 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
8579 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
8580 | | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
8581 | | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
8582 | | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
8583 | | 9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1 |
8584 | | }; |
8585 | | |
8586 | | /** Escaped hex character table: ["00" "01" "02" ... "FD" "FE" "FF"]. |
8587 | | (generated with misc/make_tables.c) */ |
8588 | | yyjson_align(2) |
8589 | | static const u8 esc_hex_char_table[512] = { |
8590 | | '0', '0', '0', '1', '0', '2', '0', '3', |
8591 | | '0', '4', '0', '5', '0', '6', '0', '7', |
8592 | | '0', '8', '0', '9', '0', 'A', '0', 'B', |
8593 | | '0', 'C', '0', 'D', '0', 'E', '0', 'F', |
8594 | | '1', '0', '1', '1', '1', '2', '1', '3', |
8595 | | '1', '4', '1', '5', '1', '6', '1', '7', |
8596 | | '1', '8', '1', '9', '1', 'A', '1', 'B', |
8597 | | '1', 'C', '1', 'D', '1', 'E', '1', 'F', |
8598 | | '2', '0', '2', '1', '2', '2', '2', '3', |
8599 | | '2', '4', '2', '5', '2', '6', '2', '7', |
8600 | | '2', '8', '2', '9', '2', 'A', '2', 'B', |
8601 | | '2', 'C', '2', 'D', '2', 'E', '2', 'F', |
8602 | | '3', '0', '3', '1', '3', '2', '3', '3', |
8603 | | '3', '4', '3', '5', '3', '6', '3', '7', |
8604 | | '3', '8', '3', '9', '3', 'A', '3', 'B', |
8605 | | '3', 'C', '3', 'D', '3', 'E', '3', 'F', |
8606 | | '4', '0', '4', '1', '4', '2', '4', '3', |
8607 | | '4', '4', '4', '5', '4', '6', '4', '7', |
8608 | | '4', '8', '4', '9', '4', 'A', '4', 'B', |
8609 | | '4', 'C', '4', 'D', '4', 'E', '4', 'F', |
8610 | | '5', '0', '5', '1', '5', '2', '5', '3', |
8611 | | '5', '4', '5', '5', '5', '6', '5', '7', |
8612 | | '5', '8', '5', '9', '5', 'A', '5', 'B', |
8613 | | '5', 'C', '5', 'D', '5', 'E', '5', 'F', |
8614 | | '6', '0', '6', '1', '6', '2', '6', '3', |
8615 | | '6', '4', '6', '5', '6', '6', '6', '7', |
8616 | | '6', '8', '6', '9', '6', 'A', '6', 'B', |
8617 | | '6', 'C', '6', 'D', '6', 'E', '6', 'F', |
8618 | | '7', '0', '7', '1', '7', '2', '7', '3', |
8619 | | '7', '4', '7', '5', '7', '6', '7', '7', |
8620 | | '7', '8', '7', '9', '7', 'A', '7', 'B', |
8621 | | '7', 'C', '7', 'D', '7', 'E', '7', 'F', |
8622 | | '8', '0', '8', '1', '8', '2', '8', '3', |
8623 | | '8', '4', '8', '5', '8', '6', '8', '7', |
8624 | | '8', '8', '8', '9', '8', 'A', '8', 'B', |
8625 | | '8', 'C', '8', 'D', '8', 'E', '8', 'F', |
8626 | | '9', '0', '9', '1', '9', '2', '9', '3', |
8627 | | '9', '4', '9', '5', '9', '6', '9', '7', |
8628 | | '9', '8', '9', '9', '9', 'A', '9', 'B', |
8629 | | '9', 'C', '9', 'D', '9', 'E', '9', 'F', |
8630 | | 'A', '0', 'A', '1', 'A', '2', 'A', '3', |
8631 | | 'A', '4', 'A', '5', 'A', '6', 'A', '7', |
8632 | | 'A', '8', 'A', '9', 'A', 'A', 'A', 'B', |
8633 | | 'A', 'C', 'A', 'D', 'A', 'E', 'A', 'F', |
8634 | | 'B', '0', 'B', '1', 'B', '2', 'B', '3', |
8635 | | 'B', '4', 'B', '5', 'B', '6', 'B', '7', |
8636 | | 'B', '8', 'B', '9', 'B', 'A', 'B', 'B', |
8637 | | 'B', 'C', 'B', 'D', 'B', 'E', 'B', 'F', |
8638 | | 'C', '0', 'C', '1', 'C', '2', 'C', '3', |
8639 | | 'C', '4', 'C', '5', 'C', '6', 'C', '7', |
8640 | | 'C', '8', 'C', '9', 'C', 'A', 'C', 'B', |
8641 | | 'C', 'C', 'C', 'D', 'C', 'E', 'C', 'F', |
8642 | | 'D', '0', 'D', '1', 'D', '2', 'D', '3', |
8643 | | 'D', '4', 'D', '5', 'D', '6', 'D', '7', |
8644 | | 'D', '8', 'D', '9', 'D', 'A', 'D', 'B', |
8645 | | 'D', 'C', 'D', 'D', 'D', 'E', 'D', 'F', |
8646 | | 'E', '0', 'E', '1', 'E', '2', 'E', '3', |
8647 | | 'E', '4', 'E', '5', 'E', '6', 'E', '7', |
8648 | | 'E', '8', 'E', '9', 'E', 'A', 'E', 'B', |
8649 | | 'E', 'C', 'E', 'D', 'E', 'E', 'E', 'F', |
8650 | | 'F', '0', 'F', '1', 'F', '2', 'F', '3', |
8651 | | 'F', '4', 'F', '5', 'F', '6', 'F', '7', |
8652 | | 'F', '8', 'F', '9', 'F', 'A', 'F', 'B', |
8653 | | 'F', 'C', 'F', 'D', 'F', 'E', 'F', 'F' |
8654 | | }; |
8655 | | |
8656 | | /** Lowercase variant of esc_hex_char_table. */ |
8657 | | yyjson_align(2) |
8658 | | static const u8 esc_hex_char_table_lower[512] = { |
8659 | | '0', '0', '0', '1', '0', '2', '0', '3', |
8660 | | '0', '4', '0', '5', '0', '6', '0', '7', |
8661 | | '0', '8', '0', '9', '0', 'a', '0', 'b', |
8662 | | '0', 'c', '0', 'd', '0', 'e', '0', 'f', |
8663 | | '1', '0', '1', '1', '1', '2', '1', '3', |
8664 | | '1', '4', '1', '5', '1', '6', '1', '7', |
8665 | | '1', '8', '1', '9', '1', 'a', '1', 'b', |
8666 | | '1', 'c', '1', 'd', '1', 'e', '1', 'f', |
8667 | | '2', '0', '2', '1', '2', '2', '2', '3', |
8668 | | '2', '4', '2', '5', '2', '6', '2', '7', |
8669 | | '2', '8', '2', '9', '2', 'a', '2', 'b', |
8670 | | '2', 'c', '2', 'd', '2', 'e', '2', 'f', |
8671 | | '3', '0', '3', '1', '3', '2', '3', '3', |
8672 | | '3', '4', '3', '5', '3', '6', '3', '7', |
8673 | | '3', '8', '3', '9', '3', 'a', '3', 'b', |
8674 | | '3', 'c', '3', 'd', '3', 'e', '3', 'f', |
8675 | | '4', '0', '4', '1', '4', '2', '4', '3', |
8676 | | '4', '4', '4', '5', '4', '6', '4', '7', |
8677 | | '4', '8', '4', '9', '4', 'a', '4', 'b', |
8678 | | '4', 'c', '4', 'd', '4', 'e', '4', 'f', |
8679 | | '5', '0', '5', '1', '5', '2', '5', '3', |
8680 | | '5', '4', '5', '5', '5', '6', '5', '7', |
8681 | | '5', '8', '5', '9', '5', 'a', '5', 'b', |
8682 | | '5', 'c', '5', 'd', '5', 'e', '5', 'f', |
8683 | | '6', '0', '6', '1', '6', '2', '6', '3', |
8684 | | '6', '4', '6', '5', '6', '6', '6', '7', |
8685 | | '6', '8', '6', '9', '6', 'a', '6', 'b', |
8686 | | '6', 'c', '6', 'd', '6', 'e', '6', 'f', |
8687 | | '7', '0', '7', '1', '7', '2', '7', '3', |
8688 | | '7', '4', '7', '5', '7', '6', '7', '7', |
8689 | | '7', '8', '7', '9', '7', 'a', '7', 'b', |
8690 | | '7', 'c', '7', 'd', '7', 'e', '7', 'f', |
8691 | | '8', '0', '8', '1', '8', '2', '8', '3', |
8692 | | '8', '4', '8', '5', '8', '6', '8', '7', |
8693 | | '8', '8', '8', '9', '8', 'a', '8', 'b', |
8694 | | '8', 'c', '8', 'd', '8', 'e', '8', 'f', |
8695 | | '9', '0', '9', '1', '9', '2', '9', '3', |
8696 | | '9', '4', '9', '5', '9', '6', '9', '7', |
8697 | | '9', '8', '9', '9', '9', 'a', '9', 'b', |
8698 | | '9', 'c', '9', 'd', '9', 'e', '9', 'f', |
8699 | | 'a', '0', 'a', '1', 'a', '2', 'a', '3', |
8700 | | 'a', '4', 'a', '5', 'a', '6', 'a', '7', |
8701 | | 'a', '8', 'a', '9', 'a', 'a', 'a', 'b', |
8702 | | 'a', 'c', 'a', 'd', 'a', 'e', 'a', 'f', |
8703 | | 'b', '0', 'b', '1', 'b', '2', 'b', '3', |
8704 | | 'b', '4', 'b', '5', 'b', '6', 'b', '7', |
8705 | | 'b', '8', 'b', '9', 'b', 'a', 'b', 'b', |
8706 | | 'b', 'c', 'b', 'd', 'b', 'e', 'b', 'f', |
8707 | | 'c', '0', 'c', '1', 'c', '2', 'c', '3', |
8708 | | 'c', '4', 'c', '5', 'c', '6', 'c', '7', |
8709 | | 'c', '8', 'c', '9', 'c', 'a', 'c', 'b', |
8710 | | 'c', 'c', 'c', 'd', 'c', 'e', 'c', 'f', |
8711 | | 'd', '0', 'd', '1', 'd', '2', 'd', '3', |
8712 | | 'd', '4', 'd', '5', 'd', '6', 'd', '7', |
8713 | | 'd', '8', 'd', '9', 'd', 'a', 'd', 'b', |
8714 | | 'd', 'c', 'd', 'd', 'd', 'e', 'd', 'f', |
8715 | | 'e', '0', 'e', '1', 'e', '2', 'e', '3', |
8716 | | 'e', '4', 'e', '5', 'e', '6', 'e', '7', |
8717 | | 'e', '8', 'e', '9', 'e', 'a', 'e', 'b', |
8718 | | 'e', 'c', 'e', 'd', 'e', 'e', 'e', 'f', |
8719 | | 'f', '0', 'f', '1', 'f', '2', 'f', '3', |
8720 | | 'f', '4', 'f', '5', 'f', '6', 'f', '7', |
8721 | | 'f', '8', 'f', '9', 'f', 'a', 'f', 'b', |
8722 | | 'f', 'c', 'f', 'd', 'f', 'e', 'f', 'f' |
8723 | | }; |
8724 | | |
8725 | | /** Escaped single character table. (generated with misc/make_tables.c) */ |
8726 | | yyjson_align(2) |
8727 | | static const u8 esc_single_char_table[512] = { |
8728 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8729 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8730 | | '\\', 'b', '\\', 't', '\\', 'n', ' ', ' ', |
8731 | | '\\', 'f', '\\', 'r', ' ', ' ', ' ', ' ', |
8732 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8733 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8734 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8735 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8736 | | ' ', ' ', ' ', ' ', '\\', '"', ' ', ' ', |
8737 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8738 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8739 | | ' ', ' ', ' ', ' ', ' ', ' ', '\\', '/', |
8740 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8741 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8742 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8743 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8744 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8745 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8746 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8747 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8748 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8749 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8750 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8751 | | '\\', '\\', ' ', ' ', ' ', ' ', ' ', ' ', |
8752 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8753 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8754 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8755 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8756 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8757 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8758 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8759 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8760 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8761 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8762 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8763 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8764 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8765 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8766 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8767 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8768 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8769 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8770 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8771 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8772 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8773 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8774 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8775 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8776 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8777 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8778 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8779 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8780 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8781 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8782 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8783 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8784 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8785 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8786 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8787 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8788 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8789 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8790 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', |
8791 | | ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' |
8792 | | }; |
8793 | | |
8794 | | /** Returns the hex digit table to use for \uXXXX escapes. */ |
8795 | 38.3k | static_inline const u8 *get_hex_table_with_flag(yyjson_write_flag flg) { |
8796 | 38.3k | return has_flg(LOWERCASE_HEX) |
8797 | 38.3k | ? esc_hex_char_table_lower |
8798 | 38.3k | : esc_hex_char_table; |
8799 | 38.3k | } |
8800 | | |
8801 | | /** Returns the encode table with options. */ |
8802 | | static_inline const char_enc_type *get_enc_table_with_flag( |
8803 | 38.3k | yyjson_write_flag flg) { |
8804 | 38.3k | if (has_flg(ESCAPE_UNICODE)) { |
8805 | 12.4k | if (has_flg(ESCAPE_SLASHES)) { |
8806 | 12.4k | return enc_table_esc_slash; |
8807 | 12.4k | } else { |
8808 | 0 | return enc_table_esc; |
8809 | 0 | } |
8810 | 25.9k | } else { |
8811 | 25.9k | if (has_flg(ESCAPE_SLASHES)) { |
8812 | 0 | return enc_table_cpy_slash; |
8813 | 25.9k | } else { |
8814 | 25.9k | return enc_table_cpy; |
8815 | 25.9k | } |
8816 | 25.9k | } |
8817 | 38.3k | } |
8818 | | |
8819 | | /** Write raw string. */ |
8820 | 0 | static_inline u8 *write_raw(u8 *cur, const u8 *raw, usize raw_len) { |
8821 | 0 | memcpy(cur, raw, raw_len); |
8822 | 0 | return cur + raw_len; |
8823 | 0 | } |
8824 | | |
8825 | | /** |
8826 | | Write string no-escape. |
8827 | | @param cur Buffer cursor. |
8828 | | @param str A UTF-8 string, null-terminator is not required. |
8829 | | @param str_len Length of string in bytes. |
8830 | | @return The buffer cursor after string. |
8831 | | */ |
8832 | 21.7M | static_inline u8 *write_str_noesc(u8 *cur, const u8 *str, usize str_len) { |
8833 | 21.7M | *cur++ = '"'; |
8834 | 43.9M | while (str_len >= 16) { |
8835 | 22.1M | byte_copy_16(cur, str); |
8836 | 22.1M | cur += 16; |
8837 | 22.1M | str += 16; |
8838 | 22.1M | str_len -= 16; |
8839 | 22.1M | } |
8840 | 33.5M | while (str_len >= 4) { |
8841 | 11.7M | byte_copy_4(cur, str); |
8842 | 11.7M | cur += 4; |
8843 | 11.7M | str += 4; |
8844 | 11.7M | str_len -= 4; |
8845 | 11.7M | } |
8846 | 49.3M | while (str_len) { |
8847 | 27.5M | *cur++ = *str++; |
8848 | 27.5M | str_len -= 1; |
8849 | 27.5M | } |
8850 | 21.7M | *cur++ = '"'; |
8851 | 21.7M | return cur; |
8852 | 21.7M | } |
8853 | | |
8854 | | /** |
8855 | | Write UTF-8 string (requires len * 6 + 2 bytes buffer). |
8856 | | @param cur Buffer cursor. |
8857 | | @param esc Escape unicode. |
8858 | | @param inv Allow invalid unicode. |
8859 | | @param str A UTF-8 string, null-terminator is not required. |
8860 | | @param str_len Length of string in bytes. |
8861 | | @param enc_table Encode type table for character. |
8862 | | @return The buffer cursor after string, or NULL on invalid unicode. |
8863 | | */ |
8864 | | static_inline u8 *write_str(u8 *cur, bool esc, bool inv, |
8865 | | const u8 *str, usize str_len, |
8866 | | const char_enc_type *enc_table, |
8867 | 28.6M | const u8 *hex_table) { |
8868 | | /* The replacement character U+FFFD, used to indicate invalid character. |
8869 | | Looked up via hex_table so that LOWERCASE_HEX produces "fffd" while |
8870 | | the default produces "FFFD". */ |
8871 | 28.6M | const v32 pre = {{ '\\', 'u', '0', '0' }}; |
8872 | | |
8873 | 28.6M | const u8 *src = str; |
8874 | 28.6M | const u8 *end = str + str_len; |
8875 | 28.6M | *cur++ = '"'; |
8876 | | |
8877 | 67.1M | copy_ascii: |
8878 | | /* |
8879 | | Copy continuous ASCII, loop unrolling, same as the following code: |
8880 | | |
8881 | | while (end > src) ( |
8882 | | if (unlikely(enc_table[*src])) break; |
8883 | | *cur++ = *src++; |
8884 | | ); |
8885 | | */ |
8886 | 67.1M | #define expr_jump(i) \ |
8887 | 289M | if (unlikely(enc_table[src[i]])) goto stop_char_##i; |
8888 | | |
8889 | 67.1M | #define expr_stop(i) \ |
8890 | 67.1M | stop_char_##i: \ |
8891 | 41.1M | memcpy(cur, src, i); \ |
8892 | 41.1M | cur += i; src += i; goto copy_utf8; |
8893 | | |
8894 | 75.4M | while (end - src >= 16) { |
8895 | 219M | repeat16_incr(expr_jump) |
8896 | 8.28M | byte_copy_16(cur, src); |
8897 | 8.28M | cur += 16; src += 16; |
8898 | 8.28M | } |
8899 | | |
8900 | 52.7M | while (end - src >= 4) { |
8901 | 43.0M | repeat4_incr(expr_jump) |
8902 | 6.29M | byte_copy_4(cur, src); |
8903 | 6.29M | cur += 4; src += 4; |
8904 | 6.29M | } |
8905 | | |
8906 | 53.2M | while (end > src) { |
8907 | 27.1M | expr_jump(0) |
8908 | 21.7M | *cur++ = *src++; |
8909 | 21.7M | } |
8910 | | |
8911 | 26.0M | *cur++ = '"'; |
8912 | 26.0M | return cur; |
8913 | | |
8914 | 41.1M | repeat16_incr(expr_stop) |
8915 | | |
8916 | 0 | #undef expr_jump |
8917 | 0 | #undef expr_stop |
8918 | | |
8919 | 670M | copy_utf8: |
8920 | 670M | if (unlikely(src + 4 > end)) { |
8921 | 46.9M | if (end == src) goto copy_end; |
8922 | 44.3M | if (end - src < enc_table[*src] / 2) goto err_one; |
8923 | 44.3M | } |
8924 | 668M | switch (enc_table[*src]) { |
8925 | 38.5M | case CHAR_ENC_CPY_1: { |
8926 | 38.5M | *cur++ = *src++; |
8927 | 38.5M | goto copy_ascii; |
8928 | 0 | } |
8929 | 1.26M | case CHAR_ENC_CPY_2: { |
8930 | | #if YYJSON_DISABLE_UTF8_VALIDATION |
8931 | | byte_copy_2(cur, src); |
8932 | | #else |
8933 | 1.26M | u32 uni = 0; |
8934 | 1.26M | byte_copy_2(&uni, src); |
8935 | 1.26M | if (unlikely(!is_utf8_seq2(uni))) goto err_cpy; |
8936 | 1.26M | byte_copy_2(cur, &uni); |
8937 | 1.26M | #endif |
8938 | 1.26M | cur += 2; |
8939 | 1.26M | src += 2; |
8940 | 1.26M | goto copy_utf8; |
8941 | 1.26M | } |
8942 | 527k | case CHAR_ENC_CPY_3: { |
8943 | | #if YYJSON_DISABLE_UTF8_VALIDATION |
8944 | | if (likely(src + 4 <= end)) { |
8945 | | byte_copy_4(cur, src); |
8946 | | } else { |
8947 | | byte_copy_2(cur, src); |
8948 | | cur[2] = src[2]; |
8949 | | } |
8950 | | #else |
8951 | 527k | u32 uni, tmp; |
8952 | 527k | if (likely(src + 4 <= end)) { |
8953 | 526k | uni = byte_load_4(src); |
8954 | 526k | if (unlikely(!is_utf8_seq3(uni))) goto err_cpy; |
8955 | 526k | byte_copy_4(cur, src); |
8956 | 526k | } else { |
8957 | 1.37k | uni = byte_load_3(src); |
8958 | 1.37k | if (unlikely(!is_utf8_seq3(uni))) goto err_cpy; |
8959 | 1.23k | byte_copy_4(cur, &uni); |
8960 | 1.23k | } |
8961 | 527k | #endif |
8962 | 527k | cur += 3; |
8963 | 527k | src += 3; |
8964 | 527k | goto copy_utf8; |
8965 | 527k | } |
8966 | 1.51M | case CHAR_ENC_CPY_4: { |
8967 | | #if YYJSON_DISABLE_UTF8_VALIDATION |
8968 | | byte_copy_4(cur, src); |
8969 | | #else |
8970 | 1.51M | u32 uni, tmp; |
8971 | 1.51M | uni = byte_load_4(src); |
8972 | 1.51M | if (unlikely(!is_utf8_seq4(uni))) goto err_cpy; |
8973 | 1.51M | byte_copy_4(cur, src); |
8974 | 1.51M | #endif |
8975 | 1.51M | cur += 4; |
8976 | 1.51M | src += 4; |
8977 | 1.51M | goto copy_utf8; |
8978 | 1.51M | } |
8979 | 137M | case CHAR_ENC_ESC_A: { |
8980 | 137M | byte_copy_2(cur, &esc_single_char_table[*src * 2]); |
8981 | 137M | cur += 2; |
8982 | 137M | src += 1; |
8983 | 137M | goto copy_utf8; |
8984 | 1.51M | } |
8985 | 487M | case CHAR_ENC_ESC_1: { |
8986 | 487M | byte_copy_4(cur + 0, &pre); |
8987 | 487M | byte_copy_2(cur + 4, &hex_table[*src * 2]); |
8988 | 487M | cur += 6; |
8989 | 487M | src += 1; |
8990 | 487M | goto copy_utf8; |
8991 | 1.51M | } |
8992 | 1.35M | case CHAR_ENC_ESC_2: { |
8993 | 1.35M | u16 u; |
8994 | 1.35M | #if !YYJSON_DISABLE_UTF8_VALIDATION |
8995 | 1.35M | u32 v4 = 0; |
8996 | 1.35M | u16 v2 = byte_load_2(src); |
8997 | 1.35M | byte_copy_2(&v4, &v2); |
8998 | 1.35M | if (unlikely(!is_utf8_seq2(v4))) goto err_esc; |
8999 | 1.35M | #endif |
9000 | 1.35M | u = (u16)(((u16)(src[0] & 0x1F) << 6) | |
9001 | 1.35M | ((u16)(src[1] & 0x3F) << 0)); |
9002 | 1.35M | byte_copy_2(cur + 0, &pre); |
9003 | 1.35M | byte_copy_2(cur + 2, &hex_table[(u >> 8) * 2]); |
9004 | 1.35M | byte_copy_2(cur + 4, &hex_table[(u & 0xFF) * 2]); |
9005 | 1.35M | cur += 6; |
9006 | 1.35M | src += 2; |
9007 | 1.35M | goto copy_utf8; |
9008 | 1.35M | } |
9009 | 12.2k | case CHAR_ENC_ESC_3: { |
9010 | 12.2k | u16 u; |
9011 | 12.2k | u32 v, tmp; |
9012 | 12.2k | #if !YYJSON_DISABLE_UTF8_VALIDATION |
9013 | 12.2k | v = byte_load_3(src); |
9014 | 12.2k | if (unlikely(!is_utf8_seq3(v))) goto err_esc; |
9015 | 12.2k | #endif |
9016 | 12.2k | u = (u16)(((u16)(src[0] & 0x0F) << 12) | |
9017 | 12.2k | ((u16)(src[1] & 0x3F) << 6) | |
9018 | 12.2k | ((u16)(src[2] & 0x3F) << 0)); |
9019 | 12.2k | byte_copy_2(cur + 0, &pre); |
9020 | 12.2k | byte_copy_2(cur + 2, &hex_table[(u >> 8) * 2]); |
9021 | 12.2k | byte_copy_2(cur + 4, &hex_table[(u & 0xFF) * 2]); |
9022 | 12.2k | cur += 6; |
9023 | 12.2k | src += 3; |
9024 | 12.2k | goto copy_utf8; |
9025 | 12.2k | } |
9026 | 39.4k | case CHAR_ENC_ESC_4: { |
9027 | 39.4k | u32 hi, lo, u, v, tmp; |
9028 | 39.4k | #if !YYJSON_DISABLE_UTF8_VALIDATION |
9029 | 39.4k | v = byte_load_4(src); |
9030 | 39.4k | if (unlikely(!is_utf8_seq4(v))) goto err_esc; |
9031 | 39.4k | #endif |
9032 | 39.4k | u = ((u32)(src[0] & 0x07) << 18) | |
9033 | 39.4k | ((u32)(src[1] & 0x3F) << 12) | |
9034 | 39.4k | ((u32)(src[2] & 0x3F) << 6) | |
9035 | 39.4k | ((u32)(src[3] & 0x3F) << 0); |
9036 | 39.4k | u -= 0x10000; |
9037 | 39.4k | hi = (u >> 10) + 0xD800; |
9038 | 39.4k | lo = (u & 0x3FF) + 0xDC00; |
9039 | 39.4k | byte_copy_2(cur + 0, &pre); |
9040 | 39.4k | byte_copy_2(cur + 2, &hex_table[(hi >> 8) * 2]); |
9041 | 39.4k | byte_copy_2(cur + 4, &hex_table[(hi & 0xFF) * 2]); |
9042 | 39.4k | byte_copy_2(cur + 6, &pre); |
9043 | 39.4k | byte_copy_2(cur + 8, &hex_table[(lo >> 8) * 2]); |
9044 | 39.4k | byte_copy_2(cur + 10, &hex_table[(lo & 0xFF) * 2]); |
9045 | 39.4k | cur += 12; |
9046 | 39.4k | src += 4; |
9047 | 39.4k | goto copy_utf8; |
9048 | 39.4k | } |
9049 | 863 | case CHAR_ENC_ERR_1: { |
9050 | 863 | goto err_one; |
9051 | 39.4k | } |
9052 | 0 | default: break; /* unreachable */ |
9053 | 668M | } |
9054 | | |
9055 | 2.59M | copy_end: |
9056 | 2.59M | *cur++ = '"'; |
9057 | 2.59M | return cur; |
9058 | | |
9059 | 942 | err_one: |
9060 | 942 | if (esc) goto err_esc; |
9061 | 942 | else goto err_cpy; |
9062 | | |
9063 | 1.63k | err_cpy: |
9064 | 1.63k | if (!inv) return NULL; |
9065 | 0 | *cur++ = *src++; |
9066 | 0 | goto copy_utf8; |
9067 | | |
9068 | 0 | err_esc: |
9069 | 0 | if (!inv) return NULL; |
9070 | 0 | byte_copy_2(cur + 0, &pre); |
9071 | | /* U+FFFD = 0xFFFD, written as two pairs from hex_table so that |
9072 | | LOWERCASE_HEX produces "fffd". Replaces a single byte_copy_4 |
9073 | | from a hardcoded uppercase "FFFD" v32; same total output, one |
9074 | | extra load on the (rare) invalid-UTF-8-with-ALLOW path. */ |
9075 | 0 | byte_copy_2(cur + 2, &hex_table[0xFF * 2]); |
9076 | 0 | byte_copy_2(cur + 4, &hex_table[0xFD * 2]); |
9077 | 0 | cur += 6; |
9078 | 0 | src += 1; |
9079 | 0 | goto copy_utf8; |
9080 | 0 | } |
9081 | | |
9082 | | |
9083 | | |
9084 | | /*============================================================================== |
9085 | | * MARK: - JSON Writer Utilities (Private) |
9086 | | *============================================================================*/ |
9087 | | |
9088 | | /** Write null (requires 8 bytes buffer). */ |
9089 | 263k | static_inline u8 *write_null(u8 *cur) { |
9090 | 263k | v64 v = {{ 'n', 'u', 'l', 'l', ',', '\n', 0, 0 }}; |
9091 | 263k | byte_copy_8(cur, &v); |
9092 | 263k | return cur + 4; |
9093 | 263k | } |
9094 | | |
9095 | | /** Write bool (requires 8 bytes buffer). */ |
9096 | 407k | static_inline u8 *write_bool(u8 *cur, bool val) { |
9097 | 407k | v64 v0 = {{ 'f', 'a', 'l', 's', 'e', ',', '\n', 0 }}; |
9098 | 407k | v64 v1 = {{ 't', 'r', 'u', 'e', ',', '\n', 0, 0 }}; |
9099 | 407k | if (val) { |
9100 | 334k | byte_copy_8(cur, &v1); |
9101 | 334k | } else { |
9102 | 73.2k | byte_copy_8(cur, &v0); |
9103 | 73.2k | } |
9104 | 407k | return cur + 5 - val; |
9105 | 407k | } |
9106 | | |
9107 | | /** Write indent (requires level x 4 bytes buffer). |
9108 | | Param spaces should not larger than 4. */ |
9109 | 7.21M | static_inline u8 *write_indent(u8 *cur, usize level, usize spaces) { |
9110 | 7.38G | while (level-- > 0) { |
9111 | 7.37G | byte_copy_4(cur, " "); |
9112 | 7.37G | cur += spaces; |
9113 | 7.37G | } |
9114 | 7.21M | return cur; |
9115 | 7.21M | } |
9116 | | |
9117 | | #if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE |
9118 | | |
9119 | | /** Write data to file pointer. */ |
9120 | | static bool write_dat_to_fp(FILE *fp, u8 *dat, usize len, |
9121 | 0 | yyjson_write_err *err) { |
9122 | 0 | if (fwrite(dat, 1, len, fp) != len) { |
9123 | 0 | err->msg = "file writing failed"; |
9124 | 0 | err->code = YYJSON_WRITE_ERROR_FILE_WRITE; |
9125 | 0 | return false; |
9126 | 0 | } |
9127 | 0 | return true; |
9128 | 0 | } |
9129 | | |
9130 | | /** Write data to file. */ |
9131 | | static bool write_dat_to_file(const char *path, u8 *dat, usize len, |
9132 | 0 | yyjson_write_err *err) { |
9133 | 0 | #define return_err(_code, _msg) do { \ |
9134 | 0 | err->msg = _msg; \ |
9135 | 0 | err->code = YYJSON_WRITE_ERROR_##_code; \ |
9136 | 0 | if (file) fclose(file); \ |
9137 | 0 | return false; \ |
9138 | 0 | } while (false) |
9139 | |
|
9140 | 0 | FILE *file = fopen_writeonly(path); |
9141 | 0 | if (file == NULL) { |
9142 | 0 | return_err(FILE_OPEN, MSG_FOPEN); |
9143 | 0 | } |
9144 | 0 | if (fwrite(dat, 1, len, file) != len) { |
9145 | 0 | return_err(FILE_WRITE, MSG_FWRITE); |
9146 | 0 | } |
9147 | 0 | if (fclose(file) != 0) { |
9148 | 0 | file = NULL; |
9149 | 0 | return_err(FILE_WRITE, MSG_FCLOSE); |
9150 | 0 | } |
9151 | 0 | return true; |
9152 | |
|
9153 | 0 | #undef return_err |
9154 | 0 | } |
9155 | | |
9156 | | #endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */ |
9157 | | |
9158 | | |
9159 | | |
9160 | | /*============================================================================== |
9161 | | * MARK: - JSON Writer Implementation (Private) |
9162 | | *============================================================================*/ |
9163 | | |
9164 | | typedef struct yyjson_write_ctx { |
9165 | | usize tag; |
9166 | | } yyjson_write_ctx; |
9167 | | |
9168 | | static_inline void yyjson_write_ctx_set(yyjson_write_ctx *ctx, |
9169 | 534k | usize size, bool is_obj) { |
9170 | 534k | ctx->tag = (size << 1) | (usize)is_obj; |
9171 | 534k | } |
9172 | | |
9173 | | static_inline void yyjson_write_ctx_get(yyjson_write_ctx *ctx, |
9174 | 184k | usize *size, bool *is_obj) { |
9175 | 184k | usize tag = ctx->tag; |
9176 | 184k | *size = tag >> 1; |
9177 | 184k | *is_obj = (bool)(tag & 1); |
9178 | 184k | } |
9179 | | |
9180 | | /** Write single JSON value. */ |
9181 | | static_inline u8 *write_root_single(yyjson_val *val, |
9182 | | yyjson_write_flag flg, |
9183 | | yyjson_alc alc, |
9184 | | char *buf, usize *dat_len, |
9185 | 22.1k | yyjson_write_err *err) { |
9186 | 22.1k | #define return_err(_code, _msg) do { \ |
9187 | 502 | if (hdr) alc.free(alc.ctx, (void *)hdr); \ |
9188 | 502 | *dat_len = 0; \ |
9189 | 502 | err->code = YYJSON_WRITE_ERROR_##_code; \ |
9190 | 502 | err->msg = _msg; \ |
9191 | 502 | return NULL; \ |
9192 | 502 | } while (false) |
9193 | | |
9194 | 22.1k | #define incr_len(_len) do { \ |
9195 | 22.1k | if (buf) hdr = *dat_len >= _len ? (u8 *)buf : (u8 *)NULL; \ |
9196 | 22.1k | else hdr = (u8 *)alc.malloc(alc.ctx, _len); \ |
9197 | 22.1k | if (!hdr) goto fail_alloc; \ |
9198 | 22.1k | cur = hdr; \ |
9199 | 22.1k | } while (false) |
9200 | | |
9201 | 22.1k | #define check_str_len(_len) do { \ |
9202 | 2.59k | if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \ |
9203 | 2.59k | goto fail_alloc; \ |
9204 | 2.59k | } while (false) |
9205 | | |
9206 | 22.1k | u8 *hdr = NULL, *cur; |
9207 | 22.1k | usize str_len; |
9208 | 22.1k | const u8 *str_ptr; |
9209 | 22.1k | const char_enc_type *enc_table = get_enc_table_with_flag(flg); |
9210 | 22.1k | const u8 *hex_table = get_hex_table_with_flag(flg); |
9211 | 22.1k | bool cpy = (enc_table == enc_table_cpy); |
9212 | 22.1k | bool esc = has_flg(ESCAPE_UNICODE) != 0; |
9213 | 22.1k | bool inv = has_allow(INVALID_UNICODE) != 0; |
9214 | 22.1k | bool newline = has_flg(NEWLINE_AT_END) != 0; |
9215 | 22.1k | const usize end_len = 2; /* '\n' and '\0' */ |
9216 | | |
9217 | 22.1k | switch (unsafe_yyjson_get_type(val)) { |
9218 | 0 | case YYJSON_TYPE_RAW: |
9219 | 0 | str_len = unsafe_yyjson_get_len(val); |
9220 | 0 | str_ptr = (const u8 *)unsafe_yyjson_get_str(val); |
9221 | 0 | check_str_len(str_len); |
9222 | 0 | incr_len(str_len + end_len); |
9223 | 0 | cur = write_raw(cur, str_ptr, str_len); |
9224 | 0 | break; |
9225 | | |
9226 | 2.59k | case YYJSON_TYPE_STR: |
9227 | 2.59k | str_len = unsafe_yyjson_get_len(val); |
9228 | 2.59k | str_ptr = (const u8 *)unsafe_yyjson_get_str(val); |
9229 | 2.59k | check_str_len(str_len); |
9230 | 2.59k | incr_len(str_len * 6 + 2 + end_len); |
9231 | 2.59k | if (likely(cpy) && unsafe_yyjson_get_subtype(val)) { |
9232 | 318 | cur = write_str_noesc(cur, str_ptr, str_len); |
9233 | 2.27k | } else { |
9234 | 2.27k | cur = write_str(cur, esc, inv, str_ptr, str_len, |
9235 | 2.27k | enc_table, hex_table); |
9236 | 2.27k | if (unlikely(!cur)) goto fail_str; |
9237 | 2.27k | } |
9238 | 2.09k | break; |
9239 | | |
9240 | 19.3k | case YYJSON_TYPE_NUM: |
9241 | 19.3k | incr_len(FP_BUF_LEN + end_len); |
9242 | 19.3k | cur = write_num(cur, val, flg); |
9243 | 19.3k | if (unlikely(!cur)) goto fail_num; |
9244 | 19.3k | break; |
9245 | | |
9246 | 19.3k | case YYJSON_TYPE_BOOL: |
9247 | 22 | incr_len(8); |
9248 | 22 | cur = write_bool(cur, unsafe_yyjson_get_bool(val)); |
9249 | 22 | break; |
9250 | | |
9251 | 12 | case YYJSON_TYPE_NULL: |
9252 | 12 | incr_len(8); |
9253 | 12 | cur = write_null(cur); |
9254 | 12 | break; |
9255 | | |
9256 | 108 | case YYJSON_TYPE_ARR: |
9257 | 108 | incr_len(2 + end_len); |
9258 | 108 | byte_copy_2(cur, "[]"); |
9259 | 108 | cur += 2; |
9260 | 108 | break; |
9261 | | |
9262 | 56 | case YYJSON_TYPE_OBJ: |
9263 | 56 | incr_len(2 + end_len); |
9264 | 56 | byte_copy_2(cur, "{}"); |
9265 | 56 | cur += 2; |
9266 | 56 | break; |
9267 | | |
9268 | 0 | default: |
9269 | 0 | goto fail_type; |
9270 | 22.1k | } |
9271 | | |
9272 | 21.6k | if (newline) *cur++ = '\n'; |
9273 | 21.6k | *cur = '\0'; |
9274 | 21.6k | *dat_len = (usize)(cur - hdr); |
9275 | 21.6k | memset(err, 0, sizeof(yyjson_write_err)); |
9276 | 21.6k | return hdr; |
9277 | | |
9278 | 0 | fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC); |
9279 | 0 | fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE); |
9280 | 0 | fail_num: return_err(NAN_OR_INF, MSG_NAN_INF); |
9281 | 502 | fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8); |
9282 | | |
9283 | 502 | #undef return_err |
9284 | 502 | #undef check_str_len |
9285 | 502 | #undef incr_len |
9286 | 502 | } |
9287 | | |
9288 | | /** Write JSON document minify. |
9289 | | The root of this document should be a non-empty container. */ |
9290 | | static_inline u8 *write_root_minify(const yyjson_val *root, |
9291 | | const yyjson_write_flag flg, |
9292 | | const yyjson_alc alc, |
9293 | | char *buf, usize *dat_len, |
9294 | 2.00k | yyjson_write_err *err) { |
9295 | 2.00k | #define return_err(_code, _msg) do { \ |
9296 | 0 | *dat_len = 0; \ |
9297 | 0 | err->code = YYJSON_WRITE_ERROR_##_code; \ |
9298 | 0 | err->msg = _msg; \ |
9299 | 0 | if (hdr) alc.free(alc.ctx, hdr); \ |
9300 | 0 | return NULL; \ |
9301 | 0 | } while (false) |
9302 | | |
9303 | 72.1k | #define incr_len(_len) do { \ |
9304 | 72.1k | ext_len = (usize)(_len); \ |
9305 | 72.1k | if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \ |
9306 | 464 | usize ctx_pos = (usize)((u8 *)ctx - hdr); \ |
9307 | 464 | usize cur_pos = (usize)(cur - hdr); \ |
9308 | 464 | yyjson_assume((u8 *)ctx <= (u8 *)end); \ |
9309 | 464 | ctx_len = (usize)((u8 *)end - (u8 *)ctx); \ |
9310 | 464 | alc_inc = yyjson_max(alc_len / 2, ext_len); \ |
9311 | 464 | alc_inc = size_align_up(alc_inc, sizeof(yyjson_write_ctx)); \ |
9312 | 464 | if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \ |
9313 | 464 | goto fail_alloc; \ |
9314 | 464 | alc_len += alc_inc; \ |
9315 | 464 | tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \ |
9316 | 464 | if (unlikely(!tmp)) goto fail_alloc; \ |
9317 | 464 | ctx_tmp = (yyjson_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \ |
9318 | 464 | memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \ |
9319 | 464 | ctx = ctx_tmp; \ |
9320 | 464 | cur = tmp + cur_pos; \ |
9321 | 464 | end = tmp + alc_len; \ |
9322 | 464 | hdr = tmp; \ |
9323 | 464 | } \ |
9324 | 72.1k | } while (false) |
9325 | | |
9326 | 25.0k | #define check_str_len(_len) do { \ |
9327 | 25.0k | if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \ |
9328 | 25.0k | goto fail_alloc; \ |
9329 | 25.0k | } while (false) |
9330 | | |
9331 | 2.00k | yyjson_val *val; |
9332 | 2.00k | yyjson_type val_type; |
9333 | 2.00k | usize ctn_len, ctn_len_tmp; |
9334 | 2.00k | bool ctn_obj, ctn_obj_tmp, is_key; |
9335 | 2.00k | u8 *hdr, *cur, *end, *tmp; |
9336 | 2.00k | yyjson_write_ctx *ctx, *ctx_tmp; |
9337 | 2.00k | usize alc_len, alc_inc, ctx_len, ext_len, str_len; |
9338 | 2.00k | const u8 *str_ptr; |
9339 | 2.00k | const char_enc_type *enc_table = get_enc_table_with_flag(flg); |
9340 | 2.00k | const u8 *hex_table = get_hex_table_with_flag(flg); |
9341 | 2.00k | bool cpy = (enc_table == enc_table_cpy); |
9342 | 2.00k | bool esc = has_flg(ESCAPE_UNICODE) != 0; |
9343 | 2.00k | bool inv = has_allow(INVALID_UNICODE) != 0; |
9344 | 2.00k | bool newline = has_flg(NEWLINE_AT_END) != 0; |
9345 | | |
9346 | 2.00k | if (buf) { |
9347 | 0 | hdr = (u8 *)buf; |
9348 | 0 | alc_len = *dat_len; |
9349 | 0 | alc_len = size_align_down(alc_len, sizeof(yyjson_write_ctx)); |
9350 | 0 | if (alc_len <= sizeof(yyjson_write_ctx)) goto fail_alloc; |
9351 | 2.00k | } else { |
9352 | 2.00k | alc_len = root->uni.ofs / sizeof(yyjson_val); |
9353 | 2.00k | alc_len = alc_len * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64; |
9354 | 2.00k | alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx)); |
9355 | 2.00k | hdr = (u8 *)alc.malloc(alc.ctx, alc_len); |
9356 | 2.00k | if (!hdr) goto fail_alloc; |
9357 | 2.00k | } |
9358 | 2.00k | cur = hdr; |
9359 | 2.00k | end = hdr + alc_len; |
9360 | 2.00k | ctx = (yyjson_write_ctx *)(void *)end; |
9361 | | |
9362 | 2.00k | doc_begin: |
9363 | 2.00k | val = constcast(yyjson_val *)root; |
9364 | 2.00k | val_type = unsafe_yyjson_get_type(val); |
9365 | 2.00k | ctn_obj = (val_type == YYJSON_TYPE_OBJ); |
9366 | 2.00k | ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj; |
9367 | 2.00k | *cur++ = (u8)('[' | ((u8)ctn_obj << 5)); |
9368 | 2.00k | val++; |
9369 | | |
9370 | 72.1k | val_begin: |
9371 | 72.1k | val_type = unsafe_yyjson_get_type(val); |
9372 | 72.1k | if (val_type == YYJSON_TYPE_STR) { |
9373 | 25.0k | is_key = ((u8)ctn_obj & (u8)~ctn_len); |
9374 | 25.0k | str_len = unsafe_yyjson_get_len(val); |
9375 | 25.0k | str_ptr = (const u8 *)unsafe_yyjson_get_str(val); |
9376 | 25.0k | check_str_len(str_len); |
9377 | 25.0k | incr_len(str_len * 6 + 16); |
9378 | 25.0k | if (likely(cpy) && unsafe_yyjson_get_subtype(val)) { |
9379 | 13.6k | cur = write_str_noesc(cur, str_ptr, str_len); |
9380 | 13.6k | } else { |
9381 | 11.3k | cur = write_str(cur, esc, inv, str_ptr, str_len, |
9382 | 11.3k | enc_table, hex_table); |
9383 | 11.3k | if (unlikely(!cur)) goto fail_str; |
9384 | 11.3k | } |
9385 | 25.0k | *cur++ = is_key ? ':' : ','; |
9386 | 25.0k | goto val_end; |
9387 | 25.0k | } |
9388 | 47.1k | if (val_type == YYJSON_TYPE_NUM) { |
9389 | 37.4k | incr_len(FP_BUF_LEN); |
9390 | 37.4k | cur = write_num(cur, val, flg); |
9391 | 37.4k | if (unlikely(!cur)) goto fail_num; |
9392 | 37.4k | *cur++ = ','; |
9393 | 37.4k | goto val_end; |
9394 | 37.4k | } |
9395 | 9.62k | if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) == |
9396 | 9.62k | (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) { |
9397 | 7.53k | ctn_len_tmp = unsafe_yyjson_get_len(val); |
9398 | 7.53k | ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ); |
9399 | 7.53k | incr_len(2 * sizeof(*ctx)); |
9400 | 7.53k | if (unlikely(ctn_len_tmp == 0)) { |
9401 | | /* write empty container */ |
9402 | 1.44k | *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5)); |
9403 | 1.44k | *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5)); |
9404 | 1.44k | *cur++ = ','; |
9405 | 1.44k | goto val_end; |
9406 | 6.08k | } else { |
9407 | | /* push context, setup new container */ |
9408 | 6.08k | yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj); |
9409 | 6.08k | ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp; |
9410 | 6.08k | ctn_obj = ctn_obj_tmp; |
9411 | 6.08k | *cur++ = (u8)('[' | ((u8)ctn_obj << 5)); |
9412 | 6.08k | val++; |
9413 | 6.08k | goto val_begin; |
9414 | 6.08k | } |
9415 | 7.53k | } |
9416 | 2.09k | if (val_type == YYJSON_TYPE_BOOL) { |
9417 | 1.40k | incr_len(16); |
9418 | 1.40k | cur = write_bool(cur, unsafe_yyjson_get_bool(val)); |
9419 | 1.40k | cur++; |
9420 | 1.40k | goto val_end; |
9421 | 1.40k | } |
9422 | 683 | if (val_type == YYJSON_TYPE_NULL) { |
9423 | 683 | incr_len(16); |
9424 | 683 | cur = write_null(cur); |
9425 | 683 | cur++; |
9426 | 683 | goto val_end; |
9427 | 683 | } |
9428 | 0 | if (val_type == YYJSON_TYPE_RAW) { |
9429 | 0 | str_len = unsafe_yyjson_get_len(val); |
9430 | 0 | str_ptr = (const u8 *)unsafe_yyjson_get_str(val); |
9431 | 0 | check_str_len(str_len); |
9432 | 0 | incr_len(str_len + 2); |
9433 | 0 | cur = write_raw(cur, str_ptr, str_len); |
9434 | 0 | *cur++ = ','; |
9435 | 0 | goto val_end; |
9436 | 0 | } |
9437 | 0 | goto fail_type; |
9438 | | |
9439 | 66.0k | val_end: |
9440 | 66.0k | val++; |
9441 | 66.0k | ctn_len--; |
9442 | 66.0k | if (unlikely(ctn_len == 0)) goto ctn_end; |
9443 | 63.3k | goto val_begin; |
9444 | | |
9445 | 63.3k | ctn_end: |
9446 | 8.09k | cur--; |
9447 | 8.09k | *cur++ = (u8)(']' | ((u8)ctn_obj << 5)); |
9448 | 8.09k | *cur++ = ','; |
9449 | 8.09k | if (unlikely((u8 *)ctx >= end)) goto doc_end; |
9450 | 6.08k | yyjson_write_ctx_get(ctx++, &ctn_len, &ctn_obj); |
9451 | 6.08k | ctn_len--; |
9452 | 6.08k | if (likely(ctn_len > 0)) { |
9453 | 664 | goto val_begin; |
9454 | 5.42k | } else { |
9455 | 5.42k | goto ctn_end; |
9456 | 5.42k | } |
9457 | | |
9458 | 2.00k | doc_end: |
9459 | 2.00k | if (newline) { |
9460 | 0 | incr_len(2); |
9461 | 0 | *(cur - 1) = '\n'; |
9462 | 0 | cur++; |
9463 | 0 | } |
9464 | 2.00k | *--cur = '\0'; |
9465 | 2.00k | *dat_len = (usize)(cur - hdr); |
9466 | 2.00k | memset(err, 0, sizeof(yyjson_write_err)); |
9467 | 2.00k | return hdr; |
9468 | | |
9469 | 0 | fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC); |
9470 | 0 | fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE); |
9471 | 0 | fail_num: return_err(NAN_OR_INF, MSG_NAN_INF); |
9472 | 0 | fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8); |
9473 | |
|
9474 | 0 | #undef return_err |
9475 | 0 | #undef incr_len |
9476 | 0 | #undef check_str_len |
9477 | 0 | } |
9478 | | |
9479 | | /** Write JSON document pretty. |
9480 | | The root of this document should be a non-empty container. */ |
9481 | | static_inline u8 *write_root_pretty(const yyjson_val *root, |
9482 | | const yyjson_write_flag flg, |
9483 | | const yyjson_alc alc, |
9484 | | char *buf, usize *dat_len, |
9485 | 2.55k | yyjson_write_err *err) { |
9486 | 2.55k | #define return_err(_code, _msg) do { \ |
9487 | 23 | *dat_len = 0; \ |
9488 | 23 | err->code = YYJSON_WRITE_ERROR_##_code; \ |
9489 | 23 | err->msg = _msg; \ |
9490 | 23 | if (hdr) alc.free(alc.ctx, hdr); \ |
9491 | 23 | return NULL; \ |
9492 | 23 | } while (false) |
9493 | | |
9494 | 3.60M | #define incr_len(_len) do { \ |
9495 | 6.85M | ext_len = (usize)(_len); \ |
9496 | 3.60M | if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \ |
9497 | 2.24k | usize ctx_pos = (usize)((u8 *)ctx - hdr); \ |
9498 | 2.24k | usize cur_pos = (usize)(cur - hdr); \ |
9499 | 2.24k | yyjson_assume((u8 *)ctx <= (u8 *)end); \ |
9500 | 2.24k | ctx_len = (usize)((u8 *)end - (u8 *)ctx); \ |
9501 | 2.24k | alc_inc = yyjson_max(alc_len / 2, ext_len); \ |
9502 | 2.24k | alc_inc = size_align_up(alc_inc, sizeof(yyjson_write_ctx)); \ |
9503 | 2.24k | if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \ |
9504 | 2.24k | goto fail_alloc; \ |
9505 | 2.24k | alc_len += alc_inc; \ |
9506 | 2.24k | tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \ |
9507 | 2.24k | if (unlikely(!tmp)) goto fail_alloc; \ |
9508 | 2.24k | ctx_tmp = (yyjson_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \ |
9509 | 2.22k | memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \ |
9510 | 2.22k | ctx = ctx_tmp; \ |
9511 | 2.22k | cur = tmp + cur_pos; \ |
9512 | 2.22k | end = tmp + alc_len; \ |
9513 | 2.22k | hdr = tmp; \ |
9514 | 2.22k | } \ |
9515 | 3.60M | } while (false) |
9516 | | |
9517 | 40.2k | #define check_str_len(_len) do { \ |
9518 | 40.2k | if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \ |
9519 | 40.2k | goto fail_alloc; \ |
9520 | 40.2k | } while (false) |
9521 | | |
9522 | 2.55k | yyjson_val *val; |
9523 | 2.55k | yyjson_type val_type; |
9524 | 2.55k | usize ctn_len, ctn_len_tmp; |
9525 | 2.55k | bool ctn_obj, ctn_obj_tmp, is_key, no_indent; |
9526 | 2.55k | u8 *hdr, *cur, *end, *tmp; |
9527 | 2.55k | yyjson_write_ctx *ctx, *ctx_tmp; |
9528 | 2.55k | usize alc_len, alc_inc, ctx_len, ext_len, str_len, level; |
9529 | 2.55k | const u8 *str_ptr; |
9530 | 2.55k | const char_enc_type *enc_table = get_enc_table_with_flag(flg); |
9531 | 2.55k | const u8 *hex_table = get_hex_table_with_flag(flg); |
9532 | 2.55k | bool cpy = (enc_table == enc_table_cpy); |
9533 | 2.55k | bool esc = has_flg(ESCAPE_UNICODE) != 0; |
9534 | 2.55k | bool inv = has_allow(INVALID_UNICODE) != 0; |
9535 | 2.55k | usize spaces = has_flg(PRETTY_TWO_SPACES) ? 2 : 4; |
9536 | 2.55k | bool newline = has_flg(NEWLINE_AT_END) != 0; |
9537 | | |
9538 | 2.55k | if (buf) { |
9539 | 0 | hdr = (u8 *)buf; |
9540 | 0 | alc_len = *dat_len; |
9541 | 0 | alc_len = size_align_down(alc_len, sizeof(yyjson_write_ctx)); |
9542 | 0 | if (alc_len <= sizeof(yyjson_write_ctx)) goto fail_alloc; |
9543 | 2.55k | } else { |
9544 | 2.55k | alc_len = root->uni.ofs / sizeof(yyjson_val); |
9545 | 2.55k | alc_len = alc_len * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64; |
9546 | 2.55k | alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx)); |
9547 | 2.55k | hdr = (u8 *)alc.malloc(alc.ctx, alc_len); |
9548 | 2.55k | if (!hdr) goto fail_alloc; |
9549 | 2.55k | } |
9550 | 2.55k | cur = hdr; |
9551 | 2.55k | end = hdr + alc_len; |
9552 | 2.55k | ctx = (yyjson_write_ctx *)(void *)end; |
9553 | | |
9554 | 2.55k | doc_begin: |
9555 | 2.55k | val = constcast(yyjson_val *)root; |
9556 | 2.55k | val_type = unsafe_yyjson_get_type(val); |
9557 | 2.55k | ctn_obj = (val_type == YYJSON_TYPE_OBJ); |
9558 | 2.55k | ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj; |
9559 | 2.55k | *cur++ = (u8)('[' | ((u8)ctn_obj << 5)); |
9560 | 2.55k | *cur++ = '\n'; |
9561 | 2.55k | val++; |
9562 | 2.55k | level = 1; |
9563 | | |
9564 | 3.42M | val_begin: |
9565 | 3.42M | val_type = unsafe_yyjson_get_type(val); |
9566 | 3.42M | if (val_type == YYJSON_TYPE_STR) { |
9567 | 40.2k | is_key = (bool)((u8)ctn_obj & (u8)~ctn_len); |
9568 | 40.2k | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
9569 | 40.2k | str_len = unsafe_yyjson_get_len(val); |
9570 | 40.2k | str_ptr = (const u8 *)unsafe_yyjson_get_str(val); |
9571 | 40.2k | check_str_len(str_len); |
9572 | 40.2k | if ((sizeof(usize) < 8) && !no_indent && |
9573 | 0 | level > (USIZE_MAX - 16 - str_len * 6) / 4) goto fail_alloc; |
9574 | 40.2k | incr_len(str_len * 6 + 16 + (no_indent ? 0 : level * 4)); |
9575 | 40.2k | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
9576 | 40.2k | if (likely(cpy) && unsafe_yyjson_get_subtype(val)) { |
9577 | 0 | cur = write_str_noesc(cur, str_ptr, str_len); |
9578 | 40.2k | } else { |
9579 | 40.2k | cur = write_str(cur, esc, inv, str_ptr, str_len, |
9580 | 40.2k | enc_table, hex_table); |
9581 | 40.2k | if (unlikely(!cur)) goto fail_str; |
9582 | 40.2k | } |
9583 | 40.2k | *cur++ = is_key ? ':' : ','; |
9584 | 40.2k | *cur++ = is_key ? ' ' : '\n'; |
9585 | 40.2k | goto val_end; |
9586 | 40.2k | } |
9587 | 3.38M | if (val_type == YYJSON_TYPE_NUM) { |
9588 | 2.31M | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
9589 | 2.31M | incr_len(FP_BUF_LEN + (no_indent ? 0 : level * 4)); |
9590 | 2.31M | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
9591 | 2.31M | cur = write_num(cur, val, flg); |
9592 | 2.31M | if (unlikely(!cur)) goto fail_num; |
9593 | 2.31M | *cur++ = ','; |
9594 | 2.31M | *cur++ = '\n'; |
9595 | 2.31M | goto val_end; |
9596 | 2.31M | } |
9597 | 1.07M | if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) == |
9598 | 1.07M | (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) { |
9599 | 876k | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
9600 | 876k | ctn_len_tmp = unsafe_yyjson_get_len(val); |
9601 | 876k | ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ); |
9602 | 876k | incr_len(2 * sizeof(*ctx) + (no_indent ? 0 : level * 4)); |
9603 | 876k | if (unlikely(ctn_len_tmp == 0)) { |
9604 | | /* write empty container */ |
9605 | 347k | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
9606 | 347k | *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5)); |
9607 | 347k | *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5)); |
9608 | 347k | *cur++ = ','; |
9609 | 347k | *cur++ = '\n'; |
9610 | 347k | goto val_end; |
9611 | 528k | } else { |
9612 | | /* push context, setup new container */ |
9613 | 528k | yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj); |
9614 | 528k | ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp; |
9615 | 528k | ctn_obj = ctn_obj_tmp; |
9616 | 528k | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
9617 | 528k | level++; |
9618 | 528k | *cur++ = (u8)('[' | ((u8)ctn_obj << 5)); |
9619 | 528k | *cur++ = '\n'; |
9620 | 528k | val++; |
9621 | 528k | goto val_begin; |
9622 | 528k | } |
9623 | 876k | } |
9624 | 195k | if (val_type == YYJSON_TYPE_BOOL) { |
9625 | 65.6k | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
9626 | 65.6k | incr_len(16 + (no_indent ? 0 : level * 4)); |
9627 | 65.6k | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
9628 | 65.6k | cur = write_bool(cur, unsafe_yyjson_get_bool(val)); |
9629 | 65.6k | cur += 2; |
9630 | 65.6k | goto val_end; |
9631 | 65.6k | } |
9632 | 130k | if (val_type == YYJSON_TYPE_NULL) { |
9633 | 130k | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
9634 | 130k | incr_len(16 + (no_indent ? 0 : level * 4)); |
9635 | 130k | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
9636 | 130k | cur = write_null(cur); |
9637 | 130k | cur += 2; |
9638 | 130k | goto val_end; |
9639 | 130k | } |
9640 | 0 | if (val_type == YYJSON_TYPE_RAW) { |
9641 | 0 | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
9642 | 0 | str_len = unsafe_yyjson_get_len(val); |
9643 | 0 | str_ptr = (const u8 *)unsafe_yyjson_get_str(val); |
9644 | 0 | check_str_len(str_len); |
9645 | 0 | incr_len(str_len + 3 + (no_indent ? 0 : level * 4)); |
9646 | 0 | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
9647 | 0 | cur = write_raw(cur, str_ptr, str_len); |
9648 | 0 | *cur++ = ','; |
9649 | 0 | *cur++ = '\n'; |
9650 | 0 | goto val_end; |
9651 | 0 | } |
9652 | 0 | goto fail_type; |
9653 | | |
9654 | 2.89M | val_end: |
9655 | 2.89M | val++; |
9656 | 2.89M | ctn_len--; |
9657 | 2.89M | if (unlikely(ctn_len == 0)) goto ctn_end; |
9658 | 2.76M | goto val_begin; |
9659 | | |
9660 | 2.76M | ctn_end: |
9661 | 180k | cur -= 2; |
9662 | 180k | *cur++ = '\n'; |
9663 | 180k | incr_len(level * 4); |
9664 | 180k | cur = write_indent(cur, --level, spaces); |
9665 | 180k | *cur++ = (u8)(']' | ((u8)ctn_obj << 5)); |
9666 | 180k | if (unlikely((u8 *)ctx >= end)) goto doc_end; |
9667 | 178k | yyjson_write_ctx_get(ctx++, &ctn_len, &ctn_obj); |
9668 | 178k | ctn_len--; |
9669 | 178k | *cur++ = ','; |
9670 | 178k | *cur++ = '\n'; |
9671 | 178k | if (likely(ctn_len > 0)) { |
9672 | 130k | goto val_begin; |
9673 | 130k | } else { |
9674 | 48.2k | goto ctn_end; |
9675 | 48.2k | } |
9676 | | |
9677 | 2.53k | doc_end: |
9678 | 2.53k | if (newline) { |
9679 | 0 | incr_len(2); |
9680 | 0 | *cur++ = '\n'; |
9681 | 0 | } |
9682 | 2.53k | *cur = '\0'; |
9683 | 2.53k | *dat_len = (usize)(cur - hdr); |
9684 | 2.53k | memset(err, 0, sizeof(yyjson_write_err)); |
9685 | 2.53k | return hdr; |
9686 | | |
9687 | 23 | fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC); |
9688 | 0 | fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE); |
9689 | 0 | fail_num: return_err(NAN_OR_INF, MSG_NAN_INF); |
9690 | 0 | fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8); |
9691 | |
|
9692 | 0 | #undef return_err |
9693 | 0 | #undef incr_len |
9694 | 0 | #undef check_str_len |
9695 | 0 | } |
9696 | | |
9697 | | static char *write_root(const yyjson_val *val, |
9698 | | yyjson_write_flag flg, |
9699 | | const yyjson_alc *alc_ptr, |
9700 | | char *buf, usize *dat_len, |
9701 | 49.2k | yyjson_write_err *err) { |
9702 | 49.2k | yyjson_write_err tmp_err; |
9703 | 49.2k | usize tmp_dat_len; |
9704 | 49.2k | yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC; |
9705 | 49.2k | yyjson_val *root = constcast(yyjson_val *)val; |
9706 | | |
9707 | 49.2k | if (!err) err = &tmp_err; |
9708 | 49.2k | if (!dat_len) dat_len = &tmp_dat_len; |
9709 | | |
9710 | 49.2k | if (unlikely(!root)) { |
9711 | 38.2k | *dat_len = 0; |
9712 | 38.2k | err->msg = "input JSON is NULL"; |
9713 | 38.2k | err->code = YYJSON_READ_ERROR_INVALID_PARAMETER; |
9714 | 38.2k | return NULL; |
9715 | 38.2k | } |
9716 | | |
9717 | 11.0k | if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) { |
9718 | 6.44k | return (char *)write_root_single(root, flg, alc, buf, dat_len, err); |
9719 | 6.44k | } else if (flg & (YYJSON_WRITE_PRETTY | YYJSON_WRITE_PRETTY_TWO_SPACES)) { |
9720 | 2.55k | return (char *)write_root_pretty(root, flg, alc, buf, dat_len, err); |
9721 | 2.55k | } else { |
9722 | 2.00k | return (char *)write_root_minify(root, flg, alc, buf, dat_len, err); |
9723 | 2.00k | } |
9724 | 11.0k | } |
9725 | | |
9726 | | |
9727 | | |
9728 | | /*============================================================================== |
9729 | | * MARK: - JSON Writer (Public) |
9730 | | *============================================================================*/ |
9731 | | |
9732 | | char *yyjson_val_write_opts(const yyjson_val *val, |
9733 | | yyjson_write_flag flg, |
9734 | | const yyjson_alc *alc_ptr, |
9735 | | usize *dat_len, |
9736 | 0 | yyjson_write_err *err) { |
9737 | 0 | return write_root(val, flg, alc_ptr, NULL, dat_len, err); |
9738 | 0 | } |
9739 | | |
9740 | | char *yyjson_write_opts(const yyjson_doc *doc, |
9741 | | yyjson_write_flag flg, |
9742 | | const yyjson_alc *alc_ptr, |
9743 | | usize *dat_len, |
9744 | 49.2k | yyjson_write_err *err) { |
9745 | 49.2k | yyjson_val *root = doc ? doc->root : NULL; |
9746 | 49.2k | return write_root(root, flg, alc_ptr, NULL, dat_len, err); |
9747 | 49.2k | } |
9748 | | |
9749 | | #if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE |
9750 | | |
9751 | | bool yyjson_val_write_file(const char *path, |
9752 | | const yyjson_val *val, |
9753 | | yyjson_write_flag flg, |
9754 | | const yyjson_alc *alc_ptr, |
9755 | 0 | yyjson_write_err *err) { |
9756 | 0 | yyjson_write_err tmp_err; |
9757 | 0 | yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC; |
9758 | 0 | u8 *dat; |
9759 | 0 | usize dat_len = 0; |
9760 | 0 | yyjson_val *root = constcast(yyjson_val *)val; |
9761 | 0 | bool suc; |
9762 | |
|
9763 | 0 | if (!err) err = &tmp_err; |
9764 | 0 | if (unlikely(!path || !*path)) { |
9765 | 0 | err->msg = "input path is invalid"; |
9766 | 0 | err->code = YYJSON_READ_ERROR_INVALID_PARAMETER; |
9767 | 0 | return false; |
9768 | 0 | } |
9769 | | |
9770 | 0 | dat = (u8 *)write_root(root, flg, &alc, NULL, &dat_len, err); |
9771 | 0 | if (unlikely(!dat)) return false; |
9772 | 0 | suc = write_dat_to_file(path, dat, dat_len, err); |
9773 | 0 | alc.free(alc.ctx, dat); |
9774 | 0 | return suc; |
9775 | 0 | } |
9776 | | |
9777 | | bool yyjson_val_write_fp(FILE *fp, |
9778 | | const yyjson_val *val, |
9779 | | yyjson_write_flag flg, |
9780 | | const yyjson_alc *alc_ptr, |
9781 | 0 | yyjson_write_err *err) { |
9782 | 0 | yyjson_write_err tmp_err; |
9783 | 0 | yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC; |
9784 | 0 | u8 *dat; |
9785 | 0 | usize dat_len = 0; |
9786 | 0 | yyjson_val *root = constcast(yyjson_val *)val; |
9787 | 0 | bool suc; |
9788 | |
|
9789 | 0 | if (!err) err = &tmp_err; |
9790 | 0 | if (unlikely(!fp)) { |
9791 | 0 | err->msg = "input fp is invalid"; |
9792 | 0 | err->code = YYJSON_READ_ERROR_INVALID_PARAMETER; |
9793 | 0 | return false; |
9794 | 0 | } |
9795 | | |
9796 | 0 | dat = (u8 *)write_root(root, flg, &alc, NULL, &dat_len, err); |
9797 | 0 | if (unlikely(!dat)) return false; |
9798 | 0 | suc = write_dat_to_fp(fp, dat, dat_len, err); |
9799 | 0 | alc.free(alc.ctx, dat); |
9800 | 0 | return suc; |
9801 | 0 | } |
9802 | | |
9803 | | bool yyjson_write_file(const char *path, |
9804 | | const yyjson_doc *doc, |
9805 | | yyjson_write_flag flg, |
9806 | | const yyjson_alc *alc_ptr, |
9807 | 0 | yyjson_write_err *err) { |
9808 | 0 | yyjson_val *root = doc ? doc->root : NULL; |
9809 | 0 | return yyjson_val_write_file(path, root, flg, alc_ptr, err); |
9810 | 0 | } |
9811 | | |
9812 | | bool yyjson_write_fp(FILE *fp, |
9813 | | const yyjson_doc *doc, |
9814 | | yyjson_write_flag flg, |
9815 | | const yyjson_alc *alc_ptr, |
9816 | 0 | yyjson_write_err *err) { |
9817 | 0 | yyjson_val *root = doc ? doc->root : NULL; |
9818 | 0 | return yyjson_val_write_fp(fp, root, flg, alc_ptr, err); |
9819 | 0 | } |
9820 | | |
9821 | | #endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */ |
9822 | | |
9823 | | size_t yyjson_val_write_buf(char *buf, size_t buf_len, |
9824 | | const yyjson_val *val, |
9825 | | yyjson_write_flag flg, |
9826 | 0 | yyjson_write_err *err) { |
9827 | 0 | if (unlikely(!buf || !buf_len)) { |
9828 | 0 | if (err) err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER; |
9829 | 0 | if (err) err->msg = "input buf or buf_len is invalid"; |
9830 | 0 | return 0; |
9831 | 0 | } else { |
9832 | 0 | write_root(val, flg, &YYJSON_NULL_ALC, buf, &buf_len, err); |
9833 | 0 | return buf_len; |
9834 | 0 | } |
9835 | 0 | } |
9836 | | |
9837 | | size_t yyjson_write_buf(char *buf, size_t buf_len, |
9838 | | const yyjson_doc *doc, |
9839 | | yyjson_write_flag flg, |
9840 | 0 | yyjson_write_err *err) { |
9841 | 0 | yyjson_val *root = doc ? doc->root : NULL; |
9842 | 0 | return yyjson_val_write_buf(buf, buf_len, root, flg, err); |
9843 | 0 | } |
9844 | | |
9845 | | |
9846 | | |
9847 | | /*============================================================================== |
9848 | | * MARK: - Mutable JSON Writer Implementation (Private) |
9849 | | *============================================================================*/ |
9850 | | |
9851 | | typedef struct yyjson_mut_write_ctx { |
9852 | | usize tag; |
9853 | | yyjson_mut_val *ctn; |
9854 | | } yyjson_mut_write_ctx; |
9855 | | |
9856 | | static_inline void yyjson_mut_write_ctx_set(yyjson_mut_write_ctx *ctx, |
9857 | | yyjson_mut_val *ctn, |
9858 | 51.2M | usize size, bool is_obj) { |
9859 | 51.2M | ctx->tag = (size << 1) | (usize)is_obj; |
9860 | 51.2M | ctx->ctn = ctn; |
9861 | 51.2M | } |
9862 | | |
9863 | | static_inline void yyjson_mut_write_ctx_get(yyjson_mut_write_ctx *ctx, |
9864 | | yyjson_mut_val **ctn, |
9865 | 50.9M | usize *size, bool *is_obj) { |
9866 | 50.9M | usize tag = ctx->tag; |
9867 | 50.9M | *size = tag >> 1; |
9868 | 50.9M | *is_obj = (bool)(tag & 1); |
9869 | 50.9M | *ctn = ctx->ctn; |
9870 | 50.9M | } |
9871 | | |
9872 | | /** Get the estimated number of values for the mutable JSON document. */ |
9873 | | static_inline usize yyjson_mut_doc_estimated_val_num( |
9874 | 11.0k | const yyjson_mut_doc *doc) { |
9875 | 11.0k | usize sum = 0; |
9876 | 11.0k | yyjson_val_chunk *chunk = doc->val_pool.chunks; |
9877 | 22.0k | while (chunk) { |
9878 | 11.0k | sum += chunk->chunk_size / sizeof(yyjson_mut_val) - 1; |
9879 | 11.0k | if (chunk == doc->val_pool.chunks) { |
9880 | 11.0k | sum -= (usize)(doc->val_pool.end - doc->val_pool.cur); |
9881 | 11.0k | } |
9882 | 11.0k | chunk = chunk->next; |
9883 | 11.0k | } |
9884 | 11.0k | return sum; |
9885 | 11.0k | } |
9886 | | |
9887 | | /** Write single JSON value. */ |
9888 | | static_inline u8 *mut_write_root_single(yyjson_mut_val *val, |
9889 | | yyjson_write_flag flg, |
9890 | | yyjson_alc alc, |
9891 | | char *buf, usize *dat_len, |
9892 | 15.7k | yyjson_write_err *err) { |
9893 | 15.7k | return write_root_single((yyjson_val *)val, flg, alc, buf, dat_len, err); |
9894 | 15.7k | } |
9895 | | |
9896 | | /** Write JSON document minify. |
9897 | | The root of this document should be a non-empty container. */ |
9898 | | static_inline u8 *mut_write_root_minify(const yyjson_mut_val *root, |
9899 | | usize estimated_val_num, |
9900 | | yyjson_write_flag flg, |
9901 | | yyjson_alc alc, |
9902 | | char *buf, usize *dat_len, |
9903 | 9.10k | yyjson_write_err *err) { |
9904 | 9.10k | #define return_err(_code, _msg) do { \ |
9905 | 1.16k | *dat_len = 0; \ |
9906 | 1.16k | err->code = YYJSON_WRITE_ERROR_##_code; \ |
9907 | 1.16k | err->msg = _msg; \ |
9908 | 1.16k | if (hdr) alc.free(alc.ctx, hdr); \ |
9909 | 1.16k | return NULL; \ |
9910 | 1.16k | } while (false) |
9911 | | |
9912 | 184M | #define incr_len(_len) do { \ |
9913 | 184M | ext_len = (usize)(_len); \ |
9914 | 184M | if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \ |
9915 | 15.3k | usize ctx_pos = (usize)((u8 *)ctx - hdr); \ |
9916 | 15.3k | usize cur_pos = (usize)(cur - hdr); \ |
9917 | 15.3k | yyjson_assume((u8 *)ctx <= (u8 *)end); \ |
9918 | 15.3k | ctx_len = (usize)((u8 *)end - (u8 *)ctx); \ |
9919 | 15.3k | alc_inc = yyjson_max(alc_len / 2, ext_len); \ |
9920 | 15.3k | alc_inc = size_align_up(alc_inc, sizeof(yyjson_mut_write_ctx)); \ |
9921 | 15.3k | if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \ |
9922 | 15.3k | goto fail_alloc; \ |
9923 | 15.3k | alc_len += alc_inc; \ |
9924 | 15.3k | tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \ |
9925 | 15.3k | if (unlikely(!tmp)) goto fail_alloc; \ |
9926 | 15.3k | ctx_tmp = (yyjson_mut_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \ |
9927 | 15.3k | memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \ |
9928 | 15.3k | ctx = ctx_tmp; \ |
9929 | 15.3k | cur = tmp + cur_pos; \ |
9930 | 15.3k | end = tmp + alc_len; \ |
9931 | 15.3k | hdr = tmp; \ |
9932 | 15.3k | } \ |
9933 | 184M | } while (false) |
9934 | | |
9935 | 50.3M | #define check_str_len(_len) do { \ |
9936 | 50.3M | if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \ |
9937 | 50.3M | goto fail_alloc; \ |
9938 | 50.3M | } while (false) |
9939 | | |
9940 | 9.10k | yyjson_mut_val *val, *ctn; |
9941 | 9.10k | yyjson_type val_type; |
9942 | 9.10k | usize ctn_len, ctn_len_tmp; |
9943 | 9.10k | bool ctn_obj, ctn_obj_tmp, is_key; |
9944 | 9.10k | u8 *hdr, *cur, *end, *tmp; |
9945 | 9.10k | yyjson_mut_write_ctx *ctx, *ctx_tmp; |
9946 | 9.10k | usize alc_len, alc_inc, ctx_len, ext_len, str_len; |
9947 | 9.10k | const u8 *str_ptr; |
9948 | 9.10k | const char_enc_type *enc_table = get_enc_table_with_flag(flg); |
9949 | 9.10k | const u8 *hex_table = get_hex_table_with_flag(flg); |
9950 | 9.10k | bool cpy = (enc_table == enc_table_cpy); |
9951 | 9.10k | bool esc = has_flg(ESCAPE_UNICODE) != 0; |
9952 | 9.10k | bool inv = has_allow(INVALID_UNICODE) != 0; |
9953 | 9.10k | bool newline = has_flg(NEWLINE_AT_END) != 0; |
9954 | | |
9955 | 9.10k | if (buf) { |
9956 | 0 | hdr = (u8 *)buf; |
9957 | 0 | alc_len = *dat_len; |
9958 | 0 | alc_len = size_align_down(alc_len, sizeof(yyjson_mut_write_ctx)); |
9959 | 0 | if (alc_len <= sizeof(yyjson_mut_write_ctx)) goto fail_alloc; |
9960 | 9.10k | } else { |
9961 | 9.10k | alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64; |
9962 | 9.10k | alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx)); |
9963 | 9.10k | hdr = (u8 *)alc.malloc(alc.ctx, alc_len); |
9964 | 9.10k | if (!hdr) goto fail_alloc; |
9965 | 9.10k | } |
9966 | 9.10k | cur = hdr; |
9967 | 9.10k | end = hdr + alc_len; |
9968 | 9.10k | ctx = (yyjson_mut_write_ctx *)(void *)end; |
9969 | | |
9970 | 9.10k | doc_begin: |
9971 | 9.10k | val = constcast(yyjson_mut_val *)root; |
9972 | 9.10k | val_type = unsafe_yyjson_get_type(val); |
9973 | 9.10k | ctn_obj = (val_type == YYJSON_TYPE_OBJ); |
9974 | 9.10k | ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj; |
9975 | 9.10k | *cur++ = (u8)('[' | ((u8)ctn_obj << 5)); |
9976 | 9.10k | ctn = val; |
9977 | 9.10k | val = (yyjson_mut_val *)val->uni.ptr; /* tail */ |
9978 | 9.10k | val = ctn_obj ? val->next->next : val->next; |
9979 | | |
9980 | 184M | val_begin: |
9981 | 184M | val_type = unsafe_yyjson_get_type(val); |
9982 | 184M | if (val_type == YYJSON_TYPE_STR) { |
9983 | 50.3M | is_key = ((u8)ctn_obj & (u8)~ctn_len); |
9984 | 50.3M | str_len = unsafe_yyjson_get_len(val); |
9985 | 50.3M | str_ptr = (const u8 *)unsafe_yyjson_get_str(val); |
9986 | 50.3M | check_str_len(str_len); |
9987 | 50.3M | incr_len(str_len * 6 + 16); |
9988 | 50.3M | if (likely(cpy) && unsafe_yyjson_get_subtype(val)) { |
9989 | 21.7M | cur = write_str_noesc(cur, str_ptr, str_len); |
9990 | 28.5M | } else { |
9991 | 28.5M | cur = write_str(cur, esc, inv, str_ptr, str_len, |
9992 | 28.5M | enc_table, hex_table); |
9993 | 28.5M | if (unlikely(!cur)) goto fail_str; |
9994 | 28.5M | } |
9995 | 50.3M | *cur++ = is_key ? ':' : ','; |
9996 | 50.3M | goto val_end; |
9997 | 50.3M | } |
9998 | 134M | if (val_type == YYJSON_TYPE_NUM) { |
9999 | 83.2M | incr_len(FP_BUF_LEN); |
10000 | 83.2M | cur = write_num(cur, (yyjson_val *)val, flg); |
10001 | 83.2M | if (unlikely(!cur)) goto fail_num; |
10002 | 83.2M | *cur++ = ','; |
10003 | 83.2M | goto val_end; |
10004 | 83.2M | } |
10005 | 51.3M | if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) == |
10006 | 51.3M | (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) { |
10007 | 51.0M | ctn_len_tmp = unsafe_yyjson_get_len(val); |
10008 | 51.0M | ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ); |
10009 | 51.0M | incr_len(2 * sizeof(*ctx)); |
10010 | 51.0M | if (unlikely(ctn_len_tmp == 0)) { |
10011 | | /* write empty container */ |
10012 | 296k | *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5)); |
10013 | 296k | *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5)); |
10014 | 296k | *cur++ = ','; |
10015 | 296k | goto val_end; |
10016 | 50.7M | } else { |
10017 | | /* push context, setup new container */ |
10018 | 50.7M | yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj); |
10019 | 50.7M | ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp; |
10020 | 50.7M | ctn_obj = ctn_obj_tmp; |
10021 | 50.7M | *cur++ = (u8)('[' | ((u8)ctn_obj << 5)); |
10022 | 50.7M | ctn = val; |
10023 | 50.7M | val = (yyjson_mut_val *)ctn->uni.ptr; /* tail */ |
10024 | 50.7M | val = ctn_obj ? val->next->next : val->next; |
10025 | 50.7M | goto val_begin; |
10026 | 50.7M | } |
10027 | 51.0M | } |
10028 | 277k | if (val_type == YYJSON_TYPE_BOOL) { |
10029 | 274k | incr_len(16); |
10030 | 274k | cur = write_bool(cur, unsafe_yyjson_get_bool(val)); |
10031 | 274k | cur++; |
10032 | 274k | goto val_end; |
10033 | 274k | } |
10034 | 3.04k | if (val_type == YYJSON_TYPE_NULL) { |
10035 | 3.04k | incr_len(16); |
10036 | 3.04k | cur = write_null(cur); |
10037 | 3.04k | cur++; |
10038 | 3.04k | goto val_end; |
10039 | 3.04k | } |
10040 | 0 | if (val_type == YYJSON_TYPE_RAW) { |
10041 | 0 | str_len = unsafe_yyjson_get_len(val); |
10042 | 0 | str_ptr = (const u8 *)unsafe_yyjson_get_str(val); |
10043 | 0 | check_str_len(str_len); |
10044 | 0 | incr_len(str_len + 2); |
10045 | 0 | cur = write_raw(cur, str_ptr, str_len); |
10046 | 0 | *cur++ = ','; |
10047 | 0 | goto val_end; |
10048 | 0 | } |
10049 | 0 | goto fail_type; |
10050 | | |
10051 | 134M | val_end: |
10052 | 134M | ctn_len--; |
10053 | 134M | if (unlikely(ctn_len == 0)) goto ctn_end; |
10054 | 104M | val = val->next; |
10055 | 104M | goto val_begin; |
10056 | | |
10057 | 50.7M | ctn_end: |
10058 | 50.7M | cur--; |
10059 | 50.7M | *cur++ = (u8)(']' | ((u8)ctn_obj << 5)); |
10060 | 50.7M | *cur++ = ','; |
10061 | 50.7M | if (unlikely((u8 *)ctx >= end)) goto doc_end; |
10062 | 50.7M | val = ctn->next; |
10063 | 50.7M | yyjson_mut_write_ctx_get(ctx++, &ctn, &ctn_len, &ctn_obj); |
10064 | 50.7M | ctn_len--; |
10065 | 50.7M | if (likely(ctn_len > 0)) { |
10066 | 29.6M | goto val_begin; |
10067 | 29.6M | } else { |
10068 | 21.0M | goto ctn_end; |
10069 | 21.0M | } |
10070 | | |
10071 | 7.94k | doc_end: |
10072 | 7.94k | if (newline) { |
10073 | 0 | incr_len(2); |
10074 | 0 | *(cur - 1) = '\n'; |
10075 | 0 | cur++; |
10076 | 0 | } |
10077 | 7.94k | *--cur = '\0'; |
10078 | 7.94k | *dat_len = (usize)(cur - hdr); |
10079 | 7.94k | err->code = YYJSON_WRITE_SUCCESS; |
10080 | 7.94k | err->msg = NULL; |
10081 | 7.94k | return hdr; |
10082 | | |
10083 | 28 | fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC); |
10084 | 0 | fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE); |
10085 | 0 | fail_num: return_err(NAN_OR_INF, MSG_NAN_INF); |
10086 | 1.13k | fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8); |
10087 | | |
10088 | 1.13k | #undef return_err |
10089 | 1.13k | #undef incr_len |
10090 | 1.13k | #undef check_str_len |
10091 | 1.13k | } |
10092 | | |
10093 | | /** Write JSON document pretty. |
10094 | | The root of this document should be a non-empty container. */ |
10095 | | static_inline u8 *mut_write_root_pretty(const yyjson_mut_val *root, |
10096 | | usize estimated_val_num, |
10097 | | yyjson_write_flag flg, |
10098 | | yyjson_alc alc, |
10099 | | char *buf, usize *dat_len, |
10100 | 2.55k | yyjson_write_err *err) { |
10101 | 2.55k | #define return_err(_code, _msg) do { \ |
10102 | 23 | *dat_len = 0; \ |
10103 | 23 | err->code = YYJSON_WRITE_ERROR_##_code; \ |
10104 | 23 | err->msg = _msg; \ |
10105 | 23 | if (hdr) alc.free(alc.ctx, hdr); \ |
10106 | 23 | return NULL; \ |
10107 | 23 | } while (false) |
10108 | | |
10109 | 3.60M | #define incr_len(_len) do { \ |
10110 | 6.85M | ext_len = (usize)(_len); \ |
10111 | 3.60M | if (unlikely((u8 *)(cur + ext_len) >= (u8 *)ctx)) { \ |
10112 | 2.25k | usize ctx_pos = (usize)((u8 *)ctx - hdr); \ |
10113 | 2.25k | usize cur_pos = (usize)(cur - hdr); \ |
10114 | 2.25k | yyjson_assume((u8 *)ctx <= (u8 *)end); \ |
10115 | 2.25k | ctx_len = (usize)((u8 *)end - (u8 *)ctx); \ |
10116 | 2.25k | alc_inc = yyjson_max(alc_len / 2, ext_len); \ |
10117 | 2.25k | alc_inc = size_align_up(alc_inc, sizeof(yyjson_mut_write_ctx)); \ |
10118 | 2.25k | if ((sizeof(usize) < 8) && size_add_is_overflow(alc_len, alc_inc)) \ |
10119 | 2.25k | goto fail_alloc; \ |
10120 | 2.25k | alc_len += alc_inc; \ |
10121 | 2.25k | tmp = (u8 *)alc.realloc(alc.ctx, hdr, alc_len - alc_inc, alc_len); \ |
10122 | 2.25k | if (unlikely(!tmp)) goto fail_alloc; \ |
10123 | 2.25k | ctx_tmp = (yyjson_mut_write_ctx *)(void *)(tmp + (alc_len - ctx_len)); \ |
10124 | 2.22k | memmove((void *)ctx_tmp, (void *)(tmp + ctx_pos), ctx_len); \ |
10125 | 2.22k | ctx = ctx_tmp; \ |
10126 | 2.22k | cur = tmp + cur_pos; \ |
10127 | 2.22k | end = tmp + alc_len; \ |
10128 | 2.22k | hdr = tmp; \ |
10129 | 2.22k | } \ |
10130 | 3.60M | } while (false) |
10131 | | |
10132 | 40.2k | #define check_str_len(_len) do { \ |
10133 | 40.2k | if ((sizeof(usize) < 8) && (_len >= (USIZE_MAX - 16) / 6)) \ |
10134 | 40.2k | goto fail_alloc; \ |
10135 | 40.2k | } while (false) |
10136 | | |
10137 | 2.55k | yyjson_mut_val *val, *ctn; |
10138 | 2.55k | yyjson_type val_type; |
10139 | 2.55k | usize ctn_len, ctn_len_tmp; |
10140 | 2.55k | bool ctn_obj, ctn_obj_tmp, is_key, no_indent; |
10141 | 2.55k | u8 *hdr, *cur, *end, *tmp; |
10142 | 2.55k | yyjson_mut_write_ctx *ctx, *ctx_tmp; |
10143 | 2.55k | usize alc_len, alc_inc, ctx_len, ext_len, str_len, level; |
10144 | 2.55k | const u8 *str_ptr; |
10145 | 2.55k | const char_enc_type *enc_table = get_enc_table_with_flag(flg); |
10146 | 2.55k | const u8 *hex_table = get_hex_table_with_flag(flg); |
10147 | 2.55k | bool cpy = (enc_table == enc_table_cpy); |
10148 | 2.55k | bool esc = has_flg(ESCAPE_UNICODE) != 0; |
10149 | 2.55k | bool inv = has_allow(INVALID_UNICODE) != 0; |
10150 | 2.55k | usize spaces = has_flg(PRETTY_TWO_SPACES) ? 2 : 4; |
10151 | 2.55k | bool newline = has_flg(NEWLINE_AT_END) != 0; |
10152 | | |
10153 | 2.55k | if (buf) { |
10154 | 0 | hdr = (u8 *)buf; |
10155 | 0 | alc_len = *dat_len; |
10156 | 0 | alc_len = size_align_down(alc_len, sizeof(yyjson_mut_write_ctx)); |
10157 | 0 | if (alc_len <= sizeof(yyjson_mut_write_ctx)) goto fail_alloc; |
10158 | 2.55k | } else { |
10159 | 2.55k | alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64; |
10160 | 2.55k | alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx)); |
10161 | 2.55k | hdr = (u8 *)alc.malloc(alc.ctx, alc_len); |
10162 | 2.55k | if (!hdr) goto fail_alloc; |
10163 | 2.55k | } |
10164 | 2.55k | cur = hdr; |
10165 | 2.55k | end = hdr + alc_len; |
10166 | 2.55k | ctx = (yyjson_mut_write_ctx *)(void *)end; |
10167 | | |
10168 | 2.55k | doc_begin: |
10169 | 2.55k | val = constcast(yyjson_mut_val *)root; |
10170 | 2.55k | val_type = unsafe_yyjson_get_type(val); |
10171 | 2.55k | ctn_obj = (val_type == YYJSON_TYPE_OBJ); |
10172 | 2.55k | ctn_len = unsafe_yyjson_get_len(val) << (u8)ctn_obj; |
10173 | 2.55k | *cur++ = (u8)('[' | ((u8)ctn_obj << 5)); |
10174 | 2.55k | *cur++ = '\n'; |
10175 | 2.55k | ctn = val; |
10176 | 2.55k | val = (yyjson_mut_val *)val->uni.ptr; /* tail */ |
10177 | 2.55k | val = ctn_obj ? val->next->next : val->next; |
10178 | 2.55k | level = 1; |
10179 | | |
10180 | 3.42M | val_begin: |
10181 | 3.42M | val_type = unsafe_yyjson_get_type(val); |
10182 | 3.42M | if (val_type == YYJSON_TYPE_STR) { |
10183 | 40.2k | is_key = (bool)((u8)ctn_obj & (u8)~ctn_len); |
10184 | 40.2k | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
10185 | 40.2k | str_len = unsafe_yyjson_get_len(val); |
10186 | 40.2k | str_ptr = (const u8 *)unsafe_yyjson_get_str(val); |
10187 | 40.2k | check_str_len(str_len); |
10188 | 40.2k | if ((sizeof(usize) < 8) && !no_indent && |
10189 | 0 | level > (USIZE_MAX - 16 - str_len * 6) / 4) goto fail_alloc; |
10190 | 40.2k | incr_len(str_len * 6 + 16 + (no_indent ? 0 : level * 4)); |
10191 | 40.2k | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
10192 | 40.2k | if (likely(cpy) && unsafe_yyjson_get_subtype(val)) { |
10193 | 0 | cur = write_str_noesc(cur, str_ptr, str_len); |
10194 | 40.2k | } else { |
10195 | 40.2k | cur = write_str(cur, esc, inv, str_ptr, str_len, |
10196 | 40.2k | enc_table, hex_table); |
10197 | 40.2k | if (unlikely(!cur)) goto fail_str; |
10198 | 40.2k | } |
10199 | 40.2k | *cur++ = is_key ? ':' : ','; |
10200 | 40.2k | *cur++ = is_key ? ' ' : '\n'; |
10201 | 40.2k | goto val_end; |
10202 | 40.2k | } |
10203 | 3.38M | if (val_type == YYJSON_TYPE_NUM) { |
10204 | 2.31M | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
10205 | 2.31M | incr_len(FP_BUF_LEN + (no_indent ? 0 : level * 4)); |
10206 | 2.31M | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
10207 | 2.31M | cur = write_num(cur, (yyjson_val *)val, flg); |
10208 | 2.31M | if (unlikely(!cur)) goto fail_num; |
10209 | 2.31M | *cur++ = ','; |
10210 | 2.31M | *cur++ = '\n'; |
10211 | 2.31M | goto val_end; |
10212 | 2.31M | } |
10213 | 1.07M | if ((val_type & (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) == |
10214 | 1.07M | (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) { |
10215 | 876k | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
10216 | 876k | ctn_len_tmp = unsafe_yyjson_get_len(val); |
10217 | 876k | ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ); |
10218 | 876k | incr_len(2 * sizeof(*ctx) + (no_indent ? 0 : level * 4)); |
10219 | 876k | if (unlikely(ctn_len_tmp == 0)) { |
10220 | | /* write empty container */ |
10221 | 347k | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
10222 | 347k | *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5)); |
10223 | 347k | *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5)); |
10224 | 347k | *cur++ = ','; |
10225 | 347k | *cur++ = '\n'; |
10226 | 347k | goto val_end; |
10227 | 528k | } else { |
10228 | | /* push context, setup new container */ |
10229 | 528k | yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj); |
10230 | 528k | ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp; |
10231 | 528k | ctn_obj = ctn_obj_tmp; |
10232 | 528k | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
10233 | 528k | level++; |
10234 | 528k | *cur++ = (u8)('[' | ((u8)ctn_obj << 5)); |
10235 | 528k | *cur++ = '\n'; |
10236 | 528k | ctn = val; |
10237 | 528k | val = (yyjson_mut_val *)ctn->uni.ptr; /* tail */ |
10238 | 528k | val = ctn_obj ? val->next->next : val->next; |
10239 | 528k | goto val_begin; |
10240 | 528k | } |
10241 | 876k | } |
10242 | 195k | if (val_type == YYJSON_TYPE_BOOL) { |
10243 | 65.6k | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
10244 | 65.6k | incr_len(16 + (no_indent ? 0 : level * 4)); |
10245 | 65.6k | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
10246 | 65.6k | cur = write_bool(cur, unsafe_yyjson_get_bool(val)); |
10247 | 65.6k | cur += 2; |
10248 | 65.6k | goto val_end; |
10249 | 65.6k | } |
10250 | 130k | if (val_type == YYJSON_TYPE_NULL) { |
10251 | 130k | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
10252 | 130k | incr_len(16 + (no_indent ? 0 : level * 4)); |
10253 | 130k | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
10254 | 130k | cur = write_null(cur); |
10255 | 130k | cur += 2; |
10256 | 130k | goto val_end; |
10257 | 130k | } |
10258 | 0 | if (val_type == YYJSON_TYPE_RAW) { |
10259 | 0 | no_indent = (bool)((u8)ctn_obj & (u8)ctn_len); |
10260 | 0 | str_len = unsafe_yyjson_get_len(val); |
10261 | 0 | str_ptr = (const u8 *)unsafe_yyjson_get_str(val); |
10262 | 0 | check_str_len(str_len); |
10263 | 0 | incr_len(str_len + 3 + (no_indent ? 0 : level * 4)); |
10264 | 0 | cur = write_indent(cur, no_indent ? 0 : level, spaces); |
10265 | 0 | cur = write_raw(cur, str_ptr, str_len); |
10266 | 0 | *cur++ = ','; |
10267 | 0 | *cur++ = '\n'; |
10268 | 0 | goto val_end; |
10269 | 0 | } |
10270 | 0 | goto fail_type; |
10271 | | |
10272 | 2.89M | val_end: |
10273 | 2.89M | ctn_len--; |
10274 | 2.89M | if (unlikely(ctn_len == 0)) goto ctn_end; |
10275 | 2.76M | val = val->next; |
10276 | 2.76M | goto val_begin; |
10277 | | |
10278 | 180k | ctn_end: |
10279 | 180k | cur -= 2; |
10280 | 180k | *cur++ = '\n'; |
10281 | 180k | incr_len(level * 4); |
10282 | 180k | cur = write_indent(cur, --level, spaces); |
10283 | 180k | *cur++ = (u8)(']' | ((u8)ctn_obj << 5)); |
10284 | 180k | if (unlikely((u8 *)ctx >= end)) goto doc_end; |
10285 | 178k | val = ctn->next; |
10286 | 178k | yyjson_mut_write_ctx_get(ctx++, &ctn, &ctn_len, &ctn_obj); |
10287 | 178k | ctn_len--; |
10288 | 178k | *cur++ = ','; |
10289 | 178k | *cur++ = '\n'; |
10290 | 178k | if (likely(ctn_len > 0)) { |
10291 | 130k | goto val_begin; |
10292 | 130k | } else { |
10293 | 48.2k | goto ctn_end; |
10294 | 48.2k | } |
10295 | | |
10296 | 2.53k | doc_end: |
10297 | 2.53k | if (newline) { |
10298 | 0 | incr_len(2); |
10299 | 0 | *cur++ = '\n'; |
10300 | 0 | } |
10301 | 2.53k | *cur = '\0'; |
10302 | 2.53k | *dat_len = (usize)(cur - hdr); |
10303 | 2.53k | err->code = YYJSON_WRITE_SUCCESS; |
10304 | 2.53k | err->msg = NULL; |
10305 | 2.53k | return hdr; |
10306 | | |
10307 | 23 | fail_alloc: return_err(MEMORY_ALLOCATION, MSG_MALLOC); |
10308 | 0 | fail_type: return_err(INVALID_VALUE_TYPE, MSG_ERR_TYPE); |
10309 | 0 | fail_num: return_err(NAN_OR_INF, MSG_NAN_INF); |
10310 | 0 | fail_str: return_err(INVALID_STRING, MSG_ERR_UTF8); |
10311 | |
|
10312 | 0 | #undef return_err |
10313 | 0 | #undef incr_len |
10314 | 0 | #undef check_str_len |
10315 | 0 | } |
10316 | | |
10317 | | static char *mut_write_root(const yyjson_mut_val *val, |
10318 | | usize estimated_val_num, |
10319 | | yyjson_write_flag flg, |
10320 | | const yyjson_alc *alc_ptr, |
10321 | | char *buf, usize *dat_len, |
10322 | 65.6k | yyjson_write_err *err) { |
10323 | 65.6k | yyjson_write_err tmp_err; |
10324 | 65.6k | usize tmp_dat_len; |
10325 | 65.6k | yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC; |
10326 | 65.6k | yyjson_mut_val *root = constcast(yyjson_mut_val *)val; |
10327 | | |
10328 | 65.6k | if (!err) err = &tmp_err; |
10329 | 65.6k | if (!dat_len) dat_len = &tmp_dat_len; |
10330 | | |
10331 | 65.6k | if (unlikely(!root)) { |
10332 | 38.2k | *dat_len = 0; |
10333 | 38.2k | err->msg = "input JSON is NULL"; |
10334 | 38.2k | err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER; |
10335 | 38.2k | return NULL; |
10336 | 38.2k | } |
10337 | | |
10338 | 27.3k | if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) { |
10339 | 15.7k | return (char *)mut_write_root_single(root, flg, alc, buf, dat_len, err); |
10340 | 15.7k | } else if (flg & (YYJSON_WRITE_PRETTY | YYJSON_WRITE_PRETTY_TWO_SPACES)) { |
10341 | 2.55k | return (char *)mut_write_root_pretty(root, estimated_val_num, |
10342 | 2.55k | flg, alc, buf, dat_len, err); |
10343 | 9.10k | } else { |
10344 | 9.10k | return (char *)mut_write_root_minify(root, estimated_val_num, |
10345 | 9.10k | flg, alc, buf, dat_len, err); |
10346 | 9.10k | } |
10347 | 27.3k | } |
10348 | | |
10349 | | |
10350 | | |
10351 | | /*============================================================================== |
10352 | | * MARK: - Mutable JSON Writer (Public) |
10353 | | *============================================================================*/ |
10354 | | |
10355 | | char *yyjson_mut_val_write_opts(const yyjson_mut_val *val, |
10356 | | yyjson_write_flag flg, |
10357 | | const yyjson_alc *alc_ptr, |
10358 | | usize *dat_len, |
10359 | 16.3k | yyjson_write_err *err) { |
10360 | 16.3k | return mut_write_root(val, 0, flg, alc_ptr, NULL, dat_len, err); |
10361 | 16.3k | } |
10362 | | |
10363 | | char *yyjson_mut_write_opts(const yyjson_mut_doc *doc, |
10364 | | yyjson_write_flag flg, |
10365 | | const yyjson_alc *alc_ptr, |
10366 | | usize *dat_len, |
10367 | 49.2k | yyjson_write_err *err) { |
10368 | 49.2k | yyjson_mut_val *root; |
10369 | 49.2k | usize estimated_val_num; |
10370 | 49.2k | if (likely(doc)) { |
10371 | 11.0k | root = doc->root; |
10372 | 11.0k | estimated_val_num = yyjson_mut_doc_estimated_val_num(doc); |
10373 | 38.2k | } else { |
10374 | 38.2k | root = NULL; |
10375 | 38.2k | estimated_val_num = 0; |
10376 | 38.2k | } |
10377 | 49.2k | return mut_write_root(root, estimated_val_num, |
10378 | 49.2k | flg, alc_ptr, NULL, dat_len, err); |
10379 | 49.2k | } |
10380 | | |
10381 | | size_t yyjson_mut_val_write_buf(char *buf, size_t buf_len, |
10382 | | const yyjson_mut_val *val, |
10383 | | yyjson_write_flag flg, |
10384 | 0 | yyjson_write_err *err) { |
10385 | 0 | if (unlikely(!buf || !buf_len)) { |
10386 | 0 | if (err) err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER; |
10387 | 0 | if (err) err->msg = "input buf or buf_len is invalid"; |
10388 | 0 | return 0; |
10389 | 0 | } else { |
10390 | 0 | mut_write_root(val, 0, flg, &YYJSON_NULL_ALC, buf, &buf_len, err); |
10391 | 0 | return buf_len; |
10392 | 0 | } |
10393 | 0 | } |
10394 | | |
10395 | | size_t yyjson_mut_write_buf(char *buf, size_t buf_len, |
10396 | | const yyjson_mut_doc *doc, |
10397 | | yyjson_write_flag flg, |
10398 | 0 | yyjson_write_err *err) { |
10399 | 0 | yyjson_mut_val *root = doc ? doc->root : NULL; |
10400 | 0 | return yyjson_mut_val_write_buf(buf, buf_len, root, flg, err); |
10401 | 0 | } |
10402 | | |
10403 | | #if !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE |
10404 | | |
10405 | | bool yyjson_mut_val_write_file(const char *path, |
10406 | | const yyjson_mut_val *val, |
10407 | | yyjson_write_flag flg, |
10408 | | const yyjson_alc *alc_ptr, |
10409 | 0 | yyjson_write_err *err) { |
10410 | 0 | yyjson_write_err tmp_err; |
10411 | 0 | yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC; |
10412 | 0 | u8 *dat; |
10413 | 0 | usize dat_len = 0; |
10414 | 0 | yyjson_mut_val *root = constcast(yyjson_mut_val *)val; |
10415 | 0 | bool suc; |
10416 | |
|
10417 | 0 | if (!err) err = &tmp_err; |
10418 | 0 | if (unlikely(!path || !*path)) { |
10419 | 0 | err->msg = "input path is invalid"; |
10420 | 0 | err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER; |
10421 | 0 | return false; |
10422 | 0 | } |
10423 | | |
10424 | 0 | dat = (u8 *)yyjson_mut_val_write_opts(root, flg, &alc, &dat_len, err); |
10425 | 0 | if (unlikely(!dat)) return false; |
10426 | 0 | suc = write_dat_to_file(path, dat, dat_len, err); |
10427 | 0 | alc.free(alc.ctx, dat); |
10428 | 0 | return suc; |
10429 | 0 | } |
10430 | | |
10431 | | bool yyjson_mut_val_write_fp(FILE *fp, |
10432 | | const yyjson_mut_val *val, |
10433 | | yyjson_write_flag flg, |
10434 | | const yyjson_alc *alc_ptr, |
10435 | 0 | yyjson_write_err *err) { |
10436 | 0 | yyjson_write_err tmp_err; |
10437 | 0 | yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC; |
10438 | 0 | u8 *dat; |
10439 | 0 | usize dat_len = 0; |
10440 | 0 | yyjson_mut_val *root = constcast(yyjson_mut_val *)val; |
10441 | 0 | bool suc; |
10442 | |
|
10443 | 0 | if (!err) err = &tmp_err; |
10444 | 0 | if (unlikely(!fp)) { |
10445 | 0 | err->msg = "input fp is invalid"; |
10446 | 0 | err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER; |
10447 | 0 | return false; |
10448 | 0 | } |
10449 | | |
10450 | 0 | dat = (u8 *)yyjson_mut_val_write_opts(root, flg, &alc, &dat_len, err); |
10451 | 0 | if (unlikely(!dat)) return false; |
10452 | 0 | suc = write_dat_to_fp(fp, dat, dat_len, err); |
10453 | 0 | alc.free(alc.ctx, dat); |
10454 | 0 | return suc; |
10455 | 0 | } |
10456 | | |
10457 | | bool yyjson_mut_write_file(const char *path, |
10458 | | const yyjson_mut_doc *doc, |
10459 | | yyjson_write_flag flg, |
10460 | | const yyjson_alc *alc_ptr, |
10461 | 0 | yyjson_write_err *err) { |
10462 | 0 | yyjson_mut_val *root = doc ? doc->root : NULL; |
10463 | 0 | return yyjson_mut_val_write_file(path, root, flg, alc_ptr, err); |
10464 | 0 | } |
10465 | | |
10466 | | bool yyjson_mut_write_fp(FILE *fp, |
10467 | | const yyjson_mut_doc *doc, |
10468 | | yyjson_write_flag flg, |
10469 | | const yyjson_alc *alc_ptr, |
10470 | 0 | yyjson_write_err *err) { |
10471 | 0 | yyjson_mut_val *root = doc ? doc->root : NULL; |
10472 | 0 | return yyjson_mut_val_write_fp(fp, root, flg, alc_ptr, err); |
10473 | 0 | } |
10474 | | |
10475 | | #endif /* !YYJSON_FREESTANDING && !YYJSON_DISABLE_FILE */ |
10476 | | |
10477 | | #undef has_flg |
10478 | | #undef has_allow |
10479 | | #endif /* YYJSON_DISABLE_WRITER */ |
10480 | | |
10481 | | |
10482 | | |
10483 | | #if !YYJSON_DISABLE_UTILS |
10484 | | |
10485 | | /*============================================================================== |
10486 | | * MARK: - JSON Pointer API (RFC 6901) (Public) |
10487 | | *============================================================================*/ |
10488 | | |
10489 | | /** |
10490 | | Get a token from JSON pointer string. |
10491 | | @param ptr [in] string that points to current token prefix `/` |
10492 | | [out] string that points to next token prefix `/`, or string end |
10493 | | @param end [in] end of the entire JSON Pointer string |
10494 | | @param len [out] unescaped token length |
10495 | | @param esc [out] number of escaped characters in this token |
10496 | | @return head of the token, or NULL if syntax error |
10497 | | */ |
10498 | | static_inline const char *ptr_next_token(const char **ptr, const char *end, |
10499 | 35.1k | usize *len, usize *esc) { |
10500 | 35.1k | const char *hdr = *ptr + 1; |
10501 | 35.1k | const char *cur = hdr; |
10502 | | /* skip unescaped characters */ |
10503 | 442k | while (cur < end && *cur != '/' && *cur != '~') cur++; |
10504 | 35.1k | if (likely(cur == end || *cur != '~')) { |
10505 | | /* no escaped characters, return */ |
10506 | 32.1k | *ptr = cur; |
10507 | 32.1k | *len = (usize)(cur - hdr); |
10508 | 32.1k | *esc = 0; |
10509 | 32.1k | return hdr; |
10510 | 32.1k | } else { |
10511 | | /* handle escaped characters */ |
10512 | 2.92k | usize esc_num = 0; |
10513 | 74.9k | while (cur < end && *cur != '/') { |
10514 | 72.0k | if (*cur++ == '~') { |
10515 | 5.38k | if (cur == end || (*cur != '0' && *cur != '1')) { |
10516 | 54 | *ptr = cur - 1; |
10517 | 54 | return NULL; |
10518 | 54 | } |
10519 | 5.32k | esc_num++; |
10520 | 5.32k | } |
10521 | 72.0k | } |
10522 | 2.87k | *ptr = cur; |
10523 | 2.87k | *len = (usize)(cur - hdr) - esc_num; |
10524 | 2.87k | *esc = esc_num; |
10525 | 2.87k | return hdr; |
10526 | 2.92k | } |
10527 | 35.1k | } |
10528 | | |
10529 | | /** |
10530 | | Convert token string to index. |
10531 | | @param cur [in] token head |
10532 | | @param len [in] token length |
10533 | | @param idx [out] the index number, or USIZE_MAX if token is '-' |
10534 | | @return true if token is a valid array index |
10535 | | */ |
10536 | 22.0k | static_inline bool ptr_token_to_idx(const char *cur, usize len, usize *idx) { |
10537 | 22.0k | const char *end = cur + len; |
10538 | 22.0k | usize num = 0, add; |
10539 | 22.0k | if (unlikely(len == 0 || len > USIZE_SAFE_DIG)) return false; |
10540 | 21.9k | if (*cur == '0') { |
10541 | 4.78k | if (unlikely(len > 1)) return false; |
10542 | 4.77k | *idx = 0; |
10543 | 4.77k | return true; |
10544 | 4.78k | } |
10545 | 17.1k | if (*cur == '-') { |
10546 | 1.25k | if (unlikely(len > 1)) return false; |
10547 | 1.24k | *idx = USIZE_MAX; |
10548 | 1.24k | return true; |
10549 | 1.25k | } |
10550 | 36.5k | for (; cur < end && (add = (usize)((u8)*cur - (u8)'0')) <= 9; cur++) { |
10551 | 20.6k | num = num * 10 + add; |
10552 | 20.6k | } |
10553 | 15.9k | if (unlikely(num == 0 || cur < end)) return false; |
10554 | 15.8k | *idx = num; |
10555 | 15.8k | return true; |
10556 | 15.9k | } |
10557 | | |
10558 | | /** |
10559 | | Compare JSON key with token. |
10560 | | @param key a string key (yyjson_val or yyjson_mut_val) |
10561 | | @param token a JSON pointer token |
10562 | | @param len unescaped token length |
10563 | | @param esc number of escaped characters in this token |
10564 | | @return true if `str` is equal to `token` |
10565 | | */ |
10566 | | static_inline bool ptr_token_eq(void *key, |
10567 | 66.7k | const char *token, usize len, usize esc) { |
10568 | 66.7k | yyjson_val *val = (yyjson_val *)key; |
10569 | 66.7k | if (unsafe_yyjson_get_len(val) != len) return false; |
10570 | 15.5k | if (likely(!esc)) { |
10571 | 10.6k | return memcmp(val->uni.str, token, len) == 0; |
10572 | 10.6k | } else { |
10573 | 4.93k | const char *str = val->uni.str; |
10574 | 33.1k | for (; len-- > 0; token++, str++) { |
10575 | 31.4k | if (*token == '~') { |
10576 | 4.21k | if (*str != (*++token == '0' ? '~' : '/')) return false; |
10577 | 27.1k | } else { |
10578 | 27.1k | if (*str != *token) return false; |
10579 | 27.1k | } |
10580 | 31.4k | } |
10581 | 1.70k | return true; |
10582 | 4.93k | } |
10583 | 15.5k | } |
10584 | | |
10585 | | /** |
10586 | | Get a value from array by token. |
10587 | | @param arr an array, should not be NULL or non-array type |
10588 | | @param token a JSON pointer token |
10589 | | @param len unescaped token length |
10590 | | @param esc number of escaped characters in this token |
10591 | | @return value at index, or NULL if token is not index or index is out of range |
10592 | | */ |
10593 | | static_inline yyjson_val *ptr_arr_get(const yyjson_val *arr, const char *token, |
10594 | 0 | usize len, usize esc) { |
10595 | 0 | yyjson_val *val = unsafe_yyjson_get_first(arr); |
10596 | 0 | usize num = unsafe_yyjson_get_len(arr), idx = 0; |
10597 | 0 | if (unlikely(num == 0)) return NULL; |
10598 | 0 | if (unlikely(!ptr_token_to_idx(token, len, &idx))) return NULL; |
10599 | 0 | if (unlikely(idx >= num)) return NULL; |
10600 | 0 | if (unsafe_yyjson_arr_is_flat(arr)) { |
10601 | 0 | return val + idx; |
10602 | 0 | } else { |
10603 | 0 | while (idx-- > 0) val = unsafe_yyjson_get_next(val); |
10604 | 0 | return val; |
10605 | 0 | } |
10606 | 0 | } |
10607 | | |
10608 | | /** |
10609 | | Get a value from object by token. |
10610 | | @param obj [in] an object, should not be NULL or non-object type |
10611 | | @param token [in] a JSON pointer token |
10612 | | @param len [in] unescaped token length |
10613 | | @param esc [in] number of escaped characters in this token |
10614 | | @return value associated with the token, or NULL if no value |
10615 | | */ |
10616 | | static_inline yyjson_val *ptr_obj_get(const yyjson_val *obj, const char *token, |
10617 | 0 | usize len, usize esc) { |
10618 | 0 | yyjson_val *key = unsafe_yyjson_get_first(obj); |
10619 | 0 | usize num = unsafe_yyjson_get_len(obj); |
10620 | 0 | if (unlikely(num == 0)) return NULL; |
10621 | 0 | for (; num > 0; num--, key = unsafe_yyjson_get_next(key + 1)) { |
10622 | 0 | if (ptr_token_eq(key, token, len, esc)) return key + 1; |
10623 | 0 | } |
10624 | 0 | return NULL; |
10625 | 0 | } |
10626 | | |
10627 | | /** |
10628 | | Get a value from array by token. |
10629 | | @param arr [in] an array, should not be NULL or non-array type |
10630 | | @param token [in] a JSON pointer token |
10631 | | @param len [in] unescaped token length |
10632 | | @param esc [in] number of escaped characters in this token |
10633 | | @param pre [out] previous (sibling) value of the returned value |
10634 | | @param last [out] whether index is last |
10635 | | @return value at index, or NULL if token is not index or index is out of range |
10636 | | */ |
10637 | | static_inline yyjson_mut_val *ptr_mut_arr_get(const yyjson_mut_val *arr, |
10638 | | const char *token, |
10639 | | usize len, usize esc, |
10640 | | yyjson_mut_val **pre, |
10641 | 22.4k | bool *last) { |
10642 | 22.4k | yyjson_mut_val *val = (yyjson_mut_val *)arr->uni.ptr; /* last (tail) */ |
10643 | 22.4k | usize num = unsafe_yyjson_get_len(arr), idx; |
10644 | 22.4k | if (last) *last = false; |
10645 | 22.4k | if (pre) *pre = NULL; |
10646 | 22.4k | if (unlikely(num == 0)) { |
10647 | 434 | if (last && len == 1 && (*token == '0' || *token == '-')) *last = true; |
10648 | 434 | return NULL; |
10649 | 434 | } |
10650 | 22.0k | if (unlikely(!ptr_token_to_idx(token, len, &idx))) return NULL; |
10651 | 21.8k | if (last) *last = (idx == num || idx == USIZE_MAX); |
10652 | 21.8k | if (unlikely(idx >= num)) return NULL; |
10653 | 65.1k | while (idx-- > 0) val = val->next; |
10654 | 18.9k | if (pre) *pre = val; |
10655 | 18.9k | return val->next; |
10656 | 21.8k | } |
10657 | | |
10658 | | /** |
10659 | | Get a value from object by token. |
10660 | | @param obj [in] an object, should not be NULL or non-object type |
10661 | | @param token [in] a JSON pointer token |
10662 | | @param len [in] unescaped token length |
10663 | | @param esc [in] number of escaped characters in this token |
10664 | | @param pre [out] previous (sibling) key of the returned value's key |
10665 | | @return value associated with the token, or NULL if no value |
10666 | | */ |
10667 | | static_inline yyjson_mut_val *ptr_mut_obj_get(const yyjson_mut_val *obj, |
10668 | | const char *token, |
10669 | | usize len, usize esc, |
10670 | 12.5k | yyjson_mut_val **pre) { |
10671 | 12.5k | yyjson_mut_val *pre_key = (yyjson_mut_val *)obj->uni.ptr, *key; |
10672 | 12.5k | usize num = unsafe_yyjson_get_len(obj); |
10673 | 12.5k | if (pre) *pre = NULL; |
10674 | 12.5k | if (unlikely(num == 0)) return NULL; |
10675 | 71.8k | for (; num > 0; num--, pre_key = key) { |
10676 | 66.7k | key = pre_key->next->next; |
10677 | 66.7k | if (ptr_token_eq(key, token, len, esc)) { |
10678 | 6.73k | if (pre) *pre = pre_key; |
10679 | 6.73k | return key->next; |
10680 | 6.73k | } |
10681 | 66.7k | } |
10682 | 5.16k | return NULL; |
10683 | 11.8k | } |
10684 | | |
10685 | | /** |
10686 | | Create a string value with JSON pointer token. |
10687 | | @param token [in] a JSON pointer token |
10688 | | @param len [in] unescaped token length |
10689 | | @param esc [in] number of escaped characters in this token |
10690 | | @param doc [in] used for memory allocation when creating value |
10691 | | @return new string value, or NULL if memory allocation failed |
10692 | | */ |
10693 | | static_inline yyjson_mut_val *ptr_new_key(const char *token, |
10694 | | usize len, usize esc, |
10695 | 10.1k | yyjson_mut_doc *doc) { |
10696 | 10.1k | const char *src = token; |
10697 | 10.1k | if (likely(!esc)) { |
10698 | 7.97k | return yyjson_mut_strncpy(doc, src, len); |
10699 | 7.97k | } else { |
10700 | 2.13k | const char *end = src + len + esc; |
10701 | 2.13k | char *dst = unsafe_yyjson_mut_str_alc(doc, len + esc); |
10702 | 2.13k | char *str = dst; |
10703 | 2.13k | if (unlikely(!dst)) return NULL; |
10704 | 80.5k | for (; src < end; src++, dst++) { |
10705 | 78.4k | if (*src != '~') *dst = *src; |
10706 | 2.85k | else *dst = (*++src == '0' ? '~' : '/'); |
10707 | 78.4k | } |
10708 | 2.12k | *dst = '\0'; |
10709 | 2.12k | return yyjson_mut_strn(doc, str, len); |
10710 | 2.13k | } |
10711 | 10.1k | } |
10712 | | |
10713 | | /* macros for yyjson_ptr */ |
10714 | 995 | #define return_err(_ret, _code, _pos, _msg) do { \ |
10715 | 995 | if (err) { \ |
10716 | 995 | err->code = YYJSON_PTR_ERR_##_code; \ |
10717 | 995 | err->msg = _msg; \ |
10718 | 995 | err->pos = (usize)(_pos); \ |
10719 | 995 | } \ |
10720 | 995 | return _ret; \ |
10721 | 995 | } while (false) |
10722 | | |
10723 | | #define return_err_resolve(_ret, _pos) \ |
10724 | 934 | return_err(_ret, RESOLVE, _pos, "JSON pointer cannot be resolved") |
10725 | | #define return_err_syntax(_ret, _pos) \ |
10726 | 54 | return_err(_ret, SYNTAX, _pos, "invalid escaped character") |
10727 | | #define return_err_alloc(_ret) \ |
10728 | 7 | return_err(_ret, MEMORY_ALLOCATION, 0, "failed to create value") |
10729 | | |
10730 | | yyjson_val *unsafe_yyjson_ptr_getx(const yyjson_val *val, |
10731 | | const char *ptr, size_t ptr_len, |
10732 | 0 | yyjson_ptr_err *err) { |
10733 | |
|
10734 | 0 | const char *hdr = ptr, *end = ptr + ptr_len, *token; |
10735 | 0 | usize len, esc; |
10736 | 0 | yyjson_type type; |
10737 | |
|
10738 | 0 | while (true) { |
10739 | 0 | token = ptr_next_token(&ptr, end, &len, &esc); |
10740 | 0 | if (unlikely(!token)) return_err_syntax(NULL, ptr - hdr); |
10741 | 0 | type = unsafe_yyjson_get_type(val); |
10742 | 0 | if (type == YYJSON_TYPE_OBJ) { |
10743 | 0 | val = ptr_obj_get(val, token, len, esc); |
10744 | 0 | } else if (type == YYJSON_TYPE_ARR) { |
10745 | 0 | val = ptr_arr_get(val, token, len, esc); |
10746 | 0 | } else { |
10747 | 0 | val = NULL; |
10748 | 0 | } |
10749 | 0 | if (!val) return_err_resolve(NULL, token - hdr); |
10750 | 0 | if (ptr == end) return constcast(yyjson_val *)val; |
10751 | 0 | } |
10752 | 0 | } |
10753 | | |
10754 | | yyjson_mut_val *unsafe_yyjson_mut_ptr_getx( |
10755 | | const yyjson_mut_val *val, const char *ptr, size_t ptr_len, |
10756 | 10.0k | yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) { |
10757 | | |
10758 | 10.0k | const char *hdr = ptr, *end = ptr + ptr_len, *token; |
10759 | 10.0k | usize len, esc; |
10760 | 10.0k | yyjson_mut_val *ctn, *pre = NULL; |
10761 | 10.0k | yyjson_type type; |
10762 | 10.0k | bool idx_is_last = false; |
10763 | | |
10764 | 10.6k | while (true) { |
10765 | 10.6k | token = ptr_next_token(&ptr, end, &len, &esc); |
10766 | 10.6k | if (unlikely(!token)) return_err_syntax(NULL, ptr - hdr); |
10767 | 10.6k | ctn = constcast(yyjson_mut_val *)val; |
10768 | 10.6k | type = unsafe_yyjson_get_type(val); |
10769 | 10.6k | if (type == YYJSON_TYPE_OBJ) { |
10770 | 1.92k | val = ptr_mut_obj_get(val, token, len, esc, &pre); |
10771 | 8.68k | } else if (type == YYJSON_TYPE_ARR) { |
10772 | 8.67k | val = ptr_mut_arr_get(val, token, len, esc, &pre, &idx_is_last); |
10773 | 8.67k | } else { |
10774 | 14 | val = NULL; |
10775 | 14 | } |
10776 | 10.6k | if (ctx && (ptr == end)) { |
10777 | 5.07k | if (type == YYJSON_TYPE_OBJ || |
10778 | 4.81k | (type == YYJSON_TYPE_ARR && (val || idx_is_last))) { |
10779 | 4.81k | ctx->ctn = ctn; |
10780 | 4.81k | ctx->pre = pre; |
10781 | 4.81k | } |
10782 | 5.07k | } |
10783 | 10.6k | if (!val) return_err_resolve(NULL, token - hdr); |
10784 | 10.0k | if (ptr == end) return constcast(yyjson_mut_val *)val; |
10785 | 10.0k | } |
10786 | 10.0k | } |
10787 | | |
10788 | | bool unsafe_yyjson_mut_ptr_putx( |
10789 | | yyjson_mut_val *val, const char *ptr, size_t ptr_len, |
10790 | | yyjson_mut_val *new_val, yyjson_mut_doc *doc, bool create_parent, |
10791 | 21.8k | bool insert_new, yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) { |
10792 | | |
10793 | 21.8k | const char *hdr = ptr, *end = ptr + ptr_len, *token; |
10794 | 21.8k | usize token_len, esc, ctn_len; |
10795 | 21.8k | yyjson_mut_val *ctn, *key, *pre = NULL; |
10796 | 21.8k | yyjson_mut_val *sep_ctn = NULL, *sep_key = NULL, *sep_val = NULL; |
10797 | 21.8k | yyjson_type ctn_type; |
10798 | 21.8k | bool idx_is_last = false; |
10799 | | |
10800 | | /* skip exist parent nodes */ |
10801 | 24.4k | while (true) { |
10802 | 24.4k | token = ptr_next_token(&ptr, end, &token_len, &esc); |
10803 | 24.4k | if (unlikely(!token)) return_err_syntax(false, ptr - hdr); |
10804 | 24.4k | ctn = val; |
10805 | 24.4k | ctn_type = unsafe_yyjson_get_type(ctn); |
10806 | 24.4k | if (ctn_type == YYJSON_TYPE_OBJ) { |
10807 | 10.6k | val = ptr_mut_obj_get(ctn, token, token_len, esc, &pre); |
10808 | 13.8k | } else if (ctn_type == YYJSON_TYPE_ARR) { |
10809 | 13.8k | val = ptr_mut_arr_get(ctn, token, token_len, esc, &pre, |
10810 | 13.8k | &idx_is_last); |
10811 | 13.8k | } else return_err_resolve(false, token - hdr); |
10812 | 24.4k | if (!val) break; |
10813 | 15.6k | if (ptr == end) break; /* is last token */ |
10814 | 15.6k | } |
10815 | | |
10816 | | /* create parent nodes if not exist */ |
10817 | 21.8k | if (unlikely(ptr != end)) { /* not last token */ |
10818 | 81 | if (!create_parent) return_err_resolve(false, token - hdr); |
10819 | | |
10820 | | /* add value at last index if container is array */ |
10821 | 0 | if (ctn_type == YYJSON_TYPE_ARR) { |
10822 | 0 | if (!idx_is_last || !insert_new) { |
10823 | 0 | return_err_resolve(false, token - hdr); |
10824 | 0 | } |
10825 | 0 | val = yyjson_mut_obj(doc); |
10826 | 0 | if (!val) return_err_alloc(false); |
10827 | | |
10828 | | /* delay attaching until all operations are completed */ |
10829 | 0 | sep_ctn = ctn; |
10830 | 0 | sep_key = NULL; |
10831 | 0 | sep_val = val; |
10832 | | |
10833 | | /* move to next token */ |
10834 | 0 | ctn = val; |
10835 | 0 | val = NULL; |
10836 | 0 | ctn_type = YYJSON_TYPE_OBJ; |
10837 | 0 | token = ptr_next_token(&ptr, end, &token_len, &esc); |
10838 | 0 | if (unlikely(!token)) return_err_syntax(false, ptr - hdr); |
10839 | 0 | } |
10840 | | |
10841 | | /* container is object, create parent nodes */ |
10842 | 0 | while (ptr != end) { /* not last token */ |
10843 | 0 | key = ptr_new_key(token, token_len, esc, doc); |
10844 | 0 | if (!key) return_err_alloc(false); |
10845 | 0 | val = yyjson_mut_obj(doc); |
10846 | 0 | if (!val) return_err_alloc(false); |
10847 | | |
10848 | | /* delay attaching until all operations are completed */ |
10849 | 0 | if (!sep_ctn) { |
10850 | 0 | sep_ctn = ctn; |
10851 | 0 | sep_key = key; |
10852 | 0 | sep_val = val; |
10853 | 0 | } else { |
10854 | 0 | yyjson_mut_obj_add(ctn, key, val); |
10855 | 0 | } |
10856 | | |
10857 | | /* move to next token */ |
10858 | 0 | ctn = val; |
10859 | 0 | val = NULL; |
10860 | 0 | token = ptr_next_token(&ptr, end, &token_len, &esc); |
10861 | 0 | if (unlikely(!token)) return_err_syntax(false, ptr - hdr); |
10862 | 0 | } |
10863 | 0 | } |
10864 | | |
10865 | | /* JSON pointer is resolved, insert or replace target value */ |
10866 | 21.7k | ctn_len = unsafe_yyjson_get_len(ctn); |
10867 | 21.7k | if (ctn_type == YYJSON_TYPE_OBJ) { |
10868 | 10.1k | if (ctx) ctx->ctn = ctn; |
10869 | 10.1k | if (!val || insert_new) { |
10870 | | /* insert new key-value pair */ |
10871 | 10.1k | key = ptr_new_key(token, token_len, esc, doc); |
10872 | 10.1k | if (unlikely(!key)) return_err_alloc(false); |
10873 | 10.0k | if (ctx) ctx->pre = ctn_len ? (yyjson_mut_val *)ctn->uni.ptr : key; |
10874 | 10.0k | unsafe_yyjson_mut_obj_add(ctn, key, new_val, ctn_len); |
10875 | 10.0k | } else { |
10876 | | /* replace exist value */ |
10877 | 0 | key = pre->next->next; |
10878 | 0 | if (ctx) ctx->pre = pre; |
10879 | 0 | if (ctx) ctx->old = val; |
10880 | 0 | yyjson_mut_obj_put(ctn, key, new_val); |
10881 | 0 | } |
10882 | 11.6k | } else { |
10883 | | /* array */ |
10884 | 11.6k | if (ctx && (val || idx_is_last)) ctx->ctn = ctn; |
10885 | 11.6k | if (insert_new) { |
10886 | | /* append new value */ |
10887 | 11.6k | if (val) { |
10888 | 8.50k | pre->next = new_val; |
10889 | 8.50k | new_val->next = val; |
10890 | 8.50k | if (ctx) ctx->pre = pre; |
10891 | 8.50k | unsafe_yyjson_set_len(ctn, ctn_len + 1); |
10892 | 8.50k | } else if (idx_is_last) { |
10893 | 2.87k | if (ctx) ctx->pre = ctn_len ? |
10894 | 0 | (yyjson_mut_val *)ctn->uni.ptr : new_val; |
10895 | 2.87k | yyjson_mut_arr_append(ctn, new_val); |
10896 | 2.87k | } else { |
10897 | 258 | return_err_resolve(false, token - hdr); |
10898 | 258 | } |
10899 | 11.6k | } else { |
10900 | | /* replace exist value */ |
10901 | 0 | if (!val) return_err_resolve(false, token - hdr); |
10902 | 0 | if (ctn_len > 1) { |
10903 | 0 | new_val->next = val->next; |
10904 | 0 | pre->next = new_val; |
10905 | 0 | if (ctn->uni.ptr == val) ctn->uni.ptr = new_val; |
10906 | 0 | } else { |
10907 | 0 | new_val->next = new_val; |
10908 | 0 | ctn->uni.ptr = new_val; |
10909 | 0 | pre = new_val; |
10910 | 0 | } |
10911 | 0 | if (ctx) ctx->pre = pre; |
10912 | 0 | if (ctx) ctx->old = val; |
10913 | 0 | } |
10914 | 11.6k | } |
10915 | | |
10916 | | /* all operations are completed, attach the new components to the target */ |
10917 | 21.4k | if (unlikely(sep_ctn)) { |
10918 | 0 | if (sep_key) yyjson_mut_obj_add(sep_ctn, sep_key, sep_val); |
10919 | 0 | else yyjson_mut_arr_append(sep_ctn, sep_val); |
10920 | 0 | } |
10921 | 21.4k | return true; |
10922 | 21.7k | } |
10923 | | |
10924 | | yyjson_mut_val *unsafe_yyjson_mut_ptr_replacex( |
10925 | | yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val, |
10926 | 2.90k | yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) { |
10927 | | |
10928 | 2.90k | yyjson_mut_val *cur_val; |
10929 | 2.90k | yyjson_ptr_ctx cur_ctx; |
10930 | 2.90k | memset(&cur_ctx, 0, sizeof(cur_ctx)); |
10931 | 2.90k | if (!ctx) ctx = &cur_ctx; |
10932 | 2.90k | cur_val = unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err); |
10933 | 2.90k | if (!cur_val) return NULL; |
10934 | | |
10935 | 2.86k | if (yyjson_mut_is_obj(ctx->ctn)) { |
10936 | 396 | yyjson_mut_val *key = ctx->pre->next->next; |
10937 | 396 | yyjson_mut_obj_put(ctx->ctn, key, new_val); |
10938 | 2.46k | } else { |
10939 | 2.46k | yyjson_ptr_ctx_replace(ctx, new_val); |
10940 | 2.46k | } |
10941 | 2.86k | ctx->old = cur_val; |
10942 | 2.86k | return cur_val; |
10943 | 2.90k | } |
10944 | | |
10945 | | yyjson_mut_val *unsafe_yyjson_mut_ptr_removex( |
10946 | | yyjson_mut_val *val, const char *ptr, size_t len, |
10947 | 2.24k | yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) { |
10948 | | |
10949 | 2.24k | yyjson_mut_val *cur_val; |
10950 | 2.24k | yyjson_ptr_ctx cur_ctx; |
10951 | 2.24k | memset(&cur_ctx, 0, sizeof(cur_ctx)); |
10952 | 2.24k | if (!ctx) ctx = &cur_ctx; |
10953 | 2.24k | cur_val = unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err); |
10954 | 2.24k | if (cur_val) { |
10955 | 1.87k | if (yyjson_mut_is_obj(ctx->ctn)) { |
10956 | 456 | yyjson_mut_val *key = ctx->pre->next->next; |
10957 | 456 | yyjson_mut_obj_put(ctx->ctn, key, NULL); |
10958 | 1.41k | } else { |
10959 | 1.41k | yyjson_ptr_ctx_remove(ctx); |
10960 | 1.41k | } |
10961 | 1.87k | ctx->pre = NULL; |
10962 | 1.87k | ctx->old = cur_val; |
10963 | 1.87k | } |
10964 | 2.24k | return cur_val; |
10965 | 2.24k | } |
10966 | | |
10967 | | /* macros for yyjson_ptr */ |
10968 | | #undef return_err |
10969 | | #undef return_err_resolve |
10970 | | #undef return_err_syntax |
10971 | | #undef return_err_alloc |
10972 | | |
10973 | | |
10974 | | |
10975 | | /*============================================================================== |
10976 | | * MARK: - JSON Patch API (RFC 6902) (Public) |
10977 | | *============================================================================*/ |
10978 | | |
10979 | | /* JSON Patch operation */ |
10980 | | typedef enum patch_op { |
10981 | | PATCH_OP_ADD, /* path, value */ |
10982 | | PATCH_OP_REMOVE, /* path */ |
10983 | | PATCH_OP_REPLACE, /* path, value */ |
10984 | | PATCH_OP_MOVE, /* from, path */ |
10985 | | PATCH_OP_COPY, /* from, path */ |
10986 | | PATCH_OP_TEST, /* path, value */ |
10987 | | PATCH_OP_NONE /* invalid */ |
10988 | | } patch_op; |
10989 | | |
10990 | 29.5k | static patch_op patch_op_get(yyjson_val *op) { |
10991 | 29.5k | const char *str = op->uni.str; |
10992 | 29.5k | switch (unsafe_yyjson_get_len(op)) { |
10993 | 7.49k | case 3: |
10994 | 7.49k | if (!memcmp(str, "add", 3)) return PATCH_OP_ADD; |
10995 | 16 | return PATCH_OP_NONE; |
10996 | 17.9k | case 4: |
10997 | 17.9k | if (!memcmp(str, "move", 4)) return PATCH_OP_MOVE; |
10998 | 16.4k | if (!memcmp(str, "copy", 4)) return PATCH_OP_COPY; |
10999 | 1.72k | if (!memcmp(str, "test", 4)) return PATCH_OP_TEST; |
11000 | 35 | return PATCH_OP_NONE; |
11001 | 966 | case 6: |
11002 | 966 | if (!memcmp(str, "remove", 6)) return PATCH_OP_REMOVE; |
11003 | 19 | return PATCH_OP_NONE; |
11004 | 3.10k | case 7: |
11005 | 3.10k | if (!memcmp(str, "replace", 7)) return PATCH_OP_REPLACE; |
11006 | 31 | return PATCH_OP_NONE; |
11007 | 84 | default: |
11008 | 84 | return PATCH_OP_NONE; |
11009 | 29.5k | } |
11010 | 29.5k | } |
11011 | | |
11012 | | /* macros for yyjson_patch */ |
11013 | 3.17k | #define return_err(_code, _msg) do { \ |
11014 | 3.17k | if (err->ptr.code == YYJSON_PTR_ERR_MEMORY_ALLOCATION) { \ |
11015 | 7 | err->code = YYJSON_PATCH_ERROR_MEMORY_ALLOCATION; \ |
11016 | 7 | err->msg = _msg; \ |
11017 | 7 | memset(&err->ptr, 0, sizeof(yyjson_ptr_err)); \ |
11018 | 3.16k | } else { \ |
11019 | 3.16k | err->code = YYJSON_PATCH_ERROR_##_code; \ |
11020 | 3.16k | err->msg = _msg; \ |
11021 | 3.16k | err->idx = iter.idx ? iter.idx - 1 : 0; \ |
11022 | 3.16k | } \ |
11023 | 3.17k | return NULL; \ |
11024 | 3.17k | } while (false) |
11025 | | |
11026 | | #define return_err_copy() \ |
11027 | 205 | return_err(MEMORY_ALLOCATION, "failed to copy value") |
11028 | | #define return_err_key(_key) \ |
11029 | 752 | return_err(MISSING_KEY, "missing key " _key) |
11030 | | #define return_err_val(_key) \ |
11031 | 16 | return_err(INVALID_MEMBER, "invalid member " _key) |
11032 | | |
11033 | 16.3k | #define ptr_get(_ptr) yyjson_mut_ptr_getx( \ |
11034 | 16.3k | root, _ptr->uni.str, _ptr##_len, NULL, &err->ptr) |
11035 | | #define ptr_add(_ptr, _val) yyjson_mut_ptr_addx( \ |
11036 | | root, _ptr->uni.str, _ptr##_len, _val, doc, false, NULL, &err->ptr) |
11037 | 1.35k | #define ptr_remove(_ptr) yyjson_mut_ptr_removex( \ |
11038 | 1.35k | root, _ptr->uni.str, _ptr##_len, NULL, &err->ptr) |
11039 | | #define ptr_replace(_ptr, _val)yyjson_mut_ptr_replacex( \ |
11040 | | root, _ptr->uni.str, _ptr##_len, _val, NULL, &err->ptr) |
11041 | | |
11042 | | yyjson_mut_val *yyjson_patch(yyjson_mut_doc *doc, |
11043 | | const yyjson_val *orig, |
11044 | | const yyjson_val *patch, |
11045 | 5.79k | yyjson_patch_err *err) { |
11046 | | |
11047 | 5.79k | yyjson_mut_val *root; |
11048 | 5.79k | yyjson_val *obj; |
11049 | 5.79k | yyjson_arr_iter iter; |
11050 | 5.79k | yyjson_patch_err err_tmp; |
11051 | 5.79k | if (!err) err = &err_tmp; |
11052 | 5.79k | memset(err, 0, sizeof(*err)); |
11053 | 5.79k | memset(&iter, 0, sizeof(iter)); |
11054 | | |
11055 | 5.79k | if (unlikely(!doc || !orig || !patch)) { |
11056 | 0 | return_err(INVALID_PARAMETER, "input parameter is NULL"); |
11057 | 0 | } |
11058 | 5.79k | if (unlikely(!yyjson_is_arr(patch))) { |
11059 | 115 | return_err(INVALID_PARAMETER, "input patch is not array"); |
11060 | 115 | } |
11061 | 5.67k | root = yyjson_val_mut_copy(doc, orig); |
11062 | 5.67k | if (unlikely(!root)) return_err_copy(); |
11063 | | |
11064 | | /* iterate through the patch array */ |
11065 | 5.67k | yyjson_arr_iter_init(patch, &iter); |
11066 | 19.2k | while ((obj = yyjson_arr_iter_next(&iter))) { |
11067 | 15.0k | patch_op op_enum; |
11068 | 15.0k | yyjson_val *op, *path, *from = NULL, *value; |
11069 | 15.0k | yyjson_mut_val *val = NULL, *test; |
11070 | 15.0k | usize path_len, from_len = 0; |
11071 | 15.0k | if (unlikely(!unsafe_yyjson_is_obj(obj))) { |
11072 | 19 | return_err(INVALID_OPERATION, "JSON patch operation is not object"); |
11073 | 19 | } |
11074 | | |
11075 | | /* get required member: op */ |
11076 | 14.9k | op = yyjson_obj_get(obj, "op"); |
11077 | 14.9k | if (unlikely(!op)) return_err_key("`op`"); |
11078 | 14.8k | if (unlikely(!yyjson_is_str(op))) return_err_val("`op`"); |
11079 | 14.8k | op_enum = patch_op_get(op); |
11080 | | |
11081 | | /* get required member: path */ |
11082 | 14.8k | path = yyjson_obj_get(obj, "path"); |
11083 | 14.8k | if (unlikely(!path)) return_err_key("`path`"); |
11084 | 14.6k | if (unlikely(!yyjson_is_str(path))) return_err_val("`path`"); |
11085 | 14.6k | path_len = unsafe_yyjson_get_len(path); |
11086 | | |
11087 | | /* get required member: value, from */ |
11088 | 14.6k | switch ((int)op_enum) { |
11089 | 6.09k | case PATCH_OP_ADD: case PATCH_OP_REPLACE: case PATCH_OP_TEST: |
11090 | 6.09k | value = yyjson_obj_get(obj, "value"); |
11091 | 6.09k | if (unlikely(!value)) return_err_key("`value`"); |
11092 | 6.03k | val = yyjson_val_mut_copy(doc, value); |
11093 | 6.03k | if (unlikely(!val)) return_err_copy(); |
11094 | 6.03k | break; |
11095 | 8.10k | case PATCH_OP_MOVE: case PATCH_OP_COPY: |
11096 | 8.10k | from = yyjson_obj_get(obj, "from"); |
11097 | 8.10k | if (unlikely(!from)) return_err_key("`from`"); |
11098 | 8.06k | if (unlikely(!yyjson_is_str(from))) return_err_val("`from`"); |
11099 | 8.06k | from_len = unsafe_yyjson_get_len(from); |
11100 | 8.06k | break; |
11101 | 498 | default: |
11102 | 498 | break; |
11103 | 14.6k | } |
11104 | | |
11105 | | /* perform an operation */ |
11106 | 14.6k | switch ((int)op_enum) { |
11107 | 3.67k | case PATCH_OP_ADD: /* add(path, val) */ |
11108 | 3.67k | if (unlikely(path_len == 0)) { root = val; break; } |
11109 | 3.20k | if (unlikely(!ptr_add(path, val))) { |
11110 | 121 | return_err(POINTER, "failed to add `path`"); |
11111 | 121 | } |
11112 | 3.08k | break; |
11113 | 3.08k | case PATCH_OP_REMOVE: /* remove(path) */ |
11114 | 468 | if (unlikely(!ptr_remove(path))) { |
11115 | 162 | return_err(POINTER, "failed to remove `path`"); |
11116 | 162 | } |
11117 | 306 | break; |
11118 | 1.53k | case PATCH_OP_REPLACE: /* replace(path, val) */ |
11119 | 1.53k | if (unlikely(path_len == 0)) { root = val; break; } |
11120 | 1.45k | if (unlikely(!ptr_replace(path, val))) { |
11121 | 27 | return_err(POINTER, "failed to replace `path`"); |
11122 | 27 | } |
11123 | 1.43k | break; |
11124 | 1.43k | case PATCH_OP_MOVE: /* val = remove(from), add(path, val) */ |
11125 | 723 | if (unlikely(from_len == 0 && path_len == 0)) break; |
11126 | 687 | val = ptr_remove(from); |
11127 | 687 | if (unlikely(!val)) { |
11128 | 52 | return_err(POINTER, "failed to remove `from`"); |
11129 | 52 | } |
11130 | 635 | if (unlikely(path_len == 0)) { root = val; break; } |
11131 | 596 | if (unlikely(!ptr_add(path, val))) { |
11132 | 41 | return_err(POINTER, "failed to add `path`"); |
11133 | 41 | } |
11134 | 555 | break; |
11135 | 7.34k | case PATCH_OP_COPY: /* val = get(from).copy, add(path, val) */ |
11136 | 7.34k | val = ptr_get(from); |
11137 | 7.34k | if (unlikely(!val)) { |
11138 | 29 | return_err(POINTER, "failed to get `from`"); |
11139 | 29 | } |
11140 | 7.31k | if (unlikely(path_len == 0)) { root = val; break; } |
11141 | 7.26k | val = yyjson_mut_val_mut_copy(doc, val); |
11142 | 7.26k | if (unlikely(!val)) return_err_copy(); |
11143 | 7.24k | if (unlikely(!ptr_add(path, val))) { |
11144 | 74 | return_err(POINTER, "failed to add `path`"); |
11145 | 74 | } |
11146 | 7.17k | break; |
11147 | 7.17k | case PATCH_OP_TEST: /* test = get(path), test.eq(val) */ |
11148 | 825 | test = ptr_get(path); |
11149 | 825 | if (unlikely(!test)) { |
11150 | 89 | return_err(POINTER, "failed to get `path`"); |
11151 | 89 | } |
11152 | 736 | if (unlikely(!yyjson_mut_equals(val, test))) { |
11153 | 368 | return_err(EQUAL, "failed to test equal"); |
11154 | 368 | } |
11155 | 368 | break; |
11156 | 368 | default: |
11157 | 30 | return_err(INVALID_MEMBER, "unsupported `op`"); |
11158 | 14.6k | } |
11159 | 14.6k | } |
11160 | 4.25k | return root; |
11161 | 5.67k | } |
11162 | | |
11163 | | yyjson_mut_val *yyjson_mut_patch(yyjson_mut_doc *doc, |
11164 | | const yyjson_mut_val *orig, |
11165 | | const yyjson_mut_val *patch, |
11166 | 5.79k | yyjson_patch_err *err) { |
11167 | 5.79k | yyjson_mut_val *root, *obj; |
11168 | 5.79k | yyjson_mut_arr_iter iter; |
11169 | 5.79k | yyjson_patch_err err_tmp; |
11170 | 5.79k | if (!err) err = &err_tmp; |
11171 | 5.79k | memset(err, 0, sizeof(*err)); |
11172 | 5.79k | memset(&iter, 0, sizeof(iter)); |
11173 | | |
11174 | 5.79k | if (unlikely(!doc || !orig || !patch)) { |
11175 | 0 | return_err(INVALID_PARAMETER, "input parameter is NULL"); |
11176 | 0 | } |
11177 | 5.79k | if (unlikely(!yyjson_mut_is_arr(patch))) { |
11178 | 115 | return_err(INVALID_PARAMETER, "input patch is not array"); |
11179 | 115 | } |
11180 | 5.67k | root = yyjson_mut_val_mut_copy(doc, orig); |
11181 | 5.67k | if (unlikely(!root)) return_err_copy(); |
11182 | | |
11183 | | /* iterate through the patch array */ |
11184 | 5.67k | yyjson_mut_arr_iter_init(constcast(yyjson_mut_val *)patch, &iter); |
11185 | 19.1k | while ((obj = yyjson_mut_arr_iter_next(&iter))) { |
11186 | 14.9k | patch_op op_enum; |
11187 | 14.9k | yyjson_mut_val *op, *path, *from = NULL, *value; |
11188 | 14.9k | yyjson_mut_val *val = NULL, *test; |
11189 | 14.9k | usize path_len, from_len = 0; |
11190 | 14.9k | if (!unsafe_yyjson_is_obj(obj)) { |
11191 | 19 | return_err(INVALID_OPERATION, "JSON patch operation is not object"); |
11192 | 19 | } |
11193 | | |
11194 | | /* get required member: op */ |
11195 | 14.9k | op = yyjson_mut_obj_get(obj, "op"); |
11196 | 14.9k | if (unlikely(!op)) return_err_key("`op`"); |
11197 | 14.7k | if (unlikely(!yyjson_mut_is_str(op))) return_err_val("`op`"); |
11198 | 14.7k | op_enum = patch_op_get((yyjson_val *)(void *)op); |
11199 | | |
11200 | | /* get required member: path */ |
11201 | 14.7k | path = yyjson_mut_obj_get(obj, "path"); |
11202 | 14.7k | if (unlikely(!path)) return_err_key("`path`"); |
11203 | 14.6k | if (unlikely(!yyjson_mut_is_str(path))) return_err_val("`path`"); |
11204 | 14.6k | path_len = unsafe_yyjson_get_len(path); |
11205 | | |
11206 | | /* get required member: value, from */ |
11207 | 14.6k | switch ((int)op_enum) { |
11208 | 6.08k | case PATCH_OP_ADD: case PATCH_OP_REPLACE: case PATCH_OP_TEST: |
11209 | 6.08k | value = yyjson_mut_obj_get(obj, "value"); |
11210 | 6.08k | if (unlikely(!value)) return_err_key("`value`"); |
11211 | 6.02k | val = yyjson_mut_val_mut_copy(doc, value); |
11212 | 6.02k | if (unlikely(!val)) return_err_copy(); |
11213 | 6.02k | break; |
11214 | 8.07k | case PATCH_OP_MOVE: case PATCH_OP_COPY: |
11215 | 8.07k | from = yyjson_mut_obj_get(obj, "from"); |
11216 | 8.07k | if (unlikely(!from)) return_err_key("`from`"); |
11217 | 8.04k | if (unlikely(!yyjson_mut_is_str(from))) { |
11218 | 1 | return_err_val("`from`"); |
11219 | 1 | } |
11220 | 8.04k | from_len = unsafe_yyjson_get_len(from); |
11221 | 8.04k | break; |
11222 | 487 | default: |
11223 | 487 | break; |
11224 | 14.6k | } |
11225 | | |
11226 | | /* perform an operation */ |
11227 | 14.5k | switch ((int)op_enum) { |
11228 | 3.67k | case PATCH_OP_ADD: /* add(path, val) */ |
11229 | 3.67k | if (unlikely(path_len == 0)) { root = val; break; } |
11230 | 3.20k | if (unlikely(!ptr_add(path, val))) { |
11231 | 120 | return_err(POINTER, "failed to add `path`"); |
11232 | 120 | } |
11233 | 3.08k | break; |
11234 | 3.08k | case PATCH_OP_REMOVE: /* remove(path) */ |
11235 | 465 | if (unlikely(!ptr_remove(path))) { |
11236 | 161 | return_err(POINTER, "failed to remove `path`"); |
11237 | 161 | } |
11238 | 304 | break; |
11239 | 1.53k | case PATCH_OP_REPLACE: /* replace(path, val) */ |
11240 | 1.53k | if (unlikely(path_len == 0)) { root = val; break; } |
11241 | 1.45k | if (unlikely(!ptr_replace(path, val))) { |
11242 | 25 | return_err(POINTER, "failed to replace `path`"); |
11243 | 25 | } |
11244 | 1.43k | break; |
11245 | 1.43k | case PATCH_OP_MOVE: /* val = remove(from), add(path, val) */ |
11246 | 705 | if (unlikely(from_len == 0 && path_len == 0)) break; |
11247 | 669 | val = ptr_remove(from); |
11248 | 669 | if (unlikely(!val)) { |
11249 | 39 | return_err(POINTER, "failed to remove `from`"); |
11250 | 39 | } |
11251 | 630 | if (unlikely(path_len == 0)) { root = val; break; } |
11252 | 591 | if (unlikely(!ptr_add(path, val))) { |
11253 | 41 | return_err(POINTER, "failed to add `path`"); |
11254 | 41 | } |
11255 | 550 | break; |
11256 | 7.33k | case PATCH_OP_COPY: /* val = get(from).copy, add(path, val) */ |
11257 | 7.33k | val = ptr_get(from); |
11258 | 7.33k | if (unlikely(!val)) { |
11259 | 26 | return_err(POINTER, "failed to get `from`"); |
11260 | 26 | } |
11261 | 7.31k | if (unlikely(path_len == 0)) { root = val; break; } |
11262 | 7.26k | val = yyjson_mut_val_mut_copy(doc, val); |
11263 | 7.26k | if (unlikely(!val)) return_err_copy(); |
11264 | 7.07k | if (unlikely(!ptr_add(path, val))) { |
11265 | 53 | return_err(POINTER, "failed to add `path`"); |
11266 | 53 | } |
11267 | 7.02k | break; |
11268 | 7.02k | case PATCH_OP_TEST: /* test = get(path), test.eq(val) */ |
11269 | 819 | test = ptr_get(path); |
11270 | 819 | if (unlikely(!test)) { |
11271 | 89 | return_err(POINTER, "failed to get `path`"); |
11272 | 89 | } |
11273 | 730 | if (unlikely(!yyjson_mut_equals(val, test))) { |
11274 | 363 | return_err(EQUAL, "failed to test equal"); |
11275 | 363 | } |
11276 | 367 | break; |
11277 | 367 | default: |
11278 | 22 | return_err(INVALID_MEMBER, "unsupported `op`"); |
11279 | 14.5k | } |
11280 | 14.5k | } |
11281 | 4.15k | return root; |
11282 | 5.67k | } |
11283 | | |
11284 | | /* macros for yyjson_patch */ |
11285 | | #undef return_err |
11286 | | #undef return_err_copy |
11287 | | #undef return_err_key |
11288 | | #undef return_err_val |
11289 | | #undef ptr_get |
11290 | | #undef ptr_add |
11291 | | #undef ptr_remove |
11292 | | #undef ptr_replace |
11293 | | |
11294 | | |
11295 | | |
11296 | | /*============================================================================== |
11297 | | * MARK: - JSON Merge-Patch API (RFC 7386) (Public) |
11298 | | *============================================================================*/ |
11299 | | |
11300 | | yyjson_mut_val *yyjson_merge_patch(yyjson_mut_doc *doc, |
11301 | | const yyjson_val *orig, |
11302 | 18.6k | const yyjson_val *patch) { |
11303 | 18.6k | usize idx, max; |
11304 | 18.6k | yyjson_val *key, *orig_val, *patch_val, local_orig; |
11305 | 18.6k | yyjson_mut_val *builder, *mut_key, *mut_val, *merged_val; |
11306 | | |
11307 | 18.6k | if (unlikely(!yyjson_is_obj(patch))) { |
11308 | 9.08k | return yyjson_val_mut_copy(doc, patch); |
11309 | 9.08k | } |
11310 | | |
11311 | 9.56k | builder = yyjson_mut_obj(doc); |
11312 | 9.56k | if (unlikely(!builder)) return NULL; |
11313 | | |
11314 | 9.56k | memset(&local_orig, 0, sizeof(local_orig)); |
11315 | 9.56k | if (!yyjson_is_obj(orig)) { |
11316 | 4.75k | local_orig.tag = builder->tag; |
11317 | 4.75k | local_orig.uni = builder->uni; |
11318 | 4.75k | orig = &local_orig; |
11319 | 4.75k | } |
11320 | | |
11321 | | /* If orig is contributing, copy any items not modified by the patch */ |
11322 | 9.56k | if (orig != &local_orig) { |
11323 | 5.11k | yyjson_obj_foreach(orig, idx, max, key, orig_val) { |
11324 | 5.11k | patch_val = yyjson_obj_getn(patch, |
11325 | 5.11k | unsafe_yyjson_get_str(key), |
11326 | 5.11k | unsafe_yyjson_get_len(key)); |
11327 | 5.11k | if (!patch_val) { |
11328 | 4.69k | mut_key = yyjson_val_mut_copy(doc, key); |
11329 | 4.69k | mut_val = yyjson_val_mut_copy(doc, orig_val); |
11330 | 4.69k | if (!yyjson_mut_obj_add(builder, mut_key, mut_val)) return NULL; |
11331 | 4.69k | } |
11332 | 5.11k | } |
11333 | 4.81k | } |
11334 | | |
11335 | | /* Merge items modified by the patch. */ |
11336 | 14.8k | yyjson_obj_foreach(patch, idx, max, key, patch_val) { |
11337 | | /* null indicates the field is removed. */ |
11338 | 14.8k | if (unsafe_yyjson_is_null(patch_val)) { |
11339 | 200 | continue; |
11340 | 200 | } |
11341 | 14.6k | mut_key = yyjson_val_mut_copy(doc, key); |
11342 | 14.6k | orig_val = yyjson_obj_getn(orig, |
11343 | 14.6k | unsafe_yyjson_get_str(key), |
11344 | 14.6k | unsafe_yyjson_get_len(key)); |
11345 | 14.6k | merged_val = yyjson_merge_patch(doc, orig_val, patch_val); |
11346 | 14.6k | if (!yyjson_mut_obj_add(builder, mut_key, merged_val)) return NULL; |
11347 | 14.6k | } |
11348 | | |
11349 | 9.56k | return builder; |
11350 | 9.56k | } |
11351 | | |
11352 | | yyjson_mut_val *yyjson_mut_merge_patch(yyjson_mut_doc *doc, |
11353 | | const yyjson_mut_val *orig, |
11354 | 18.6k | const yyjson_mut_val *patch) { |
11355 | 18.6k | usize idx, max; |
11356 | 18.6k | yyjson_mut_val *key, *orig_val, *patch_val, local_orig; |
11357 | 18.6k | yyjson_mut_val *builder, *mut_key, *mut_val, *merged_val; |
11358 | | |
11359 | 18.6k | if (unlikely(!yyjson_mut_is_obj(patch))) { |
11360 | 9.08k | return yyjson_mut_val_mut_copy(doc, patch); |
11361 | 9.08k | } |
11362 | | |
11363 | 9.56k | builder = yyjson_mut_obj(doc); |
11364 | 9.56k | if (unlikely(!builder)) return NULL; |
11365 | | |
11366 | 9.56k | memset(&local_orig, 0, sizeof(local_orig)); |
11367 | 9.56k | if (!yyjson_mut_is_obj(orig)) { |
11368 | 4.75k | local_orig.tag = builder->tag; |
11369 | 4.75k | local_orig.uni = builder->uni; |
11370 | 4.75k | orig = &local_orig; |
11371 | 4.75k | } |
11372 | | |
11373 | | /* If orig is contributing, copy any items not modified by the patch */ |
11374 | 9.56k | if (orig != &local_orig) { |
11375 | 5.11k | yyjson_mut_obj_foreach(orig, idx, max, key, orig_val) { |
11376 | 5.11k | patch_val = yyjson_mut_obj_getn(patch, |
11377 | 5.11k | unsafe_yyjson_get_str(key), |
11378 | 5.11k | unsafe_yyjson_get_len(key)); |
11379 | 5.11k | if (!patch_val) { |
11380 | 4.69k | mut_key = yyjson_mut_val_mut_copy(doc, key); |
11381 | 4.69k | mut_val = yyjson_mut_val_mut_copy(doc, orig_val); |
11382 | 4.69k | if (!yyjson_mut_obj_add(builder, mut_key, mut_val)) return NULL; |
11383 | 4.69k | } |
11384 | 5.11k | } |
11385 | 4.81k | } |
11386 | | |
11387 | | /* Merge items modified by the patch. */ |
11388 | 14.8k | yyjson_mut_obj_foreach(patch, idx, max, key, patch_val) { |
11389 | | /* null indicates the field is removed. */ |
11390 | 14.8k | if (unsafe_yyjson_is_null(patch_val)) { |
11391 | 200 | continue; |
11392 | 200 | } |
11393 | 14.6k | mut_key = yyjson_mut_val_mut_copy(doc, key); |
11394 | 14.6k | orig_val = yyjson_mut_obj_getn(orig, |
11395 | 14.6k | unsafe_yyjson_get_str(key), |
11396 | 14.6k | unsafe_yyjson_get_len(key)); |
11397 | 14.6k | merged_val = yyjson_mut_merge_patch(doc, orig_val, patch_val); |
11398 | 14.6k | if (!yyjson_mut_obj_add(builder, mut_key, merged_val)) return NULL; |
11399 | 14.6k | } |
11400 | | |
11401 | 9.56k | return builder; |
11402 | 9.56k | } |
11403 | | |
11404 | | #endif /* YYJSON_DISABLE_UTILS */ |