From 06c774c655d5bb8dfb34ea0fac3d48cfb86d80de Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Wed, 18 Feb 2026 23:50:58 -0500 Subject: [PATCH] 4.3.0 --- CMakeLists.txt | 6 +- Doxyfile | 2 +- include/simdjson/simdjson_version.h | 6 +- singleheader/simdjson.cpp | 6810 +++++++- singleheader/simdjson.h | 22854 +++++++++++++++++++++++++- singleheader/singleheader.zip | Bin 9098768 -> 10312652 bytes 6 files changed, 29490 insertions(+), 188 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d77d3467e..440ec6a9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ endif() project( simdjson # The version number is modified by tools/release.py - VERSION 4.2.4 + VERSION 4.3.0 DESCRIPTION "Parsing gigabytes of JSON per second" HOMEPAGE_URL "https://simdjson.org/" LANGUAGES CXX C @@ -29,8 +29,8 @@ string( # ---- Options, variables ---- # These version numbers are modified by tools/release.py -set(SIMDJSON_LIB_VERSION "29.0.0" CACHE STRING "simdjson library version") -set(SIMDJSON_LIB_SOVERSION "29" CACHE STRING "simdjson library soversion") +set(SIMDJSON_LIB_VERSION "30.0.0" CACHE STRING "simdjson library version") +set(SIMDJSON_LIB_SOVERSION "30" CACHE STRING "simdjson library soversion") option(SIMDJSON_BUILD_STATIC_LIB "Build simdjson_static library along with simdjson (only makes sense if BUILD_SHARED_LIBS=ON)" OFF) if(SIMDJSON_BUILD_STATIC_LIB AND NOT BUILD_SHARED_LIBS) diff --git a/Doxyfile b/Doxyfile index 25965b297..fa0f450ec 100644 --- a/Doxyfile +++ b/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = simdjson # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = "4.2.4" +PROJECT_NUMBER = "4.3.0" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/include/simdjson/simdjson_version.h b/include/simdjson/simdjson_version.h index 2f7004b46..66406f289 100644 --- a/include/simdjson/simdjson_version.h +++ b/include/simdjson/simdjson_version.h @@ -4,7 +4,7 @@ #define SIMDJSON_SIMDJSON_VERSION_H /** The version of simdjson being used (major.minor.revision) */ -#define SIMDJSON_VERSION "4.2.4" +#define SIMDJSON_VERSION "4.3.0" namespace simdjson { enum { @@ -15,11 +15,11 @@ enum { /** * The minor version (major.MINOR.revision) of simdjson being used. */ - SIMDJSON_VERSION_MINOR = 2, + SIMDJSON_VERSION_MINOR = 3, /** * The revision (major.minor.REVISION) of simdjson being used. */ - SIMDJSON_VERSION_REVISION = 4 + SIMDJSON_VERSION_REVISION = 0 }; } // namespace simdjson diff --git a/singleheader/simdjson.cpp b/singleheader/simdjson.cpp index d06853aca..010cb2242 100644 --- a/singleheader/simdjson.cpp +++ b/singleheader/simdjson.cpp @@ -1,4 +1,4 @@ -/* auto-generated on 2026-01-17 14:20:47 -0500. version 4.2.4 Do not edit! */ +/* auto-generated on 2026-02-18 20:08:53 -0500. version 4.3.0 Do not edit! */ /* including simdjson.cpp: */ /* begin file simdjson.cpp */ #define SIMDJSON_SRC_SIMDJSON_CPP @@ -198,22 +198,20 @@ using std::size_t; #define SIMDJSON_IS_ARM64 1 #elif defined(__riscv) && __riscv_xlen == 64 #define SIMDJSON_IS_RISCV64 1 + #if __riscv_v_intrinsic >= 11000 #define SIMDJSON_HAS_RVV_INTRINSICS 1 #endif - #define SIMDJSON_HAS_ZVBB_INTRINSICS \ - 0 // there is currently no way to detect this - - #if SIMDJSON_HAS_RVV_INTRINSICS && __riscv_vector && \ - __riscv_v_min_vlen >= 128 && __riscv_v_elen >= 64 - // RISC-V V extension - #define SIMDJSON_IS_RVV 1 - #if SIMDJSON_HAS_ZVBB_INTRINSICS && __riscv_zvbb >= 1000000 - // RISC-V Vector Basic Bit-manipulation - #define SIMDJSON_IS_ZVBB 1 - #endif + #if SIMDJSON_HAS_RVV_INTRINSICS && __riscv_vector && __riscv_v_min_vlen >= 128 && __riscv_v_elen >= 64 + #define SIMDJSON_IS_RVV 1 // RISC-V V extension #endif + + // current toolchains don't support fixed-size SIMD types that don't match VLEN directly + #if __riscv_v_fixed_vlen >= 128 && __riscv_v_fixed_vlen <= 512 + #define SIMDJSON_IS_RVV_VLS 1 + #endif + #elif defined(__loongarch_lp64) #define SIMDJSON_IS_LOONGARCH64 1 #if defined(__loongarch_sx) && defined(__loongarch_asx) @@ -6724,6 +6722,8 @@ SIMDJSON_DLLIMPORTEXPORT const uint64_t simdjson::internal::power_of_five_128[]= #define SIMDJSON_IMPLEMENTATION_ID_westmere 6 #define SIMDJSON_IMPLEMENTATION_ID_lsx 7 #define SIMDJSON_IMPLEMENTATION_ID_lasx 8 +//#define SIMDJSON_IMPLEMENTATION_ID_rvv 9 +#define SIMDJSON_IMPLEMENTATION_ID_rvv_vls 10 #define SIMDJSON_IMPLEMENTATION_ID_FOR(IMPL) SIMDJSON_CAT(SIMDJSON_IMPLEMENTATION_ID_, IMPL) #define SIMDJSON_IMPLEMENTATION_ID SIMDJSON_IMPLEMENTATION_ID_FOR(SIMDJSON_IMPLEMENTATION) @@ -6838,9 +6838,14 @@ SIMDJSON_DLLIMPORTEXPORT const uint64_t simdjson::internal::power_of_five_128[]= #endif #define SIMDJSON_CAN_ALWAYS_RUN_LSX (SIMDJSON_IMPLEMENTATION_LSX) +#define SIMDJSON_CAN_ALWAYS_RUN_RVV_VLS SIMDJSON_IS_RVV_VLS +#ifndef SIMDJSON_IMPLEMENTATION_RVV_VLS +#define SIMDJSON_IMPLEMENTATION_RVV_VLS SIMDJSON_CAN_ALWAYS_RUN_RVV_VLS +#endif + // Default Fallback to on unless a builtin implementation has already been selected. #ifndef SIMDJSON_IMPLEMENTATION_FALLBACK -#if SIMDJSON_CAN_ALWAYS_RUN_ARM64 || SIMDJSON_CAN_ALWAYS_RUN_ICELAKE || SIMDJSON_CAN_ALWAYS_RUN_HASWELL || SIMDJSON_CAN_ALWAYS_RUN_WESTMERE || SIMDJSON_CAN_ALWAYS_RUN_PPC64 || SIMDJSON_CAN_ALWAYS_RUN_LSX || SIMDJSON_CAN_ALWAYS_RUN_LASX +#if SIMDJSON_CAN_ALWAYS_RUN_ARM64 || SIMDJSON_CAN_ALWAYS_RUN_ICELAKE || SIMDJSON_CAN_ALWAYS_RUN_HASWELL || SIMDJSON_CAN_ALWAYS_RUN_WESTMERE || SIMDJSON_CAN_ALWAYS_RUN_PPC64 || SIMDJSON_CAN_ALWAYS_RUN_LSX || SIMDJSON_CAN_ALWAYS_RUN_LASX || SIMDJSON_CAN_ALWAYS_RUN_RVV_VLS // if anything at all except fallback can always run, then disable fallback. #define SIMDJSON_IMPLEMENTATION_FALLBACK 0 #else @@ -6866,6 +6871,8 @@ SIMDJSON_DLLIMPORTEXPORT const uint64_t simdjson::internal::power_of_five_128[]= #define SIMDJSON_BUILTIN_IMPLEMENTATION lsx #elif SIMDJSON_CAN_ALWAYS_RUN_LASX #define SIMDJSON_BUILTIN_IMPLEMENTATION lasx +#elif SIMDJSON_CAN_ALWAYS_RUN_RVV_VLS +#define SIMDJSON_BUILTIN_IMPLEMENTATION rvv_vls #elif SIMDJSON_CAN_ALWAYS_RUN_FALLBACK #define SIMDJSON_BUILTIN_IMPLEMENTATION fallback #else @@ -7622,6 +7629,8 @@ enum instruction_set { AVX512VBMI2 = 0x10000, LSX = 0x20000, LASX = 0x40000, + //RVV = 0x80000, + RVV_VLS = 0x100000, }; } // namespace internal @@ -8119,6 +8128,16 @@ static inline uint32_t detect_supported_architectures() { return host_isa; } +#elif SIMDJSON_IS_RISCV64 + +static inline uint32_t detect_supported_architectures() { + uint32_t host_isa = instruction_set::DEFAULT; +#if SIMDJSON_IS_RVV_VLS + host_isa |= instruction_set::RVV_VLS; +#endif + return host_isa; +} + #else // fallback @@ -8535,6 +8554,53 @@ static const simdjson::lsx::implementation* get_lsx_singleton() { } // namespace simdjson #endif // SIMDJSON_IMPLEMENTATION_LSX +#if SIMDJSON_IMPLEMENTATION_RVV_VLS +/* including simdjson/rvv-vls/implementation.h: #include */ +/* begin file simdjson/rvv-vls/implementation.h */ +#ifndef SIMDJSON_RVV_VLS_IMPLEMENTATION_H +#define SIMDJSON_RVV_VLS_IMPLEMENTATION_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { + +/** + * @private + */ +class implementation final : public simdjson::implementation { +public: + simdjson_inline implementation() : simdjson::implementation( + "rvv_vls", + "RISC-V V extension", + 0 + ) {} + simdjson_warn_unused error_code create_dom_parser_implementation( + size_t capacity, + size_t max_length, + std::unique_ptr& dst + ) const noexcept final; + simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final; + simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final; +}; + +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_IMPLEMENTATION_H +/* end file simdjson/rvv-vls/implementation.h */ +namespace simdjson { +namespace internal { +static const simdjson::rvv_vls::implementation* get_rvv_vls_singleton() { + static const simdjson::rvv_vls::implementation rvv_vls_singleton{}; + return &rvv_vls_singleton; +} +} // namespace internal +} // namespace simdjson +#endif // SIMDJSON_IMPLEMENTATION_RVV_VLS /* undefining SIMDJSON_CONDITIONAL_INCLUDE */ #undef SIMDJSON_CONDITIONAL_INCLUDE @@ -8549,10 +8615,10 @@ namespace internal { + SIMDJSON_IMPLEMENTATION_HASWELL + SIMDJSON_IMPLEMENTATION_WESTMERE \ + SIMDJSON_IMPLEMENTATION_ARM64 + SIMDJSON_IMPLEMENTATION_PPC64 \ + SIMDJSON_IMPLEMENTATION_LSX + SIMDJSON_IMPLEMENTATION_LASX \ - + SIMDJSON_IMPLEMENTATION_FALLBACK == 1) + + SIMDJSON_IMPLEMENTATION_RVV_VLS + SIMDJSON_IMPLEMENTATION_FALLBACK == 1) #if SIMDJSON_SINGLE_IMPLEMENTATION - static const implementation* get_single_implementation() { + simdjson_really_inline static const implementation* get_single_implementation() { return #if SIMDJSON_IMPLEMENTATION_ICELAKE get_icelake_singleton(); @@ -8575,6 +8641,9 @@ namespace internal { #if SIMDJSON_IMPLEMENTATION_LASX get_lasx_singleton(); #endif +#if SIMDJSON_IMPLEMENTATION_RVV_VLS + get_rvv_vls_singleton(); +#endif #if SIMDJSON_IMPLEMENTATION_FALLBACK get_fallback_singleton(); #endif @@ -8635,6 +8704,9 @@ static const std::initializer_list& get_available_implem #if SIMDJSON_IMPLEMENTATION_LSX get_lsx_singleton(), #endif +#if SIMDJSON_IMPLEMENTATION_RVV_VLS + get_rvv_vls_singleton(), +#endif #if SIMDJSON_IMPLEMENTATION_FALLBACK get_fallback_singleton(), #endif @@ -9476,6 +9548,7 @@ namespace { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, "ARM kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -9671,6 +9744,8 @@ simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *ds /* amalgamation skipped (editor-only): #include "simdjson/lasx/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_LSX */ /* amalgamation skipped (editor-only): #include "simdjson/lsx/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_RVV_VLS */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_FALLBACK */ /* amalgamation skipped (editor-only): #include "simdjson/fallback/begin.h" */ /* amalgamation skipped (editor-only): #else */ @@ -12352,6 +12427,7 @@ namespace { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, "ARM kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -13138,7 +13214,7 @@ using namespace simd; simdjson_inline simd8 is_incomplete(const simd8 input) { // If the previous input's last 3 bytes match this, they're too short (they ended at EOF): // ... 1111____ 111_____ 11______ -#if SIMDJSON_IMPLEMENTATION_ICELAKE +#if SIMDJSON_IMPLEMENTATION_ICELAKE || (SIMDJSON_IMPLEMENTATION_RVV_VLS && __riscv_v_fixed_vlen >= 512) static const uint8_t max_array[64] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, @@ -13199,18 +13275,18 @@ using namespace simd; || (simd8x64::NUM_CHUNKS == 4), "We support one, two or four chunks per 64-byte block."); SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 1) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); } else SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 2) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); - this->check_utf8_bytes(input.chunks[1], input.chunks[0]); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); + this->check_utf8_bytes(input.get<1>(), input.get<0>()); } else SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 4) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); - this->check_utf8_bytes(input.chunks[1], input.chunks[0]); - this->check_utf8_bytes(input.chunks[2], input.chunks[1]); - this->check_utf8_bytes(input.chunks[3], input.chunks[2]); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); + this->check_utf8_bytes(input.get<1>(), input.get<0>()); + this->check_utf8_bytes(input.get<2>(), input.get<1>()); + this->check_utf8_bytes(input.get<3>(), input.get<2>()); } - this->prev_incomplete = is_incomplete(input.chunks[simd8x64::NUM_CHUNKS-1]); - this->prev_input_block = input.chunks[simd8x64::NUM_CHUNKS-1]; + this->prev_incomplete = is_incomplete(input.get::NUM_CHUNKS-1>()); + this->prev_input_block = input.get::NUM_CHUNKS-1>(); } } // do not forget to call check_eof! @@ -15990,6 +16066,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 2, "Haswell kernel should use two registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -16169,6 +16246,8 @@ simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *ds /* amalgamation skipped (editor-only): #include "simdjson/lasx/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_LSX */ /* amalgamation skipped (editor-only): #include "simdjson/lsx/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_RVV_VLS */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_FALLBACK */ /* amalgamation skipped (editor-only): #include "simdjson/fallback/begin.h" */ /* amalgamation skipped (editor-only): #else */ @@ -18725,6 +18804,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 2, "Haswell kernel should use two registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -19495,7 +19575,7 @@ using namespace simd; simdjson_inline simd8 is_incomplete(const simd8 input) { // If the previous input's last 3 bytes match this, they're too short (they ended at EOF): // ... 1111____ 111_____ 11______ -#if SIMDJSON_IMPLEMENTATION_ICELAKE +#if SIMDJSON_IMPLEMENTATION_ICELAKE || (SIMDJSON_IMPLEMENTATION_RVV_VLS && __riscv_v_fixed_vlen >= 512) static const uint8_t max_array[64] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, @@ -19556,18 +19636,18 @@ using namespace simd; || (simd8x64::NUM_CHUNKS == 4), "We support one, two or four chunks per 64-byte block."); SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 1) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); } else SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 2) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); - this->check_utf8_bytes(input.chunks[1], input.chunks[0]); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); + this->check_utf8_bytes(input.get<1>(), input.get<0>()); } else SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 4) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); - this->check_utf8_bytes(input.chunks[1], input.chunks[0]); - this->check_utf8_bytes(input.chunks[2], input.chunks[1]); - this->check_utf8_bytes(input.chunks[3], input.chunks[2]); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); + this->check_utf8_bytes(input.get<1>(), input.get<0>()); + this->check_utf8_bytes(input.get<2>(), input.get<1>()); + this->check_utf8_bytes(input.get<3>(), input.get<2>()); } - this->prev_incomplete = is_incomplete(input.chunks[simd8x64::NUM_CHUNKS-1]); - this->prev_input_block = input.chunks[simd8x64::NUM_CHUNKS-1]; + this->prev_incomplete = is_incomplete(input.get::NUM_CHUNKS-1>()); + this->prev_input_block = input.get::NUM_CHUNKS-1>(); } } // do not forget to call check_eof! @@ -22298,6 +22378,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 1, "Icelake kernel should use one register per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -22522,6 +22603,8 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t /* amalgamation skipped (editor-only): #include "simdjson/lasx/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_LSX */ /* amalgamation skipped (editor-only): #include "simdjson/lsx/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_RVV_VLS */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_FALLBACK */ /* amalgamation skipped (editor-only): #include "simdjson/fallback/begin.h" */ /* amalgamation skipped (editor-only): #else */ @@ -25032,6 +25115,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 1, "Icelake kernel should use one register per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -25847,7 +25931,7 @@ using namespace simd; simdjson_inline simd8 is_incomplete(const simd8 input) { // If the previous input's last 3 bytes match this, they're too short (they ended at EOF): // ... 1111____ 111_____ 11______ -#if SIMDJSON_IMPLEMENTATION_ICELAKE +#if SIMDJSON_IMPLEMENTATION_ICELAKE || (SIMDJSON_IMPLEMENTATION_RVV_VLS && __riscv_v_fixed_vlen >= 512) static const uint8_t max_array[64] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, @@ -25908,18 +25992,18 @@ using namespace simd; || (simd8x64::NUM_CHUNKS == 4), "We support one, two or four chunks per 64-byte block."); SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 1) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); } else SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 2) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); - this->check_utf8_bytes(input.chunks[1], input.chunks[0]); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); + this->check_utf8_bytes(input.get<1>(), input.get<0>()); } else SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 4) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); - this->check_utf8_bytes(input.chunks[1], input.chunks[0]); - this->check_utf8_bytes(input.chunks[2], input.chunks[1]); - this->check_utf8_bytes(input.chunks[3], input.chunks[2]); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); + this->check_utf8_bytes(input.get<1>(), input.get<0>()); + this->check_utf8_bytes(input.get<2>(), input.get<1>()); + this->check_utf8_bytes(input.get<3>(), input.get<2>()); } - this->prev_incomplete = is_incomplete(input.chunks[simd8x64::NUM_CHUNKS-1]); - this->prev_input_block = input.chunks[simd8x64::NUM_CHUNKS-1]; + this->prev_incomplete = is_incomplete(input.get::NUM_CHUNKS-1>()); + this->prev_input_block = input.get::NUM_CHUNKS-1>(); } } // do not forget to call check_eof! @@ -28830,6 +28914,7 @@ template struct simd8x64 { static_assert(NUM_CHUNKS == 4, "PPC64 kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64 &o) = delete; // no copy allowed simd8x64 & @@ -29032,6 +29117,8 @@ simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *ds /* amalgamation skipped (editor-only): #include "simdjson/lasx/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_LSX */ /* amalgamation skipped (editor-only): #include "simdjson/lsx/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_RVV_VLS */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_FALLBACK */ /* amalgamation skipped (editor-only): #include "simdjson/fallback/begin.h" */ /* amalgamation skipped (editor-only): #else */ @@ -31677,6 +31764,7 @@ template struct simd8x64 { static_assert(NUM_CHUNKS == 4, "PPC64 kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64 &o) = delete; // no copy allowed simd8x64 & @@ -32470,7 +32558,7 @@ using namespace simd; simdjson_inline simd8 is_incomplete(const simd8 input) { // If the previous input's last 3 bytes match this, they're too short (they ended at EOF): // ... 1111____ 111_____ 11______ -#if SIMDJSON_IMPLEMENTATION_ICELAKE +#if SIMDJSON_IMPLEMENTATION_ICELAKE || (SIMDJSON_IMPLEMENTATION_RVV_VLS && __riscv_v_fixed_vlen >= 512) static const uint8_t max_array[64] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, @@ -32531,18 +32619,18 @@ using namespace simd; || (simd8x64::NUM_CHUNKS == 4), "We support one, two or four chunks per 64-byte block."); SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 1) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); } else SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 2) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); - this->check_utf8_bytes(input.chunks[1], input.chunks[0]); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); + this->check_utf8_bytes(input.get<1>(), input.get<0>()); } else SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 4) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); - this->check_utf8_bytes(input.chunks[1], input.chunks[0]); - this->check_utf8_bytes(input.chunks[2], input.chunks[1]); - this->check_utf8_bytes(input.chunks[3], input.chunks[2]); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); + this->check_utf8_bytes(input.get<1>(), input.get<0>()); + this->check_utf8_bytes(input.get<2>(), input.get<1>()); + this->check_utf8_bytes(input.get<3>(), input.get<2>()); } - this->prev_incomplete = is_incomplete(input.chunks[simd8x64::NUM_CHUNKS-1]); - this->prev_input_block = input.chunks[simd8x64::NUM_CHUNKS-1]; + this->prev_incomplete = is_incomplete(input.get::NUM_CHUNKS-1>()); + this->prev_input_block = input.get::NUM_CHUNKS-1>(); } } // do not forget to call check_eof! @@ -35301,6 +35389,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, "Westmere kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -35729,6 +35818,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, "Westmere kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -35901,6 +35991,8 @@ simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *ds /* amalgamation skipped (editor-only): #include "simdjson/lasx/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_LSX */ /* amalgamation skipped (editor-only): #include "simdjson/lsx/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_RVV_VLS */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_FALLBACK */ /* amalgamation skipped (editor-only): #include "simdjson/fallback/begin.h" */ /* amalgamation skipped (editor-only): #else */ @@ -38462,6 +38554,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, "Westmere kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -38890,6 +38983,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, "Westmere kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -39653,7 +39747,7 @@ using namespace simd; simdjson_inline simd8 is_incomplete(const simd8 input) { // If the previous input's last 3 bytes match this, they're too short (they ended at EOF): // ... 1111____ 111_____ 11______ -#if SIMDJSON_IMPLEMENTATION_ICELAKE +#if SIMDJSON_IMPLEMENTATION_ICELAKE || (SIMDJSON_IMPLEMENTATION_RVV_VLS && __riscv_v_fixed_vlen >= 512) static const uint8_t max_array[64] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, @@ -39714,18 +39808,18 @@ using namespace simd; || (simd8x64::NUM_CHUNKS == 4), "We support one, two or four chunks per 64-byte block."); SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 1) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); } else SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 2) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); - this->check_utf8_bytes(input.chunks[1], input.chunks[0]); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); + this->check_utf8_bytes(input.get<1>(), input.get<0>()); } else SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 4) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); - this->check_utf8_bytes(input.chunks[1], input.chunks[0]); - this->check_utf8_bytes(input.chunks[2], input.chunks[1]); - this->check_utf8_bytes(input.chunks[3], input.chunks[2]); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); + this->check_utf8_bytes(input.get<1>(), input.get<0>()); + this->check_utf8_bytes(input.get<2>(), input.get<1>()); + this->check_utf8_bytes(input.get<3>(), input.get<2>()); } - this->prev_incomplete = is_incomplete(input.chunks[simd8x64::NUM_CHUNKS-1]); - this->prev_input_block = input.chunks[simd8x64::NUM_CHUNKS-1]; + this->prev_incomplete = is_incomplete(input.get::NUM_CHUNKS-1>()); + this->prev_input_block = input.get::NUM_CHUNKS-1>(); } } // do not forget to call check_eof! @@ -42433,6 +42527,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 2, "LASX kernel should use two registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -42616,6 +42711,8 @@ simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *ds /* amalgamation skipped (editor-only): #include "simdjson/lasx/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_LSX */ /* amalgamation skipped (editor-only): #include "simdjson/lsx/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_RVV_VLS */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_FALLBACK */ /* amalgamation skipped (editor-only): #include "simdjson/fallback/begin.h" */ /* amalgamation skipped (editor-only): #else */ @@ -45095,6 +45192,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 2, "LASX kernel should use two registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -45869,7 +45967,7 @@ using namespace simd; simdjson_inline simd8 is_incomplete(const simd8 input) { // If the previous input's last 3 bytes match this, they're too short (they ended at EOF): // ... 1111____ 111_____ 11______ -#if SIMDJSON_IMPLEMENTATION_ICELAKE +#if SIMDJSON_IMPLEMENTATION_ICELAKE || (SIMDJSON_IMPLEMENTATION_RVV_VLS && __riscv_v_fixed_vlen >= 512) static const uint8_t max_array[64] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, @@ -45930,18 +46028,18 @@ using namespace simd; || (simd8x64::NUM_CHUNKS == 4), "We support one, two or four chunks per 64-byte block."); SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 1) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); } else SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 2) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); - this->check_utf8_bytes(input.chunks[1], input.chunks[0]); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); + this->check_utf8_bytes(input.get<1>(), input.get<0>()); } else SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 4) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); - this->check_utf8_bytes(input.chunks[1], input.chunks[0]); - this->check_utf8_bytes(input.chunks[2], input.chunks[1]); - this->check_utf8_bytes(input.chunks[3], input.chunks[2]); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); + this->check_utf8_bytes(input.get<1>(), input.get<0>()); + this->check_utf8_bytes(input.get<2>(), input.get<1>()); + this->check_utf8_bytes(input.get<3>(), input.get<2>()); } - this->prev_incomplete = is_incomplete(input.chunks[simd8x64::NUM_CHUNKS-1]); - this->prev_input_block = input.chunks[simd8x64::NUM_CHUNKS-1]; + this->prev_incomplete = is_incomplete(input.get::NUM_CHUNKS-1>()); + this->prev_input_block = input.get::NUM_CHUNKS-1>(); } } // do not forget to call check_eof! @@ -48561,6 +48659,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, "LSX kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -48769,6 +48868,8 @@ simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *ds /* amalgamation skipped (editor-only): #include "simdjson/lasx/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_LSX */ /* amalgamation skipped (editor-only): #include "simdjson/lsx/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_RVV_VLS */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_FALLBACK */ /* amalgamation skipped (editor-only): #include "simdjson/fallback/begin.h" */ /* amalgamation skipped (editor-only): #else */ @@ -51190,6 +51291,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, "LSX kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -51989,7 +52091,7 @@ using namespace simd; simdjson_inline simd8 is_incomplete(const simd8 input) { // If the previous input's last 3 bytes match this, they're too short (they ended at EOF): // ... 1111____ 111_____ 11______ -#if SIMDJSON_IMPLEMENTATION_ICELAKE +#if SIMDJSON_IMPLEMENTATION_ICELAKE || (SIMDJSON_IMPLEMENTATION_RVV_VLS && __riscv_v_fixed_vlen >= 512) static const uint8_t max_array[64] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, @@ -52050,18 +52152,18 @@ using namespace simd; || (simd8x64::NUM_CHUNKS == 4), "We support one, two or four chunks per 64-byte block."); SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 1) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); } else SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 2) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); - this->check_utf8_bytes(input.chunks[1], input.chunks[0]); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); + this->check_utf8_bytes(input.get<1>(), input.get<0>()); } else SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 4) { - this->check_utf8_bytes(input.chunks[0], this->prev_input_block); - this->check_utf8_bytes(input.chunks[1], input.chunks[0]); - this->check_utf8_bytes(input.chunks[2], input.chunks[1]); - this->check_utf8_bytes(input.chunks[3], input.chunks[2]); + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); + this->check_utf8_bytes(input.get<1>(), input.get<0>()); + this->check_utf8_bytes(input.get<2>(), input.get<1>()); + this->check_utf8_bytes(input.get<3>(), input.get<2>()); } - this->prev_incomplete = is_incomplete(input.chunks[simd8x64::NUM_CHUNKS-1]); - this->prev_input_block = input.chunks[simd8x64::NUM_CHUNKS-1]; + this->prev_incomplete = is_incomplete(input.get::NUM_CHUNKS-1>()); + this->prev_input_block = input.get::NUM_CHUNKS-1>(); } } // do not forget to call check_eof! @@ -54214,6 +54316,6542 @@ simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t * #endif // SIMDJSON_SRC_LSX_CPP /* end file lsx.cpp */ #endif +#if SIMDJSON_IMPLEMENTATION_RVV_VLS +/* including rvv-vls.cpp: #include */ +/* begin file rvv-vls.cpp */ +#ifndef SIMDJSON_SRC_RVV_VLS_CPP +#define SIMDJSON_SRC_RVV_VLS_CPP + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +/* including simdjson/rvv-vls.h: #include */ +/* begin file simdjson/rvv-vls.h */ +#ifndef SIMDJSON_RVV_VLS_H +#define SIMDJSON_RVV_VLS_H + + +/* including simdjson/rvv-vls/begin.h: #include "simdjson/rvv-vls/begin.h" */ +/* begin file simdjson/rvv-vls/begin.h */ +/* defining SIMDJSON_IMPLEMENTATION to "rvv_vls" */ +#define SIMDJSON_IMPLEMENTATION rvv_vls +/* including simdjson/rvv-vls/base.h: #include "simdjson/rvv-vls/base.h" */ +/* begin file simdjson/rvv-vls/base.h */ +#ifndef SIMDJSON_RVV_VLS_BASE_H +#define SIMDJSON_RVV_VLS_BASE_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +/** + * RVV-VLS implementation. + */ +namespace rvv_vls { + +class implementation; + +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_BASE_H +/* end file simdjson/rvv-vls/base.h */ +/* including simdjson/rvv-vls/intrinsics.h: #include "simdjson/rvv-vls/intrinsics.h" */ +/* begin file simdjson/rvv-vls/intrinsics.h */ +#ifndef SIMDJSON_RVV_VLS_INTRINSICS_H +#define SIMDJSON_RVV_VLS_INTRINSICS_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include + +#define simdutf_vrgather_u8m1x2(tbl, idx) \ + __riscv_vcreate_v_u8m1_u8m2( \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m2_u8m1(idx, 0), \ + __riscv_vsetvlmax_e8m1()), \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m2_u8m1(idx, 1), \ + __riscv_vsetvlmax_e8m1())) + +#define simdutf_vrgather_u8m1x4(tbl, idx) \ + __riscv_vcreate_v_u8m1_u8m4( \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 0), \ + __riscv_vsetvlmax_e8m1()), \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 1), \ + __riscv_vsetvlmax_e8m1()), \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 2), \ + __riscv_vsetvlmax_e8m1()), \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 3), \ + __riscv_vsetvlmax_e8m1())) + +#if __riscv_zbc +#include +#endif + +#endif // SIMDJSON_RVV_VLS_INTRINSICS_H +/* end file simdjson/rvv-vls/intrinsics.h */ +/* including simdjson/rvv-vls/bitmanipulation.h: #include "simdjson/rvv-vls/bitmanipulation.h" */ +/* begin file simdjson/rvv-vls/bitmanipulation.h */ +#ifndef SIMDJSON_RVV_VLS_BITMANIPULATION_H +#define SIMDJSON_RVV_VLS_BITMANIPULATION_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { + +// We sometimes call trailing_zero on inputs that are zero, +// but the algorithms do not end up using the returned value. +// Sadly, sanitizers are not smart enough to figure it out. +SIMDJSON_NO_SANITIZE_UNDEFINED +// This function can be used safely even if not all bytes have been +// initialized. +// See issue https://github.com/simdjson/simdjson/issues/1965 +SIMDJSON_NO_SANITIZE_MEMORY +simdjson_inline int trailing_zeroes(uint64_t input_num) { + return __builtin_ctzll(input_num); +} + +/* result might be undefined when input_num is zero */ +simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) { + return input_num & (input_num-1); +} + +/* result might be undefined when input_num is zero */ +simdjson_inline int leading_zeroes(uint64_t input_num) { + return __builtin_clzll(input_num); +} + +simdjson_inline long long int count_ones(uint64_t input_num) { + return __builtin_popcountll(input_num); +} + +simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, + uint64_t *result) { + return __builtin_uaddll_overflow(value1, value2, + reinterpret_cast(result)); +} + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_BITMANIPULATION_H +/* end file simdjson/rvv-vls/bitmanipulation.h */ +/* including simdjson/rvv-vls/bitmask.h: #include "simdjson/rvv-vls/bitmask.h" */ +/* begin file simdjson/rvv-vls/bitmask.h */ +#ifndef SIMDJSON_RVV_VLS_BITMASK_H +#define SIMDJSON_RVV_VLS_BITMASK_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/intrinsics.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { + +// +// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered. +// +// For example, prefix_xor(00100100) == 00011100 +// +simdjson_inline uint64_t prefix_xor(uint64_t bitmask) { +#if __riscv_zbc + return __riscv_clmul_64(bitmask, ~(uint64_t)0); +#elif __riscv_zvbc + return __riscv_vmv_x(__riscv_vclmul(__riscv_vmv_s_x_u64m1(bitmask, 1), ~(uint64_t)0, 1)); +#else + bitmask ^= bitmask << 1; + bitmask ^= bitmask << 2; + bitmask ^= bitmask << 4; + bitmask ^= bitmask << 8; + bitmask ^= bitmask << 16; + bitmask ^= bitmask << 32; +#endif + return bitmask; +} + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_BITMASK_H + +/* end file simdjson/rvv-vls/bitmask.h */ +/* including simdjson/rvv-vls/simd.h: #include "simdjson/rvv-vls/simd.h" */ +/* begin file simdjson/rvv-vls/simd.h */ +#ifndef SIMDJSON_RVV_VLS_SIMD_H +#define SIMDJSON_RVV_VLS_SIMD_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/bitmanipulation.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/simdprune_tables.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace simd { + +#if __riscv_v_fixed_vlen >= 512 + static constexpr size_t VL8 = 512/8; + using vint8_t = vint8m1_t __attribute__((riscv_rvv_vector_bits(512))); + using vuint8_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(512))); + using vbool_t = vbool8_t __attribute__((riscv_rvv_vector_bits(512/8))); + using vbitmask_t = uint64_t; +#else + static constexpr size_t VL8 = __riscv_v_fixed_vlen/8; + using vint8_t = vint8m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen))); + using vuint8_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen))); + using vbool_t = vbool8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/8))); + #if __riscv_v_fixed_vlen == 128 + using vbitmask_t = uint16_t; + #elif __riscv_v_fixed_vlen == 256 + using vbitmask_t = uint32_t; + #endif +#endif + +#if __riscv_v_fixed_vlen == 128 + using vuint8x64_t = vuint8m4_t __attribute__((riscv_rvv_vector_bits(512))); + using vboolx64_t = vbool2_t __attribute__((riscv_rvv_vector_bits(512/8))); +#elif __riscv_v_fixed_vlen == 256 + using vuint8x64_t = vuint8m2_t __attribute__((riscv_rvv_vector_bits(512))); + using vboolx64_t = vbool4_t __attribute__((riscv_rvv_vector_bits(512/8))); +#else + using vuint8x64_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(512))); + using vboolx64_t = vbool8_t __attribute__((riscv_rvv_vector_bits(512/8))); +#endif + + template + struct simd8; + + // SIMD byte mask type (returned by things like eq and gt) + template<> + struct simd8 { + vbool_t value; + using bitmask_t = vbitmask_t; + static constexpr int SIZE = sizeof(value); + + simdjson_inline simd8(const vbool_t _value) : value(_value) {} + simdjson_inline simd8() : simd8(__riscv_vmclr_m_b8(VL8)) {} + simdjson_inline simd8(bool _value) : simd8(splat(_value)) {} + + simdjson_inline operator const vbool_t&() const { return value; } + simdjson_inline operator vbool_t&() { return value; } + + static simdjson_inline simd8 splat(bool _value) { + return __riscv_vreinterpret_b8(__riscv_vmv_v_x_u64m1(((uint64_t)!_value)-1, 1)); + } + + simdjson_inline vbitmask_t to_bitmask() const { +#if __riscv_v_fixed_vlen == 128 + return __riscv_vmv_x(__riscv_vreinterpret_u16m1(value)); +#elif __riscv_v_fixed_vlen == 256 + return __riscv_vmv_x(__riscv_vreinterpret_u32m1(value)); +#else + return __riscv_vmv_x(__riscv_vreinterpret_u64m1(value)); +#endif + } + + // Bit operations + simdjson_inline simd8 operator|(const simd8 other) const { return __riscv_vmor(*this, other, VL8); } + simdjson_inline simd8 operator&(const simd8 other) const { return __riscv_vmand(*this, other, VL8); } + simdjson_inline simd8 operator^(const simd8 other) const { return __riscv_vmxor(*this, other, VL8); } + simdjson_inline simd8 bit_andnot(const simd8 other) const { return __riscv_vmandn(other, *this, VL8); } + simdjson_inline simd8 operator~() const { return __riscv_vmnot(*this, VL8); } + simdjson_inline simd8& operator|=(const simd8 other) { auto this_cast = static_cast*>(this); *this_cast = *this_cast | other; return *this_cast; } + simdjson_inline simd8& operator&=(const simd8 other) { auto this_cast = static_cast*>(this); *this_cast = *this_cast & other; return *this_cast; } + simdjson_inline simd8& operator^=(const simd8 other) { auto this_cast = static_cast*>(this); *this_cast = *this_cast ^ other; return *this_cast; } + }; + + // Unsigned bytes + template<> + struct simd8 { + + vuint8_t value; + static constexpr int SIZE = sizeof(value); + + simdjson_inline simd8(const vuint8_t _value) : value(_value) {} + simdjson_inline simd8() : simd8(zero()) {} + simdjson_inline simd8(const uint8_t values[VL8]) : simd8(load(values)) {} + simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {} + simdjson_inline simd8(simd8 mask) : value(__riscv_vmerge_vxm_u8m1(zero(), -1, (vbool_t)mask, VL8)) {} + + simdjson_inline operator const vuint8_t&() const { return this->value; } + simdjson_inline operator vuint8_t&() { return this->value; } + + simdjson_inline simd8( + uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7, + uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15 + ) : simd8(vuint8_t{ + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + }) {} + + // Repeat 16 values as many times as necessary (usually for lookup tables) + simdjson_inline static simd8 repeat_16( + uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7, + uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15 + ) { + return simd8( + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + ); + } + + static simdjson_inline vuint8_t splat(uint8_t _value) { return __riscv_vmv_v_x_u8m1(_value, VL8); } + static simdjson_inline vuint8_t zero() { return splat(0); } + static simdjson_inline vuint8_t load(const uint8_t values[VL8]) { return __riscv_vle8_v_u8m1(values, VL8); } + + // Bit operations + simdjson_inline simd8 operator|(const simd8 other) const { return __riscv_vor_vv_u8m1( value, other, VL8); } + simdjson_inline simd8 operator&(const simd8 other) const { return __riscv_vand_vv_u8m1( value, other, VL8); } + simdjson_inline simd8 operator^(const simd8 other) const { return __riscv_vxor_vv_u8m1( value, other, VL8); } + simdjson_inline simd8 operator~() const { return __riscv_vnot_v_u8m1(value, VL8); } +#if __riscv_zvbb + simdjson_inline simd8 bit_andnot(const simd8 other) const { return __riscv_vandn_vv_u8m1(other, value, VL8); } +#else + simdjson_inline simd8 bit_andnot(const simd8 other) const { return other & ~*this; } +#endif + simdjson_inline simd8& operator|=(const simd8 other) { value = *this | other; return *this; } + simdjson_inline simd8& operator&=(const simd8 other) { value = *this & other; return *this; } + simdjson_inline simd8& operator^=(const simd8 other) { value = *this ^ other; return *this; } + + simdjson_inline simd8 operator==(const simd8 other) const { return __riscv_vmseq(value, other, VL8); } + simdjson_inline simd8 operator==(uint8_t other) const { return __riscv_vmseq(value, other, VL8); } + + template + simdjson_inline simd8 prev(const simd8 prev_chunk) const { + return __riscv_vslideup(__riscv_vslidedown(prev_chunk, VL8-N, VL8), value, N, VL8); + } + + // Store to array + simdjson_inline void store(uint8_t dst[VL8]) const { return __riscv_vse8(dst, value, VL8); } + + // Saturated math + simdjson_inline simd8 saturating_add(const simd8 other) const { return __riscv_vsaddu(value, other, VL8); } + simdjson_inline simd8 saturating_sub(const simd8 other) const { return __riscv_vssubu(value, other, VL8); } + + // Addition/subtraction are the same for signed and unsigned + simdjson_inline simd8 operator+(const simd8 other) const { return __riscv_vadd(value, other, VL8); } + simdjson_inline simd8 operator-(const simd8 other) const { return __riscv_vsub(value, other, VL8); } + simdjson_inline simd8& operator+=(const simd8 other) { value = *this + other; return *this; } + simdjson_inline simd8& operator-=(const simd8 other) { value = *this - other; return *this; } + + // Order-specific operations + simdjson_inline simd8 operator<=(const simd8 other) const { return __riscv_vmsleu(value, other, VL8); } + simdjson_inline simd8 operator>=(const simd8 other) const { return __riscv_vmsgeu(value, other, VL8); } + simdjson_inline simd8 operator<(const simd8 other) const { return __riscv_vmsltu(value, other, VL8); } + simdjson_inline simd8 operator>(const simd8 other) const { return __riscv_vmsgtu(value, other, VL8); } + + // Same as >, but instead of guaranteeing all 1's == true, false = 0 and true = nonzero. + simdjson_inline simd8 gt_bits(const simd8 other) const { return simd8(*this > other); } + // Same as <, but instead of guaranteeing all 1's == true, false = 0 and true = nonzero. + simdjson_inline simd8 lt_bits(const simd8 other) const { return simd8(*this < other); } + + // Bit-specific operations + simdjson_inline bool any_bits_set_anywhere() const { + return __riscv_vfirst(__riscv_vmsne(value, 0, VL8), VL8) >= 0; + } + simdjson_inline bool any_bits_set_anywhere(simd8 bits) const { return (*this & bits).any_bits_set_anywhere(); } + template + simdjson_inline simd8 shr() const { return __riscv_vsrl(value, N, VL8); } + template + simdjson_inline simd8 shl() const { return __riscv_vsll(value, N, VL8); } + + + // Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values) + template + simdjson_inline simd8 lookup_16(simd8 lookup_table) const { + return __riscv_vrgather(lookup_table, value, VL8); + } + + // compress inactive elements, to match AVX-512 behavior + template + simdjson_inline void compress(vbitmask_t mask, L * output) const { + mask = (vbitmask_t)~mask; +#if __riscv_v_fixed_vlen == 128 + vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u16m1(mask, 1)); +#elif __riscv_v_fixed_vlen == 256 + vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u32m1(mask, 1)); +#else + vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u64m1(mask, 1)); +#endif + __riscv_vse8_v_u8m1(output, __riscv_vcompress(value, m, VL8), count_ones(mask)); + } + + template + simdjson_inline simd8 lookup_16( + L replace0, L replace1, L replace2, L replace3, + L replace4, L replace5, L replace6, L replace7, + L replace8, L replace9, L replace10, L replace11, + L replace12, L replace13, L replace14, L replace15) const { + return lookup_16(simd8::repeat_16( + replace0, replace1, replace2, replace3, + replace4, replace5, replace6, replace7, + replace8, replace9, replace10, replace11, + replace12, replace13, replace14, replace15 + )); + } + }; + + // Signed bytes + template<> + struct simd8 { + vint8_t value; + static constexpr int SIZE = sizeof(value); + + simdjson_inline simd8(const vint8_t _value) : value(_value) {} + simdjson_inline simd8() : simd8(zero()) {} + simdjson_inline simd8(const int8_t values[VL8]) : simd8(load(values)) {} + simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {} + + simdjson_inline operator const vint8_t&() const { return this->value; } + simdjson_inline operator vint8_t&() { return this->value; } + + simdjson_inline simd8( + int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7, + int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15 + ) : simd8(vint8_t{ + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + }) {} + + // Repeat 16 values as many times as necessary (usually for lookup tables) + simdjson_inline static simd8 repeat_16( + int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7, + int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15 + ) { + return simd8( + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + ); + } + + static simdjson_inline vint8_t splat(int8_t _value) { return __riscv_vmv_v_x_i8m1(_value, VL8); } + static simdjson_inline vint8_t zero() { return splat(0); } + static simdjson_inline vint8_t load(const int8_t values[VL8]) { return __riscv_vle8_v_i8m1(values, VL8); } + + + simdjson_inline void store(int8_t dst[VL8]) const { return __riscv_vse8(dst, value, VL8); } + + // Explicit conversion to/from unsigned + simdjson_inline explicit simd8(const vuint8_t other): simd8(__riscv_vreinterpret_i8m1(other)) {} + simdjson_inline explicit operator simd8() const { return __riscv_vreinterpret_u8m1(value); } + + // Math + simdjson_inline simd8 operator+(const simd8 other) const { return __riscv_vadd(value, other, VL8); } + simdjson_inline simd8 operator-(const simd8 other) const { return __riscv_vsub(value, other, VL8); } + simdjson_inline simd8& operator+=(const simd8 other) { value = *this + other; return *this; } + simdjson_inline simd8& operator-=(const simd8 other) { value = *this - other; return *this; } + + // Order-sensitive comparisons + simdjson_inline simd8 max_val( const simd8 other) const { return __riscv_vmax( value, other, VL8); } + simdjson_inline simd8 min_val( const simd8 other) const { return __riscv_vmin( value, other, VL8); } + simdjson_inline simd8 operator>( const simd8 other) const { return __riscv_vmsgt(value, other, VL8); } + simdjson_inline simd8 operator<( const simd8 other) const { return __riscv_vmslt(value, other, VL8); } + simdjson_inline simd8 operator==(const simd8 other) const { return __riscv_vmseq(value, other, VL8); } + + template + simdjson_inline simd8 prev(const simd8 prev_chunk) const { + return __riscv_vslideup(__riscv_vslidedown(prev_chunk, VL8-N, VL8), value, N, VL8); + } + + // Perform a lookup assuming no value is larger than 16 + template + simdjson_inline simd8 lookup_16(simd8 lookup_table) const { + return __riscv_vrgather(lookup_table, value, VL8); + } + template + simdjson_inline simd8 lookup_16( + L replace0, L replace1, L replace2, L replace3, + L replace4, L replace5, L replace6, L replace7, + L replace8, L replace9, L replace10, L replace11, + L replace12, L replace13, L replace14, L replace15) const { + return lookup_16(simd8::repeat_16( + replace0, replace1, replace2, replace3, + replace4, replace5, replace6, replace7, + replace8, replace9, replace10, replace11, + replace12, replace13, replace14, replace15 + )); + } + }; + + template + struct simd8x64; + template<> + struct simd8x64 { + static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); + vuint8x64_t value; + +#if __riscv_v_fixed_vlen >= 512 + template simd8 get() const { return value; } +#else + template simd8 get() const { return __riscv_vget_u8m1(value, idx); } +#endif + + simdjson_inline operator const vuint8x64_t&() const { return this->value; } + simdjson_inline operator vuint8x64_t&() { return this->value; } + + simd8x64(const simd8x64& o) = delete; // no copy allowed + simd8x64& operator=(const simd8& other) = delete; // no assignment allowed + simd8x64() = delete; // no default constructor allowed + +#if __riscv_v_fixed_vlen == 128 + simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m4(ptr, n)) {} +#elif __riscv_v_fixed_vlen == 256 + simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m2(ptr, n)) {} +#else + simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m1(ptr, n)) {} +#endif + + simdjson_inline void store(uint8_t ptr[64]) const { + __riscv_vse8(ptr, value, 64); + } + + simdjson_inline bool is_ascii() const { +#if __riscv_v_fixed_vlen == 128 + return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m4(value), 0, 64), 64) < 0; +#elif __riscv_v_fixed_vlen == 256 + return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m2(value), 0, 64), 64) < 0; +#else + return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m1(value), 0, 64), 64) < 0; +#endif + } + + // compress inactive elements, to match AVX-512 behavior + simdjson_inline uint64_t compress(uint64_t mask, uint8_t * output) const { + mask = ~mask; +#if __riscv_v_fixed_vlen == 128 + vboolx64_t m = __riscv_vreinterpret_b2(__riscv_vmv_s_x_u64m1(mask, 1)); +#elif __riscv_v_fixed_vlen == 256 + vboolx64_t m = __riscv_vreinterpret_b4(__riscv_vmv_s_x_u64m1(mask, 1)); +#else + vboolx64_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u64m1(mask, 1)); +#endif + size_t cnt = count_ones(mask); + __riscv_vse8(output, __riscv_vcompress(value, m, 64), cnt); + return cnt; + } + + simdjson_inline uint64_t eq(const uint8_t m) const { + return __riscv_vmv_x(__riscv_vreinterpret_u64m1(__riscv_vmseq(value, m, 64))); + } + + simdjson_inline uint64_t lteq(const uint8_t m) const { + return __riscv_vmv_x(__riscv_vreinterpret_u64m1(__riscv_vmsleu(value, m, 64))); + } + }; // struct simd8x64 + +} // namespace simd +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_SIMD_H +/* end file simdjson/rvv-vls/simd.h */ +/* including simdjson/rvv-vls/stringparsing_defs.h: #include "simdjson/rvv-vls/stringparsing_defs.h" */ +/* begin file simdjson/rvv-vls/stringparsing_defs.h */ +#ifndef SIMDJSON_RVV_VLS_STRINGPARSING_DEFS_H +#define SIMDJSON_RVV_VLS_STRINGPARSING_DEFS_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { + +using namespace simd; + +// Holds backslashes and quotes locations. +struct backslash_and_quote { +public: + static constexpr uint64_t BYTES_PROCESSED = sizeof(simd8); + simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + + simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; } + simdjson_inline bool has_backslash() { return ((quote_bits - 1) & bs_bits) != 0; } + simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); } + simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); } + + uint64_t bs_bits; + uint64_t quote_bits; +}; // struct backslash_and_quote + +simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) { + static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes"); + simd8 v(src); + v.store(dst); + return { (v == '\\').to_bitmask(), (v == '"').to_bitmask() }; +} + +struct escaping { + static constexpr uint64_t BYTES_PROCESSED = sizeof(simd8); + simdjson_inline static escaping copy_and_find(const uint8_t *src, uint8_t *dst); + + simdjson_inline bool has_escape() { return escape_bits != 0; } + simdjson_inline int escape_index() { return trailing_zeroes(escape_bits) / 4; } + + uint64_t escape_bits; +}; // struct escaping + +simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *dst) { + static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "escaping finder must process fewer than SIMDJSON_PADDING bytes"); + simd8 v(src); + v.store(dst); + return { ((v == '"') | (v == '\\') | (v == 32)).to_bitmask() }; +} + + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_STRINGPARSING_DEFS_H +/* end file simdjson/rvv-vls/stringparsing_defs.h */ +/* including simdjson/rvv-vls/numberparsing_defs.h: #include "simdjson/rvv-vls/numberparsing_defs.h" */ +/* begin file simdjson/rvv-vls/numberparsing_defs.h */ +#ifndef SIMDJSON_RVV_VLS_NUMBERPARSING_DEFS_H +#define SIMDJSON_RVV_VLS_NUMBERPARSING_DEFS_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include + +#ifdef JSON_TEST_NUMBERS // for unit testing +void found_invalid_number(const uint8_t *buf); +void found_integer(int64_t result, const uint8_t *buf); +void found_unsigned_integer(uint64_t result, const uint8_t *buf); +void found_float(double result, const uint8_t *buf); +#endif + +namespace simdjson { +namespace rvv_vls { +namespace numberparsing { + +// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/ +/** @private */ +static simdjson_inline uint32_t parse_eight_digits_unrolled(const char *chars) { + uint64_t val; +#if __riscv_misaligned_fast + memcpy(&val, chars, sizeof(uint64_t)); +#else + val = __riscv_vmv_x(__riscv_vreinterpret_u64m1(__riscv_vlmul_ext_u8m1(__riscv_vle8_v_u8mf2((uint8_t*)chars, 8)))); +#endif + val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8; + val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16; + return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32); +} + +/** @private */ +static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) { + return parse_eight_digits_unrolled(reinterpret_cast(chars)); +} + +/** @private */ +simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) { + internal::value128 answer; + __uint128_t r = (static_cast<__uint128_t>(value1)) * value2; + answer.low = uint64_t(r); + answer.high = uint64_t(r >> 64); + return answer; +} + +} // namespace numberparsing +} // namespace rvv_vls +} // namespace simdjson + +#define SIMDJSON_SWAR_NUMBER_PARSING 1 + +#endif // SIMDJSON_RVV_VLS_NUMBERPARSING_DEFS_H +/* end file simdjson/rvv-vls/numberparsing_defs.h */ + +#define SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT 1 +/* end file simdjson/rvv-vls/begin.h */ +/* including simdjson/generic/amalgamated.h for rvv_vls: #include "simdjson/generic/amalgamated.h" */ +/* begin file simdjson/generic/amalgamated.h for rvv_vls */ +#if defined(SIMDJSON_CONDITIONAL_INCLUDE) && !defined(SIMDJSON_GENERIC_DEPENDENCIES_H) +#error simdjson/generic/dependencies.h must be included before simdjson/generic/amalgamated.h! +#endif + +/* including simdjson/generic/base.h for rvv_vls: #include "simdjson/generic/base.h" */ +/* begin file simdjson/generic/base.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_BASE_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_BASE_H */ +/* amalgamation skipped (editor-only): #include "simdjson/base.h" */ +/* amalgamation skipped (editor-only): // If we haven't got an implementation yet, we're in the editor, editing a generic file! Just */ +/* amalgamation skipped (editor-only): // use the most advanced one we can so the most possible stuff can be tested. */ +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_IMPLEMENTATION */ +/* amalgamation skipped (editor-only): #include "simdjson/implementation_detection.h" */ +/* amalgamation skipped (editor-only): #if SIMDJSON_IMPLEMENTATION_ICELAKE */ +/* amalgamation skipped (editor-only): #include "simdjson/icelake/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_HASWELL */ +/* amalgamation skipped (editor-only): #include "simdjson/haswell/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_WESTMERE */ +/* amalgamation skipped (editor-only): #include "simdjson/westmere/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_ARM64 */ +/* amalgamation skipped (editor-only): #include "simdjson/arm64/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_PPC64 */ +/* amalgamation skipped (editor-only): #include "simdjson/ppc64/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_LASX */ +/* amalgamation skipped (editor-only): #include "simdjson/lasx/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_LSX */ +/* amalgamation skipped (editor-only): #include "simdjson/lsx/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_RVV_VLS */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_FALLBACK */ +/* amalgamation skipped (editor-only): #include "simdjson/fallback/begin.h" */ +/* amalgamation skipped (editor-only): #else */ +/* amalgamation skipped (editor-only): #error "All possible implementations (including fallback) have been disabled! simdjson will not run." */ +/* amalgamation skipped (editor-only): #endif */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_IMPLEMENTATION */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { + +struct open_container; +class dom_parser_implementation; + +/** + * The type of a JSON number + */ +enum class number_type { + floating_point_number=1, /// a binary64 number + signed_integer, /// a signed integer that fits in a 64-bit word using two's complement + unsigned_integer, /// a positive integer larger or equal to 1<<63 + big_integer /// a big integer that does not fit in a 64-bit word +}; + +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_BASE_H +/* end file simdjson/generic/base.h for rvv_vls */ +/* including simdjson/generic/jsoncharutils.h for rvv_vls: #include "simdjson/generic/jsoncharutils.h" */ +/* begin file simdjson/generic/jsoncharutils.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_JSONCHARUTILS_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_JSONCHARUTILS_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/jsoncharutils_tables.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace jsoncharutils { + +// return non-zero if not a structural or whitespace char +// zero otherwise +simdjson_inline uint32_t is_not_structural_or_whitespace(uint8_t c) { + return internal::structural_or_whitespace_negated[c]; +} + +simdjson_inline uint32_t is_structural_or_whitespace(uint8_t c) { + return internal::structural_or_whitespace[c]; +} + +// returns a value with the high 16 bits set if not valid +// otherwise returns the conversion of the 4 hex digits at src into the bottom +// 16 bits of the 32-bit return register +// +// see +// https://lemire.me/blog/2019/04/17/parsing-short-hexadecimal-strings-efficiently/ +static inline uint32_t hex_to_u32_nocheck( + const uint8_t *src) { // strictly speaking, static inline is a C-ism + uint32_t v1 = internal::digit_to_val32[630 + src[0]]; + uint32_t v2 = internal::digit_to_val32[420 + src[1]]; + uint32_t v3 = internal::digit_to_val32[210 + src[2]]; + uint32_t v4 = internal::digit_to_val32[0 + src[3]]; + return v1 | v2 | v3 | v4; +} + +// given a code point cp, writes to c +// the utf-8 code, outputting the length in +// bytes, if the length is zero, the code point +// is invalid +// +// This can possibly be made faster using pdep +// and clz and table lookups, but JSON documents +// have few escaped code points, and the following +// function looks cheap. +// +// Note: we assume that surrogates are treated separately +// +simdjson_inline size_t codepoint_to_utf8(uint32_t cp, uint8_t *c) { + if (cp <= 0x7F) { + c[0] = uint8_t(cp); + return 1; // ascii + } + if (cp <= 0x7FF) { + c[0] = uint8_t((cp >> 6) + 192); + c[1] = uint8_t((cp & 63) + 128); + return 2; // universal plane + // Surrogates are treated elsewhere... + //} //else if (0xd800 <= cp && cp <= 0xdfff) { + // return 0; // surrogates // could put assert here + } else if (cp <= 0xFFFF) { + c[0] = uint8_t((cp >> 12) + 224); + c[1] = uint8_t(((cp >> 6) & 63) + 128); + c[2] = uint8_t((cp & 63) + 128); + return 3; + } else if (cp <= 0x10FFFF) { // if you know you have a valid code point, this + // is not needed + c[0] = uint8_t((cp >> 18) + 240); + c[1] = uint8_t(((cp >> 12) & 63) + 128); + c[2] = uint8_t(((cp >> 6) & 63) + 128); + c[3] = uint8_t((cp & 63) + 128); + return 4; + } + // will return 0 when the code point was too large. + return 0; // bad r +} + +#if SIMDJSON_IS_32BITS // _umul128 for x86, arm +// this is a slow emulation routine for 32-bit +// +static simdjson_inline uint64_t __emulu(uint32_t x, uint32_t y) { + return x * (uint64_t)y; +} +static simdjson_inline uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi) { + uint64_t ad = __emulu((uint32_t)(ab >> 32), (uint32_t)cd); + uint64_t bd = __emulu((uint32_t)ab, (uint32_t)cd); + uint64_t adbc = ad + __emulu((uint32_t)ab, (uint32_t)(cd >> 32)); + uint64_t adbc_carry = !!(adbc < ad); + uint64_t lo = bd + (adbc << 32); + *hi = __emulu((uint32_t)(ab >> 32), (uint32_t)(cd >> 32)) + (adbc >> 32) + + (adbc_carry << 32) + !!(lo < bd); + return lo; +} +#endif + +} // namespace jsoncharutils +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_JSONCHARUTILS_H +/* end file simdjson/generic/jsoncharutils.h for rvv_vls */ +/* including simdjson/generic/atomparsing.h for rvv_vls: #include "simdjson/generic/atomparsing.h" */ +/* begin file simdjson/generic/atomparsing.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ATOMPARSING_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ATOMPARSING_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/jsoncharutils.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include + +namespace simdjson { +namespace rvv_vls { +namespace { +/// @private +namespace atomparsing { + +// The string_to_uint32 is exclusively used to map literal strings to 32-bit values. +// We use memcpy instead of a pointer cast to avoid undefined behaviors since we cannot +// be certain that the character pointer will be properly aligned. +// You might think that using memcpy makes this function expensive, but you'd be wrong. +// All decent optimizing compilers (GCC, clang, Visual Studio) will compile string_to_uint32("false"); +// to the compile-time constant 1936482662. +simdjson_inline uint32_t string_to_uint32(const char* str) { uint32_t val; std::memcpy(&val, str, sizeof(uint32_t)); return val; } + + +// Again in str4ncmp we use a memcpy to avoid undefined behavior. The memcpy may appear expensive. +// Yet all decent optimizing compilers will compile memcpy to a single instruction, just about. +simdjson_warn_unused +simdjson_inline uint32_t str4ncmp(const uint8_t *src, const char* atom) { + uint32_t srcval; // we want to avoid unaligned 32-bit loads (undefined in C/C++) + static_assert(sizeof(uint32_t) <= SIMDJSON_PADDING, "SIMDJSON_PADDING must be larger than 4 bytes"); + std::memcpy(&srcval, src, sizeof(uint32_t)); + return srcval ^ string_to_uint32(atom); +} + +simdjson_warn_unused +simdjson_inline bool is_valid_true_atom(const uint8_t *src) { + return (str4ncmp(src, "true") | jsoncharutils::is_not_structural_or_whitespace(src[4])) == 0; +} + +simdjson_warn_unused +simdjson_inline bool is_valid_true_atom(const uint8_t *src, size_t len) { + if (len > 4) { return is_valid_true_atom(src); } + else if (len == 4) { return !str4ncmp(src, "true"); } + else { return false; } +} + +simdjson_warn_unused +simdjson_inline bool is_valid_false_atom(const uint8_t *src) { + return (str4ncmp(src+1, "alse") | jsoncharutils::is_not_structural_or_whitespace(src[5])) == 0; +} + +simdjson_warn_unused +simdjson_inline bool is_valid_false_atom(const uint8_t *src, size_t len) { + if (len > 5) { return is_valid_false_atom(src); } + else if (len == 5) { return !str4ncmp(src+1, "alse"); } + else { return false; } +} + +simdjson_warn_unused +simdjson_inline bool is_valid_null_atom(const uint8_t *src) { + return (str4ncmp(src, "null") | jsoncharutils::is_not_structural_or_whitespace(src[4])) == 0; +} + +simdjson_warn_unused +simdjson_inline bool is_valid_null_atom(const uint8_t *src, size_t len) { + if (len > 4) { return is_valid_null_atom(src); } + else if (len == 4) { return !str4ncmp(src, "null"); } + else { return false; } +} + +} // namespace atomparsing +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ATOMPARSING_H +/* end file simdjson/generic/atomparsing.h for rvv_vls */ +/* including simdjson/generic/dom_parser_implementation.h for rvv_vls: #include "simdjson/generic/dom_parser_implementation.h" */ +/* begin file simdjson/generic/dom_parser_implementation.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_DOM_PARSER_IMPLEMENTATION_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_DOM_PARSER_IMPLEMENTATION_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { + +// expectation: sizeof(open_container) = 64/8. +struct open_container { + uint32_t tape_index; // where, on the tape, does the scope ([,{) begins + uint32_t count; // how many elements in the scope +}; // struct open_container + +static_assert(sizeof(open_container) == 64/8, "Open container must be 64 bits"); + +class dom_parser_implementation final : public internal::dom_parser_implementation { +public: + /** Tape location of each open { or [ */ + std::unique_ptr open_containers{}; + /** Whether each open container is a [ or { */ + std::unique_ptr is_array{}; + /** Buffer passed to stage 1 */ + const uint8_t *buf{}; + /** Length passed to stage 1 */ + size_t len{0}; + /** Document passed to stage 2 */ + dom::document *doc{}; + + inline dom_parser_implementation() noexcept; + inline dom_parser_implementation(dom_parser_implementation &&other) noexcept; + inline dom_parser_implementation &operator=(dom_parser_implementation &&other) noexcept; + dom_parser_implementation(const dom_parser_implementation &) = delete; + dom_parser_implementation &operator=(const dom_parser_implementation &) = delete; + + simdjson_warn_unused error_code parse(const uint8_t *buf, size_t len, dom::document &doc) noexcept final; + simdjson_warn_unused error_code stage1(const uint8_t *buf, size_t len, stage1_mode partial) noexcept final; + simdjson_warn_unused error_code stage2(dom::document &doc) noexcept final; + simdjson_warn_unused error_code stage2_next(dom::document &doc) noexcept final; + simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept final; + simdjson_warn_unused uint8_t *parse_wobbly_string(const uint8_t *src, uint8_t *dst) const noexcept final; + inline simdjson_warn_unused error_code set_capacity(size_t capacity) noexcept final; + inline simdjson_warn_unused error_code set_max_depth(size_t max_depth) noexcept final; +private: + simdjson_inline simdjson_warn_unused error_code set_capacity_stage1(size_t capacity); + +}; + +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { +namespace rvv_vls { + +inline dom_parser_implementation::dom_parser_implementation() noexcept = default; +inline dom_parser_implementation::dom_parser_implementation(dom_parser_implementation &&other) noexcept = default; +inline dom_parser_implementation &dom_parser_implementation::operator=(dom_parser_implementation &&other) noexcept = default; + +// Leaving these here so they can be inlined if so desired +inline simdjson_warn_unused error_code dom_parser_implementation::set_capacity(size_t capacity) noexcept { + if(capacity > SIMDJSON_MAXSIZE_BYTES) { return CAPACITY; } + // Stage 1 index output + size_t max_structures = SIMDJSON_ROUNDUP_N(capacity, 64) + 2 + 7; + structural_indexes.reset( new (std::nothrow) uint32_t[max_structures] ); + if (!structural_indexes) { _capacity = 0; return MEMALLOC; } + structural_indexes[0] = 0; + n_structural_indexes = 0; + + _capacity = capacity; + return SUCCESS; +} + +inline simdjson_warn_unused error_code dom_parser_implementation::set_max_depth(size_t max_depth) noexcept { + // Stage 2 stacks + open_containers.reset(new (std::nothrow) open_container[max_depth]); + is_array.reset(new (std::nothrow) bool[max_depth]); + if (!is_array || !open_containers) { _max_depth = 0; return MEMALLOC; } + + _max_depth = max_depth; + return SUCCESS; +} + +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_DOM_PARSER_IMPLEMENTATION_H +/* end file simdjson/generic/dom_parser_implementation.h for rvv_vls */ +/* including simdjson/generic/implementation_simdjson_result_base.h for rvv_vls: #include "simdjson/generic/implementation_simdjson_result_base.h" */ +/* begin file simdjson/generic/implementation_simdjson_result_base.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_IMPLEMENTATION_SIMDJSON_RESULT_BASE_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_IMPLEMENTATION_SIMDJSON_RESULT_BASE_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { + +// This is a near copy of include/error.h's implementation_simdjson_result_base, except it doesn't use std::pair +// so we can avoid inlining errors +// TODO reconcile these! +/** + * The result of a simdjson operation that could fail. + * + * Gives the option of reading error codes, or throwing an exception by casting to the desired result. + * + * This is a base class for implementations that want to add functions to the result type for + * chaining. + * + * Override like: + * + * struct simdjson_result : public internal::implementation_simdjson_result_base { + * simdjson_result() noexcept : internal::implementation_simdjson_result_base() {} + * simdjson_result(error_code error) noexcept : internal::implementation_simdjson_result_base(error) {} + * simdjson_result(T &&value) noexcept : internal::implementation_simdjson_result_base(std::forward(value)) {} + * simdjson_result(T &&value, error_code error) noexcept : internal::implementation_simdjson_result_base(value, error) {} + * // Your extra methods here + * } + * + * Then any method returning simdjson_result will be chainable with your methods. + */ +template +struct implementation_simdjson_result_base { + + /** + * Create a new empty result with error = UNINITIALIZED. + */ + simdjson_inline implementation_simdjson_result_base() noexcept = default; + + /** + * Create a new error result. + */ + simdjson_inline implementation_simdjson_result_base(error_code error) noexcept; + + /** + * Create a new successful result. + */ + simdjson_inline implementation_simdjson_result_base(T &&value) noexcept; + + /** + * Create a new result with both things (use if you don't want to branch when creating the result). + */ + simdjson_inline implementation_simdjson_result_base(T &&value, error_code error) noexcept; + + /** + * Move the value and the error to the provided variables. + * + * @param value The variable to assign the value to. May not be set if there is an error. + * @param error The variable to assign the error to. Set to SUCCESS if there is no error. + */ + simdjson_inline void tie(T &value, error_code &error) && noexcept; + + /** + * Move the value to the provided variable. + * + * @param value The variable to assign the value to. May not be set if there is an error. + */ + simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept; + + /** + * The error. + */ + simdjson_warn_unused simdjson_inline error_code error() const noexcept; + + /** + * Whether there is a value. + */ + simdjson_warn_unused simdjson_inline bool has_value() const noexcept; + +#if SIMDJSON_EXCEPTIONS + + /** + * Get the result value. + * + * @throw simdjson_error if there was an error. + */ + simdjson_inline T& operator*() & noexcept(false); + simdjson_inline T&& operator*() && noexcept(false); + /** + * Arrow operator to access members of the contained value. + * + * @throw simdjson_error if there was an error. + */ + simdjson_inline T* operator->() noexcept(false); + simdjson_inline const T* operator->() const noexcept(false); + + simdjson_inline T& value() & noexcept(false); + + /** + * Take the result value (move it). + * + * @throw simdjson_error if there was an error. + */ + simdjson_inline T&& value() && noexcept(false); + + /** + * Take the result value (move it). + * + * @throw simdjson_error if there was an error. + */ + simdjson_inline T&& take_value() && noexcept(false); + + /** + * Cast to the value (will throw on error). + * + * @throw simdjson_error if there was an error. + */ + simdjson_inline operator T&&() && noexcept(false); + + +#endif // SIMDJSON_EXCEPTIONS + + /** + * Get the result value. This function is safe if and only + * the error() method returns a value that evaluates to false. + */ + simdjson_inline const T& value_unsafe() const& noexcept; + /** + * Get the result value. This function is safe if and only + * the error() method returns a value that evaluates to false. + */ + simdjson_inline T& value_unsafe() & noexcept; + /** + * Take the result value (move it). This function is safe if and only + * the error() method returns a value that evaluates to false. + */ + simdjson_inline T&& value_unsafe() && noexcept; + + using value_type = T; + using error_type = error_code; + +protected: + /** users should never directly access first and second. **/ + T first{}; /** Users should never directly access 'first'. **/ + error_code second{UNINITIALIZED}; /** Users should never directly access 'second'. **/ +}; // struct implementation_simdjson_result_base + +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_IMPLEMENTATION_SIMDJSON_RESULT_BASE_H +/* end file simdjson/generic/implementation_simdjson_result_base.h for rvv_vls */ +/* including simdjson/generic/numberparsing.h for rvv_vls: #include "simdjson/generic/numberparsing.h" */ +/* begin file simdjson/generic/numberparsing.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_NUMBERPARSING_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_NUMBERPARSING_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/jsoncharutils.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include +#include +#include + +namespace simdjson { +namespace rvv_vls { +namespace numberparsing { + +#ifdef JSON_TEST_NUMBERS +#define INVALID_NUMBER(SRC) (found_invalid_number((SRC)), NUMBER_ERROR) +#define WRITE_INTEGER(VALUE, SRC, WRITER) (found_integer((VALUE), (SRC)), (WRITER).append_s64((VALUE))) +#define WRITE_UNSIGNED(VALUE, SRC, WRITER) (found_unsigned_integer((VALUE), (SRC)), (WRITER).append_u64((VALUE))) +#define WRITE_DOUBLE(VALUE, SRC, WRITER) (found_float((VALUE), (SRC)), (WRITER).append_double((VALUE))) +#define BIGINT_NUMBER(SRC) (found_invalid_number((SRC)), BIGINT_ERROR) +#else +#define INVALID_NUMBER(SRC) (NUMBER_ERROR) +#define WRITE_INTEGER(VALUE, SRC, WRITER) (WRITER).append_s64((VALUE)) +#define WRITE_UNSIGNED(VALUE, SRC, WRITER) (WRITER).append_u64((VALUE)) +#define WRITE_DOUBLE(VALUE, SRC, WRITER) (WRITER).append_double((VALUE)) +#define BIGINT_NUMBER(SRC) (BIGINT_ERROR) +#endif + +namespace { + +// Convert a mantissa, an exponent and a sign bit into an ieee64 double. +// The real_exponent needs to be in [0, 2046] (technically real_exponent = 2047 would be acceptable). +// The mantissa should be in [0,1<<53). The bit at index (1ULL << 52) while be zeroed. +simdjson_inline double to_double(uint64_t mantissa, uint64_t real_exponent, bool negative) { + double d; + mantissa &= ~(1ULL << 52); + mantissa |= real_exponent << 52; + mantissa |= ((static_cast(negative)) << 63); + std::memcpy(&d, &mantissa, sizeof(d)); + return d; +} + +// Attempts to compute i * 10^(power) exactly; and if "negative" is +// true, negate the result. +// This function will only work in some cases, when it does not work, success is +// set to false. This should work *most of the time* (like 99% of the time). +// We assume that power is in the [smallest_power, +// largest_power] interval: the caller is responsible for this check. +simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, double &d) { + // we start with a fast path + // It was described in + // Clinger WD. How to read floating point numbers accurately. + // ACM SIGPLAN Notices. 1990 +#ifndef FLT_EVAL_METHOD +#error "FLT_EVAL_METHOD should be defined, please include cfloat." +#endif +#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) + // We cannot be certain that x/y is rounded to nearest. + if (0 <= power && power <= 22 && i <= 9007199254740991) +#else + if (-22 <= power && power <= 22 && i <= 9007199254740991) +#endif + { + // convert the integer into a double. This is lossless since + // 0 <= i <= 2^53 - 1. + d = double(i); + // + // The general idea is as follows. + // If 0 <= s < 2^53 and if 10^0 <= p <= 10^22 then + // 1) Both s and p can be represented exactly as 64-bit floating-point + // values + // (binary64). + // 2) Because s and p can be represented exactly as floating-point values, + // then s * p + // and s / p will produce correctly rounded values. + // + if (power < 0) { + d = d / simdjson::internal::power_of_ten[-power]; + } else { + d = d * simdjson::internal::power_of_ten[power]; + } + if (negative) { + d = -d; + } + return true; + } + // When 22 < power && power < 22 + 16, we could + // hope for another, secondary fast path. It was + // described by David M. Gay in "Correctly rounded + // binary-decimal and decimal-binary conversions." (1990) + // If you need to compute i * 10^(22 + x) for x < 16, + // first compute i * 10^x, if you know that result is exact + // (e.g., when i * 10^x < 2^53), + // then you can still proceed and do (i * 10^x) * 10^22. + // Is this worth your time? + // You need 22 < power *and* power < 22 + 16 *and* (i * 10^(x-22) < 2^53) + // for this second fast path to work. + // If you you have 22 < power *and* power < 22 + 16, and then you + // optimistically compute "i * 10^(x-22)", there is still a chance that you + // have wasted your time if i * 10^(x-22) >= 2^53. It makes the use cases of + // this optimization maybe less common than we would like. Source: + // http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ + // also used in RapidJSON: https://rapidjson.org/strtod_8h_source.html + + // The fast path has now failed, so we are failing back on the slower path. + + // In the slow path, we need to adjust i so that it is > 1<<63 which is always + // possible, except if i == 0, so we handle i == 0 separately. + if(i == 0) { + d = negative ? -0.0 : 0.0; + return true; + } + + + // The exponent is 1024 + 63 + power + // + floor(log(5**power)/log(2)). + // The 1024 comes from the ieee64 standard. + // The 63 comes from the fact that we use a 64-bit word. + // + // Computing floor(log(5**power)/log(2)) could be + // slow. Instead we use a fast function. + // + // For power in (-400,350), we have that + // (((152170 + 65536) * power ) >> 16); + // is equal to + // floor(log(5**power)/log(2)) + power when power >= 0 + // and it is equal to + // ceil(log(5**-power)/log(2)) + power when power < 0 + // + // The 65536 is (1<<16) and corresponds to + // (65536 * power) >> 16 ---> power + // + // ((152170 * power ) >> 16) is equal to + // floor(log(5**power)/log(2)) + // + // Note that this is not magic: 152170/(1<<16) is + // approximately equal to log(5)/log(2). + // The 1<<16 value is a power of two; we could use a + // larger power of 2 if we wanted to. + // + int64_t exponent = (((152170 + 65536) * power) >> 16) + 1024 + 63; + + + // We want the most significant bit of i to be 1. Shift if needed. + int lz = leading_zeroes(i); + i <<= lz; + + + // We are going to need to do some 64-bit arithmetic to get a precise product. + // We use a table lookup approach. + // It is safe because + // power >= smallest_power + // and power <= largest_power + // We recover the mantissa of the power, it has a leading 1. It is always + // rounded down. + // + // We want the most significant 64 bits of the product. We know + // this will be non-zero because the most significant bit of i is + // 1. + const uint32_t index = 2 * uint32_t(power - simdjson::internal::smallest_power); + // Optimization: It may be that materializing the index as a variable might confuse some compilers and prevent effective complex-addressing loads. (Done for code clarity.) + // + // The full_multiplication function computes the 128-bit product of two 64-bit words + // with a returned value of type value128 with a "low component" corresponding to the + // 64-bit least significant bits of the product and with a "high component" corresponding + // to the 64-bit most significant bits of the product. +#if SIMDJSON_STATIC_REFLECTION + simdjson::internal::value128 firstproduct = full_multiplication(i, simdjson::internal::powers_template<>::power_of_five_128[index]); +#else + simdjson::internal::value128 firstproduct = full_multiplication(i, simdjson::internal::power_of_five_128[index]); +#endif + + // Both i and power_of_five_128[index] have their most significant bit set to 1 which + // implies that the either the most or the second most significant bit of the product + // is 1. We pack values in this manner for efficiency reasons: it maximizes the use + // we make of the product. It also makes it easy to reason about the product: there + // is 0 or 1 leading zero in the product. + + // Unless the least significant 9 bits of the high (64-bit) part of the full + // product are all 1s, then we know that the most significant 55 bits are + // exact and no further work is needed. Having 55 bits is necessary because + // we need 53 bits for the mantissa but we have to have one rounding bit and + // we can waste a bit if the most significant bit of the product is zero. + if((firstproduct.high & 0x1FF) == 0x1FF) { + // We want to compute i * 5^q, but only care about the top 55 bits at most. + // Consider the scenario where q>=0. Then 5^q may not fit in 64-bits. Doing + // the full computation is wasteful. So we do what is called a "truncated + // multiplication". + // We take the most significant 64-bits, and we put them in + // power_of_five_128[index]. Usually, that's good enough to approximate i * 5^q + // to the desired approximation using one multiplication. Sometimes it does not suffice. + // Then we store the next most significant 64 bits in power_of_five_128[index + 1], and + // then we get a better approximation to i * 5^q. + // + // That's for when q>=0. The logic for q<0 is somewhat similar but it is somewhat + // more complicated. + // + // There is an extra layer of complexity in that we need more than 55 bits of + // accuracy in the round-to-even scenario. + // + // The full_multiplication function computes the 128-bit product of two 64-bit words + // with a returned value of type value128 with a "low component" corresponding to the + // 64-bit least significant bits of the product and with a "high component" corresponding + // to the 64-bit most significant bits of the product. +#if SIMDJSON_STATIC_REFLECTION + simdjson::internal::value128 secondproduct = full_multiplication(i, simdjson::internal::powers_template<>::power_of_five_128[index + 1]); +#else + simdjson::internal::value128 secondproduct = full_multiplication(i, simdjson::internal::power_of_five_128[index + 1]); +#endif + firstproduct.low += secondproduct.high; + if(secondproduct.high > firstproduct.low) { firstproduct.high++; } + // As it has been proven by Noble Mushtak and Daniel Lemire in "Fast Number Parsing Without + // Fallback" (https://arxiv.org/abs/2212.06644), at this point we are sure that the product + // is sufficiently accurate, and more computation is not needed. + } + uint64_t lower = firstproduct.low; + uint64_t upper = firstproduct.high; + // The final mantissa should be 53 bits with a leading 1. + // We shift it so that it occupies 54 bits with a leading 1. + /////// + uint64_t upperbit = upper >> 63; + uint64_t mantissa = upper >> (upperbit + 9); + lz += int(1 ^ upperbit); + + // Here we have mantissa < (1<<54). + int64_t real_exponent = exponent - lz; + if (simdjson_unlikely(real_exponent <= 0)) { // we have a subnormal? + // Here have that real_exponent <= 0 so -real_exponent >= 0 + if(-real_exponent + 1 >= 64) { // if we have more than 64 bits below the minimum exponent, you have a zero for sure. + d = negative ? -0.0 : 0.0; + return true; + } + // next line is safe because -real_exponent + 1 < 0 + mantissa >>= -real_exponent + 1; + // Thankfully, we can't have both "round-to-even" and subnormals because + // "round-to-even" only occurs for powers close to 0. + mantissa += (mantissa & 1); // round up + mantissa >>= 1; + // There is a weird scenario where we don't have a subnormal but just. + // Suppose we start with 2.2250738585072013e-308, we end up + // with 0x3fffffffffffff x 2^-1023-53 which is technically subnormal + // whereas 0x40000000000000 x 2^-1023-53 is normal. Now, we need to round + // up 0x3fffffffffffff x 2^-1023-53 and once we do, we are no longer + // subnormal, but we can only know this after rounding. + // So we only declare a subnormal if we are smaller than the threshold. + real_exponent = (mantissa < (uint64_t(1) << 52)) ? 0 : 1; + d = to_double(mantissa, real_exponent, negative); + return true; + } + // We have to round to even. The "to even" part + // is only a problem when we are right in between two floats + // which we guard against. + // If we have lots of trailing zeros, we may fall right between two + // floating-point values. + // + // The round-to-even cases take the form of a number 2m+1 which is in (2^53,2^54] + // times a power of two. That is, it is right between a number with binary significand + // m and another number with binary significand m+1; and it must be the case + // that it cannot be represented by a float itself. + // + // We must have that w * 10 ^q == (2m+1) * 2^p for some power of two 2^p. + // Recall that 10^q = 5^q * 2^q. + // When q >= 0, we must have that (2m+1) is divible by 5^q, so 5^q <= 2^54. We have that + // 5^23 <= 2^54 and it is the last power of five to qualify, so q <= 23. + // When q<0, we have w >= (2m+1) x 5^{-q}. We must have that w<2^{64} so + // (2m+1) x 5^{-q} < 2^{64}. We have that 2m+1>2^{53}. Hence, we must have + // 2^{53} x 5^{-q} < 2^{64}. + // Hence we have 5^{-q} < 2^{11}$ or q>= -4. + // + // We require lower <= 1 and not lower == 0 because we could not prove that + // that lower == 0 is implied; but we could prove that lower <= 1 is a necessary and sufficient test. + if (simdjson_unlikely((lower <= 1) && (power >= -4) && (power <= 23) && ((mantissa & 3) == 1))) { + if((mantissa << (upperbit + 64 - 53 - 2)) == upper) { + mantissa &= ~1; // flip it so that we do not round up + } + } + + mantissa += mantissa & 1; + mantissa >>= 1; + + // Here we have mantissa < (1<<53), unless there was an overflow + if (mantissa >= (1ULL << 53)) { + ////////// + // This will happen when parsing values such as 7.2057594037927933e+16 + //////// + mantissa = (1ULL << 52); + real_exponent++; + } + mantissa &= ~(1ULL << 52); + // we have to check that real_exponent is in range, otherwise we bail out + if (simdjson_unlikely(real_exponent > 2046)) { + // We have an infinite value!!! We could actually throw an error here if we could. + return false; + } + d = to_double(mantissa, real_exponent, negative); + return true; +} + +// We call a fallback floating-point parser that might be slow. Note +// it will accept JSON numbers, but the JSON spec. is more restrictive so +// before you call parse_float_fallback, you need to have validated the input +// string with the JSON grammar. +// It will return an error (false) if the parsed number is infinite. +// The string parsing itself always succeeds. We know that there is at least +// one digit. +static bool parse_float_fallback(const uint8_t *ptr, double *outDouble) { + *outDouble = simdjson::internal::from_chars(reinterpret_cast(ptr)); + // We do not accept infinite values. + + // Detecting finite values in a portable manner is ridiculously hard, ideally + // we would want to do: + // return !std::isfinite(*outDouble); + // but that mysteriously fails under legacy/old libc++ libraries, see + // https://github.com/simdjson/simdjson/issues/1286 + // + // Therefore, fall back to this solution (the extra parens are there + // to handle that max may be a macro on windows). + return !(*outDouble > (std::numeric_limits::max)() || *outDouble < std::numeric_limits::lowest()); +} + +static bool parse_float_fallback(const uint8_t *ptr, const uint8_t *end_ptr, double *outDouble) { + *outDouble = simdjson::internal::from_chars(reinterpret_cast(ptr), reinterpret_cast(end_ptr)); + // We do not accept infinite values. + + // Detecting finite values in a portable manner is ridiculously hard, ideally + // we would want to do: + // return !std::isfinite(*outDouble); + // but that mysteriously fails under legacy/old libc++ libraries, see + // https://github.com/simdjson/simdjson/issues/1286 + // + // Therefore, fall back to this solution (the extra parens are there + // to handle that max may be a macro on windows). + return !(*outDouble > (std::numeric_limits::max)() || *outDouble < std::numeric_limits::lowest()); +} + +// check quickly whether the next 8 chars are made of digits +// at a glance, it looks better than Mula's +// http://0x80.pl/articles/swar-digits-validate.html +simdjson_inline bool is_made_of_eight_digits_fast(const uint8_t *chars) { + uint64_t val; + // this can read up to 7 bytes beyond the buffer size, but we require + // SIMDJSON_PADDING of padding + static_assert(7 <= SIMDJSON_PADDING, "SIMDJSON_PADDING must be bigger than 7"); + std::memcpy(&val, chars, 8); + // a branchy method might be faster: + // return (( val & 0xF0F0F0F0F0F0F0F0 ) == 0x3030303030303030) + // && (( (val + 0x0606060606060606) & 0xF0F0F0F0F0F0F0F0 ) == + // 0x3030303030303030); + return (((val & 0xF0F0F0F0F0F0F0F0) | + (((val + 0x0606060606060606) & 0xF0F0F0F0F0F0F0F0) >> 4)) == + 0x3333333333333333); +} + +template +SIMDJSON_NO_SANITIZE_UNDEFINED // We deliberately allow overflow here and check later +simdjson_inline bool parse_digit(const uint8_t c, I &i) { + const uint8_t digit = static_cast(c - '0'); + if (digit > 9) { + return false; + } + // PERF NOTE: multiplication by 10 is cheaper than arbitrary integer multiplication + i = 10 * i + digit; // might overflow, we will handle the overflow later + return true; +} + +simdjson_inline bool is_digit(const uint8_t c) { + return static_cast(c - '0') <= 9; +} + +simdjson_warn_unused simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const uint8_t *const src, const uint8_t *&p, uint64_t &i, int64_t &exponent) { + // we continue with the fiction that we have an integer. If the + // floating point number is representable as x * 10^z for some integer + // z that fits in 53 bits, then we will be able to convert back the + // the integer into a float in a lossless manner. + const uint8_t *const first_after_period = p; + +#ifdef SIMDJSON_SWAR_NUMBER_PARSING +#if SIMDJSON_SWAR_NUMBER_PARSING + // this helps if we have lots of decimals! + // this turns out to be frequent enough. + if (is_made_of_eight_digits_fast(p)) { + i = i * 100000000 + parse_eight_digits_unrolled(p); + p += 8; + } +#endif // SIMDJSON_SWAR_NUMBER_PARSING +#endif // #ifdef SIMDJSON_SWAR_NUMBER_PARSING + // Unrolling the first digit makes a small difference on some implementations (e.g. westmere) + if (parse_digit(*p, i)) { ++p; } + while (parse_digit(*p, i)) { p++; } + exponent = first_after_period - p; + // Decimal without digits (123.) is illegal + if (exponent == 0) { + return INVALID_NUMBER(src); + } + return SUCCESS; +} + +simdjson_warn_unused simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const src, const uint8_t *&p, int64_t &exponent) { + // Exp Sign: -123.456e[-]78 + bool neg_exp = ('-' == *p); + if (neg_exp || '+' == *p) { p++; } // Skip + as well + + // Exponent: -123.456e-[78] + auto start_exp = p; + int64_t exp_number = 0; + while (parse_digit(*p, exp_number)) { ++p; } + // It is possible for parse_digit to overflow. + // In particular, it could overflow to INT64_MIN, and we cannot do - INT64_MIN. + // Thus we *must* check for possible overflow before we negate exp_number. + + // Performance notes: it may seem like combining the two "simdjson_unlikely checks" below into + // a single simdjson_unlikely path would be faster. The reasoning is sound, but the compiler may + // not oblige and may, in fact, generate two distinct paths in any case. It might be + // possible to do uint64_t(p - start_exp - 1) >= 18 but it could end up trading off + // instructions for a simdjson_likely branch, an unconclusive gain. + + // If there were no digits, it's an error. + if (simdjson_unlikely(p == start_exp)) { + return INVALID_NUMBER(src); + } + // We have a valid positive exponent in exp_number at this point, except that + // it may have overflowed. + + // If there were more than 18 digits, we may have overflowed the integer. We have to do + // something!!!! + if (simdjson_unlikely(p > start_exp+18)) { + // Skip leading zeroes: 1e000000000000000000001 is technically valid and does not overflow + while (*start_exp == '0') { start_exp++; } + // 19 digits could overflow int64_t and is kind of absurd anyway. We don't + // support exponents smaller than -999,999,999,999,999,999 and bigger + // than 999,999,999,999,999,999. + // We can truncate. + // Note that 999999999999999999 is assuredly too large. The maximal ieee64 value before + // infinity is ~1.8e308. The smallest subnormal is ~5e-324. So, actually, we could + // truncate at 324. + // Note that there is no reason to fail per se at this point in time. + // E.g., 0e999999999999999999999 is a fine number. + if (p > start_exp+18) { exp_number = 999999999999999999; } + } + // At this point, we know that exp_number is a sane, positive, signed integer. + // It is <= 999,999,999,999,999,999. As long as 'exponent' is in + // [-8223372036854775808, 8223372036854775808], we won't overflow. Because 'exponent' + // is bounded in magnitude by the size of the JSON input, we are fine in this universe. + // To sum it up: the next line should never overflow. + exponent += (neg_exp ? -exp_number : exp_number); + return SUCCESS; +} + +simdjson_inline bool check_if_integer(const uint8_t *const src, size_t max_length) { + const uint8_t *const srcend = src + max_length; + bool negative = (*src == '-'); // we can always read at least one character after the '-' + const uint8_t *p = src + uint8_t(negative); + if(p == srcend) { return false; } + if(*p == '0') { + ++p; + if(p == srcend) { return true; } + if(jsoncharutils::is_not_structural_or_whitespace(*p)) { return false; } + return true; + } + while(p != srcend && is_digit(*p)) { ++p; } + if(p == srcend) { return true; } + if(jsoncharutils::is_not_structural_or_whitespace(*p)) { return false; } + return true; +} + +simdjson_inline size_t significant_digits(const uint8_t * start_digits, size_t digit_count) { + // It is possible that the integer had an overflow. + // We have to handle the case where we have 0.0000somenumber. + const uint8_t *start = start_digits; + while ((*start == '0') || (*start == '.')) { ++start; } + // we over-decrement by one when there is a '.' + return digit_count - size_t(start - start_digits); +} + +} // unnamed namespace + +/** @private */ +static error_code slow_float_parsing(simdjson_unused const uint8_t * src, double* answer) { + if (parse_float_fallback(src, answer)) { + return SUCCESS; + } + return INVALID_NUMBER(src); +} + +/** @private */ +template +simdjson_warn_unused simdjson_inline error_code write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer) { + // If we frequently had to deal with long strings of digits, + // we could extend our code by using a 128-bit integer instead + // of a 64-bit integer. However, this is uncommon in practice. + // + // 9999999999999999999 < 2**64 so we can accommodate 19 digits. + // If we have a decimal separator, then digit_count - 1 is the number of digits, but we + // may not have a decimal separator! + if (simdjson_unlikely(digit_count > 19 && significant_digits(start_digits, digit_count) > 19)) { + // Ok, chances are good that we had an overflow! + // this is almost never going to get called!!! + // we start anew, going slowly!!! + // This will happen in the following examples: + // 10000000000000000000000000000000000000000000e+308 + // 3.1415926535897932384626433832795028841971693993751 + // + // NOTE: We do not pass a reference to the to slow_float_parsing. If we passed our writer + // reference to it, it would force it to be stored in memory, preventing the compiler from + // picking it apart and putting into registers. i.e. if we pass it as reference, + // it gets slow. + double d; + error_code error = slow_float_parsing(src, &d); + writer.append_double(d); + return error; + } + // NOTE: it's weird that the simdjson_unlikely() only wraps half the if, but it seems to get slower any other + // way we've tried: https://github.com/simdjson/simdjson/pull/990#discussion_r448497331 + // To future reader: we'd love if someone found a better way, or at least could explain this result! + if (simdjson_unlikely(exponent < simdjson::internal::smallest_power) || (exponent > simdjson::internal::largest_power)) { + // + // Important: smallest_power is such that it leads to a zero value. + // Observe that 18446744073709551615e-343 == 0, i.e. (2**64 - 1) e -343 is zero + // so something x 10^-343 goes to zero, but not so with something x 10^-342. + static_assert(simdjson::internal::smallest_power <= -342, "smallest_power is not small enough"); + // + if((exponent < simdjson::internal::smallest_power) || (i == 0)) { + // E.g. Parse "-0.0e-999" into the same value as "-0.0". See https://en.wikipedia.org/wiki/Signed_zero + WRITE_DOUBLE(negative ? -0.0 : 0.0, src, writer); + return SUCCESS; + } else { // (exponent > largest_power) and (i != 0) + // We have, for sure, an infinite value and simdjson refuses to parse infinite values. + return INVALID_NUMBER(src); + } + } + double d; + if (!compute_float_64(exponent, i, negative, d)) { + // we are almost never going to get here. + if (!parse_float_fallback(src, &d)) { return INVALID_NUMBER(src); } + } + WRITE_DOUBLE(d, src, writer); + return SUCCESS; +} + +// parse the number at src +// define JSON_TEST_NUMBERS for unit testing +// +// It is assumed that the number is followed by a structural ({,},],[) character +// or a white space character. If that is not the case (e.g., when the JSON +// document is made of a single number), then it is necessary to copy the +// content and append a space before calling this function. +// +// Our objective is accurate parsing (ULP of 0) at high speed. +template +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer); + +// for performance analysis, it is sometimes useful to skip parsing +#ifdef SIMDJSON_SKIPNUMBERPARSING + +template +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const, W &writer) { + writer.append_s64(0); // always write zero + return SUCCESS; // always succeeds +} + +simdjson_unused simdjson_inline simdjson_result parse_unsigned(const uint8_t * const src) noexcept { return 0; } +simdjson_unused simdjson_inline simdjson_result parse_integer(const uint8_t * const src) noexcept { return 0; } +simdjson_unused simdjson_inline simdjson_result parse_double(const uint8_t * const src) noexcept { return 0; } +simdjson_unused simdjson_inline simdjson_result parse_unsigned_in_string(const uint8_t * const src) noexcept { return 0; } +simdjson_unused simdjson_inline simdjson_result parse_integer_in_string(const uint8_t * const src) noexcept { return 0; } +simdjson_unused simdjson_inline simdjson_result parse_double_in_string(const uint8_t * const src) noexcept { return 0; } +simdjson_unused simdjson_inline bool is_negative(const uint8_t * src) noexcept { return false; } +simdjson_unused simdjson_inline simdjson_result is_integer(const uint8_t * src) noexcept { return false; } +simdjson_unused simdjson_inline simdjson_result get_number_type(const uint8_t * src) noexcept { return number_type::signed_integer; } +#else + +// parse the number at src +// define JSON_TEST_NUMBERS for unit testing +// +// It is assumed that the number is followed by a structural ({,},],[) character +// or a white space character. If that is not the case (e.g., when the JSON +// document is made of a single number), then it is necessary to copy the +// content and append a space before calling this function. +// +// Our objective is accurate parsing (ULP of 0) at high speed. +template +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { + // + // Check for minus sign + // + bool negative = (*src == '-'); + const uint8_t *p = src + uint8_t(negative); + + // + // Parse the integer part. + // + // PERF NOTE: we don't use is_made_of_eight_digits_fast because large integers like 123456789 are rare + const uint8_t *const start_digits = p; + uint64_t i = 0; + while (parse_digit(*p, i)) { p++; } + + // If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error. + // Optimization note: size_t is expected to be unsigned. + size_t digit_count = size_t(p - start_digits); + if (digit_count == 0 || ('0' == *start_digits && digit_count > 1)) { return INVALID_NUMBER(src); } + + // + // Handle floats if there is a . or e (or both) + // + int64_t exponent = 0; + bool is_float = false; + if ('.' == *p) { + is_float = true; + ++p; + SIMDJSON_TRY( parse_decimal_after_separator(src, p, i, exponent) ); + digit_count = int(p - start_digits); // used later to guard against overflows + } + if (('e' == *p) || ('E' == *p)) { + is_float = true; + ++p; + SIMDJSON_TRY( parse_exponent(src, p, exponent) ); + } + if (is_float) { + const bool dirty_end = jsoncharutils::is_not_structural_or_whitespace(*p); + SIMDJSON_TRY( write_float(src, negative, i, start_digits, digit_count, exponent, writer) ); + if (dirty_end) { return INVALID_NUMBER(src); } + return SUCCESS; + } + + // The longest negative 64-bit number is 19 digits. + // The longest positive 64-bit number is 20 digits. + // We do it this way so we don't trigger this branch unless we must. + size_t longest_digit_count = negative ? 19 : 20; + if (digit_count > longest_digit_count) { return BIGINT_NUMBER(src); } + if (digit_count == longest_digit_count) { + if (negative) { + // Anything negative above INT64_MAX+1 is invalid + if (i > uint64_t(INT64_MAX)+1) { return BIGINT_NUMBER(src); } + WRITE_INTEGER(~i+1, src, writer); + if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); } + return SUCCESS; + // Positive overflow check: + // - A 20 digit number starting with 2-9 is overflow, because 18,446,744,073,709,551,615 is the + // biggest uint64_t. + // - A 20 digit number starting with 1 is overflow if it is less than INT64_MAX. + // If we got here, it's a 20 digit number starting with the digit "1". + // - If a 20 digit number starting with 1 overflowed (i*10+digit), the result will be smaller + // than 1,553,255,926,290,448,384. + // - That is smaller than the smallest possible 20-digit number the user could write: + // 10,000,000,000,000,000,000. + // - Therefore, if the number is positive and lower than that, it's overflow. + // - The value we are looking at is less than or equal to INT64_MAX. + // + } else if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INVALID_NUMBER(src); } + } + + // Write unsigned if it does not fit in a signed integer. + if (i > uint64_t(INT64_MAX)) { + WRITE_UNSIGNED(i, src, writer); + } else { +#if SIMDJSON_MINUS_ZERO_AS_FLOAT + if(i == 0 && negative) { + // We have to write -0.0 instead of 0 + WRITE_DOUBLE(-0.0, src, writer); + } else { + WRITE_INTEGER(negative ? (~i+1) : i, src, writer); + } +#else + WRITE_INTEGER(negative ? (~i+1) : i, src, writer); +#endif + } + if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); } + return SUCCESS; +} + +// Inlineable functions +namespace { + +// This table can be used to characterize the final character of an integer +// string. For JSON structural character and allowable white space characters, +// we return SUCCESS. For 'e', '.' and 'E', we return INCORRECT_TYPE. Otherwise +// we return NUMBER_ERROR. +// Optimization note: we could easily reduce the size of the table by half (to 128) +// at the cost of an extra branch. +// Optimization note: we want the values to use at most 8 bits (not, e.g., 32 bits): +static_assert(error_code(uint8_t(NUMBER_ERROR))== NUMBER_ERROR, "bad NUMBER_ERROR cast"); +static_assert(error_code(uint8_t(SUCCESS))== SUCCESS, "bad NUMBER_ERROR cast"); +static_assert(error_code(uint8_t(INCORRECT_TYPE))== INCORRECT_TYPE, "bad NUMBER_ERROR cast"); + +const uint8_t integer_string_finisher[256] = { + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, SUCCESS, + SUCCESS, NUMBER_ERROR, NUMBER_ERROR, SUCCESS, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, SUCCESS, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, SUCCESS, + NUMBER_ERROR, INCORRECT_TYPE, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, SUCCESS, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, INCORRECT_TYPE, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, SUCCESS, NUMBER_ERROR, SUCCESS, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, INCORRECT_TYPE, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, SUCCESS, NUMBER_ERROR, + SUCCESS, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR}; + +// Parse any number from 0 to 18,446,744,073,709,551,615 +simdjson_unused simdjson_inline simdjson_result parse_unsigned(const uint8_t * const src) noexcept { + const uint8_t *p = src; + // + // Parse the integer part. + // + // PERF NOTE: we don't use is_made_of_eight_digits_fast because large integers like 123456789 are rare + const uint8_t *const start_digits = p; + uint64_t i = 0; + while (parse_digit(*p, i)) { p++; } + + // If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error. + // Optimization note: size_t is expected to be unsigned. + size_t digit_count = size_t(p - start_digits); + // The longest positive 64-bit number is 20 digits. + // We do it this way so we don't trigger this branch unless we must. + // Optimization note: the compiler can probably merge + // ((digit_count == 0) || (digit_count > 20)) + // into a single branch since digit_count is unsigned. + if ((digit_count == 0) || (digit_count > 20)) { return INCORRECT_TYPE; } + // Here digit_count > 0. + if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; } + // We can do the following... + // if (!jsoncharutils::is_structural_or_whitespace(*p)) { + // return (*p == '.' || *p == 'e' || *p == 'E') ? INCORRECT_TYPE : NUMBER_ERROR; + // } + // as a single table lookup: + if (integer_string_finisher[*p] != SUCCESS) { return error_code(integer_string_finisher[*p]); } + + if (digit_count == 20) { + // Positive overflow check: + // - A 20 digit number starting with 2-9 is overflow, because 18,446,744,073,709,551,615 is the + // biggest uint64_t. + // - A 20 digit number starting with 1 is overflow if it is less than INT64_MAX. + // If we got here, it's a 20 digit number starting with the digit "1". + // - If a 20 digit number starting with 1 overflowed (i*10+digit), the result will be smaller + // than 1,553,255,926,290,448,384. + // - That is smaller than the smallest possible 20-digit number the user could write: + // 10,000,000,000,000,000,000. + // - Therefore, if the number is positive and lower than that, it's overflow. + // - The value we are looking at is less than or equal to INT64_MAX. + // + if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; } + } + + return i; +} + + +// Parse any number from 0 to 18,446,744,073,709,551,615 +// Never read at src_end or beyond +simdjson_unused simdjson_inline simdjson_result parse_unsigned(const uint8_t * const src, const uint8_t * const src_end) noexcept { + const uint8_t *p = src; + // + // Parse the integer part. + // + // PERF NOTE: we don't use is_made_of_eight_digits_fast because large integers like 123456789 are rare + const uint8_t *const start_digits = p; + uint64_t i = 0; + while ((p != src_end) && parse_digit(*p, i)) { p++; } + + // If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error. + // Optimization note: size_t is expected to be unsigned. + size_t digit_count = size_t(p - start_digits); + // The longest positive 64-bit number is 20 digits. + // We do it this way so we don't trigger this branch unless we must. + // Optimization note: the compiler can probably merge + // ((digit_count == 0) || (digit_count > 20)) + // into a single branch since digit_count is unsigned. + if ((digit_count == 0) || (digit_count > 20)) { return INCORRECT_TYPE; } + // Here digit_count > 0. + if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; } + // We can do the following... + // if (!jsoncharutils::is_structural_or_whitespace(*p)) { + // return (*p == '.' || *p == 'e' || *p == 'E') ? INCORRECT_TYPE : NUMBER_ERROR; + // } + // as a single table lookup: + if ((p != src_end) && integer_string_finisher[*p] != SUCCESS) { return error_code(integer_string_finisher[*p]); } + + if (digit_count == 20) { + // Positive overflow check: + // - A 20 digit number starting with 2-9 is overflow, because 18,446,744,073,709,551,615 is the + // biggest uint64_t. + // - A 20 digit number starting with 1 is overflow if it is less than INT64_MAX. + // If we got here, it's a 20 digit number starting with the digit "1". + // - If a 20 digit number starting with 1 overflowed (i*10+digit), the result will be smaller + // than 1,553,255,926,290,448,384. + // - That is smaller than the smallest possible 20-digit number the user could write: + // 10,000,000,000,000,000,000. + // - Therefore, if the number is positive and lower than that, it's overflow. + // - The value we are looking at is less than or equal to INT64_MAX. + // + if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; } + } + + return i; +} + +// Parse any number from 0 to 18,446,744,073,709,551,615 +simdjson_unused simdjson_inline simdjson_result parse_unsigned_in_string(const uint8_t * const src) noexcept { + const uint8_t *p = src + 1; + // + // Parse the integer part. + // + // PERF NOTE: we don't use is_made_of_eight_digits_fast because large integers like 123456789 are rare + const uint8_t *const start_digits = p; + uint64_t i = 0; + while (parse_digit(*p, i)) { p++; } + + // If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error. + // Optimization note: size_t is expected to be unsigned. + size_t digit_count = size_t(p - start_digits); + // The longest positive 64-bit number is 20 digits. + // We do it this way so we don't trigger this branch unless we must. + // Optimization note: the compiler can probably merge + // ((digit_count == 0) || (digit_count > 20)) + // into a single branch since digit_count is unsigned. + if ((digit_count == 0) || (digit_count > 20)) { return INCORRECT_TYPE; } + // Here digit_count > 0. + if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; } + // We can do the following... + // if (!jsoncharutils::is_structural_or_whitespace(*p)) { + // return (*p == '.' || *p == 'e' || *p == 'E') ? INCORRECT_TYPE : NUMBER_ERROR; + // } + // as a single table lookup: + if (*p != '"') { return NUMBER_ERROR; } + + if (digit_count == 20) { + // Positive overflow check: + // - A 20 digit number starting with 2-9 is overflow, because 18,446,744,073,709,551,615 is the + // biggest uint64_t. + // - A 20 digit number starting with 1 is overflow if it is less than INT64_MAX. + // If we got here, it's a 20 digit number starting with the digit "1". + // - If a 20 digit number starting with 1 overflowed (i*10+digit), the result will be smaller + // than 1,553,255,926,290,448,384. + // - That is smaller than the smallest possible 20-digit number the user could write: + // 10,000,000,000,000,000,000. + // - Therefore, if the number is positive and lower than that, it's overflow. + // - The value we are looking at is less than or equal to INT64_MAX. + // + // Note: we use src[1] and not src[0] because src[0] is the quote character in this + // instance. + if (src[1] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; } + } + + return i; +} + +// Parse any number from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 +simdjson_unused simdjson_inline simdjson_result parse_integer(const uint8_t *src) noexcept { + // + // Check for minus sign + // + bool negative = (*src == '-'); + const uint8_t *p = src + uint8_t(negative); + + // + // Parse the integer part. + // + // PERF NOTE: we don't use is_made_of_eight_digits_fast because large integers like 123456789 are rare + const uint8_t *const start_digits = p; + uint64_t i = 0; + while (parse_digit(*p, i)) { p++; } + + // If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error. + // Optimization note: size_t is expected to be unsigned. + size_t digit_count = size_t(p - start_digits); + // We go from + // -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 + // so we can never represent numbers that have more than 19 digits. + size_t longest_digit_count = 19; + // Optimization note: the compiler can probably merge + // ((digit_count == 0) || (digit_count > longest_digit_count)) + // into a single branch since digit_count is unsigned. + if ((digit_count == 0) || (digit_count > longest_digit_count)) { return INCORRECT_TYPE; } + // Here digit_count > 0. + if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; } + // We can do the following... + // if (!jsoncharutils::is_structural_or_whitespace(*p)) { + // return (*p == '.' || *p == 'e' || *p == 'E') ? INCORRECT_TYPE : NUMBER_ERROR; + // } + // as a single table lookup: + if(integer_string_finisher[*p] != SUCCESS) { return error_code(integer_string_finisher[*p]); } + // Negative numbers have can go down to - INT64_MAX - 1 whereas positive numbers are limited to INT64_MAX. + // Performance note: This check is only needed when digit_count == longest_digit_count but it is + // so cheap that we might as well always make it. + if(i > uint64_t(INT64_MAX) + uint64_t(negative)) { return INCORRECT_TYPE; } + return negative ? (~i+1) : i; +} + +// Parse any number from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 +// Never read at src_end or beyond +simdjson_unused simdjson_inline simdjson_result parse_integer(const uint8_t * const src, const uint8_t * const src_end) noexcept { + // + // Check for minus sign + // + if(src == src_end) { return NUMBER_ERROR; } + bool negative = (*src == '-'); + const uint8_t *p = src + uint8_t(negative); + + // + // Parse the integer part. + // + // PERF NOTE: we don't use is_made_of_eight_digits_fast because large integers like 123456789 are rare + const uint8_t *const start_digits = p; + uint64_t i = 0; + while ((p != src_end) && parse_digit(*p, i)) { p++; } + + // If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error. + // Optimization note: size_t is expected to be unsigned. + size_t digit_count = size_t(p - start_digits); + // We go from + // -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 + // so we can never represent numbers that have more than 19 digits. + size_t longest_digit_count = 19; + // Optimization note: the compiler can probably merge + // ((digit_count == 0) || (digit_count > longest_digit_count)) + // into a single branch since digit_count is unsigned. + if ((digit_count == 0) || (digit_count > longest_digit_count)) { return INCORRECT_TYPE; } + // Here digit_count > 0. + if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; } + // We can do the following... + // if (!jsoncharutils::is_structural_or_whitespace(*p)) { + // return (*p == '.' || *p == 'e' || *p == 'E') ? INCORRECT_TYPE : NUMBER_ERROR; + // } + // as a single table lookup: + if((p != src_end) && integer_string_finisher[*p] != SUCCESS) { return error_code(integer_string_finisher[*p]); } + // Negative numbers have can go down to - INT64_MAX - 1 whereas positive numbers are limited to INT64_MAX. + // Performance note: This check is only needed when digit_count == longest_digit_count but it is + // so cheap that we might as well always make it. + if(i > uint64_t(INT64_MAX) + uint64_t(negative)) { return INCORRECT_TYPE; } + return negative ? (~i+1) : i; +} + +// Parse any number from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 +simdjson_unused simdjson_inline simdjson_result parse_integer_in_string(const uint8_t *src) noexcept { + // + // Check for minus sign + // + bool negative = (*(src + 1) == '-'); + src += uint8_t(negative) + 1; + + // + // Parse the integer part. + // + // PERF NOTE: we don't use is_made_of_eight_digits_fast because large integers like 123456789 are rare + const uint8_t *const start_digits = src; + uint64_t i = 0; + while (parse_digit(*src, i)) { src++; } + + // If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error. + // Optimization note: size_t is expected to be unsigned. + size_t digit_count = size_t(src - start_digits); + // We go from + // -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 + // so we can never represent numbers that have more than 19 digits. + size_t longest_digit_count = 19; + // Optimization note: the compiler can probably merge + // ((digit_count == 0) || (digit_count > longest_digit_count)) + // into a single branch since digit_count is unsigned. + if ((digit_count == 0) || (digit_count > longest_digit_count)) { return INCORRECT_TYPE; } + // Here digit_count > 0. + if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; } + // We can do the following... + // if (!jsoncharutils::is_structural_or_whitespace(*src)) { + // return (*src == '.' || *src == 'e' || *src == 'E') ? INCORRECT_TYPE : NUMBER_ERROR; + // } + // as a single table lookup: + if(*src != '"') { return NUMBER_ERROR; } + // Negative numbers have can go down to - INT64_MAX - 1 whereas positive numbers are limited to INT64_MAX. + // Performance note: This check is only needed when digit_count == longest_digit_count but it is + // so cheap that we might as well always make it. + if(i > uint64_t(INT64_MAX) + uint64_t(negative)) { return INCORRECT_TYPE; } + return negative ? (~i+1) : i; +} + +simdjson_unused simdjson_inline simdjson_result parse_double(const uint8_t * src) noexcept { + // + // Check for minus sign + // + bool negative = (*src == '-'); + src += uint8_t(negative); + + // + // Parse the integer part. + // + uint64_t i = 0; + const uint8_t *p = src; + p += parse_digit(*p, i); + bool leading_zero = (i == 0); + while (parse_digit(*p, i)) { p++; } + // no integer digits, or 0123 (zero must be solo) + if ( p == src ) { return INCORRECT_TYPE; } + if ( (leading_zero && p != src+1)) { return NUMBER_ERROR; } + + // + // Parse the decimal part. + // + int64_t exponent = 0; + bool overflow; + if (simdjson_likely(*p == '.')) { + p++; + const uint8_t *start_decimal_digits = p; + if (!parse_digit(*p, i)) { return NUMBER_ERROR; } // no decimal digits + p++; + while (parse_digit(*p, i)) { p++; } + exponent = -(p - start_decimal_digits); + + // Overflow check. More than 19 digits (minus the decimal) may be overflow. + overflow = p-src-1 > 19; + if (simdjson_unlikely(overflow && leading_zero)) { + // Skip leading 0.00000 and see if it still overflows + const uint8_t *start_digits = src + 2; + while (*start_digits == '0') { start_digits++; } + overflow = p-start_digits > 19; + } + } else { + overflow = p-src > 19; + } + + // + // Parse the exponent + // + if (*p == 'e' || *p == 'E') { + p++; + bool exp_neg = *p == '-'; + p += exp_neg || *p == '+'; + + uint64_t exp = 0; + const uint8_t *start_exp_digits = p; + while (parse_digit(*p, exp)) { p++; } + // no exp digits, or 20+ exp digits + if (p-start_exp_digits == 0 || p-start_exp_digits > 19) { return NUMBER_ERROR; } + + exponent += exp_neg ? 0-exp : exp; + } + + if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return NUMBER_ERROR; } + + overflow = overflow || exponent < simdjson::internal::smallest_power || exponent > simdjson::internal::largest_power; + + // + // Assemble (or slow-parse) the float + // + double d; + if (simdjson_likely(!overflow)) { + if (compute_float_64(exponent, i, negative, d)) { return d; } + } + if (!parse_float_fallback(src - uint8_t(negative), &d)) { + return NUMBER_ERROR; + } + return d; +} + +simdjson_unused simdjson_inline bool is_negative(const uint8_t * src) noexcept { + return (*src == '-'); +} + +simdjson_unused simdjson_inline simdjson_result is_integer(const uint8_t * src) noexcept { + bool negative = (*src == '-'); + src += uint8_t(negative); + const uint8_t *p = src; + while(static_cast(*p - '0') <= 9) { p++; } + if ( p == src ) { return NUMBER_ERROR; } + if (jsoncharutils::is_structural_or_whitespace(*p)) { return true; } + return false; +} + +simdjson_unused simdjson_inline simdjson_result get_number_type(const uint8_t * src) noexcept { + bool negative = (*src == '-'); + src += uint8_t(negative); + const uint8_t *p = src; + while(static_cast(*p - '0') <= 9) { p++; } + size_t digit_count = size_t(p - src); + if ( p == src ) { return NUMBER_ERROR; } + if (jsoncharutils::is_structural_or_whitespace(*p)) { + static const uint8_t * smaller_big_integer = reinterpret_cast("9223372036854775808"); + // We have an integer. + if(simdjson_unlikely(digit_count > 20)) { + return number_type::big_integer; + } + // If the number is negative and valid, it must be a signed integer. + if(negative) { + if (simdjson_unlikely(digit_count > 19)) return number_type::big_integer; + if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) { + return number_type::big_integer; + } +#if SIMDJSON_MINUS_ZERO_AS_FLOAT + if(digit_count == 1 && src[0] == '0') { + // We have to write -0.0 instead of 0 + return number_type::floating_point_number; + } +#endif + return number_type::signed_integer; + } + // Let us check if we have a big integer (>=2**64). + static const uint8_t * two_to_sixtyfour = reinterpret_cast("18446744073709551616"); + if((digit_count > 20) || (digit_count == 20 && memcmp(src, two_to_sixtyfour, 20) >= 0)) { + return number_type::big_integer; + } + // The number is positive and smaller than 18446744073709551616 (or 2**64). + // We want values larger or equal to 9223372036854775808 to be unsigned + // integers, and the other values to be signed integers. + if((digit_count == 20) || (digit_count >= 19 && memcmp(src, smaller_big_integer, 19) >= 0)) { + return number_type::unsigned_integer; + } + return number_type::signed_integer; + } + // Hopefully, we have 'e' or 'E' or '.'. + return number_type::floating_point_number; +} + +// Never read at src_end or beyond +simdjson_unused simdjson_inline simdjson_result parse_double(const uint8_t * src, const uint8_t * const src_end) noexcept { + if(src == src_end) { return NUMBER_ERROR; } + // + // Check for minus sign + // + bool negative = (*src == '-'); + src += uint8_t(negative); + + // + // Parse the integer part. + // + uint64_t i = 0; + const uint8_t *p = src; + if(p == src_end) { return NUMBER_ERROR; } + p += parse_digit(*p, i); + bool leading_zero = (i == 0); + while ((p != src_end) && parse_digit(*p, i)) { p++; } + // no integer digits, or 0123 (zero must be solo) + if ( p == src ) { return INCORRECT_TYPE; } + if ( (leading_zero && p != src+1)) { return NUMBER_ERROR; } + + // + // Parse the decimal part. + // + int64_t exponent = 0; + bool overflow; + if (simdjson_likely((p != src_end) && (*p == '.'))) { + p++; + const uint8_t *start_decimal_digits = p; + if ((p == src_end) || !parse_digit(*p, i)) { return NUMBER_ERROR; } // no decimal digits + p++; + while ((p != src_end) && parse_digit(*p, i)) { p++; } + exponent = -(p - start_decimal_digits); + + // Overflow check. More than 19 digits (minus the decimal) may be overflow. + overflow = p-src-1 > 19; + if (simdjson_unlikely(overflow && leading_zero)) { + // Skip leading 0.00000 and see if it still overflows + const uint8_t *start_digits = src + 2; + while (*start_digits == '0') { start_digits++; } + overflow = start_digits-src > 19; + } + } else { + overflow = p-src > 19; + } + + // + // Parse the exponent + // + if ((p != src_end) && (*p == 'e' || *p == 'E')) { + p++; + if(p == src_end) { return NUMBER_ERROR; } + bool exp_neg = *p == '-'; + p += exp_neg || *p == '+'; + + uint64_t exp = 0; + const uint8_t *start_exp_digits = p; + while ((p != src_end) && parse_digit(*p, exp)) { p++; } + // no exp digits, or 20+ exp digits + if (p-start_exp_digits == 0 || p-start_exp_digits > 19) { return NUMBER_ERROR; } + + exponent += exp_neg ? 0-exp : exp; + } + + if ((p != src_end) && jsoncharutils::is_not_structural_or_whitespace(*p)) { return NUMBER_ERROR; } + + overflow = overflow || exponent < simdjson::internal::smallest_power || exponent > simdjson::internal::largest_power; + + // + // Assemble (or slow-parse) the float + // + double d; + if (simdjson_likely(!overflow)) { + if (compute_float_64(exponent, i, negative, d)) { return d; } + } + if (!parse_float_fallback(src - uint8_t(negative), src_end, &d)) { + return NUMBER_ERROR; + } + return d; +} + +simdjson_unused simdjson_inline simdjson_result parse_double_in_string(const uint8_t * src) noexcept { + // + // Check for minus sign + // + bool negative = (*(src + 1) == '-'); + src += uint8_t(negative) + 1; + + // + // Parse the integer part. + // + uint64_t i = 0; + const uint8_t *p = src; + p += parse_digit(*p, i); + bool leading_zero = (i == 0); + while (parse_digit(*p, i)) { p++; } + // no integer digits, or 0123 (zero must be solo) + if ( p == src ) { return INCORRECT_TYPE; } + if ( (leading_zero && p != src+1)) { return NUMBER_ERROR; } + + // + // Parse the decimal part. + // + int64_t exponent = 0; + bool overflow; + if (simdjson_likely(*p == '.')) { + p++; + const uint8_t *start_decimal_digits = p; + if (!parse_digit(*p, i)) { return NUMBER_ERROR; } // no decimal digits + p++; + while (parse_digit(*p, i)) { p++; } + exponent = -(p - start_decimal_digits); + + // Overflow check. More than 19 digits (minus the decimal) may be overflow. + overflow = p-src-1 > 19; + if (simdjson_unlikely(overflow && leading_zero)) { + // Skip leading 0.00000 and see if it still overflows + const uint8_t *start_digits = src + 2; + while (*start_digits == '0') { start_digits++; } + overflow = p-start_digits > 19; + } + } else { + overflow = p-src > 19; + } + + // + // Parse the exponent + // + if (*p == 'e' || *p == 'E') { + p++; + bool exp_neg = *p == '-'; + p += exp_neg || *p == '+'; + + uint64_t exp = 0; + const uint8_t *start_exp_digits = p; + while (parse_digit(*p, exp)) { p++; } + // no exp digits, or 20+ exp digits + if (p-start_exp_digits == 0 || p-start_exp_digits > 19) { return NUMBER_ERROR; } + + exponent += exp_neg ? 0-exp : exp; + } + + if (*p != '"') { return NUMBER_ERROR; } + + overflow = overflow || exponent < simdjson::internal::smallest_power || exponent > simdjson::internal::largest_power; + + // + // Assemble (or slow-parse) the float + // + double d; + if (simdjson_likely(!overflow)) { + if (compute_float_64(exponent, i, negative, d)) { return d; } + } + if (!parse_float_fallback(src - uint8_t(negative), &d)) { + return NUMBER_ERROR; + } + return d; +} + +} // unnamed namespace +#endif // SIMDJSON_SKIPNUMBERPARSING + +} // namespace numberparsing + +inline std::ostream& operator<<(std::ostream& out, number_type type) noexcept { + switch (type) { + case number_type::signed_integer: out << "integer in [-9223372036854775808,9223372036854775808)"; break; + case number_type::unsigned_integer: out << "unsigned integer in [9223372036854775808,18446744073709551616)"; break; + case number_type::floating_point_number: out << "floating-point number (binary64)"; break; + case number_type::big_integer: out << "big integer"; break; + default: SIMDJSON_UNREACHABLE(); + } + return out; +} + +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_NUMBERPARSING_H +/* end file simdjson/generic/numberparsing.h for rvv_vls */ + +/* including simdjson/generic/implementation_simdjson_result_base-inl.h for rvv_vls: #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */ +/* begin file simdjson/generic/implementation_simdjson_result_base-inl.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_IMPLEMENTATION_SIMDJSON_RESULT_BASE_INL_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_IMPLEMENTATION_SIMDJSON_RESULT_BASE_INL_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { + +// +// internal::implementation_simdjson_result_base inline implementation +// + +template +simdjson_inline void implementation_simdjson_result_base::tie(T &value, error_code &error) && noexcept { + error = this->second; + if (!error) { + value = std::forward>(*this).first; + } +} + +template +simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_base::get(T &value) && noexcept { + error_code error; + std::forward>(*this).tie(value, error); + return error; +} + +template +simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_base::error() const noexcept { + return this->second; +} + + +template +simdjson_warn_unused simdjson_inline bool implementation_simdjson_result_base::has_value() const noexcept { + return this->error() == SUCCESS; +} + +#if SIMDJSON_EXCEPTIONS + +template +simdjson_inline T& implementation_simdjson_result_base::operator*() & noexcept(false) { + return this->value(); +} + +template +simdjson_inline T&& implementation_simdjson_result_base::operator*() && noexcept(false) { + return std::forward>(*this).value(); +} + +template +simdjson_inline T* implementation_simdjson_result_base::operator->() noexcept(false) { + if (this->error()) { throw simdjson_error(this->error()); } + return &this->first; +} + + +template +simdjson_inline const T* implementation_simdjson_result_base::operator->() const noexcept(false) { + if (this->error()) { throw simdjson_error(this->error()); } + return &this->first; +} + +template +simdjson_inline T& implementation_simdjson_result_base::value() & noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return this->first; +} + +template +simdjson_inline T&& implementation_simdjson_result_base::value() && noexcept(false) { + return std::forward>(*this).take_value(); +} + +template +simdjson_inline T&& implementation_simdjson_result_base::take_value() && noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return std::forward(this->first); +} + +template +simdjson_inline implementation_simdjson_result_base::operator T&&() && noexcept(false) { + return std::forward>(*this).take_value(); +} + +#endif // SIMDJSON_EXCEPTIONS + +template +simdjson_inline const T& implementation_simdjson_result_base::value_unsafe() const& noexcept { + return this->first; +} + +template +simdjson_inline T& implementation_simdjson_result_base::value_unsafe() & noexcept { + return this->first; +} + +template +simdjson_inline T&& implementation_simdjson_result_base::value_unsafe() && noexcept { + return std::forward(this->first); +} + +template +simdjson_inline implementation_simdjson_result_base::implementation_simdjson_result_base(T &&value, error_code error) noexcept + : first{std::forward(value)}, second{error} {} +template +simdjson_inline implementation_simdjson_result_base::implementation_simdjson_result_base(error_code error) noexcept + : implementation_simdjson_result_base(T{}, error) {} +template +simdjson_inline implementation_simdjson_result_base::implementation_simdjson_result_base(T &&value) noexcept + : implementation_simdjson_result_base(std::forward(value), SUCCESS) {} + +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_IMPLEMENTATION_SIMDJSON_RESULT_BASE_INL_H +/* end file simdjson/generic/implementation_simdjson_result_base-inl.h for rvv_vls */ +/* end file simdjson/generic/amalgamated.h for rvv_vls */ +/* including simdjson/rvv-vls/end.h: #include "simdjson/rvv-vls/end.h" */ +/* begin file simdjson/rvv-vls/end.h */ +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +/* undefining SIMDJSON_IMPLEMENTATION from "rvv_vls" */ +#undef SIMDJSON_IMPLEMENTATION +/* end file simdjson/rvv-vls/end.h */ + +#endif // SIMDJSON_RVV_VLS_H +/* end file simdjson/rvv-vls.h */ +/* including simdjson/rvv-vls/implementation.h: #include */ +/* begin file simdjson/rvv-vls/implementation.h */ +#ifndef SIMDJSON_RVV_VLS_IMPLEMENTATION_H +#define SIMDJSON_RVV_VLS_IMPLEMENTATION_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { + +/** + * @private + */ +class implementation final : public simdjson::implementation { +public: + simdjson_inline implementation() : simdjson::implementation( + "rvv_vls", + "RISC-V V extension", + 0 + ) {} + simdjson_warn_unused error_code create_dom_parser_implementation( + size_t capacity, + size_t max_length, + std::unique_ptr& dst + ) const noexcept final; + simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final; + simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final; +}; + +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_IMPLEMENTATION_H +/* end file simdjson/rvv-vls/implementation.h */ + +/* including simdjson/rvv-vls/begin.h: #include */ +/* begin file simdjson/rvv-vls/begin.h */ +/* defining SIMDJSON_IMPLEMENTATION to "rvv_vls" */ +#define SIMDJSON_IMPLEMENTATION rvv_vls +/* including simdjson/rvv-vls/base.h: #include "simdjson/rvv-vls/base.h" */ +/* begin file simdjson/rvv-vls/base.h */ +#ifndef SIMDJSON_RVV_VLS_BASE_H +#define SIMDJSON_RVV_VLS_BASE_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +/** + * RVV-VLS implementation. + */ +namespace rvv_vls { + +class implementation; + +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_BASE_H +/* end file simdjson/rvv-vls/base.h */ +/* including simdjson/rvv-vls/intrinsics.h: #include "simdjson/rvv-vls/intrinsics.h" */ +/* begin file simdjson/rvv-vls/intrinsics.h */ +#ifndef SIMDJSON_RVV_VLS_INTRINSICS_H +#define SIMDJSON_RVV_VLS_INTRINSICS_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include + +#define simdutf_vrgather_u8m1x2(tbl, idx) \ + __riscv_vcreate_v_u8m1_u8m2( \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m2_u8m1(idx, 0), \ + __riscv_vsetvlmax_e8m1()), \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m2_u8m1(idx, 1), \ + __riscv_vsetvlmax_e8m1())) + +#define simdutf_vrgather_u8m1x4(tbl, idx) \ + __riscv_vcreate_v_u8m1_u8m4( \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 0), \ + __riscv_vsetvlmax_e8m1()), \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 1), \ + __riscv_vsetvlmax_e8m1()), \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 2), \ + __riscv_vsetvlmax_e8m1()), \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 3), \ + __riscv_vsetvlmax_e8m1())) + +#if __riscv_zbc +#include +#endif + +#endif // SIMDJSON_RVV_VLS_INTRINSICS_H +/* end file simdjson/rvv-vls/intrinsics.h */ +/* including simdjson/rvv-vls/bitmanipulation.h: #include "simdjson/rvv-vls/bitmanipulation.h" */ +/* begin file simdjson/rvv-vls/bitmanipulation.h */ +#ifndef SIMDJSON_RVV_VLS_BITMANIPULATION_H +#define SIMDJSON_RVV_VLS_BITMANIPULATION_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { + +// We sometimes call trailing_zero on inputs that are zero, +// but the algorithms do not end up using the returned value. +// Sadly, sanitizers are not smart enough to figure it out. +SIMDJSON_NO_SANITIZE_UNDEFINED +// This function can be used safely even if not all bytes have been +// initialized. +// See issue https://github.com/simdjson/simdjson/issues/1965 +SIMDJSON_NO_SANITIZE_MEMORY +simdjson_inline int trailing_zeroes(uint64_t input_num) { + return __builtin_ctzll(input_num); +} + +/* result might be undefined when input_num is zero */ +simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) { + return input_num & (input_num-1); +} + +/* result might be undefined when input_num is zero */ +simdjson_inline int leading_zeroes(uint64_t input_num) { + return __builtin_clzll(input_num); +} + +simdjson_inline long long int count_ones(uint64_t input_num) { + return __builtin_popcountll(input_num); +} + +simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, + uint64_t *result) { + return __builtin_uaddll_overflow(value1, value2, + reinterpret_cast(result)); +} + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_BITMANIPULATION_H +/* end file simdjson/rvv-vls/bitmanipulation.h */ +/* including simdjson/rvv-vls/bitmask.h: #include "simdjson/rvv-vls/bitmask.h" */ +/* begin file simdjson/rvv-vls/bitmask.h */ +#ifndef SIMDJSON_RVV_VLS_BITMASK_H +#define SIMDJSON_RVV_VLS_BITMASK_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/intrinsics.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { + +// +// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered. +// +// For example, prefix_xor(00100100) == 00011100 +// +simdjson_inline uint64_t prefix_xor(uint64_t bitmask) { +#if __riscv_zbc + return __riscv_clmul_64(bitmask, ~(uint64_t)0); +#elif __riscv_zvbc + return __riscv_vmv_x(__riscv_vclmul(__riscv_vmv_s_x_u64m1(bitmask, 1), ~(uint64_t)0, 1)); +#else + bitmask ^= bitmask << 1; + bitmask ^= bitmask << 2; + bitmask ^= bitmask << 4; + bitmask ^= bitmask << 8; + bitmask ^= bitmask << 16; + bitmask ^= bitmask << 32; +#endif + return bitmask; +} + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_BITMASK_H + +/* end file simdjson/rvv-vls/bitmask.h */ +/* including simdjson/rvv-vls/simd.h: #include "simdjson/rvv-vls/simd.h" */ +/* begin file simdjson/rvv-vls/simd.h */ +#ifndef SIMDJSON_RVV_VLS_SIMD_H +#define SIMDJSON_RVV_VLS_SIMD_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/bitmanipulation.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/simdprune_tables.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace simd { + +#if __riscv_v_fixed_vlen >= 512 + static constexpr size_t VL8 = 512/8; + using vint8_t = vint8m1_t __attribute__((riscv_rvv_vector_bits(512))); + using vuint8_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(512))); + using vbool_t = vbool8_t __attribute__((riscv_rvv_vector_bits(512/8))); + using vbitmask_t = uint64_t; +#else + static constexpr size_t VL8 = __riscv_v_fixed_vlen/8; + using vint8_t = vint8m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen))); + using vuint8_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen))); + using vbool_t = vbool8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/8))); + #if __riscv_v_fixed_vlen == 128 + using vbitmask_t = uint16_t; + #elif __riscv_v_fixed_vlen == 256 + using vbitmask_t = uint32_t; + #endif +#endif + +#if __riscv_v_fixed_vlen == 128 + using vuint8x64_t = vuint8m4_t __attribute__((riscv_rvv_vector_bits(512))); + using vboolx64_t = vbool2_t __attribute__((riscv_rvv_vector_bits(512/8))); +#elif __riscv_v_fixed_vlen == 256 + using vuint8x64_t = vuint8m2_t __attribute__((riscv_rvv_vector_bits(512))); + using vboolx64_t = vbool4_t __attribute__((riscv_rvv_vector_bits(512/8))); +#else + using vuint8x64_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(512))); + using vboolx64_t = vbool8_t __attribute__((riscv_rvv_vector_bits(512/8))); +#endif + + template + struct simd8; + + // SIMD byte mask type (returned by things like eq and gt) + template<> + struct simd8 { + vbool_t value; + using bitmask_t = vbitmask_t; + static constexpr int SIZE = sizeof(value); + + simdjson_inline simd8(const vbool_t _value) : value(_value) {} + simdjson_inline simd8() : simd8(__riscv_vmclr_m_b8(VL8)) {} + simdjson_inline simd8(bool _value) : simd8(splat(_value)) {} + + simdjson_inline operator const vbool_t&() const { return value; } + simdjson_inline operator vbool_t&() { return value; } + + static simdjson_inline simd8 splat(bool _value) { + return __riscv_vreinterpret_b8(__riscv_vmv_v_x_u64m1(((uint64_t)!_value)-1, 1)); + } + + simdjson_inline vbitmask_t to_bitmask() const { +#if __riscv_v_fixed_vlen == 128 + return __riscv_vmv_x(__riscv_vreinterpret_u16m1(value)); +#elif __riscv_v_fixed_vlen == 256 + return __riscv_vmv_x(__riscv_vreinterpret_u32m1(value)); +#else + return __riscv_vmv_x(__riscv_vreinterpret_u64m1(value)); +#endif + } + + // Bit operations + simdjson_inline simd8 operator|(const simd8 other) const { return __riscv_vmor(*this, other, VL8); } + simdjson_inline simd8 operator&(const simd8 other) const { return __riscv_vmand(*this, other, VL8); } + simdjson_inline simd8 operator^(const simd8 other) const { return __riscv_vmxor(*this, other, VL8); } + simdjson_inline simd8 bit_andnot(const simd8 other) const { return __riscv_vmandn(other, *this, VL8); } + simdjson_inline simd8 operator~() const { return __riscv_vmnot(*this, VL8); } + simdjson_inline simd8& operator|=(const simd8 other) { auto this_cast = static_cast*>(this); *this_cast = *this_cast | other; return *this_cast; } + simdjson_inline simd8& operator&=(const simd8 other) { auto this_cast = static_cast*>(this); *this_cast = *this_cast & other; return *this_cast; } + simdjson_inline simd8& operator^=(const simd8 other) { auto this_cast = static_cast*>(this); *this_cast = *this_cast ^ other; return *this_cast; } + }; + + // Unsigned bytes + template<> + struct simd8 { + + vuint8_t value; + static constexpr int SIZE = sizeof(value); + + simdjson_inline simd8(const vuint8_t _value) : value(_value) {} + simdjson_inline simd8() : simd8(zero()) {} + simdjson_inline simd8(const uint8_t values[VL8]) : simd8(load(values)) {} + simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {} + simdjson_inline simd8(simd8 mask) : value(__riscv_vmerge_vxm_u8m1(zero(), -1, (vbool_t)mask, VL8)) {} + + simdjson_inline operator const vuint8_t&() const { return this->value; } + simdjson_inline operator vuint8_t&() { return this->value; } + + simdjson_inline simd8( + uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7, + uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15 + ) : simd8(vuint8_t{ + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + }) {} + + // Repeat 16 values as many times as necessary (usually for lookup tables) + simdjson_inline static simd8 repeat_16( + uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7, + uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15 + ) { + return simd8( + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + ); + } + + static simdjson_inline vuint8_t splat(uint8_t _value) { return __riscv_vmv_v_x_u8m1(_value, VL8); } + static simdjson_inline vuint8_t zero() { return splat(0); } + static simdjson_inline vuint8_t load(const uint8_t values[VL8]) { return __riscv_vle8_v_u8m1(values, VL8); } + + // Bit operations + simdjson_inline simd8 operator|(const simd8 other) const { return __riscv_vor_vv_u8m1( value, other, VL8); } + simdjson_inline simd8 operator&(const simd8 other) const { return __riscv_vand_vv_u8m1( value, other, VL8); } + simdjson_inline simd8 operator^(const simd8 other) const { return __riscv_vxor_vv_u8m1( value, other, VL8); } + simdjson_inline simd8 operator~() const { return __riscv_vnot_v_u8m1(value, VL8); } +#if __riscv_zvbb + simdjson_inline simd8 bit_andnot(const simd8 other) const { return __riscv_vandn_vv_u8m1(other, value, VL8); } +#else + simdjson_inline simd8 bit_andnot(const simd8 other) const { return other & ~*this; } +#endif + simdjson_inline simd8& operator|=(const simd8 other) { value = *this | other; return *this; } + simdjson_inline simd8& operator&=(const simd8 other) { value = *this & other; return *this; } + simdjson_inline simd8& operator^=(const simd8 other) { value = *this ^ other; return *this; } + + simdjson_inline simd8 operator==(const simd8 other) const { return __riscv_vmseq(value, other, VL8); } + simdjson_inline simd8 operator==(uint8_t other) const { return __riscv_vmseq(value, other, VL8); } + + template + simdjson_inline simd8 prev(const simd8 prev_chunk) const { + return __riscv_vslideup(__riscv_vslidedown(prev_chunk, VL8-N, VL8), value, N, VL8); + } + + // Store to array + simdjson_inline void store(uint8_t dst[VL8]) const { return __riscv_vse8(dst, value, VL8); } + + // Saturated math + simdjson_inline simd8 saturating_add(const simd8 other) const { return __riscv_vsaddu(value, other, VL8); } + simdjson_inline simd8 saturating_sub(const simd8 other) const { return __riscv_vssubu(value, other, VL8); } + + // Addition/subtraction are the same for signed and unsigned + simdjson_inline simd8 operator+(const simd8 other) const { return __riscv_vadd(value, other, VL8); } + simdjson_inline simd8 operator-(const simd8 other) const { return __riscv_vsub(value, other, VL8); } + simdjson_inline simd8& operator+=(const simd8 other) { value = *this + other; return *this; } + simdjson_inline simd8& operator-=(const simd8 other) { value = *this - other; return *this; } + + // Order-specific operations + simdjson_inline simd8 operator<=(const simd8 other) const { return __riscv_vmsleu(value, other, VL8); } + simdjson_inline simd8 operator>=(const simd8 other) const { return __riscv_vmsgeu(value, other, VL8); } + simdjson_inline simd8 operator<(const simd8 other) const { return __riscv_vmsltu(value, other, VL8); } + simdjson_inline simd8 operator>(const simd8 other) const { return __riscv_vmsgtu(value, other, VL8); } + + // Same as >, but instead of guaranteeing all 1's == true, false = 0 and true = nonzero. + simdjson_inline simd8 gt_bits(const simd8 other) const { return simd8(*this > other); } + // Same as <, but instead of guaranteeing all 1's == true, false = 0 and true = nonzero. + simdjson_inline simd8 lt_bits(const simd8 other) const { return simd8(*this < other); } + + // Bit-specific operations + simdjson_inline bool any_bits_set_anywhere() const { + return __riscv_vfirst(__riscv_vmsne(value, 0, VL8), VL8) >= 0; + } + simdjson_inline bool any_bits_set_anywhere(simd8 bits) const { return (*this & bits).any_bits_set_anywhere(); } + template + simdjson_inline simd8 shr() const { return __riscv_vsrl(value, N, VL8); } + template + simdjson_inline simd8 shl() const { return __riscv_vsll(value, N, VL8); } + + + // Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values) + template + simdjson_inline simd8 lookup_16(simd8 lookup_table) const { + return __riscv_vrgather(lookup_table, value, VL8); + } + + // compress inactive elements, to match AVX-512 behavior + template + simdjson_inline void compress(vbitmask_t mask, L * output) const { + mask = (vbitmask_t)~mask; +#if __riscv_v_fixed_vlen == 128 + vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u16m1(mask, 1)); +#elif __riscv_v_fixed_vlen == 256 + vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u32m1(mask, 1)); +#else + vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u64m1(mask, 1)); +#endif + __riscv_vse8_v_u8m1(output, __riscv_vcompress(value, m, VL8), count_ones(mask)); + } + + template + simdjson_inline simd8 lookup_16( + L replace0, L replace1, L replace2, L replace3, + L replace4, L replace5, L replace6, L replace7, + L replace8, L replace9, L replace10, L replace11, + L replace12, L replace13, L replace14, L replace15) const { + return lookup_16(simd8::repeat_16( + replace0, replace1, replace2, replace3, + replace4, replace5, replace6, replace7, + replace8, replace9, replace10, replace11, + replace12, replace13, replace14, replace15 + )); + } + }; + + // Signed bytes + template<> + struct simd8 { + vint8_t value; + static constexpr int SIZE = sizeof(value); + + simdjson_inline simd8(const vint8_t _value) : value(_value) {} + simdjson_inline simd8() : simd8(zero()) {} + simdjson_inline simd8(const int8_t values[VL8]) : simd8(load(values)) {} + simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {} + + simdjson_inline operator const vint8_t&() const { return this->value; } + simdjson_inline operator vint8_t&() { return this->value; } + + simdjson_inline simd8( + int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7, + int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15 + ) : simd8(vint8_t{ + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + }) {} + + // Repeat 16 values as many times as necessary (usually for lookup tables) + simdjson_inline static simd8 repeat_16( + int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7, + int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15 + ) { + return simd8( + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + ); + } + + static simdjson_inline vint8_t splat(int8_t _value) { return __riscv_vmv_v_x_i8m1(_value, VL8); } + static simdjson_inline vint8_t zero() { return splat(0); } + static simdjson_inline vint8_t load(const int8_t values[VL8]) { return __riscv_vle8_v_i8m1(values, VL8); } + + + simdjson_inline void store(int8_t dst[VL8]) const { return __riscv_vse8(dst, value, VL8); } + + // Explicit conversion to/from unsigned + simdjson_inline explicit simd8(const vuint8_t other): simd8(__riscv_vreinterpret_i8m1(other)) {} + simdjson_inline explicit operator simd8() const { return __riscv_vreinterpret_u8m1(value); } + + // Math + simdjson_inline simd8 operator+(const simd8 other) const { return __riscv_vadd(value, other, VL8); } + simdjson_inline simd8 operator-(const simd8 other) const { return __riscv_vsub(value, other, VL8); } + simdjson_inline simd8& operator+=(const simd8 other) { value = *this + other; return *this; } + simdjson_inline simd8& operator-=(const simd8 other) { value = *this - other; return *this; } + + // Order-sensitive comparisons + simdjson_inline simd8 max_val( const simd8 other) const { return __riscv_vmax( value, other, VL8); } + simdjson_inline simd8 min_val( const simd8 other) const { return __riscv_vmin( value, other, VL8); } + simdjson_inline simd8 operator>( const simd8 other) const { return __riscv_vmsgt(value, other, VL8); } + simdjson_inline simd8 operator<( const simd8 other) const { return __riscv_vmslt(value, other, VL8); } + simdjson_inline simd8 operator==(const simd8 other) const { return __riscv_vmseq(value, other, VL8); } + + template + simdjson_inline simd8 prev(const simd8 prev_chunk) const { + return __riscv_vslideup(__riscv_vslidedown(prev_chunk, VL8-N, VL8), value, N, VL8); + } + + // Perform a lookup assuming no value is larger than 16 + template + simdjson_inline simd8 lookup_16(simd8 lookup_table) const { + return __riscv_vrgather(lookup_table, value, VL8); + } + template + simdjson_inline simd8 lookup_16( + L replace0, L replace1, L replace2, L replace3, + L replace4, L replace5, L replace6, L replace7, + L replace8, L replace9, L replace10, L replace11, + L replace12, L replace13, L replace14, L replace15) const { + return lookup_16(simd8::repeat_16( + replace0, replace1, replace2, replace3, + replace4, replace5, replace6, replace7, + replace8, replace9, replace10, replace11, + replace12, replace13, replace14, replace15 + )); + } + }; + + template + struct simd8x64; + template<> + struct simd8x64 { + static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); + vuint8x64_t value; + +#if __riscv_v_fixed_vlen >= 512 + template simd8 get() const { return value; } +#else + template simd8 get() const { return __riscv_vget_u8m1(value, idx); } +#endif + + simdjson_inline operator const vuint8x64_t&() const { return this->value; } + simdjson_inline operator vuint8x64_t&() { return this->value; } + + simd8x64(const simd8x64& o) = delete; // no copy allowed + simd8x64& operator=(const simd8& other) = delete; // no assignment allowed + simd8x64() = delete; // no default constructor allowed + +#if __riscv_v_fixed_vlen == 128 + simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m4(ptr, n)) {} +#elif __riscv_v_fixed_vlen == 256 + simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m2(ptr, n)) {} +#else + simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m1(ptr, n)) {} +#endif + + simdjson_inline void store(uint8_t ptr[64]) const { + __riscv_vse8(ptr, value, 64); + } + + simdjson_inline bool is_ascii() const { +#if __riscv_v_fixed_vlen == 128 + return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m4(value), 0, 64), 64) < 0; +#elif __riscv_v_fixed_vlen == 256 + return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m2(value), 0, 64), 64) < 0; +#else + return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m1(value), 0, 64), 64) < 0; +#endif + } + + // compress inactive elements, to match AVX-512 behavior + simdjson_inline uint64_t compress(uint64_t mask, uint8_t * output) const { + mask = ~mask; +#if __riscv_v_fixed_vlen == 128 + vboolx64_t m = __riscv_vreinterpret_b2(__riscv_vmv_s_x_u64m1(mask, 1)); +#elif __riscv_v_fixed_vlen == 256 + vboolx64_t m = __riscv_vreinterpret_b4(__riscv_vmv_s_x_u64m1(mask, 1)); +#else + vboolx64_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u64m1(mask, 1)); +#endif + size_t cnt = count_ones(mask); + __riscv_vse8(output, __riscv_vcompress(value, m, 64), cnt); + return cnt; + } + + simdjson_inline uint64_t eq(const uint8_t m) const { + return __riscv_vmv_x(__riscv_vreinterpret_u64m1(__riscv_vmseq(value, m, 64))); + } + + simdjson_inline uint64_t lteq(const uint8_t m) const { + return __riscv_vmv_x(__riscv_vreinterpret_u64m1(__riscv_vmsleu(value, m, 64))); + } + }; // struct simd8x64 + +} // namespace simd +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_SIMD_H +/* end file simdjson/rvv-vls/simd.h */ +/* including simdjson/rvv-vls/stringparsing_defs.h: #include "simdjson/rvv-vls/stringparsing_defs.h" */ +/* begin file simdjson/rvv-vls/stringparsing_defs.h */ +#ifndef SIMDJSON_RVV_VLS_STRINGPARSING_DEFS_H +#define SIMDJSON_RVV_VLS_STRINGPARSING_DEFS_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { + +using namespace simd; + +// Holds backslashes and quotes locations. +struct backslash_and_quote { +public: + static constexpr uint64_t BYTES_PROCESSED = sizeof(simd8); + simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + + simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; } + simdjson_inline bool has_backslash() { return ((quote_bits - 1) & bs_bits) != 0; } + simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); } + simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); } + + uint64_t bs_bits; + uint64_t quote_bits; +}; // struct backslash_and_quote + +simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) { + static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes"); + simd8 v(src); + v.store(dst); + return { (v == '\\').to_bitmask(), (v == '"').to_bitmask() }; +} + +struct escaping { + static constexpr uint64_t BYTES_PROCESSED = sizeof(simd8); + simdjson_inline static escaping copy_and_find(const uint8_t *src, uint8_t *dst); + + simdjson_inline bool has_escape() { return escape_bits != 0; } + simdjson_inline int escape_index() { return trailing_zeroes(escape_bits) / 4; } + + uint64_t escape_bits; +}; // struct escaping + +simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *dst) { + static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "escaping finder must process fewer than SIMDJSON_PADDING bytes"); + simd8 v(src); + v.store(dst); + return { ((v == '"') | (v == '\\') | (v == 32)).to_bitmask() }; +} + + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_STRINGPARSING_DEFS_H +/* end file simdjson/rvv-vls/stringparsing_defs.h */ +/* including simdjson/rvv-vls/numberparsing_defs.h: #include "simdjson/rvv-vls/numberparsing_defs.h" */ +/* begin file simdjson/rvv-vls/numberparsing_defs.h */ +#ifndef SIMDJSON_RVV_VLS_NUMBERPARSING_DEFS_H +#define SIMDJSON_RVV_VLS_NUMBERPARSING_DEFS_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include + +#ifdef JSON_TEST_NUMBERS // for unit testing +void found_invalid_number(const uint8_t *buf); +void found_integer(int64_t result, const uint8_t *buf); +void found_unsigned_integer(uint64_t result, const uint8_t *buf); +void found_float(double result, const uint8_t *buf); +#endif + +namespace simdjson { +namespace rvv_vls { +namespace numberparsing { + +// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/ +/** @private */ +static simdjson_inline uint32_t parse_eight_digits_unrolled(const char *chars) { + uint64_t val; +#if __riscv_misaligned_fast + memcpy(&val, chars, sizeof(uint64_t)); +#else + val = __riscv_vmv_x(__riscv_vreinterpret_u64m1(__riscv_vlmul_ext_u8m1(__riscv_vle8_v_u8mf2((uint8_t*)chars, 8)))); +#endif + val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8; + val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16; + return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32); +} + +/** @private */ +static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) { + return parse_eight_digits_unrolled(reinterpret_cast(chars)); +} + +/** @private */ +simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) { + internal::value128 answer; + __uint128_t r = (static_cast<__uint128_t>(value1)) * value2; + answer.low = uint64_t(r); + answer.high = uint64_t(r >> 64); + return answer; +} + +} // namespace numberparsing +} // namespace rvv_vls +} // namespace simdjson + +#define SIMDJSON_SWAR_NUMBER_PARSING 1 + +#endif // SIMDJSON_RVV_VLS_NUMBERPARSING_DEFS_H +/* end file simdjson/rvv-vls/numberparsing_defs.h */ + +#define SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT 1 +/* end file simdjson/rvv-vls/begin.h */ +/* including simdjson/rvv-vls/simd.h: #include */ +/* begin file simdjson/rvv-vls/simd.h */ +#ifndef SIMDJSON_RVV_VLS_SIMD_H +#define SIMDJSON_RVV_VLS_SIMD_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/bitmanipulation.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/simdprune_tables.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace simd { + +#if __riscv_v_fixed_vlen >= 512 + static constexpr size_t VL8 = 512/8; + using vint8_t = vint8m1_t __attribute__((riscv_rvv_vector_bits(512))); + using vuint8_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(512))); + using vbool_t = vbool8_t __attribute__((riscv_rvv_vector_bits(512/8))); + using vbitmask_t = uint64_t; +#else + static constexpr size_t VL8 = __riscv_v_fixed_vlen/8; + using vint8_t = vint8m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen))); + using vuint8_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen))); + using vbool_t = vbool8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/8))); + #if __riscv_v_fixed_vlen == 128 + using vbitmask_t = uint16_t; + #elif __riscv_v_fixed_vlen == 256 + using vbitmask_t = uint32_t; + #endif +#endif + +#if __riscv_v_fixed_vlen == 128 + using vuint8x64_t = vuint8m4_t __attribute__((riscv_rvv_vector_bits(512))); + using vboolx64_t = vbool2_t __attribute__((riscv_rvv_vector_bits(512/8))); +#elif __riscv_v_fixed_vlen == 256 + using vuint8x64_t = vuint8m2_t __attribute__((riscv_rvv_vector_bits(512))); + using vboolx64_t = vbool4_t __attribute__((riscv_rvv_vector_bits(512/8))); +#else + using vuint8x64_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(512))); + using vboolx64_t = vbool8_t __attribute__((riscv_rvv_vector_bits(512/8))); +#endif + + template + struct simd8; + + // SIMD byte mask type (returned by things like eq and gt) + template<> + struct simd8 { + vbool_t value; + using bitmask_t = vbitmask_t; + static constexpr int SIZE = sizeof(value); + + simdjson_inline simd8(const vbool_t _value) : value(_value) {} + simdjson_inline simd8() : simd8(__riscv_vmclr_m_b8(VL8)) {} + simdjson_inline simd8(bool _value) : simd8(splat(_value)) {} + + simdjson_inline operator const vbool_t&() const { return value; } + simdjson_inline operator vbool_t&() { return value; } + + static simdjson_inline simd8 splat(bool _value) { + return __riscv_vreinterpret_b8(__riscv_vmv_v_x_u64m1(((uint64_t)!_value)-1, 1)); + } + + simdjson_inline vbitmask_t to_bitmask() const { +#if __riscv_v_fixed_vlen == 128 + return __riscv_vmv_x(__riscv_vreinterpret_u16m1(value)); +#elif __riscv_v_fixed_vlen == 256 + return __riscv_vmv_x(__riscv_vreinterpret_u32m1(value)); +#else + return __riscv_vmv_x(__riscv_vreinterpret_u64m1(value)); +#endif + } + + // Bit operations + simdjson_inline simd8 operator|(const simd8 other) const { return __riscv_vmor(*this, other, VL8); } + simdjson_inline simd8 operator&(const simd8 other) const { return __riscv_vmand(*this, other, VL8); } + simdjson_inline simd8 operator^(const simd8 other) const { return __riscv_vmxor(*this, other, VL8); } + simdjson_inline simd8 bit_andnot(const simd8 other) const { return __riscv_vmandn(other, *this, VL8); } + simdjson_inline simd8 operator~() const { return __riscv_vmnot(*this, VL8); } + simdjson_inline simd8& operator|=(const simd8 other) { auto this_cast = static_cast*>(this); *this_cast = *this_cast | other; return *this_cast; } + simdjson_inline simd8& operator&=(const simd8 other) { auto this_cast = static_cast*>(this); *this_cast = *this_cast & other; return *this_cast; } + simdjson_inline simd8& operator^=(const simd8 other) { auto this_cast = static_cast*>(this); *this_cast = *this_cast ^ other; return *this_cast; } + }; + + // Unsigned bytes + template<> + struct simd8 { + + vuint8_t value; + static constexpr int SIZE = sizeof(value); + + simdjson_inline simd8(const vuint8_t _value) : value(_value) {} + simdjson_inline simd8() : simd8(zero()) {} + simdjson_inline simd8(const uint8_t values[VL8]) : simd8(load(values)) {} + simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {} + simdjson_inline simd8(simd8 mask) : value(__riscv_vmerge_vxm_u8m1(zero(), -1, (vbool_t)mask, VL8)) {} + + simdjson_inline operator const vuint8_t&() const { return this->value; } + simdjson_inline operator vuint8_t&() { return this->value; } + + simdjson_inline simd8( + uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7, + uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15 + ) : simd8(vuint8_t{ + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + }) {} + + // Repeat 16 values as many times as necessary (usually for lookup tables) + simdjson_inline static simd8 repeat_16( + uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7, + uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15 + ) { + return simd8( + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + ); + } + + static simdjson_inline vuint8_t splat(uint8_t _value) { return __riscv_vmv_v_x_u8m1(_value, VL8); } + static simdjson_inline vuint8_t zero() { return splat(0); } + static simdjson_inline vuint8_t load(const uint8_t values[VL8]) { return __riscv_vle8_v_u8m1(values, VL8); } + + // Bit operations + simdjson_inline simd8 operator|(const simd8 other) const { return __riscv_vor_vv_u8m1( value, other, VL8); } + simdjson_inline simd8 operator&(const simd8 other) const { return __riscv_vand_vv_u8m1( value, other, VL8); } + simdjson_inline simd8 operator^(const simd8 other) const { return __riscv_vxor_vv_u8m1( value, other, VL8); } + simdjson_inline simd8 operator~() const { return __riscv_vnot_v_u8m1(value, VL8); } +#if __riscv_zvbb + simdjson_inline simd8 bit_andnot(const simd8 other) const { return __riscv_vandn_vv_u8m1(other, value, VL8); } +#else + simdjson_inline simd8 bit_andnot(const simd8 other) const { return other & ~*this; } +#endif + simdjson_inline simd8& operator|=(const simd8 other) { value = *this | other; return *this; } + simdjson_inline simd8& operator&=(const simd8 other) { value = *this & other; return *this; } + simdjson_inline simd8& operator^=(const simd8 other) { value = *this ^ other; return *this; } + + simdjson_inline simd8 operator==(const simd8 other) const { return __riscv_vmseq(value, other, VL8); } + simdjson_inline simd8 operator==(uint8_t other) const { return __riscv_vmseq(value, other, VL8); } + + template + simdjson_inline simd8 prev(const simd8 prev_chunk) const { + return __riscv_vslideup(__riscv_vslidedown(prev_chunk, VL8-N, VL8), value, N, VL8); + } + + // Store to array + simdjson_inline void store(uint8_t dst[VL8]) const { return __riscv_vse8(dst, value, VL8); } + + // Saturated math + simdjson_inline simd8 saturating_add(const simd8 other) const { return __riscv_vsaddu(value, other, VL8); } + simdjson_inline simd8 saturating_sub(const simd8 other) const { return __riscv_vssubu(value, other, VL8); } + + // Addition/subtraction are the same for signed and unsigned + simdjson_inline simd8 operator+(const simd8 other) const { return __riscv_vadd(value, other, VL8); } + simdjson_inline simd8 operator-(const simd8 other) const { return __riscv_vsub(value, other, VL8); } + simdjson_inline simd8& operator+=(const simd8 other) { value = *this + other; return *this; } + simdjson_inline simd8& operator-=(const simd8 other) { value = *this - other; return *this; } + + // Order-specific operations + simdjson_inline simd8 operator<=(const simd8 other) const { return __riscv_vmsleu(value, other, VL8); } + simdjson_inline simd8 operator>=(const simd8 other) const { return __riscv_vmsgeu(value, other, VL8); } + simdjson_inline simd8 operator<(const simd8 other) const { return __riscv_vmsltu(value, other, VL8); } + simdjson_inline simd8 operator>(const simd8 other) const { return __riscv_vmsgtu(value, other, VL8); } + + // Same as >, but instead of guaranteeing all 1's == true, false = 0 and true = nonzero. + simdjson_inline simd8 gt_bits(const simd8 other) const { return simd8(*this > other); } + // Same as <, but instead of guaranteeing all 1's == true, false = 0 and true = nonzero. + simdjson_inline simd8 lt_bits(const simd8 other) const { return simd8(*this < other); } + + // Bit-specific operations + simdjson_inline bool any_bits_set_anywhere() const { + return __riscv_vfirst(__riscv_vmsne(value, 0, VL8), VL8) >= 0; + } + simdjson_inline bool any_bits_set_anywhere(simd8 bits) const { return (*this & bits).any_bits_set_anywhere(); } + template + simdjson_inline simd8 shr() const { return __riscv_vsrl(value, N, VL8); } + template + simdjson_inline simd8 shl() const { return __riscv_vsll(value, N, VL8); } + + + // Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values) + template + simdjson_inline simd8 lookup_16(simd8 lookup_table) const { + return __riscv_vrgather(lookup_table, value, VL8); + } + + // compress inactive elements, to match AVX-512 behavior + template + simdjson_inline void compress(vbitmask_t mask, L * output) const { + mask = (vbitmask_t)~mask; +#if __riscv_v_fixed_vlen == 128 + vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u16m1(mask, 1)); +#elif __riscv_v_fixed_vlen == 256 + vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u32m1(mask, 1)); +#else + vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u64m1(mask, 1)); +#endif + __riscv_vse8_v_u8m1(output, __riscv_vcompress(value, m, VL8), count_ones(mask)); + } + + template + simdjson_inline simd8 lookup_16( + L replace0, L replace1, L replace2, L replace3, + L replace4, L replace5, L replace6, L replace7, + L replace8, L replace9, L replace10, L replace11, + L replace12, L replace13, L replace14, L replace15) const { + return lookup_16(simd8::repeat_16( + replace0, replace1, replace2, replace3, + replace4, replace5, replace6, replace7, + replace8, replace9, replace10, replace11, + replace12, replace13, replace14, replace15 + )); + } + }; + + // Signed bytes + template<> + struct simd8 { + vint8_t value; + static constexpr int SIZE = sizeof(value); + + simdjson_inline simd8(const vint8_t _value) : value(_value) {} + simdjson_inline simd8() : simd8(zero()) {} + simdjson_inline simd8(const int8_t values[VL8]) : simd8(load(values)) {} + simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {} + + simdjson_inline operator const vint8_t&() const { return this->value; } + simdjson_inline operator vint8_t&() { return this->value; } + + simdjson_inline simd8( + int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7, + int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15 + ) : simd8(vint8_t{ + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + }) {} + + // Repeat 16 values as many times as necessary (usually for lookup tables) + simdjson_inline static simd8 repeat_16( + int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7, + int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15 + ) { + return simd8( + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + ); + } + + static simdjson_inline vint8_t splat(int8_t _value) { return __riscv_vmv_v_x_i8m1(_value, VL8); } + static simdjson_inline vint8_t zero() { return splat(0); } + static simdjson_inline vint8_t load(const int8_t values[VL8]) { return __riscv_vle8_v_i8m1(values, VL8); } + + + simdjson_inline void store(int8_t dst[VL8]) const { return __riscv_vse8(dst, value, VL8); } + + // Explicit conversion to/from unsigned + simdjson_inline explicit simd8(const vuint8_t other): simd8(__riscv_vreinterpret_i8m1(other)) {} + simdjson_inline explicit operator simd8() const { return __riscv_vreinterpret_u8m1(value); } + + // Math + simdjson_inline simd8 operator+(const simd8 other) const { return __riscv_vadd(value, other, VL8); } + simdjson_inline simd8 operator-(const simd8 other) const { return __riscv_vsub(value, other, VL8); } + simdjson_inline simd8& operator+=(const simd8 other) { value = *this + other; return *this; } + simdjson_inline simd8& operator-=(const simd8 other) { value = *this - other; return *this; } + + // Order-sensitive comparisons + simdjson_inline simd8 max_val( const simd8 other) const { return __riscv_vmax( value, other, VL8); } + simdjson_inline simd8 min_val( const simd8 other) const { return __riscv_vmin( value, other, VL8); } + simdjson_inline simd8 operator>( const simd8 other) const { return __riscv_vmsgt(value, other, VL8); } + simdjson_inline simd8 operator<( const simd8 other) const { return __riscv_vmslt(value, other, VL8); } + simdjson_inline simd8 operator==(const simd8 other) const { return __riscv_vmseq(value, other, VL8); } + + template + simdjson_inline simd8 prev(const simd8 prev_chunk) const { + return __riscv_vslideup(__riscv_vslidedown(prev_chunk, VL8-N, VL8), value, N, VL8); + } + + // Perform a lookup assuming no value is larger than 16 + template + simdjson_inline simd8 lookup_16(simd8 lookup_table) const { + return __riscv_vrgather(lookup_table, value, VL8); + } + template + simdjson_inline simd8 lookup_16( + L replace0, L replace1, L replace2, L replace3, + L replace4, L replace5, L replace6, L replace7, + L replace8, L replace9, L replace10, L replace11, + L replace12, L replace13, L replace14, L replace15) const { + return lookup_16(simd8::repeat_16( + replace0, replace1, replace2, replace3, + replace4, replace5, replace6, replace7, + replace8, replace9, replace10, replace11, + replace12, replace13, replace14, replace15 + )); + } + }; + + template + struct simd8x64; + template<> + struct simd8x64 { + static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); + vuint8x64_t value; + +#if __riscv_v_fixed_vlen >= 512 + template simd8 get() const { return value; } +#else + template simd8 get() const { return __riscv_vget_u8m1(value, idx); } +#endif + + simdjson_inline operator const vuint8x64_t&() const { return this->value; } + simdjson_inline operator vuint8x64_t&() { return this->value; } + + simd8x64(const simd8x64& o) = delete; // no copy allowed + simd8x64& operator=(const simd8& other) = delete; // no assignment allowed + simd8x64() = delete; // no default constructor allowed + +#if __riscv_v_fixed_vlen == 128 + simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m4(ptr, n)) {} +#elif __riscv_v_fixed_vlen == 256 + simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m2(ptr, n)) {} +#else + simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m1(ptr, n)) {} +#endif + + simdjson_inline void store(uint8_t ptr[64]) const { + __riscv_vse8(ptr, value, 64); + } + + simdjson_inline bool is_ascii() const { +#if __riscv_v_fixed_vlen == 128 + return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m4(value), 0, 64), 64) < 0; +#elif __riscv_v_fixed_vlen == 256 + return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m2(value), 0, 64), 64) < 0; +#else + return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m1(value), 0, 64), 64) < 0; +#endif + } + + // compress inactive elements, to match AVX-512 behavior + simdjson_inline uint64_t compress(uint64_t mask, uint8_t * output) const { + mask = ~mask; +#if __riscv_v_fixed_vlen == 128 + vboolx64_t m = __riscv_vreinterpret_b2(__riscv_vmv_s_x_u64m1(mask, 1)); +#elif __riscv_v_fixed_vlen == 256 + vboolx64_t m = __riscv_vreinterpret_b4(__riscv_vmv_s_x_u64m1(mask, 1)); +#else + vboolx64_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u64m1(mask, 1)); +#endif + size_t cnt = count_ones(mask); + __riscv_vse8(output, __riscv_vcompress(value, m, 64), cnt); + return cnt; + } + + simdjson_inline uint64_t eq(const uint8_t m) const { + return __riscv_vmv_x(__riscv_vreinterpret_u64m1(__riscv_vmseq(value, m, 64))); + } + + simdjson_inline uint64_t lteq(const uint8_t m) const { + return __riscv_vmv_x(__riscv_vreinterpret_u64m1(__riscv_vmsleu(value, m, 64))); + } + }; // struct simd8x64 + +} // namespace simd +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_SIMD_H +/* end file simdjson/rvv-vls/simd.h */ +/* including generic/amalgamated.h for rvv_vls: #include */ +/* begin file generic/amalgamated.h for rvv_vls */ +#if defined(SIMDJSON_CONDITIONAL_INCLUDE) && !defined(SIMDJSON_SRC_GENERIC_DEPENDENCIES_H) +#error generic/dependencies.h must be included before generic/amalgamated.h! +#endif + +/* including generic/base.h for rvv_vls: #include */ +/* begin file generic/base.h for rvv_vls */ +#ifndef SIMDJSON_SRC_GENERIC_BASE_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_SRC_GENERIC_BASE_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { + +struct json_character_block; + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_SRC_GENERIC_BASE_H +/* end file generic/base.h for rvv_vls */ +/* including generic/dom_parser_implementation.h for rvv_vls: #include */ +/* begin file generic/dom_parser_implementation.h for rvv_vls */ +#ifndef SIMDJSON_SRC_GENERIC_DOM_PARSER_IMPLEMENTATION_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_SRC_GENERIC_DOM_PARSER_IMPLEMENTATION_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +// Interface a dom parser implementation must fulfill +namespace simdjson { +namespace rvv_vls { +namespace { + +simdjson_inline simd8 must_be_2_3_continuation(const simd8 prev2, const simd8 prev3); +simdjson_inline bool is_ascii(const simd8x64& input); + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_SRC_GENERIC_DOM_PARSER_IMPLEMENTATION_H +/* end file generic/dom_parser_implementation.h for rvv_vls */ +/* including generic/json_character_block.h for rvv_vls: #include */ +/* begin file generic/json_character_block.h for rvv_vls */ +#ifndef SIMDJSON_SRC_GENERIC_JSON_CHARACTER_BLOCK_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_SRC_GENERIC_JSON_CHARACTER_BLOCK_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { + +struct json_character_block { + static simdjson_inline json_character_block classify(const simd::simd8x64& in); + + simdjson_inline uint64_t whitespace() const noexcept { return _whitespace; } + simdjson_inline uint64_t op() const noexcept { return _op; } + simdjson_inline uint64_t scalar() const noexcept { return ~(op() | whitespace()); } + + uint64_t _whitespace; + uint64_t _op; +}; + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_SRC_GENERIC_JSON_CHARACTER_BLOCK_H +/* end file generic/json_character_block.h for rvv_vls */ +/* end file generic/amalgamated.h for rvv_vls */ +/* including generic/stage1/amalgamated.h for rvv_vls: #include */ +/* begin file generic/stage1/amalgamated.h for rvv_vls */ +// Stuff other things depend on +/* including generic/stage1/base.h for rvv_vls: #include */ +/* begin file generic/stage1/base.h for rvv_vls */ +#ifndef SIMDJSON_SRC_GENERIC_STAGE1_BASE_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_SRC_GENERIC_STAGE1_BASE_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace stage1 { + +class bit_indexer; +template +struct buf_block_reader; +struct json_block; +class json_minifier; +class json_scanner; +struct json_string_block; +class json_string_scanner; +class json_structural_indexer; + +} // namespace stage1 + +namespace utf8_validation { +struct utf8_checker; +} // namespace utf8_validation + +using utf8_validation::utf8_checker; + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_SRC_GENERIC_STAGE1_BASE_H +/* end file generic/stage1/base.h for rvv_vls */ +/* including generic/stage1/buf_block_reader.h for rvv_vls: #include */ +/* begin file generic/stage1/buf_block_reader.h for rvv_vls */ +#ifndef SIMDJSON_SRC_GENERIC_STAGE1_BUF_BLOCK_READER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_SRC_GENERIC_STAGE1_BUF_BLOCK_READER_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace stage1 { + +// Walks through a buffer in block-sized increments, loading the last part with spaces +template +struct buf_block_reader { +public: + simdjson_inline buf_block_reader(const uint8_t *_buf, size_t _len); + simdjson_inline size_t block_index(); + simdjson_inline bool has_full_block() const; + simdjson_inline const uint8_t *full_block() const; + /** + * Get the last block, padded with spaces. + * + * There will always be a last block, with at least 1 byte, unless len == 0 (in which case this + * function fills the buffer with spaces and returns 0. In particular, if len == STEP_SIZE there + * will be 0 full_blocks and 1 remainder block with STEP_SIZE bytes and no spaces for padding. + * + * @return the number of effective characters in the last block. + */ + simdjson_inline size_t get_remainder(uint8_t *dst) const; + simdjson_inline void advance(); +private: + const uint8_t *buf; + const size_t len; + const size_t lenminusstep; + size_t idx; +}; + +// Routines to print masks and text for debugging bitmask operations +simdjson_unused static char * format_input_text_64(const uint8_t *text) { + static char buf[sizeof(simd8x64) + 1]; + for (size_t i=0; i); i++) { + buf[i] = int8_t(text[i]) < ' ' ? '_' : int8_t(text[i]); + } + buf[sizeof(simd8x64)] = '\0'; + return buf; +} + +// Routines to print masks and text for debugging bitmask operations +simdjson_unused static char * format_input_text(const simd8x64& in) { + static char buf[sizeof(simd8x64) + 1]; + in.store(reinterpret_cast(buf)); + for (size_t i=0; i); i++) { + if (buf[i] < ' ') { buf[i] = '_'; } + } + buf[sizeof(simd8x64)] = '\0'; + return buf; +} + +simdjson_unused static char * format_input_text(const simd8x64& in, uint64_t mask) { + static char buf[sizeof(simd8x64) + 1]; + in.store(reinterpret_cast(buf)); + for (size_t i=0; i); i++) { + if (buf[i] <= ' ') { buf[i] = '_'; } + if (!(mask & (size_t(1) << i))) { buf[i] = ' '; } + } + buf[sizeof(simd8x64)] = '\0'; + return buf; +} + +simdjson_unused static char * format_mask(uint64_t mask) { + static char buf[sizeof(simd8x64) + 1]; + for (size_t i=0; i<64; i++) { + buf[i] = (mask & (size_t(1) << i)) ? 'X' : ' '; + } + buf[64] = '\0'; + return buf; +} + +template +simdjson_inline buf_block_reader::buf_block_reader(const uint8_t *_buf, size_t _len) : buf{_buf}, len{_len}, lenminusstep{len < STEP_SIZE ? 0 : len - STEP_SIZE}, idx{0} {} + +template +simdjson_inline size_t buf_block_reader::block_index() { return idx; } + +template +simdjson_inline bool buf_block_reader::has_full_block() const { + return idx < lenminusstep; +} + +template +simdjson_inline const uint8_t *buf_block_reader::full_block() const { + return &buf[idx]; +} + +template +simdjson_inline size_t buf_block_reader::get_remainder(uint8_t *dst) const { + if(len == idx) { return 0; } // memcpy(dst, null, 0) will trigger an error with some sanitizers + std::memset(dst, 0x20, STEP_SIZE); // std::memset STEP_SIZE because it's more efficient to write out 8 or 16 bytes at once. + std::memcpy(dst, buf + idx, len - idx); + return len - idx; +} + +template +simdjson_inline void buf_block_reader::advance() { + idx += STEP_SIZE; +} + +} // namespace stage1 +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_SRC_GENERIC_STAGE1_BUF_BLOCK_READER_H +/* end file generic/stage1/buf_block_reader.h for rvv_vls */ +/* including generic/stage1/json_escape_scanner.h for rvv_vls: #include */ +/* begin file generic/stage1/json_escape_scanner.h for rvv_vls */ +#ifndef SIMDJSON_SRC_GENERIC_STAGE1_JSON_ESCAPE_SCANNER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_SRC_GENERIC_STAGE1_JSON_ESCAPE_SCANNER_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace stage1 { + +/** + * Scans for escape characters in JSON, taking care with multiple backslashes (\\n vs. \n). + */ +struct json_escape_scanner { + /** The actual escape characters (the backslashes themselves). */ + uint64_t next_is_escaped = 0ULL; + + struct escaped_and_escape { + /** + * Mask of escaped characters. + * + * ``` + * \n \\n \\\n \\\\n \ + * 0100100010100101000 + * n \ \ n \ \ + * ``` + */ + uint64_t escaped; + /** + * Mask of escape characters. + * + * ``` + * \n \\n \\\n \\\\n \ + * 1001000101001010001 + * \ \ \ \ \ \ \ + * ``` + */ + uint64_t escape; + }; + + /** + * Get a mask of both escape and escaped characters (the characters following a backslash). + * + * @param potential_escape A mask of the character that can escape others (but could be + * escaped itself). e.g. block.eq('\\') + */ + simdjson_really_inline escaped_and_escape next(uint64_t backslash) noexcept { + +#if !SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT + if (!backslash) { return {next_escaped_without_backslashes(), 0}; } +#endif + + // | | Mask (shows characters instead of 1's) | Depth | Instructions | + // |--------------------------------|----------------------------------------|-------|---------------------| + // | string | `\\n_\\\n___\\\n___\\\\___\\\\__\\\` | | | + // | | ` even odd even odd odd` | | | + // | potential_escape | ` \ \\\ \\\ \\\\ \\\\ \\\` | 1 | 1 (backslash & ~first_is_escaped) + // | escape_and_terminal_code | ` \n \ \n \ \n \ \ \ \ \ \` | 5 | 5 (next_escape_and_terminal_code()) + // | escaped | `\ \ n \ n \ \ \ \ \ ` X | 6 | 7 (escape_and_terminal_code ^ (potential_escape | first_is_escaped)) + // | escape | ` \ \ \ \ \ \ \ \ \ \` | 6 | 8 (escape_and_terminal_code & backslash) + // | first_is_escaped | `\ ` | 7 (*) | 9 (escape >> 63) () + // (*) this is not needed until the next iteration + uint64_t escape_and_terminal_code = next_escape_and_terminal_code(backslash & ~this->next_is_escaped); + uint64_t escaped = escape_and_terminal_code ^ (backslash | this->next_is_escaped); + uint64_t escape = escape_and_terminal_code & backslash; + this->next_is_escaped = escape >> 63; + return {escaped, escape}; + } + +private: + static constexpr const uint64_t ODD_BITS = 0xAAAAAAAAAAAAAAAAULL; + + simdjson_really_inline uint64_t next_escaped_without_backslashes() noexcept { + uint64_t escaped = this->next_is_escaped; + this->next_is_escaped = 0; + return escaped; + } + + /** + * Returns a mask of the next escape characters (masking out escaped backslashes), along with + * any non-backslash escape codes. + * + * \n \\n \\\n \\\\n returns: + * \n \ \ \n \ \ + * 11 100 1011 10100 + * + * You are expected to mask out the first bit yourself if the previous block had a trailing + * escape. + * + * & the result with potential_escape to get just the escape characters. + * ^ the result with (potential_escape | first_is_escaped) to get escaped characters. + */ + static simdjson_really_inline uint64_t next_escape_and_terminal_code(uint64_t potential_escape) noexcept { + // If we were to just shift and mask out any odd bits, we'd actually get a *half* right answer: + // any even-aligned backslash runs would be correct! Odd-aligned backslash runs would be + // inverted (\\\ would be 010 instead of 101). + // + // ``` + // string: | ____\\\\_\\\\_____ | + // maybe_escaped | ODD | \ \ \ \ | + // even-aligned ^^^ ^^^^ odd-aligned + // ``` + // + // Taking that into account, our basic strategy is: + // + // 1. Use subtraction to produce a mask with 1's for even-aligned runs and 0's for + // odd-aligned runs. + // 2. XOR all odd bits, which masks out the odd bits in even-aligned runs, and brings IN the + // odd bits in odd-aligned runs. + // 3. & with backslash to clean up any stray bits. + // runs are set to 0, and then XORing with "odd": + // + // | | Mask (shows characters instead of 1's) | Instructions | + // |--------------------------------|----------------------------------------|---------------------| + // | string | `\\n_\\\n___\\\n___\\\\___\\\\__\\\` | + // | | ` even odd even odd odd` | + // | maybe_escaped | ` n \\n \\n \\\_ \\\_ \\` X | 1 (potential_escape << 1) + // | maybe_escaped_and_odd | ` \n_ \\n _ \\\n_ _ \\\__ _\\\_ \\\` | 1 (maybe_escaped | odd) + // | even_series_codes_and_odd | ` n_\\\ _ n_ _\\\\ _ _ ` | 1 (maybe_escaped_and_odd - potential_escape) + // | escape_and_terminal_code | ` \n \ \n \ \n \ \ \ \ \ \` | 1 (^ odd) + // + + // Escaped characters are characters following an escape. + uint64_t maybe_escaped = potential_escape << 1; + + // To distinguish odd from even escape sequences, therefore, we turn on any *starting* + // escapes that are on an odd byte. (We actually bring in all odd bits, for speed.) + // - Odd runs of backslashes are 0000, and the code at the end ("n" in \n or \\n) is 1. + // - Odd runs of backslashes are 1111, and the code at the end ("n" in \n or \\n) is 0. + // - All other odd bytes are 1, and even bytes are 0. + uint64_t maybe_escaped_and_odd_bits = maybe_escaped | ODD_BITS; + uint64_t even_series_codes_and_odd_bits = maybe_escaped_and_odd_bits - potential_escape; + + // Now we flip all odd bytes back with xor. This: + // - Makes odd runs of backslashes go from 0000 to 1010 + // - Makes even runs of backslashes go from 1111 to 1010 + // - Sets actually-escaped codes to 1 (the n in \n and \\n: \n = 11, \\n = 100) + // - Resets all other bytes to 0 + return even_series_codes_and_odd_bits ^ ODD_BITS; + } +}; + +} // namespace stage1 +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_SRC_GENERIC_STAGE1_JSON_STRING_SCANNER_H +/* end file generic/stage1/json_escape_scanner.h for rvv_vls */ +/* including generic/stage1/json_string_scanner.h for rvv_vls: #include */ +/* begin file generic/stage1/json_string_scanner.h for rvv_vls */ +#ifndef SIMDJSON_SRC_GENERIC_STAGE1_JSON_STRING_SCANNER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_SRC_GENERIC_STAGE1_JSON_STRING_SCANNER_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace stage1 { + +struct json_string_block { + // We spell out the constructors in the hope of resolving inlining issues with Visual Studio 2017 + simdjson_really_inline json_string_block(uint64_t escaped, uint64_t quote, uint64_t in_string) : + _escaped(escaped), _quote(quote), _in_string(in_string) {} + + // Escaped characters (characters following an escape() character) + simdjson_really_inline uint64_t escaped() const { return _escaped; } + // Real (non-backslashed) quotes + simdjson_really_inline uint64_t quote() const { return _quote; } + // Only characters inside the string (not including the quotes) + simdjson_really_inline uint64_t string_content() const { return _in_string & ~_quote; } + // Return a mask of whether the given characters are inside a string (only works on non-quotes) + simdjson_really_inline uint64_t non_quote_inside_string(uint64_t mask) const { return mask & _in_string; } + // Return a mask of whether the given characters are inside a string (only works on non-quotes) + simdjson_really_inline uint64_t non_quote_outside_string(uint64_t mask) const { return mask & ~_in_string; } + // Tail of string (everything except the start quote) + simdjson_really_inline uint64_t string_tail() const { return _in_string ^ _quote; } + + // escaped characters (backslashed--does not include the hex characters after \u) + uint64_t _escaped; + // real quotes (non-escaped ones) + uint64_t _quote; + // string characters (includes start quote but not end quote) + uint64_t _in_string; +}; + +// Scans blocks for string characters, storing the state necessary to do so +class json_string_scanner { +public: + simdjson_really_inline json_string_block next(const simd::simd8x64& in); + // Returns either UNCLOSED_STRING or SUCCESS + simdjson_really_inline error_code finish(); + +private: + // Scans for escape characters + json_escape_scanner escape_scanner{}; + // Whether the last iteration was still inside a string (all 1's = true, all 0's = false). + uint64_t prev_in_string = 0ULL; +}; + +// +// Return a mask of all string characters plus end quotes. +// +// prev_escaped is overflow saying whether the next character is escaped. +// prev_in_string is overflow saying whether we're still in a string. +// +// Backslash sequences outside of quotes will be detected in stage 2. +// +simdjson_really_inline json_string_block json_string_scanner::next(const simd::simd8x64& in) { + const uint64_t backslash = in.eq('\\'); + const uint64_t escaped = escape_scanner.next(backslash).escaped; + const uint64_t quote = in.eq('"') & ~escaped; + + // + // prefix_xor flips on bits inside the string (and flips off the end quote). + // + // Then we xor with prev_in_string: if we were in a string already, its effect is flipped + // (characters inside strings are outside, and characters outside strings are inside). + // + const uint64_t in_string = prefix_xor(quote) ^ prev_in_string; + + // + // Check if we're still in a string at the end of the box so the next block will know + // + prev_in_string = uint64_t(static_cast(in_string) >> 63); + + // Use ^ to turn the beginning quote off, and the end quote on. + + // We are returning a function-local object so either we get a move constructor + // or we get copy elision. + return json_string_block(escaped, quote, in_string); +} + +simdjson_really_inline error_code json_string_scanner::finish() { + if (prev_in_string) { + return UNCLOSED_STRING; + } + return SUCCESS; +} + +} // namespace stage1 +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_SRC_GENERIC_STAGE1_JSON_STRING_SCANNER_H +/* end file generic/stage1/json_string_scanner.h for rvv_vls */ +/* including generic/stage1/utf8_lookup4_algorithm.h for rvv_vls: #include */ +/* begin file generic/stage1/utf8_lookup4_algorithm.h for rvv_vls */ +#ifndef SIMDJSON_SRC_GENERIC_STAGE1_UTF8_LOOKUP4_ALGORITHM_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_SRC_GENERIC_STAGE1_UTF8_LOOKUP4_ALGORITHM_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace utf8_validation { + +using namespace simd; + + simdjson_inline simd8 check_special_cases(const simd8 input, const simd8 prev1) { +// Bit 0 = Too Short (lead byte/ASCII followed by lead byte/ASCII) +// Bit 1 = Too Long (ASCII followed by continuation) +// Bit 2 = Overlong 3-byte +// Bit 4 = Surrogate +// Bit 5 = Overlong 2-byte +// Bit 7 = Two Continuations + constexpr const uint8_t TOO_SHORT = 1<<0; // 11______ 0_______ + // 11______ 11______ + constexpr const uint8_t TOO_LONG = 1<<1; // 0_______ 10______ + constexpr const uint8_t OVERLONG_3 = 1<<2; // 11100000 100_____ + constexpr const uint8_t SURROGATE = 1<<4; // 11101101 101_____ + constexpr const uint8_t OVERLONG_2 = 1<<5; // 1100000_ 10______ + constexpr const uint8_t TWO_CONTS = 1<<7; // 10______ 10______ + constexpr const uint8_t TOO_LARGE = 1<<3; // 11110100 1001____ + // 11110100 101_____ + // 11110101 1001____ + // 11110101 101_____ + // 1111011_ 1001____ + // 1111011_ 101_____ + // 11111___ 1001____ + // 11111___ 101_____ + constexpr const uint8_t TOO_LARGE_1000 = 1<<6; + // 11110101 1000____ + // 1111011_ 1000____ + // 11111___ 1000____ + constexpr const uint8_t OVERLONG_4 = 1<<6; // 11110000 1000____ + + const simd8 byte_1_high = prev1.shr<4>().lookup_16( + // 0_______ ________ + TOO_LONG, TOO_LONG, TOO_LONG, TOO_LONG, + TOO_LONG, TOO_LONG, TOO_LONG, TOO_LONG, + // 10______ ________ + TWO_CONTS, TWO_CONTS, TWO_CONTS, TWO_CONTS, + // 1100____ ________ + TOO_SHORT | OVERLONG_2, + // 1101____ ________ + TOO_SHORT, + // 1110____ ________ + TOO_SHORT | OVERLONG_3 | SURROGATE, + // 1111____ ________ + TOO_SHORT | TOO_LARGE | TOO_LARGE_1000 | OVERLONG_4 + ); + constexpr const uint8_t CARRY = TOO_SHORT | TOO_LONG | TWO_CONTS; // These all have ____ in byte 1 . + const simd8 byte_1_low = (prev1 & 0x0F).lookup_16( + // ____0000 ________ + CARRY | OVERLONG_3 | OVERLONG_2 | OVERLONG_4, + // ____0001 ________ + CARRY | OVERLONG_2, + // ____001_ ________ + CARRY, + CARRY, + + // ____0100 ________ + CARRY | TOO_LARGE, + // ____0101 ________ + CARRY | TOO_LARGE | TOO_LARGE_1000, + // ____011_ ________ + CARRY | TOO_LARGE | TOO_LARGE_1000, + CARRY | TOO_LARGE | TOO_LARGE_1000, + + // ____1___ ________ + CARRY | TOO_LARGE | TOO_LARGE_1000, + CARRY | TOO_LARGE | TOO_LARGE_1000, + CARRY | TOO_LARGE | TOO_LARGE_1000, + CARRY | TOO_LARGE | TOO_LARGE_1000, + CARRY | TOO_LARGE | TOO_LARGE_1000, + // ____1101 ________ + CARRY | TOO_LARGE | TOO_LARGE_1000 | SURROGATE, + CARRY | TOO_LARGE | TOO_LARGE_1000, + CARRY | TOO_LARGE | TOO_LARGE_1000 + ); + const simd8 byte_2_high = input.shr<4>().lookup_16( + // ________ 0_______ + TOO_SHORT, TOO_SHORT, TOO_SHORT, TOO_SHORT, + TOO_SHORT, TOO_SHORT, TOO_SHORT, TOO_SHORT, + + // ________ 1000____ + TOO_LONG | OVERLONG_2 | TWO_CONTS | OVERLONG_3 | TOO_LARGE_1000 | OVERLONG_4, + // ________ 1001____ + TOO_LONG | OVERLONG_2 | TWO_CONTS | OVERLONG_3 | TOO_LARGE, + // ________ 101_____ + TOO_LONG | OVERLONG_2 | TWO_CONTS | SURROGATE | TOO_LARGE, + TOO_LONG | OVERLONG_2 | TWO_CONTS | SURROGATE | TOO_LARGE, + + // ________ 11______ + TOO_SHORT, TOO_SHORT, TOO_SHORT, TOO_SHORT + ); + return (byte_1_high & byte_1_low & byte_2_high); + } + simdjson_inline simd8 check_multibyte_lengths(const simd8 input, + const simd8 prev_input, const simd8 sc) { + simd8 prev2 = input.prev<2>(prev_input); + simd8 prev3 = input.prev<3>(prev_input); + simd8 must23 = must_be_2_3_continuation(prev2, prev3); + simd8 must23_80 = must23 & uint8_t(0x80); + return must23_80 ^ sc; + } + + // + // Return nonzero if there are incomplete multibyte characters at the end of the block: + // e.g. if there is a 4-byte character, but it's 3 bytes from the end. + // + simdjson_inline simd8 is_incomplete(const simd8 input) { + // If the previous input's last 3 bytes match this, they're too short (they ended at EOF): + // ... 1111____ 111_____ 11______ +#if SIMDJSON_IMPLEMENTATION_ICELAKE || (SIMDJSON_IMPLEMENTATION_RVV_VLS && __riscv_v_fixed_vlen >= 512) + static const uint8_t max_array[64] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 0xf0u-1, 0xe0u-1, 0xc0u-1 + }; +#else + static const uint8_t max_array[32] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 0xf0u-1, 0xe0u-1, 0xc0u-1 + }; +#endif + const simd8 max_value(&max_array[sizeof(max_array)-sizeof(simd8)]); + return input.gt_bits(max_value); + } + + struct utf8_checker { + // If this is nonzero, there has been a UTF-8 error. + simd8 error; + // The last input we received + simd8 prev_input_block; + // Whether the last input we received was incomplete (used for ASCII fast path) + simd8 prev_incomplete; + + // + // Check whether the current bytes are valid UTF-8. + // + simdjson_inline void check_utf8_bytes(const simd8 input, const simd8 prev_input) { + // Flip prev1...prev3 so we can easily determine if they are 2+, 3+ or 4+ lead bytes + // (2, 3, 4-byte leads become large positive numbers instead of small negative numbers) + simd8 prev1 = input.prev<1>(prev_input); + simd8 sc = check_special_cases(input, prev1); + this->error |= check_multibyte_lengths(input, prev_input, sc); + } + + // The only problem that can happen at EOF is that a multibyte character is too short + // or a byte value too large in the last bytes: check_special_cases only checks for bytes + // too large in the first of two bytes. + simdjson_inline void check_eof() { + // If the previous block had incomplete UTF-8 characters at the end, an ASCII block can't + // possibly finish them. + this->error |= this->prev_incomplete; + } + + simdjson_inline void check_next_input(const simd8x64& input) { + if(simdjson_likely(is_ascii(input))) { + this->error |= this->prev_incomplete; + } else { + // you might think that a for-loop would work, but under Visual Studio, it is not good enough. + static_assert((simd8x64::NUM_CHUNKS == 1) + ||(simd8x64::NUM_CHUNKS == 2) + || (simd8x64::NUM_CHUNKS == 4), + "We support one, two or four chunks per 64-byte block."); + SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 1) { + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); + } else SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 2) { + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); + this->check_utf8_bytes(input.get<1>(), input.get<0>()); + } else SIMDJSON_IF_CONSTEXPR (simd8x64::NUM_CHUNKS == 4) { + this->check_utf8_bytes(input.get<0>(), this->prev_input_block); + this->check_utf8_bytes(input.get<1>(), input.get<0>()); + this->check_utf8_bytes(input.get<2>(), input.get<1>()); + this->check_utf8_bytes(input.get<3>(), input.get<2>()); + } + this->prev_incomplete = is_incomplete(input.get::NUM_CHUNKS-1>()); + this->prev_input_block = input.get::NUM_CHUNKS-1>(); + } + } + // do not forget to call check_eof! + simdjson_warn_unused simdjson_inline error_code errors() { + return this->error.any_bits_set_anywhere() ? error_code::UTF8_ERROR : error_code::SUCCESS; + } + + }; // struct utf8_checker +} // namespace utf8_validation + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_SRC_GENERIC_STAGE1_UTF8_LOOKUP4_ALGORITHM_H +/* end file generic/stage1/utf8_lookup4_algorithm.h for rvv_vls */ +/* including generic/stage1/json_scanner.h for rvv_vls: #include */ +/* begin file generic/stage1/json_scanner.h for rvv_vls */ +#ifndef SIMDJSON_SRC_GENERIC_STAGE1_JSON_SCANNER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_SRC_GENERIC_STAGE1_JSON_SCANNER_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace stage1 { + +/** + * A block of scanned json, with information on operators and scalars. + * + * We seek to identify pseudo-structural characters. Anything that is inside + * a string must be omitted (hence & ~_string.string_tail()). + * Otherwise, pseudo-structural characters come in two forms. + * 1. We have the structural characters ([,],{,},:, comma). The + * term 'structural character' is from the JSON RFC. + * 2. We have the 'scalar pseudo-structural characters'. + * Scalars are quotes, and any character except structural characters and white space. + * + * To identify the scalar pseudo-structural characters, we must look at what comes + * before them: it must be a space, a quote or a structural characters. + * Starting with simdjson v0.3, we identify them by + * negation: we identify everything that is followed by a non-quote scalar, + * and we negate that. Whatever remains must be a 'scalar pseudo-structural character'. + */ +struct json_block { +public: + // We spell out the constructors in the hope of resolving inlining issues with Visual Studio 2017 + simdjson_inline json_block(json_string_block&& string, json_character_block characters, uint64_t follows_potential_nonquote_scalar) : + _string(std::move(string)), _characters(characters), _follows_potential_nonquote_scalar(follows_potential_nonquote_scalar) {} + simdjson_inline json_block(json_string_block string, json_character_block characters, uint64_t follows_potential_nonquote_scalar) : + _string(string), _characters(characters), _follows_potential_nonquote_scalar(follows_potential_nonquote_scalar) {} + + /** + * The start of structurals. + * In simdjson prior to v0.3, these were called the pseudo-structural characters. + **/ + simdjson_inline uint64_t structural_start() const noexcept { return potential_structural_start() & ~_string.string_tail(); } + /** All JSON whitespace (i.e. not in a string) */ + simdjson_inline uint64_t whitespace() const noexcept { return non_quote_outside_string(_characters.whitespace()); } + + // Helpers + + /** Whether the given characters are inside a string (only works on non-quotes) */ + simdjson_inline uint64_t non_quote_inside_string(uint64_t mask) const noexcept { return _string.non_quote_inside_string(mask); } + /** Whether the given characters are outside a string (only works on non-quotes) */ + simdjson_inline uint64_t non_quote_outside_string(uint64_t mask) const noexcept { return _string.non_quote_outside_string(mask); } + + // string and escape characters + json_string_block _string; + // whitespace, structural characters ('operators'), scalars + json_character_block _characters; + // whether the previous character was a scalar + uint64_t _follows_potential_nonquote_scalar; +private: + // Potential structurals (i.e. disregarding strings) + + /** + * structural elements ([,],{,},:, comma) plus scalar starts like 123, true and "abc". + * They may reside inside a string. + **/ + simdjson_inline uint64_t potential_structural_start() const noexcept { return _characters.op() | potential_scalar_start(); } + /** + * The start of non-operator runs, like 123, true and "abc". + * It main reside inside a string. + **/ + simdjson_inline uint64_t potential_scalar_start() const noexcept { + // The term "scalar" refers to anything except structural characters and white space + // (so letters, numbers, quotes). + // Whenever it is preceded by something that is not a structural element ({,},[,],:, ") nor a white-space + // then we know that it is irrelevant structurally. + return _characters.scalar() & ~follows_potential_scalar(); + } + /** + * Whether the given character is immediately after a non-operator like 123, true. + * The characters following a quote are not included. + */ + simdjson_inline uint64_t follows_potential_scalar() const noexcept { + // _follows_potential_nonquote_scalar: is defined as marking any character that follows a character + // that is not a structural element ({,},[,],:, comma) nor a quote (") and that is not a + // white space. + // It is understood that within quoted region, anything at all could be marked (irrelevant). + return _follows_potential_nonquote_scalar; + } +}; + +/** + * Scans JSON for important bits: structural characters or 'operators', strings, and scalars. + * + * The scanner starts by calculating two distinct things: + * - string characters (taking \" into account) + * - structural characters or 'operators' ([]{},:, comma) + * and scalars (runs of non-operators like 123, true and "abc") + * + * To minimize data dependency (a key component of the scanner's speed), it finds these in parallel: + * in particular, the operator/scalar bit will find plenty of things that are actually part of + * strings. When we're done, json_block will fuse the two together by masking out tokens that are + * part of a string. + */ +class json_scanner { +public: + json_scanner() = default; + simdjson_inline json_block next(const simd::simd8x64& in); + // Returns either UNCLOSED_STRING or SUCCESS + simdjson_warn_unused simdjson_inline error_code finish(); + +private: + // Whether the last character of the previous iteration is part of a scalar token + // (anything except whitespace or a structural character/'operator'). + uint64_t prev_scalar = 0ULL; + json_string_scanner string_scanner{}; +}; + + +// +// Check if the current character immediately follows a matching character. +// +// For example, this checks for quotes with backslashes in front of them: +// +// const uint64_t backslashed_quote = in.eq('"') & immediately_follows(in.eq('\'), prev_backslash); +// +simdjson_inline uint64_t follows(const uint64_t match, uint64_t &overflow) { + const uint64_t result = match << 1 | overflow; + overflow = match >> 63; + return result; +} + +simdjson_inline json_block json_scanner::next(const simd::simd8x64& in) { + json_string_block strings = string_scanner.next(in); + // identifies the white-space and the structural characters + json_character_block characters = json_character_block::classify(in); + // The term "scalar" refers to anything except structural characters and white space + // (so letters, numbers, quotes). + // We want follows_scalar to mark anything that follows a non-quote scalar (so letters and numbers). + // + // A terminal quote should either be followed by a structural character (comma, brace, bracket, colon) + // or nothing. However, we still want ' "a string"true ' to mark the 't' of 'true' as a potential + // pseudo-structural character just like we would if we had ' "a string" true '; otherwise we + // may need to add an extra check when parsing strings. + // + // Performance: there are many ways to skin this cat. + const uint64_t nonquote_scalar = characters.scalar() & ~strings.quote(); + uint64_t follows_nonquote_scalar = follows(nonquote_scalar, prev_scalar); + // We are returning a function-local object so either we get a move constructor + // or we get copy elision. + return json_block( + strings,// strings is a function-local object so either it moves or the copy is elided. + characters, + follows_nonquote_scalar + ); +} + +simdjson_warn_unused simdjson_inline error_code json_scanner::finish() { + return string_scanner.finish(); +} + +} // namespace stage1 +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_SRC_GENERIC_STAGE1_JSON_SCANNER_H +/* end file generic/stage1/json_scanner.h for rvv_vls */ + +// All other declarations +/* including generic/stage1/find_next_document_index.h for rvv_vls: #include */ +/* begin file generic/stage1/find_next_document_index.h for rvv_vls */ +#ifndef SIMDJSON_SRC_GENERIC_STAGE1_FIND_NEXT_DOCUMENT_INDEX_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_SRC_GENERIC_STAGE1_FIND_NEXT_DOCUMENT_INDEX_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace stage1 { + +/** + * This algorithm is used to quickly identify the last structural position that + * makes up a complete document. + * + * It does this by going backwards and finding the last *document boundary* (a + * place where one value follows another without a comma between them). If the + * last document (the characters after the boundary) has an equal number of + * start and end brackets, it is considered complete. + * + * Simply put, we iterate over the structural characters, starting from + * the end. We consider that we found the end of a JSON document when the + * first element of the pair is NOT one of these characters: '{' '[' ':' ',' + * and when the second element is NOT one of these characters: '}' ']' ':' ','. + * + * This simple comparison works most of the time, but it does not cover cases + * where the batch's structural indexes contain a perfect amount of documents. + * In such a case, we do not have access to the structural index which follows + * the last document, therefore, we do not have access to the second element in + * the pair, and that means we cannot identify the last document. To fix this + * issue, we keep a count of the open and closed curly/square braces we found + * while searching for the pair. When we find a pair AND the count of open and + * closed curly/square braces is the same, we know that we just passed a + * complete document, therefore the last json buffer location is the end of the + * batch. + */ +simdjson_inline uint32_t find_next_document_index(dom_parser_implementation &parser) { + // Variant: do not count separately, just figure out depth + if(parser.n_structural_indexes == 0) { return 0; } + auto arr_cnt = 0; + auto obj_cnt = 0; + for (auto i = parser.n_structural_indexes - 1; i > 0; i--) { + auto idxb = parser.structural_indexes[i]; + switch (parser.buf[idxb]) { + case ':': + case ',': + continue; + case '}': + obj_cnt--; + continue; + case ']': + arr_cnt--; + continue; + case '{': + obj_cnt++; + break; + case '[': + arr_cnt++; + break; + } + auto idxa = parser.structural_indexes[i - 1]; + switch (parser.buf[idxa]) { + case '{': + case '[': + case ':': + case ',': + continue; + } + // Last document is complete, so the next document will appear after! + if (!arr_cnt && !obj_cnt) { + return parser.n_structural_indexes; + } + // Last document is incomplete; mark the document at i + 1 as the next one + return i; + } + // If we made it to the end, we want to finish counting to see if we have a full document. + switch (parser.buf[parser.structural_indexes[0]]) { + case '}': + obj_cnt--; + break; + case ']': + arr_cnt--; + break; + case '{': + obj_cnt++; + break; + case '[': + arr_cnt++; + break; + } + if (!arr_cnt && !obj_cnt) { + // We have a complete document. + return parser.n_structural_indexes; + } + return 0; +} + +} // namespace stage1 +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_SRC_GENERIC_STAGE1_FIND_NEXT_DOCUMENT_INDEX_H +/* end file generic/stage1/find_next_document_index.h for rvv_vls */ +/* including generic/stage1/json_minifier.h for rvv_vls: #include */ +/* begin file generic/stage1/json_minifier.h for rvv_vls */ +#ifndef SIMDJSON_SRC_GENERIC_STAGE1_JSON_MINIFIER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_SRC_GENERIC_STAGE1_JSON_MINIFIER_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +// This file contains the common code every implementation uses in stage1 +// It is intended to be included multiple times and compiled multiple times +// We assume the file in which it is included already includes +// "simdjson/stage1.h" (this simplifies amalgation) + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace stage1 { + +class json_minifier { +public: + template + static error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) noexcept; + +private: + simdjson_inline json_minifier(uint8_t *_dst) + : dst{_dst} + {} + template + simdjson_inline void step(const uint8_t *block_buf, buf_block_reader &reader) noexcept; + simdjson_inline void next(const simd::simd8x64& in, const json_block& block); + simdjson_warn_unused simdjson_inline error_code finish(uint8_t *dst_start, size_t &dst_len); + json_scanner scanner{}; + uint8_t *dst; +}; + +simdjson_inline void json_minifier::next(const simd::simd8x64& in, const json_block& block) { + uint64_t mask = block.whitespace(); + dst += in.compress(mask, dst); +} + +simdjson_warn_unused simdjson_inline error_code json_minifier::finish(uint8_t *dst_start, size_t &dst_len) { + error_code error = scanner.finish(); + if (error) { dst_len = 0; return error; } + dst_len = dst - dst_start; + return SUCCESS; +} + +template<> +simdjson_inline void json_minifier::step<128>(const uint8_t *block_buf, buf_block_reader<128> &reader) noexcept { + simd::simd8x64 in_1(block_buf); + simd::simd8x64 in_2(block_buf+64); + json_block block_1 = scanner.next(in_1); + json_block block_2 = scanner.next(in_2); + this->next(in_1, block_1); + this->next(in_2, block_2); + reader.advance(); +} + +template<> +simdjson_inline void json_minifier::step<64>(const uint8_t *block_buf, buf_block_reader<64> &reader) noexcept { + simd::simd8x64 in_1(block_buf); + json_block block_1 = scanner.next(in_1); + this->next(block_buf, block_1); + reader.advance(); +} + +template +error_code json_minifier::minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) noexcept { + buf_block_reader reader(buf, len); + json_minifier minifier(dst); + + // Index the first n-1 blocks + while (reader.has_full_block()) { + minifier.step(reader.full_block(), reader); + } + + // Index the last (remainder) block, padded with spaces + uint8_t block[STEP_SIZE]; + size_t remaining_bytes = reader.get_remainder(block); + if (remaining_bytes > 0) { + // We do not want to write directly to the output stream. Rather, we write + // to a local buffer (for safety). + uint8_t out_block[STEP_SIZE]; + uint8_t * const guarded_dst{minifier.dst}; + minifier.dst = out_block; + minifier.step(block, reader); + size_t to_write = minifier.dst - out_block; + // In some cases, we could be enticed to consider the padded spaces + // as part of the string. This is fine as long as we do not write more + // than we consumed. + if(to_write > remaining_bytes) { to_write = remaining_bytes; } + memcpy(guarded_dst, out_block, to_write); + minifier.dst = guarded_dst + to_write; + } + return minifier.finish(dst, dst_len); +} + +} // namespace stage1 +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_SRC_GENERIC_STAGE1_JSON_MINIFIER_H +/* end file generic/stage1/json_minifier.h for rvv_vls */ +/* including generic/stage1/json_structural_indexer.h for rvv_vls: #include */ +/* begin file generic/stage1/json_structural_indexer.h for rvv_vls */ +#ifndef SIMDJSON_SRC_GENERIC_STAGE1_JSON_STRUCTURAL_INDEXER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_SRC_GENERIC_STAGE1_JSON_STRUCTURAL_INDEXER_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +// This file contains the common code every implementation uses in stage1 +// It is intended to be included multiple times and compiled multiple times +// We assume the file in which it is included already includes +// "simdjson/stage1.h" (this simplifies amalgation) + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace stage1 { + +class bit_indexer { +public: + uint32_t *tail; + + simdjson_inline bit_indexer(uint32_t *index_buf) : tail(index_buf) {} + +#if SIMDJSON_PREFER_REVERSE_BITS + /** + * ARM lacks a fast trailing zero instruction, but it has a fast + * bit reversal instruction and a fast leading zero instruction. + * Thus it may be profitable to reverse the bits (once) and then + * to rely on a sequence of instructions that call the leading + * zero instruction. + * + * Performance notes: + * The chosen routine is not optimal in terms of data dependency + * since zero_leading_bit might require two instructions. However, + * it tends to minimize the total number of instructions which is + * beneficial. + */ + simdjson_inline void write_index(uint32_t idx, uint64_t& rev_bits, int i) { + int lz = leading_zeroes(rev_bits); + this->tail[i] = static_cast(idx) + lz; + rev_bits = zero_leading_bit(rev_bits, lz); + } +#else + /** + * Under recent x64 systems, we often have both a fast trailing zero + * instruction and a fast 'clear-lower-bit' instruction so the following + * algorithm can be competitive. + */ + + simdjson_inline void write_index(uint32_t idx, uint64_t& bits, int i) { + this->tail[i] = idx + trailing_zeroes(bits); + bits = clear_lowest_bit(bits); + } +#endif // SIMDJSON_PREFER_REVERSE_BITS + + template + simdjson_inline int write_indexes(uint32_t idx, uint64_t& bits) { + write_index(idx, bits, START); + SIMDJSON_IF_CONSTEXPR (N > 1) { + write_indexes<(N-1>0?START+1:START), (N-1>=0?N-1:1)>(idx, bits); + } + return START+N; + } + + template + simdjson_inline int write_indexes_stepped(uint32_t idx, uint64_t& bits, int cnt) { + write_indexes(idx, bits); + SIMDJSON_IF_CONSTEXPR ((START+STEP) < END) { + if (simdjson_unlikely((START+STEP) < cnt)) { + write_indexes_stepped<(START+STEP(idx, bits, cnt); + } + } + return ((END-START) % STEP) == 0 ? END : (END-START) - ((END-START) % STEP) + STEP; + } + + // flatten out values in 'bits' assuming that they are are to have values of idx + // plus their position in the bitvector, and store these indexes at + // base_ptr[base] incrementing base as we go + // will potentially store extra values beyond end of valid bits, so base_ptr + // needs to be large enough to handle this + // + // If the kernel sets SIMDJSON_GENERIC_JSON_STRUCTURAL_INDEXER_CUSTOM_BIT_INDEXER, then it + // will provide its own version of the code. +#ifdef SIMDJSON_GENERIC_JSON_STRUCTURAL_INDEXER_CUSTOM_BIT_INDEXER + simdjson_inline void write(uint32_t idx, uint64_t bits); +#else + simdjson_inline void write(uint32_t idx, uint64_t bits) { + // In some instances, the next branch is expensive because it is mispredicted. + // Unfortunately, in other cases, + // it helps tremendously. + if (bits == 0) + return; + + int cnt = static_cast(count_ones(bits)); + +#if SIMDJSON_PREFER_REVERSE_BITS + bits = reverse_bits(bits); +#endif +#ifdef SIMDJSON_STRUCTURAL_INDEXER_STEP + static constexpr const int STEP = SIMDJSON_STRUCTURAL_INDEXER_STEP; +#else + static constexpr const int STEP = 4; +#endif + static constexpr const int STEP_UNTIL = 24; + + write_indexes_stepped<0, STEP_UNTIL, STEP>(idx, bits, cnt); + SIMDJSON_IF_CONSTEXPR (STEP_UNTIL < 64) { + if (simdjson_unlikely(STEP_UNTIL < cnt)) { + for (int i=STEP_UNTIL; itail += cnt; + } +#endif // SIMDJSON_GENERIC_JSON_STRUCTURAL_INDEXER_CUSTOM_BIT_INDEXER + +}; + +class json_structural_indexer { +public: + /** + * Find the important bits of JSON in a 128-byte chunk, and add them to structural_indexes. + * + * @param partial Setting the partial parameter to true allows the find_structural_bits to + * tolerate unclosed strings. The caller should still ensure that the input is valid UTF-8. If + * you are processing substrings, you may want to call on a function like trimmed_length_safe_utf8. + */ + template + static error_code index(const uint8_t *buf, size_t len, dom_parser_implementation &parser, stage1_mode partial) noexcept; + +private: + simdjson_inline json_structural_indexer(uint32_t *structural_indexes); + template + simdjson_inline void step(const uint8_t *block, buf_block_reader &reader) noexcept; + simdjson_inline void next(const simd::simd8x64& in, const json_block& block, size_t idx); + simdjson_warn_unused simdjson_inline error_code finish(dom_parser_implementation &parser, size_t idx, size_t len, stage1_mode partial); + + json_scanner scanner{}; + utf8_checker checker{}; + bit_indexer indexer; + uint64_t prev_structurals = 0; + uint64_t unescaped_chars_error = 0; +}; + +simdjson_inline json_structural_indexer::json_structural_indexer(uint32_t *structural_indexes) : indexer{structural_indexes} {} + +// Skip the last character if it is partial +simdjson_inline size_t trim_partial_utf8(const uint8_t *buf, size_t len) { + if (simdjson_unlikely(len < 3)) { + switch (len) { + case 2: + if (buf[len-1] >= 0xc0) { return len-1; } // 2-, 3- and 4-byte characters with only 1 byte left + if (buf[len-2] >= 0xe0) { return len-2; } // 3- and 4-byte characters with only 2 bytes left + return len; + case 1: + if (buf[len-1] >= 0xc0) { return len-1; } // 2-, 3- and 4-byte characters with only 1 byte left + return len; + case 0: + return len; + } + } + if (buf[len-1] >= 0xc0) { return len-1; } // 2-, 3- and 4-byte characters with only 1 byte left + if (buf[len-2] >= 0xe0) { return len-2; } // 3- and 4-byte characters with only 1 byte left + if (buf[len-3] >= 0xf0) { return len-3; } // 4-byte characters with only 3 bytes left + return len; +} + +// +// PERF NOTES: +// We pipe 2 inputs through these stages: +// 1. Load JSON into registers. This takes a long time and is highly parallelizable, so we load +// 2 inputs' worth at once so that by the time step 2 is looking for them input, it's available. +// 2. Scan the JSON for critical data: strings, scalars and operators. This is the critical path. +// The output of step 1 depends entirely on this information. These functions don't quite use +// up enough CPU: the second half of the functions is highly serial, only using 1 execution core +// at a time. The second input's scans has some dependency on the first ones finishing it, but +// they can make a lot of progress before they need that information. +// 3. Step 1 does not use enough capacity, so we run some extra stuff while we're waiting for that +// to finish: utf-8 checks and generating the output from the last iteration. +// +// The reason we run 2 inputs at a time, is steps 2 and 3 are *still* not enough to soak up all +// available capacity with just one input. Running 2 at a time seems to give the CPU a good enough +// workout. +// +template +error_code json_structural_indexer::index(const uint8_t *buf, size_t len, dom_parser_implementation &parser, stage1_mode partial) noexcept { + if (simdjson_unlikely(len > parser.capacity())) { return CAPACITY; } + // We guard the rest of the code so that we can assume that len > 0 throughout. + if (len == 0) { return EMPTY; } + if (is_streaming(partial)) { + len = trim_partial_utf8(buf, len); + // If you end up with an empty window after trimming + // the partial UTF-8 bytes, then chances are good that you + // have an UTF-8 formatting error. + if(len == 0) { return UTF8_ERROR; } + } + buf_block_reader reader(buf, len); + json_structural_indexer indexer(parser.structural_indexes.get()); + + // Read all but the last block + while (reader.has_full_block()) { + indexer.step(reader.full_block(), reader); + } + // Take care of the last block (will always be there unless file is empty which is + // not supposed to happen.) + uint8_t block[STEP_SIZE]; + if (simdjson_unlikely(reader.get_remainder(block) == 0)) { return UNEXPECTED_ERROR; } + indexer.step(block, reader); + return indexer.finish(parser, reader.block_index(), len, partial); +} + +template<> +simdjson_inline void json_structural_indexer::step<128>(const uint8_t *block, buf_block_reader<128> &reader) noexcept { + simd::simd8x64 in_1(block); + simd::simd8x64 in_2(block+64); + json_block block_1 = scanner.next(in_1); + json_block block_2 = scanner.next(in_2); + this->next(in_1, block_1, reader.block_index()); + this->next(in_2, block_2, reader.block_index()+64); + reader.advance(); +} + +template<> +simdjson_inline void json_structural_indexer::step<64>(const uint8_t *block, buf_block_reader<64> &reader) noexcept { + simd::simd8x64 in_1(block); + json_block block_1 = scanner.next(in_1); + this->next(in_1, block_1, reader.block_index()); + reader.advance(); +} + +simdjson_inline void json_structural_indexer::next(const simd::simd8x64& in, const json_block& block, size_t idx) { + uint64_t unescaped = in.lteq(0x1F); +#if SIMDJSON_UTF8VALIDATION + checker.check_next_input(in); +#endif + indexer.write(uint32_t(idx-64), prev_structurals); // Output *last* iteration's structurals to the parser + prev_structurals = block.structural_start(); + unescaped_chars_error |= block.non_quote_inside_string(unescaped); +} + +simdjson_inline error_code json_structural_indexer::finish(dom_parser_implementation &parser, size_t idx, size_t len, stage1_mode partial) { + // Write out the final iteration's structurals + indexer.write(uint32_t(idx-64), prev_structurals); + error_code error = scanner.finish(); + // We deliberately break down the next expression so that it is + // human readable. + const bool should_we_exit = is_streaming(partial) ? + ((error != SUCCESS) && (error != UNCLOSED_STRING)) // when partial we tolerate UNCLOSED_STRING + : (error != SUCCESS); // if partial is false, we must have SUCCESS + const bool have_unclosed_string = (error == UNCLOSED_STRING); + if (simdjson_unlikely(should_we_exit)) { return error; } + + if (unescaped_chars_error) { + return UNESCAPED_CHARS; + } + parser.n_structural_indexes = uint32_t(indexer.tail - parser.structural_indexes.get()); + /*** + * The On-Demand API requires special padding. + * + * This is related to https://github.com/simdjson/simdjson/issues/906 + * Basically, we want to make sure that if the parsing continues beyond the last (valid) + * structural character, it quickly stops. + * Only three structural characters can be repeated without triggering an error in JSON: [,] and }. + * We repeat the padding character (at 'len'). We don't know what it is, but if the parsing + * continues, then it must be [,] or }. + * Suppose it is ] or }. We backtrack to the first character, what could it be that would + * not trigger an error? It could be ] or } but no, because you can't start a document that way. + * It can't be a comma, a colon or any simple value. So the only way we could continue is + * if the repeated character is [. But if so, the document must start with [. But if the document + * starts with [, it should end with ]. If we enforce that rule, then we would get + * ][[ which is invalid. + * + * This is illustrated with the test array_iterate_unclosed_error() on the following input: + * R"({ "a": [,,)" + **/ + parser.structural_indexes[parser.n_structural_indexes] = uint32_t(len); // used later in partial == stage1_mode::streaming_final + parser.structural_indexes[parser.n_structural_indexes + 1] = uint32_t(len); + parser.structural_indexes[parser.n_structural_indexes + 2] = 0; + parser.next_structural_index = 0; + // a valid JSON file cannot have zero structural indexes - we should have found something + if (simdjson_unlikely(parser.n_structural_indexes == 0u)) { + return EMPTY; + } + if (simdjson_unlikely(parser.structural_indexes[parser.n_structural_indexes - 1] > len)) { + return UNEXPECTED_ERROR; + } + if (partial == stage1_mode::streaming_partial) { + // If we have an unclosed string, then the last structural + // will be the quote and we want to make sure to omit it. + if(have_unclosed_string) { + parser.n_structural_indexes--; + // a valid JSON file cannot have zero structural indexes - we should have found something + if (simdjson_unlikely(parser.n_structural_indexes == 0u)) { return CAPACITY; } + } + // We truncate the input to the end of the last complete document (or zero). + auto new_structural_indexes = find_next_document_index(parser); + if (new_structural_indexes == 0 && parser.n_structural_indexes > 0) { + if(parser.structural_indexes[0] == 0) { + // If the buffer is partial and we started at index 0 but the document is + // incomplete, it's too big to parse. + return CAPACITY; + } else { + // It is possible that the document could be parsed, we just had a lot + // of white space. + parser.n_structural_indexes = 0; + return EMPTY; + } + } + + parser.n_structural_indexes = new_structural_indexes; + } else if (partial == stage1_mode::streaming_final) { + if(have_unclosed_string) { parser.n_structural_indexes--; } + // We truncate the input to the end of the last complete document (or zero). + // Because partial == stage1_mode::streaming_final, it means that we may + // silently ignore trailing garbage. Though it sounds bad, we do it + // deliberately because many people who have streams of JSON documents + // will truncate them for processing. E.g., imagine that you are uncompressing + // the data from a size file or receiving it in chunks from the network. You + // may not know where exactly the last document will be. Meanwhile the + // document_stream instances allow people to know the JSON documents they are + // parsing (see the iterator.source() method). + parser.n_structural_indexes = find_next_document_index(parser); + // We store the initial n_structural_indexes so that the client can see + // whether we used truncation. If initial_n_structural_indexes == parser.n_structural_indexes, + // then this will query parser.structural_indexes[parser.n_structural_indexes] which is len, + // otherwise, it will copy some prior index. + parser.structural_indexes[parser.n_structural_indexes + 1] = parser.structural_indexes[parser.n_structural_indexes]; + // This next line is critical, do not change it unless you understand what you are + // doing. + parser.structural_indexes[parser.n_structural_indexes] = uint32_t(len); + if (simdjson_unlikely(parser.n_structural_indexes == 0u)) { + // We tolerate an unclosed string at the very end of the stream. Indeed, users + // often load their data in bulk without being careful and they want us to ignore + // the trailing garbage. + return EMPTY; + } + } + checker.check_eof(); + return checker.errors(); +} + +} // namespace stage1 +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +// Clear CUSTOM_BIT_INDEXER so other implementations can set it if they need to. +#undef SIMDJSON_GENERIC_JSON_STRUCTURAL_INDEXER_CUSTOM_BIT_INDEXER + +#endif // SIMDJSON_SRC_GENERIC_STAGE1_JSON_STRUCTURAL_INDEXER_H +/* end file generic/stage1/json_structural_indexer.h for rvv_vls */ +/* including generic/stage1/utf8_validator.h for rvv_vls: #include */ +/* begin file generic/stage1/utf8_validator.h for rvv_vls */ +#ifndef SIMDJSON_SRC_GENERIC_STAGE1_UTF8_VALIDATOR_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_SRC_GENERIC_STAGE1_UTF8_VALIDATOR_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace stage1 { + +/** + * Validates that the string is actual UTF-8. + */ +template +bool generic_validate_utf8(const uint8_t * input, size_t length) { + checker c{}; + buf_block_reader<64> reader(input, length); + while (reader.has_full_block()) { + simd::simd8x64 in(reader.full_block()); + c.check_next_input(in); + reader.advance(); + } + uint8_t block[64]{}; + reader.get_remainder(block); + simd::simd8x64 in(block); + c.check_next_input(in); + reader.advance(); + c.check_eof(); + return c.errors() == error_code::SUCCESS; +} + +bool generic_validate_utf8(const char * input, size_t length) { + return generic_validate_utf8(reinterpret_cast(input),length); +} + +} // namespace stage1 +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_SRC_GENERIC_STAGE1_UTF8_VALIDATOR_H +/* end file generic/stage1/utf8_validator.h for rvv_vls */ +/* end file generic/stage1/amalgamated.h for rvv_vls */ +/* including generic/stage2/amalgamated.h for rvv_vls: #include */ +/* begin file generic/stage2/amalgamated.h for rvv_vls */ +// Stuff other things depend on +/* including generic/stage2/base.h for rvv_vls: #include */ +/* begin file generic/stage2/base.h for rvv_vls */ +#ifndef SIMDJSON_SRC_GENERIC_STAGE2_BASE_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_SRC_GENERIC_STAGE2_BASE_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace stage2 { + +class json_iterator; +class structural_iterator; +struct tape_builder; +struct tape_writer; + +} // namespace stage2 +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_SRC_GENERIC_STAGE2_BASE_H +/* end file generic/stage2/base.h for rvv_vls */ +/* including generic/stage2/tape_writer.h for rvv_vls: #include */ +/* begin file generic/stage2/tape_writer.h for rvv_vls */ +#ifndef SIMDJSON_SRC_GENERIC_STAGE2_TAPE_WRITER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_SRC_GENERIC_STAGE2_TAPE_WRITER_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace stage2 { + +struct tape_writer { + /** The next place to write to tape */ + uint64_t *next_tape_loc; + + /** Write a signed 64-bit value to tape. */ + simdjson_inline void append_s64(int64_t value) noexcept; + + /** Write an unsigned 64-bit value to tape. */ + simdjson_inline void append_u64(uint64_t value) noexcept; + + /** Write a double value to tape. */ + simdjson_inline void append_double(double value) noexcept; + + /** + * Append a tape entry (an 8-bit type,and 56 bits worth of value). + */ + simdjson_inline void append(uint64_t val, internal::tape_type t) noexcept; + + /** + * Skip the current tape entry without writing. + * + * Used to skip the start of the container, since we'll come back later to fill it in when the + * container ends. + */ + simdjson_inline void skip() noexcept; + + /** + * Skip the number of tape entries necessary to write a large u64 or i64. + */ + simdjson_inline void skip_large_integer() noexcept; + + /** + * Skip the number of tape entries necessary to write a double. + */ + simdjson_inline void skip_double() noexcept; + + /** + * Write a value to a known location on tape. + * + * Used to go back and write out the start of a container after the container ends. + */ + simdjson_inline static void write(uint64_t &tape_loc, uint64_t val, internal::tape_type t) noexcept; + +private: + /** + * Append both the tape entry, and a supplementary value following it. Used for types that need + * all 64 bits, such as double and uint64_t. + */ + template + simdjson_inline void append2(uint64_t val, T val2, internal::tape_type t) noexcept; +}; // struct tape_writer + +simdjson_inline void tape_writer::append_s64(int64_t value) noexcept { + append2(0, value, internal::tape_type::INT64); +} + +simdjson_inline void tape_writer::append_u64(uint64_t value) noexcept { + append(0, internal::tape_type::UINT64); + *next_tape_loc = value; + next_tape_loc++; +} + +/** Write a double value to tape. */ +simdjson_inline void tape_writer::append_double(double value) noexcept { + append2(0, value, internal::tape_type::DOUBLE); +} + +simdjson_inline void tape_writer::skip() noexcept { + next_tape_loc++; +} + +simdjson_inline void tape_writer::skip_large_integer() noexcept { + next_tape_loc += 2; +} + +simdjson_inline void tape_writer::skip_double() noexcept { + next_tape_loc += 2; +} + +simdjson_inline void tape_writer::append(uint64_t val, internal::tape_type t) noexcept { + *next_tape_loc = val | ((uint64_t(char(t))) << 56); + next_tape_loc++; +} + +template +simdjson_inline void tape_writer::append2(uint64_t val, T val2, internal::tape_type t) noexcept { + append(val, t); + static_assert(sizeof(val2) == sizeof(*next_tape_loc), "Type is not 64 bits!"); + memcpy(next_tape_loc, &val2, sizeof(val2)); + next_tape_loc++; +} + +simdjson_inline void tape_writer::write(uint64_t &tape_loc, uint64_t val, internal::tape_type t) noexcept { + tape_loc = val | ((uint64_t(char(t))) << 56); +} + +} // namespace stage2 +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_SRC_GENERIC_STAGE2_TAPE_WRITER_H +/* end file generic/stage2/tape_writer.h for rvv_vls */ +/* including generic/stage2/logger.h for rvv_vls: #include */ +/* begin file generic/stage2/logger.h for rvv_vls */ +#ifndef SIMDJSON_SRC_GENERIC_STAGE2_LOGGER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_SRC_GENERIC_STAGE2_LOGGER_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include + + +// This is for an internal-only stage 2 specific logger. +// Set LOG_ENABLED = true to log what stage 2 is doing! +namespace simdjson { +namespace rvv_vls { +namespace { +namespace logger { + + static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"; + +#if SIMDJSON_VERBOSE_LOGGING + static constexpr const bool LOG_ENABLED = true; +#else + static constexpr const bool LOG_ENABLED = false; +#endif + static constexpr const int LOG_EVENT_LEN = 20; + static constexpr const int LOG_BUFFER_LEN = 30; + static constexpr const int LOG_SMALL_BUFFER_LEN = 10; + static constexpr const int LOG_INDEX_LEN = 5; + + static int log_depth; // Not threadsafe. Log only. + + // Helper to turn unprintable or newline characters into spaces + static simdjson_inline char printable_char(char c) { + if (c >= 0x20) { + return c; + } else { + return ' '; + } + } + + // Print the header and set up log_start + static simdjson_inline void log_start() { + if (LOG_ENABLED) { + log_depth = 0; + printf("\n"); + printf("| %-*s | %-*s | %-*s | %-*s | Detail |\n", LOG_EVENT_LEN, "Event", LOG_BUFFER_LEN, "Buffer", LOG_SMALL_BUFFER_LEN, "Next", 5, "Next#"); + printf("|%.*s|%.*s|%.*s|%.*s|--------|\n", LOG_EVENT_LEN+2, DASHES, LOG_BUFFER_LEN+2, DASHES, LOG_SMALL_BUFFER_LEN+2, DASHES, 5+2, DASHES); + } + } + + simdjson_unused static simdjson_inline void log_string(const char *message) { + if (LOG_ENABLED) { + printf("%s\n", message); + } + } + + // Logs a single line from the stage 2 DOM parser + template + static simdjson_inline void log_line(S &structurals, const char *title_prefix, const char *title, const char *detail) { + if (LOG_ENABLED) { + printf("| %*s%s%-*s ", log_depth*2, "", title_prefix, LOG_EVENT_LEN - log_depth*2 - int(strlen(title_prefix)), title); + auto current_index = structurals.at_beginning() ? nullptr : structurals.next_structural-1; + auto next_index = structurals.next_structural; + auto current = current_index ? &structurals.buf[*current_index] : reinterpret_cast(" "); + auto next = &structurals.buf[*next_index]; + { + // Print the next N characters in the buffer. + printf("| "); + // Otherwise, print the characters starting from the buffer position. + // Print spaces for unprintable or newline characters. + for (int i=0;i */ +/* begin file generic/stage2/json_iterator.h for rvv_vls */ +#ifndef SIMDJSON_SRC_GENERIC_STAGE2_JSON_ITERATOR_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_SRC_GENERIC_STAGE2_JSON_ITERATOR_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace stage2 { + +class json_iterator { +public: + const uint8_t* const buf; + uint32_t *next_structural; + dom_parser_implementation &dom_parser; + uint32_t depth{0}; + + /** + * Walk the JSON document. + * + * The visitor receives callbacks when values are encountered. All callbacks pass the iterator as + * the first parameter; some callbacks have other parameters as well: + * + * - visit_document_start() - at the beginning. + * - visit_document_end() - at the end (if things were successful). + * + * - visit_array_start() - at the start `[` of a non-empty array. + * - visit_array_end() - at the end `]` of a non-empty array. + * - visit_empty_array() - when an empty array is encountered. + * + * - visit_object_end() - at the start `]` of a non-empty object. + * - visit_object_start() - at the end `]` of a non-empty object. + * - visit_empty_object() - when an empty object is encountered. + * - visit_key(const uint8_t *key) - when a key in an object field is encountered. key is + * guaranteed to point at the first quote of the string (`"key"`). + * - visit_primitive(const uint8_t *value) - when a value is a string, number, boolean or null. + * - visit_root_primitive(iter, uint8_t *value) - when the top-level value is a string, number, boolean or null. + * + * - increment_count(iter) - each time a value is found in an array or object. + */ + template + simdjson_warn_unused simdjson_inline error_code walk_document(V &visitor) noexcept; + + /** + * Create an iterator capable of walking a JSON document. + * + * The document must have already passed through stage 1. + */ + simdjson_inline json_iterator(dom_parser_implementation &_dom_parser, size_t start_structural_index); + + /** + * Look at the next token. + * + * Tokens can be strings, numbers, booleans, null, or operators (`[{]},:`)). + * + * They may include invalid JSON as well (such as `1.2.3` or `ture`). + */ + simdjson_inline const uint8_t *peek() const noexcept; + /** + * Advance to the next token. + * + * Tokens can be strings, numbers, booleans, null, or operators (`[{]},:`)). + * + * They may include invalid JSON as well (such as `1.2.3` or `ture`). + */ + simdjson_inline const uint8_t *advance() noexcept; + /** + * Get the remaining length of the document, from the start of the current token. + */ + simdjson_inline size_t remaining_len() const noexcept; + /** + * Check if we are at the end of the document. + * + * If this is true, there are no more tokens. + */ + simdjson_inline bool at_eof() const noexcept; + /** + * Check if we are at the beginning of the document. + */ + simdjson_inline bool at_beginning() const noexcept; + simdjson_inline uint8_t last_structural() const noexcept; + + /** + * Log that a value has been found. + * + * Set LOG_ENABLED=true in logger.h to see logging. + */ + simdjson_inline void log_value(const char *type) const noexcept; + /** + * Log the start of a multipart value. + * + * Set LOG_ENABLED=true in logger.h to see logging. + */ + simdjson_inline void log_start_value(const char *type) const noexcept; + /** + * Log the end of a multipart value. + * + * Set LOG_ENABLED=true in logger.h to see logging. + */ + simdjson_inline void log_end_value(const char *type) const noexcept; + /** + * Log an error. + * + * Set LOG_ENABLED=true in logger.h to see logging. + */ + simdjson_inline void log_error(const char *error) const noexcept; + + template + simdjson_warn_unused simdjson_inline error_code visit_root_primitive(V &visitor, const uint8_t *value) noexcept; + template + simdjson_warn_unused simdjson_inline error_code visit_primitive(V &visitor, const uint8_t *value) noexcept; +}; + +template +simdjson_warn_unused simdjson_inline error_code json_iterator::walk_document(V &visitor) noexcept { + logger::log_start(); + + // + // Start the document + // + if (at_eof()) { return EMPTY; } + log_start_value("document"); + SIMDJSON_TRY( visitor.visit_document_start(*this) ); + + // + // Read first value + // + { + auto value = advance(); + + // Make sure the outer object or array is closed before continuing; otherwise, there are ways we + // could get into memory corruption. See https://github.com/simdjson/simdjson/issues/906 + if (!STREAMING) { + switch (*value) { + case '{': if (last_structural() != '}') { log_value("starting brace unmatched"); return TAPE_ERROR; }; break; + case '[': if (last_structural() != ']') { log_value("starting bracket unmatched"); return TAPE_ERROR; }; break; + } + } + + switch (*value) { + case '{': if (*peek() == '}') { advance(); log_value("empty object"); SIMDJSON_TRY( visitor.visit_empty_object(*this) ); break; } goto object_begin; + case '[': if (*peek() == ']') { advance(); log_value("empty array"); SIMDJSON_TRY( visitor.visit_empty_array(*this) ); break; } goto array_begin; + default: SIMDJSON_TRY( visitor.visit_root_primitive(*this, value) ); break; + } + } + goto document_end; + +// +// Object parser states +// +object_begin: + log_start_value("object"); + depth++; + if (depth >= dom_parser.max_depth()) { log_error("Exceeded max depth!"); return DEPTH_ERROR; } + dom_parser.is_array[depth] = false; + SIMDJSON_TRY( visitor.visit_object_start(*this) ); + + { + auto key = advance(); + if (*key != '"') { log_error("Object does not start with a key"); return TAPE_ERROR; } + SIMDJSON_TRY( visitor.increment_count(*this) ); + SIMDJSON_TRY( visitor.visit_key(*this, key) ); + } + +object_field: + if (simdjson_unlikely( *advance() != ':' )) { log_error("Missing colon after key in object"); return TAPE_ERROR; } + { + auto value = advance(); + switch (*value) { + case '{': if (*peek() == '}') { advance(); log_value("empty object"); SIMDJSON_TRY( visitor.visit_empty_object(*this) ); break; } goto object_begin; + case '[': if (*peek() == ']') { advance(); log_value("empty array"); SIMDJSON_TRY( visitor.visit_empty_array(*this) ); break; } goto array_begin; + default: SIMDJSON_TRY( visitor.visit_primitive(*this, value) ); break; + } + } + +object_continue: + switch (*advance()) { + case ',': + SIMDJSON_TRY( visitor.increment_count(*this) ); + { + auto key = advance(); + if (simdjson_unlikely( *key != '"' )) { log_error("Key string missing at beginning of field in object"); return TAPE_ERROR; } + SIMDJSON_TRY( visitor.visit_key(*this, key) ); + } + goto object_field; + case '}': log_end_value("object"); SIMDJSON_TRY( visitor.visit_object_end(*this) ); goto scope_end; + default: log_error("No comma between object fields"); return TAPE_ERROR; + } + +scope_end: + depth--; + if (depth == 0) { goto document_end; } + if (dom_parser.is_array[depth]) { goto array_continue; } + goto object_continue; + +// +// Array parser states +// +array_begin: + log_start_value("array"); + depth++; + if (depth >= dom_parser.max_depth()) { log_error("Exceeded max depth!"); return DEPTH_ERROR; } + dom_parser.is_array[depth] = true; + SIMDJSON_TRY( visitor.visit_array_start(*this) ); + SIMDJSON_TRY( visitor.increment_count(*this) ); + +array_value: + { + auto value = advance(); + switch (*value) { + case '{': if (*peek() == '}') { advance(); log_value("empty object"); SIMDJSON_TRY( visitor.visit_empty_object(*this) ); break; } goto object_begin; + case '[': if (*peek() == ']') { advance(); log_value("empty array"); SIMDJSON_TRY( visitor.visit_empty_array(*this) ); break; } goto array_begin; + default: SIMDJSON_TRY( visitor.visit_primitive(*this, value) ); break; + } + } + +array_continue: + switch (*advance()) { + case ',': SIMDJSON_TRY( visitor.increment_count(*this) ); goto array_value; + case ']': log_end_value("array"); SIMDJSON_TRY( visitor.visit_array_end(*this) ); goto scope_end; + default: log_error("Missing comma between array values"); return TAPE_ERROR; + } + +document_end: + log_end_value("document"); + SIMDJSON_TRY( visitor.visit_document_end(*this) ); + + dom_parser.next_structural_index = uint32_t(next_structural - &dom_parser.structural_indexes[0]); + + // If we didn't make it to the end, it's an error + if ( !STREAMING && dom_parser.next_structural_index != dom_parser.n_structural_indexes ) { + log_error("More than one JSON value at the root of the document, or extra characters at the end of the JSON!"); + return TAPE_ERROR; + } + + return SUCCESS; + +} // walk_document() + +simdjson_inline json_iterator::json_iterator(dom_parser_implementation &_dom_parser, size_t start_structural_index) + : buf{_dom_parser.buf}, + next_structural{&_dom_parser.structural_indexes[start_structural_index]}, + dom_parser{_dom_parser} { +} + +simdjson_inline const uint8_t *json_iterator::peek() const noexcept { + return &buf[*(next_structural)]; +} +simdjson_inline const uint8_t *json_iterator::advance() noexcept { + return &buf[*(next_structural++)]; +} +simdjson_inline size_t json_iterator::remaining_len() const noexcept { + return dom_parser.len - *(next_structural-1); +} + +simdjson_inline bool json_iterator::at_eof() const noexcept { + return next_structural == &dom_parser.structural_indexes[dom_parser.n_structural_indexes]; +} +simdjson_inline bool json_iterator::at_beginning() const noexcept { + return next_structural == dom_parser.structural_indexes.get(); +} +simdjson_inline uint8_t json_iterator::last_structural() const noexcept { + return buf[dom_parser.structural_indexes[dom_parser.n_structural_indexes - 1]]; +} + +simdjson_inline void json_iterator::log_value(const char *type) const noexcept { + logger::log_line(*this, "", type, ""); +} + +simdjson_inline void json_iterator::log_start_value(const char *type) const noexcept { + logger::log_line(*this, "+", type, ""); + if (logger::LOG_ENABLED) { logger::log_depth++; } +} + +simdjson_inline void json_iterator::log_end_value(const char *type) const noexcept { + if (logger::LOG_ENABLED) { logger::log_depth--; } + logger::log_line(*this, "-", type, ""); +} + +simdjson_inline void json_iterator::log_error(const char *error) const noexcept { + logger::log_line(*this, "", "ERROR", error); +} + +template +simdjson_warn_unused simdjson_inline error_code json_iterator::visit_root_primitive(V &visitor, const uint8_t *value) noexcept { + switch (*value) { + case '"': return visitor.visit_root_string(*this, value); + case 't': return visitor.visit_root_true_atom(*this, value); + case 'f': return visitor.visit_root_false_atom(*this, value); + case 'n': return visitor.visit_root_null_atom(*this, value); + case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + return visitor.visit_root_number(*this, value); + default: + log_error("Document starts with a non-value character"); + return TAPE_ERROR; + } +} +template +simdjson_warn_unused simdjson_inline error_code json_iterator::visit_primitive(V &visitor, const uint8_t *value) noexcept { + // Use the fact that most scalars are going to be either strings or numbers. + if(*value == '"') { + return visitor.visit_string(*this, value); + } else if (((*value - '0') < 10) || (*value == '-')) { + return visitor.visit_number(*this, value); + } + // true, false, null are uncommon. + switch (*value) { + case 't': return visitor.visit_true_atom(*this, value); + case 'f': return visitor.visit_false_atom(*this, value); + case 'n': return visitor.visit_null_atom(*this, value); + default: + log_error("Non-value found when value was expected!"); + return TAPE_ERROR; + } +} + +} // namespace stage2 +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_SRC_GENERIC_STAGE2_JSON_ITERATOR_H +/* end file generic/stage2/json_iterator.h for rvv_vls */ +/* including generic/stage2/stringparsing.h for rvv_vls: #include */ +/* begin file generic/stage2/stringparsing.h for rvv_vls */ +#include +#ifndef SIMDJSON_SRC_GENERIC_STAGE2_STRINGPARSING_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_SRC_GENERIC_STAGE2_STRINGPARSING_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +// This file contains the common code every implementation uses +// It is intended to be included multiple times and compiled multiple times + +namespace simdjson { +namespace rvv_vls { +namespace { +/// @private +namespace stringparsing { + +// begin copypasta +// These chars yield themselves: " \ / +// b -> backspace, f -> formfeed, n -> newline, r -> cr, t -> horizontal tab +// u not handled in this table as it's complex +static const uint8_t escape_map[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x0. + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0x22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2f, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x4. + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0, 0, // 0x5. + 0, 0, 0x08, 0, 0, 0, 0x0c, 0, 0, 0, 0, 0, 0, 0, 0x0a, 0, // 0x6. + 0, 0, 0x0d, 0, 0x09, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x7. + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +// handle a unicode codepoint +// write appropriate values into dest +// src will advance 6 bytes or 12 bytes +// dest will advance a variable amount (return via pointer) +// return true if the unicode codepoint was valid +// We work in little-endian then swap at write time +simdjson_warn_unused +simdjson_inline bool handle_unicode_codepoint(const uint8_t **src_ptr, + uint8_t **dst_ptr, bool allow_replacement) { + // Use the default Unicode Character 'REPLACEMENT CHARACTER' (U+FFFD) + constexpr uint32_t substitution_code_point = 0xfffd; + // jsoncharutils::hex_to_u32_nocheck fills high 16 bits of the return value with 1s if the + // conversion is not valid; we defer the check for this to inside the + // multilingual plane check. + uint32_t code_point = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2); + *src_ptr += 6; + + // If we found a high surrogate, we must + // check for low surrogate for characters + // outside the Basic + // Multilingual Plane. + if (code_point >= 0xd800 && code_point < 0xdc00) { + const uint8_t *src_data = *src_ptr; + /* Compiler optimizations convert this to a single 16-bit load and compare on most platforms */ + if (((src_data[0] << 8) | src_data[1]) != ((static_cast ('\\') << 8) | static_cast ('u'))) { + if(!allow_replacement) { return false; } + code_point = substitution_code_point; + } else { + uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(src_data + 2); + + // We have already checked that the high surrogate is valid and + // (code_point - 0xd800) < 1024. + // + // Check that code_point_2 is in the range 0xdc00..0xdfff + // and that code_point_2 was parsed from valid hex. + uint32_t low_bit = code_point_2 - 0xdc00; + if (low_bit >> 10) { + if(!allow_replacement) { return false; } + code_point = substitution_code_point; + } else { + code_point = (((code_point - 0xd800) << 10) | low_bit) + 0x10000; + *src_ptr += 6; + } + + } + } else if (code_point >= 0xdc00 && code_point <= 0xdfff) { + // If we encounter a low surrogate (not preceded by a high surrogate) + // then we have an error. + if(!allow_replacement) { return false; } + code_point = substitution_code_point; + } + size_t offset = jsoncharutils::codepoint_to_utf8(code_point, *dst_ptr); + *dst_ptr += offset; + return offset > 0; +} + + +// handle a unicode codepoint using the wobbly convention +// https://simonsapin.github.io/wtf-8/ +// write appropriate values into dest +// src will advance 6 bytes or 12 bytes +// dest will advance a variable amount (return via pointer) +// return true if the unicode codepoint was valid +// We work in little-endian then swap at write time +simdjson_warn_unused +simdjson_inline bool handle_unicode_codepoint_wobbly(const uint8_t **src_ptr, + uint8_t **dst_ptr) { + // It is not ideal that this function is nearly identical to handle_unicode_codepoint. + // + // jsoncharutils::hex_to_u32_nocheck fills high 16 bits of the return value with 1s if the + // conversion is not valid; we defer the check for this to inside the + // multilingual plane check. + uint32_t code_point = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2); + *src_ptr += 6; + // If we found a high surrogate, we must + // check for low surrogate for characters + // outside the Basic + // Multilingual Plane. + if (code_point >= 0xd800 && code_point < 0xdc00) { + const uint8_t *src_data = *src_ptr; + /* Compiler optimizations convert this to a single 16-bit load and compare on most platforms */ + if (((src_data[0] << 8) | src_data[1]) == ((static_cast ('\\') << 8) | static_cast ('u'))) { + uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(src_data + 2); + uint32_t low_bit = code_point_2 - 0xdc00; + if ((low_bit >> 10) == 0) { + code_point = + (((code_point - 0xd800) << 10) | low_bit) + 0x10000; + *src_ptr += 6; + } + } + } + + size_t offset = jsoncharutils::codepoint_to_utf8(code_point, *dst_ptr); + *dst_ptr += offset; + return offset > 0; +} + + +/** + * Unescape a valid UTF-8 string from src to dst, stopping at a final unescaped quote. There + * must be an unescaped quote terminating the string. It returns the final output + * position as pointer. In case of error (e.g., the string has bad escaped codes), + * then null_ptr is returned. It is assumed that the output buffer is large + * enough. E.g., if src points at 'joe"', then dst needs to have four free bytes + + * SIMDJSON_PADDING bytes. + */ +simdjson_warn_unused simdjson_inline uint8_t *parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) { + while (1) { + // Copy the next n bytes, and find the backslash and quote in them. + auto b = backslash_and_quote{}; + auto bs_quote = b.copy_and_find(src, dst); + // If the next thing is the end quote, copy and return + if (bs_quote.has_quote_first()) { + // we encountered quotes first. Move dst to point to quotes and exit + return dst + bs_quote.quote_index(); + } + if (bs_quote.has_backslash()) { + /* find out where the backspace is */ + auto bs_dist = bs_quote.backslash_index(); + uint8_t escape_char = src[bs_dist + 1]; + /* we encountered backslash first. Handle backslash */ + if (escape_char == 'u') { + /* move src/dst up to the start; they will be further adjusted + within the unicode codepoint handling code. */ + src += bs_dist; + dst += bs_dist; + if (!handle_unicode_codepoint(&src, &dst, allow_replacement)) { + return nullptr; + } + } else { + /* simple 1:1 conversion. Will eat bs_dist+2 characters in input and + * write bs_dist+1 characters to output + * note this may reach beyond the part of the buffer we've actually + * seen. I think this is ok */ + uint8_t escape_result = escape_map[escape_char]; + if (escape_result == 0u) { + return nullptr; /* bogus escape value is an error */ + } + dst[bs_dist] = escape_result; + src += bs_dist + 2; + dst += bs_dist + 1; + } + } else { + /* they are the same. Since they can't co-occur, it means we + * encountered neither. */ + src += backslash_and_quote::BYTES_PROCESSED; + dst += backslash_and_quote::BYTES_PROCESSED; + } + } +} + +simdjson_warn_unused simdjson_inline uint8_t *parse_wobbly_string(const uint8_t *src, uint8_t *dst) { + // It is not ideal that this function is nearly identical to parse_string. + while (1) { + // Copy the next n bytes, and find the backslash and quote in them. + auto b = backslash_and_quote{}; + auto bs_quote = b.copy_and_find(src, dst); + // If the next thing is the end quote, copy and return + if (bs_quote.has_quote_first()) { + // we encountered quotes first. Move dst to point to quotes and exit + return dst + bs_quote.quote_index(); + } + if (bs_quote.has_backslash()) { + /* find out where the backspace is */ + auto bs_dist = bs_quote.backslash_index(); + uint8_t escape_char = src[bs_dist + 1]; + /* we encountered backslash first. Handle backslash */ + if (escape_char == 'u') { + /* move src/dst up to the start; they will be further adjusted + within the unicode codepoint handling code. */ + src += bs_dist; + dst += bs_dist; + if (!handle_unicode_codepoint_wobbly(&src, &dst)) { + return nullptr; + } + } else { + /* simple 1:1 conversion. Will eat bs_dist+2 characters in input and + * write bs_dist+1 characters to output + * note this may reach beyond the part of the buffer we've actually + * seen. I think this is ok */ + uint8_t escape_result = escape_map[escape_char]; + if (escape_result == 0u) { + return nullptr; /* bogus escape value is an error */ + } + dst[bs_dist] = escape_result; + src += bs_dist + 2; + dst += bs_dist + 1; + } + } else { + /* they are the same. Since they can't co-occur, it means we + * encountered neither. */ + src += backslash_and_quote::BYTES_PROCESSED; + dst += backslash_and_quote::BYTES_PROCESSED; + } + } +} + +} // namespace stringparsing + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_SRC_GENERIC_STAGE2_STRINGPARSING_H +/* end file generic/stage2/stringparsing.h for rvv_vls */ +/* including generic/stage2/structural_iterator.h for rvv_vls: #include */ +/* begin file generic/stage2/structural_iterator.h for rvv_vls */ +#ifndef SIMDJSON_SRC_GENERIC_STAGE2_STRUCTURAL_ITERATOR_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_SRC_GENERIC_STAGE2_STRUCTURAL_ITERATOR_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace stage2 { + +class structural_iterator { +public: + const uint8_t* const buf; + uint32_t *next_structural; + dom_parser_implementation &dom_parser; + + // Start a structural + simdjson_inline structural_iterator(dom_parser_implementation &_dom_parser, size_t start_structural_index) + : buf{_dom_parser.buf}, + next_structural{&_dom_parser.structural_indexes[start_structural_index]}, + dom_parser{_dom_parser} { + } + // Get the buffer position of the current structural character + simdjson_inline const uint8_t* current() { + return &buf[*(next_structural-1)]; + } + // Get the current structural character + simdjson_inline char current_char() { + return buf[*(next_structural-1)]; + } + // Get the next structural character without advancing + simdjson_inline char peek_next_char() { + return buf[*next_structural]; + } + simdjson_inline const uint8_t* peek() { + return &buf[*next_structural]; + } + simdjson_inline const uint8_t* advance() { + return &buf[*(next_structural++)]; + } + simdjson_inline char advance_char() { + return buf[*(next_structural++)]; + } + simdjson_inline size_t remaining_len() { + return dom_parser.len - *(next_structural-1); + } + + simdjson_inline bool at_end() { + return next_structural == &dom_parser.structural_indexes[dom_parser.n_structural_indexes]; + } + simdjson_inline bool at_beginning() { + return next_structural == dom_parser.structural_indexes.get(); + } +}; + +} // namespace stage2 +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_SRC_GENERIC_STAGE2_STRUCTURAL_ITERATOR_H +/* end file generic/stage2/structural_iterator.h for rvv_vls */ +/* including generic/stage2/tape_builder.h for rvv_vls: #include */ +/* begin file generic/stage2/tape_builder.h for rvv_vls */ +#ifndef SIMDJSON_SRC_GENERIC_STAGE2_TAPE_BUILDER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_SRC_GENERIC_STAGE2_TAPE_BUILDER_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace stage2 { + +struct tape_builder { + template + simdjson_warn_unused static simdjson_inline error_code parse_document( + dom_parser_implementation &dom_parser, + dom::document &doc) noexcept; + + /** Called when a non-empty document starts. */ + simdjson_warn_unused simdjson_inline error_code visit_document_start(json_iterator &iter) noexcept; + /** Called when a non-empty document ends without error. */ + simdjson_warn_unused simdjson_inline error_code visit_document_end(json_iterator &iter) noexcept; + + /** Called when a non-empty array starts. */ + simdjson_warn_unused simdjson_inline error_code visit_array_start(json_iterator &iter) noexcept; + /** Called when a non-empty array ends. */ + simdjson_warn_unused simdjson_inline error_code visit_array_end(json_iterator &iter) noexcept; + /** Called when an empty array is found. */ + simdjson_warn_unused simdjson_inline error_code visit_empty_array(json_iterator &iter) noexcept; + + /** Called when a non-empty object starts. */ + simdjson_warn_unused simdjson_inline error_code visit_object_start(json_iterator &iter) noexcept; + /** + * Called when a key in a field is encountered. + * + * primitive, visit_object_start, visit_empty_object, visit_array_start, or visit_empty_array + * will be called after this with the field value. + */ + simdjson_warn_unused simdjson_inline error_code visit_key(json_iterator &iter, const uint8_t *key) noexcept; + /** Called when a non-empty object ends. */ + simdjson_warn_unused simdjson_inline error_code visit_object_end(json_iterator &iter) noexcept; + /** Called when an empty object is found. */ + simdjson_warn_unused simdjson_inline error_code visit_empty_object(json_iterator &iter) noexcept; + + /** + * Called when a string, number, boolean or null is found. + */ + simdjson_warn_unused simdjson_inline error_code visit_primitive(json_iterator &iter, const uint8_t *value) noexcept; + /** + * Called when a string, number, boolean or null is found at the top level of a document (i.e. + * when there is no array or object and the entire document is a single string, number, boolean or + * null. + * + * This is separate from primitive() because simdjson's normal primitive parsing routines assume + * there is at least one more token after the value, which is only true in an array or object. + */ + simdjson_warn_unused simdjson_inline error_code visit_root_primitive(json_iterator &iter, const uint8_t *value) noexcept; + + simdjson_warn_unused simdjson_inline error_code visit_string(json_iterator &iter, const uint8_t *value, bool key = false) noexcept; + simdjson_warn_unused simdjson_inline error_code visit_number(json_iterator &iter, const uint8_t *value) noexcept; + simdjson_warn_unused simdjson_inline error_code visit_true_atom(json_iterator &iter, const uint8_t *value) noexcept; + simdjson_warn_unused simdjson_inline error_code visit_false_atom(json_iterator &iter, const uint8_t *value) noexcept; + simdjson_warn_unused simdjson_inline error_code visit_null_atom(json_iterator &iter, const uint8_t *value) noexcept; + + simdjson_warn_unused simdjson_inline error_code visit_root_string(json_iterator &iter, const uint8_t *value) noexcept; + simdjson_warn_unused simdjson_inline error_code visit_root_number(json_iterator &iter, const uint8_t *value) noexcept; + simdjson_warn_unused simdjson_inline error_code visit_root_true_atom(json_iterator &iter, const uint8_t *value) noexcept; + simdjson_warn_unused simdjson_inline error_code visit_root_false_atom(json_iterator &iter, const uint8_t *value) noexcept; + simdjson_warn_unused simdjson_inline error_code visit_root_null_atom(json_iterator &iter, const uint8_t *value) noexcept; + + /** Called each time a new field or element in an array or object is found. */ + simdjson_warn_unused simdjson_inline error_code increment_count(json_iterator &iter) noexcept; + + /** Next location to write to tape */ + tape_writer tape; +private: + /** Next write location in the string buf for stage 2 parsing */ + uint8_t *current_string_buf_loc; + + simdjson_inline tape_builder(dom::document &doc) noexcept; + + simdjson_inline uint32_t next_tape_index(json_iterator &iter) const noexcept; + simdjson_inline void start_container(json_iterator &iter) noexcept; + simdjson_warn_unused simdjson_inline error_code end_container(json_iterator &iter, internal::tape_type start, internal::tape_type end) noexcept; + simdjson_warn_unused simdjson_inline error_code empty_container(json_iterator &iter, internal::tape_type start, internal::tape_type end) noexcept; + simdjson_inline uint8_t *on_start_string(json_iterator &iter) noexcept; + simdjson_inline void on_end_string(uint8_t *dst) noexcept; +}; // struct tape_builder + +template +simdjson_warn_unused simdjson_inline error_code tape_builder::parse_document( + dom_parser_implementation &dom_parser, + dom::document &doc) noexcept { + dom_parser.doc = &doc; + json_iterator iter(dom_parser, STREAMING ? dom_parser.next_structural_index : 0); + tape_builder builder(doc); + return iter.walk_document(builder); +} + +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_primitive(json_iterator &iter, const uint8_t *value) noexcept { + return iter.visit_root_primitive(*this, value); +} +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_primitive(json_iterator &iter, const uint8_t *value) noexcept { + return iter.visit_primitive(*this, value); +} +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_empty_object(json_iterator &iter) noexcept { + return empty_container(iter, internal::tape_type::START_OBJECT, internal::tape_type::END_OBJECT); +} +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_empty_array(json_iterator &iter) noexcept { + return empty_container(iter, internal::tape_type::START_ARRAY, internal::tape_type::END_ARRAY); +} + +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_document_start(json_iterator &iter) noexcept { + start_container(iter); + return SUCCESS; +} +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_object_start(json_iterator &iter) noexcept { + start_container(iter); + return SUCCESS; +} +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_array_start(json_iterator &iter) noexcept { + start_container(iter); + return SUCCESS; +} + +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_object_end(json_iterator &iter) noexcept { + return end_container(iter, internal::tape_type::START_OBJECT, internal::tape_type::END_OBJECT); +} +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_array_end(json_iterator &iter) noexcept { + return end_container(iter, internal::tape_type::START_ARRAY, internal::tape_type::END_ARRAY); +} +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_document_end(json_iterator &iter) noexcept { + constexpr uint32_t start_tape_index = 0; + tape.append(start_tape_index, internal::tape_type::ROOT); + tape_writer::write(iter.dom_parser.doc->tape[start_tape_index], next_tape_index(iter), internal::tape_type::ROOT); + return SUCCESS; +} +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_key(json_iterator &iter, const uint8_t *key) noexcept { + return visit_string(iter, key, true); +} + +simdjson_warn_unused simdjson_inline error_code tape_builder::increment_count(json_iterator &iter) noexcept { + iter.dom_parser.open_containers[iter.depth].count++; // we have a key value pair in the object at parser.dom_parser.depth - 1 + return SUCCESS; +} + +simdjson_inline tape_builder::tape_builder(dom::document &doc) noexcept : tape{doc.tape.get()}, current_string_buf_loc{doc.string_buf.get()} {} + +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_string(json_iterator &iter, const uint8_t *value, bool key) noexcept { + iter.log_value(key ? "key" : "string"); + uint8_t *dst = on_start_string(iter); + dst = stringparsing::parse_string(value+1, dst, false); // We do not allow replacement when the escape characters are invalid. + if (dst == nullptr) { + iter.log_error("Invalid escape in string"); + return STRING_ERROR; + } + on_end_string(dst); + return SUCCESS; +} + +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_string(json_iterator &iter, const uint8_t *value) noexcept { + return visit_string(iter, value); +} + +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_iterator &iter, const uint8_t *value) noexcept { + iter.log_value("number"); + return numberparsing::parse_number(value, tape); +} + +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_number(json_iterator &iter, const uint8_t *value) noexcept { + // + // We need to make a copy to make sure that the string is space terminated. + // This is not about padding the input, which should already padded up + // to len + SIMDJSON_PADDING. However, we have no control at this stage + // on how the padding was done. What if the input string was padded with nulls? + // It is quite common for an input string to have an extra null character (C string). + // We do not want to allow 9\0 (where \0 is the null character) inside a JSON + // document, but the string "9\0" by itself is fine. So we make a copy and + // pad the input with spaces when we know that there is just one input element. + // This copy is relatively expensive, but it will almost never be called in + // practice unless you are in the strange scenario where you have many JSON + // documents made of single atoms. + // + std::unique_ptrcopy(new (std::nothrow) uint8_t[iter.remaining_len() + SIMDJSON_PADDING]); + if (copy.get() == nullptr) { return MEMALLOC; } + std::memcpy(copy.get(), value, iter.remaining_len()); + std::memset(copy.get() + iter.remaining_len(), ' ', SIMDJSON_PADDING); + error_code error = visit_number(iter, copy.get()); + return error; +} + +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_true_atom(json_iterator &iter, const uint8_t *value) noexcept { + iter.log_value("true"); + if (!atomparsing::is_valid_true_atom(value)) { return T_ATOM_ERROR; } + tape.append(0, internal::tape_type::TRUE_VALUE); + return SUCCESS; +} + +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_true_atom(json_iterator &iter, const uint8_t *value) noexcept { + iter.log_value("true"); + if (!atomparsing::is_valid_true_atom(value, iter.remaining_len())) { return T_ATOM_ERROR; } + tape.append(0, internal::tape_type::TRUE_VALUE); + return SUCCESS; +} + +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_false_atom(json_iterator &iter, const uint8_t *value) noexcept { + iter.log_value("false"); + if (!atomparsing::is_valid_false_atom(value)) { return F_ATOM_ERROR; } + tape.append(0, internal::tape_type::FALSE_VALUE); + return SUCCESS; +} + +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_false_atom(json_iterator &iter, const uint8_t *value) noexcept { + iter.log_value("false"); + if (!atomparsing::is_valid_false_atom(value, iter.remaining_len())) { return F_ATOM_ERROR; } + tape.append(0, internal::tape_type::FALSE_VALUE); + return SUCCESS; +} + +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_null_atom(json_iterator &iter, const uint8_t *value) noexcept { + iter.log_value("null"); + if (!atomparsing::is_valid_null_atom(value)) { return N_ATOM_ERROR; } + tape.append(0, internal::tape_type::NULL_VALUE); + return SUCCESS; +} + +simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_null_atom(json_iterator &iter, const uint8_t *value) noexcept { + iter.log_value("null"); + if (!atomparsing::is_valid_null_atom(value, iter.remaining_len())) { return N_ATOM_ERROR; } + tape.append(0, internal::tape_type::NULL_VALUE); + return SUCCESS; +} + +// private: + +simdjson_inline uint32_t tape_builder::next_tape_index(json_iterator &iter) const noexcept { + return uint32_t(tape.next_tape_loc - iter.dom_parser.doc->tape.get()); +} + +simdjson_warn_unused simdjson_inline error_code tape_builder::empty_container(json_iterator &iter, internal::tape_type start, internal::tape_type end) noexcept { + auto start_index = next_tape_index(iter); + tape.append(start_index+2, start); + tape.append(start_index, end); + return SUCCESS; +} + +simdjson_inline void tape_builder::start_container(json_iterator &iter) noexcept { + iter.dom_parser.open_containers[iter.depth].tape_index = next_tape_index(iter); + iter.dom_parser.open_containers[iter.depth].count = 0; + tape.skip(); // We don't actually *write* the start element until the end. +} + +simdjson_warn_unused simdjson_inline error_code tape_builder::end_container(json_iterator &iter, internal::tape_type start, internal::tape_type end) noexcept { + // Write the ending tape element, pointing at the start location + const uint32_t start_tape_index = iter.dom_parser.open_containers[iter.depth].tape_index; + tape.append(start_tape_index, end); + // Write the start tape element, pointing at the end location (and including count) + // count can overflow if it exceeds 24 bits... so we saturate + // the convention being that a cnt of 0xffffff or more is undetermined in value (>= 0xffffff). + const uint32_t count = iter.dom_parser.open_containers[iter.depth].count; + const uint32_t cntsat = count > 0xFFFFFF ? 0xFFFFFF : count; + tape_writer::write(iter.dom_parser.doc->tape[start_tape_index], next_tape_index(iter) | (uint64_t(cntsat) << 32), start); + return SUCCESS; +} + +simdjson_inline uint8_t *tape_builder::on_start_string(json_iterator &iter) noexcept { + // we advance the point, accounting for the fact that we have a NULL termination + tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::STRING); + return current_string_buf_loc + sizeof(uint32_t); +} + +simdjson_inline void tape_builder::on_end_string(uint8_t *dst) noexcept { + uint32_t str_length = uint32_t(dst - (current_string_buf_loc + sizeof(uint32_t))); + // TODO check for overflow in case someone has a crazy string (>=4GB?) + // But only add the overflow check when the document itself exceeds 4GB + // Currently unneeded because we refuse to parse docs larger or equal to 4GB. + memcpy(current_string_buf_loc, &str_length, sizeof(uint32_t)); + // NULL termination is still handy if you expect all your strings to + // be NULL terminated? It comes at a small cost + *dst = 0; + current_string_buf_loc = dst + 1; +} + +} // namespace stage2 +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_SRC_GENERIC_STAGE2_TAPE_BUILDER_H +/* end file generic/stage2/tape_builder.h for rvv_vls */ +/* end file generic/stage2/amalgamated.h for rvv_vls */ + +// +// Stage 1 +// +namespace simdjson { +namespace rvv_vls { + +simdjson_warn_unused error_code implementation::create_dom_parser_implementation( + size_t capacity, + size_t max_depth, + std::unique_ptr& dst +) const noexcept { + dst.reset( new (std::nothrow) dom_parser_implementation() ); + if (!dst) { return MEMALLOC; } + if (auto err = dst->set_capacity(capacity)) + return err; + if (auto err = dst->set_max_depth(max_depth)) + return err; + return SUCCESS; +} + +namespace { + +using namespace simd; + +simdjson_inline json_character_block json_character_block::classify(const simd::simd8x64& in) { + static const uint8_t wsTable[16] = { ' ', 100, 100, 100, 17, 100, 113, 2, 100, '\t', '\n', 112, 100, '\r', 100, 100 }; + static const uint8_t opTable[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ':', '{', ',', '}', 0, 0 }; + vuint8_t vws = __riscv_vle8_v_u8m1(wsTable, 16); + vuint8_t vop = __riscv_vle8_v_u8m1(opTable, 16); + vuint8x64_t lo = __riscv_vand(in, 15, 64); + vuint8x64_t curl = __riscv_vor(in, 0x20, 64); + +#if __riscv_v_fixed_vlen == 128 + vboolx64_t mws = __riscv_vmseq(simdutf_vrgather_u8m1x4(vws, lo), in, 64); + vboolx64_t mop = __riscv_vmseq(simdutf_vrgather_u8m1x4(vop, lo), curl, 64); +#elif __riscv_v_fixed_vlen == 256 + vboolx64_t mws = __riscv_vmseq(simdutf_vrgather_u8m1x2(vws, lo), in, 64); + vboolx64_t mop = __riscv_vmseq(simdutf_vrgather_u8m1x2(vop, lo), curl, 64); +#else + vboolx64_t mws = __riscv_vmseq(__riscv_vrgather(vws, lo, 64), in, 64); + vboolx64_t mop = __riscv_vmseq(__riscv_vrgather(vop, lo, 64), curl, 64); +#endif + + return { + __riscv_vmv_x(__riscv_vreinterpret_u64m1(mws)), + __riscv_vmv_x(__riscv_vreinterpret_u64m1(mop)) + }; +} + +simdjson_inline bool is_ascii(const simd8x64& input) { + return input.is_ascii(); +} + +simdjson_inline simd8 must_be_2_3_continuation(const simd8 prev2, const simd8 prev3) { + simd8 is_third_byte = prev2.saturating_sub(0xe0u-0x80); // Only 111_____ will be >= 0x80 + simd8 is_fourth_byte = prev3.saturating_sub(0xf0u-0x80); // Only 1111____ will be >= 0x80 + return is_third_byte | is_fourth_byte; +} + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +// +// Stage 2 +// + +// +// Implementation-specific overrides +// +namespace simdjson { +namespace rvv_vls { + +simdjson_warn_unused error_code implementation::minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept { + return rvv_vls::stage1::json_minifier::minify<64>(buf, len, dst, dst_len); +} + +simdjson_warn_unused error_code dom_parser_implementation::stage1(const uint8_t *_buf, size_t _len, stage1_mode streaming) noexcept { + this->buf = _buf; + this->len = _len; + return rvv_vls::stage1::json_structural_indexer::index<64>(buf, len, *this, streaming); +} + +simdjson_warn_unused bool implementation::validate_utf8(const char *buf, size_t len) const noexcept { + return rvv_vls::stage1::generic_validate_utf8(buf,len); +} + +simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept { + return stage2::tape_builder::parse_document(*this, _doc); +} + +simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept { + return stage2::tape_builder::parse_document(*this, _doc); +} + +SIMDJSON_NO_SANITIZE_MEMORY +simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept { + return rvv_vls::stringparsing::parse_string(src, dst, allow_replacement); +} + +simdjson_warn_unused uint8_t *dom_parser_implementation::parse_wobbly_string(const uint8_t *src, uint8_t *dst) const noexcept { + return rvv_vls::stringparsing::parse_wobbly_string(src, dst); +} + +simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept { + auto error = stage1(_buf, _len, stage1_mode::regular); + if (error) { return error; } + return stage2(_doc); +} + +} // namespace rvv_vls +} // namespace simdjson + +/* including simdjson/rvv-vls/end.h: #include */ +/* begin file simdjson/rvv-vls/end.h */ +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +/* undefining SIMDJSON_IMPLEMENTATION from "rvv_vls" */ +#undef SIMDJSON_IMPLEMENTATION +/* end file simdjson/rvv-vls/end.h */ + +#endif // SIMDJSON_SRC_RVV_VLS_CPP +/* end file rvv-vls.cpp */ +#endif #if SIMDJSON_IMPLEMENTATION_FALLBACK /* including fallback.cpp: #include */ /* begin file fallback.cpp */ @@ -54484,6 +61122,8 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t /* amalgamation skipped (editor-only): #include "simdjson/lasx/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_LSX */ /* amalgamation skipped (editor-only): #include "simdjson/lsx/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_RVV_VLS */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_FALLBACK */ /* amalgamation skipped (editor-only): #include "simdjson/fallback/begin.h" */ /* amalgamation skipped (editor-only): #else */ diff --git a/singleheader/simdjson.h b/singleheader/simdjson.h index b956bb188..23df944b0 100644 --- a/singleheader/simdjson.h +++ b/singleheader/simdjson.h @@ -1,4 +1,4 @@ -/* auto-generated on 2026-01-17 14:20:47 -0500. version 4.2.4 Do not edit! */ +/* auto-generated on 2026-02-18 20:08:53 -0500. version 4.3.0 Do not edit! */ /* including simdjson.h: */ /* begin file simdjson.h */ #ifndef SIMDJSON_H @@ -218,22 +218,20 @@ using std::size_t; #define SIMDJSON_IS_ARM64 1 #elif defined(__riscv) && __riscv_xlen == 64 #define SIMDJSON_IS_RISCV64 1 + #if __riscv_v_intrinsic >= 11000 #define SIMDJSON_HAS_RVV_INTRINSICS 1 #endif - #define SIMDJSON_HAS_ZVBB_INTRINSICS \ - 0 // there is currently no way to detect this - - #if SIMDJSON_HAS_RVV_INTRINSICS && __riscv_vector && \ - __riscv_v_min_vlen >= 128 && __riscv_v_elen >= 64 - // RISC-V V extension - #define SIMDJSON_IS_RVV 1 - #if SIMDJSON_HAS_ZVBB_INTRINSICS && __riscv_zvbb >= 1000000 - // RISC-V Vector Basic Bit-manipulation - #define SIMDJSON_IS_ZVBB 1 - #endif + #if SIMDJSON_HAS_RVV_INTRINSICS && __riscv_vector && __riscv_v_min_vlen >= 128 && __riscv_v_elen >= 64 + #define SIMDJSON_IS_RVV 1 // RISC-V V extension #endif + + // current toolchains don't support fixed-size SIMD types that don't match VLEN directly + #if __riscv_v_fixed_vlen >= 128 && __riscv_v_fixed_vlen <= 512 + #define SIMDJSON_IS_RVV_VLS 1 + #endif + #elif defined(__loongarch_lp64) #define SIMDJSON_IS_LOONGARCH64 1 #if defined(__loongarch_sx) && defined(__loongarch_asx) @@ -2522,7 +2520,7 @@ namespace std { #define SIMDJSON_SIMDJSON_VERSION_H /** The version of simdjson being used (major.minor.revision) */ -#define SIMDJSON_VERSION "4.2.4" +#define SIMDJSON_VERSION "4.3.0" namespace simdjson { enum { @@ -2533,11 +2531,11 @@ enum { /** * The minor version (major.MINOR.revision) of simdjson being used. */ - SIMDJSON_VERSION_MINOR = 2, + SIMDJSON_VERSION_MINOR = 3, /** * The revision (major.minor.REVISION) of simdjson being used. */ - SIMDJSON_VERSION_REVISION = 4 + SIMDJSON_VERSION_REVISION = 0 }; } // namespace simdjson @@ -4149,6 +4147,16 @@ struct padded_string final { **/ char *data() noexcept; + /** + * Append data to the padded string. Return true on success, false on failure. + * The complexity is O(n) where n is the new size of the string. If you are + * doing multiple appends, consider using padded_string_builder for better performance. + * + * @param data the buffer to append + * @param length the number of bytes to append + */ + inline bool append(const char *data, size_t length) noexcept; + /** * Create a std::string_view with the same content. */ @@ -4192,6 +4200,7 @@ struct padded_string final { #endif private: + friend class padded_string_builder; padded_string &operator=(const padded_string &o) = delete; padded_string(const padded_string &o) = delete; @@ -4200,6 +4209,101 @@ private: }; // padded_string +/** + * Builder for constructing padded_string incrementally. + * + * This class allows efficient appending of data and then building a padded_string. + */ +class padded_string_builder { +public: + /** + * Create a new, empty padded string builder. + */ + inline padded_string_builder() noexcept; + + /** + * Create a new padded string builder with initial capacity. + * + * @param capacity the initial capacity of the builder. + */ + inline padded_string_builder(size_t capacity) noexcept; + + /** + * Move constructor. + */ + inline padded_string_builder(padded_string_builder &&o) noexcept; + + /** + * Move assignment. + */ + inline padded_string_builder &operator=(padded_string_builder &&o) noexcept; + + /** + * Copy constructor (deleted). + */ + padded_string_builder(const padded_string_builder &) = delete; + + /** + * Copy assignment (deleted). + */ + padded_string_builder &operator=(const padded_string_builder &) = delete; + + /** + * Destructor. + */ + inline ~padded_string_builder() noexcept; + + /** + * Append data to the builder. + * + * @param newdata the buffer to append + * @param length the number of bytes to append + * @return true if the append succeeded, false if allocation failed + */ + inline bool append(const char *newdata, size_t length) noexcept; + + /** + * Append a string view to the builder. + * + * @param sv the string view to append + * @return true if the append succeeded, false if allocation failed + */ + inline bool append(std::string_view sv) noexcept; + + /** + * Get the current length of the built string. + */ + inline size_t length() const noexcept; + + /** + * Build a padded_string from the current content. The builder's content + * is not modified. If you want to avoid the copy, use convert() instead. + * + * @return a padded_string containing a copy of the built content. + */ + inline padded_string build() const noexcept; + + /** + * Convert the current content into a padded_string. The + * builder's content is emptied, the capacity is lost. + * + * @return a padded_string containing the built content. + */ + inline padded_string convert() noexcept; +private: + size_t size{0}; + size_t capacity{0}; + char *data{nullptr}; + + /** + * Ensure the builder has enough capacity. + * + * @param additional the additional capacity needed. + * @return true if the reservation succeeded, false if allocation failed + */ + inline bool reserve(size_t additional) noexcept; +}; + /** * Send padded_string instance to an output stream. * @@ -4620,6 +4724,33 @@ inline const char *padded_string::data() const noexcept { return data_ptr; } inline char *padded_string::data() noexcept { return data_ptr; } +inline bool padded_string::append(const char *data, size_t length) noexcept { + if (length == 0) { + return true; // Nothing to append + } + size_t new_size = viable_size + length; + if (new_size < viable_size) { + // Overflow, cannot append + return false; + } + char *new_data_ptr = internal::allocate_padded_buffer(new_size); + if (new_data_ptr == nullptr) { + // Allocation failed, cannot append + return false; + } + // Copy existing data + if (viable_size > 0) { + std::memcpy(new_data_ptr, data_ptr, viable_size); + } + // Copy new data + std::memcpy(new_data_ptr + viable_size, data, length); + // Update + delete[] data_ptr; + data_ptr = new_data_ptr; + viable_size = new_size; + return true; +} + inline padded_string::operator std::string_view() const simdjson_lifetime_bound { return std::string_view(data(), length()); } inline padded_string::operator padded_string_view() const noexcept simdjson_lifetime_bound { @@ -4736,6 +4867,103 @@ inline simdjson_result padded_string::load(std::wstring_view file } #endif +// padded_string_builder implementations + +inline padded_string_builder::padded_string_builder() noexcept = default; + +inline padded_string_builder::padded_string_builder(size_t new_capacity) noexcept { + if (new_capacity > 0) { + data = internal::allocate_padded_buffer(new_capacity); + if (data != nullptr) { + this->capacity = new_capacity; + } + } +} + +inline padded_string_builder::padded_string_builder(padded_string_builder &&o) noexcept + : size(o.size), capacity(o.capacity), data(o.data) { + o.size = 0; + o.capacity = 0; + o.data = nullptr; +} + +inline padded_string_builder &padded_string_builder::operator=(padded_string_builder &&o) noexcept { + if (this != &o) { + delete[] data; + size = o.size; + capacity = o.capacity; + data = o.data; + o.size = 0; + o.capacity = 0; + o.data = nullptr; + } + return *this; +} + +inline padded_string_builder::~padded_string_builder() noexcept { + delete[] data; +} + +inline bool padded_string_builder::append(const char *newdata, size_t length) noexcept { + if (length == 0) { + return true; + } + if (!reserve(length)) { + return false; + } + std::memcpy(data + size, newdata, length); + size += length; + return true; +} + +inline bool padded_string_builder::append(std::string_view sv) noexcept { + return append(sv.data(), sv.size()); +} + +inline size_t padded_string_builder::length() const noexcept { + return size; +} + +inline padded_string padded_string_builder::build() const noexcept { + return padded_string(data, size); +} + +inline padded_string padded_string_builder::convert() noexcept { + padded_string result{}; + result.data_ptr = data; + result.viable_size = size; + data = nullptr; + size = 0; + capacity = 0; + return result; +} + +inline bool padded_string_builder::reserve(size_t additional) noexcept { + size_t needed = size + additional; + if (needed <= capacity) { + return true; + } + size_t new_capacity = needed; + // We are going to grow the capacity exponentially to avoid + // repeated allocations. + if (new_capacity < 4096) { + new_capacity *= 2; + } else { + new_capacity += new_capacity/2; // grow by 1.5x + } + char *new_data = internal::allocate_padded_buffer(new_capacity); + if (new_data == nullptr) { + return false; // Allocation failed + } + if (size > 0) { + std::memcpy(new_data, data, size); + } + delete[] data; + data = new_data; + capacity = new_capacity; + return true; +} + } // namespace simdjson inline simdjson::padded_string operator ""_padded(const char *str, size_t len) { @@ -7398,6 +7626,168 @@ template std::string prettify(simdjson_result x) { #endif /* end file simdjson/dom/serialization.h */ +/* including simdjson/dom/fractured_json.h: #include "simdjson/dom/fractured_json.h" */ +/* begin file simdjson/dom/fractured_json.h */ +#ifndef SIMDJSON_DOM_FRACTURED_JSON_H +#define SIMDJSON_DOM_FRACTURED_JSON_H + +/* skipped duplicate #include "simdjson/dom/base.h" */ +/* skipped duplicate #include "simdjson/dom/element.h" */ + +namespace simdjson { + +/** + * Configuration options for FracturedJson formatting. + * + * FracturedJson intelligently chooses between different layout strategies + * (inline, compact multiline, table, expanded) based on content complexity, + * length, and structure similarity. + */ +struct fractured_json_options { + /** + * Maximum total characters per line (default: 120). + * Content exceeding this will be expanded to multiple lines. + */ + size_t max_total_line_length = 120; + + /** + * Maximum length for inlined elements (default: 80). + * Simple arrays/objects shorter than this may be rendered inline. + */ + size_t max_inline_length = 80; + + /** + * Maximum nesting depth for inline rendering (default: 2). + * Elements with complexity exceeding this will be expanded. + * Complexity 0 = scalar, 1 = flat array/object, 2 = one level of nesting. + */ + size_t max_inline_complexity = 2; + + /** + * Maximum complexity for compact array formatting (default: 1). + * Arrays with elements of this complexity or less may have multiple + * items per line. + */ + size_t max_compact_array_complexity = 1; + + /** + * Number of spaces per indentation level (default: 4). + */ + size_t indent_spaces = 4; + + /** + * Enable tabular formatting for arrays of similar objects (default: true). + * When enabled, arrays of objects with identical keys are formatted + * as aligned tables. + */ + bool enable_table_format = true; + + /** + * Minimum number of rows to trigger table mode (default: 3). + */ + size_t min_table_rows = 3; + + /** + * Similarity threshold for table detection (default: 0.8). + * Objects must share at least this fraction of keys to be formatted + * as a table. + */ + double table_similarity_threshold = 0.8; + + /** + * Enable compact multiline arrays (default: true). + * When enabled, arrays of simple elements may have multiple items + * per line. + */ + bool enable_compact_multiline = true; + + /** + * Maximum array items per line in compact mode (default: 10). + */ + size_t max_items_per_line = 10; + + /** + * Add space inside brackets for simple containers (default: true). + * When true: { "key": "value" } + * When false: {"key": "value"} + */ + bool simple_bracket_padding = true; + + /** + * Add space after colons (default: true). + * When true: "key": "value" + * When false: "key":"value" + */ + bool colon_padding = true; + + /** + * Add space after commas in inline content (default: true). + * When true: [1, 2, 3] + * When false: [1,2,3] + */ + bool comma_padding = true; +}; + +/** + * Format JSON using FracturedJson formatting with default options. + * + * FracturedJson produces human-readable yet compact output by intelligently + * choosing between inline, compact multiline, table, and expanded layouts. + * + * dom::parser parser; + * element doc = parser.parse(json_string); + * cout << fractured_json(doc) << endl; + */ +template +std::string fractured_json(T x); + +/** + * Format JSON using FracturedJson formatting with custom options. + * + * dom::parser parser; + * element doc = parser.parse(json_string); + * fractured_json_options opts; + * opts.max_total_line_length = 80; + * cout << fractured_json(doc, opts) << endl; + */ +template +std::string fractured_json(T x, const fractured_json_options& options); + +#if SIMDJSON_EXCEPTIONS +template +std::string fractured_json(simdjson_result x); + +template +std::string fractured_json(simdjson_result x, const fractured_json_options& options); +#endif + +/** + * Format a JSON string using FracturedJson formatting. + * + * This is useful for formatting output from the builder/static reflection API + * or any valid JSON string. + * + * // With static reflection + * MyStruct data = {...}; + * auto minified = simdjson::to_json_string(data); + * auto formatted = simdjson::fractured_json_string(minified.value()); + * + * // Or with any JSON string + * std::string json = R"({"key":"value"})"; + * auto formatted = simdjson::fractured_json_string(json); + */ +inline std::string fractured_json_string(std::string_view json_str); + +/** + * Format a JSON string using FracturedJson formatting with custom options. + */ +inline std::string fractured_json_string(std::string_view json_str, + const fractured_json_options& options); + +} // namespace simdjson + +#endif // SIMDJSON_DOM_FRACTURED_JSON_H +/* end file simdjson/dom/fractured_json.h */ // Inline functions /* including simdjson/dom/array-inl.h: #include "simdjson/dom/array-inl.h" */ @@ -10274,6 +10664,1420 @@ simdjson_inline std::string_view string_builder::str() const { #endif /* end file simdjson/dom/serialization-inl.h */ +/* including simdjson/dom/fractured_json-inl.h: #include "simdjson/dom/fractured_json-inl.h" */ +/* begin file simdjson/dom/fractured_json-inl.h */ +#ifndef SIMDJSON_DOM_FRACTURED_JSON_INL_H +#define SIMDJSON_DOM_FRACTURED_JSON_INL_H + +/* skipped duplicate #include "simdjson/dom/fractured_json.h" */ +/* skipped duplicate #include "simdjson/dom/serialization.h" */ +/* skipped duplicate #include "simdjson/dom/element-inl.h" */ +/* skipped duplicate #include "simdjson/dom/array-inl.h" */ +/* skipped duplicate #include "simdjson/dom/object-inl.h" */ +/* skipped duplicate #include "simdjson/dom/parser-inl.h" */ +/* skipped duplicate #include "simdjson/padded_string.h" */ +/* including simdjson/internal/json_structure_analyzer.h: #include "simdjson/internal/json_structure_analyzer.h" */ +/* begin file simdjson/internal/json_structure_analyzer.h */ +#ifndef SIMDJSON_INTERNAL_JSON_STRUCTURE_ANALYZER_H +#define SIMDJSON_INTERNAL_JSON_STRUCTURE_ANALYZER_H + +/* skipped duplicate #include "simdjson/dom/base.h" */ +/* skipped duplicate #include "simdjson/dom/element.h" */ +/* skipped duplicate #include "simdjson/dom/array.h" */ +/* skipped duplicate #include "simdjson/dom/object.h" */ +/* skipped duplicate #include "simdjson/dom/fractured_json.h" */ +/* skipped duplicate #include "simdjson/internal/tape_type.h" */ + +#include +#include +#include +#include + +namespace simdjson { +namespace internal { + +/** + * Layout mode for fractured JSON formatting. + */ +enum class layout_mode { + INLINE, // Single line: [1, 2, 3] or {"a": 1} + COMPACT_MULTILINE, // Multiple items per line with breaks + TABLE, // Tabular format for arrays of similar objects + EXPANDED // Traditional multi-line with indentation +}; + +/** + * Metrics computed for a JSON element during structure analysis. + * These metrics drive layout decisions and contain child metrics for recursive formatting. + */ +struct element_metrics { + /** Nesting depth score (0 = scalar, 1 = flat container, etc.) */ + size_t complexity = 0; + + /** Estimated character length if rendered inline (minified + spaces) */ + size_t estimated_inline_len = 0; + + /** Number of direct children (0 for scalars) */ + size_t child_count = 0; + + /** Pre-computed: can this element be rendered inline? */ + bool can_inline = false; + + /** Is this an array where all elements have similar structure? */ + bool is_uniform_array = false; + + /** For uniform arrays of objects: the common keys */ + std::vector common_keys{}; + + /** Recommended layout mode based on analysis */ + layout_mode recommended_layout = layout_mode::EXPANDED; + + /** Child metrics for arrays and objects (in order of iteration) */ + std::vector children{}; +}; + +/** + * Analyzes JSON structure to compute metrics for formatting decisions. + * + * The analyzer performs a single pass over the DOM to compute: + * - Complexity (nesting depth) + * - Estimated inline length + * - Array uniformity for table detection + * + * Metrics are stored hierarchically with child metrics embedded in parent metrics, + * enabling efficient lookup during formatting without address-based caching. + */ +class structure_analyzer { +public: + /** Default constructor */ + structure_analyzer() : current_opts_(nullptr) {} + + /** Copy constructor - deleted since class has pointer member */ + structure_analyzer(const structure_analyzer&) = delete; + + /** Copy assignment - deleted since class has pointer member */ + structure_analyzer& operator=(const structure_analyzer&) = delete; + + /** Move constructor */ + structure_analyzer(structure_analyzer&&) = default; + + /** Move assignment */ + structure_analyzer& operator=(structure_analyzer&&) = default; + + /** + * Analyze a DOM element and compute metrics. + * @param elem The element to analyze + * @param opts Formatting options that affect metric computation + * @return Metrics for the root element (with child metrics embedded) + */ + element_metrics analyze(const dom::element& elem, + const fractured_json_options& opts); + + /** + * Clear state. + */ + void clear(); + + /** + * Analyze an array element directly (for standalone array formatting). + * @param arr The array to analyze + * @param opts Formatting options + * @return Metrics for the array + */ + element_metrics analyze_array(const dom::array& arr, + const fractured_json_options& opts); + + /** + * Analyze an object element directly (for standalone object formatting). + * @param obj The object to analyze + * @param opts Formatting options + * @return Metrics for the object + */ + element_metrics analyze_object(const dom::object& obj, + const fractured_json_options& opts); + +private: + const fractured_json_options* current_opts_ = nullptr; + + /** Recursive analysis implementation */ + element_metrics analyze_element(const dom::element& elem, size_t depth); + + /** Analyze scalar values (strings, numbers, booleans, null) */ + element_metrics analyze_scalar(const dom::element& elem); + + /** Analyze an array element */ + element_metrics analyze_array(const dom::array& arr, size_t depth); + + /** Analyze an object element */ + element_metrics analyze_object(const dom::object& obj, size_t depth); + + /** Estimate inline length for a string (including quotes and escaping) */ + size_t estimate_string_length(std::string_view s) const; + + /** Estimate inline length for a number */ + size_t estimate_number_length(double d) const; + size_t estimate_number_length(int64_t i) const; + size_t estimate_number_length(uint64_t u) const; + + /** + * Check if an array contains uniform objects suitable for table formatting. + * @param arr The array to check + * @param common_keys Output: keys common to all objects + * @return true if the array is suitable for table formatting + */ + bool check_array_uniformity(const dom::array& arr, + std::vector& common_keys) const; + + /** + * Compute similarity between two objects. + * @return Fraction of keys that are common (0.0 to 1.0) + */ + double compute_object_similarity(const dom::object& a, + const dom::object& b) const; + + /** + * Decide the recommended layout mode based on metrics and options. + */ + layout_mode decide_layout(const element_metrics& metrics, + size_t depth, + size_t available_width) const; +}; + +} // namespace internal +} // namespace simdjson + +#endif // SIMDJSON_INTERNAL_JSON_STRUCTURE_ANALYZER_H +/* end file simdjson/internal/json_structure_analyzer.h */ +/* including simdjson/internal/fractured_formatter.h: #include "simdjson/internal/fractured_formatter.h" */ +/* begin file simdjson/internal/fractured_formatter.h */ +#ifndef SIMDJSON_INTERNAL_FRACTURED_FORMATTER_H +#define SIMDJSON_INTERNAL_FRACTURED_FORMATTER_H + +/* skipped duplicate #include "simdjson/dom/serialization.h" */ +/* skipped duplicate #include "simdjson/dom/fractured_json.h" */ +/* skipped duplicate #include "simdjson/internal/json_structure_analyzer.h" */ + +namespace simdjson { +namespace internal { + +/** + * Fractured JSON formatter using CRTP pattern. + * + * This formatter intelligently chooses between different layout modes + * (inline, compact multiline, table, expanded) based on pre-computed + * structure metrics. + */ +class fractured_formatter : public base_formatter { +public: + explicit fractured_formatter(const fractured_json_options& opts = {}); + + /** CRTP hook: print newline (context-aware) */ + simdjson_inline void print_newline(); + + /** CRTP hook: print indentation */ + simdjson_inline void print_indents(size_t depth); + + /** CRTP hook: print space (context-aware) */ + simdjson_inline void print_space(); + + /** Set the current layout mode */ + void set_layout_mode(layout_mode mode); + + /** Get the current layout mode */ + layout_mode get_layout_mode() const; + + /** Set current depth for formatting decisions */ + void set_depth(size_t depth); + + /** Get current depth */ + size_t get_depth() const; + + /** Track current line length for compact multiline decisions */ + void track_line_length(size_t chars); + + /** Reset line length (after newline) */ + void reset_line_length(); + + /** Get current line length */ + size_t get_line_length() const; + + /** Check if we should break to a new line in compact mode */ + bool should_break_line(size_t upcoming_length) const; + + /** Get the options */ + const fractured_json_options& options() const; + + // Table formatting support + /** Begin a table row */ + void begin_table_row(); + + /** End a table row */ + void end_table_row(); + + /** Set column widths for table alignment */ + void set_column_widths(const std::vector& widths); + + /** Get current column index in table mode */ + size_t get_column_index() const; + + /** Advance to next column */ + void next_column(); + + /** Add padding to align with column width */ + void align_to_column_width(size_t actual_width); + +private: + fractured_json_options options_; + layout_mode current_layout_ = layout_mode::EXPANDED; + size_t current_depth_ = 0; + size_t current_line_length_ = 0; + + // Table state + bool in_table_mode_ = false; + std::vector column_widths_; + size_t current_column_ = 0; +}; + +/** + * Specialized string builder for fractured JSON formatting. + * + * This builder performs two passes: + * 1. Analyze the structure to compute metrics + * 2. Format using the metrics to make layout decisions + */ +class fractured_string_builder { +public: + fractured_string_builder(const fractured_json_options& opts = {}); + + /** Append a DOM element with fractured formatting */ + void append(const dom::element& value); + + /** Append a DOM array with fractured formatting */ + void append(const dom::array& value); + + /** Append a DOM object with fractured formatting */ + void append(const dom::object& value); + + /** Clear the builder */ + simdjson_inline void clear(); + + /** Get the formatted string */ + simdjson_inline std::string_view str() const; + +private: + fractured_formatter format_; + structure_analyzer analyzer_; + fractured_json_options options_; + + /** Format an element using pre-computed metrics */ + void format_element(const dom::element& elem, const element_metrics& metrics, size_t depth); + + /** Format an array with the appropriate layout */ + void format_array(const dom::array& arr, const element_metrics& metrics, size_t depth); + + /** Format an array inline: [1, 2, 3] */ + void format_array_inline(const dom::array& arr, const element_metrics& metrics); + + /** Format an array with compact multiline: multiple items per line */ + void format_array_compact_multiline(const dom::array& arr, const element_metrics& metrics, size_t depth); + + /** Format an array as a table */ + void format_array_as_table(const dom::array& arr, const element_metrics& metrics, size_t depth); + + /** Format an array expanded: one item per line */ + void format_array_expanded(const dom::array& arr, const element_metrics& metrics, size_t depth); + + /** Format an object with the appropriate layout */ + void format_object(const dom::object& obj, const element_metrics& metrics, size_t depth); + + /** Format an object inline: {"a": 1, "b": 2} */ + void format_object_inline(const dom::object& obj, const element_metrics& metrics); + + /** Format an object expanded: one key per line */ + void format_object_expanded(const dom::object& obj, const element_metrics& metrics, size_t depth); + + /** Format a scalar value */ + void format_scalar(const dom::element& elem); + + /** Calculate column widths for table formatting */ + std::vector calculate_column_widths(const dom::array& arr, + const std::vector& columns) const; + + /** Measure the actual formatted length of a value (for alignment) */ + size_t measure_value_length(const dom::element& elem) const; +}; + +} // namespace internal +} // namespace simdjson + +#endif // SIMDJSON_INTERNAL_FRACTURED_FORMATTER_H +/* end file simdjson/internal/fractured_formatter.h */ + +#include +#include +#include + +namespace simdjson { +namespace internal { + +// +// Structure Analyzer Implementation +// + +inline element_metrics structure_analyzer::analyze(const dom::element& elem, + const fractured_json_options& opts) { + current_opts_ = &opts; + return analyze_element(elem, 0); +} + +inline void structure_analyzer::clear() { + current_opts_ = nullptr; +} + +inline element_metrics structure_analyzer::analyze_array(const dom::array& arr, + const fractured_json_options& opts) { + current_opts_ = &opts; + return analyze_array(arr, 0); +} + +inline element_metrics structure_analyzer::analyze_object(const dom::object& obj, + const fractured_json_options& opts) { + current_opts_ = &opts; + return analyze_object(obj, 0); +} + +inline element_metrics structure_analyzer::analyze_element(const dom::element& elem, size_t depth) { + switch (elem.type()) { + case dom::element_type::ARRAY: { + dom::array arr; + if (elem.get_array().get(arr) == SUCCESS) { + return analyze_array(arr, depth); + } + break; + } + case dom::element_type::OBJECT: { + dom::object obj; + if (elem.get_object().get(obj) == SUCCESS) { + return analyze_object(obj, depth); + } + break; + } + default: + // Handle all scalar types with a helper + return analyze_scalar(elem); + } + return element_metrics{}; +} + +inline element_metrics structure_analyzer::analyze_scalar(const dom::element& elem) { + element_metrics metrics; + metrics.complexity = 0; + metrics.child_count = 0; + metrics.can_inline = true; + metrics.recommended_layout = layout_mode::INLINE; + + switch (elem.type()) { + case dom::element_type::STRING: { + std::string_view str; + if (elem.get_string().get(str) == SUCCESS) { + metrics.estimated_inline_len = estimate_string_length(str); + } + break; + } + case dom::element_type::INT64: { + int64_t val; + if (elem.get_int64().get(val) == SUCCESS) { + metrics.estimated_inline_len = estimate_number_length(val); + } + break; + } + case dom::element_type::UINT64: { + uint64_t val; + if (elem.get_uint64().get(val) == SUCCESS) { + metrics.estimated_inline_len = estimate_number_length(val); + } + break; + } + case dom::element_type::DOUBLE: { + double val; + if (elem.get_double().get(val) == SUCCESS) { + metrics.estimated_inline_len = estimate_number_length(val); + } + break; + } + case dom::element_type::BOOL: { + bool val; + if (elem.get_bool().get(val) == SUCCESS) { + metrics.estimated_inline_len = val ? 4 : 5; // "true" or "false" + } + break; + } + case dom::element_type::NULL_VALUE: + metrics.estimated_inline_len = 4; // "null" + break; + default: + break; + } + + return metrics; +} + +inline element_metrics structure_analyzer::analyze_array(const dom::array& arr, + size_t depth) { + element_metrics metrics; + metrics.complexity = 1; // At least 1 for being an array + metrics.estimated_inline_len = 2; // "[]" + metrics.child_count = 0; + + size_t max_child_complexity = 0; + bool first = true; + + for (dom::element child : arr) { + if (!first) { + metrics.estimated_inline_len += 2; // ", " + } + first = false; + + element_metrics child_metrics = analyze_element(child, depth + 1); + metrics.estimated_inline_len += child_metrics.estimated_inline_len; + max_child_complexity = (std::max)(max_child_complexity, child_metrics.complexity); + metrics.child_count++; + metrics.children.push_back(std::move(child_metrics)); + } + + // Complexity is 1 + max child complexity + metrics.complexity = 1 + max_child_complexity; + + // Check if can inline + metrics.can_inline = (metrics.complexity <= current_opts_->max_inline_complexity) && + (metrics.estimated_inline_len <= current_opts_->max_inline_length); + + // Check for uniform array (table formatting) + if (current_opts_->enable_table_format && + metrics.child_count >= current_opts_->min_table_rows) { + metrics.is_uniform_array = check_array_uniformity(arr, metrics.common_keys); + } + + // Decide layout + if (metrics.child_count == 0) { + metrics.recommended_layout = layout_mode::INLINE; + } else if (metrics.can_inline) { + metrics.recommended_layout = layout_mode::INLINE; + } else if (metrics.is_uniform_array && !metrics.common_keys.empty()) { + metrics.recommended_layout = layout_mode::TABLE; + } else if (current_opts_->enable_compact_multiline && + max_child_complexity <= current_opts_->max_compact_array_complexity) { + metrics.recommended_layout = layout_mode::COMPACT_MULTILINE; + } else { + metrics.recommended_layout = layout_mode::EXPANDED; + } + + return metrics; +} + +inline element_metrics structure_analyzer::analyze_object(const dom::object& obj, + size_t depth) { + element_metrics metrics; + metrics.complexity = 1; + metrics.estimated_inline_len = 2; // "{}" + metrics.child_count = 0; + + size_t max_child_complexity = 0; + bool first = true; + + for (dom::key_value_pair field : obj) { + if (!first) { + metrics.estimated_inline_len += 2; // ", " + } + first = false; + + // Key length: quotes + key + colon + space + metrics.estimated_inline_len += estimate_string_length(field.key) + 2; + + element_metrics child_metrics = analyze_element(field.value, depth + 1); + metrics.estimated_inline_len += child_metrics.estimated_inline_len; + max_child_complexity = (std::max)(max_child_complexity, child_metrics.complexity); + metrics.child_count++; + metrics.children.push_back(std::move(child_metrics)); + } + + metrics.complexity = 1 + max_child_complexity; + + metrics.can_inline = (metrics.complexity <= current_opts_->max_inline_complexity) && + (metrics.estimated_inline_len <= current_opts_->max_inline_length); + + // Objects use inline or expanded (no table/compact for objects) + if (metrics.child_count == 0 || metrics.can_inline) { + metrics.recommended_layout = layout_mode::INLINE; + } else { + metrics.recommended_layout = layout_mode::EXPANDED; + } + + return metrics; +} + +inline size_t structure_analyzer::estimate_string_length(std::string_view s) const { + size_t len = 2; // quotes + for (char c : s) { + if (c == '"' || c == '\\' || static_cast(c) < 32) { + len += 2; // escape sequence (at least) + } else { + len += 1; + } + } + return len; +} + +inline size_t structure_analyzer::estimate_number_length(double d) const { + if (std::isnan(d) || std::isinf(d)) { + return 4; // "null" for invalid numbers + } + // Rough estimate: up to 17 significant digits + sign + decimal point + exponent + char buf[32]; + int len = snprintf(buf, sizeof(buf), "%.17g", d); + return len > 0 ? static_cast(len) : 20; +} + +inline size_t structure_analyzer::estimate_number_length(int64_t i) const { + if (i == 0) return 1; + // Handle INT64_MIN specially to avoid overflow when negating + if (i == INT64_MIN) return 20; // "-9223372036854775808" is 20 characters + size_t len = (i < 0) ? 1 : 0; // negative sign + int64_t abs_val = (i < 0) ? -i : i; + while (abs_val > 0) { + len++; + abs_val /= 10; + } + return len; +} + +inline size_t structure_analyzer::estimate_number_length(uint64_t u) const { + if (u == 0) return 1; + size_t len = 0; + while (u > 0) { + len++; + u /= 10; + } + return len; +} + +inline bool structure_analyzer::check_array_uniformity(const dom::array& arr, + std::vector& common_keys) const { + common_keys.clear(); + + std::set shared_keys; + dom::object first_obj; + bool have_first = false; + size_t object_count = 0; + + for (dom::element elem : arr) { + if (elem.type() != dom::element_type::OBJECT) { + return false; // Not all elements are objects + } + + dom::object obj; + if (elem.get_object().get(obj) != SUCCESS) { + return false; + } + + std::set current_keys; + for (dom::key_value_pair field : obj) { + current_keys.insert(std::string(field.key)); + } + + if (!have_first) { + shared_keys = current_keys; + first_obj = obj; + have_first = true; + } else { + // Check similarity threshold against the first object + double similarity = compute_object_similarity(first_obj, obj); + if (similarity < current_opts_->table_similarity_threshold) { + return false; // Objects are too dissimilar for table format + } + + // Intersect with current keys + std::set intersection; + std::set_intersection(shared_keys.begin(), shared_keys.end(), + current_keys.begin(), current_keys.end(), + std::inserter(intersection, intersection.begin())); + shared_keys = intersection; + } + + object_count++; + } + + if (object_count < current_opts_->min_table_rows) { + return false; + } + + // Require at least one common key for table formatting + if (shared_keys.empty()) { + return false; + } + + common_keys.assign(shared_keys.begin(), shared_keys.end()); + return true; +} + +inline double structure_analyzer::compute_object_similarity(const dom::object& a, + const dom::object& b) const { + std::set keys_a, keys_b; + for (dom::key_value_pair field : a) { + keys_a.insert(std::string(field.key)); + } + for (dom::key_value_pair field : b) { + keys_b.insert(std::string(field.key)); + } + + std::set intersection; + std::set_intersection(keys_a.begin(), keys_a.end(), + keys_b.begin(), keys_b.end(), + std::inserter(intersection, intersection.begin())); + + std::set union_set; + std::set_union(keys_a.begin(), keys_a.end(), + keys_b.begin(), keys_b.end(), + std::inserter(union_set, union_set.begin())); + + if (union_set.empty()) return 1.0; + return static_cast(intersection.size()) / static_cast(union_set.size()); +} + +inline layout_mode structure_analyzer::decide_layout(const element_metrics& metrics, + size_t depth, + size_t available_width) const { + if (metrics.child_count == 0) { + return layout_mode::INLINE; + } + + // Check inline feasibility + size_t indent_width = depth * current_opts_->indent_spaces; + if (metrics.can_inline && + metrics.estimated_inline_len + indent_width <= available_width) { + return layout_mode::INLINE; + } + + // Check table mode + if (metrics.is_uniform_array && !metrics.common_keys.empty()) { + return layout_mode::TABLE; + } + + // Check compact multiline + if (current_opts_->enable_compact_multiline && + metrics.complexity <= current_opts_->max_compact_array_complexity + 1) { + return layout_mode::COMPACT_MULTILINE; + } + + return layout_mode::EXPANDED; +} + +// +// Fractured Formatter Implementation +// + +inline fractured_formatter::fractured_formatter(const fractured_json_options& opts) + : options_(opts), column_widths_{} {} + +simdjson_inline void fractured_formatter::print_newline() { + if (current_layout_ == layout_mode::INLINE) { + return; // No newlines in inline mode + } + one_char('\n'); + current_line_length_ = 0; +} + +simdjson_inline void fractured_formatter::print_indents(size_t depth) { + if (current_layout_ == layout_mode::INLINE) { + return; // No indentation in inline mode + } + for (size_t i = 0; i < depth * options_.indent_spaces; i++) { + one_char(' '); + current_line_length_++; + } +} + +simdjson_inline void fractured_formatter::print_space() { + one_char(' '); + current_line_length_++; +} + +inline void fractured_formatter::set_layout_mode(layout_mode mode) { + current_layout_ = mode; +} + +inline layout_mode fractured_formatter::get_layout_mode() const { + return current_layout_; +} + +inline void fractured_formatter::set_depth(size_t depth) { + current_depth_ = depth; +} + +inline size_t fractured_formatter::get_depth() const { + return current_depth_; +} + +inline void fractured_formatter::track_line_length(size_t chars) { + current_line_length_ += chars; +} + +inline void fractured_formatter::reset_line_length() { + current_line_length_ = 0; +} + +inline size_t fractured_formatter::get_line_length() const { + return current_line_length_; +} + +inline bool fractured_formatter::should_break_line(size_t upcoming_length) const { + return (current_line_length_ + upcoming_length) > options_.max_total_line_length; +} + +inline const fractured_json_options& fractured_formatter::options() const { + return options_; +} + +inline void fractured_formatter::begin_table_row() { + in_table_mode_ = true; + current_column_ = 0; +} + +inline void fractured_formatter::end_table_row() { + in_table_mode_ = false; + current_column_ = 0; +} + +inline void fractured_formatter::set_column_widths(const std::vector& widths) { + column_widths_ = widths; +} + +inline size_t fractured_formatter::get_column_index() const { + return current_column_; +} + +inline void fractured_formatter::next_column() { + current_column_++; +} + +inline void fractured_formatter::align_to_column_width(size_t actual_width) { + if (current_column_ < column_widths_.size()) { + size_t target_width = column_widths_[current_column_]; + while (actual_width < target_width) { + one_char(' '); + actual_width++; + current_line_length_++; + } + } +} + +// +// Fractured String Builder Implementation +// + +inline fractured_string_builder::fractured_string_builder(const fractured_json_options& opts) + : format_(opts), analyzer_{}, options_(opts) {} + +inline void fractured_string_builder::append(const dom::element& value) { + // Phase 1: Analyze structure (metrics tree is built recursively) + element_metrics root_metrics = analyzer_.analyze(value, options_); + + // Phase 2: Format using metrics tree (passed through recursion) + format_element(value, root_metrics, 0); +} + +inline void fractured_string_builder::append(const dom::array& value) { + // Analyze the array to get proper metrics with children + element_metrics metrics = analyzer_.analyze_array(value, options_); + format_array(value, metrics, 0); +} + +inline void fractured_string_builder::append(const dom::object& value) { + // Analyze the object to get proper metrics with children + element_metrics metrics = analyzer_.analyze_object(value, options_); + format_object(value, metrics, 0); +} + +simdjson_inline void fractured_string_builder::clear() { + format_.clear(); + analyzer_.clear(); +} + +simdjson_inline std::string_view fractured_string_builder::str() const { + return format_.str(); +} + +inline void fractured_string_builder::format_element(const dom::element& elem, + const element_metrics& metrics, + size_t depth) { + switch (elem.type()) { + case dom::element_type::ARRAY: { + dom::array arr; + if (elem.get_array().get(arr) == SUCCESS) { + format_array(arr, metrics, depth); + } + break; + } + case dom::element_type::OBJECT: { + dom::object obj; + if (elem.get_object().get(obj) == SUCCESS) { + format_object(obj, metrics, depth); + } + break; + } + default: + format_scalar(elem); + break; + } +} + +inline void fractured_string_builder::format_array(const dom::array& arr, + const element_metrics& metrics, + size_t depth) { + switch (metrics.recommended_layout) { + case layout_mode::INLINE: + format_array_inline(arr, metrics); + break; + case layout_mode::COMPACT_MULTILINE: + format_array_compact_multiline(arr, metrics, depth); + break; + case layout_mode::TABLE: + format_array_as_table(arr, metrics, depth); + break; + case layout_mode::EXPANDED: + default: + format_array_expanded(arr, metrics, depth); + break; + } +} + +inline void fractured_string_builder::format_array_inline(const dom::array& arr, + const element_metrics& metrics) { + layout_mode prev_layout = format_.get_layout_mode(); + format_.set_layout_mode(layout_mode::INLINE); + + format_.start_array(); + + bool first = true; + bool empty = true; + size_t child_idx = 0; + for (dom::element elem : arr) { + empty = false; + if (!first) { + format_.comma(); + if (options_.comma_padding) { + format_.print_space(); + } + } else if (options_.simple_bracket_padding) { + format_.print_space(); + } + first = false; + const element_metrics& child_metrics = (child_idx < metrics.children.size()) + ? metrics.children[child_idx] : element_metrics{}; + format_element(elem, child_metrics, 0); + child_idx++; + } + + if (options_.simple_bracket_padding && !empty) { + format_.print_space(); + } + format_.end_array(); + + format_.set_layout_mode(prev_layout); +} + +inline void fractured_string_builder::format_array_compact_multiline(const dom::array& arr, + const element_metrics& metrics, + size_t depth) { + format_.start_array(); + format_.print_newline(); + format_.print_indents(depth + 1); + + size_t items_on_line = 0; + bool first = true; + size_t child_idx = 0; + + for (dom::element elem : arr) { + if (!first) { + format_.comma(); + + // Check if we should break to new line + if (items_on_line >= options_.max_items_per_line || + format_.should_break_line(20)) { // 20 is rough estimate for next item + format_.print_newline(); + format_.print_indents(depth + 1); + items_on_line = 0; + } else if (options_.comma_padding) { + format_.print_space(); + } + } + first = false; + + // Format element inline + layout_mode prev_layout = format_.get_layout_mode(); + format_.set_layout_mode(layout_mode::INLINE); + const element_metrics& child_metrics = (child_idx < metrics.children.size()) + ? metrics.children[child_idx] : element_metrics{}; + format_element(elem, child_metrics, depth + 1); + format_.set_layout_mode(prev_layout); + + items_on_line++; + child_idx++; + } + + format_.print_newline(); + format_.print_indents(depth); + format_.end_array(); +} + +inline void fractured_string_builder::format_array_as_table(const dom::array& arr, + const element_metrics& metrics, + size_t depth) { + const std::vector& columns = metrics.common_keys; + if (columns.empty()) { + format_array_expanded(arr, metrics, depth); + return; + } + + // Calculate column widths for alignment + std::vector col_widths = calculate_column_widths(arr, columns); + format_.set_column_widths(col_widths); + + format_.start_array(); + format_.print_newline(); + + bool first_row = true; + size_t child_idx = 0; + for (dom::element elem : arr) { + if (!first_row) { + format_.comma(); + format_.print_newline(); + } + first_row = false; + + format_.print_indents(depth + 1); + format_.begin_table_row(); + + // Format object as inline with aligned columns + dom::object obj; + if (elem.get_object().get(obj) != SUCCESS) { + child_idx++; + continue; + } + + // Get child metrics for this row (object) + const element_metrics& row_metrics = (child_idx < metrics.children.size()) + ? metrics.children[child_idx] : element_metrics{}; + + format_.start_object(); + if (options_.simple_bracket_padding) { + format_.print_space(); + } + + bool first_col = true; + const size_t num_columns = columns.size(); + + for (size_t col_idx = 0; col_idx < num_columns; col_idx++) { + const std::string& key = columns[col_idx]; + const bool is_last_col = (col_idx == num_columns - 1); + + if (!first_col) { + format_.comma(); + if (options_.comma_padding) { + format_.print_space(); + } + } + first_col = false; + + // Write key + format_.key(key); + if (options_.colon_padding) { + format_.print_space(); + } + + // Find the value for this key and its metrics + dom::element value; + bool found = false; + size_t field_idx = 0; + for (dom::key_value_pair field : obj) { + if (field.key == key) { + value = field.value; + found = true; + break; + } + field_idx++; + } + + // Write value + if (found) { + layout_mode prev_layout = format_.get_layout_mode(); + format_.set_layout_mode(layout_mode::INLINE); + const element_metrics& value_metrics = (field_idx < row_metrics.children.size()) + ? row_metrics.children[field_idx] : element_metrics{}; + format_element(value, value_metrics, depth + 1); + format_.set_layout_mode(prev_layout); + } else { + format_.null_atom(); + } + + // Only pad non-last columns to align values across rows + if (!is_last_col) { + size_t actual_len = found ? measure_value_length(value) : 4; // 4 for "null" + size_t target_width = col_widths[col_idx]; + while (actual_len < target_width) { + format_.one_char(' '); + actual_len++; + } + } + + format_.next_column(); + } + + if (options_.simple_bracket_padding) { + format_.print_space(); + } + format_.end_object(); + format_.end_table_row(); + child_idx++; + } + + format_.print_newline(); + format_.print_indents(depth); + format_.end_array(); +} + +inline void fractured_string_builder::format_array_expanded(const dom::array& arr, + const element_metrics& metrics, + size_t depth) { + format_.start_array(); + + bool empty = true; + bool first = true; + size_t child_idx = 0; + + for (dom::element elem : arr) { + empty = false; + if (!first) { + format_.comma(); + } + first = false; + + format_.print_newline(); + format_.print_indents(depth + 1); + const element_metrics& child_metrics = (child_idx < metrics.children.size()) + ? metrics.children[child_idx] : element_metrics{}; + format_element(elem, child_metrics, depth + 1); + child_idx++; + } + + if (!empty) { + format_.print_newline(); + format_.print_indents(depth); + } + format_.end_array(); +} + +inline void fractured_string_builder::format_object(const dom::object& obj, + const element_metrics& metrics, + size_t depth) { + if (metrics.recommended_layout == layout_mode::INLINE || metrics.can_inline) { + format_object_inline(obj, metrics); + } else { + format_object_expanded(obj, metrics, depth); + } +} + +inline void fractured_string_builder::format_object_inline(const dom::object& obj, + const element_metrics& metrics) { + layout_mode prev_layout = format_.get_layout_mode(); + format_.set_layout_mode(layout_mode::INLINE); + + format_.start_object(); + + bool empty = true; + bool first = true; + size_t child_idx = 0; + + for (dom::key_value_pair field : obj) { + empty = false; + if (!first) { + format_.comma(); + if (options_.comma_padding) { + format_.print_space(); + } + } else if (options_.simple_bracket_padding) { + format_.print_space(); + } + first = false; + + format_.key(field.key); + if (options_.colon_padding) { + format_.print_space(); + } + const element_metrics& child_metrics = (child_idx < metrics.children.size()) + ? metrics.children[child_idx] : element_metrics{}; + format_element(field.value, child_metrics, 0); + child_idx++; + } + + if (options_.simple_bracket_padding && !empty) { + format_.print_space(); + } + format_.end_object(); + + format_.set_layout_mode(prev_layout); +} + +inline void fractured_string_builder::format_object_expanded(const dom::object& obj, + const element_metrics& metrics, + size_t depth) { + format_.start_object(); + + bool empty = true; + bool first = true; + size_t child_idx = 0; + + for (dom::key_value_pair field : obj) { + empty = false; + if (!first) { + format_.comma(); + } + first = false; + + format_.print_newline(); + format_.print_indents(depth + 1); + format_.key(field.key); + if (options_.colon_padding) { + format_.print_space(); + } + const element_metrics& child_metrics = (child_idx < metrics.children.size()) + ? metrics.children[child_idx] : element_metrics{}; + format_element(field.value, child_metrics, depth + 1); + child_idx++; + } + + if (!empty) { + format_.print_newline(); + format_.print_indents(depth); + } + format_.end_object(); +} + +inline void fractured_string_builder::format_scalar(const dom::element& elem) { + switch (elem.type()) { + case dom::element_type::STRING: { + std::string_view str; + if (elem.get_string().get(str) == SUCCESS) { + format_.string(str); + } + break; + } + case dom::element_type::INT64: { + int64_t val; + if (elem.get_int64().get(val) == SUCCESS) { + format_.number(val); + } + break; + } + case dom::element_type::UINT64: { + uint64_t val; + if (elem.get_uint64().get(val) == SUCCESS) { + format_.number(val); + } + break; + } + case dom::element_type::DOUBLE: { + double val; + if (elem.get_double().get(val) == SUCCESS) { + format_.number(val); + } + break; + } + case dom::element_type::BOOL: { + bool val; + if (elem.get_bool().get(val) == SUCCESS) { + val ? format_.true_atom() : format_.false_atom(); + } + break; + } + case dom::element_type::NULL_VALUE: + format_.null_atom(); + break; + default: + break; + } +} + +inline size_t fractured_string_builder::measure_value_length(const dom::element& elem) const { + switch (elem.type()) { + case dom::element_type::STRING: { + std::string_view str; + if (elem.get_string().get(str) == SUCCESS) { + // Count actual escaped length + size_t len = 2; // quotes + for (char c : str) { + if (c == '"' || c == '\\' || static_cast(c) < 32) { + len += 2; // escape sequence + } else { + len += 1; + } + } + return len; + } + return 2; + } + case dom::element_type::INT64: { + int64_t val; + if (elem.get_int64().get(val) == SUCCESS) { + if (val == 0) return 1; + // Handle INT64_MIN specially to avoid overflow when negating + if (val == INT64_MIN) return 20; // "-9223372036854775808" is 20 characters + size_t len = (val < 0) ? 1 : 0; + int64_t abs_val = (val < 0) ? -val : val; + while (abs_val > 0) { len++; abs_val /= 10; } + return len; + } + return 1; + } + case dom::element_type::UINT64: { + uint64_t val; + if (elem.get_uint64().get(val) == SUCCESS) { + if (val == 0) return 1; + size_t len = 0; + while (val > 0) { len++; val /= 10; } + return len; + } + return 1; + } + case dom::element_type::DOUBLE: { + double val; + if (elem.get_double().get(val) == SUCCESS) { + char buf[32]; + int len = snprintf(buf, sizeof(buf), "%.17g", val); + return len > 0 ? static_cast(len) : 1; + } + return 1; + } + case dom::element_type::BOOL: { + bool val; + if (elem.get_bool().get(val) == SUCCESS) { + return val ? 4 : 5; // "true" or "false" + } + return 5; + } + case dom::element_type::NULL_VALUE: + return 4; // "null" + default: + return 4; + } +} + +inline std::vector fractured_string_builder::calculate_column_widths( + const dom::array& arr, + const std::vector& columns) const { + + std::vector widths(columns.size(), 0); + + for (dom::element elem : arr) { + dom::object obj; + if (elem.get_object().get(obj) != SUCCESS) { + continue; + } + + for (size_t col_idx = 0; col_idx < columns.size(); col_idx++) { + const std::string& key = columns[col_idx]; + + for (dom::key_value_pair field : obj) { + if (field.key == key) { + // Measure actual value length + size_t len = measure_value_length(field.value); + widths[col_idx] = (std::max)(widths[col_idx], len); + break; + } + } + } + } + + return widths; +} + +} // namespace internal + +// +// Public API Implementation +// + +template +std::string fractured_json(T x) { + return fractured_json(x, fractured_json_options{}); +} + +template +std::string fractured_json(T x, const fractured_json_options& options) { + internal::fractured_string_builder sb(options); + sb.append(x); + std::string_view result = sb.str(); + return std::string(result.data(), result.size()); +} + +#if SIMDJSON_EXCEPTIONS +template +std::string fractured_json(simdjson_result x) { + if (x.error()) { + throw simdjson_error(x.error()); + } + return fractured_json(x.value()); +} + +template +std::string fractured_json(simdjson_result x, const fractured_json_options& options) { + if (x.error()) { + throw simdjson_error(x.error()); + } + return fractured_json(x.value(), options); +} +#endif + +// Explicit template instantiations for common types +template std::string fractured_json(dom::element x); +template std::string fractured_json(dom::element x, const fractured_json_options& options); +template std::string fractured_json(dom::array x); +template std::string fractured_json(dom::array x, const fractured_json_options& options); +template std::string fractured_json(dom::object x); +template std::string fractured_json(dom::object x, const fractured_json_options& options); + +#if SIMDJSON_EXCEPTIONS +template std::string fractured_json(simdjson_result x); +template std::string fractured_json(simdjson_result x, const fractured_json_options& options); +#endif + +// +// String-based API for formatting any JSON string +// + +inline std::string fractured_json_string(std::string_view json_str) { + return fractured_json_string(json_str, fractured_json_options{}); +} + +inline std::string fractured_json_string(std::string_view json_str, + const fractured_json_options& options) { + // Parse the JSON string + dom::parser parser; + dom::element doc; + // Need to pad the string for simdjson + auto padded = padded_string(json_str); + auto error = parser.parse(padded).get(doc); + if (error) { + // If parsing fails, return the original string + return std::string(json_str); + } + return fractured_json(doc, options); +} + +} // namespace simdjson + +#endif // SIMDJSON_DOM_FRACTURED_JSON_INL_H +/* end file simdjson/dom/fractured_json-inl.h */ #endif // SIMDJSON_DOM_H /* end file simdjson/dom.h */ @@ -10314,6 +12118,8 @@ simdjson_inline std::string_view string_builder::str() const { #define SIMDJSON_IMPLEMENTATION_ID_westmere 6 #define SIMDJSON_IMPLEMENTATION_ID_lsx 7 #define SIMDJSON_IMPLEMENTATION_ID_lasx 8 +//#define SIMDJSON_IMPLEMENTATION_ID_rvv 9 +#define SIMDJSON_IMPLEMENTATION_ID_rvv_vls 10 #define SIMDJSON_IMPLEMENTATION_ID_FOR(IMPL) SIMDJSON_CAT(SIMDJSON_IMPLEMENTATION_ID_, IMPL) #define SIMDJSON_IMPLEMENTATION_ID SIMDJSON_IMPLEMENTATION_ID_FOR(SIMDJSON_IMPLEMENTATION) @@ -10428,9 +12234,14 @@ simdjson_inline std::string_view string_builder::str() const { #endif #define SIMDJSON_CAN_ALWAYS_RUN_LSX (SIMDJSON_IMPLEMENTATION_LSX) +#define SIMDJSON_CAN_ALWAYS_RUN_RVV_VLS SIMDJSON_IS_RVV_VLS +#ifndef SIMDJSON_IMPLEMENTATION_RVV_VLS +#define SIMDJSON_IMPLEMENTATION_RVV_VLS SIMDJSON_CAN_ALWAYS_RUN_RVV_VLS +#endif + // Default Fallback to on unless a builtin implementation has already been selected. #ifndef SIMDJSON_IMPLEMENTATION_FALLBACK -#if SIMDJSON_CAN_ALWAYS_RUN_ARM64 || SIMDJSON_CAN_ALWAYS_RUN_ICELAKE || SIMDJSON_CAN_ALWAYS_RUN_HASWELL || SIMDJSON_CAN_ALWAYS_RUN_WESTMERE || SIMDJSON_CAN_ALWAYS_RUN_PPC64 || SIMDJSON_CAN_ALWAYS_RUN_LSX || SIMDJSON_CAN_ALWAYS_RUN_LASX +#if SIMDJSON_CAN_ALWAYS_RUN_ARM64 || SIMDJSON_CAN_ALWAYS_RUN_ICELAKE || SIMDJSON_CAN_ALWAYS_RUN_HASWELL || SIMDJSON_CAN_ALWAYS_RUN_WESTMERE || SIMDJSON_CAN_ALWAYS_RUN_PPC64 || SIMDJSON_CAN_ALWAYS_RUN_LSX || SIMDJSON_CAN_ALWAYS_RUN_LASX || SIMDJSON_CAN_ALWAYS_RUN_RVV_VLS // if anything at all except fallback can always run, then disable fallback. #define SIMDJSON_IMPLEMENTATION_FALLBACK 0 #else @@ -10456,6 +12267,8 @@ simdjson_inline std::string_view string_builder::str() const { #define SIMDJSON_BUILTIN_IMPLEMENTATION lsx #elif SIMDJSON_CAN_ALWAYS_RUN_LASX #define SIMDJSON_BUILTIN_IMPLEMENTATION lasx +#elif SIMDJSON_CAN_ALWAYS_RUN_RVV_VLS +#define SIMDJSON_BUILTIN_IMPLEMENTATION rvv_vls #elif SIMDJSON_CAN_ALWAYS_RUN_FALLBACK #define SIMDJSON_BUILTIN_IMPLEMENTATION fallback #else @@ -10487,6 +12300,8 @@ namespace simdjson { namespace lsx {} #elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx) namespace lasx {} +#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(rvv_vls) + namespace rvv_vls {} #else #error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION #endif @@ -10601,6 +12416,8 @@ enum instruction_set { AVX512VBMI2 = 0x10000, LSX = 0x20000, LASX = 0x40000, + //RVV = 0x80000, + RVV_VLS = 0x100000, }; } // namespace internal @@ -11691,6 +13508,44 @@ public: #endif // SIMDJSON_LASX_IMPLEMENTATION_H /* end file simdjson/lasx/implementation.h */ +#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(rvv_vls) +/* including simdjson/rvv-vls/implementation.h: #include "simdjson/rvv-vls/implementation.h" */ +/* begin file simdjson/rvv-vls/implementation.h */ +#ifndef SIMDJSON_RVV_VLS_IMPLEMENTATION_H +#define SIMDJSON_RVV_VLS_IMPLEMENTATION_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { + +/** + * @private + */ +class implementation final : public simdjson::implementation { +public: + simdjson_inline implementation() : simdjson::implementation( + "rvv_vls", + "RISC-V V extension", + 0 + ) {} + simdjson_warn_unused error_code create_dom_parser_implementation( + size_t capacity, + size_t max_length, + std::unique_ptr& dst + ) const noexcept final; + simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final; + simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final; +}; + +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_IMPLEMENTATION_H +/* end file simdjson/rvv-vls/implementation.h */ #else #error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION #endif @@ -12431,6 +14286,7 @@ namespace { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, "ARM kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -12626,6 +14482,8 @@ simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *ds /* amalgamation skipped (editor-only): #include "simdjson/lasx/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_LSX */ /* amalgamation skipped (editor-only): #include "simdjson/lsx/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_RVV_VLS */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_FALLBACK */ /* amalgamation skipped (editor-only): #include "simdjson/fallback/begin.h" */ /* amalgamation skipped (editor-only): #else */ @@ -14824,6 +16682,8 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t /* amalgamation skipped (editor-only): #include "simdjson/lasx/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_LSX */ /* amalgamation skipped (editor-only): #include "simdjson/lsx/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_RVV_VLS */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_FALLBACK */ /* amalgamation skipped (editor-only): #include "simdjson/fallback/begin.h" */ /* amalgamation skipped (editor-only): #else */ @@ -17342,6 +19202,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 2, "Haswell kernel should use two registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -17521,6 +19382,8 @@ simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *ds /* amalgamation skipped (editor-only): #include "simdjson/lasx/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_LSX */ /* amalgamation skipped (editor-only): #include "simdjson/lsx/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_RVV_VLS */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_FALLBACK */ /* amalgamation skipped (editor-only): #include "simdjson/fallback/begin.h" */ /* amalgamation skipped (editor-only): #else */ @@ -19994,6 +21857,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 1, "Icelake kernel should use one register per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -20218,6 +22082,8 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t /* amalgamation skipped (editor-only): #include "simdjson/lasx/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_LSX */ /* amalgamation skipped (editor-only): #include "simdjson/lsx/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_RVV_VLS */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_FALLBACK */ /* amalgamation skipped (editor-only): #include "simdjson/fallback/begin.h" */ /* amalgamation skipped (editor-only): #else */ @@ -22828,6 +24694,7 @@ template struct simd8x64 { static_assert(NUM_CHUNKS == 4, "PPC64 kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64 &o) = delete; // no copy allowed simd8x64 & @@ -23030,6 +24897,8 @@ simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *ds /* amalgamation skipped (editor-only): #include "simdjson/lasx/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_LSX */ /* amalgamation skipped (editor-only): #include "simdjson/lsx/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_RVV_VLS */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_FALLBACK */ /* amalgamation skipped (editor-only): #include "simdjson/fallback/begin.h" */ /* amalgamation skipped (editor-only): #else */ @@ -25558,6 +27427,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, "Westmere kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -25986,6 +27856,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, "Westmere kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -26158,6 +28029,8 @@ simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *ds /* amalgamation skipped (editor-only): #include "simdjson/lasx/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_LSX */ /* amalgamation skipped (editor-only): #include "simdjson/lsx/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_RVV_VLS */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_FALLBACK */ /* amalgamation skipped (editor-only): #include "simdjson/fallback/begin.h" */ /* amalgamation skipped (editor-only): #else */ @@ -28604,6 +30477,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 2, "LASX kernel should use two registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -28787,6 +30661,8 @@ simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *ds /* amalgamation skipped (editor-only): #include "simdjson/lasx/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_LSX */ /* amalgamation skipped (editor-only): #include "simdjson/lsx/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_RVV_VLS */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_FALLBACK */ /* amalgamation skipped (editor-only): #include "simdjson/fallback/begin.h" */ /* amalgamation skipped (editor-only): #else */ @@ -31186,6 +33062,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, "LSX kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -31394,6 +33271,8 @@ simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *ds /* amalgamation skipped (editor-only): #include "simdjson/lasx/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_LSX */ /* amalgamation skipped (editor-only): #include "simdjson/lsx/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_RVV_VLS */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/begin.h" */ /* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_FALLBACK */ /* amalgamation skipped (editor-only): #include "simdjson/fallback/begin.h" */ /* amalgamation skipped (editor-only): #else */ @@ -33331,6 +35210,2632 @@ simdjson_inline implementation_simdjson_result_base::implementation_simdjson_ #endif // SIMDJSON_LSX_H /* end file simdjson/lsx.h */ +#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(rvv_vls) +/* including simdjson/rvv-vls.h: #include "simdjson/rvv-vls.h" */ +/* begin file simdjson/rvv-vls.h */ +#ifndef SIMDJSON_RVV_VLS_H +#define SIMDJSON_RVV_VLS_H + + +/* including simdjson/rvv-vls/begin.h: #include "simdjson/rvv-vls/begin.h" */ +/* begin file simdjson/rvv-vls/begin.h */ +/* defining SIMDJSON_IMPLEMENTATION to "rvv_vls" */ +#define SIMDJSON_IMPLEMENTATION rvv_vls +/* including simdjson/rvv-vls/base.h: #include "simdjson/rvv-vls/base.h" */ +/* begin file simdjson/rvv-vls/base.h */ +#ifndef SIMDJSON_RVV_VLS_BASE_H +#define SIMDJSON_RVV_VLS_BASE_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +/** + * RVV-VLS implementation. + */ +namespace rvv_vls { + +class implementation; + +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_BASE_H +/* end file simdjson/rvv-vls/base.h */ +/* including simdjson/rvv-vls/intrinsics.h: #include "simdjson/rvv-vls/intrinsics.h" */ +/* begin file simdjson/rvv-vls/intrinsics.h */ +#ifndef SIMDJSON_RVV_VLS_INTRINSICS_H +#define SIMDJSON_RVV_VLS_INTRINSICS_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include + +#define simdutf_vrgather_u8m1x2(tbl, idx) \ + __riscv_vcreate_v_u8m1_u8m2( \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m2_u8m1(idx, 0), \ + __riscv_vsetvlmax_e8m1()), \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m2_u8m1(idx, 1), \ + __riscv_vsetvlmax_e8m1())) + +#define simdutf_vrgather_u8m1x4(tbl, idx) \ + __riscv_vcreate_v_u8m1_u8m4( \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 0), \ + __riscv_vsetvlmax_e8m1()), \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 1), \ + __riscv_vsetvlmax_e8m1()), \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 2), \ + __riscv_vsetvlmax_e8m1()), \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 3), \ + __riscv_vsetvlmax_e8m1())) + +#if __riscv_zbc +#include +#endif + +#endif // SIMDJSON_RVV_VLS_INTRINSICS_H +/* end file simdjson/rvv-vls/intrinsics.h */ +/* including simdjson/rvv-vls/bitmanipulation.h: #include "simdjson/rvv-vls/bitmanipulation.h" */ +/* begin file simdjson/rvv-vls/bitmanipulation.h */ +#ifndef SIMDJSON_RVV_VLS_BITMANIPULATION_H +#define SIMDJSON_RVV_VLS_BITMANIPULATION_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { + +// We sometimes call trailing_zero on inputs that are zero, +// but the algorithms do not end up using the returned value. +// Sadly, sanitizers are not smart enough to figure it out. +SIMDJSON_NO_SANITIZE_UNDEFINED +// This function can be used safely even if not all bytes have been +// initialized. +// See issue https://github.com/simdjson/simdjson/issues/1965 +SIMDJSON_NO_SANITIZE_MEMORY +simdjson_inline int trailing_zeroes(uint64_t input_num) { + return __builtin_ctzll(input_num); +} + +/* result might be undefined when input_num is zero */ +simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) { + return input_num & (input_num-1); +} + +/* result might be undefined when input_num is zero */ +simdjson_inline int leading_zeroes(uint64_t input_num) { + return __builtin_clzll(input_num); +} + +simdjson_inline long long int count_ones(uint64_t input_num) { + return __builtin_popcountll(input_num); +} + +simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, + uint64_t *result) { + return __builtin_uaddll_overflow(value1, value2, + reinterpret_cast(result)); +} + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_BITMANIPULATION_H +/* end file simdjson/rvv-vls/bitmanipulation.h */ +/* including simdjson/rvv-vls/bitmask.h: #include "simdjson/rvv-vls/bitmask.h" */ +/* begin file simdjson/rvv-vls/bitmask.h */ +#ifndef SIMDJSON_RVV_VLS_BITMASK_H +#define SIMDJSON_RVV_VLS_BITMASK_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/intrinsics.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { + +// +// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered. +// +// For example, prefix_xor(00100100) == 00011100 +// +simdjson_inline uint64_t prefix_xor(uint64_t bitmask) { +#if __riscv_zbc + return __riscv_clmul_64(bitmask, ~(uint64_t)0); +#elif __riscv_zvbc + return __riscv_vmv_x(__riscv_vclmul(__riscv_vmv_s_x_u64m1(bitmask, 1), ~(uint64_t)0, 1)); +#else + bitmask ^= bitmask << 1; + bitmask ^= bitmask << 2; + bitmask ^= bitmask << 4; + bitmask ^= bitmask << 8; + bitmask ^= bitmask << 16; + bitmask ^= bitmask << 32; +#endif + return bitmask; +} + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_BITMASK_H + +/* end file simdjson/rvv-vls/bitmask.h */ +/* including simdjson/rvv-vls/simd.h: #include "simdjson/rvv-vls/simd.h" */ +/* begin file simdjson/rvv-vls/simd.h */ +#ifndef SIMDJSON_RVV_VLS_SIMD_H +#define SIMDJSON_RVV_VLS_SIMD_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/bitmanipulation.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/simdprune_tables.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace simd { + +#if __riscv_v_fixed_vlen >= 512 + static constexpr size_t VL8 = 512/8; + using vint8_t = vint8m1_t __attribute__((riscv_rvv_vector_bits(512))); + using vuint8_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(512))); + using vbool_t = vbool8_t __attribute__((riscv_rvv_vector_bits(512/8))); + using vbitmask_t = uint64_t; +#else + static constexpr size_t VL8 = __riscv_v_fixed_vlen/8; + using vint8_t = vint8m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen))); + using vuint8_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen))); + using vbool_t = vbool8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/8))); + #if __riscv_v_fixed_vlen == 128 + using vbitmask_t = uint16_t; + #elif __riscv_v_fixed_vlen == 256 + using vbitmask_t = uint32_t; + #endif +#endif + +#if __riscv_v_fixed_vlen == 128 + using vuint8x64_t = vuint8m4_t __attribute__((riscv_rvv_vector_bits(512))); + using vboolx64_t = vbool2_t __attribute__((riscv_rvv_vector_bits(512/8))); +#elif __riscv_v_fixed_vlen == 256 + using vuint8x64_t = vuint8m2_t __attribute__((riscv_rvv_vector_bits(512))); + using vboolx64_t = vbool4_t __attribute__((riscv_rvv_vector_bits(512/8))); +#else + using vuint8x64_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(512))); + using vboolx64_t = vbool8_t __attribute__((riscv_rvv_vector_bits(512/8))); +#endif + + template + struct simd8; + + // SIMD byte mask type (returned by things like eq and gt) + template<> + struct simd8 { + vbool_t value; + using bitmask_t = vbitmask_t; + static constexpr int SIZE = sizeof(value); + + simdjson_inline simd8(const vbool_t _value) : value(_value) {} + simdjson_inline simd8() : simd8(__riscv_vmclr_m_b8(VL8)) {} + simdjson_inline simd8(bool _value) : simd8(splat(_value)) {} + + simdjson_inline operator const vbool_t&() const { return value; } + simdjson_inline operator vbool_t&() { return value; } + + static simdjson_inline simd8 splat(bool _value) { + return __riscv_vreinterpret_b8(__riscv_vmv_v_x_u64m1(((uint64_t)!_value)-1, 1)); + } + + simdjson_inline vbitmask_t to_bitmask() const { +#if __riscv_v_fixed_vlen == 128 + return __riscv_vmv_x(__riscv_vreinterpret_u16m1(value)); +#elif __riscv_v_fixed_vlen == 256 + return __riscv_vmv_x(__riscv_vreinterpret_u32m1(value)); +#else + return __riscv_vmv_x(__riscv_vreinterpret_u64m1(value)); +#endif + } + + // Bit operations + simdjson_inline simd8 operator|(const simd8 other) const { return __riscv_vmor(*this, other, VL8); } + simdjson_inline simd8 operator&(const simd8 other) const { return __riscv_vmand(*this, other, VL8); } + simdjson_inline simd8 operator^(const simd8 other) const { return __riscv_vmxor(*this, other, VL8); } + simdjson_inline simd8 bit_andnot(const simd8 other) const { return __riscv_vmandn(other, *this, VL8); } + simdjson_inline simd8 operator~() const { return __riscv_vmnot(*this, VL8); } + simdjson_inline simd8& operator|=(const simd8 other) { auto this_cast = static_cast*>(this); *this_cast = *this_cast | other; return *this_cast; } + simdjson_inline simd8& operator&=(const simd8 other) { auto this_cast = static_cast*>(this); *this_cast = *this_cast & other; return *this_cast; } + simdjson_inline simd8& operator^=(const simd8 other) { auto this_cast = static_cast*>(this); *this_cast = *this_cast ^ other; return *this_cast; } + }; + + // Unsigned bytes + template<> + struct simd8 { + + vuint8_t value; + static constexpr int SIZE = sizeof(value); + + simdjson_inline simd8(const vuint8_t _value) : value(_value) {} + simdjson_inline simd8() : simd8(zero()) {} + simdjson_inline simd8(const uint8_t values[VL8]) : simd8(load(values)) {} + simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {} + simdjson_inline simd8(simd8 mask) : value(__riscv_vmerge_vxm_u8m1(zero(), -1, (vbool_t)mask, VL8)) {} + + simdjson_inline operator const vuint8_t&() const { return this->value; } + simdjson_inline operator vuint8_t&() { return this->value; } + + simdjson_inline simd8( + uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7, + uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15 + ) : simd8(vuint8_t{ + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + }) {} + + // Repeat 16 values as many times as necessary (usually for lookup tables) + simdjson_inline static simd8 repeat_16( + uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7, + uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15 + ) { + return simd8( + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + ); + } + + static simdjson_inline vuint8_t splat(uint8_t _value) { return __riscv_vmv_v_x_u8m1(_value, VL8); } + static simdjson_inline vuint8_t zero() { return splat(0); } + static simdjson_inline vuint8_t load(const uint8_t values[VL8]) { return __riscv_vle8_v_u8m1(values, VL8); } + + // Bit operations + simdjson_inline simd8 operator|(const simd8 other) const { return __riscv_vor_vv_u8m1( value, other, VL8); } + simdjson_inline simd8 operator&(const simd8 other) const { return __riscv_vand_vv_u8m1( value, other, VL8); } + simdjson_inline simd8 operator^(const simd8 other) const { return __riscv_vxor_vv_u8m1( value, other, VL8); } + simdjson_inline simd8 operator~() const { return __riscv_vnot_v_u8m1(value, VL8); } +#if __riscv_zvbb + simdjson_inline simd8 bit_andnot(const simd8 other) const { return __riscv_vandn_vv_u8m1(other, value, VL8); } +#else + simdjson_inline simd8 bit_andnot(const simd8 other) const { return other & ~*this; } +#endif + simdjson_inline simd8& operator|=(const simd8 other) { value = *this | other; return *this; } + simdjson_inline simd8& operator&=(const simd8 other) { value = *this & other; return *this; } + simdjson_inline simd8& operator^=(const simd8 other) { value = *this ^ other; return *this; } + + simdjson_inline simd8 operator==(const simd8 other) const { return __riscv_vmseq(value, other, VL8); } + simdjson_inline simd8 operator==(uint8_t other) const { return __riscv_vmseq(value, other, VL8); } + + template + simdjson_inline simd8 prev(const simd8 prev_chunk) const { + return __riscv_vslideup(__riscv_vslidedown(prev_chunk, VL8-N, VL8), value, N, VL8); + } + + // Store to array + simdjson_inline void store(uint8_t dst[VL8]) const { return __riscv_vse8(dst, value, VL8); } + + // Saturated math + simdjson_inline simd8 saturating_add(const simd8 other) const { return __riscv_vsaddu(value, other, VL8); } + simdjson_inline simd8 saturating_sub(const simd8 other) const { return __riscv_vssubu(value, other, VL8); } + + // Addition/subtraction are the same for signed and unsigned + simdjson_inline simd8 operator+(const simd8 other) const { return __riscv_vadd(value, other, VL8); } + simdjson_inline simd8 operator-(const simd8 other) const { return __riscv_vsub(value, other, VL8); } + simdjson_inline simd8& operator+=(const simd8 other) { value = *this + other; return *this; } + simdjson_inline simd8& operator-=(const simd8 other) { value = *this - other; return *this; } + + // Order-specific operations + simdjson_inline simd8 operator<=(const simd8 other) const { return __riscv_vmsleu(value, other, VL8); } + simdjson_inline simd8 operator>=(const simd8 other) const { return __riscv_vmsgeu(value, other, VL8); } + simdjson_inline simd8 operator<(const simd8 other) const { return __riscv_vmsltu(value, other, VL8); } + simdjson_inline simd8 operator>(const simd8 other) const { return __riscv_vmsgtu(value, other, VL8); } + + // Same as >, but instead of guaranteeing all 1's == true, false = 0 and true = nonzero. + simdjson_inline simd8 gt_bits(const simd8 other) const { return simd8(*this > other); } + // Same as <, but instead of guaranteeing all 1's == true, false = 0 and true = nonzero. + simdjson_inline simd8 lt_bits(const simd8 other) const { return simd8(*this < other); } + + // Bit-specific operations + simdjson_inline bool any_bits_set_anywhere() const { + return __riscv_vfirst(__riscv_vmsne(value, 0, VL8), VL8) >= 0; + } + simdjson_inline bool any_bits_set_anywhere(simd8 bits) const { return (*this & bits).any_bits_set_anywhere(); } + template + simdjson_inline simd8 shr() const { return __riscv_vsrl(value, N, VL8); } + template + simdjson_inline simd8 shl() const { return __riscv_vsll(value, N, VL8); } + + + // Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values) + template + simdjson_inline simd8 lookup_16(simd8 lookup_table) const { + return __riscv_vrgather(lookup_table, value, VL8); + } + + // compress inactive elements, to match AVX-512 behavior + template + simdjson_inline void compress(vbitmask_t mask, L * output) const { + mask = (vbitmask_t)~mask; +#if __riscv_v_fixed_vlen == 128 + vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u16m1(mask, 1)); +#elif __riscv_v_fixed_vlen == 256 + vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u32m1(mask, 1)); +#else + vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u64m1(mask, 1)); +#endif + __riscv_vse8_v_u8m1(output, __riscv_vcompress(value, m, VL8), count_ones(mask)); + } + + template + simdjson_inline simd8 lookup_16( + L replace0, L replace1, L replace2, L replace3, + L replace4, L replace5, L replace6, L replace7, + L replace8, L replace9, L replace10, L replace11, + L replace12, L replace13, L replace14, L replace15) const { + return lookup_16(simd8::repeat_16( + replace0, replace1, replace2, replace3, + replace4, replace5, replace6, replace7, + replace8, replace9, replace10, replace11, + replace12, replace13, replace14, replace15 + )); + } + }; + + // Signed bytes + template<> + struct simd8 { + vint8_t value; + static constexpr int SIZE = sizeof(value); + + simdjson_inline simd8(const vint8_t _value) : value(_value) {} + simdjson_inline simd8() : simd8(zero()) {} + simdjson_inline simd8(const int8_t values[VL8]) : simd8(load(values)) {} + simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {} + + simdjson_inline operator const vint8_t&() const { return this->value; } + simdjson_inline operator vint8_t&() { return this->value; } + + simdjson_inline simd8( + int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7, + int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15 + ) : simd8(vint8_t{ + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + }) {} + + // Repeat 16 values as many times as necessary (usually for lookup tables) + simdjson_inline static simd8 repeat_16( + int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7, + int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15 + ) { + return simd8( + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + ); + } + + static simdjson_inline vint8_t splat(int8_t _value) { return __riscv_vmv_v_x_i8m1(_value, VL8); } + static simdjson_inline vint8_t zero() { return splat(0); } + static simdjson_inline vint8_t load(const int8_t values[VL8]) { return __riscv_vle8_v_i8m1(values, VL8); } + + + simdjson_inline void store(int8_t dst[VL8]) const { return __riscv_vse8(dst, value, VL8); } + + // Explicit conversion to/from unsigned + simdjson_inline explicit simd8(const vuint8_t other): simd8(__riscv_vreinterpret_i8m1(other)) {} + simdjson_inline explicit operator simd8() const { return __riscv_vreinterpret_u8m1(value); } + + // Math + simdjson_inline simd8 operator+(const simd8 other) const { return __riscv_vadd(value, other, VL8); } + simdjson_inline simd8 operator-(const simd8 other) const { return __riscv_vsub(value, other, VL8); } + simdjson_inline simd8& operator+=(const simd8 other) { value = *this + other; return *this; } + simdjson_inline simd8& operator-=(const simd8 other) { value = *this - other; return *this; } + + // Order-sensitive comparisons + simdjson_inline simd8 max_val( const simd8 other) const { return __riscv_vmax( value, other, VL8); } + simdjson_inline simd8 min_val( const simd8 other) const { return __riscv_vmin( value, other, VL8); } + simdjson_inline simd8 operator>( const simd8 other) const { return __riscv_vmsgt(value, other, VL8); } + simdjson_inline simd8 operator<( const simd8 other) const { return __riscv_vmslt(value, other, VL8); } + simdjson_inline simd8 operator==(const simd8 other) const { return __riscv_vmseq(value, other, VL8); } + + template + simdjson_inline simd8 prev(const simd8 prev_chunk) const { + return __riscv_vslideup(__riscv_vslidedown(prev_chunk, VL8-N, VL8), value, N, VL8); + } + + // Perform a lookup assuming no value is larger than 16 + template + simdjson_inline simd8 lookup_16(simd8 lookup_table) const { + return __riscv_vrgather(lookup_table, value, VL8); + } + template + simdjson_inline simd8 lookup_16( + L replace0, L replace1, L replace2, L replace3, + L replace4, L replace5, L replace6, L replace7, + L replace8, L replace9, L replace10, L replace11, + L replace12, L replace13, L replace14, L replace15) const { + return lookup_16(simd8::repeat_16( + replace0, replace1, replace2, replace3, + replace4, replace5, replace6, replace7, + replace8, replace9, replace10, replace11, + replace12, replace13, replace14, replace15 + )); + } + }; + + template + struct simd8x64; + template<> + struct simd8x64 { + static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); + vuint8x64_t value; + +#if __riscv_v_fixed_vlen >= 512 + template simd8 get() const { return value; } +#else + template simd8 get() const { return __riscv_vget_u8m1(value, idx); } +#endif + + simdjson_inline operator const vuint8x64_t&() const { return this->value; } + simdjson_inline operator vuint8x64_t&() { return this->value; } + + simd8x64(const simd8x64& o) = delete; // no copy allowed + simd8x64& operator=(const simd8& other) = delete; // no assignment allowed + simd8x64() = delete; // no default constructor allowed + +#if __riscv_v_fixed_vlen == 128 + simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m4(ptr, n)) {} +#elif __riscv_v_fixed_vlen == 256 + simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m2(ptr, n)) {} +#else + simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m1(ptr, n)) {} +#endif + + simdjson_inline void store(uint8_t ptr[64]) const { + __riscv_vse8(ptr, value, 64); + } + + simdjson_inline bool is_ascii() const { +#if __riscv_v_fixed_vlen == 128 + return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m4(value), 0, 64), 64) < 0; +#elif __riscv_v_fixed_vlen == 256 + return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m2(value), 0, 64), 64) < 0; +#else + return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m1(value), 0, 64), 64) < 0; +#endif + } + + // compress inactive elements, to match AVX-512 behavior + simdjson_inline uint64_t compress(uint64_t mask, uint8_t * output) const { + mask = ~mask; +#if __riscv_v_fixed_vlen == 128 + vboolx64_t m = __riscv_vreinterpret_b2(__riscv_vmv_s_x_u64m1(mask, 1)); +#elif __riscv_v_fixed_vlen == 256 + vboolx64_t m = __riscv_vreinterpret_b4(__riscv_vmv_s_x_u64m1(mask, 1)); +#else + vboolx64_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u64m1(mask, 1)); +#endif + size_t cnt = count_ones(mask); + __riscv_vse8(output, __riscv_vcompress(value, m, 64), cnt); + return cnt; + } + + simdjson_inline uint64_t eq(const uint8_t m) const { + return __riscv_vmv_x(__riscv_vreinterpret_u64m1(__riscv_vmseq(value, m, 64))); + } + + simdjson_inline uint64_t lteq(const uint8_t m) const { + return __riscv_vmv_x(__riscv_vreinterpret_u64m1(__riscv_vmsleu(value, m, 64))); + } + }; // struct simd8x64 + +} // namespace simd +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_SIMD_H +/* end file simdjson/rvv-vls/simd.h */ +/* including simdjson/rvv-vls/stringparsing_defs.h: #include "simdjson/rvv-vls/stringparsing_defs.h" */ +/* begin file simdjson/rvv-vls/stringparsing_defs.h */ +#ifndef SIMDJSON_RVV_VLS_STRINGPARSING_DEFS_H +#define SIMDJSON_RVV_VLS_STRINGPARSING_DEFS_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { + +using namespace simd; + +// Holds backslashes and quotes locations. +struct backslash_and_quote { +public: + static constexpr uint64_t BYTES_PROCESSED = sizeof(simd8); + simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + + simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; } + simdjson_inline bool has_backslash() { return ((quote_bits - 1) & bs_bits) != 0; } + simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); } + simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); } + + uint64_t bs_bits; + uint64_t quote_bits; +}; // struct backslash_and_quote + +simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) { + static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes"); + simd8 v(src); + v.store(dst); + return { (v == '\\').to_bitmask(), (v == '"').to_bitmask() }; +} + +struct escaping { + static constexpr uint64_t BYTES_PROCESSED = sizeof(simd8); + simdjson_inline static escaping copy_and_find(const uint8_t *src, uint8_t *dst); + + simdjson_inline bool has_escape() { return escape_bits != 0; } + simdjson_inline int escape_index() { return trailing_zeroes(escape_bits) / 4; } + + uint64_t escape_bits; +}; // struct escaping + +simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *dst) { + static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "escaping finder must process fewer than SIMDJSON_PADDING bytes"); + simd8 v(src); + v.store(dst); + return { ((v == '"') | (v == '\\') | (v == 32)).to_bitmask() }; +} + + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_STRINGPARSING_DEFS_H +/* end file simdjson/rvv-vls/stringparsing_defs.h */ +/* including simdjson/rvv-vls/numberparsing_defs.h: #include "simdjson/rvv-vls/numberparsing_defs.h" */ +/* begin file simdjson/rvv-vls/numberparsing_defs.h */ +#ifndef SIMDJSON_RVV_VLS_NUMBERPARSING_DEFS_H +#define SIMDJSON_RVV_VLS_NUMBERPARSING_DEFS_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include + +#ifdef JSON_TEST_NUMBERS // for unit testing +void found_invalid_number(const uint8_t *buf); +void found_integer(int64_t result, const uint8_t *buf); +void found_unsigned_integer(uint64_t result, const uint8_t *buf); +void found_float(double result, const uint8_t *buf); +#endif + +namespace simdjson { +namespace rvv_vls { +namespace numberparsing { + +// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/ +/** @private */ +static simdjson_inline uint32_t parse_eight_digits_unrolled(const char *chars) { + uint64_t val; +#if __riscv_misaligned_fast + memcpy(&val, chars, sizeof(uint64_t)); +#else + val = __riscv_vmv_x(__riscv_vreinterpret_u64m1(__riscv_vlmul_ext_u8m1(__riscv_vle8_v_u8mf2((uint8_t*)chars, 8)))); +#endif + val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8; + val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16; + return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32); +} + +/** @private */ +static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) { + return parse_eight_digits_unrolled(reinterpret_cast(chars)); +} + +/** @private */ +simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) { + internal::value128 answer; + __uint128_t r = (static_cast<__uint128_t>(value1)) * value2; + answer.low = uint64_t(r); + answer.high = uint64_t(r >> 64); + return answer; +} + +} // namespace numberparsing +} // namespace rvv_vls +} // namespace simdjson + +#define SIMDJSON_SWAR_NUMBER_PARSING 1 + +#endif // SIMDJSON_RVV_VLS_NUMBERPARSING_DEFS_H +/* end file simdjson/rvv-vls/numberparsing_defs.h */ + +#define SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT 1 +/* end file simdjson/rvv-vls/begin.h */ +/* including simdjson/generic/amalgamated.h for rvv_vls: #include "simdjson/generic/amalgamated.h" */ +/* begin file simdjson/generic/amalgamated.h for rvv_vls */ +#if defined(SIMDJSON_CONDITIONAL_INCLUDE) && !defined(SIMDJSON_GENERIC_DEPENDENCIES_H) +#error simdjson/generic/dependencies.h must be included before simdjson/generic/amalgamated.h! +#endif + +/* including simdjson/generic/base.h for rvv_vls: #include "simdjson/generic/base.h" */ +/* begin file simdjson/generic/base.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_BASE_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_BASE_H */ +/* amalgamation skipped (editor-only): #include "simdjson/base.h" */ +/* amalgamation skipped (editor-only): // If we haven't got an implementation yet, we're in the editor, editing a generic file! Just */ +/* amalgamation skipped (editor-only): // use the most advanced one we can so the most possible stuff can be tested. */ +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_IMPLEMENTATION */ +/* amalgamation skipped (editor-only): #include "simdjson/implementation_detection.h" */ +/* amalgamation skipped (editor-only): #if SIMDJSON_IMPLEMENTATION_ICELAKE */ +/* amalgamation skipped (editor-only): #include "simdjson/icelake/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_HASWELL */ +/* amalgamation skipped (editor-only): #include "simdjson/haswell/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_WESTMERE */ +/* amalgamation skipped (editor-only): #include "simdjson/westmere/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_ARM64 */ +/* amalgamation skipped (editor-only): #include "simdjson/arm64/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_PPC64 */ +/* amalgamation skipped (editor-only): #include "simdjson/ppc64/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_LASX */ +/* amalgamation skipped (editor-only): #include "simdjson/lasx/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_LSX */ +/* amalgamation skipped (editor-only): #include "simdjson/lsx/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_RVV_VLS */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/begin.h" */ +/* amalgamation skipped (editor-only): #elif SIMDJSON_IMPLEMENTATION_FALLBACK */ +/* amalgamation skipped (editor-only): #include "simdjson/fallback/begin.h" */ +/* amalgamation skipped (editor-only): #else */ +/* amalgamation skipped (editor-only): #error "All possible implementations (including fallback) have been disabled! simdjson will not run." */ +/* amalgamation skipped (editor-only): #endif */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_IMPLEMENTATION */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { + +struct open_container; +class dom_parser_implementation; + +/** + * The type of a JSON number + */ +enum class number_type { + floating_point_number=1, /// a binary64 number + signed_integer, /// a signed integer that fits in a 64-bit word using two's complement + unsigned_integer, /// a positive integer larger or equal to 1<<63 + big_integer /// a big integer that does not fit in a 64-bit word +}; + +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_BASE_H +/* end file simdjson/generic/base.h for rvv_vls */ +/* including simdjson/generic/jsoncharutils.h for rvv_vls: #include "simdjson/generic/jsoncharutils.h" */ +/* begin file simdjson/generic/jsoncharutils.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_JSONCHARUTILS_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_JSONCHARUTILS_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/jsoncharutils_tables.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace jsoncharutils { + +// return non-zero if not a structural or whitespace char +// zero otherwise +simdjson_inline uint32_t is_not_structural_or_whitespace(uint8_t c) { + return internal::structural_or_whitespace_negated[c]; +} + +simdjson_inline uint32_t is_structural_or_whitespace(uint8_t c) { + return internal::structural_or_whitespace[c]; +} + +// returns a value with the high 16 bits set if not valid +// otherwise returns the conversion of the 4 hex digits at src into the bottom +// 16 bits of the 32-bit return register +// +// see +// https://lemire.me/blog/2019/04/17/parsing-short-hexadecimal-strings-efficiently/ +static inline uint32_t hex_to_u32_nocheck( + const uint8_t *src) { // strictly speaking, static inline is a C-ism + uint32_t v1 = internal::digit_to_val32[630 + src[0]]; + uint32_t v2 = internal::digit_to_val32[420 + src[1]]; + uint32_t v3 = internal::digit_to_val32[210 + src[2]]; + uint32_t v4 = internal::digit_to_val32[0 + src[3]]; + return v1 | v2 | v3 | v4; +} + +// given a code point cp, writes to c +// the utf-8 code, outputting the length in +// bytes, if the length is zero, the code point +// is invalid +// +// This can possibly be made faster using pdep +// and clz and table lookups, but JSON documents +// have few escaped code points, and the following +// function looks cheap. +// +// Note: we assume that surrogates are treated separately +// +simdjson_inline size_t codepoint_to_utf8(uint32_t cp, uint8_t *c) { + if (cp <= 0x7F) { + c[0] = uint8_t(cp); + return 1; // ascii + } + if (cp <= 0x7FF) { + c[0] = uint8_t((cp >> 6) + 192); + c[1] = uint8_t((cp & 63) + 128); + return 2; // universal plane + // Surrogates are treated elsewhere... + //} //else if (0xd800 <= cp && cp <= 0xdfff) { + // return 0; // surrogates // could put assert here + } else if (cp <= 0xFFFF) { + c[0] = uint8_t((cp >> 12) + 224); + c[1] = uint8_t(((cp >> 6) & 63) + 128); + c[2] = uint8_t((cp & 63) + 128); + return 3; + } else if (cp <= 0x10FFFF) { // if you know you have a valid code point, this + // is not needed + c[0] = uint8_t((cp >> 18) + 240); + c[1] = uint8_t(((cp >> 12) & 63) + 128); + c[2] = uint8_t(((cp >> 6) & 63) + 128); + c[3] = uint8_t((cp & 63) + 128); + return 4; + } + // will return 0 when the code point was too large. + return 0; // bad r +} + +#if SIMDJSON_IS_32BITS // _umul128 for x86, arm +// this is a slow emulation routine for 32-bit +// +static simdjson_inline uint64_t __emulu(uint32_t x, uint32_t y) { + return x * (uint64_t)y; +} +static simdjson_inline uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi) { + uint64_t ad = __emulu((uint32_t)(ab >> 32), (uint32_t)cd); + uint64_t bd = __emulu((uint32_t)ab, (uint32_t)cd); + uint64_t adbc = ad + __emulu((uint32_t)ab, (uint32_t)(cd >> 32)); + uint64_t adbc_carry = !!(adbc < ad); + uint64_t lo = bd + (adbc << 32); + *hi = __emulu((uint32_t)(ab >> 32), (uint32_t)(cd >> 32)) + (adbc >> 32) + + (adbc_carry << 32) + !!(lo < bd); + return lo; +} +#endif + +} // namespace jsoncharutils +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_JSONCHARUTILS_H +/* end file simdjson/generic/jsoncharutils.h for rvv_vls */ +/* including simdjson/generic/atomparsing.h for rvv_vls: #include "simdjson/generic/atomparsing.h" */ +/* begin file simdjson/generic/atomparsing.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ATOMPARSING_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ATOMPARSING_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/jsoncharutils.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include + +namespace simdjson { +namespace rvv_vls { +namespace { +/// @private +namespace atomparsing { + +// The string_to_uint32 is exclusively used to map literal strings to 32-bit values. +// We use memcpy instead of a pointer cast to avoid undefined behaviors since we cannot +// be certain that the character pointer will be properly aligned. +// You might think that using memcpy makes this function expensive, but you'd be wrong. +// All decent optimizing compilers (GCC, clang, Visual Studio) will compile string_to_uint32("false"); +// to the compile-time constant 1936482662. +simdjson_inline uint32_t string_to_uint32(const char* str) { uint32_t val; std::memcpy(&val, str, sizeof(uint32_t)); return val; } + + +// Again in str4ncmp we use a memcpy to avoid undefined behavior. The memcpy may appear expensive. +// Yet all decent optimizing compilers will compile memcpy to a single instruction, just about. +simdjson_warn_unused +simdjson_inline uint32_t str4ncmp(const uint8_t *src, const char* atom) { + uint32_t srcval; // we want to avoid unaligned 32-bit loads (undefined in C/C++) + static_assert(sizeof(uint32_t) <= SIMDJSON_PADDING, "SIMDJSON_PADDING must be larger than 4 bytes"); + std::memcpy(&srcval, src, sizeof(uint32_t)); + return srcval ^ string_to_uint32(atom); +} + +simdjson_warn_unused +simdjson_inline bool is_valid_true_atom(const uint8_t *src) { + return (str4ncmp(src, "true") | jsoncharutils::is_not_structural_or_whitespace(src[4])) == 0; +} + +simdjson_warn_unused +simdjson_inline bool is_valid_true_atom(const uint8_t *src, size_t len) { + if (len > 4) { return is_valid_true_atom(src); } + else if (len == 4) { return !str4ncmp(src, "true"); } + else { return false; } +} + +simdjson_warn_unused +simdjson_inline bool is_valid_false_atom(const uint8_t *src) { + return (str4ncmp(src+1, "alse") | jsoncharutils::is_not_structural_or_whitespace(src[5])) == 0; +} + +simdjson_warn_unused +simdjson_inline bool is_valid_false_atom(const uint8_t *src, size_t len) { + if (len > 5) { return is_valid_false_atom(src); } + else if (len == 5) { return !str4ncmp(src+1, "alse"); } + else { return false; } +} + +simdjson_warn_unused +simdjson_inline bool is_valid_null_atom(const uint8_t *src) { + return (str4ncmp(src, "null") | jsoncharutils::is_not_structural_or_whitespace(src[4])) == 0; +} + +simdjson_warn_unused +simdjson_inline bool is_valid_null_atom(const uint8_t *src, size_t len) { + if (len > 4) { return is_valid_null_atom(src); } + else if (len == 4) { return !str4ncmp(src, "null"); } + else { return false; } +} + +} // namespace atomparsing +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ATOMPARSING_H +/* end file simdjson/generic/atomparsing.h for rvv_vls */ +/* including simdjson/generic/dom_parser_implementation.h for rvv_vls: #include "simdjson/generic/dom_parser_implementation.h" */ +/* begin file simdjson/generic/dom_parser_implementation.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_DOM_PARSER_IMPLEMENTATION_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_DOM_PARSER_IMPLEMENTATION_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { + +// expectation: sizeof(open_container) = 64/8. +struct open_container { + uint32_t tape_index; // where, on the tape, does the scope ([,{) begins + uint32_t count; // how many elements in the scope +}; // struct open_container + +static_assert(sizeof(open_container) == 64/8, "Open container must be 64 bits"); + +class dom_parser_implementation final : public internal::dom_parser_implementation { +public: + /** Tape location of each open { or [ */ + std::unique_ptr open_containers{}; + /** Whether each open container is a [ or { */ + std::unique_ptr is_array{}; + /** Buffer passed to stage 1 */ + const uint8_t *buf{}; + /** Length passed to stage 1 */ + size_t len{0}; + /** Document passed to stage 2 */ + dom::document *doc{}; + + inline dom_parser_implementation() noexcept; + inline dom_parser_implementation(dom_parser_implementation &&other) noexcept; + inline dom_parser_implementation &operator=(dom_parser_implementation &&other) noexcept; + dom_parser_implementation(const dom_parser_implementation &) = delete; + dom_parser_implementation &operator=(const dom_parser_implementation &) = delete; + + simdjson_warn_unused error_code parse(const uint8_t *buf, size_t len, dom::document &doc) noexcept final; + simdjson_warn_unused error_code stage1(const uint8_t *buf, size_t len, stage1_mode partial) noexcept final; + simdjson_warn_unused error_code stage2(dom::document &doc) noexcept final; + simdjson_warn_unused error_code stage2_next(dom::document &doc) noexcept final; + simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept final; + simdjson_warn_unused uint8_t *parse_wobbly_string(const uint8_t *src, uint8_t *dst) const noexcept final; + inline simdjson_warn_unused error_code set_capacity(size_t capacity) noexcept final; + inline simdjson_warn_unused error_code set_max_depth(size_t max_depth) noexcept final; +private: + simdjson_inline simdjson_warn_unused error_code set_capacity_stage1(size_t capacity); + +}; + +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { +namespace rvv_vls { + +inline dom_parser_implementation::dom_parser_implementation() noexcept = default; +inline dom_parser_implementation::dom_parser_implementation(dom_parser_implementation &&other) noexcept = default; +inline dom_parser_implementation &dom_parser_implementation::operator=(dom_parser_implementation &&other) noexcept = default; + +// Leaving these here so they can be inlined if so desired +inline simdjson_warn_unused error_code dom_parser_implementation::set_capacity(size_t capacity) noexcept { + if(capacity > SIMDJSON_MAXSIZE_BYTES) { return CAPACITY; } + // Stage 1 index output + size_t max_structures = SIMDJSON_ROUNDUP_N(capacity, 64) + 2 + 7; + structural_indexes.reset( new (std::nothrow) uint32_t[max_structures] ); + if (!structural_indexes) { _capacity = 0; return MEMALLOC; } + structural_indexes[0] = 0; + n_structural_indexes = 0; + + _capacity = capacity; + return SUCCESS; +} + +inline simdjson_warn_unused error_code dom_parser_implementation::set_max_depth(size_t max_depth) noexcept { + // Stage 2 stacks + open_containers.reset(new (std::nothrow) open_container[max_depth]); + is_array.reset(new (std::nothrow) bool[max_depth]); + if (!is_array || !open_containers) { _max_depth = 0; return MEMALLOC; } + + _max_depth = max_depth; + return SUCCESS; +} + +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_DOM_PARSER_IMPLEMENTATION_H +/* end file simdjson/generic/dom_parser_implementation.h for rvv_vls */ +/* including simdjson/generic/implementation_simdjson_result_base.h for rvv_vls: #include "simdjson/generic/implementation_simdjson_result_base.h" */ +/* begin file simdjson/generic/implementation_simdjson_result_base.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_IMPLEMENTATION_SIMDJSON_RESULT_BASE_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_IMPLEMENTATION_SIMDJSON_RESULT_BASE_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { + +// This is a near copy of include/error.h's implementation_simdjson_result_base, except it doesn't use std::pair +// so we can avoid inlining errors +// TODO reconcile these! +/** + * The result of a simdjson operation that could fail. + * + * Gives the option of reading error codes, or throwing an exception by casting to the desired result. + * + * This is a base class for implementations that want to add functions to the result type for + * chaining. + * + * Override like: + * + * struct simdjson_result : public internal::implementation_simdjson_result_base { + * simdjson_result() noexcept : internal::implementation_simdjson_result_base() {} + * simdjson_result(error_code error) noexcept : internal::implementation_simdjson_result_base(error) {} + * simdjson_result(T &&value) noexcept : internal::implementation_simdjson_result_base(std::forward(value)) {} + * simdjson_result(T &&value, error_code error) noexcept : internal::implementation_simdjson_result_base(value, error) {} + * // Your extra methods here + * } + * + * Then any method returning simdjson_result will be chainable with your methods. + */ +template +struct implementation_simdjson_result_base { + + /** + * Create a new empty result with error = UNINITIALIZED. + */ + simdjson_inline implementation_simdjson_result_base() noexcept = default; + + /** + * Create a new error result. + */ + simdjson_inline implementation_simdjson_result_base(error_code error) noexcept; + + /** + * Create a new successful result. + */ + simdjson_inline implementation_simdjson_result_base(T &&value) noexcept; + + /** + * Create a new result with both things (use if you don't want to branch when creating the result). + */ + simdjson_inline implementation_simdjson_result_base(T &&value, error_code error) noexcept; + + /** + * Move the value and the error to the provided variables. + * + * @param value The variable to assign the value to. May not be set if there is an error. + * @param error The variable to assign the error to. Set to SUCCESS if there is no error. + */ + simdjson_inline void tie(T &value, error_code &error) && noexcept; + + /** + * Move the value to the provided variable. + * + * @param value The variable to assign the value to. May not be set if there is an error. + */ + simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept; + + /** + * The error. + */ + simdjson_warn_unused simdjson_inline error_code error() const noexcept; + + /** + * Whether there is a value. + */ + simdjson_warn_unused simdjson_inline bool has_value() const noexcept; + +#if SIMDJSON_EXCEPTIONS + + /** + * Get the result value. + * + * @throw simdjson_error if there was an error. + */ + simdjson_inline T& operator*() & noexcept(false); + simdjson_inline T&& operator*() && noexcept(false); + /** + * Arrow operator to access members of the contained value. + * + * @throw simdjson_error if there was an error. + */ + simdjson_inline T* operator->() noexcept(false); + simdjson_inline const T* operator->() const noexcept(false); + + simdjson_inline T& value() & noexcept(false); + + /** + * Take the result value (move it). + * + * @throw simdjson_error if there was an error. + */ + simdjson_inline T&& value() && noexcept(false); + + /** + * Take the result value (move it). + * + * @throw simdjson_error if there was an error. + */ + simdjson_inline T&& take_value() && noexcept(false); + + /** + * Cast to the value (will throw on error). + * + * @throw simdjson_error if there was an error. + */ + simdjson_inline operator T&&() && noexcept(false); + + +#endif // SIMDJSON_EXCEPTIONS + + /** + * Get the result value. This function is safe if and only + * the error() method returns a value that evaluates to false. + */ + simdjson_inline const T& value_unsafe() const& noexcept; + /** + * Get the result value. This function is safe if and only + * the error() method returns a value that evaluates to false. + */ + simdjson_inline T& value_unsafe() & noexcept; + /** + * Take the result value (move it). This function is safe if and only + * the error() method returns a value that evaluates to false. + */ + simdjson_inline T&& value_unsafe() && noexcept; + + using value_type = T; + using error_type = error_code; + +protected: + /** users should never directly access first and second. **/ + T first{}; /** Users should never directly access 'first'. **/ + error_code second{UNINITIALIZED}; /** Users should never directly access 'second'. **/ +}; // struct implementation_simdjson_result_base + +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_IMPLEMENTATION_SIMDJSON_RESULT_BASE_H +/* end file simdjson/generic/implementation_simdjson_result_base.h for rvv_vls */ +/* including simdjson/generic/numberparsing.h for rvv_vls: #include "simdjson/generic/numberparsing.h" */ +/* begin file simdjson/generic/numberparsing.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_NUMBERPARSING_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_NUMBERPARSING_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/jsoncharutils.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include +#include +#include + +namespace simdjson { +namespace rvv_vls { +namespace numberparsing { + +#ifdef JSON_TEST_NUMBERS +#define INVALID_NUMBER(SRC) (found_invalid_number((SRC)), NUMBER_ERROR) +#define WRITE_INTEGER(VALUE, SRC, WRITER) (found_integer((VALUE), (SRC)), (WRITER).append_s64((VALUE))) +#define WRITE_UNSIGNED(VALUE, SRC, WRITER) (found_unsigned_integer((VALUE), (SRC)), (WRITER).append_u64((VALUE))) +#define WRITE_DOUBLE(VALUE, SRC, WRITER) (found_float((VALUE), (SRC)), (WRITER).append_double((VALUE))) +#define BIGINT_NUMBER(SRC) (found_invalid_number((SRC)), BIGINT_ERROR) +#else +#define INVALID_NUMBER(SRC) (NUMBER_ERROR) +#define WRITE_INTEGER(VALUE, SRC, WRITER) (WRITER).append_s64((VALUE)) +#define WRITE_UNSIGNED(VALUE, SRC, WRITER) (WRITER).append_u64((VALUE)) +#define WRITE_DOUBLE(VALUE, SRC, WRITER) (WRITER).append_double((VALUE)) +#define BIGINT_NUMBER(SRC) (BIGINT_ERROR) +#endif + +namespace { + +// Convert a mantissa, an exponent and a sign bit into an ieee64 double. +// The real_exponent needs to be in [0, 2046] (technically real_exponent = 2047 would be acceptable). +// The mantissa should be in [0,1<<53). The bit at index (1ULL << 52) while be zeroed. +simdjson_inline double to_double(uint64_t mantissa, uint64_t real_exponent, bool negative) { + double d; + mantissa &= ~(1ULL << 52); + mantissa |= real_exponent << 52; + mantissa |= ((static_cast(negative)) << 63); + std::memcpy(&d, &mantissa, sizeof(d)); + return d; +} + +// Attempts to compute i * 10^(power) exactly; and if "negative" is +// true, negate the result. +// This function will only work in some cases, when it does not work, success is +// set to false. This should work *most of the time* (like 99% of the time). +// We assume that power is in the [smallest_power, +// largest_power] interval: the caller is responsible for this check. +simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative, double &d) { + // we start with a fast path + // It was described in + // Clinger WD. How to read floating point numbers accurately. + // ACM SIGPLAN Notices. 1990 +#ifndef FLT_EVAL_METHOD +#error "FLT_EVAL_METHOD should be defined, please include cfloat." +#endif +#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) + // We cannot be certain that x/y is rounded to nearest. + if (0 <= power && power <= 22 && i <= 9007199254740991) +#else + if (-22 <= power && power <= 22 && i <= 9007199254740991) +#endif + { + // convert the integer into a double. This is lossless since + // 0 <= i <= 2^53 - 1. + d = double(i); + // + // The general idea is as follows. + // If 0 <= s < 2^53 and if 10^0 <= p <= 10^22 then + // 1) Both s and p can be represented exactly as 64-bit floating-point + // values + // (binary64). + // 2) Because s and p can be represented exactly as floating-point values, + // then s * p + // and s / p will produce correctly rounded values. + // + if (power < 0) { + d = d / simdjson::internal::power_of_ten[-power]; + } else { + d = d * simdjson::internal::power_of_ten[power]; + } + if (negative) { + d = -d; + } + return true; + } + // When 22 < power && power < 22 + 16, we could + // hope for another, secondary fast path. It was + // described by David M. Gay in "Correctly rounded + // binary-decimal and decimal-binary conversions." (1990) + // If you need to compute i * 10^(22 + x) for x < 16, + // first compute i * 10^x, if you know that result is exact + // (e.g., when i * 10^x < 2^53), + // then you can still proceed and do (i * 10^x) * 10^22. + // Is this worth your time? + // You need 22 < power *and* power < 22 + 16 *and* (i * 10^(x-22) < 2^53) + // for this second fast path to work. + // If you you have 22 < power *and* power < 22 + 16, and then you + // optimistically compute "i * 10^(x-22)", there is still a chance that you + // have wasted your time if i * 10^(x-22) >= 2^53. It makes the use cases of + // this optimization maybe less common than we would like. Source: + // http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ + // also used in RapidJSON: https://rapidjson.org/strtod_8h_source.html + + // The fast path has now failed, so we are failing back on the slower path. + + // In the slow path, we need to adjust i so that it is > 1<<63 which is always + // possible, except if i == 0, so we handle i == 0 separately. + if(i == 0) { + d = negative ? -0.0 : 0.0; + return true; + } + + + // The exponent is 1024 + 63 + power + // + floor(log(5**power)/log(2)). + // The 1024 comes from the ieee64 standard. + // The 63 comes from the fact that we use a 64-bit word. + // + // Computing floor(log(5**power)/log(2)) could be + // slow. Instead we use a fast function. + // + // For power in (-400,350), we have that + // (((152170 + 65536) * power ) >> 16); + // is equal to + // floor(log(5**power)/log(2)) + power when power >= 0 + // and it is equal to + // ceil(log(5**-power)/log(2)) + power when power < 0 + // + // The 65536 is (1<<16) and corresponds to + // (65536 * power) >> 16 ---> power + // + // ((152170 * power ) >> 16) is equal to + // floor(log(5**power)/log(2)) + // + // Note that this is not magic: 152170/(1<<16) is + // approximately equal to log(5)/log(2). + // The 1<<16 value is a power of two; we could use a + // larger power of 2 if we wanted to. + // + int64_t exponent = (((152170 + 65536) * power) >> 16) + 1024 + 63; + + + // We want the most significant bit of i to be 1. Shift if needed. + int lz = leading_zeroes(i); + i <<= lz; + + + // We are going to need to do some 64-bit arithmetic to get a precise product. + // We use a table lookup approach. + // It is safe because + // power >= smallest_power + // and power <= largest_power + // We recover the mantissa of the power, it has a leading 1. It is always + // rounded down. + // + // We want the most significant 64 bits of the product. We know + // this will be non-zero because the most significant bit of i is + // 1. + const uint32_t index = 2 * uint32_t(power - simdjson::internal::smallest_power); + // Optimization: It may be that materializing the index as a variable might confuse some compilers and prevent effective complex-addressing loads. (Done for code clarity.) + // + // The full_multiplication function computes the 128-bit product of two 64-bit words + // with a returned value of type value128 with a "low component" corresponding to the + // 64-bit least significant bits of the product and with a "high component" corresponding + // to the 64-bit most significant bits of the product. +#if SIMDJSON_STATIC_REFLECTION + simdjson::internal::value128 firstproduct = full_multiplication(i, simdjson::internal::powers_template<>::power_of_five_128[index]); +#else + simdjson::internal::value128 firstproduct = full_multiplication(i, simdjson::internal::power_of_five_128[index]); +#endif + + // Both i and power_of_five_128[index] have their most significant bit set to 1 which + // implies that the either the most or the second most significant bit of the product + // is 1. We pack values in this manner for efficiency reasons: it maximizes the use + // we make of the product. It also makes it easy to reason about the product: there + // is 0 or 1 leading zero in the product. + + // Unless the least significant 9 bits of the high (64-bit) part of the full + // product are all 1s, then we know that the most significant 55 bits are + // exact and no further work is needed. Having 55 bits is necessary because + // we need 53 bits for the mantissa but we have to have one rounding bit and + // we can waste a bit if the most significant bit of the product is zero. + if((firstproduct.high & 0x1FF) == 0x1FF) { + // We want to compute i * 5^q, but only care about the top 55 bits at most. + // Consider the scenario where q>=0. Then 5^q may not fit in 64-bits. Doing + // the full computation is wasteful. So we do what is called a "truncated + // multiplication". + // We take the most significant 64-bits, and we put them in + // power_of_five_128[index]. Usually, that's good enough to approximate i * 5^q + // to the desired approximation using one multiplication. Sometimes it does not suffice. + // Then we store the next most significant 64 bits in power_of_five_128[index + 1], and + // then we get a better approximation to i * 5^q. + // + // That's for when q>=0. The logic for q<0 is somewhat similar but it is somewhat + // more complicated. + // + // There is an extra layer of complexity in that we need more than 55 bits of + // accuracy in the round-to-even scenario. + // + // The full_multiplication function computes the 128-bit product of two 64-bit words + // with a returned value of type value128 with a "low component" corresponding to the + // 64-bit least significant bits of the product and with a "high component" corresponding + // to the 64-bit most significant bits of the product. +#if SIMDJSON_STATIC_REFLECTION + simdjson::internal::value128 secondproduct = full_multiplication(i, simdjson::internal::powers_template<>::power_of_five_128[index + 1]); +#else + simdjson::internal::value128 secondproduct = full_multiplication(i, simdjson::internal::power_of_five_128[index + 1]); +#endif + firstproduct.low += secondproduct.high; + if(secondproduct.high > firstproduct.low) { firstproduct.high++; } + // As it has been proven by Noble Mushtak and Daniel Lemire in "Fast Number Parsing Without + // Fallback" (https://arxiv.org/abs/2212.06644), at this point we are sure that the product + // is sufficiently accurate, and more computation is not needed. + } + uint64_t lower = firstproduct.low; + uint64_t upper = firstproduct.high; + // The final mantissa should be 53 bits with a leading 1. + // We shift it so that it occupies 54 bits with a leading 1. + /////// + uint64_t upperbit = upper >> 63; + uint64_t mantissa = upper >> (upperbit + 9); + lz += int(1 ^ upperbit); + + // Here we have mantissa < (1<<54). + int64_t real_exponent = exponent - lz; + if (simdjson_unlikely(real_exponent <= 0)) { // we have a subnormal? + // Here have that real_exponent <= 0 so -real_exponent >= 0 + if(-real_exponent + 1 >= 64) { // if we have more than 64 bits below the minimum exponent, you have a zero for sure. + d = negative ? -0.0 : 0.0; + return true; + } + // next line is safe because -real_exponent + 1 < 0 + mantissa >>= -real_exponent + 1; + // Thankfully, we can't have both "round-to-even" and subnormals because + // "round-to-even" only occurs for powers close to 0. + mantissa += (mantissa & 1); // round up + mantissa >>= 1; + // There is a weird scenario where we don't have a subnormal but just. + // Suppose we start with 2.2250738585072013e-308, we end up + // with 0x3fffffffffffff x 2^-1023-53 which is technically subnormal + // whereas 0x40000000000000 x 2^-1023-53 is normal. Now, we need to round + // up 0x3fffffffffffff x 2^-1023-53 and once we do, we are no longer + // subnormal, but we can only know this after rounding. + // So we only declare a subnormal if we are smaller than the threshold. + real_exponent = (mantissa < (uint64_t(1) << 52)) ? 0 : 1; + d = to_double(mantissa, real_exponent, negative); + return true; + } + // We have to round to even. The "to even" part + // is only a problem when we are right in between two floats + // which we guard against. + // If we have lots of trailing zeros, we may fall right between two + // floating-point values. + // + // The round-to-even cases take the form of a number 2m+1 which is in (2^53,2^54] + // times a power of two. That is, it is right between a number with binary significand + // m and another number with binary significand m+1; and it must be the case + // that it cannot be represented by a float itself. + // + // We must have that w * 10 ^q == (2m+1) * 2^p for some power of two 2^p. + // Recall that 10^q = 5^q * 2^q. + // When q >= 0, we must have that (2m+1) is divible by 5^q, so 5^q <= 2^54. We have that + // 5^23 <= 2^54 and it is the last power of five to qualify, so q <= 23. + // When q<0, we have w >= (2m+1) x 5^{-q}. We must have that w<2^{64} so + // (2m+1) x 5^{-q} < 2^{64}. We have that 2m+1>2^{53}. Hence, we must have + // 2^{53} x 5^{-q} < 2^{64}. + // Hence we have 5^{-q} < 2^{11}$ or q>= -4. + // + // We require lower <= 1 and not lower == 0 because we could not prove that + // that lower == 0 is implied; but we could prove that lower <= 1 is a necessary and sufficient test. + if (simdjson_unlikely((lower <= 1) && (power >= -4) && (power <= 23) && ((mantissa & 3) == 1))) { + if((mantissa << (upperbit + 64 - 53 - 2)) == upper) { + mantissa &= ~1; // flip it so that we do not round up + } + } + + mantissa += mantissa & 1; + mantissa >>= 1; + + // Here we have mantissa < (1<<53), unless there was an overflow + if (mantissa >= (1ULL << 53)) { + ////////// + // This will happen when parsing values such as 7.2057594037927933e+16 + //////// + mantissa = (1ULL << 52); + real_exponent++; + } + mantissa &= ~(1ULL << 52); + // we have to check that real_exponent is in range, otherwise we bail out + if (simdjson_unlikely(real_exponent > 2046)) { + // We have an infinite value!!! We could actually throw an error here if we could. + return false; + } + d = to_double(mantissa, real_exponent, negative); + return true; +} + +// We call a fallback floating-point parser that might be slow. Note +// it will accept JSON numbers, but the JSON spec. is more restrictive so +// before you call parse_float_fallback, you need to have validated the input +// string with the JSON grammar. +// It will return an error (false) if the parsed number is infinite. +// The string parsing itself always succeeds. We know that there is at least +// one digit. +static bool parse_float_fallback(const uint8_t *ptr, double *outDouble) { + *outDouble = simdjson::internal::from_chars(reinterpret_cast(ptr)); + // We do not accept infinite values. + + // Detecting finite values in a portable manner is ridiculously hard, ideally + // we would want to do: + // return !std::isfinite(*outDouble); + // but that mysteriously fails under legacy/old libc++ libraries, see + // https://github.com/simdjson/simdjson/issues/1286 + // + // Therefore, fall back to this solution (the extra parens are there + // to handle that max may be a macro on windows). + return !(*outDouble > (std::numeric_limits::max)() || *outDouble < std::numeric_limits::lowest()); +} + +static bool parse_float_fallback(const uint8_t *ptr, const uint8_t *end_ptr, double *outDouble) { + *outDouble = simdjson::internal::from_chars(reinterpret_cast(ptr), reinterpret_cast(end_ptr)); + // We do not accept infinite values. + + // Detecting finite values in a portable manner is ridiculously hard, ideally + // we would want to do: + // return !std::isfinite(*outDouble); + // but that mysteriously fails under legacy/old libc++ libraries, see + // https://github.com/simdjson/simdjson/issues/1286 + // + // Therefore, fall back to this solution (the extra parens are there + // to handle that max may be a macro on windows). + return !(*outDouble > (std::numeric_limits::max)() || *outDouble < std::numeric_limits::lowest()); +} + +// check quickly whether the next 8 chars are made of digits +// at a glance, it looks better than Mula's +// http://0x80.pl/articles/swar-digits-validate.html +simdjson_inline bool is_made_of_eight_digits_fast(const uint8_t *chars) { + uint64_t val; + // this can read up to 7 bytes beyond the buffer size, but we require + // SIMDJSON_PADDING of padding + static_assert(7 <= SIMDJSON_PADDING, "SIMDJSON_PADDING must be bigger than 7"); + std::memcpy(&val, chars, 8); + // a branchy method might be faster: + // return (( val & 0xF0F0F0F0F0F0F0F0 ) == 0x3030303030303030) + // && (( (val + 0x0606060606060606) & 0xF0F0F0F0F0F0F0F0 ) == + // 0x3030303030303030); + return (((val & 0xF0F0F0F0F0F0F0F0) | + (((val + 0x0606060606060606) & 0xF0F0F0F0F0F0F0F0) >> 4)) == + 0x3333333333333333); +} + +template +SIMDJSON_NO_SANITIZE_UNDEFINED // We deliberately allow overflow here and check later +simdjson_inline bool parse_digit(const uint8_t c, I &i) { + const uint8_t digit = static_cast(c - '0'); + if (digit > 9) { + return false; + } + // PERF NOTE: multiplication by 10 is cheaper than arbitrary integer multiplication + i = 10 * i + digit; // might overflow, we will handle the overflow later + return true; +} + +simdjson_inline bool is_digit(const uint8_t c) { + return static_cast(c - '0') <= 9; +} + +simdjson_warn_unused simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const uint8_t *const src, const uint8_t *&p, uint64_t &i, int64_t &exponent) { + // we continue with the fiction that we have an integer. If the + // floating point number is representable as x * 10^z for some integer + // z that fits in 53 bits, then we will be able to convert back the + // the integer into a float in a lossless manner. + const uint8_t *const first_after_period = p; + +#ifdef SIMDJSON_SWAR_NUMBER_PARSING +#if SIMDJSON_SWAR_NUMBER_PARSING + // this helps if we have lots of decimals! + // this turns out to be frequent enough. + if (is_made_of_eight_digits_fast(p)) { + i = i * 100000000 + parse_eight_digits_unrolled(p); + p += 8; + } +#endif // SIMDJSON_SWAR_NUMBER_PARSING +#endif // #ifdef SIMDJSON_SWAR_NUMBER_PARSING + // Unrolling the first digit makes a small difference on some implementations (e.g. westmere) + if (parse_digit(*p, i)) { ++p; } + while (parse_digit(*p, i)) { p++; } + exponent = first_after_period - p; + // Decimal without digits (123.) is illegal + if (exponent == 0) { + return INVALID_NUMBER(src); + } + return SUCCESS; +} + +simdjson_warn_unused simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const src, const uint8_t *&p, int64_t &exponent) { + // Exp Sign: -123.456e[-]78 + bool neg_exp = ('-' == *p); + if (neg_exp || '+' == *p) { p++; } // Skip + as well + + // Exponent: -123.456e-[78] + auto start_exp = p; + int64_t exp_number = 0; + while (parse_digit(*p, exp_number)) { ++p; } + // It is possible for parse_digit to overflow. + // In particular, it could overflow to INT64_MIN, and we cannot do - INT64_MIN. + // Thus we *must* check for possible overflow before we negate exp_number. + + // Performance notes: it may seem like combining the two "simdjson_unlikely checks" below into + // a single simdjson_unlikely path would be faster. The reasoning is sound, but the compiler may + // not oblige and may, in fact, generate two distinct paths in any case. It might be + // possible to do uint64_t(p - start_exp - 1) >= 18 but it could end up trading off + // instructions for a simdjson_likely branch, an unconclusive gain. + + // If there were no digits, it's an error. + if (simdjson_unlikely(p == start_exp)) { + return INVALID_NUMBER(src); + } + // We have a valid positive exponent in exp_number at this point, except that + // it may have overflowed. + + // If there were more than 18 digits, we may have overflowed the integer. We have to do + // something!!!! + if (simdjson_unlikely(p > start_exp+18)) { + // Skip leading zeroes: 1e000000000000000000001 is technically valid and does not overflow + while (*start_exp == '0') { start_exp++; } + // 19 digits could overflow int64_t and is kind of absurd anyway. We don't + // support exponents smaller than -999,999,999,999,999,999 and bigger + // than 999,999,999,999,999,999. + // We can truncate. + // Note that 999999999999999999 is assuredly too large. The maximal ieee64 value before + // infinity is ~1.8e308. The smallest subnormal is ~5e-324. So, actually, we could + // truncate at 324. + // Note that there is no reason to fail per se at this point in time. + // E.g., 0e999999999999999999999 is a fine number. + if (p > start_exp+18) { exp_number = 999999999999999999; } + } + // At this point, we know that exp_number is a sane, positive, signed integer. + // It is <= 999,999,999,999,999,999. As long as 'exponent' is in + // [-8223372036854775808, 8223372036854775808], we won't overflow. Because 'exponent' + // is bounded in magnitude by the size of the JSON input, we are fine in this universe. + // To sum it up: the next line should never overflow. + exponent += (neg_exp ? -exp_number : exp_number); + return SUCCESS; +} + +simdjson_inline bool check_if_integer(const uint8_t *const src, size_t max_length) { + const uint8_t *const srcend = src + max_length; + bool negative = (*src == '-'); // we can always read at least one character after the '-' + const uint8_t *p = src + uint8_t(negative); + if(p == srcend) { return false; } + if(*p == '0') { + ++p; + if(p == srcend) { return true; } + if(jsoncharutils::is_not_structural_or_whitespace(*p)) { return false; } + return true; + } + while(p != srcend && is_digit(*p)) { ++p; } + if(p == srcend) { return true; } + if(jsoncharutils::is_not_structural_or_whitespace(*p)) { return false; } + return true; +} + +simdjson_inline size_t significant_digits(const uint8_t * start_digits, size_t digit_count) { + // It is possible that the integer had an overflow. + // We have to handle the case where we have 0.0000somenumber. + const uint8_t *start = start_digits; + while ((*start == '0') || (*start == '.')) { ++start; } + // we over-decrement by one when there is a '.' + return digit_count - size_t(start - start_digits); +} + +} // unnamed namespace + +/** @private */ +static error_code slow_float_parsing(simdjson_unused const uint8_t * src, double* answer) { + if (parse_float_fallback(src, answer)) { + return SUCCESS; + } + return INVALID_NUMBER(src); +} + +/** @private */ +template +simdjson_warn_unused simdjson_inline error_code write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer) { + // If we frequently had to deal with long strings of digits, + // we could extend our code by using a 128-bit integer instead + // of a 64-bit integer. However, this is uncommon in practice. + // + // 9999999999999999999 < 2**64 so we can accommodate 19 digits. + // If we have a decimal separator, then digit_count - 1 is the number of digits, but we + // may not have a decimal separator! + if (simdjson_unlikely(digit_count > 19 && significant_digits(start_digits, digit_count) > 19)) { + // Ok, chances are good that we had an overflow! + // this is almost never going to get called!!! + // we start anew, going slowly!!! + // This will happen in the following examples: + // 10000000000000000000000000000000000000000000e+308 + // 3.1415926535897932384626433832795028841971693993751 + // + // NOTE: We do not pass a reference to the to slow_float_parsing. If we passed our writer + // reference to it, it would force it to be stored in memory, preventing the compiler from + // picking it apart and putting into registers. i.e. if we pass it as reference, + // it gets slow. + double d; + error_code error = slow_float_parsing(src, &d); + writer.append_double(d); + return error; + } + // NOTE: it's weird that the simdjson_unlikely() only wraps half the if, but it seems to get slower any other + // way we've tried: https://github.com/simdjson/simdjson/pull/990#discussion_r448497331 + // To future reader: we'd love if someone found a better way, or at least could explain this result! + if (simdjson_unlikely(exponent < simdjson::internal::smallest_power) || (exponent > simdjson::internal::largest_power)) { + // + // Important: smallest_power is such that it leads to a zero value. + // Observe that 18446744073709551615e-343 == 0, i.e. (2**64 - 1) e -343 is zero + // so something x 10^-343 goes to zero, but not so with something x 10^-342. + static_assert(simdjson::internal::smallest_power <= -342, "smallest_power is not small enough"); + // + if((exponent < simdjson::internal::smallest_power) || (i == 0)) { + // E.g. Parse "-0.0e-999" into the same value as "-0.0". See https://en.wikipedia.org/wiki/Signed_zero + WRITE_DOUBLE(negative ? -0.0 : 0.0, src, writer); + return SUCCESS; + } else { // (exponent > largest_power) and (i != 0) + // We have, for sure, an infinite value and simdjson refuses to parse infinite values. + return INVALID_NUMBER(src); + } + } + double d; + if (!compute_float_64(exponent, i, negative, d)) { + // we are almost never going to get here. + if (!parse_float_fallback(src, &d)) { return INVALID_NUMBER(src); } + } + WRITE_DOUBLE(d, src, writer); + return SUCCESS; +} + +// parse the number at src +// define JSON_TEST_NUMBERS for unit testing +// +// It is assumed that the number is followed by a structural ({,},],[) character +// or a white space character. If that is not the case (e.g., when the JSON +// document is made of a single number), then it is necessary to copy the +// content and append a space before calling this function. +// +// Our objective is accurate parsing (ULP of 0) at high speed. +template +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer); + +// for performance analysis, it is sometimes useful to skip parsing +#ifdef SIMDJSON_SKIPNUMBERPARSING + +template +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const, W &writer) { + writer.append_s64(0); // always write zero + return SUCCESS; // always succeeds +} + +simdjson_unused simdjson_inline simdjson_result parse_unsigned(const uint8_t * const src) noexcept { return 0; } +simdjson_unused simdjson_inline simdjson_result parse_integer(const uint8_t * const src) noexcept { return 0; } +simdjson_unused simdjson_inline simdjson_result parse_double(const uint8_t * const src) noexcept { return 0; } +simdjson_unused simdjson_inline simdjson_result parse_unsigned_in_string(const uint8_t * const src) noexcept { return 0; } +simdjson_unused simdjson_inline simdjson_result parse_integer_in_string(const uint8_t * const src) noexcept { return 0; } +simdjson_unused simdjson_inline simdjson_result parse_double_in_string(const uint8_t * const src) noexcept { return 0; } +simdjson_unused simdjson_inline bool is_negative(const uint8_t * src) noexcept { return false; } +simdjson_unused simdjson_inline simdjson_result is_integer(const uint8_t * src) noexcept { return false; } +simdjson_unused simdjson_inline simdjson_result get_number_type(const uint8_t * src) noexcept { return number_type::signed_integer; } +#else + +// parse the number at src +// define JSON_TEST_NUMBERS for unit testing +// +// It is assumed that the number is followed by a structural ({,},],[) character +// or a white space character. If that is not the case (e.g., when the JSON +// document is made of a single number), then it is necessary to copy the +// content and append a space before calling this function. +// +// Our objective is accurate parsing (ULP of 0) at high speed. +template +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { + // + // Check for minus sign + // + bool negative = (*src == '-'); + const uint8_t *p = src + uint8_t(negative); + + // + // Parse the integer part. + // + // PERF NOTE: we don't use is_made_of_eight_digits_fast because large integers like 123456789 are rare + const uint8_t *const start_digits = p; + uint64_t i = 0; + while (parse_digit(*p, i)) { p++; } + + // If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error. + // Optimization note: size_t is expected to be unsigned. + size_t digit_count = size_t(p - start_digits); + if (digit_count == 0 || ('0' == *start_digits && digit_count > 1)) { return INVALID_NUMBER(src); } + + // + // Handle floats if there is a . or e (or both) + // + int64_t exponent = 0; + bool is_float = false; + if ('.' == *p) { + is_float = true; + ++p; + SIMDJSON_TRY( parse_decimal_after_separator(src, p, i, exponent) ); + digit_count = int(p - start_digits); // used later to guard against overflows + } + if (('e' == *p) || ('E' == *p)) { + is_float = true; + ++p; + SIMDJSON_TRY( parse_exponent(src, p, exponent) ); + } + if (is_float) { + const bool dirty_end = jsoncharutils::is_not_structural_or_whitespace(*p); + SIMDJSON_TRY( write_float(src, negative, i, start_digits, digit_count, exponent, writer) ); + if (dirty_end) { return INVALID_NUMBER(src); } + return SUCCESS; + } + + // The longest negative 64-bit number is 19 digits. + // The longest positive 64-bit number is 20 digits. + // We do it this way so we don't trigger this branch unless we must. + size_t longest_digit_count = negative ? 19 : 20; + if (digit_count > longest_digit_count) { return BIGINT_NUMBER(src); } + if (digit_count == longest_digit_count) { + if (negative) { + // Anything negative above INT64_MAX+1 is invalid + if (i > uint64_t(INT64_MAX)+1) { return BIGINT_NUMBER(src); } + WRITE_INTEGER(~i+1, src, writer); + if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); } + return SUCCESS; + // Positive overflow check: + // - A 20 digit number starting with 2-9 is overflow, because 18,446,744,073,709,551,615 is the + // biggest uint64_t. + // - A 20 digit number starting with 1 is overflow if it is less than INT64_MAX. + // If we got here, it's a 20 digit number starting with the digit "1". + // - If a 20 digit number starting with 1 overflowed (i*10+digit), the result will be smaller + // than 1,553,255,926,290,448,384. + // - That is smaller than the smallest possible 20-digit number the user could write: + // 10,000,000,000,000,000,000. + // - Therefore, if the number is positive and lower than that, it's overflow. + // - The value we are looking at is less than or equal to INT64_MAX. + // + } else if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INVALID_NUMBER(src); } + } + + // Write unsigned if it does not fit in a signed integer. + if (i > uint64_t(INT64_MAX)) { + WRITE_UNSIGNED(i, src, writer); + } else { +#if SIMDJSON_MINUS_ZERO_AS_FLOAT + if(i == 0 && negative) { + // We have to write -0.0 instead of 0 + WRITE_DOUBLE(-0.0, src, writer); + } else { + WRITE_INTEGER(negative ? (~i+1) : i, src, writer); + } +#else + WRITE_INTEGER(negative ? (~i+1) : i, src, writer); +#endif + } + if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); } + return SUCCESS; +} + +// Inlineable functions +namespace { + +// This table can be used to characterize the final character of an integer +// string. For JSON structural character and allowable white space characters, +// we return SUCCESS. For 'e', '.' and 'E', we return INCORRECT_TYPE. Otherwise +// we return NUMBER_ERROR. +// Optimization note: we could easily reduce the size of the table by half (to 128) +// at the cost of an extra branch. +// Optimization note: we want the values to use at most 8 bits (not, e.g., 32 bits): +static_assert(error_code(uint8_t(NUMBER_ERROR))== NUMBER_ERROR, "bad NUMBER_ERROR cast"); +static_assert(error_code(uint8_t(SUCCESS))== SUCCESS, "bad NUMBER_ERROR cast"); +static_assert(error_code(uint8_t(INCORRECT_TYPE))== INCORRECT_TYPE, "bad NUMBER_ERROR cast"); + +const uint8_t integer_string_finisher[256] = { + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, SUCCESS, + SUCCESS, NUMBER_ERROR, NUMBER_ERROR, SUCCESS, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, SUCCESS, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, SUCCESS, + NUMBER_ERROR, INCORRECT_TYPE, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, SUCCESS, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, INCORRECT_TYPE, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, SUCCESS, NUMBER_ERROR, SUCCESS, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, INCORRECT_TYPE, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, SUCCESS, NUMBER_ERROR, + SUCCESS, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, + NUMBER_ERROR}; + +// Parse any number from 0 to 18,446,744,073,709,551,615 +simdjson_unused simdjson_inline simdjson_result parse_unsigned(const uint8_t * const src) noexcept { + const uint8_t *p = src; + // + // Parse the integer part. + // + // PERF NOTE: we don't use is_made_of_eight_digits_fast because large integers like 123456789 are rare + const uint8_t *const start_digits = p; + uint64_t i = 0; + while (parse_digit(*p, i)) { p++; } + + // If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error. + // Optimization note: size_t is expected to be unsigned. + size_t digit_count = size_t(p - start_digits); + // The longest positive 64-bit number is 20 digits. + // We do it this way so we don't trigger this branch unless we must. + // Optimization note: the compiler can probably merge + // ((digit_count == 0) || (digit_count > 20)) + // into a single branch since digit_count is unsigned. + if ((digit_count == 0) || (digit_count > 20)) { return INCORRECT_TYPE; } + // Here digit_count > 0. + if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; } + // We can do the following... + // if (!jsoncharutils::is_structural_or_whitespace(*p)) { + // return (*p == '.' || *p == 'e' || *p == 'E') ? INCORRECT_TYPE : NUMBER_ERROR; + // } + // as a single table lookup: + if (integer_string_finisher[*p] != SUCCESS) { return error_code(integer_string_finisher[*p]); } + + if (digit_count == 20) { + // Positive overflow check: + // - A 20 digit number starting with 2-9 is overflow, because 18,446,744,073,709,551,615 is the + // biggest uint64_t. + // - A 20 digit number starting with 1 is overflow if it is less than INT64_MAX. + // If we got here, it's a 20 digit number starting with the digit "1". + // - If a 20 digit number starting with 1 overflowed (i*10+digit), the result will be smaller + // than 1,553,255,926,290,448,384. + // - That is smaller than the smallest possible 20-digit number the user could write: + // 10,000,000,000,000,000,000. + // - Therefore, if the number is positive and lower than that, it's overflow. + // - The value we are looking at is less than or equal to INT64_MAX. + // + if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; } + } + + return i; +} + + +// Parse any number from 0 to 18,446,744,073,709,551,615 +// Never read at src_end or beyond +simdjson_unused simdjson_inline simdjson_result parse_unsigned(const uint8_t * const src, const uint8_t * const src_end) noexcept { + const uint8_t *p = src; + // + // Parse the integer part. + // + // PERF NOTE: we don't use is_made_of_eight_digits_fast because large integers like 123456789 are rare + const uint8_t *const start_digits = p; + uint64_t i = 0; + while ((p != src_end) && parse_digit(*p, i)) { p++; } + + // If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error. + // Optimization note: size_t is expected to be unsigned. + size_t digit_count = size_t(p - start_digits); + // The longest positive 64-bit number is 20 digits. + // We do it this way so we don't trigger this branch unless we must. + // Optimization note: the compiler can probably merge + // ((digit_count == 0) || (digit_count > 20)) + // into a single branch since digit_count is unsigned. + if ((digit_count == 0) || (digit_count > 20)) { return INCORRECT_TYPE; } + // Here digit_count > 0. + if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; } + // We can do the following... + // if (!jsoncharutils::is_structural_or_whitespace(*p)) { + // return (*p == '.' || *p == 'e' || *p == 'E') ? INCORRECT_TYPE : NUMBER_ERROR; + // } + // as a single table lookup: + if ((p != src_end) && integer_string_finisher[*p] != SUCCESS) { return error_code(integer_string_finisher[*p]); } + + if (digit_count == 20) { + // Positive overflow check: + // - A 20 digit number starting with 2-9 is overflow, because 18,446,744,073,709,551,615 is the + // biggest uint64_t. + // - A 20 digit number starting with 1 is overflow if it is less than INT64_MAX. + // If we got here, it's a 20 digit number starting with the digit "1". + // - If a 20 digit number starting with 1 overflowed (i*10+digit), the result will be smaller + // than 1,553,255,926,290,448,384. + // - That is smaller than the smallest possible 20-digit number the user could write: + // 10,000,000,000,000,000,000. + // - Therefore, if the number is positive and lower than that, it's overflow. + // - The value we are looking at is less than or equal to INT64_MAX. + // + if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; } + } + + return i; +} + +// Parse any number from 0 to 18,446,744,073,709,551,615 +simdjson_unused simdjson_inline simdjson_result parse_unsigned_in_string(const uint8_t * const src) noexcept { + const uint8_t *p = src + 1; + // + // Parse the integer part. + // + // PERF NOTE: we don't use is_made_of_eight_digits_fast because large integers like 123456789 are rare + const uint8_t *const start_digits = p; + uint64_t i = 0; + while (parse_digit(*p, i)) { p++; } + + // If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error. + // Optimization note: size_t is expected to be unsigned. + size_t digit_count = size_t(p - start_digits); + // The longest positive 64-bit number is 20 digits. + // We do it this way so we don't trigger this branch unless we must. + // Optimization note: the compiler can probably merge + // ((digit_count == 0) || (digit_count > 20)) + // into a single branch since digit_count is unsigned. + if ((digit_count == 0) || (digit_count > 20)) { return INCORRECT_TYPE; } + // Here digit_count > 0. + if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; } + // We can do the following... + // if (!jsoncharutils::is_structural_or_whitespace(*p)) { + // return (*p == '.' || *p == 'e' || *p == 'E') ? INCORRECT_TYPE : NUMBER_ERROR; + // } + // as a single table lookup: + if (*p != '"') { return NUMBER_ERROR; } + + if (digit_count == 20) { + // Positive overflow check: + // - A 20 digit number starting with 2-9 is overflow, because 18,446,744,073,709,551,615 is the + // biggest uint64_t. + // - A 20 digit number starting with 1 is overflow if it is less than INT64_MAX. + // If we got here, it's a 20 digit number starting with the digit "1". + // - If a 20 digit number starting with 1 overflowed (i*10+digit), the result will be smaller + // than 1,553,255,926,290,448,384. + // - That is smaller than the smallest possible 20-digit number the user could write: + // 10,000,000,000,000,000,000. + // - Therefore, if the number is positive and lower than that, it's overflow. + // - The value we are looking at is less than or equal to INT64_MAX. + // + // Note: we use src[1] and not src[0] because src[0] is the quote character in this + // instance. + if (src[1] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; } + } + + return i; +} + +// Parse any number from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 +simdjson_unused simdjson_inline simdjson_result parse_integer(const uint8_t *src) noexcept { + // + // Check for minus sign + // + bool negative = (*src == '-'); + const uint8_t *p = src + uint8_t(negative); + + // + // Parse the integer part. + // + // PERF NOTE: we don't use is_made_of_eight_digits_fast because large integers like 123456789 are rare + const uint8_t *const start_digits = p; + uint64_t i = 0; + while (parse_digit(*p, i)) { p++; } + + // If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error. + // Optimization note: size_t is expected to be unsigned. + size_t digit_count = size_t(p - start_digits); + // We go from + // -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 + // so we can never represent numbers that have more than 19 digits. + size_t longest_digit_count = 19; + // Optimization note: the compiler can probably merge + // ((digit_count == 0) || (digit_count > longest_digit_count)) + // into a single branch since digit_count is unsigned. + if ((digit_count == 0) || (digit_count > longest_digit_count)) { return INCORRECT_TYPE; } + // Here digit_count > 0. + if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; } + // We can do the following... + // if (!jsoncharutils::is_structural_or_whitespace(*p)) { + // return (*p == '.' || *p == 'e' || *p == 'E') ? INCORRECT_TYPE : NUMBER_ERROR; + // } + // as a single table lookup: + if(integer_string_finisher[*p] != SUCCESS) { return error_code(integer_string_finisher[*p]); } + // Negative numbers have can go down to - INT64_MAX - 1 whereas positive numbers are limited to INT64_MAX. + // Performance note: This check is only needed when digit_count == longest_digit_count but it is + // so cheap that we might as well always make it. + if(i > uint64_t(INT64_MAX) + uint64_t(negative)) { return INCORRECT_TYPE; } + return negative ? (~i+1) : i; +} + +// Parse any number from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 +// Never read at src_end or beyond +simdjson_unused simdjson_inline simdjson_result parse_integer(const uint8_t * const src, const uint8_t * const src_end) noexcept { + // + // Check for minus sign + // + if(src == src_end) { return NUMBER_ERROR; } + bool negative = (*src == '-'); + const uint8_t *p = src + uint8_t(negative); + + // + // Parse the integer part. + // + // PERF NOTE: we don't use is_made_of_eight_digits_fast because large integers like 123456789 are rare + const uint8_t *const start_digits = p; + uint64_t i = 0; + while ((p != src_end) && parse_digit(*p, i)) { p++; } + + // If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error. + // Optimization note: size_t is expected to be unsigned. + size_t digit_count = size_t(p - start_digits); + // We go from + // -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 + // so we can never represent numbers that have more than 19 digits. + size_t longest_digit_count = 19; + // Optimization note: the compiler can probably merge + // ((digit_count == 0) || (digit_count > longest_digit_count)) + // into a single branch since digit_count is unsigned. + if ((digit_count == 0) || (digit_count > longest_digit_count)) { return INCORRECT_TYPE; } + // Here digit_count > 0. + if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; } + // We can do the following... + // if (!jsoncharutils::is_structural_or_whitespace(*p)) { + // return (*p == '.' || *p == 'e' || *p == 'E') ? INCORRECT_TYPE : NUMBER_ERROR; + // } + // as a single table lookup: + if((p != src_end) && integer_string_finisher[*p] != SUCCESS) { return error_code(integer_string_finisher[*p]); } + // Negative numbers have can go down to - INT64_MAX - 1 whereas positive numbers are limited to INT64_MAX. + // Performance note: This check is only needed when digit_count == longest_digit_count but it is + // so cheap that we might as well always make it. + if(i > uint64_t(INT64_MAX) + uint64_t(negative)) { return INCORRECT_TYPE; } + return negative ? (~i+1) : i; +} + +// Parse any number from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 +simdjson_unused simdjson_inline simdjson_result parse_integer_in_string(const uint8_t *src) noexcept { + // + // Check for minus sign + // + bool negative = (*(src + 1) == '-'); + src += uint8_t(negative) + 1; + + // + // Parse the integer part. + // + // PERF NOTE: we don't use is_made_of_eight_digits_fast because large integers like 123456789 are rare + const uint8_t *const start_digits = src; + uint64_t i = 0; + while (parse_digit(*src, i)) { src++; } + + // If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error. + // Optimization note: size_t is expected to be unsigned. + size_t digit_count = size_t(src - start_digits); + // We go from + // -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 + // so we can never represent numbers that have more than 19 digits. + size_t longest_digit_count = 19; + // Optimization note: the compiler can probably merge + // ((digit_count == 0) || (digit_count > longest_digit_count)) + // into a single branch since digit_count is unsigned. + if ((digit_count == 0) || (digit_count > longest_digit_count)) { return INCORRECT_TYPE; } + // Here digit_count > 0. + if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; } + // We can do the following... + // if (!jsoncharutils::is_structural_or_whitespace(*src)) { + // return (*src == '.' || *src == 'e' || *src == 'E') ? INCORRECT_TYPE : NUMBER_ERROR; + // } + // as a single table lookup: + if(*src != '"') { return NUMBER_ERROR; } + // Negative numbers have can go down to - INT64_MAX - 1 whereas positive numbers are limited to INT64_MAX. + // Performance note: This check is only needed when digit_count == longest_digit_count but it is + // so cheap that we might as well always make it. + if(i > uint64_t(INT64_MAX) + uint64_t(negative)) { return INCORRECT_TYPE; } + return negative ? (~i+1) : i; +} + +simdjson_unused simdjson_inline simdjson_result parse_double(const uint8_t * src) noexcept { + // + // Check for minus sign + // + bool negative = (*src == '-'); + src += uint8_t(negative); + + // + // Parse the integer part. + // + uint64_t i = 0; + const uint8_t *p = src; + p += parse_digit(*p, i); + bool leading_zero = (i == 0); + while (parse_digit(*p, i)) { p++; } + // no integer digits, or 0123 (zero must be solo) + if ( p == src ) { return INCORRECT_TYPE; } + if ( (leading_zero && p != src+1)) { return NUMBER_ERROR; } + + // + // Parse the decimal part. + // + int64_t exponent = 0; + bool overflow; + if (simdjson_likely(*p == '.')) { + p++; + const uint8_t *start_decimal_digits = p; + if (!parse_digit(*p, i)) { return NUMBER_ERROR; } // no decimal digits + p++; + while (parse_digit(*p, i)) { p++; } + exponent = -(p - start_decimal_digits); + + // Overflow check. More than 19 digits (minus the decimal) may be overflow. + overflow = p-src-1 > 19; + if (simdjson_unlikely(overflow && leading_zero)) { + // Skip leading 0.00000 and see if it still overflows + const uint8_t *start_digits = src + 2; + while (*start_digits == '0') { start_digits++; } + overflow = p-start_digits > 19; + } + } else { + overflow = p-src > 19; + } + + // + // Parse the exponent + // + if (*p == 'e' || *p == 'E') { + p++; + bool exp_neg = *p == '-'; + p += exp_neg || *p == '+'; + + uint64_t exp = 0; + const uint8_t *start_exp_digits = p; + while (parse_digit(*p, exp)) { p++; } + // no exp digits, or 20+ exp digits + if (p-start_exp_digits == 0 || p-start_exp_digits > 19) { return NUMBER_ERROR; } + + exponent += exp_neg ? 0-exp : exp; + } + + if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return NUMBER_ERROR; } + + overflow = overflow || exponent < simdjson::internal::smallest_power || exponent > simdjson::internal::largest_power; + + // + // Assemble (or slow-parse) the float + // + double d; + if (simdjson_likely(!overflow)) { + if (compute_float_64(exponent, i, negative, d)) { return d; } + } + if (!parse_float_fallback(src - uint8_t(negative), &d)) { + return NUMBER_ERROR; + } + return d; +} + +simdjson_unused simdjson_inline bool is_negative(const uint8_t * src) noexcept { + return (*src == '-'); +} + +simdjson_unused simdjson_inline simdjson_result is_integer(const uint8_t * src) noexcept { + bool negative = (*src == '-'); + src += uint8_t(negative); + const uint8_t *p = src; + while(static_cast(*p - '0') <= 9) { p++; } + if ( p == src ) { return NUMBER_ERROR; } + if (jsoncharutils::is_structural_or_whitespace(*p)) { return true; } + return false; +} + +simdjson_unused simdjson_inline simdjson_result get_number_type(const uint8_t * src) noexcept { + bool negative = (*src == '-'); + src += uint8_t(negative); + const uint8_t *p = src; + while(static_cast(*p - '0') <= 9) { p++; } + size_t digit_count = size_t(p - src); + if ( p == src ) { return NUMBER_ERROR; } + if (jsoncharutils::is_structural_or_whitespace(*p)) { + static const uint8_t * smaller_big_integer = reinterpret_cast("9223372036854775808"); + // We have an integer. + if(simdjson_unlikely(digit_count > 20)) { + return number_type::big_integer; + } + // If the number is negative and valid, it must be a signed integer. + if(negative) { + if (simdjson_unlikely(digit_count > 19)) return number_type::big_integer; + if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) { + return number_type::big_integer; + } +#if SIMDJSON_MINUS_ZERO_AS_FLOAT + if(digit_count == 1 && src[0] == '0') { + // We have to write -0.0 instead of 0 + return number_type::floating_point_number; + } +#endif + return number_type::signed_integer; + } + // Let us check if we have a big integer (>=2**64). + static const uint8_t * two_to_sixtyfour = reinterpret_cast("18446744073709551616"); + if((digit_count > 20) || (digit_count == 20 && memcmp(src, two_to_sixtyfour, 20) >= 0)) { + return number_type::big_integer; + } + // The number is positive and smaller than 18446744073709551616 (or 2**64). + // We want values larger or equal to 9223372036854775808 to be unsigned + // integers, and the other values to be signed integers. + if((digit_count == 20) || (digit_count >= 19 && memcmp(src, smaller_big_integer, 19) >= 0)) { + return number_type::unsigned_integer; + } + return number_type::signed_integer; + } + // Hopefully, we have 'e' or 'E' or '.'. + return number_type::floating_point_number; +} + +// Never read at src_end or beyond +simdjson_unused simdjson_inline simdjson_result parse_double(const uint8_t * src, const uint8_t * const src_end) noexcept { + if(src == src_end) { return NUMBER_ERROR; } + // + // Check for minus sign + // + bool negative = (*src == '-'); + src += uint8_t(negative); + + // + // Parse the integer part. + // + uint64_t i = 0; + const uint8_t *p = src; + if(p == src_end) { return NUMBER_ERROR; } + p += parse_digit(*p, i); + bool leading_zero = (i == 0); + while ((p != src_end) && parse_digit(*p, i)) { p++; } + // no integer digits, or 0123 (zero must be solo) + if ( p == src ) { return INCORRECT_TYPE; } + if ( (leading_zero && p != src+1)) { return NUMBER_ERROR; } + + // + // Parse the decimal part. + // + int64_t exponent = 0; + bool overflow; + if (simdjson_likely((p != src_end) && (*p == '.'))) { + p++; + const uint8_t *start_decimal_digits = p; + if ((p == src_end) || !parse_digit(*p, i)) { return NUMBER_ERROR; } // no decimal digits + p++; + while ((p != src_end) && parse_digit(*p, i)) { p++; } + exponent = -(p - start_decimal_digits); + + // Overflow check. More than 19 digits (minus the decimal) may be overflow. + overflow = p-src-1 > 19; + if (simdjson_unlikely(overflow && leading_zero)) { + // Skip leading 0.00000 and see if it still overflows + const uint8_t *start_digits = src + 2; + while (*start_digits == '0') { start_digits++; } + overflow = start_digits-src > 19; + } + } else { + overflow = p-src > 19; + } + + // + // Parse the exponent + // + if ((p != src_end) && (*p == 'e' || *p == 'E')) { + p++; + if(p == src_end) { return NUMBER_ERROR; } + bool exp_neg = *p == '-'; + p += exp_neg || *p == '+'; + + uint64_t exp = 0; + const uint8_t *start_exp_digits = p; + while ((p != src_end) && parse_digit(*p, exp)) { p++; } + // no exp digits, or 20+ exp digits + if (p-start_exp_digits == 0 || p-start_exp_digits > 19) { return NUMBER_ERROR; } + + exponent += exp_neg ? 0-exp : exp; + } + + if ((p != src_end) && jsoncharutils::is_not_structural_or_whitespace(*p)) { return NUMBER_ERROR; } + + overflow = overflow || exponent < simdjson::internal::smallest_power || exponent > simdjson::internal::largest_power; + + // + // Assemble (or slow-parse) the float + // + double d; + if (simdjson_likely(!overflow)) { + if (compute_float_64(exponent, i, negative, d)) { return d; } + } + if (!parse_float_fallback(src - uint8_t(negative), src_end, &d)) { + return NUMBER_ERROR; + } + return d; +} + +simdjson_unused simdjson_inline simdjson_result parse_double_in_string(const uint8_t * src) noexcept { + // + // Check for minus sign + // + bool negative = (*(src + 1) == '-'); + src += uint8_t(negative) + 1; + + // + // Parse the integer part. + // + uint64_t i = 0; + const uint8_t *p = src; + p += parse_digit(*p, i); + bool leading_zero = (i == 0); + while (parse_digit(*p, i)) { p++; } + // no integer digits, or 0123 (zero must be solo) + if ( p == src ) { return INCORRECT_TYPE; } + if ( (leading_zero && p != src+1)) { return NUMBER_ERROR; } + + // + // Parse the decimal part. + // + int64_t exponent = 0; + bool overflow; + if (simdjson_likely(*p == '.')) { + p++; + const uint8_t *start_decimal_digits = p; + if (!parse_digit(*p, i)) { return NUMBER_ERROR; } // no decimal digits + p++; + while (parse_digit(*p, i)) { p++; } + exponent = -(p - start_decimal_digits); + + // Overflow check. More than 19 digits (minus the decimal) may be overflow. + overflow = p-src-1 > 19; + if (simdjson_unlikely(overflow && leading_zero)) { + // Skip leading 0.00000 and see if it still overflows + const uint8_t *start_digits = src + 2; + while (*start_digits == '0') { start_digits++; } + overflow = p-start_digits > 19; + } + } else { + overflow = p-src > 19; + } + + // + // Parse the exponent + // + if (*p == 'e' || *p == 'E') { + p++; + bool exp_neg = *p == '-'; + p += exp_neg || *p == '+'; + + uint64_t exp = 0; + const uint8_t *start_exp_digits = p; + while (parse_digit(*p, exp)) { p++; } + // no exp digits, or 20+ exp digits + if (p-start_exp_digits == 0 || p-start_exp_digits > 19) { return NUMBER_ERROR; } + + exponent += exp_neg ? 0-exp : exp; + } + + if (*p != '"') { return NUMBER_ERROR; } + + overflow = overflow || exponent < simdjson::internal::smallest_power || exponent > simdjson::internal::largest_power; + + // + // Assemble (or slow-parse) the float + // + double d; + if (simdjson_likely(!overflow)) { + if (compute_float_64(exponent, i, negative, d)) { return d; } + } + if (!parse_float_fallback(src - uint8_t(negative), &d)) { + return NUMBER_ERROR; + } + return d; +} + +} // unnamed namespace +#endif // SIMDJSON_SKIPNUMBERPARSING + +} // namespace numberparsing + +inline std::ostream& operator<<(std::ostream& out, number_type type) noexcept { + switch (type) { + case number_type::signed_integer: out << "integer in [-9223372036854775808,9223372036854775808)"; break; + case number_type::unsigned_integer: out << "unsigned integer in [9223372036854775808,18446744073709551616)"; break; + case number_type::floating_point_number: out << "floating-point number (binary64)"; break; + case number_type::big_integer: out << "big integer"; break; + default: SIMDJSON_UNREACHABLE(); + } + return out; +} + +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_NUMBERPARSING_H +/* end file simdjson/generic/numberparsing.h for rvv_vls */ + +/* including simdjson/generic/implementation_simdjson_result_base-inl.h for rvv_vls: #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */ +/* begin file simdjson/generic/implementation_simdjson_result_base-inl.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_IMPLEMENTATION_SIMDJSON_RESULT_BASE_INL_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_IMPLEMENTATION_SIMDJSON_RESULT_BASE_INL_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { + +// +// internal::implementation_simdjson_result_base inline implementation +// + +template +simdjson_inline void implementation_simdjson_result_base::tie(T &value, error_code &error) && noexcept { + error = this->second; + if (!error) { + value = std::forward>(*this).first; + } +} + +template +simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_base::get(T &value) && noexcept { + error_code error; + std::forward>(*this).tie(value, error); + return error; +} + +template +simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_base::error() const noexcept { + return this->second; +} + + +template +simdjson_warn_unused simdjson_inline bool implementation_simdjson_result_base::has_value() const noexcept { + return this->error() == SUCCESS; +} + +#if SIMDJSON_EXCEPTIONS + +template +simdjson_inline T& implementation_simdjson_result_base::operator*() & noexcept(false) { + return this->value(); +} + +template +simdjson_inline T&& implementation_simdjson_result_base::operator*() && noexcept(false) { + return std::forward>(*this).value(); +} + +template +simdjson_inline T* implementation_simdjson_result_base::operator->() noexcept(false) { + if (this->error()) { throw simdjson_error(this->error()); } + return &this->first; +} + + +template +simdjson_inline const T* implementation_simdjson_result_base::operator->() const noexcept(false) { + if (this->error()) { throw simdjson_error(this->error()); } + return &this->first; +} + +template +simdjson_inline T& implementation_simdjson_result_base::value() & noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return this->first; +} + +template +simdjson_inline T&& implementation_simdjson_result_base::value() && noexcept(false) { + return std::forward>(*this).take_value(); +} + +template +simdjson_inline T&& implementation_simdjson_result_base::take_value() && noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return std::forward(this->first); +} + +template +simdjson_inline implementation_simdjson_result_base::operator T&&() && noexcept(false) { + return std::forward>(*this).take_value(); +} + +#endif // SIMDJSON_EXCEPTIONS + +template +simdjson_inline const T& implementation_simdjson_result_base::value_unsafe() const& noexcept { + return this->first; +} + +template +simdjson_inline T& implementation_simdjson_result_base::value_unsafe() & noexcept { + return this->first; +} + +template +simdjson_inline T&& implementation_simdjson_result_base::value_unsafe() && noexcept { + return std::forward(this->first); +} + +template +simdjson_inline implementation_simdjson_result_base::implementation_simdjson_result_base(T &&value, error_code error) noexcept + : first{std::forward(value)}, second{error} {} +template +simdjson_inline implementation_simdjson_result_base::implementation_simdjson_result_base(error_code error) noexcept + : implementation_simdjson_result_base(T{}, error) {} +template +simdjson_inline implementation_simdjson_result_base::implementation_simdjson_result_base(T &&value) noexcept + : implementation_simdjson_result_base(std::forward(value), SUCCESS) {} + +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_IMPLEMENTATION_SIMDJSON_RESULT_BASE_INL_H +/* end file simdjson/generic/implementation_simdjson_result_base-inl.h for rvv_vls */ +/* end file simdjson/generic/amalgamated.h for rvv_vls */ +/* including simdjson/rvv-vls/end.h: #include "simdjson/rvv-vls/end.h" */ +/* begin file simdjson/rvv-vls/end.h */ +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +/* undefining SIMDJSON_IMPLEMENTATION from "rvv_vls" */ +#undef SIMDJSON_IMPLEMENTATION +/* end file simdjson/rvv-vls/end.h */ + +#endif // SIMDJSON_RVV_VLS_H +/* end file simdjson/rvv-vls.h */ #else #error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION #endif @@ -33355,6 +37860,7 @@ simdjson_inline implementation_simdjson_result_base::implementation_simdjson_ // All includes not under simdjson/generic/builder must be here! // Otherwise, amalgamation will fail. /* skipped duplicate #include "simdjson/concepts.h" */ +/* skipped duplicate #include "simdjson/dom/fractured_json.h" */ #endif // SIMDJSON_GENERIC_BUILDER_DEPENDENCIES_H /* end file simdjson/generic/builder/dependencies.h */ @@ -34077,6 +38583,7 @@ namespace { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, "ARM kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -34531,7 +39038,7 @@ simdjson_warn_unused simdjson_result to_json(const Z &z, size_t ini return std::string(s); } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = simdjson::arm64::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = simdjson::arm64::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { simdjson::arm64::builder::string_builder b(initial_capacity); b.append(z); std::string_view sv; @@ -34828,7 +39335,7 @@ simdjson_warn_unused simdjson_result to_json_string(const Z &z, siz } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { string_builder b(initial_capacity); append(b, z); std::string_view view; @@ -34905,7 +39412,7 @@ simdjson_warn_unused simdjson_result to_json(const Z &z, size_t ini return std::string(s); } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = arm64::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = arm64::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { arm64::builder::string_builder b(initial_capacity); arm64::builder::append(b, z); std::string_view view; @@ -34930,6 +39437,126 @@ simdjson_warn_unused simdjson_result extract_from(const T &obj, siz #endif /* end file simdjson/generic/builder/json_builder.h for arm64 */ +/* including simdjson/generic/builder/fractured_json_builder.h for arm64: #include "simdjson/generic/builder/fractured_json_builder.h" */ +/* begin file simdjson/generic/builder/fractured_json_builder.h for arm64 */ +#ifndef SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H +#define SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/builder/json_builder.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/dom/fractured_json.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#if SIMDJSON_STATIC_REFLECTION + +namespace simdjson { +namespace arm64 { +namespace builder { + +/** + * Serialize an object to a FracturedJson-formatted string. + * + * FracturedJson produces human-readable yet compact JSON output by intelligently + * choosing between different layout strategies (inline, compact multiline, table, + * expanded) based on content complexity, length, and structure similarity. + * + * This function combines the builder's serialization with FracturedJson formatting: + * 1. Serializes the object to minified JSON using reflection + * 2. Parses and reformats using FracturedJson + * + * Example: + * struct User { int id; std::string name; bool active; }; + * User user{1, "Alice", true}; + * auto result = to_fractured_json_string(user); + * // result.value() == "{ \"id\": 1, \"name\": \"Alice\", \"active\": true }" + * + * @param obj The object to serialize (must be a reflectable type) + * @param opts FracturedJson formatting options + * @param initial_capacity Initial buffer capacity for serialization + * @return The formatted JSON string, or an error + */ +template +simdjson_warn_unused simdjson_result to_fractured_json_string( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + // Step 1: Serialize to minified JSON + std::string formatted; + auto error = to_json_string(obj, initial_capacity).get(formatted); + if (error) { + return error; + } + + // Step 2: Reformat with FracturedJson + return fractured_json_string(formatted, opts); +} + +/** + * Extract specific fields from an object and format with FracturedJson. + * + * Example: + * struct User { int id; std::string name; std::string email; bool active; }; + * User user{1, "Alice", "alice@example.com", true}; + * auto result = extract_fractured_json<"id", "name">(user); + * // result.value() == "{ \"id\": 1, \"name\": \"Alice\" }" + * + * @param obj The object to serialize + * @param opts FracturedJson formatting options + * @param initial_capacity Initial buffer capacity for serialization + * @return The formatted JSON string containing only the specified fields + */ +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_result extract_fractured_json( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + // Step 1: Extract fields to minified JSON + std::string formatted; + auto error = extract_from(obj, initial_capacity).get(formatted); + if (error) { + return error; + } + + // Step 2: Reformat with FracturedJson + return fractured_json_string(formatted, opts); +} + +} // namespace builder +} // namespace arm64 + +// Global namespace convenience functions + +/** + * Serialize an object to a FracturedJson-formatted string. + * Global namespace version for convenience. + */ +template +simdjson_warn_unused simdjson_result to_fractured_json_string( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = arm64::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + return arm64::builder::to_fractured_json_string(obj, opts, initial_capacity); +} +/** + * Extract specific fields from an object and format with FracturedJson. + * Global namespace version for convenience. + */ +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_result extract_fractured_json( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = arm64::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + return arm64::builder::extract_fractured_json(obj, opts, initial_capacity); +} + +} // namespace simdjson + +#endif // SIMDJSON_STATIC_REFLECTION + +#endif // SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H +/* end file simdjson/generic/builder/fractured_json_builder.h for arm64 */ @@ -34967,9 +39594,15 @@ simdjson_warn_unused simdjson_result extract_from(const T &obj, siz #endif #if SIMDJSON_EXPERIMENTAL_HAS_NEON #include +#ifdef _MSC_VER +#include +#endif #endif #if SIMDJSON_EXPERIMENTAL_HAS_SSE2 #include +#ifdef _MSC_VER +#include +#endif #endif namespace simdjson { @@ -35077,10 +39710,10 @@ simdjson_inline bool fast_needs_escaping(std::string_view view) { } #endif -SIMDJSON_CONSTEXPR_LAMBDA inline size_t -find_next_json_quotable_character(const std::string_view view, - size_t location) noexcept { - +// Scalar fallback for finding next quotable character +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline size_t +find_next_json_quotable_character_scalar(const std::string_view view, + size_t location) noexcept { for (auto pos = view.begin() + location; pos != view.end(); ++pos) { if (json_quotable_character[static_cast(*pos)]) { return pos - view.begin(); @@ -35089,6 +39722,114 @@ find_next_json_quotable_character(const std::string_view view, return size_t(view.size()); } +// SIMD-accelerated position finding that directly locates the first quotable +// character, combining detection and position extraction in a single pass to +// minimize redundant work. +#if SIMDJSON_EXPERIMENTAL_HAS_NEON +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants for characters requiring escape + uint8x16_t v34 = vdupq_n_u8(34); // '"' + uint8x16_t v92 = vdupq_n_u8(92); // '\\' + uint8x16_t v32 = vdupq_n_u8(32); // control char threshold + + while (remaining >= 16) { + uint8x16_t word = vld1q_u8(ptr); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + uint8x16_t needs_escape = vceqq_u8(word, v34); + needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92)); + needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32)); + + if (vmaxvq_u32(vreinterpretq_u32_u8(needs_escape)) != 0) { + // Found quotable character - extract exact byte position using ctz + uint64x2_t as64 = vreinterpretq_u64_u8(needs_escape); + uint64_t lo = vgetq_lane_u64(as64, 0); + uint64_t hi = vgetq_lane_u64(as64, 1); + size_t offset = ptr - reinterpret_cast(view.data()); +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + if (lo != 0) { + _BitScanForward64(&trailing_zero, lo); + return offset + trailing_zero / 8; + } else { + _BitScanForward64(&trailing_zero, hi); + return offset + 8 + trailing_zero / 8; + } +#else + if (lo != 0) { + return offset + __builtin_ctzll(lo) / 8; + } else { + return offset + 8 + __builtin_ctzll(hi) / 8; + } +#endif + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_SSE2 +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants + __m128i v34 = _mm_set1_epi8(34); // '"' + __m128i v92 = _mm_set1_epi8(92); // '\\' + __m128i v31 = _mm_set1_epi8(31); // for control char detection + + while (remaining >= 16) { + __m128i word = _mm_loadu_si128(reinterpret_cast(ptr)); + + // Check for quotable characters + __m128i needs_escape = _mm_cmpeq_epi8(word, v34); + needs_escape = _mm_or_si128(needs_escape, _mm_cmpeq_epi8(word, v92)); + needs_escape = _mm_or_si128( + needs_escape, + _mm_cmpeq_epi8(_mm_subs_epu8(word, v31), _mm_setzero_si128())); + + int mask = _mm_movemask_epi8(needs_escape); + if (mask != 0) { + // Found quotable character - use trailing zero count to find position + size_t offset = ptr - reinterpret_cast(view.data()); +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + _BitScanForward(&trailing_zero, mask); + return offset + trailing_zero; +#else + return offset + __builtin_ctz(mask); +#endif + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#else +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + return find_next_json_quotable_character_scalar(view, location); +} +#endif + SIMDJSON_CONSTEXPR_LAMBDA static std::string_view control_chars[] = { "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", @@ -35101,7 +39842,7 @@ SIMDJSON_CONSTEXPR_LAMBDA static std::string_view control_chars[] = { // control characters (U+0000 through U+001F). There are two-character sequence // escape representations of some popular characters: // \", \\, \b, \f, \n, \r, \t. -SIMDJSON_CONSTEXPR_LAMBDA void escape_json_char(char c, char *&out) { +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline void escape_json_char(char c, char *&out) { if (c == '"') { memcpy(out, "\\\"", 2); out += 2; @@ -35115,14 +39856,20 @@ SIMDJSON_CONSTEXPR_LAMBDA void escape_json_char(char c, char *&out) { } } +// Writes the escaped version of input to out, returning the number of bytes +// written. Uses SIMD position finding to locate quotable characters efficiently. inline size_t write_string_escaped(const std::string_view input, char *out) { size_t mysize = input.size(); - if (!fast_needs_escaping(input)) { // fast path! + + // Use SIMD position finder directly - it returns mysize if no escape needed + size_t location = find_next_json_quotable_character(input, 0); + if (location == mysize) { + // Fast path: no escaping needed memcpy(out, input.data(), input.size()); return input.size(); } + const char *const initout = out; - size_t location = find_next_json_quotable_character(input, 0); memcpy(out, input.data(), location); out += location; escape_json_char(input[location], out); @@ -35321,12 +40068,29 @@ simdjson_inline void string_builder::append(number_type v) noexcept { } } else SIMDJSON_IF_CONSTEXPR(std::is_unsigned::value) { + // Process 4 digits at a time instead of 2, reducing store operations + // and divisions by approximately half for large numbers. constexpr size_t max_number_size = 20; if (capacity_check(max_number_size)) { using unsigned_type = typename std::make_unsigned::type; unsigned_type pv = static_cast(v); size_t dc = internal::digit_count(pv); char *write_pointer = buffer.get() + position + dc - 1; + + // Process 4 digits per iteration for large numbers + while (pv >= 10000) { + unsigned_type q = pv / 10000; + unsigned_type r = pv % 10000; + unsigned_type r_hi = r / 100; // High 2 digits of remainder + unsigned_type r_lo = r % 100; // Low 2 digits of remainder + // Write low 2 digits first (rightmost), then high 2 digits + memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2); + memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2); + write_pointer -= 4; + pv = q; + } + + // Handle remaining 1-4 digits with original 2-digit loop while (pv >= 100) { memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2); write_pointer -= 2; @@ -35341,6 +40105,7 @@ simdjson_inline void string_builder::append(number_type v) noexcept { } } else SIMDJSON_IF_CONSTEXPR(std::is_integral::value) { + // Same 4-digit batching as unsigned path for signed integers constexpr size_t max_number_size = 20; if (capacity_check(max_number_size)) { using unsigned_type = typename std::make_unsigned::type; @@ -35354,6 +40119,20 @@ simdjson_inline void string_builder::append(number_type v) noexcept { buffer.get()[position] = '-'; position += negative ? 1 : 0; char *write_pointer = buffer.get() + position + dc - 1; + + // Process 4 digits per iteration for large numbers + while (pv >= 10000) { + unsigned_type q = pv / 10000; + unsigned_type r = pv % 10000; + unsigned_type r_hi = r / 100; + unsigned_type r_lo = r % 100; + memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2); + memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2); + write_pointer -= 4; + pv = q; + } + + // Handle remaining 1-4 digits while (pv >= 100) { memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2); write_pointer -= 2; @@ -36170,7 +40949,7 @@ simdjson_warn_unused simdjson_result to_json(const Z &z, size_t ini return std::string(s); } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = simdjson::fallback::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = simdjson::fallback::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { simdjson::fallback::builder::string_builder b(initial_capacity); b.append(z); std::string_view sv; @@ -36467,7 +41246,7 @@ simdjson_warn_unused simdjson_result to_json_string(const Z &z, siz } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { string_builder b(initial_capacity); append(b, z); std::string_view view; @@ -36544,7 +41323,7 @@ simdjson_warn_unused simdjson_result to_json(const Z &z, size_t ini return std::string(s); } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = fallback::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = fallback::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { fallback::builder::string_builder b(initial_capacity); fallback::builder::append(b, z); std::string_view view; @@ -36569,6 +41348,126 @@ simdjson_warn_unused simdjson_result extract_from(const T &obj, siz #endif /* end file simdjson/generic/builder/json_builder.h for fallback */ +/* including simdjson/generic/builder/fractured_json_builder.h for fallback: #include "simdjson/generic/builder/fractured_json_builder.h" */ +/* begin file simdjson/generic/builder/fractured_json_builder.h for fallback */ +#ifndef SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H +#define SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/builder/json_builder.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/dom/fractured_json.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#if SIMDJSON_STATIC_REFLECTION + +namespace simdjson { +namespace fallback { +namespace builder { + +/** + * Serialize an object to a FracturedJson-formatted string. + * + * FracturedJson produces human-readable yet compact JSON output by intelligently + * choosing between different layout strategies (inline, compact multiline, table, + * expanded) based on content complexity, length, and structure similarity. + * + * This function combines the builder's serialization with FracturedJson formatting: + * 1. Serializes the object to minified JSON using reflection + * 2. Parses and reformats using FracturedJson + * + * Example: + * struct User { int id; std::string name; bool active; }; + * User user{1, "Alice", true}; + * auto result = to_fractured_json_string(user); + * // result.value() == "{ \"id\": 1, \"name\": \"Alice\", \"active\": true }" + * + * @param obj The object to serialize (must be a reflectable type) + * @param opts FracturedJson formatting options + * @param initial_capacity Initial buffer capacity for serialization + * @return The formatted JSON string, or an error + */ +template +simdjson_warn_unused simdjson_result to_fractured_json_string( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + // Step 1: Serialize to minified JSON + std::string formatted; + auto error = to_json_string(obj, initial_capacity).get(formatted); + if (error) { + return error; + } + + // Step 2: Reformat with FracturedJson + return fractured_json_string(formatted, opts); +} + +/** + * Extract specific fields from an object and format with FracturedJson. + * + * Example: + * struct User { int id; std::string name; std::string email; bool active; }; + * User user{1, "Alice", "alice@example.com", true}; + * auto result = extract_fractured_json<"id", "name">(user); + * // result.value() == "{ \"id\": 1, \"name\": \"Alice\" }" + * + * @param obj The object to serialize + * @param opts FracturedJson formatting options + * @param initial_capacity Initial buffer capacity for serialization + * @return The formatted JSON string containing only the specified fields + */ +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_result extract_fractured_json( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + // Step 1: Extract fields to minified JSON + std::string formatted; + auto error = extract_from(obj, initial_capacity).get(formatted); + if (error) { + return error; + } + + // Step 2: Reformat with FracturedJson + return fractured_json_string(formatted, opts); +} + +} // namespace builder +} // namespace fallback + +// Global namespace convenience functions + +/** + * Serialize an object to a FracturedJson-formatted string. + * Global namespace version for convenience. + */ +template +simdjson_warn_unused simdjson_result to_fractured_json_string( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = fallback::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + return fallback::builder::to_fractured_json_string(obj, opts, initial_capacity); +} +/** + * Extract specific fields from an object and format with FracturedJson. + * Global namespace version for convenience. + */ +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_result extract_fractured_json( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = fallback::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + return fallback::builder::extract_fractured_json(obj, opts, initial_capacity); +} + +} // namespace simdjson + +#endif // SIMDJSON_STATIC_REFLECTION + +#endif // SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H +/* end file simdjson/generic/builder/fractured_json_builder.h for fallback */ @@ -36606,9 +41505,15 @@ simdjson_warn_unused simdjson_result extract_from(const T &obj, siz #endif #if SIMDJSON_EXPERIMENTAL_HAS_NEON #include +#ifdef _MSC_VER +#include +#endif #endif #if SIMDJSON_EXPERIMENTAL_HAS_SSE2 #include +#ifdef _MSC_VER +#include +#endif #endif namespace simdjson { @@ -36716,10 +41621,10 @@ simdjson_inline bool fast_needs_escaping(std::string_view view) { } #endif -SIMDJSON_CONSTEXPR_LAMBDA inline size_t -find_next_json_quotable_character(const std::string_view view, - size_t location) noexcept { - +// Scalar fallback for finding next quotable character +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline size_t +find_next_json_quotable_character_scalar(const std::string_view view, + size_t location) noexcept { for (auto pos = view.begin() + location; pos != view.end(); ++pos) { if (json_quotable_character[static_cast(*pos)]) { return pos - view.begin(); @@ -36728,6 +41633,114 @@ find_next_json_quotable_character(const std::string_view view, return size_t(view.size()); } +// SIMD-accelerated position finding that directly locates the first quotable +// character, combining detection and position extraction in a single pass to +// minimize redundant work. +#if SIMDJSON_EXPERIMENTAL_HAS_NEON +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants for characters requiring escape + uint8x16_t v34 = vdupq_n_u8(34); // '"' + uint8x16_t v92 = vdupq_n_u8(92); // '\\' + uint8x16_t v32 = vdupq_n_u8(32); // control char threshold + + while (remaining >= 16) { + uint8x16_t word = vld1q_u8(ptr); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + uint8x16_t needs_escape = vceqq_u8(word, v34); + needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92)); + needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32)); + + if (vmaxvq_u32(vreinterpretq_u32_u8(needs_escape)) != 0) { + // Found quotable character - extract exact byte position using ctz + uint64x2_t as64 = vreinterpretq_u64_u8(needs_escape); + uint64_t lo = vgetq_lane_u64(as64, 0); + uint64_t hi = vgetq_lane_u64(as64, 1); + size_t offset = ptr - reinterpret_cast(view.data()); +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + if (lo != 0) { + _BitScanForward64(&trailing_zero, lo); + return offset + trailing_zero / 8; + } else { + _BitScanForward64(&trailing_zero, hi); + return offset + 8 + trailing_zero / 8; + } +#else + if (lo != 0) { + return offset + __builtin_ctzll(lo) / 8; + } else { + return offset + 8 + __builtin_ctzll(hi) / 8; + } +#endif + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_SSE2 +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants + __m128i v34 = _mm_set1_epi8(34); // '"' + __m128i v92 = _mm_set1_epi8(92); // '\\' + __m128i v31 = _mm_set1_epi8(31); // for control char detection + + while (remaining >= 16) { + __m128i word = _mm_loadu_si128(reinterpret_cast(ptr)); + + // Check for quotable characters + __m128i needs_escape = _mm_cmpeq_epi8(word, v34); + needs_escape = _mm_or_si128(needs_escape, _mm_cmpeq_epi8(word, v92)); + needs_escape = _mm_or_si128( + needs_escape, + _mm_cmpeq_epi8(_mm_subs_epu8(word, v31), _mm_setzero_si128())); + + int mask = _mm_movemask_epi8(needs_escape); + if (mask != 0) { + // Found quotable character - use trailing zero count to find position + size_t offset = ptr - reinterpret_cast(view.data()); +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + _BitScanForward(&trailing_zero, mask); + return offset + trailing_zero; +#else + return offset + __builtin_ctz(mask); +#endif + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#else +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + return find_next_json_quotable_character_scalar(view, location); +} +#endif + SIMDJSON_CONSTEXPR_LAMBDA static std::string_view control_chars[] = { "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", @@ -36740,7 +41753,7 @@ SIMDJSON_CONSTEXPR_LAMBDA static std::string_view control_chars[] = { // control characters (U+0000 through U+001F). There are two-character sequence // escape representations of some popular characters: // \", \\, \b, \f, \n, \r, \t. -SIMDJSON_CONSTEXPR_LAMBDA void escape_json_char(char c, char *&out) { +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline void escape_json_char(char c, char *&out) { if (c == '"') { memcpy(out, "\\\"", 2); out += 2; @@ -36754,14 +41767,20 @@ SIMDJSON_CONSTEXPR_LAMBDA void escape_json_char(char c, char *&out) { } } +// Writes the escaped version of input to out, returning the number of bytes +// written. Uses SIMD position finding to locate quotable characters efficiently. inline size_t write_string_escaped(const std::string_view input, char *out) { size_t mysize = input.size(); - if (!fast_needs_escaping(input)) { // fast path! + + // Use SIMD position finder directly - it returns mysize if no escape needed + size_t location = find_next_json_quotable_character(input, 0); + if (location == mysize) { + // Fast path: no escaping needed memcpy(out, input.data(), input.size()); return input.size(); } + const char *const initout = out; - size_t location = find_next_json_quotable_character(input, 0); memcpy(out, input.data(), location); out += location; escape_json_char(input[location], out); @@ -36960,12 +41979,29 @@ simdjson_inline void string_builder::append(number_type v) noexcept { } } else SIMDJSON_IF_CONSTEXPR(std::is_unsigned::value) { + // Process 4 digits at a time instead of 2, reducing store operations + // and divisions by approximately half for large numbers. constexpr size_t max_number_size = 20; if (capacity_check(max_number_size)) { using unsigned_type = typename std::make_unsigned::type; unsigned_type pv = static_cast(v); size_t dc = internal::digit_count(pv); char *write_pointer = buffer.get() + position + dc - 1; + + // Process 4 digits per iteration for large numbers + while (pv >= 10000) { + unsigned_type q = pv / 10000; + unsigned_type r = pv % 10000; + unsigned_type r_hi = r / 100; // High 2 digits of remainder + unsigned_type r_lo = r % 100; // Low 2 digits of remainder + // Write low 2 digits first (rightmost), then high 2 digits + memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2); + memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2); + write_pointer -= 4; + pv = q; + } + + // Handle remaining 1-4 digits with original 2-digit loop while (pv >= 100) { memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2); write_pointer -= 2; @@ -36980,6 +42016,7 @@ simdjson_inline void string_builder::append(number_type v) noexcept { } } else SIMDJSON_IF_CONSTEXPR(std::is_integral::value) { + // Same 4-digit batching as unsigned path for signed integers constexpr size_t max_number_size = 20; if (capacity_check(max_number_size)) { using unsigned_type = typename std::make_unsigned::type; @@ -36993,6 +42030,20 @@ simdjson_inline void string_builder::append(number_type v) noexcept { buffer.get()[position] = '-'; position += negative ? 1 : 0; char *write_pointer = buffer.get() + position + dc - 1; + + // Process 4 digits per iteration for large numbers + while (pv >= 10000) { + unsigned_type q = pv / 10000; + unsigned_type r = pv % 10000; + unsigned_type r_hi = r / 100; + unsigned_type r_lo = r % 100; + memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2); + memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2); + write_pointer -= 4; + pv = q; + } + + // Handle remaining 1-4 digits while (pv >= 100) { memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2); write_pointer -= 2; @@ -37870,6 +42921,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 2, "Haswell kernel should use two registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -38308,7 +43360,7 @@ simdjson_warn_unused simdjson_result to_json(const Z &z, size_t ini return std::string(s); } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = simdjson::haswell::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = simdjson::haswell::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { simdjson::haswell::builder::string_builder b(initial_capacity); b.append(z); std::string_view sv; @@ -38605,7 +43657,7 @@ simdjson_warn_unused simdjson_result to_json_string(const Z &z, siz } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { string_builder b(initial_capacity); append(b, z); std::string_view view; @@ -38682,7 +43734,7 @@ simdjson_warn_unused simdjson_result to_json(const Z &z, size_t ini return std::string(s); } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = haswell::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = haswell::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { haswell::builder::string_builder b(initial_capacity); haswell::builder::append(b, z); std::string_view view; @@ -38707,6 +43759,126 @@ simdjson_warn_unused simdjson_result extract_from(const T &obj, siz #endif /* end file simdjson/generic/builder/json_builder.h for haswell */ +/* including simdjson/generic/builder/fractured_json_builder.h for haswell: #include "simdjson/generic/builder/fractured_json_builder.h" */ +/* begin file simdjson/generic/builder/fractured_json_builder.h for haswell */ +#ifndef SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H +#define SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/builder/json_builder.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/dom/fractured_json.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#if SIMDJSON_STATIC_REFLECTION + +namespace simdjson { +namespace haswell { +namespace builder { + +/** + * Serialize an object to a FracturedJson-formatted string. + * + * FracturedJson produces human-readable yet compact JSON output by intelligently + * choosing between different layout strategies (inline, compact multiline, table, + * expanded) based on content complexity, length, and structure similarity. + * + * This function combines the builder's serialization with FracturedJson formatting: + * 1. Serializes the object to minified JSON using reflection + * 2. Parses and reformats using FracturedJson + * + * Example: + * struct User { int id; std::string name; bool active; }; + * User user{1, "Alice", true}; + * auto result = to_fractured_json_string(user); + * // result.value() == "{ \"id\": 1, \"name\": \"Alice\", \"active\": true }" + * + * @param obj The object to serialize (must be a reflectable type) + * @param opts FracturedJson formatting options + * @param initial_capacity Initial buffer capacity for serialization + * @return The formatted JSON string, or an error + */ +template +simdjson_warn_unused simdjson_result to_fractured_json_string( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + // Step 1: Serialize to minified JSON + std::string formatted; + auto error = to_json_string(obj, initial_capacity).get(formatted); + if (error) { + return error; + } + + // Step 2: Reformat with FracturedJson + return fractured_json_string(formatted, opts); +} + +/** + * Extract specific fields from an object and format with FracturedJson. + * + * Example: + * struct User { int id; std::string name; std::string email; bool active; }; + * User user{1, "Alice", "alice@example.com", true}; + * auto result = extract_fractured_json<"id", "name">(user); + * // result.value() == "{ \"id\": 1, \"name\": \"Alice\" }" + * + * @param obj The object to serialize + * @param opts FracturedJson formatting options + * @param initial_capacity Initial buffer capacity for serialization + * @return The formatted JSON string containing only the specified fields + */ +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_result extract_fractured_json( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + // Step 1: Extract fields to minified JSON + std::string formatted; + auto error = extract_from(obj, initial_capacity).get(formatted); + if (error) { + return error; + } + + // Step 2: Reformat with FracturedJson + return fractured_json_string(formatted, opts); +} + +} // namespace builder +} // namespace haswell + +// Global namespace convenience functions + +/** + * Serialize an object to a FracturedJson-formatted string. + * Global namespace version for convenience. + */ +template +simdjson_warn_unused simdjson_result to_fractured_json_string( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = haswell::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + return haswell::builder::to_fractured_json_string(obj, opts, initial_capacity); +} +/** + * Extract specific fields from an object and format with FracturedJson. + * Global namespace version for convenience. + */ +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_result extract_fractured_json( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = haswell::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + return haswell::builder::extract_fractured_json(obj, opts, initial_capacity); +} + +} // namespace simdjson + +#endif // SIMDJSON_STATIC_REFLECTION + +#endif // SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H +/* end file simdjson/generic/builder/fractured_json_builder.h for haswell */ @@ -38744,9 +43916,15 @@ simdjson_warn_unused simdjson_result extract_from(const T &obj, siz #endif #if SIMDJSON_EXPERIMENTAL_HAS_NEON #include +#ifdef _MSC_VER +#include +#endif #endif #if SIMDJSON_EXPERIMENTAL_HAS_SSE2 #include +#ifdef _MSC_VER +#include +#endif #endif namespace simdjson { @@ -38854,10 +44032,10 @@ simdjson_inline bool fast_needs_escaping(std::string_view view) { } #endif -SIMDJSON_CONSTEXPR_LAMBDA inline size_t -find_next_json_quotable_character(const std::string_view view, - size_t location) noexcept { - +// Scalar fallback for finding next quotable character +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline size_t +find_next_json_quotable_character_scalar(const std::string_view view, + size_t location) noexcept { for (auto pos = view.begin() + location; pos != view.end(); ++pos) { if (json_quotable_character[static_cast(*pos)]) { return pos - view.begin(); @@ -38866,6 +44044,114 @@ find_next_json_quotable_character(const std::string_view view, return size_t(view.size()); } +// SIMD-accelerated position finding that directly locates the first quotable +// character, combining detection and position extraction in a single pass to +// minimize redundant work. +#if SIMDJSON_EXPERIMENTAL_HAS_NEON +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants for characters requiring escape + uint8x16_t v34 = vdupq_n_u8(34); // '"' + uint8x16_t v92 = vdupq_n_u8(92); // '\\' + uint8x16_t v32 = vdupq_n_u8(32); // control char threshold + + while (remaining >= 16) { + uint8x16_t word = vld1q_u8(ptr); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + uint8x16_t needs_escape = vceqq_u8(word, v34); + needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92)); + needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32)); + + if (vmaxvq_u32(vreinterpretq_u32_u8(needs_escape)) != 0) { + // Found quotable character - extract exact byte position using ctz + uint64x2_t as64 = vreinterpretq_u64_u8(needs_escape); + uint64_t lo = vgetq_lane_u64(as64, 0); + uint64_t hi = vgetq_lane_u64(as64, 1); + size_t offset = ptr - reinterpret_cast(view.data()); +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + if (lo != 0) { + _BitScanForward64(&trailing_zero, lo); + return offset + trailing_zero / 8; + } else { + _BitScanForward64(&trailing_zero, hi); + return offset + 8 + trailing_zero / 8; + } +#else + if (lo != 0) { + return offset + __builtin_ctzll(lo) / 8; + } else { + return offset + 8 + __builtin_ctzll(hi) / 8; + } +#endif + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_SSE2 +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants + __m128i v34 = _mm_set1_epi8(34); // '"' + __m128i v92 = _mm_set1_epi8(92); // '\\' + __m128i v31 = _mm_set1_epi8(31); // for control char detection + + while (remaining >= 16) { + __m128i word = _mm_loadu_si128(reinterpret_cast(ptr)); + + // Check for quotable characters + __m128i needs_escape = _mm_cmpeq_epi8(word, v34); + needs_escape = _mm_or_si128(needs_escape, _mm_cmpeq_epi8(word, v92)); + needs_escape = _mm_or_si128( + needs_escape, + _mm_cmpeq_epi8(_mm_subs_epu8(word, v31), _mm_setzero_si128())); + + int mask = _mm_movemask_epi8(needs_escape); + if (mask != 0) { + // Found quotable character - use trailing zero count to find position + size_t offset = ptr - reinterpret_cast(view.data()); +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + _BitScanForward(&trailing_zero, mask); + return offset + trailing_zero; +#else + return offset + __builtin_ctz(mask); +#endif + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#else +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + return find_next_json_quotable_character_scalar(view, location); +} +#endif + SIMDJSON_CONSTEXPR_LAMBDA static std::string_view control_chars[] = { "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", @@ -38878,7 +44164,7 @@ SIMDJSON_CONSTEXPR_LAMBDA static std::string_view control_chars[] = { // control characters (U+0000 through U+001F). There are two-character sequence // escape representations of some popular characters: // \", \\, \b, \f, \n, \r, \t. -SIMDJSON_CONSTEXPR_LAMBDA void escape_json_char(char c, char *&out) { +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline void escape_json_char(char c, char *&out) { if (c == '"') { memcpy(out, "\\\"", 2); out += 2; @@ -38892,14 +44178,20 @@ SIMDJSON_CONSTEXPR_LAMBDA void escape_json_char(char c, char *&out) { } } +// Writes the escaped version of input to out, returning the number of bytes +// written. Uses SIMD position finding to locate quotable characters efficiently. inline size_t write_string_escaped(const std::string_view input, char *out) { size_t mysize = input.size(); - if (!fast_needs_escaping(input)) { // fast path! + + // Use SIMD position finder directly - it returns mysize if no escape needed + size_t location = find_next_json_quotable_character(input, 0); + if (location == mysize) { + // Fast path: no escaping needed memcpy(out, input.data(), input.size()); return input.size(); } + const char *const initout = out; - size_t location = find_next_json_quotable_character(input, 0); memcpy(out, input.data(), location); out += location; escape_json_char(input[location], out); @@ -39098,12 +44390,29 @@ simdjson_inline void string_builder::append(number_type v) noexcept { } } else SIMDJSON_IF_CONSTEXPR(std::is_unsigned::value) { + // Process 4 digits at a time instead of 2, reducing store operations + // and divisions by approximately half for large numbers. constexpr size_t max_number_size = 20; if (capacity_check(max_number_size)) { using unsigned_type = typename std::make_unsigned::type; unsigned_type pv = static_cast(v); size_t dc = internal::digit_count(pv); char *write_pointer = buffer.get() + position + dc - 1; + + // Process 4 digits per iteration for large numbers + while (pv >= 10000) { + unsigned_type q = pv / 10000; + unsigned_type r = pv % 10000; + unsigned_type r_hi = r / 100; // High 2 digits of remainder + unsigned_type r_lo = r % 100; // Low 2 digits of remainder + // Write low 2 digits first (rightmost), then high 2 digits + memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2); + memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2); + write_pointer -= 4; + pv = q; + } + + // Handle remaining 1-4 digits with original 2-digit loop while (pv >= 100) { memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2); write_pointer -= 2; @@ -39118,6 +44427,7 @@ simdjson_inline void string_builder::append(number_type v) noexcept { } } else SIMDJSON_IF_CONSTEXPR(std::is_integral::value) { + // Same 4-digit batching as unsigned path for signed integers constexpr size_t max_number_size = 20; if (capacity_check(max_number_size)) { using unsigned_type = typename std::make_unsigned::type; @@ -39131,6 +44441,20 @@ simdjson_inline void string_builder::append(number_type v) noexcept { buffer.get()[position] = '-'; position += negative ? 1 : 0; char *write_pointer = buffer.get() + position + dc - 1; + + // Process 4 digits per iteration for large numbers + while (pv >= 10000) { + unsigned_type q = pv / 10000; + unsigned_type r = pv % 10000; + unsigned_type r_hi = r / 100; + unsigned_type r_lo = r % 100; + memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2); + memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2); + write_pointer -= 4; + pv = q; + } + + // Handle remaining 1-4 digits while (pv >= 100) { memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2); write_pointer -= 2; @@ -39963,6 +45287,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 1, "Icelake kernel should use one register per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -40446,7 +45771,7 @@ simdjson_warn_unused simdjson_result to_json(const Z &z, size_t ini return std::string(s); } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = simdjson::icelake::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = simdjson::icelake::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { simdjson::icelake::builder::string_builder b(initial_capacity); b.append(z); std::string_view sv; @@ -40743,7 +46068,7 @@ simdjson_warn_unused simdjson_result to_json_string(const Z &z, siz } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { string_builder b(initial_capacity); append(b, z); std::string_view view; @@ -40820,7 +46145,7 @@ simdjson_warn_unused simdjson_result to_json(const Z &z, size_t ini return std::string(s); } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = icelake::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = icelake::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { icelake::builder::string_builder b(initial_capacity); icelake::builder::append(b, z); std::string_view view; @@ -40845,6 +46170,126 @@ simdjson_warn_unused simdjson_result extract_from(const T &obj, siz #endif /* end file simdjson/generic/builder/json_builder.h for icelake */ +/* including simdjson/generic/builder/fractured_json_builder.h for icelake: #include "simdjson/generic/builder/fractured_json_builder.h" */ +/* begin file simdjson/generic/builder/fractured_json_builder.h for icelake */ +#ifndef SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H +#define SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/builder/json_builder.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/dom/fractured_json.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#if SIMDJSON_STATIC_REFLECTION + +namespace simdjson { +namespace icelake { +namespace builder { + +/** + * Serialize an object to a FracturedJson-formatted string. + * + * FracturedJson produces human-readable yet compact JSON output by intelligently + * choosing between different layout strategies (inline, compact multiline, table, + * expanded) based on content complexity, length, and structure similarity. + * + * This function combines the builder's serialization with FracturedJson formatting: + * 1. Serializes the object to minified JSON using reflection + * 2. Parses and reformats using FracturedJson + * + * Example: + * struct User { int id; std::string name; bool active; }; + * User user{1, "Alice", true}; + * auto result = to_fractured_json_string(user); + * // result.value() == "{ \"id\": 1, \"name\": \"Alice\", \"active\": true }" + * + * @param obj The object to serialize (must be a reflectable type) + * @param opts FracturedJson formatting options + * @param initial_capacity Initial buffer capacity for serialization + * @return The formatted JSON string, or an error + */ +template +simdjson_warn_unused simdjson_result to_fractured_json_string( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + // Step 1: Serialize to minified JSON + std::string formatted; + auto error = to_json_string(obj, initial_capacity).get(formatted); + if (error) { + return error; + } + + // Step 2: Reformat with FracturedJson + return fractured_json_string(formatted, opts); +} + +/** + * Extract specific fields from an object and format with FracturedJson. + * + * Example: + * struct User { int id; std::string name; std::string email; bool active; }; + * User user{1, "Alice", "alice@example.com", true}; + * auto result = extract_fractured_json<"id", "name">(user); + * // result.value() == "{ \"id\": 1, \"name\": \"Alice\" }" + * + * @param obj The object to serialize + * @param opts FracturedJson formatting options + * @param initial_capacity Initial buffer capacity for serialization + * @return The formatted JSON string containing only the specified fields + */ +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_result extract_fractured_json( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + // Step 1: Extract fields to minified JSON + std::string formatted; + auto error = extract_from(obj, initial_capacity).get(formatted); + if (error) { + return error; + } + + // Step 2: Reformat with FracturedJson + return fractured_json_string(formatted, opts); +} + +} // namespace builder +} // namespace icelake + +// Global namespace convenience functions + +/** + * Serialize an object to a FracturedJson-formatted string. + * Global namespace version for convenience. + */ +template +simdjson_warn_unused simdjson_result to_fractured_json_string( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = icelake::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + return icelake::builder::to_fractured_json_string(obj, opts, initial_capacity); +} +/** + * Extract specific fields from an object and format with FracturedJson. + * Global namespace version for convenience. + */ +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_result extract_fractured_json( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = icelake::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + return icelake::builder::extract_fractured_json(obj, opts, initial_capacity); +} + +} // namespace simdjson + +#endif // SIMDJSON_STATIC_REFLECTION + +#endif // SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H +/* end file simdjson/generic/builder/fractured_json_builder.h for icelake */ @@ -40882,9 +46327,15 @@ simdjson_warn_unused simdjson_result extract_from(const T &obj, siz #endif #if SIMDJSON_EXPERIMENTAL_HAS_NEON #include +#ifdef _MSC_VER +#include +#endif #endif #if SIMDJSON_EXPERIMENTAL_HAS_SSE2 #include +#ifdef _MSC_VER +#include +#endif #endif namespace simdjson { @@ -40992,10 +46443,10 @@ simdjson_inline bool fast_needs_escaping(std::string_view view) { } #endif -SIMDJSON_CONSTEXPR_LAMBDA inline size_t -find_next_json_quotable_character(const std::string_view view, - size_t location) noexcept { - +// Scalar fallback for finding next quotable character +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline size_t +find_next_json_quotable_character_scalar(const std::string_view view, + size_t location) noexcept { for (auto pos = view.begin() + location; pos != view.end(); ++pos) { if (json_quotable_character[static_cast(*pos)]) { return pos - view.begin(); @@ -41004,6 +46455,114 @@ find_next_json_quotable_character(const std::string_view view, return size_t(view.size()); } +// SIMD-accelerated position finding that directly locates the first quotable +// character, combining detection and position extraction in a single pass to +// minimize redundant work. +#if SIMDJSON_EXPERIMENTAL_HAS_NEON +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants for characters requiring escape + uint8x16_t v34 = vdupq_n_u8(34); // '"' + uint8x16_t v92 = vdupq_n_u8(92); // '\\' + uint8x16_t v32 = vdupq_n_u8(32); // control char threshold + + while (remaining >= 16) { + uint8x16_t word = vld1q_u8(ptr); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + uint8x16_t needs_escape = vceqq_u8(word, v34); + needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92)); + needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32)); + + if (vmaxvq_u32(vreinterpretq_u32_u8(needs_escape)) != 0) { + // Found quotable character - extract exact byte position using ctz + uint64x2_t as64 = vreinterpretq_u64_u8(needs_escape); + uint64_t lo = vgetq_lane_u64(as64, 0); + uint64_t hi = vgetq_lane_u64(as64, 1); + size_t offset = ptr - reinterpret_cast(view.data()); +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + if (lo != 0) { + _BitScanForward64(&trailing_zero, lo); + return offset + trailing_zero / 8; + } else { + _BitScanForward64(&trailing_zero, hi); + return offset + 8 + trailing_zero / 8; + } +#else + if (lo != 0) { + return offset + __builtin_ctzll(lo) / 8; + } else { + return offset + 8 + __builtin_ctzll(hi) / 8; + } +#endif + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_SSE2 +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants + __m128i v34 = _mm_set1_epi8(34); // '"' + __m128i v92 = _mm_set1_epi8(92); // '\\' + __m128i v31 = _mm_set1_epi8(31); // for control char detection + + while (remaining >= 16) { + __m128i word = _mm_loadu_si128(reinterpret_cast(ptr)); + + // Check for quotable characters + __m128i needs_escape = _mm_cmpeq_epi8(word, v34); + needs_escape = _mm_or_si128(needs_escape, _mm_cmpeq_epi8(word, v92)); + needs_escape = _mm_or_si128( + needs_escape, + _mm_cmpeq_epi8(_mm_subs_epu8(word, v31), _mm_setzero_si128())); + + int mask = _mm_movemask_epi8(needs_escape); + if (mask != 0) { + // Found quotable character - use trailing zero count to find position + size_t offset = ptr - reinterpret_cast(view.data()); +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + _BitScanForward(&trailing_zero, mask); + return offset + trailing_zero; +#else + return offset + __builtin_ctz(mask); +#endif + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#else +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + return find_next_json_quotable_character_scalar(view, location); +} +#endif + SIMDJSON_CONSTEXPR_LAMBDA static std::string_view control_chars[] = { "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", @@ -41016,7 +46575,7 @@ SIMDJSON_CONSTEXPR_LAMBDA static std::string_view control_chars[] = { // control characters (U+0000 through U+001F). There are two-character sequence // escape representations of some popular characters: // \", \\, \b, \f, \n, \r, \t. -SIMDJSON_CONSTEXPR_LAMBDA void escape_json_char(char c, char *&out) { +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline void escape_json_char(char c, char *&out) { if (c == '"') { memcpy(out, "\\\"", 2); out += 2; @@ -41030,14 +46589,20 @@ SIMDJSON_CONSTEXPR_LAMBDA void escape_json_char(char c, char *&out) { } } +// Writes the escaped version of input to out, returning the number of bytes +// written. Uses SIMD position finding to locate quotable characters efficiently. inline size_t write_string_escaped(const std::string_view input, char *out) { size_t mysize = input.size(); - if (!fast_needs_escaping(input)) { // fast path! + + // Use SIMD position finder directly - it returns mysize if no escape needed + size_t location = find_next_json_quotable_character(input, 0); + if (location == mysize) { + // Fast path: no escaping needed memcpy(out, input.data(), input.size()); return input.size(); } + const char *const initout = out; - size_t location = find_next_json_quotable_character(input, 0); memcpy(out, input.data(), location); out += location; escape_json_char(input[location], out); @@ -41236,12 +46801,29 @@ simdjson_inline void string_builder::append(number_type v) noexcept { } } else SIMDJSON_IF_CONSTEXPR(std::is_unsigned::value) { + // Process 4 digits at a time instead of 2, reducing store operations + // and divisions by approximately half for large numbers. constexpr size_t max_number_size = 20; if (capacity_check(max_number_size)) { using unsigned_type = typename std::make_unsigned::type; unsigned_type pv = static_cast(v); size_t dc = internal::digit_count(pv); char *write_pointer = buffer.get() + position + dc - 1; + + // Process 4 digits per iteration for large numbers + while (pv >= 10000) { + unsigned_type q = pv / 10000; + unsigned_type r = pv % 10000; + unsigned_type r_hi = r / 100; // High 2 digits of remainder + unsigned_type r_lo = r % 100; // Low 2 digits of remainder + // Write low 2 digits first (rightmost), then high 2 digits + memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2); + memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2); + write_pointer -= 4; + pv = q; + } + + // Handle remaining 1-4 digits with original 2-digit loop while (pv >= 100) { memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2); write_pointer -= 2; @@ -41256,6 +46838,7 @@ simdjson_inline void string_builder::append(number_type v) noexcept { } } else SIMDJSON_IF_CONSTEXPR(std::is_integral::value) { + // Same 4-digit batching as unsigned path for signed integers constexpr size_t max_number_size = 20; if (capacity_check(max_number_size)) { using unsigned_type = typename std::make_unsigned::type; @@ -41269,6 +46852,20 @@ simdjson_inline void string_builder::append(number_type v) noexcept { buffer.get()[position] = '-'; position += negative ? 1 : 0; char *write_pointer = buffer.get() + position + dc - 1; + + // Process 4 digits per iteration for large numbers + while (pv >= 10000) { + unsigned_type q = pv / 10000; + unsigned_type r = pv % 10000; + unsigned_type r_hi = r / 100; + unsigned_type r_lo = r % 100; + memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2); + memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2); + write_pointer -= 4; + pv = q; + } + + // Handle remaining 1-4 digits while (pv >= 100) { memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2); write_pointer -= 2; @@ -42238,6 +47835,7 @@ template struct simd8x64 { static_assert(NUM_CHUNKS == 4, "PPC64 kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64 &o) = delete; // no copy allowed simd8x64 & @@ -42699,7 +48297,7 @@ simdjson_warn_unused simdjson_result to_json(const Z &z, size_t ini return std::string(s); } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = simdjson::ppc64::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = simdjson::ppc64::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { simdjson::ppc64::builder::string_builder b(initial_capacity); b.append(z); std::string_view sv; @@ -42996,7 +48594,7 @@ simdjson_warn_unused simdjson_result to_json_string(const Z &z, siz } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { string_builder b(initial_capacity); append(b, z); std::string_view view; @@ -43073,7 +48671,7 @@ simdjson_warn_unused simdjson_result to_json(const Z &z, size_t ini return std::string(s); } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = ppc64::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = ppc64::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { ppc64::builder::string_builder b(initial_capacity); ppc64::builder::append(b, z); std::string_view view; @@ -43098,6 +48696,126 @@ simdjson_warn_unused simdjson_result extract_from(const T &obj, siz #endif /* end file simdjson/generic/builder/json_builder.h for ppc64 */ +/* including simdjson/generic/builder/fractured_json_builder.h for ppc64: #include "simdjson/generic/builder/fractured_json_builder.h" */ +/* begin file simdjson/generic/builder/fractured_json_builder.h for ppc64 */ +#ifndef SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H +#define SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/builder/json_builder.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/dom/fractured_json.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#if SIMDJSON_STATIC_REFLECTION + +namespace simdjson { +namespace ppc64 { +namespace builder { + +/** + * Serialize an object to a FracturedJson-formatted string. + * + * FracturedJson produces human-readable yet compact JSON output by intelligently + * choosing between different layout strategies (inline, compact multiline, table, + * expanded) based on content complexity, length, and structure similarity. + * + * This function combines the builder's serialization with FracturedJson formatting: + * 1. Serializes the object to minified JSON using reflection + * 2. Parses and reformats using FracturedJson + * + * Example: + * struct User { int id; std::string name; bool active; }; + * User user{1, "Alice", true}; + * auto result = to_fractured_json_string(user); + * // result.value() == "{ \"id\": 1, \"name\": \"Alice\", \"active\": true }" + * + * @param obj The object to serialize (must be a reflectable type) + * @param opts FracturedJson formatting options + * @param initial_capacity Initial buffer capacity for serialization + * @return The formatted JSON string, or an error + */ +template +simdjson_warn_unused simdjson_result to_fractured_json_string( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + // Step 1: Serialize to minified JSON + std::string formatted; + auto error = to_json_string(obj, initial_capacity).get(formatted); + if (error) { + return error; + } + + // Step 2: Reformat with FracturedJson + return fractured_json_string(formatted, opts); +} + +/** + * Extract specific fields from an object and format with FracturedJson. + * + * Example: + * struct User { int id; std::string name; std::string email; bool active; }; + * User user{1, "Alice", "alice@example.com", true}; + * auto result = extract_fractured_json<"id", "name">(user); + * // result.value() == "{ \"id\": 1, \"name\": \"Alice\" }" + * + * @param obj The object to serialize + * @param opts FracturedJson formatting options + * @param initial_capacity Initial buffer capacity for serialization + * @return The formatted JSON string containing only the specified fields + */ +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_result extract_fractured_json( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + // Step 1: Extract fields to minified JSON + std::string formatted; + auto error = extract_from(obj, initial_capacity).get(formatted); + if (error) { + return error; + } + + // Step 2: Reformat with FracturedJson + return fractured_json_string(formatted, opts); +} + +} // namespace builder +} // namespace ppc64 + +// Global namespace convenience functions + +/** + * Serialize an object to a FracturedJson-formatted string. + * Global namespace version for convenience. + */ +template +simdjson_warn_unused simdjson_result to_fractured_json_string( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = ppc64::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + return ppc64::builder::to_fractured_json_string(obj, opts, initial_capacity); +} +/** + * Extract specific fields from an object and format with FracturedJson. + * Global namespace version for convenience. + */ +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_result extract_fractured_json( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = ppc64::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + return ppc64::builder::extract_fractured_json(obj, opts, initial_capacity); +} + +} // namespace simdjson + +#endif // SIMDJSON_STATIC_REFLECTION + +#endif // SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H +/* end file simdjson/generic/builder/fractured_json_builder.h for ppc64 */ @@ -43135,9 +48853,15 @@ simdjson_warn_unused simdjson_result extract_from(const T &obj, siz #endif #if SIMDJSON_EXPERIMENTAL_HAS_NEON #include +#ifdef _MSC_VER +#include +#endif #endif #if SIMDJSON_EXPERIMENTAL_HAS_SSE2 #include +#ifdef _MSC_VER +#include +#endif #endif namespace simdjson { @@ -43245,10 +48969,10 @@ simdjson_inline bool fast_needs_escaping(std::string_view view) { } #endif -SIMDJSON_CONSTEXPR_LAMBDA inline size_t -find_next_json_quotable_character(const std::string_view view, - size_t location) noexcept { - +// Scalar fallback for finding next quotable character +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline size_t +find_next_json_quotable_character_scalar(const std::string_view view, + size_t location) noexcept { for (auto pos = view.begin() + location; pos != view.end(); ++pos) { if (json_quotable_character[static_cast(*pos)]) { return pos - view.begin(); @@ -43257,6 +48981,114 @@ find_next_json_quotable_character(const std::string_view view, return size_t(view.size()); } +// SIMD-accelerated position finding that directly locates the first quotable +// character, combining detection and position extraction in a single pass to +// minimize redundant work. +#if SIMDJSON_EXPERIMENTAL_HAS_NEON +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants for characters requiring escape + uint8x16_t v34 = vdupq_n_u8(34); // '"' + uint8x16_t v92 = vdupq_n_u8(92); // '\\' + uint8x16_t v32 = vdupq_n_u8(32); // control char threshold + + while (remaining >= 16) { + uint8x16_t word = vld1q_u8(ptr); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + uint8x16_t needs_escape = vceqq_u8(word, v34); + needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92)); + needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32)); + + if (vmaxvq_u32(vreinterpretq_u32_u8(needs_escape)) != 0) { + // Found quotable character - extract exact byte position using ctz + uint64x2_t as64 = vreinterpretq_u64_u8(needs_escape); + uint64_t lo = vgetq_lane_u64(as64, 0); + uint64_t hi = vgetq_lane_u64(as64, 1); + size_t offset = ptr - reinterpret_cast(view.data()); +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + if (lo != 0) { + _BitScanForward64(&trailing_zero, lo); + return offset + trailing_zero / 8; + } else { + _BitScanForward64(&trailing_zero, hi); + return offset + 8 + trailing_zero / 8; + } +#else + if (lo != 0) { + return offset + __builtin_ctzll(lo) / 8; + } else { + return offset + 8 + __builtin_ctzll(hi) / 8; + } +#endif + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_SSE2 +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants + __m128i v34 = _mm_set1_epi8(34); // '"' + __m128i v92 = _mm_set1_epi8(92); // '\\' + __m128i v31 = _mm_set1_epi8(31); // for control char detection + + while (remaining >= 16) { + __m128i word = _mm_loadu_si128(reinterpret_cast(ptr)); + + // Check for quotable characters + __m128i needs_escape = _mm_cmpeq_epi8(word, v34); + needs_escape = _mm_or_si128(needs_escape, _mm_cmpeq_epi8(word, v92)); + needs_escape = _mm_or_si128( + needs_escape, + _mm_cmpeq_epi8(_mm_subs_epu8(word, v31), _mm_setzero_si128())); + + int mask = _mm_movemask_epi8(needs_escape); + if (mask != 0) { + // Found quotable character - use trailing zero count to find position + size_t offset = ptr - reinterpret_cast(view.data()); +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + _BitScanForward(&trailing_zero, mask); + return offset + trailing_zero; +#else + return offset + __builtin_ctz(mask); +#endif + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#else +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + return find_next_json_quotable_character_scalar(view, location); +} +#endif + SIMDJSON_CONSTEXPR_LAMBDA static std::string_view control_chars[] = { "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", @@ -43269,7 +49101,7 @@ SIMDJSON_CONSTEXPR_LAMBDA static std::string_view control_chars[] = { // control characters (U+0000 through U+001F). There are two-character sequence // escape representations of some popular characters: // \", \\, \b, \f, \n, \r, \t. -SIMDJSON_CONSTEXPR_LAMBDA void escape_json_char(char c, char *&out) { +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline void escape_json_char(char c, char *&out) { if (c == '"') { memcpy(out, "\\\"", 2); out += 2; @@ -43283,14 +49115,20 @@ SIMDJSON_CONSTEXPR_LAMBDA void escape_json_char(char c, char *&out) { } } +// Writes the escaped version of input to out, returning the number of bytes +// written. Uses SIMD position finding to locate quotable characters efficiently. inline size_t write_string_escaped(const std::string_view input, char *out) { size_t mysize = input.size(); - if (!fast_needs_escaping(input)) { // fast path! + + // Use SIMD position finder directly - it returns mysize if no escape needed + size_t location = find_next_json_quotable_character(input, 0); + if (location == mysize) { + // Fast path: no escaping needed memcpy(out, input.data(), input.size()); return input.size(); } + const char *const initout = out; - size_t location = find_next_json_quotable_character(input, 0); memcpy(out, input.data(), location); out += location; escape_json_char(input[location], out); @@ -43489,12 +49327,29 @@ simdjson_inline void string_builder::append(number_type v) noexcept { } } else SIMDJSON_IF_CONSTEXPR(std::is_unsigned::value) { + // Process 4 digits at a time instead of 2, reducing store operations + // and divisions by approximately half for large numbers. constexpr size_t max_number_size = 20; if (capacity_check(max_number_size)) { using unsigned_type = typename std::make_unsigned::type; unsigned_type pv = static_cast(v); size_t dc = internal::digit_count(pv); char *write_pointer = buffer.get() + position + dc - 1; + + // Process 4 digits per iteration for large numbers + while (pv >= 10000) { + unsigned_type q = pv / 10000; + unsigned_type r = pv % 10000; + unsigned_type r_hi = r / 100; // High 2 digits of remainder + unsigned_type r_lo = r % 100; // Low 2 digits of remainder + // Write low 2 digits first (rightmost), then high 2 digits + memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2); + memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2); + write_pointer -= 4; + pv = q; + } + + // Handle remaining 1-4 digits with original 2-digit loop while (pv >= 100) { memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2); write_pointer -= 2; @@ -43509,6 +49364,7 @@ simdjson_inline void string_builder::append(number_type v) noexcept { } } else SIMDJSON_IF_CONSTEXPR(std::is_integral::value) { + // Same 4-digit batching as unsigned path for signed integers constexpr size_t max_number_size = 20; if (capacity_check(max_number_size)) { using unsigned_type = typename std::make_unsigned::type; @@ -43522,6 +49378,20 @@ simdjson_inline void string_builder::append(number_type v) noexcept { buffer.get()[position] = '-'; position += negative ? 1 : 0; char *write_pointer = buffer.get() + position + dc - 1; + + // Process 4 digits per iteration for large numbers + while (pv >= 10000) { + unsigned_type q = pv / 10000; + unsigned_type r = pv % 10000; + unsigned_type r_hi = r / 100; + unsigned_type r_lo = r % 100; + memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2); + memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2); + write_pointer -= 4; + pv = q; + } + + // Handle remaining 1-4 digits while (pv >= 100) { memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2); write_pointer -= 2; @@ -44409,6 +50279,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, "Westmere kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -44837,6 +50708,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, "Westmere kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -45268,7 +51140,7 @@ simdjson_warn_unused simdjson_result to_json(const Z &z, size_t ini return std::string(s); } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = simdjson::westmere::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = simdjson::westmere::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { simdjson::westmere::builder::string_builder b(initial_capacity); b.append(z); std::string_view sv; @@ -45565,7 +51437,7 @@ simdjson_warn_unused simdjson_result to_json_string(const Z &z, siz } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { string_builder b(initial_capacity); append(b, z); std::string_view view; @@ -45642,7 +51514,7 @@ simdjson_warn_unused simdjson_result to_json(const Z &z, size_t ini return std::string(s); } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = westmere::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = westmere::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { westmere::builder::string_builder b(initial_capacity); westmere::builder::append(b, z); std::string_view view; @@ -45667,6 +51539,126 @@ simdjson_warn_unused simdjson_result extract_from(const T &obj, siz #endif /* end file simdjson/generic/builder/json_builder.h for westmere */ +/* including simdjson/generic/builder/fractured_json_builder.h for westmere: #include "simdjson/generic/builder/fractured_json_builder.h" */ +/* begin file simdjson/generic/builder/fractured_json_builder.h for westmere */ +#ifndef SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H +#define SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/builder/json_builder.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/dom/fractured_json.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#if SIMDJSON_STATIC_REFLECTION + +namespace simdjson { +namespace westmere { +namespace builder { + +/** + * Serialize an object to a FracturedJson-formatted string. + * + * FracturedJson produces human-readable yet compact JSON output by intelligently + * choosing between different layout strategies (inline, compact multiline, table, + * expanded) based on content complexity, length, and structure similarity. + * + * This function combines the builder's serialization with FracturedJson formatting: + * 1. Serializes the object to minified JSON using reflection + * 2. Parses and reformats using FracturedJson + * + * Example: + * struct User { int id; std::string name; bool active; }; + * User user{1, "Alice", true}; + * auto result = to_fractured_json_string(user); + * // result.value() == "{ \"id\": 1, \"name\": \"Alice\", \"active\": true }" + * + * @param obj The object to serialize (must be a reflectable type) + * @param opts FracturedJson formatting options + * @param initial_capacity Initial buffer capacity for serialization + * @return The formatted JSON string, or an error + */ +template +simdjson_warn_unused simdjson_result to_fractured_json_string( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + // Step 1: Serialize to minified JSON + std::string formatted; + auto error = to_json_string(obj, initial_capacity).get(formatted); + if (error) { + return error; + } + + // Step 2: Reformat with FracturedJson + return fractured_json_string(formatted, opts); +} + +/** + * Extract specific fields from an object and format with FracturedJson. + * + * Example: + * struct User { int id; std::string name; std::string email; bool active; }; + * User user{1, "Alice", "alice@example.com", true}; + * auto result = extract_fractured_json<"id", "name">(user); + * // result.value() == "{ \"id\": 1, \"name\": \"Alice\" }" + * + * @param obj The object to serialize + * @param opts FracturedJson formatting options + * @param initial_capacity Initial buffer capacity for serialization + * @return The formatted JSON string containing only the specified fields + */ +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_result extract_fractured_json( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + // Step 1: Extract fields to minified JSON + std::string formatted; + auto error = extract_from(obj, initial_capacity).get(formatted); + if (error) { + return error; + } + + // Step 2: Reformat with FracturedJson + return fractured_json_string(formatted, opts); +} + +} // namespace builder +} // namespace westmere + +// Global namespace convenience functions + +/** + * Serialize an object to a FracturedJson-formatted string. + * Global namespace version for convenience. + */ +template +simdjson_warn_unused simdjson_result to_fractured_json_string( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = westmere::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + return westmere::builder::to_fractured_json_string(obj, opts, initial_capacity); +} +/** + * Extract specific fields from an object and format with FracturedJson. + * Global namespace version for convenience. + */ +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_result extract_fractured_json( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = westmere::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + return westmere::builder::extract_fractured_json(obj, opts, initial_capacity); +} + +} // namespace simdjson + +#endif // SIMDJSON_STATIC_REFLECTION + +#endif // SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H +/* end file simdjson/generic/builder/fractured_json_builder.h for westmere */ @@ -45704,9 +51696,15 @@ simdjson_warn_unused simdjson_result extract_from(const T &obj, siz #endif #if SIMDJSON_EXPERIMENTAL_HAS_NEON #include +#ifdef _MSC_VER +#include +#endif #endif #if SIMDJSON_EXPERIMENTAL_HAS_SSE2 #include +#ifdef _MSC_VER +#include +#endif #endif namespace simdjson { @@ -45814,10 +51812,10 @@ simdjson_inline bool fast_needs_escaping(std::string_view view) { } #endif -SIMDJSON_CONSTEXPR_LAMBDA inline size_t -find_next_json_quotable_character(const std::string_view view, - size_t location) noexcept { - +// Scalar fallback for finding next quotable character +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline size_t +find_next_json_quotable_character_scalar(const std::string_view view, + size_t location) noexcept { for (auto pos = view.begin() + location; pos != view.end(); ++pos) { if (json_quotable_character[static_cast(*pos)]) { return pos - view.begin(); @@ -45826,6 +51824,114 @@ find_next_json_quotable_character(const std::string_view view, return size_t(view.size()); } +// SIMD-accelerated position finding that directly locates the first quotable +// character, combining detection and position extraction in a single pass to +// minimize redundant work. +#if SIMDJSON_EXPERIMENTAL_HAS_NEON +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants for characters requiring escape + uint8x16_t v34 = vdupq_n_u8(34); // '"' + uint8x16_t v92 = vdupq_n_u8(92); // '\\' + uint8x16_t v32 = vdupq_n_u8(32); // control char threshold + + while (remaining >= 16) { + uint8x16_t word = vld1q_u8(ptr); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + uint8x16_t needs_escape = vceqq_u8(word, v34); + needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92)); + needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32)); + + if (vmaxvq_u32(vreinterpretq_u32_u8(needs_escape)) != 0) { + // Found quotable character - extract exact byte position using ctz + uint64x2_t as64 = vreinterpretq_u64_u8(needs_escape); + uint64_t lo = vgetq_lane_u64(as64, 0); + uint64_t hi = vgetq_lane_u64(as64, 1); + size_t offset = ptr - reinterpret_cast(view.data()); +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + if (lo != 0) { + _BitScanForward64(&trailing_zero, lo); + return offset + trailing_zero / 8; + } else { + _BitScanForward64(&trailing_zero, hi); + return offset + 8 + trailing_zero / 8; + } +#else + if (lo != 0) { + return offset + __builtin_ctzll(lo) / 8; + } else { + return offset + 8 + __builtin_ctzll(hi) / 8; + } +#endif + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_SSE2 +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants + __m128i v34 = _mm_set1_epi8(34); // '"' + __m128i v92 = _mm_set1_epi8(92); // '\\' + __m128i v31 = _mm_set1_epi8(31); // for control char detection + + while (remaining >= 16) { + __m128i word = _mm_loadu_si128(reinterpret_cast(ptr)); + + // Check for quotable characters + __m128i needs_escape = _mm_cmpeq_epi8(word, v34); + needs_escape = _mm_or_si128(needs_escape, _mm_cmpeq_epi8(word, v92)); + needs_escape = _mm_or_si128( + needs_escape, + _mm_cmpeq_epi8(_mm_subs_epu8(word, v31), _mm_setzero_si128())); + + int mask = _mm_movemask_epi8(needs_escape); + if (mask != 0) { + // Found quotable character - use trailing zero count to find position + size_t offset = ptr - reinterpret_cast(view.data()); +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + _BitScanForward(&trailing_zero, mask); + return offset + trailing_zero; +#else + return offset + __builtin_ctz(mask); +#endif + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#else +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + return find_next_json_quotable_character_scalar(view, location); +} +#endif + SIMDJSON_CONSTEXPR_LAMBDA static std::string_view control_chars[] = { "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", @@ -45838,7 +51944,7 @@ SIMDJSON_CONSTEXPR_LAMBDA static std::string_view control_chars[] = { // control characters (U+0000 through U+001F). There are two-character sequence // escape representations of some popular characters: // \", \\, \b, \f, \n, \r, \t. -SIMDJSON_CONSTEXPR_LAMBDA void escape_json_char(char c, char *&out) { +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline void escape_json_char(char c, char *&out) { if (c == '"') { memcpy(out, "\\\"", 2); out += 2; @@ -45852,14 +51958,20 @@ SIMDJSON_CONSTEXPR_LAMBDA void escape_json_char(char c, char *&out) { } } +// Writes the escaped version of input to out, returning the number of bytes +// written. Uses SIMD position finding to locate quotable characters efficiently. inline size_t write_string_escaped(const std::string_view input, char *out) { size_t mysize = input.size(); - if (!fast_needs_escaping(input)) { // fast path! + + // Use SIMD position finder directly - it returns mysize if no escape needed + size_t location = find_next_json_quotable_character(input, 0); + if (location == mysize) { + // Fast path: no escaping needed memcpy(out, input.data(), input.size()); return input.size(); } + const char *const initout = out; - size_t location = find_next_json_quotable_character(input, 0); memcpy(out, input.data(), location); out += location; escape_json_char(input[location], out); @@ -46058,12 +52170,29 @@ simdjson_inline void string_builder::append(number_type v) noexcept { } } else SIMDJSON_IF_CONSTEXPR(std::is_unsigned::value) { + // Process 4 digits at a time instead of 2, reducing store operations + // and divisions by approximately half for large numbers. constexpr size_t max_number_size = 20; if (capacity_check(max_number_size)) { using unsigned_type = typename std::make_unsigned::type; unsigned_type pv = static_cast(v); size_t dc = internal::digit_count(pv); char *write_pointer = buffer.get() + position + dc - 1; + + // Process 4 digits per iteration for large numbers + while (pv >= 10000) { + unsigned_type q = pv / 10000; + unsigned_type r = pv % 10000; + unsigned_type r_hi = r / 100; // High 2 digits of remainder + unsigned_type r_lo = r % 100; // Low 2 digits of remainder + // Write low 2 digits first (rightmost), then high 2 digits + memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2); + memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2); + write_pointer -= 4; + pv = q; + } + + // Handle remaining 1-4 digits with original 2-digit loop while (pv >= 100) { memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2); write_pointer -= 2; @@ -46078,6 +52207,7 @@ simdjson_inline void string_builder::append(number_type v) noexcept { } } else SIMDJSON_IF_CONSTEXPR(std::is_integral::value) { + // Same 4-digit batching as unsigned path for signed integers constexpr size_t max_number_size = 20; if (capacity_check(max_number_size)) { using unsigned_type = typename std::make_unsigned::type; @@ -46091,6 +52221,20 @@ simdjson_inline void string_builder::append(number_type v) noexcept { buffer.get()[position] = '-'; position += negative ? 1 : 0; char *write_pointer = buffer.get() + position + dc - 1; + + // Process 4 digits per iteration for large numbers + while (pv >= 10000) { + unsigned_type q = pv / 10000; + unsigned_type r = pv % 10000; + unsigned_type r_hi = r / 100; + unsigned_type r_lo = r % 100; + memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2); + memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2); + write_pointer -= 4; + pv = q; + } + + // Handle remaining 1-4 digits while (pv >= 100) { memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2); write_pointer -= 2; @@ -46845,6 +52989,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, "LSX kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -47312,7 +53457,7 @@ simdjson_warn_unused simdjson_result to_json(const Z &z, size_t ini return std::string(s); } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = simdjson::lsx::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = simdjson::lsx::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { simdjson::lsx::builder::string_builder b(initial_capacity); b.append(z); std::string_view sv; @@ -47609,7 +53754,7 @@ simdjson_warn_unused simdjson_result to_json_string(const Z &z, siz } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { string_builder b(initial_capacity); append(b, z); std::string_view view; @@ -47686,7 +53831,7 @@ simdjson_warn_unused simdjson_result to_json(const Z &z, size_t ini return std::string(s); } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = lsx::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = lsx::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { lsx::builder::string_builder b(initial_capacity); lsx::builder::append(b, z); std::string_view view; @@ -47711,6 +53856,126 @@ simdjson_warn_unused simdjson_result extract_from(const T &obj, siz #endif /* end file simdjson/generic/builder/json_builder.h for lsx */ +/* including simdjson/generic/builder/fractured_json_builder.h for lsx: #include "simdjson/generic/builder/fractured_json_builder.h" */ +/* begin file simdjson/generic/builder/fractured_json_builder.h for lsx */ +#ifndef SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H +#define SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/builder/json_builder.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/dom/fractured_json.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#if SIMDJSON_STATIC_REFLECTION + +namespace simdjson { +namespace lsx { +namespace builder { + +/** + * Serialize an object to a FracturedJson-formatted string. + * + * FracturedJson produces human-readable yet compact JSON output by intelligently + * choosing between different layout strategies (inline, compact multiline, table, + * expanded) based on content complexity, length, and structure similarity. + * + * This function combines the builder's serialization with FracturedJson formatting: + * 1. Serializes the object to minified JSON using reflection + * 2. Parses and reformats using FracturedJson + * + * Example: + * struct User { int id; std::string name; bool active; }; + * User user{1, "Alice", true}; + * auto result = to_fractured_json_string(user); + * // result.value() == "{ \"id\": 1, \"name\": \"Alice\", \"active\": true }" + * + * @param obj The object to serialize (must be a reflectable type) + * @param opts FracturedJson formatting options + * @param initial_capacity Initial buffer capacity for serialization + * @return The formatted JSON string, or an error + */ +template +simdjson_warn_unused simdjson_result to_fractured_json_string( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + // Step 1: Serialize to minified JSON + std::string formatted; + auto error = to_json_string(obj, initial_capacity).get(formatted); + if (error) { + return error; + } + + // Step 2: Reformat with FracturedJson + return fractured_json_string(formatted, opts); +} + +/** + * Extract specific fields from an object and format with FracturedJson. + * + * Example: + * struct User { int id; std::string name; std::string email; bool active; }; + * User user{1, "Alice", "alice@example.com", true}; + * auto result = extract_fractured_json<"id", "name">(user); + * // result.value() == "{ \"id\": 1, \"name\": \"Alice\" }" + * + * @param obj The object to serialize + * @param opts FracturedJson formatting options + * @param initial_capacity Initial buffer capacity for serialization + * @return The formatted JSON string containing only the specified fields + */ +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_result extract_fractured_json( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + // Step 1: Extract fields to minified JSON + std::string formatted; + auto error = extract_from(obj, initial_capacity).get(formatted); + if (error) { + return error; + } + + // Step 2: Reformat with FracturedJson + return fractured_json_string(formatted, opts); +} + +} // namespace builder +} // namespace lsx + +// Global namespace convenience functions + +/** + * Serialize an object to a FracturedJson-formatted string. + * Global namespace version for convenience. + */ +template +simdjson_warn_unused simdjson_result to_fractured_json_string( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = lsx::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + return lsx::builder::to_fractured_json_string(obj, opts, initial_capacity); +} +/** + * Extract specific fields from an object and format with FracturedJson. + * Global namespace version for convenience. + */ +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_result extract_fractured_json( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = lsx::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + return lsx::builder::extract_fractured_json(obj, opts, initial_capacity); +} + +} // namespace simdjson + +#endif // SIMDJSON_STATIC_REFLECTION + +#endif // SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H +/* end file simdjson/generic/builder/fractured_json_builder.h for lsx */ @@ -47748,9 +54013,15 @@ simdjson_warn_unused simdjson_result extract_from(const T &obj, siz #endif #if SIMDJSON_EXPERIMENTAL_HAS_NEON #include +#ifdef _MSC_VER +#include +#endif #endif #if SIMDJSON_EXPERIMENTAL_HAS_SSE2 #include +#ifdef _MSC_VER +#include +#endif #endif namespace simdjson { @@ -47858,10 +54129,10 @@ simdjson_inline bool fast_needs_escaping(std::string_view view) { } #endif -SIMDJSON_CONSTEXPR_LAMBDA inline size_t -find_next_json_quotable_character(const std::string_view view, - size_t location) noexcept { - +// Scalar fallback for finding next quotable character +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline size_t +find_next_json_quotable_character_scalar(const std::string_view view, + size_t location) noexcept { for (auto pos = view.begin() + location; pos != view.end(); ++pos) { if (json_quotable_character[static_cast(*pos)]) { return pos - view.begin(); @@ -47870,6 +54141,114 @@ find_next_json_quotable_character(const std::string_view view, return size_t(view.size()); } +// SIMD-accelerated position finding that directly locates the first quotable +// character, combining detection and position extraction in a single pass to +// minimize redundant work. +#if SIMDJSON_EXPERIMENTAL_HAS_NEON +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants for characters requiring escape + uint8x16_t v34 = vdupq_n_u8(34); // '"' + uint8x16_t v92 = vdupq_n_u8(92); // '\\' + uint8x16_t v32 = vdupq_n_u8(32); // control char threshold + + while (remaining >= 16) { + uint8x16_t word = vld1q_u8(ptr); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + uint8x16_t needs_escape = vceqq_u8(word, v34); + needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92)); + needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32)); + + if (vmaxvq_u32(vreinterpretq_u32_u8(needs_escape)) != 0) { + // Found quotable character - extract exact byte position using ctz + uint64x2_t as64 = vreinterpretq_u64_u8(needs_escape); + uint64_t lo = vgetq_lane_u64(as64, 0); + uint64_t hi = vgetq_lane_u64(as64, 1); + size_t offset = ptr - reinterpret_cast(view.data()); +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + if (lo != 0) { + _BitScanForward64(&trailing_zero, lo); + return offset + trailing_zero / 8; + } else { + _BitScanForward64(&trailing_zero, hi); + return offset + 8 + trailing_zero / 8; + } +#else + if (lo != 0) { + return offset + __builtin_ctzll(lo) / 8; + } else { + return offset + 8 + __builtin_ctzll(hi) / 8; + } +#endif + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_SSE2 +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants + __m128i v34 = _mm_set1_epi8(34); // '"' + __m128i v92 = _mm_set1_epi8(92); // '\\' + __m128i v31 = _mm_set1_epi8(31); // for control char detection + + while (remaining >= 16) { + __m128i word = _mm_loadu_si128(reinterpret_cast(ptr)); + + // Check for quotable characters + __m128i needs_escape = _mm_cmpeq_epi8(word, v34); + needs_escape = _mm_or_si128(needs_escape, _mm_cmpeq_epi8(word, v92)); + needs_escape = _mm_or_si128( + needs_escape, + _mm_cmpeq_epi8(_mm_subs_epu8(word, v31), _mm_setzero_si128())); + + int mask = _mm_movemask_epi8(needs_escape); + if (mask != 0) { + // Found quotable character - use trailing zero count to find position + size_t offset = ptr - reinterpret_cast(view.data()); +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + _BitScanForward(&trailing_zero, mask); + return offset + trailing_zero; +#else + return offset + __builtin_ctz(mask); +#endif + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#else +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + return find_next_json_quotable_character_scalar(view, location); +} +#endif + SIMDJSON_CONSTEXPR_LAMBDA static std::string_view control_chars[] = { "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", @@ -47882,7 +54261,7 @@ SIMDJSON_CONSTEXPR_LAMBDA static std::string_view control_chars[] = { // control characters (U+0000 through U+001F). There are two-character sequence // escape representations of some popular characters: // \", \\, \b, \f, \n, \r, \t. -SIMDJSON_CONSTEXPR_LAMBDA void escape_json_char(char c, char *&out) { +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline void escape_json_char(char c, char *&out) { if (c == '"') { memcpy(out, "\\\"", 2); out += 2; @@ -47896,14 +54275,20 @@ SIMDJSON_CONSTEXPR_LAMBDA void escape_json_char(char c, char *&out) { } } +// Writes the escaped version of input to out, returning the number of bytes +// written. Uses SIMD position finding to locate quotable characters efficiently. inline size_t write_string_escaped(const std::string_view input, char *out) { size_t mysize = input.size(); - if (!fast_needs_escaping(input)) { // fast path! + + // Use SIMD position finder directly - it returns mysize if no escape needed + size_t location = find_next_json_quotable_character(input, 0); + if (location == mysize) { + // Fast path: no escaping needed memcpy(out, input.data(), input.size()); return input.size(); } + const char *const initout = out; - size_t location = find_next_json_quotable_character(input, 0); memcpy(out, input.data(), location); out += location; escape_json_char(input[location], out); @@ -48102,12 +54487,29 @@ simdjson_inline void string_builder::append(number_type v) noexcept { } } else SIMDJSON_IF_CONSTEXPR(std::is_unsigned::value) { + // Process 4 digits at a time instead of 2, reducing store operations + // and divisions by approximately half for large numbers. constexpr size_t max_number_size = 20; if (capacity_check(max_number_size)) { using unsigned_type = typename std::make_unsigned::type; unsigned_type pv = static_cast(v); size_t dc = internal::digit_count(pv); char *write_pointer = buffer.get() + position + dc - 1; + + // Process 4 digits per iteration for large numbers + while (pv >= 10000) { + unsigned_type q = pv / 10000; + unsigned_type r = pv % 10000; + unsigned_type r_hi = r / 100; // High 2 digits of remainder + unsigned_type r_lo = r % 100; // Low 2 digits of remainder + // Write low 2 digits first (rightmost), then high 2 digits + memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2); + memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2); + write_pointer -= 4; + pv = q; + } + + // Handle remaining 1-4 digits with original 2-digit loop while (pv >= 100) { memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2); write_pointer -= 2; @@ -48122,6 +54524,7 @@ simdjson_inline void string_builder::append(number_type v) noexcept { } } else SIMDJSON_IF_CONSTEXPR(std::is_integral::value) { + // Same 4-digit batching as unsigned path for signed integers constexpr size_t max_number_size = 20; if (capacity_check(max_number_size)) { using unsigned_type = typename std::make_unsigned::type; @@ -48135,6 +54538,20 @@ simdjson_inline void string_builder::append(number_type v) noexcept { buffer.get()[position] = '-'; position += negative ? 1 : 0; char *write_pointer = buffer.get() + position + dc - 1; + + // Process 4 digits per iteration for large numbers + while (pv >= 10000) { + unsigned_type q = pv / 10000; + unsigned_type r = pv % 10000; + unsigned_type r_hi = r / 100; + unsigned_type r_lo = r % 100; + memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2); + memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2); + write_pointer -= 4; + pv = q; + } + + // Handle remaining 1-4 digits while (pv >= 100) { memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2); write_pointer -= 2; @@ -48937,6 +55354,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 2, "LASX kernel should use two registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -49379,7 +55797,7 @@ simdjson_warn_unused simdjson_result to_json(const Z &z, size_t ini return std::string(s); } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = simdjson::lasx::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = simdjson::lasx::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { simdjson::lasx::builder::string_builder b(initial_capacity); b.append(z); std::string_view sv; @@ -49676,7 +56094,7 @@ simdjson_warn_unused simdjson_result to_json_string(const Z &z, siz } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { string_builder b(initial_capacity); append(b, z); std::string_view view; @@ -49753,7 +56171,7 @@ simdjson_warn_unused simdjson_result to_json(const Z &z, size_t ini return std::string(s); } template -simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = lasx::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = lasx::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { lasx::builder::string_builder b(initial_capacity); lasx::builder::append(b, z); std::string_view view; @@ -49778,6 +56196,126 @@ simdjson_warn_unused simdjson_result extract_from(const T &obj, siz #endif /* end file simdjson/generic/builder/json_builder.h for lasx */ +/* including simdjson/generic/builder/fractured_json_builder.h for lasx: #include "simdjson/generic/builder/fractured_json_builder.h" */ +/* begin file simdjson/generic/builder/fractured_json_builder.h for lasx */ +#ifndef SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H +#define SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/builder/json_builder.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/dom/fractured_json.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#if SIMDJSON_STATIC_REFLECTION + +namespace simdjson { +namespace lasx { +namespace builder { + +/** + * Serialize an object to a FracturedJson-formatted string. + * + * FracturedJson produces human-readable yet compact JSON output by intelligently + * choosing between different layout strategies (inline, compact multiline, table, + * expanded) based on content complexity, length, and structure similarity. + * + * This function combines the builder's serialization with FracturedJson formatting: + * 1. Serializes the object to minified JSON using reflection + * 2. Parses and reformats using FracturedJson + * + * Example: + * struct User { int id; std::string name; bool active; }; + * User user{1, "Alice", true}; + * auto result = to_fractured_json_string(user); + * // result.value() == "{ \"id\": 1, \"name\": \"Alice\", \"active\": true }" + * + * @param obj The object to serialize (must be a reflectable type) + * @param opts FracturedJson formatting options + * @param initial_capacity Initial buffer capacity for serialization + * @return The formatted JSON string, or an error + */ +template +simdjson_warn_unused simdjson_result to_fractured_json_string( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + // Step 1: Serialize to minified JSON + std::string formatted; + auto error = to_json_string(obj, initial_capacity).get(formatted); + if (error) { + return error; + } + + // Step 2: Reformat with FracturedJson + return fractured_json_string(formatted, opts); +} + +/** + * Extract specific fields from an object and format with FracturedJson. + * + * Example: + * struct User { int id; std::string name; std::string email; bool active; }; + * User user{1, "Alice", "alice@example.com", true}; + * auto result = extract_fractured_json<"id", "name">(user); + * // result.value() == "{ \"id\": 1, \"name\": \"Alice\" }" + * + * @param obj The object to serialize + * @param opts FracturedJson formatting options + * @param initial_capacity Initial buffer capacity for serialization + * @return The formatted JSON string containing only the specified fields + */ +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_result extract_fractured_json( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + // Step 1: Extract fields to minified JSON + std::string formatted; + auto error = extract_from(obj, initial_capacity).get(formatted); + if (error) { + return error; + } + + // Step 2: Reformat with FracturedJson + return fractured_json_string(formatted, opts); +} + +} // namespace builder +} // namespace lasx + +// Global namespace convenience functions + +/** + * Serialize an object to a FracturedJson-formatted string. + * Global namespace version for convenience. + */ +template +simdjson_warn_unused simdjson_result to_fractured_json_string( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = lasx::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + return lasx::builder::to_fractured_json_string(obj, opts, initial_capacity); +} +/** + * Extract specific fields from an object and format with FracturedJson. + * Global namespace version for convenience. + */ +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_result extract_fractured_json( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = lasx::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + return lasx::builder::extract_fractured_json(obj, opts, initial_capacity); +} + +} // namespace simdjson + +#endif // SIMDJSON_STATIC_REFLECTION + +#endif // SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H +/* end file simdjson/generic/builder/fractured_json_builder.h for lasx */ @@ -49815,9 +56353,15 @@ simdjson_warn_unused simdjson_result extract_from(const T &obj, siz #endif #if SIMDJSON_EXPERIMENTAL_HAS_NEON #include +#ifdef _MSC_VER +#include +#endif #endif #if SIMDJSON_EXPERIMENTAL_HAS_SSE2 #include +#ifdef _MSC_VER +#include +#endif #endif namespace simdjson { @@ -49925,10 +56469,10 @@ simdjson_inline bool fast_needs_escaping(std::string_view view) { } #endif -SIMDJSON_CONSTEXPR_LAMBDA inline size_t -find_next_json_quotable_character(const std::string_view view, - size_t location) noexcept { - +// Scalar fallback for finding next quotable character +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline size_t +find_next_json_quotable_character_scalar(const std::string_view view, + size_t location) noexcept { for (auto pos = view.begin() + location; pos != view.end(); ++pos) { if (json_quotable_character[static_cast(*pos)]) { return pos - view.begin(); @@ -49937,6 +56481,114 @@ find_next_json_quotable_character(const std::string_view view, return size_t(view.size()); } +// SIMD-accelerated position finding that directly locates the first quotable +// character, combining detection and position extraction in a single pass to +// minimize redundant work. +#if SIMDJSON_EXPERIMENTAL_HAS_NEON +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants for characters requiring escape + uint8x16_t v34 = vdupq_n_u8(34); // '"' + uint8x16_t v92 = vdupq_n_u8(92); // '\\' + uint8x16_t v32 = vdupq_n_u8(32); // control char threshold + + while (remaining >= 16) { + uint8x16_t word = vld1q_u8(ptr); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + uint8x16_t needs_escape = vceqq_u8(word, v34); + needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92)); + needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32)); + + if (vmaxvq_u32(vreinterpretq_u32_u8(needs_escape)) != 0) { + // Found quotable character - extract exact byte position using ctz + uint64x2_t as64 = vreinterpretq_u64_u8(needs_escape); + uint64_t lo = vgetq_lane_u64(as64, 0); + uint64_t hi = vgetq_lane_u64(as64, 1); + size_t offset = ptr - reinterpret_cast(view.data()); +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + if (lo != 0) { + _BitScanForward64(&trailing_zero, lo); + return offset + trailing_zero / 8; + } else { + _BitScanForward64(&trailing_zero, hi); + return offset + 8 + trailing_zero / 8; + } +#else + if (lo != 0) { + return offset + __builtin_ctzll(lo) / 8; + } else { + return offset + 8 + __builtin_ctzll(hi) / 8; + } +#endif + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_SSE2 +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants + __m128i v34 = _mm_set1_epi8(34); // '"' + __m128i v92 = _mm_set1_epi8(92); // '\\' + __m128i v31 = _mm_set1_epi8(31); // for control char detection + + while (remaining >= 16) { + __m128i word = _mm_loadu_si128(reinterpret_cast(ptr)); + + // Check for quotable characters + __m128i needs_escape = _mm_cmpeq_epi8(word, v34); + needs_escape = _mm_or_si128(needs_escape, _mm_cmpeq_epi8(word, v92)); + needs_escape = _mm_or_si128( + needs_escape, + _mm_cmpeq_epi8(_mm_subs_epu8(word, v31), _mm_setzero_si128())); + + int mask = _mm_movemask_epi8(needs_escape); + if (mask != 0) { + // Found quotable character - use trailing zero count to find position + size_t offset = ptr - reinterpret_cast(view.data()); +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + _BitScanForward(&trailing_zero, mask); + return offset + trailing_zero; +#else + return offset + __builtin_ctz(mask); +#endif + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#else +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + return find_next_json_quotable_character_scalar(view, location); +} +#endif + SIMDJSON_CONSTEXPR_LAMBDA static std::string_view control_chars[] = { "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", @@ -49949,7 +56601,7 @@ SIMDJSON_CONSTEXPR_LAMBDA static std::string_view control_chars[] = { // control characters (U+0000 through U+001F). There are two-character sequence // escape representations of some popular characters: // \", \\, \b, \f, \n, \r, \t. -SIMDJSON_CONSTEXPR_LAMBDA void escape_json_char(char c, char *&out) { +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline void escape_json_char(char c, char *&out) { if (c == '"') { memcpy(out, "\\\"", 2); out += 2; @@ -49963,14 +56615,20 @@ SIMDJSON_CONSTEXPR_LAMBDA void escape_json_char(char c, char *&out) { } } +// Writes the escaped version of input to out, returning the number of bytes +// written. Uses SIMD position finding to locate quotable characters efficiently. inline size_t write_string_escaped(const std::string_view input, char *out) { size_t mysize = input.size(); - if (!fast_needs_escaping(input)) { // fast path! + + // Use SIMD position finder directly - it returns mysize if no escape needed + size_t location = find_next_json_quotable_character(input, 0); + if (location == mysize) { + // Fast path: no escaping needed memcpy(out, input.data(), input.size()); return input.size(); } + const char *const initout = out; - size_t location = find_next_json_quotable_character(input, 0); memcpy(out, input.data(), location); out += location; escape_json_char(input[location], out); @@ -50169,12 +56827,29 @@ simdjson_inline void string_builder::append(number_type v) noexcept { } } else SIMDJSON_IF_CONSTEXPR(std::is_unsigned::value) { + // Process 4 digits at a time instead of 2, reducing store operations + // and divisions by approximately half for large numbers. constexpr size_t max_number_size = 20; if (capacity_check(max_number_size)) { using unsigned_type = typename std::make_unsigned::type; unsigned_type pv = static_cast(v); size_t dc = internal::digit_count(pv); char *write_pointer = buffer.get() + position + dc - 1; + + // Process 4 digits per iteration for large numbers + while (pv >= 10000) { + unsigned_type q = pv / 10000; + unsigned_type r = pv % 10000; + unsigned_type r_hi = r / 100; // High 2 digits of remainder + unsigned_type r_lo = r % 100; // Low 2 digits of remainder + // Write low 2 digits first (rightmost), then high 2 digits + memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2); + memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2); + write_pointer -= 4; + pv = q; + } + + // Handle remaining 1-4 digits with original 2-digit loop while (pv >= 100) { memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2); write_pointer -= 2; @@ -50189,6 +56864,7 @@ simdjson_inline void string_builder::append(number_type v) noexcept { } } else SIMDJSON_IF_CONSTEXPR(std::is_integral::value) { + // Same 4-digit batching as unsigned path for signed integers constexpr size_t max_number_size = 20; if (capacity_check(max_number_size)) { using unsigned_type = typename std::make_unsigned::type; @@ -50202,6 +56878,20 @@ simdjson_inline void string_builder::append(number_type v) noexcept { buffer.get()[position] = '-'; position += negative ? 1 : 0; char *write_pointer = buffer.get() + position + dc - 1; + + // Process 4 digits per iteration for large numbers + while (pv >= 10000) { + unsigned_type q = pv / 10000; + unsigned_type r = pv % 10000; + unsigned_type r_hi = r / 100; + unsigned_type r_lo = r % 100; + memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2); + memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2); + write_pointer -= 4; + pv = q; + } + + // Handle remaining 1-4 digits while (pv >= 100) { memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2); write_pointer -= 2; @@ -50505,6 +57195,2342 @@ SIMDJSON_UNTARGET_REGION #endif // SIMDJSON_LASX_BUILDER_H /* end file simdjson/lasx/builder.h */ +#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(rvv_vls) +/* including simdjson/rvv-vls/builder.h: #include "simdjson/rvv-vls/builder.h" */ +/* begin file simdjson/rvv-vls/builder.h */ +#ifndef SIMDJSON_RVV_VLS_BUILDER_H +#define SIMDJSON_RVV_VLS_BUILDER_H + +/* including simdjson/rvv-vls/begin.h: #include "simdjson/rvv-vls/begin.h" */ +/* begin file simdjson/rvv-vls/begin.h */ +/* defining SIMDJSON_IMPLEMENTATION to "rvv_vls" */ +#define SIMDJSON_IMPLEMENTATION rvv_vls +/* including simdjson/rvv-vls/base.h: #include "simdjson/rvv-vls/base.h" */ +/* begin file simdjson/rvv-vls/base.h */ +#ifndef SIMDJSON_RVV_VLS_BASE_H +#define SIMDJSON_RVV_VLS_BASE_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +/** + * RVV-VLS implementation. + */ +namespace rvv_vls { + +class implementation; + +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_BASE_H +/* end file simdjson/rvv-vls/base.h */ +/* including simdjson/rvv-vls/intrinsics.h: #include "simdjson/rvv-vls/intrinsics.h" */ +/* begin file simdjson/rvv-vls/intrinsics.h */ +#ifndef SIMDJSON_RVV_VLS_INTRINSICS_H +#define SIMDJSON_RVV_VLS_INTRINSICS_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include + +#define simdutf_vrgather_u8m1x2(tbl, idx) \ + __riscv_vcreate_v_u8m1_u8m2( \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m2_u8m1(idx, 0), \ + __riscv_vsetvlmax_e8m1()), \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m2_u8m1(idx, 1), \ + __riscv_vsetvlmax_e8m1())) + +#define simdutf_vrgather_u8m1x4(tbl, idx) \ + __riscv_vcreate_v_u8m1_u8m4( \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 0), \ + __riscv_vsetvlmax_e8m1()), \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 1), \ + __riscv_vsetvlmax_e8m1()), \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 2), \ + __riscv_vsetvlmax_e8m1()), \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 3), \ + __riscv_vsetvlmax_e8m1())) + +#if __riscv_zbc +#include +#endif + +#endif // SIMDJSON_RVV_VLS_INTRINSICS_H +/* end file simdjson/rvv-vls/intrinsics.h */ +/* including simdjson/rvv-vls/bitmanipulation.h: #include "simdjson/rvv-vls/bitmanipulation.h" */ +/* begin file simdjson/rvv-vls/bitmanipulation.h */ +#ifndef SIMDJSON_RVV_VLS_BITMANIPULATION_H +#define SIMDJSON_RVV_VLS_BITMANIPULATION_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { + +// We sometimes call trailing_zero on inputs that are zero, +// but the algorithms do not end up using the returned value. +// Sadly, sanitizers are not smart enough to figure it out. +SIMDJSON_NO_SANITIZE_UNDEFINED +// This function can be used safely even if not all bytes have been +// initialized. +// See issue https://github.com/simdjson/simdjson/issues/1965 +SIMDJSON_NO_SANITIZE_MEMORY +simdjson_inline int trailing_zeroes(uint64_t input_num) { + return __builtin_ctzll(input_num); +} + +/* result might be undefined when input_num is zero */ +simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) { + return input_num & (input_num-1); +} + +/* result might be undefined when input_num is zero */ +simdjson_inline int leading_zeroes(uint64_t input_num) { + return __builtin_clzll(input_num); +} + +simdjson_inline long long int count_ones(uint64_t input_num) { + return __builtin_popcountll(input_num); +} + +simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, + uint64_t *result) { + return __builtin_uaddll_overflow(value1, value2, + reinterpret_cast(result)); +} + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_BITMANIPULATION_H +/* end file simdjson/rvv-vls/bitmanipulation.h */ +/* including simdjson/rvv-vls/bitmask.h: #include "simdjson/rvv-vls/bitmask.h" */ +/* begin file simdjson/rvv-vls/bitmask.h */ +#ifndef SIMDJSON_RVV_VLS_BITMASK_H +#define SIMDJSON_RVV_VLS_BITMASK_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/intrinsics.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { + +// +// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered. +// +// For example, prefix_xor(00100100) == 00011100 +// +simdjson_inline uint64_t prefix_xor(uint64_t bitmask) { +#if __riscv_zbc + return __riscv_clmul_64(bitmask, ~(uint64_t)0); +#elif __riscv_zvbc + return __riscv_vmv_x(__riscv_vclmul(__riscv_vmv_s_x_u64m1(bitmask, 1), ~(uint64_t)0, 1)); +#else + bitmask ^= bitmask << 1; + bitmask ^= bitmask << 2; + bitmask ^= bitmask << 4; + bitmask ^= bitmask << 8; + bitmask ^= bitmask << 16; + bitmask ^= bitmask << 32; +#endif + return bitmask; +} + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_BITMASK_H + +/* end file simdjson/rvv-vls/bitmask.h */ +/* including simdjson/rvv-vls/simd.h: #include "simdjson/rvv-vls/simd.h" */ +/* begin file simdjson/rvv-vls/simd.h */ +#ifndef SIMDJSON_RVV_VLS_SIMD_H +#define SIMDJSON_RVV_VLS_SIMD_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/bitmanipulation.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/simdprune_tables.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace simd { + +#if __riscv_v_fixed_vlen >= 512 + static constexpr size_t VL8 = 512/8; + using vint8_t = vint8m1_t __attribute__((riscv_rvv_vector_bits(512))); + using vuint8_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(512))); + using vbool_t = vbool8_t __attribute__((riscv_rvv_vector_bits(512/8))); + using vbitmask_t = uint64_t; +#else + static constexpr size_t VL8 = __riscv_v_fixed_vlen/8; + using vint8_t = vint8m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen))); + using vuint8_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen))); + using vbool_t = vbool8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/8))); + #if __riscv_v_fixed_vlen == 128 + using vbitmask_t = uint16_t; + #elif __riscv_v_fixed_vlen == 256 + using vbitmask_t = uint32_t; + #endif +#endif + +#if __riscv_v_fixed_vlen == 128 + using vuint8x64_t = vuint8m4_t __attribute__((riscv_rvv_vector_bits(512))); + using vboolx64_t = vbool2_t __attribute__((riscv_rvv_vector_bits(512/8))); +#elif __riscv_v_fixed_vlen == 256 + using vuint8x64_t = vuint8m2_t __attribute__((riscv_rvv_vector_bits(512))); + using vboolx64_t = vbool4_t __attribute__((riscv_rvv_vector_bits(512/8))); +#else + using vuint8x64_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(512))); + using vboolx64_t = vbool8_t __attribute__((riscv_rvv_vector_bits(512/8))); +#endif + + template + struct simd8; + + // SIMD byte mask type (returned by things like eq and gt) + template<> + struct simd8 { + vbool_t value; + using bitmask_t = vbitmask_t; + static constexpr int SIZE = sizeof(value); + + simdjson_inline simd8(const vbool_t _value) : value(_value) {} + simdjson_inline simd8() : simd8(__riscv_vmclr_m_b8(VL8)) {} + simdjson_inline simd8(bool _value) : simd8(splat(_value)) {} + + simdjson_inline operator const vbool_t&() const { return value; } + simdjson_inline operator vbool_t&() { return value; } + + static simdjson_inline simd8 splat(bool _value) { + return __riscv_vreinterpret_b8(__riscv_vmv_v_x_u64m1(((uint64_t)!_value)-1, 1)); + } + + simdjson_inline vbitmask_t to_bitmask() const { +#if __riscv_v_fixed_vlen == 128 + return __riscv_vmv_x(__riscv_vreinterpret_u16m1(value)); +#elif __riscv_v_fixed_vlen == 256 + return __riscv_vmv_x(__riscv_vreinterpret_u32m1(value)); +#else + return __riscv_vmv_x(__riscv_vreinterpret_u64m1(value)); +#endif + } + + // Bit operations + simdjson_inline simd8 operator|(const simd8 other) const { return __riscv_vmor(*this, other, VL8); } + simdjson_inline simd8 operator&(const simd8 other) const { return __riscv_vmand(*this, other, VL8); } + simdjson_inline simd8 operator^(const simd8 other) const { return __riscv_vmxor(*this, other, VL8); } + simdjson_inline simd8 bit_andnot(const simd8 other) const { return __riscv_vmandn(other, *this, VL8); } + simdjson_inline simd8 operator~() const { return __riscv_vmnot(*this, VL8); } + simdjson_inline simd8& operator|=(const simd8 other) { auto this_cast = static_cast*>(this); *this_cast = *this_cast | other; return *this_cast; } + simdjson_inline simd8& operator&=(const simd8 other) { auto this_cast = static_cast*>(this); *this_cast = *this_cast & other; return *this_cast; } + simdjson_inline simd8& operator^=(const simd8 other) { auto this_cast = static_cast*>(this); *this_cast = *this_cast ^ other; return *this_cast; } + }; + + // Unsigned bytes + template<> + struct simd8 { + + vuint8_t value; + static constexpr int SIZE = sizeof(value); + + simdjson_inline simd8(const vuint8_t _value) : value(_value) {} + simdjson_inline simd8() : simd8(zero()) {} + simdjson_inline simd8(const uint8_t values[VL8]) : simd8(load(values)) {} + simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {} + simdjson_inline simd8(simd8 mask) : value(__riscv_vmerge_vxm_u8m1(zero(), -1, (vbool_t)mask, VL8)) {} + + simdjson_inline operator const vuint8_t&() const { return this->value; } + simdjson_inline operator vuint8_t&() { return this->value; } + + simdjson_inline simd8( + uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7, + uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15 + ) : simd8(vuint8_t{ + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + }) {} + + // Repeat 16 values as many times as necessary (usually for lookup tables) + simdjson_inline static simd8 repeat_16( + uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7, + uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15 + ) { + return simd8( + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + ); + } + + static simdjson_inline vuint8_t splat(uint8_t _value) { return __riscv_vmv_v_x_u8m1(_value, VL8); } + static simdjson_inline vuint8_t zero() { return splat(0); } + static simdjson_inline vuint8_t load(const uint8_t values[VL8]) { return __riscv_vle8_v_u8m1(values, VL8); } + + // Bit operations + simdjson_inline simd8 operator|(const simd8 other) const { return __riscv_vor_vv_u8m1( value, other, VL8); } + simdjson_inline simd8 operator&(const simd8 other) const { return __riscv_vand_vv_u8m1( value, other, VL8); } + simdjson_inline simd8 operator^(const simd8 other) const { return __riscv_vxor_vv_u8m1( value, other, VL8); } + simdjson_inline simd8 operator~() const { return __riscv_vnot_v_u8m1(value, VL8); } +#if __riscv_zvbb + simdjson_inline simd8 bit_andnot(const simd8 other) const { return __riscv_vandn_vv_u8m1(other, value, VL8); } +#else + simdjson_inline simd8 bit_andnot(const simd8 other) const { return other & ~*this; } +#endif + simdjson_inline simd8& operator|=(const simd8 other) { value = *this | other; return *this; } + simdjson_inline simd8& operator&=(const simd8 other) { value = *this & other; return *this; } + simdjson_inline simd8& operator^=(const simd8 other) { value = *this ^ other; return *this; } + + simdjson_inline simd8 operator==(const simd8 other) const { return __riscv_vmseq(value, other, VL8); } + simdjson_inline simd8 operator==(uint8_t other) const { return __riscv_vmseq(value, other, VL8); } + + template + simdjson_inline simd8 prev(const simd8 prev_chunk) const { + return __riscv_vslideup(__riscv_vslidedown(prev_chunk, VL8-N, VL8), value, N, VL8); + } + + // Store to array + simdjson_inline void store(uint8_t dst[VL8]) const { return __riscv_vse8(dst, value, VL8); } + + // Saturated math + simdjson_inline simd8 saturating_add(const simd8 other) const { return __riscv_vsaddu(value, other, VL8); } + simdjson_inline simd8 saturating_sub(const simd8 other) const { return __riscv_vssubu(value, other, VL8); } + + // Addition/subtraction are the same for signed and unsigned + simdjson_inline simd8 operator+(const simd8 other) const { return __riscv_vadd(value, other, VL8); } + simdjson_inline simd8 operator-(const simd8 other) const { return __riscv_vsub(value, other, VL8); } + simdjson_inline simd8& operator+=(const simd8 other) { value = *this + other; return *this; } + simdjson_inline simd8& operator-=(const simd8 other) { value = *this - other; return *this; } + + // Order-specific operations + simdjson_inline simd8 operator<=(const simd8 other) const { return __riscv_vmsleu(value, other, VL8); } + simdjson_inline simd8 operator>=(const simd8 other) const { return __riscv_vmsgeu(value, other, VL8); } + simdjson_inline simd8 operator<(const simd8 other) const { return __riscv_vmsltu(value, other, VL8); } + simdjson_inline simd8 operator>(const simd8 other) const { return __riscv_vmsgtu(value, other, VL8); } + + // Same as >, but instead of guaranteeing all 1's == true, false = 0 and true = nonzero. + simdjson_inline simd8 gt_bits(const simd8 other) const { return simd8(*this > other); } + // Same as <, but instead of guaranteeing all 1's == true, false = 0 and true = nonzero. + simdjson_inline simd8 lt_bits(const simd8 other) const { return simd8(*this < other); } + + // Bit-specific operations + simdjson_inline bool any_bits_set_anywhere() const { + return __riscv_vfirst(__riscv_vmsne(value, 0, VL8), VL8) >= 0; + } + simdjson_inline bool any_bits_set_anywhere(simd8 bits) const { return (*this & bits).any_bits_set_anywhere(); } + template + simdjson_inline simd8 shr() const { return __riscv_vsrl(value, N, VL8); } + template + simdjson_inline simd8 shl() const { return __riscv_vsll(value, N, VL8); } + + + // Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values) + template + simdjson_inline simd8 lookup_16(simd8 lookup_table) const { + return __riscv_vrgather(lookup_table, value, VL8); + } + + // compress inactive elements, to match AVX-512 behavior + template + simdjson_inline void compress(vbitmask_t mask, L * output) const { + mask = (vbitmask_t)~mask; +#if __riscv_v_fixed_vlen == 128 + vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u16m1(mask, 1)); +#elif __riscv_v_fixed_vlen == 256 + vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u32m1(mask, 1)); +#else + vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u64m1(mask, 1)); +#endif + __riscv_vse8_v_u8m1(output, __riscv_vcompress(value, m, VL8), count_ones(mask)); + } + + template + simdjson_inline simd8 lookup_16( + L replace0, L replace1, L replace2, L replace3, + L replace4, L replace5, L replace6, L replace7, + L replace8, L replace9, L replace10, L replace11, + L replace12, L replace13, L replace14, L replace15) const { + return lookup_16(simd8::repeat_16( + replace0, replace1, replace2, replace3, + replace4, replace5, replace6, replace7, + replace8, replace9, replace10, replace11, + replace12, replace13, replace14, replace15 + )); + } + }; + + // Signed bytes + template<> + struct simd8 { + vint8_t value; + static constexpr int SIZE = sizeof(value); + + simdjson_inline simd8(const vint8_t _value) : value(_value) {} + simdjson_inline simd8() : simd8(zero()) {} + simdjson_inline simd8(const int8_t values[VL8]) : simd8(load(values)) {} + simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {} + + simdjson_inline operator const vint8_t&() const { return this->value; } + simdjson_inline operator vint8_t&() { return this->value; } + + simdjson_inline simd8( + int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7, + int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15 + ) : simd8(vint8_t{ + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + }) {} + + // Repeat 16 values as many times as necessary (usually for lookup tables) + simdjson_inline static simd8 repeat_16( + int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7, + int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15 + ) { + return simd8( + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + ); + } + + static simdjson_inline vint8_t splat(int8_t _value) { return __riscv_vmv_v_x_i8m1(_value, VL8); } + static simdjson_inline vint8_t zero() { return splat(0); } + static simdjson_inline vint8_t load(const int8_t values[VL8]) { return __riscv_vle8_v_i8m1(values, VL8); } + + + simdjson_inline void store(int8_t dst[VL8]) const { return __riscv_vse8(dst, value, VL8); } + + // Explicit conversion to/from unsigned + simdjson_inline explicit simd8(const vuint8_t other): simd8(__riscv_vreinterpret_i8m1(other)) {} + simdjson_inline explicit operator simd8() const { return __riscv_vreinterpret_u8m1(value); } + + // Math + simdjson_inline simd8 operator+(const simd8 other) const { return __riscv_vadd(value, other, VL8); } + simdjson_inline simd8 operator-(const simd8 other) const { return __riscv_vsub(value, other, VL8); } + simdjson_inline simd8& operator+=(const simd8 other) { value = *this + other; return *this; } + simdjson_inline simd8& operator-=(const simd8 other) { value = *this - other; return *this; } + + // Order-sensitive comparisons + simdjson_inline simd8 max_val( const simd8 other) const { return __riscv_vmax( value, other, VL8); } + simdjson_inline simd8 min_val( const simd8 other) const { return __riscv_vmin( value, other, VL8); } + simdjson_inline simd8 operator>( const simd8 other) const { return __riscv_vmsgt(value, other, VL8); } + simdjson_inline simd8 operator<( const simd8 other) const { return __riscv_vmslt(value, other, VL8); } + simdjson_inline simd8 operator==(const simd8 other) const { return __riscv_vmseq(value, other, VL8); } + + template + simdjson_inline simd8 prev(const simd8 prev_chunk) const { + return __riscv_vslideup(__riscv_vslidedown(prev_chunk, VL8-N, VL8), value, N, VL8); + } + + // Perform a lookup assuming no value is larger than 16 + template + simdjson_inline simd8 lookup_16(simd8 lookup_table) const { + return __riscv_vrgather(lookup_table, value, VL8); + } + template + simdjson_inline simd8 lookup_16( + L replace0, L replace1, L replace2, L replace3, + L replace4, L replace5, L replace6, L replace7, + L replace8, L replace9, L replace10, L replace11, + L replace12, L replace13, L replace14, L replace15) const { + return lookup_16(simd8::repeat_16( + replace0, replace1, replace2, replace3, + replace4, replace5, replace6, replace7, + replace8, replace9, replace10, replace11, + replace12, replace13, replace14, replace15 + )); + } + }; + + template + struct simd8x64; + template<> + struct simd8x64 { + static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); + vuint8x64_t value; + +#if __riscv_v_fixed_vlen >= 512 + template simd8 get() const { return value; } +#else + template simd8 get() const { return __riscv_vget_u8m1(value, idx); } +#endif + + simdjson_inline operator const vuint8x64_t&() const { return this->value; } + simdjson_inline operator vuint8x64_t&() { return this->value; } + + simd8x64(const simd8x64& o) = delete; // no copy allowed + simd8x64& operator=(const simd8& other) = delete; // no assignment allowed + simd8x64() = delete; // no default constructor allowed + +#if __riscv_v_fixed_vlen == 128 + simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m4(ptr, n)) {} +#elif __riscv_v_fixed_vlen == 256 + simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m2(ptr, n)) {} +#else + simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m1(ptr, n)) {} +#endif + + simdjson_inline void store(uint8_t ptr[64]) const { + __riscv_vse8(ptr, value, 64); + } + + simdjson_inline bool is_ascii() const { +#if __riscv_v_fixed_vlen == 128 + return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m4(value), 0, 64), 64) < 0; +#elif __riscv_v_fixed_vlen == 256 + return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m2(value), 0, 64), 64) < 0; +#else + return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m1(value), 0, 64), 64) < 0; +#endif + } + + // compress inactive elements, to match AVX-512 behavior + simdjson_inline uint64_t compress(uint64_t mask, uint8_t * output) const { + mask = ~mask; +#if __riscv_v_fixed_vlen == 128 + vboolx64_t m = __riscv_vreinterpret_b2(__riscv_vmv_s_x_u64m1(mask, 1)); +#elif __riscv_v_fixed_vlen == 256 + vboolx64_t m = __riscv_vreinterpret_b4(__riscv_vmv_s_x_u64m1(mask, 1)); +#else + vboolx64_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u64m1(mask, 1)); +#endif + size_t cnt = count_ones(mask); + __riscv_vse8(output, __riscv_vcompress(value, m, 64), cnt); + return cnt; + } + + simdjson_inline uint64_t eq(const uint8_t m) const { + return __riscv_vmv_x(__riscv_vreinterpret_u64m1(__riscv_vmseq(value, m, 64))); + } + + simdjson_inline uint64_t lteq(const uint8_t m) const { + return __riscv_vmv_x(__riscv_vreinterpret_u64m1(__riscv_vmsleu(value, m, 64))); + } + }; // struct simd8x64 + +} // namespace simd +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_SIMD_H +/* end file simdjson/rvv-vls/simd.h */ +/* including simdjson/rvv-vls/stringparsing_defs.h: #include "simdjson/rvv-vls/stringparsing_defs.h" */ +/* begin file simdjson/rvv-vls/stringparsing_defs.h */ +#ifndef SIMDJSON_RVV_VLS_STRINGPARSING_DEFS_H +#define SIMDJSON_RVV_VLS_STRINGPARSING_DEFS_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { + +using namespace simd; + +// Holds backslashes and quotes locations. +struct backslash_and_quote { +public: + static constexpr uint64_t BYTES_PROCESSED = sizeof(simd8); + simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + + simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; } + simdjson_inline bool has_backslash() { return ((quote_bits - 1) & bs_bits) != 0; } + simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); } + simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); } + + uint64_t bs_bits; + uint64_t quote_bits; +}; // struct backslash_and_quote + +simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) { + static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes"); + simd8 v(src); + v.store(dst); + return { (v == '\\').to_bitmask(), (v == '"').to_bitmask() }; +} + +struct escaping { + static constexpr uint64_t BYTES_PROCESSED = sizeof(simd8); + simdjson_inline static escaping copy_and_find(const uint8_t *src, uint8_t *dst); + + simdjson_inline bool has_escape() { return escape_bits != 0; } + simdjson_inline int escape_index() { return trailing_zeroes(escape_bits) / 4; } + + uint64_t escape_bits; +}; // struct escaping + +simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *dst) { + static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "escaping finder must process fewer than SIMDJSON_PADDING bytes"); + simd8 v(src); + v.store(dst); + return { ((v == '"') | (v == '\\') | (v == 32)).to_bitmask() }; +} + + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_STRINGPARSING_DEFS_H +/* end file simdjson/rvv-vls/stringparsing_defs.h */ +/* including simdjson/rvv-vls/numberparsing_defs.h: #include "simdjson/rvv-vls/numberparsing_defs.h" */ +/* begin file simdjson/rvv-vls/numberparsing_defs.h */ +#ifndef SIMDJSON_RVV_VLS_NUMBERPARSING_DEFS_H +#define SIMDJSON_RVV_VLS_NUMBERPARSING_DEFS_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include + +#ifdef JSON_TEST_NUMBERS // for unit testing +void found_invalid_number(const uint8_t *buf); +void found_integer(int64_t result, const uint8_t *buf); +void found_unsigned_integer(uint64_t result, const uint8_t *buf); +void found_float(double result, const uint8_t *buf); +#endif + +namespace simdjson { +namespace rvv_vls { +namespace numberparsing { + +// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/ +/** @private */ +static simdjson_inline uint32_t parse_eight_digits_unrolled(const char *chars) { + uint64_t val; +#if __riscv_misaligned_fast + memcpy(&val, chars, sizeof(uint64_t)); +#else + val = __riscv_vmv_x(__riscv_vreinterpret_u64m1(__riscv_vlmul_ext_u8m1(__riscv_vle8_v_u8mf2((uint8_t*)chars, 8)))); +#endif + val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8; + val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16; + return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32); +} + +/** @private */ +static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) { + return parse_eight_digits_unrolled(reinterpret_cast(chars)); +} + +/** @private */ +simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) { + internal::value128 answer; + __uint128_t r = (static_cast<__uint128_t>(value1)) * value2; + answer.low = uint64_t(r); + answer.high = uint64_t(r >> 64); + return answer; +} + +} // namespace numberparsing +} // namespace rvv_vls +} // namespace simdjson + +#define SIMDJSON_SWAR_NUMBER_PARSING 1 + +#endif // SIMDJSON_RVV_VLS_NUMBERPARSING_DEFS_H +/* end file simdjson/rvv-vls/numberparsing_defs.h */ + +#define SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT 1 +/* end file simdjson/rvv-vls/begin.h */ +/* including simdjson/generic/builder/amalgamated.h for rvv_vls: #include "simdjson/generic/builder/amalgamated.h" */ +/* begin file simdjson/generic/builder/amalgamated.h for rvv_vls */ +#if defined(SIMDJSON_CONDITIONAL_INCLUDE) && !defined(SIMDJSON_GENERIC_BUILDER_DEPENDENCIES_H) +#error simdjson/generic/builder/dependencies.h must be included before simdjson/generic/builder/amalgamated.h! +#endif + +/* including simdjson/generic/builder/json_string_builder.h for rvv_vls: #include "simdjson/generic/builder/json_string_builder.h" */ +/* begin file simdjson/generic/builder/json_string_builder.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_STRING_BUILDER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_STRING_BUILDER_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { + + +#if SIMDJSON_SUPPORTS_CONCEPTS + +namespace rvv_vls { +namespace builder { + class string_builder; +}} + +template +struct has_custom_serialization : std::false_type {}; + +inline constexpr struct serialize_tag { + template + constexpr void operator()(rvv_vls::builder::string_builder& b, T&& obj) const{ + return tag_invoke(*this, b, std::forward(obj)); + } + + +} serialize{}; +template +struct has_custom_serialization(), std::declval())) +>> : std::true_type {}; + +template +constexpr bool require_custom_serialization = has_custom_serialization::value; +#else +struct has_custom_serialization : std::false_type {}; +#endif // SIMDJSON_SUPPORTS_CONCEPTS + +namespace rvv_vls { +namespace builder { +/** + * A builder for JSON strings representing documents. This is a low-level + * builder that is not meant to be used directly by end-users. Though it + * supports atomic types (Booleans, strings), it does not support composed + * types (arrays and objects). + * + * Ultimately, this class can support kernel-specific optimizations. E.g., + * it may make use of SIMD instructions to escape strings faster. + */ +class string_builder { +public: + simdjson_inline string_builder(size_t initial_capacity = DEFAULT_INITIAL_CAPACITY); + + static constexpr size_t DEFAULT_INITIAL_CAPACITY = 1024; + + /** + * Append number (includes Booleans). Booleans are mapped to the strings + * false and true. Numbers are converted to strings abiding by the JSON standard. + * Floating-point numbers are converted to the shortest string that 'correctly' + * represents the number. + */ + template::value>::type> + simdjson_inline void append(number_type v) noexcept; + + /** + * Append character c. + */ + simdjson_inline void append(char c) noexcept; + + /** + * Append the string 'null'. + */ + simdjson_inline void append_null() noexcept; + + /** + * Clear the content. + */ + simdjson_inline void clear() noexcept; + + /** + * Append the std::string_view, after escaping it. + * There is no UTF-8 validation. + */ + simdjson_inline void escape_and_append(std::string_view input) noexcept; + + /** + * Append the std::string_view surrounded by double quotes, after escaping it. + * There is no UTF-8 validation. + */ + simdjson_inline void escape_and_append_with_quotes(std::string_view input) noexcept; +#if SIMDJSON_SUPPORTS_CONCEPTS + template + simdjson_inline void escape_and_append_with_quotes() noexcept; +#endif + /** + * Append the character surrounded by double quotes, after escaping it. + * There is no UTF-8 validation. + */ + simdjson_inline void escape_and_append_with_quotes(char input) noexcept; + + /** + * Append the character surrounded by double quotes, after escaping it. + * There is no UTF-8 validation. + */ + simdjson_inline void escape_and_append_with_quotes(const char* input) noexcept; + + /** + * Append the C string directly, without escaping. + * There is no UTF-8 validation. + */ + simdjson_inline void append_raw(const char *c) noexcept; + + /** + * Append "{" to the buffer. + */ + simdjson_inline void start_object() noexcept; + + /** + * Append "}" to the buffer. + */ + simdjson_inline void end_object() noexcept; + + /** + * Append "[" to the buffer. + */ + simdjson_inline void start_array() noexcept; + + /** + * Append "]" to the buffer. + */ + simdjson_inline void end_array() noexcept; + + /** + * Append "," to the buffer. + */ + simdjson_inline void append_comma() noexcept; + + /** + * Append ":" to the buffer. + */ + simdjson_inline void append_colon() noexcept; + + /** + * Append a key-value pair to the buffer. + * The key is escaped and surrounded by double quotes. + * The value is escaped if it is a string. + */ + template + simdjson_inline void append_key_value(key_type key, value_type value) noexcept; +#if SIMDJSON_SUPPORTS_CONCEPTS + template + simdjson_inline void append_key_value(value_type value) noexcept; + + // Support for optional types (std::optional, etc.) + template + requires(!require_custom_serialization) + simdjson_inline void append(const T &opt); + + template + requires(require_custom_serialization) + simdjson_inline void append(T &&val); + + // Support for string-like types + template + requires(std::is_convertible::value || + std::is_same::value ) + simdjson_inline void append(const T &value); +#endif +#if SIMDJSON_SUPPORTS_RANGES && SIMDJSON_SUPPORTS_CONCEPTS + // Support for range-based appending (std::ranges::view, etc.) + template +requires (!std::is_convertible::value && !require_custom_serialization) + simdjson_inline void append(const R &range) noexcept; +#endif + /** + * Append the std::string_view directly, without escaping. + * There is no UTF-8 validation. + */ + simdjson_inline void append_raw(std::string_view input) noexcept; + + /** + * Append len characters from str. + * There is no UTF-8 validation. + */ + simdjson_inline void append_raw(const char *str, size_t len) noexcept; +#if SIMDJSON_EXCEPTIONS + /** + * Creates an std::string from the written JSON buffer. + * Throws if memory allocation failed + * + * The result may not be valid UTF-8 if some of your content was not valid UTF-8. + * Use validate_unicode() to check the content if needed. + */ + simdjson_inline operator std::string() const noexcept(false); + + /** + * Creates an std::string_view from the written JSON buffer. + * Throws if memory allocation failed. + * + * The result may not be valid UTF-8 if some of your content was not valid UTF-8. + * Use validate_unicode() to check the content if needed. + */ + simdjson_inline operator std::string_view() const noexcept(false) simdjson_lifetime_bound; +#endif + + /** + * Returns a view on the written JSON buffer. Returns an error + * if memory allocation failed. + * + * The result may not be valid UTF-8 if some of your content was not valid UTF-8. + * Use validate_unicode() to check the content. + */ + simdjson_inline simdjson_result view() const noexcept; + + /** + * Appends the null character to the buffer and returns + * a pointer to the beginning of the written JSON buffer. + * Returns an error if memory allocation failed. + * The result is null-terminated. + * + * The result may not be valid UTF-8 if some of your content was not valid UTF-8. + * Use validate_unicode() to check the content. + */ + simdjson_inline simdjson_result c_str() noexcept; + + /** + * Return true if the content is valid UTF-8. + */ + simdjson_inline bool validate_unicode() const noexcept; + + /** + * Returns the current size of the written JSON buffer. + * If an error occurred, returns 0. + */ + simdjson_inline size_t size() const noexcept; + +private: + /** + * Returns true if we can write at least upcoming_bytes bytes. + * The underlying buffer is reallocated if needed. It is designed + * to be called before writing to the buffer. It should be fast. + */ + simdjson_inline bool capacity_check(size_t upcoming_bytes); + + /** + * Grow the buffer to at least desired_capacity bytes. + * If the allocation fails, is_valid is set to false. We expect + * that this function would not be repeatedly called. + */ + simdjson_inline void grow_buffer(size_t desired_capacity); + + /** + * We use this helper function to make sure that is_valid is kept consistent. + */ + simdjson_inline void set_valid(bool valid) noexcept; + + std::unique_ptr buffer{}; + size_t position{0}; + size_t capacity{0}; + bool is_valid{true}; +}; + + + +} +} + + +#if !SIMDJSON_STATIC_REFLECTION +// fallback implementation until we have static reflection +template +simdjson_warn_unused simdjson_result to_json(const Z &z, size_t initial_capacity = simdjson::rvv_vls::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + simdjson::rvv_vls::builder::string_builder b(initial_capacity); + b.append(z); + std::string_view s; + auto e = b.view().get(s); + if(e) { return e; } + return std::string(s); +} +template +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = simdjson::rvv_vls::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + simdjson::rvv_vls::builder::string_builder b(initial_capacity); + b.append(z); + std::string_view sv; + auto e = b.view().get(sv); + if(e) { return e; } + s.assign(sv.data(), sv.size()); + return simdjson::SUCCESS; +} +#endif + +#if SIMDJSON_SUPPORTS_CONCEPTS +#endif // SIMDJSON_SUPPORTS_CONCEPTS + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_STRING_BUILDER_H +/* end file simdjson/generic/builder/json_string_builder.h for rvv_vls */ +/* including simdjson/generic/builder/json_builder.h for rvv_vls: #include "simdjson/generic/builder/json_builder.h" */ +/* begin file simdjson/generic/builder/json_builder.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_BUILDER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_STRING_BUILDER_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/builder/json_string_builder.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/concepts.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ +#if SIMDJSON_STATIC_REFLECTION + +#include +#include +#include +#include +#include +#include +#include +#include +// #include // for std::define_static_string - header not available yet + +namespace simdjson { +namespace rvv_vls { +namespace builder { + +template + requires(concepts::container_but_not_string && !require_custom_serialization) +constexpr void atom(string_builder &b, const T &t) { + auto it = t.begin(); + auto end = t.end(); + if (it == end) { + b.append_raw("[]"); + return; + } + b.append('['); + atom(b, *it); + ++it; + for (; it != end; ++it) { + b.append(','); + atom(b, *it); + } + b.append(']'); +} + +template + requires(std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v) +constexpr void atom(string_builder &b, const T &t) { + b.escape_and_append_with_quotes(t); +} + +template + requires(!require_custom_serialization) +constexpr void atom(string_builder &b, const T &m) { + if (m.empty()) { + b.append_raw("{}"); + return; + } + b.append('{'); + bool first = true; + for (const auto& [key, value] : m) { + if (!first) { + b.append(','); + } + first = false; + // Keys must be convertible to string_view per the concept + b.escape_and_append_with_quotes(key); + b.append(':'); + atom(b, value); + } + b.append('}'); +} + + +template::value && !std::is_same_v>::type> +constexpr void atom(string_builder &b, const number_type t) { + b.append(t); +} + +template + requires(std::is_class_v && !concepts::container_but_not_string && + !concepts::string_view_keyed_map && + !concepts::optional_type && + !concepts::smart_pointer && + !concepts::appendable_containers && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v && !require_custom_serialization) +constexpr void atom(string_builder &b, const T &t) { + int i = 0; + b.append('{'); + template for (constexpr auto dm : std::define_static_array(std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()))) { + if (i != 0) + b.append(','); + constexpr auto key = std::define_static_string(constevalutil::consteval_to_quoted_escaped(std::meta::identifier_of(dm))); + b.append_raw(key); + b.append(':'); + atom(b, t.[:dm:]); + i++; + }; + b.append('}'); +} + +// Support for optional types (std::optional, etc.) +template + requires(!require_custom_serialization) +constexpr void atom(string_builder &b, const T &opt) { + if (opt) { + atom(b, opt.value()); + } else { + b.append_raw("null"); + } +} + +// Support for smart pointers (std::unique_ptr, std::shared_ptr, etc.) +template + requires(!require_custom_serialization) +constexpr void atom(string_builder &b, const T &ptr) { + if (ptr) { + atom(b, *ptr); + } else { + b.append_raw("null"); + } +} + +// Support for enums - serialize as string representation using expand approach from P2996R12 +template + requires(std::is_enum_v && !require_custom_serialization) +void atom(string_builder &b, const T &e) { +#if SIMDJSON_STATIC_REFLECTION + constexpr auto enumerators = std::define_static_array(std::meta::enumerators_of(^^T)); + template for (constexpr auto enum_val : enumerators) { + constexpr auto enum_str = std::define_static_string(constevalutil::consteval_to_quoted_escaped(std::meta::identifier_of(enum_val))); + if (e == [:enum_val:]) { + b.append_raw(enum_str); + return; + } + }; + // Fallback to integer if enum value not found + atom(b, static_cast>(e)); +#else + // Fallback: serialize as integer if reflection not available + atom(b, static_cast>(e)); +#endif +} + +// Support for appendable containers that don't have operator[] (sets, etc.) +template + requires(!concepts::container_but_not_string && !concepts::string_view_keyed_map && + !concepts::optional_type && !concepts::smart_pointer && + !std::is_same_v && + !std::is_same_v && !std::is_same_v && !require_custom_serialization) +constexpr void atom(string_builder &b, const T &container) { + if (container.empty()) { + b.append_raw("[]"); + return; + } + b.append('['); + bool first = true; + for (const auto& item : container) { + if (!first) { + b.append(','); + } + first = false; + atom(b, item); + } + b.append(']'); +} + +// append functions that delegate to atom functions for primitive types +template + requires(std::is_arithmetic_v && !std::is_same_v) +void append(string_builder &b, const T &t) { + atom(b, t); +} + +template + requires(std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v) +void append(string_builder &b, const T &t) { + atom(b, t); +} + +template + requires(!require_custom_serialization) +void append(string_builder &b, const T &t) { + atom(b, t); +} + +template + requires(!require_custom_serialization) +void append(string_builder &b, const T &t) { + atom(b, t); +} + +template + requires(!concepts::container_but_not_string && !concepts::string_view_keyed_map && + !concepts::optional_type && !concepts::smart_pointer && + !std::is_same_v && + !std::is_same_v && !std::is_same_v && !require_custom_serialization) +void append(string_builder &b, const T &t) { + atom(b, t); +} + +template + requires(!require_custom_serialization) +void append(string_builder &b, const T &t) { + atom(b, t); +} + +// works for struct +template + requires(std::is_class_v && !concepts::container_but_not_string && + !concepts::string_view_keyed_map && + !concepts::optional_type && + !concepts::smart_pointer && + !concepts::appendable_containers && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v && !require_custom_serialization) +void append(string_builder &b, const Z &z) { + int i = 0; + b.append('{'); + template for (constexpr auto dm : std::define_static_array(std::meta::nonstatic_data_members_of(^^Z, std::meta::access_context::unchecked()))) { + if (i != 0) + b.append(','); + constexpr auto key = std::define_static_string(constevalutil::consteval_to_quoted_escaped(std::meta::identifier_of(dm))); + b.append_raw(key); + b.append(':'); + atom(b, z.[:dm:]); + i++; + }; + b.append('}'); +} + +// works for container that have begin() and end() iterators +template + requires(concepts::container_but_not_string && !require_custom_serialization) +void append(string_builder &b, const Z &z) { + auto it = z.begin(); + auto end = z.end(); + if (it == end) { + b.append_raw("[]"); + return; + } + b.append('['); + atom(b, *it); + ++it; + for (; it != end; ++it) { + b.append(','); + atom(b, *it); + } + b.append(']'); +} + +template + requires (require_custom_serialization) +void append(string_builder &b, const Z &z) { + b.append(z); +} + + +template +simdjson_warn_unused simdjson_result to_json_string(const Z &z, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + string_builder b(initial_capacity); + append(b, z); + std::string_view s; + if(auto e = b.view().get(s); e) { return e; } + return std::string(s); +} + +template +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + string_builder b(initial_capacity); + append(b, z); + std::string_view view; + if(auto e = b.view().get(view); e) { return e; } + s.assign(view); + return SUCCESS; +} + +template +string_builder& operator<<(string_builder& b, const Z& z) { + append(b, z); + return b; +} + +// extract_from: Serialize only specific fields from a struct to JSON +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +void extract_from(string_builder &b, const T &obj) { + // Helper to check if a field name matches any of the requested fields + auto should_extract = [](std::string_view field_name) constexpr -> bool { + return ((FieldNames.view() == field_name) || ...); + }; + + b.append('{'); + bool first = true; + + // Iterate through all members of T using reflection + template for (constexpr auto mem : std::define_static_array( + std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()))) { + + if constexpr (std::meta::is_public(mem)) { + constexpr std::string_view key = std::define_static_string(std::meta::identifier_of(mem)); + + // Only serialize this field if it's in our list of requested fields + if constexpr (should_extract(key)) { + if (!first) { + b.append(','); + } + first = false; + + // Serialize the key + constexpr auto quoted_key = std::define_static_string(constevalutil::consteval_to_quoted_escaped(std::meta::identifier_of(mem))); + b.append_raw(quoted_key); + b.append(':'); + + // Serialize the value + atom(b, obj.[:mem:]); + } + } + }; + + b.append('}'); +} + +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_result extract_from(const T &obj, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + string_builder b(initial_capacity); + extract_from(b, obj); + std::string_view s; + if(auto e = b.view().get(s); e) { return e; } + return std::string(s); +} + +} // namespace builder +} // namespace rvv_vls +// Alias the function template to 'to' in the global namespace +template +simdjson_warn_unused simdjson_result to_json(const Z &z, size_t initial_capacity = rvv_vls::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + rvv_vls::builder::string_builder b(initial_capacity); + rvv_vls::builder::append(b, z); + std::string_view s; + if(auto e = b.view().get(s); e) { return e; } + return std::string(s); +} +template +simdjson_warn_unused error_code to_json(const Z &z, std::string &s, size_t initial_capacity = rvv_vls::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + rvv_vls::builder::string_builder b(initial_capacity); + rvv_vls::builder::append(b, z); + std::string_view view; + if(auto e = b.view().get(view); e) { return e; } + s.assign(view); + return SUCCESS; +} +// Global namespace function for extract_from +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_result extract_from(const T &obj, size_t initial_capacity = rvv_vls::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + rvv_vls::builder::string_builder b(initial_capacity); + rvv_vls::builder::extract_from(b, obj); + std::string_view s; + if(auto e = b.view().get(s); e) { return e; } + return std::string(s); +} + +} // namespace simdjson + +#endif // SIMDJSON_STATIC_REFLECTION + +#endif +/* end file simdjson/generic/builder/json_builder.h for rvv_vls */ +/* including simdjson/generic/builder/fractured_json_builder.h for rvv_vls: #include "simdjson/generic/builder/fractured_json_builder.h" */ +/* begin file simdjson/generic/builder/fractured_json_builder.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H +#define SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/builder/json_builder.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/dom/fractured_json.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#if SIMDJSON_STATIC_REFLECTION + +namespace simdjson { +namespace rvv_vls { +namespace builder { + +/** + * Serialize an object to a FracturedJson-formatted string. + * + * FracturedJson produces human-readable yet compact JSON output by intelligently + * choosing between different layout strategies (inline, compact multiline, table, + * expanded) based on content complexity, length, and structure similarity. + * + * This function combines the builder's serialization with FracturedJson formatting: + * 1. Serializes the object to minified JSON using reflection + * 2. Parses and reformats using FracturedJson + * + * Example: + * struct User { int id; std::string name; bool active; }; + * User user{1, "Alice", true}; + * auto result = to_fractured_json_string(user); + * // result.value() == "{ \"id\": 1, \"name\": \"Alice\", \"active\": true }" + * + * @param obj The object to serialize (must be a reflectable type) + * @param opts FracturedJson formatting options + * @param initial_capacity Initial buffer capacity for serialization + * @return The formatted JSON string, or an error + */ +template +simdjson_warn_unused simdjson_result to_fractured_json_string( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + // Step 1: Serialize to minified JSON + std::string formatted; + auto error = to_json_string(obj, initial_capacity).get(formatted); + if (error) { + return error; + } + + // Step 2: Reformat with FracturedJson + return fractured_json_string(formatted, opts); +} + +/** + * Extract specific fields from an object and format with FracturedJson. + * + * Example: + * struct User { int id; std::string name; std::string email; bool active; }; + * User user{1, "Alice", "alice@example.com", true}; + * auto result = extract_fractured_json<"id", "name">(user); + * // result.value() == "{ \"id\": 1, \"name\": \"Alice\" }" + * + * @param obj The object to serialize + * @param opts FracturedJson formatting options + * @param initial_capacity Initial buffer capacity for serialization + * @return The formatted JSON string containing only the specified fields + */ +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_result extract_fractured_json( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) { + // Step 1: Extract fields to minified JSON + std::string formatted; + auto error = extract_from(obj, initial_capacity).get(formatted); + if (error) { + return error; + } + + // Step 2: Reformat with FracturedJson + return fractured_json_string(formatted, opts); +} + +} // namespace builder +} // namespace rvv_vls + +// Global namespace convenience functions + +/** + * Serialize an object to a FracturedJson-formatted string. + * Global namespace version for convenience. + */ +template +simdjson_warn_unused simdjson_result to_fractured_json_string( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = rvv_vls::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + return rvv_vls::builder::to_fractured_json_string(obj, opts, initial_capacity); +} +/** + * Extract specific fields from an object and format with FracturedJson. + * Global namespace version for convenience. + */ +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_result extract_fractured_json( + const T& obj, + const fractured_json_options& opts = {}, + size_t initial_capacity = rvv_vls::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + return rvv_vls::builder::extract_fractured_json(obj, opts, initial_capacity); +} + +} // namespace simdjson + +#endif // SIMDJSON_STATIC_REFLECTION + +#endif // SIMDJSON_GENERIC_FRACTURED_JSON_BUILDER_H +/* end file simdjson/generic/builder/fractured_json_builder.h for rvv_vls */ + + + +// JSON builder inline definitions +/* including simdjson/generic/builder/json_string_builder-inl.h for rvv_vls: #include "simdjson/generic/builder/json_string_builder-inl.h" */ +/* begin file simdjson/generic/builder/json_string_builder-inl.h for rvv_vls */ +#include +#include +#include +#ifndef SIMDJSON_GENERIC_STRING_BUILDER_INL_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_STRING_BUILDER_INL_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/builder/json_string_builder.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +/* + * Empirically, we have found that an inlined optimization is important for + * performance. The following macros are not ideal. We should find a better + * way to inline the code. + */ + +#if defined(__SSE2__) || defined(__x86_64__) || defined(__x86_64) || \ + (defined(_M_AMD64) || defined(_M_X64) || \ + (defined(_M_IX86_FP) && _M_IX86_FP == 2)) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_SSE2 +#define SIMDJSON_EXPERIMENTAL_HAS_SSE2 1 +#endif +#endif + +#if defined(__aarch64__) || defined(_M_ARM64) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_NEON +#define SIMDJSON_EXPERIMENTAL_HAS_NEON 1 +#endif +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_NEON +#include +#ifdef _MSC_VER +#include +#endif +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_SSE2 +#include +#ifdef _MSC_VER +#include +#endif +#endif + +namespace simdjson { +namespace rvv_vls { +namespace builder { + +static SIMDJSON_CONSTEXPR_LAMBDA std::array + json_quotable_character = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +/** + +A possible SWAR implementation of has_json_escapable_byte. It is not used +because it is slower than the current implementation. It is kept here for +reference (to show that we tried it). + +inline bool has_json_escapable_byte(uint64_t x) { + uint64_t is_ascii = 0x8080808080808080ULL & ~x; + uint64_t xor2 = x ^ 0x0202020202020202ULL; + uint64_t lt32_or_eq34 = xor2 - 0x2121212121212121ULL; + uint64_t sub92 = x ^ 0x5C5C5C5C5C5C5C5CULL; + uint64_t eq92 = (sub92 - 0x0101010101010101ULL); + return ((lt32_or_eq34 | eq92) & is_ascii) != 0; +} + +**/ + +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline bool +simple_needs_escaping(std::string_view v) { + for (char c : v) { + // a table lookup is faster than a series of comparisons + if (json_quotable_character[static_cast(c)]) { + return true; + } + } + return false; +} + +#if SIMDJSON_EXPERIMENTAL_HAS_NEON +simdjson_inline bool fast_needs_escaping(std::string_view view) { + if (view.size() < 16) { + return simple_needs_escaping(view); + } + size_t i = 0; + uint8x16_t running = vdupq_n_u8(0); + uint8x16_t v34 = vdupq_n_u8(34); + uint8x16_t v92 = vdupq_n_u8(92); + + for (; i + 15 < view.size(); i += 16) { + uint8x16_t word = vld1q_u8((const uint8_t *)view.data() + i); + running = vorrq_u8(running, vceqq_u8(word, v34)); + running = vorrq_u8(running, vceqq_u8(word, v92)); + running = vorrq_u8(running, vcltq_u8(word, vdupq_n_u8(32))); + } + if (i < view.size()) { + uint8x16_t word = + vld1q_u8((const uint8_t *)view.data() + view.length() - 16); + running = vorrq_u8(running, vceqq_u8(word, v34)); + running = vorrq_u8(running, vceqq_u8(word, v92)); + running = vorrq_u8(running, vcltq_u8(word, vdupq_n_u8(32))); + } + return vmaxvq_u32(vreinterpretq_u32_u8(running)) != 0; +} +#elif SIMDJSON_EXPERIMENTAL_HAS_SSE2 +simdjson_inline bool fast_needs_escaping(std::string_view view) { + if (view.size() < 16) { + return simple_needs_escaping(view); + } + size_t i = 0; + __m128i running = _mm_setzero_si128(); + for (; i + 15 < view.size(); i += 16) { + + __m128i word = + _mm_loadu_si128(reinterpret_cast(view.data() + i)); + running = _mm_or_si128(running, _mm_cmpeq_epi8(word, _mm_set1_epi8(34))); + running = _mm_or_si128(running, _mm_cmpeq_epi8(word, _mm_set1_epi8(92))); + running = _mm_or_si128( + running, _mm_cmpeq_epi8(_mm_subs_epu8(word, _mm_set1_epi8(31)), + _mm_setzero_si128())); + } + if (i < view.size()) { + __m128i word = _mm_loadu_si128( + reinterpret_cast(view.data() + view.length() - 16)); + running = _mm_or_si128(running, _mm_cmpeq_epi8(word, _mm_set1_epi8(34))); + running = _mm_or_si128(running, _mm_cmpeq_epi8(word, _mm_set1_epi8(92))); + running = _mm_or_si128( + running, _mm_cmpeq_epi8(_mm_subs_epu8(word, _mm_set1_epi8(31)), + _mm_setzero_si128())); + } + return _mm_movemask_epi8(running) != 0; +} +#else +simdjson_inline bool fast_needs_escaping(std::string_view view) { + return simple_needs_escaping(view); +} +#endif + +// Scalar fallback for finding next quotable character +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline size_t +find_next_json_quotable_character_scalar(const std::string_view view, + size_t location) noexcept { + for (auto pos = view.begin() + location; pos != view.end(); ++pos) { + if (json_quotable_character[static_cast(*pos)]) { + return pos - view.begin(); + } + } + return size_t(view.size()); +} + +// SIMD-accelerated position finding that directly locates the first quotable +// character, combining detection and position extraction in a single pass to +// minimize redundant work. +#if SIMDJSON_EXPERIMENTAL_HAS_NEON +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants for characters requiring escape + uint8x16_t v34 = vdupq_n_u8(34); // '"' + uint8x16_t v92 = vdupq_n_u8(92); // '\\' + uint8x16_t v32 = vdupq_n_u8(32); // control char threshold + + while (remaining >= 16) { + uint8x16_t word = vld1q_u8(ptr); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + uint8x16_t needs_escape = vceqq_u8(word, v34); + needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92)); + needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32)); + + if (vmaxvq_u32(vreinterpretq_u32_u8(needs_escape)) != 0) { + // Found quotable character - extract exact byte position using ctz + uint64x2_t as64 = vreinterpretq_u64_u8(needs_escape); + uint64_t lo = vgetq_lane_u64(as64, 0); + uint64_t hi = vgetq_lane_u64(as64, 1); + size_t offset = ptr - reinterpret_cast(view.data()); +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + if (lo != 0) { + _BitScanForward64(&trailing_zero, lo); + return offset + trailing_zero / 8; + } else { + _BitScanForward64(&trailing_zero, hi); + return offset + 8 + trailing_zero / 8; + } +#else + if (lo != 0) { + return offset + __builtin_ctzll(lo) / 8; + } else { + return offset + 8 + __builtin_ctzll(hi) / 8; + } +#endif + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_SSE2 +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants + __m128i v34 = _mm_set1_epi8(34); // '"' + __m128i v92 = _mm_set1_epi8(92); // '\\' + __m128i v31 = _mm_set1_epi8(31); // for control char detection + + while (remaining >= 16) { + __m128i word = _mm_loadu_si128(reinterpret_cast(ptr)); + + // Check for quotable characters + __m128i needs_escape = _mm_cmpeq_epi8(word, v34); + needs_escape = _mm_or_si128(needs_escape, _mm_cmpeq_epi8(word, v92)); + needs_escape = _mm_or_si128( + needs_escape, + _mm_cmpeq_epi8(_mm_subs_epu8(word, v31), _mm_setzero_si128())); + + int mask = _mm_movemask_epi8(needs_escape); + if (mask != 0) { + // Found quotable character - use trailing zero count to find position + size_t offset = ptr - reinterpret_cast(view.data()); +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + _BitScanForward(&trailing_zero, mask); + return offset + trailing_zero; +#else + return offset + __builtin_ctz(mask); +#endif + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#else +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + return find_next_json_quotable_character_scalar(view, location); +} +#endif + +SIMDJSON_CONSTEXPR_LAMBDA static std::string_view control_chars[] = { + "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", + "\\u0007", "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", + "\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012", "\\u0013", "\\u0014", + "\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019", "\\u001a", "\\u001b", + "\\u001c", "\\u001d", "\\u001e", "\\u001f"}; + +// All Unicode characters may be placed within the quotation marks, except for +// the characters that MUST be escaped: quotation mark, reverse solidus, and the +// control characters (U+0000 through U+001F). There are two-character sequence +// escape representations of some popular characters: +// \", \\, \b, \f, \n, \r, \t. +SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline void escape_json_char(char c, char *&out) { + if (c == '"') { + memcpy(out, "\\\"", 2); + out += 2; + } else if (c == '\\') { + memcpy(out, "\\\\", 2); + out += 2; + } else { + std::string_view v = control_chars[uint8_t(c)]; + memcpy(out, v.data(), v.size()); + out += v.size(); + } +} + +// Writes the escaped version of input to out, returning the number of bytes +// written. Uses SIMD position finding to locate quotable characters efficiently. +inline size_t write_string_escaped(const std::string_view input, char *out) { + size_t mysize = input.size(); + + // Use SIMD position finder directly - it returns mysize if no escape needed + size_t location = find_next_json_quotable_character(input, 0); + if (location == mysize) { + // Fast path: no escaping needed + memcpy(out, input.data(), input.size()); + return input.size(); + } + + const char *const initout = out; + memcpy(out, input.data(), location); + out += location; + escape_json_char(input[location], out); + location += 1; + while (location < mysize) { + size_t newlocation = find_next_json_quotable_character(input, location); + memcpy(out, input.data() + location, newlocation - location); + out += newlocation - location; + location = newlocation; + if (location == mysize) { + break; + } + escape_json_char(input[location], out); + location += 1; + } + return out - initout; +} + +simdjson_inline string_builder::string_builder(size_t initial_capacity) + : buffer(new(std::nothrow) char[initial_capacity]), position(0), + capacity(buffer.get() != nullptr ? initial_capacity : 0), + is_valid(buffer.get() != nullptr) {} + +simdjson_inline bool string_builder::capacity_check(size_t upcoming_bytes) { + // We use the convention that when is_valid is false, then the capacity and + // the position are 0. + // Most of the time, this function will return true. + if (simdjson_likely(upcoming_bytes <= capacity - position)) { + return true; + } + // check for overflow, most of the time there is no overflow + if (simdjson_likely(position + upcoming_bytes < position)) { + return false; + } + // We will rarely get here. + grow_buffer((std::max)(capacity * 2, position + upcoming_bytes)); + // If the buffer allocation failed, we set is_valid to false. + return is_valid; +} + +simdjson_inline void string_builder::grow_buffer(size_t desired_capacity) { + if (!is_valid) { + return; + } + std::unique_ptr new_buffer(new (std::nothrow) char[desired_capacity]); + if (new_buffer.get() == nullptr) { + set_valid(false); + return; + } + std::memcpy(new_buffer.get(), buffer.get(), position); + buffer.swap(new_buffer); + capacity = desired_capacity; +} + +simdjson_inline void string_builder::set_valid(bool valid) noexcept { + if (!valid) { + is_valid = false; + capacity = 0; + position = 0; + buffer.reset(); + } else { + is_valid = true; + } +} + +simdjson_inline size_t string_builder::size() const noexcept { + return position; +} + +simdjson_inline void string_builder::append(char c) noexcept { + if (capacity_check(1)) { + buffer.get()[position++] = c; + } +} + +simdjson_inline void string_builder::append_null() noexcept { + constexpr char null_literal[] = "null"; + constexpr size_t null_len = sizeof(null_literal) - 1; + if (capacity_check(null_len)) { + std::memcpy(buffer.get() + position, null_literal, null_len); + position += null_len; + } +} + +simdjson_inline void string_builder::clear() noexcept { + position = 0; + // if it was invalid, we should try to repair it + if (!is_valid) { + capacity = 0; + buffer.reset(); + is_valid = true; + } +} + +namespace internal { + +template ::value>::type> +simdjson_really_inline int int_log2(number_type x) { + return 63 - leading_zeroes(uint64_t(x) | 1); +} + +simdjson_really_inline int fast_digit_count_32(uint32_t x) { + static uint64_t table[] = { + 4294967296, 8589934582, 8589934582, 8589934582, 12884901788, + 12884901788, 12884901788, 17179868184, 17179868184, 17179868184, + 21474826480, 21474826480, 21474826480, 21474826480, 25769703776, + 25769703776, 25769703776, 30063771072, 30063771072, 30063771072, + 34349738368, 34349738368, 34349738368, 34349738368, 38554705664, + 38554705664, 38554705664, 41949672960, 41949672960, 41949672960, + 42949672960, 42949672960}; + return uint32_t((x + table[int_log2(x)]) >> 32); +} + +simdjson_really_inline int fast_digit_count_64(uint64_t x) { + static uint64_t table[] = {9, + 99, + 999, + 9999, + 99999, + 999999, + 9999999, + 99999999, + 999999999, + 9999999999, + 99999999999, + 999999999999, + 9999999999999, + 99999999999999, + 999999999999999ULL, + 9999999999999999ULL, + 99999999999999999ULL, + 999999999999999999ULL, + 9999999999999999999ULL}; + int y = (19 * int_log2(x) >> 6); + y += x > table[y]; + return y + 1; +} + +template ::value>::type> +simdjson_really_inline size_t digit_count(number_type v) noexcept { + static_assert(sizeof(number_type) == 8 || sizeof(number_type) == 4 || + sizeof(number_type) == 2 || sizeof(number_type) == 1, + "We only support 8-bit, 16-bit, 32-bit and 64-bit numbers"); + SIMDJSON_IF_CONSTEXPR(sizeof(number_type) <= 4) { + return fast_digit_count_32(static_cast(v)); + } + else { + return fast_digit_count_64(static_cast(v)); + } +} +static const char decimal_table[200] = { + 0x30, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30, 0x33, 0x30, 0x34, 0x30, 0x35, + 0x30, 0x36, 0x30, 0x37, 0x30, 0x38, 0x30, 0x39, 0x31, 0x30, 0x31, 0x31, + 0x31, 0x32, 0x31, 0x33, 0x31, 0x34, 0x31, 0x35, 0x31, 0x36, 0x31, 0x37, + 0x31, 0x38, 0x31, 0x39, 0x32, 0x30, 0x32, 0x31, 0x32, 0x32, 0x32, 0x33, + 0x32, 0x34, 0x32, 0x35, 0x32, 0x36, 0x32, 0x37, 0x32, 0x38, 0x32, 0x39, + 0x33, 0x30, 0x33, 0x31, 0x33, 0x32, 0x33, 0x33, 0x33, 0x34, 0x33, 0x35, + 0x33, 0x36, 0x33, 0x37, 0x33, 0x38, 0x33, 0x39, 0x34, 0x30, 0x34, 0x31, + 0x34, 0x32, 0x34, 0x33, 0x34, 0x34, 0x34, 0x35, 0x34, 0x36, 0x34, 0x37, + 0x34, 0x38, 0x34, 0x39, 0x35, 0x30, 0x35, 0x31, 0x35, 0x32, 0x35, 0x33, + 0x35, 0x34, 0x35, 0x35, 0x35, 0x36, 0x35, 0x37, 0x35, 0x38, 0x35, 0x39, + 0x36, 0x30, 0x36, 0x31, 0x36, 0x32, 0x36, 0x33, 0x36, 0x34, 0x36, 0x35, + 0x36, 0x36, 0x36, 0x37, 0x36, 0x38, 0x36, 0x39, 0x37, 0x30, 0x37, 0x31, + 0x37, 0x32, 0x37, 0x33, 0x37, 0x34, 0x37, 0x35, 0x37, 0x36, 0x37, 0x37, + 0x37, 0x38, 0x37, 0x39, 0x38, 0x30, 0x38, 0x31, 0x38, 0x32, 0x38, 0x33, + 0x38, 0x34, 0x38, 0x35, 0x38, 0x36, 0x38, 0x37, 0x38, 0x38, 0x38, 0x39, + 0x39, 0x30, 0x39, 0x31, 0x39, 0x32, 0x39, 0x33, 0x39, 0x34, 0x39, 0x35, + 0x39, 0x36, 0x39, 0x37, 0x39, 0x38, 0x39, 0x39, +}; +} // namespace internal + +template +simdjson_inline void string_builder::append(number_type v) noexcept { + static_assert(std::is_same::value || + std::is_integral::value || + std::is_floating_point::value, + "Unsupported number type"); + // If C++17 is available, we can 'if constexpr' here. + SIMDJSON_IF_CONSTEXPR(std::is_same::value) { + if (v) { + constexpr char true_literal[] = "true"; + constexpr size_t true_len = sizeof(true_literal) - 1; + if (capacity_check(true_len)) { + std::memcpy(buffer.get() + position, true_literal, true_len); + position += true_len; + } + } else { + constexpr char false_literal[] = "false"; + constexpr size_t false_len = sizeof(false_literal) - 1; + if (capacity_check(false_len)) { + std::memcpy(buffer.get() + position, false_literal, false_len); + position += false_len; + } + } + } + else SIMDJSON_IF_CONSTEXPR(std::is_unsigned::value) { + // Process 4 digits at a time instead of 2, reducing store operations + // and divisions by approximately half for large numbers. + constexpr size_t max_number_size = 20; + if (capacity_check(max_number_size)) { + using unsigned_type = typename std::make_unsigned::type; + unsigned_type pv = static_cast(v); + size_t dc = internal::digit_count(pv); + char *write_pointer = buffer.get() + position + dc - 1; + + // Process 4 digits per iteration for large numbers + while (pv >= 10000) { + unsigned_type q = pv / 10000; + unsigned_type r = pv % 10000; + unsigned_type r_hi = r / 100; // High 2 digits of remainder + unsigned_type r_lo = r % 100; // Low 2 digits of remainder + // Write low 2 digits first (rightmost), then high 2 digits + memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2); + memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2); + write_pointer -= 4; + pv = q; + } + + // Handle remaining 1-4 digits with original 2-digit loop + while (pv >= 100) { + memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2); + write_pointer -= 2; + pv /= 100; + } + if (pv >= 10) { + *write_pointer-- = char('0' + (pv % 10)); + pv /= 10; + } + *write_pointer = char('0' + pv); + position += dc; + } + } + else SIMDJSON_IF_CONSTEXPR(std::is_integral::value) { + // Same 4-digit batching as unsigned path for signed integers + constexpr size_t max_number_size = 20; + if (capacity_check(max_number_size)) { + using unsigned_type = typename std::make_unsigned::type; + bool negative = v < 0; + unsigned_type pv = static_cast(v); + if (negative) { + pv = 0 - pv; // the 0 is for Microsoft + } + size_t dc = internal::digit_count(pv); + // by always writing the minus sign, we avoid the branch. + buffer.get()[position] = '-'; + position += negative ? 1 : 0; + char *write_pointer = buffer.get() + position + dc - 1; + + // Process 4 digits per iteration for large numbers + while (pv >= 10000) { + unsigned_type q = pv / 10000; + unsigned_type r = pv % 10000; + unsigned_type r_hi = r / 100; + unsigned_type r_lo = r % 100; + memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2); + memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2); + write_pointer -= 4; + pv = q; + } + + // Handle remaining 1-4 digits + while (pv >= 100) { + memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2); + write_pointer -= 2; + pv /= 100; + } + if (pv >= 10) { + *write_pointer-- = char('0' + (pv % 10)); + pv /= 10; + } + *write_pointer = char('0' + pv); + position += dc; + } + } + else SIMDJSON_IF_CONSTEXPR(std::is_floating_point::value) { + constexpr size_t max_number_size = 24; + if (capacity_check(max_number_size)) { + // We could specialize for float. + char *end = simdjson::internal::to_chars(buffer.get() + position, nullptr, + double(v)); + position = end - buffer.get(); + } + } +} + +simdjson_inline void +string_builder::escape_and_append(std::string_view input) noexcept { + // escaping might turn a control character into \x00xx so 6 characters. + if (capacity_check(6 * input.size())) { + position += write_string_escaped(input, buffer.get() + position); + } +} + +simdjson_inline void +string_builder::escape_and_append_with_quotes(std::string_view input) noexcept { + // escaping might turn a control character into \x00xx so 6 characters. + if (capacity_check(2 + 6 * input.size())) { + buffer.get()[position++] = '"'; + position += write_string_escaped(input, buffer.get() + position); + buffer.get()[position++] = '"'; + } +} + +simdjson_inline void +string_builder::escape_and_append_with_quotes(char input) noexcept { + // escaping might turn a control character into \x00xx so 6 characters. + if (capacity_check(2 + 6 * 1)) { + buffer.get()[position++] = '"'; + std::string_view cinput(&input, 1); + position += write_string_escaped(cinput, buffer.get() + position); + buffer.get()[position++] = '"'; + } +} + +simdjson_inline void +string_builder::escape_and_append_with_quotes(const char *input) noexcept { + std::string_view cinput(input); + escape_and_append_with_quotes(cinput); +} +#if SIMDJSON_SUPPORTS_CONCEPTS +template +simdjson_inline void string_builder::escape_and_append_with_quotes() noexcept { + escape_and_append_with_quotes(constevalutil::string_constant::value); +} +#endif + +simdjson_inline void string_builder::append_raw(const char *c) noexcept { + size_t len = std::strlen(c); + append_raw(c, len); +} + +simdjson_inline void +string_builder::append_raw(std::string_view input) noexcept { + if (capacity_check(input.size())) { + std::memcpy(buffer.get() + position, input.data(), input.size()); + position += input.size(); + } +} + +simdjson_inline void string_builder::append_raw(const char *str, + size_t len) noexcept { + if (capacity_check(len)) { + std::memcpy(buffer.get() + position, str, len); + position += len; + } +} +#if SIMDJSON_SUPPORTS_CONCEPTS +// Support for optional types (std::optional, etc.) +template + requires(!require_custom_serialization) +simdjson_inline void string_builder::append(const T &opt) { + if (opt) { + append(*opt); + } else { + append_null(); + } +} + +template + requires(require_custom_serialization) +simdjson_inline void string_builder::append(T &&val) { + serialize(*this, std::forward(val)); +} + +template + requires(std::is_convertible::value || + std::is_same::value) +simdjson_inline void string_builder::append(const T &value) { + escape_and_append_with_quotes(value); +} +#endif + +#if SIMDJSON_SUPPORTS_RANGES && SIMDJSON_SUPPORTS_CONCEPTS +// Support for range-based appending (std::ranges::view, etc.) +template + requires(!std::is_convertible::value && !require_custom_serialization) +simdjson_inline void string_builder::append(const R &range) noexcept { + auto it = std::ranges::begin(range); + auto end = std::ranges::end(range); + if constexpr (concepts::is_pair>) { + start_object(); + + if (it == end) { + end_object(); + return; // Handle empty range + } + // Append first item without leading comma + append_key_value(it->first, it->second); + ++it; + + // Append remaining items with preceding commas + for (; it != end; ++it) { + append_comma(); + append_key_value(it->first, it->second); + } + end_object(); + } else { + start_array(); + if (it == end) { + end_array(); + return; // Handle empty range + } + + // Append first item without leading comma + append(*it); + ++it; + + // Append remaining items with preceding commas + for (; it != end; ++it) { + append_comma(); + append(*it); + } + end_array(); + } +} + +#endif + +#if SIMDJSON_EXCEPTIONS +simdjson_inline string_builder::operator std::string() const noexcept(false) { + return std::string(operator std::string_view()); +} + +simdjson_inline string_builder::operator std::string_view() const + noexcept(false) simdjson_lifetime_bound { + return view(); +} +#endif + +simdjson_inline simdjson_result +string_builder::view() const noexcept { + if (!is_valid) { + return simdjson::OUT_OF_CAPACITY; + } + return std::string_view(buffer.get(), position); +} + +simdjson_inline simdjson_result string_builder::c_str() noexcept { + if (capacity_check(1)) { + buffer.get()[position] = '\0'; + return buffer.get(); + } + return simdjson::OUT_OF_CAPACITY; +} + +simdjson_inline bool string_builder::validate_unicode() const noexcept { + return simdjson::validate_utf8(buffer.get(), position); +} + +simdjson_inline void string_builder::start_object() noexcept { + if (capacity_check(1)) { + buffer.get()[position++] = '{'; + } +} + +simdjson_inline void string_builder::end_object() noexcept { + if (capacity_check(1)) { + buffer.get()[position++] = '}'; + } +} + +simdjson_inline void string_builder::start_array() noexcept { + if (capacity_check(1)) { + buffer.get()[position++] = '['; + } +} + +simdjson_inline void string_builder::end_array() noexcept { + if (capacity_check(1)) { + buffer.get()[position++] = ']'; + } +} + +simdjson_inline void string_builder::append_comma() noexcept { + if (capacity_check(1)) { + buffer.get()[position++] = ','; + } +} + +simdjson_inline void string_builder::append_colon() noexcept { + if (capacity_check(1)) { + buffer.get()[position++] = ':'; + } +} + +template +simdjson_inline void +string_builder::append_key_value(key_type key, value_type value) noexcept { + static_assert(std::is_same::value || + std::is_convertible::value, + "Unsupported key type"); + escape_and_append_with_quotes(key); + append_colon(); + SIMDJSON_IF_CONSTEXPR(std::is_same::value) { + append_null(); + } + else SIMDJSON_IF_CONSTEXPR(std::is_same::value) { + escape_and_append_with_quotes(value); + } + else SIMDJSON_IF_CONSTEXPR( + std::is_convertible::value) { + escape_and_append_with_quotes(value); + } + else SIMDJSON_IF_CONSTEXPR(std::is_same::value) { + escape_and_append_with_quotes(value); + } + else { + append(value); + } +} + +#if SIMDJSON_SUPPORTS_CONCEPTS +template +simdjson_inline void +string_builder::append_key_value(value_type value) noexcept { + escape_and_append_with_quotes(); + append_colon(); + SIMDJSON_IF_CONSTEXPR(std::is_same::value) { + append_null(); + } + else SIMDJSON_IF_CONSTEXPR(std::is_same::value) { + escape_and_append_with_quotes(value); + } + else SIMDJSON_IF_CONSTEXPR( + std::is_convertible::value) { + escape_and_append_with_quotes(value); + } + else SIMDJSON_IF_CONSTEXPR(std::is_same::value) { + escape_and_append_with_quotes(value); + } + else { + append(value); + } +} +#endif + +} // namespace builder +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_STRING_BUILDER_INL_H +/* end file simdjson/generic/builder/json_string_builder-inl.h for rvv_vls */ + +/* end file simdjson/generic/builder/amalgamated.h for rvv_vls */ +/* including simdjson/rvv-vls/end.h: #include "simdjson/rvv-vls/end.h" */ +/* begin file simdjson/rvv-vls/end.h */ +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +/* undefining SIMDJSON_IMPLEMENTATION from "rvv_vls" */ +#undef SIMDJSON_IMPLEMENTATION +/* end file simdjson/rvv-vls/end.h */ + +#endif // SIMDJSON_RVV_VLS_BUILDER_H +/* end file simdjson/rvv-vls/builder.h */ #else #error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION #endif @@ -51285,6 +60311,7 @@ namespace { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, "ARM kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -62570,9 +71597,13 @@ simdjson_warn_unused simdjson_inline simdjson_result value_ite template simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept { std::string_view content; + // Save the string buffer location so that we can restore it after get_string + auto saved_string_buf_loc = _json_iter->string_buf_loc(); auto err = get_string(allow_replacement).get(content); if (err) { return err; } receiver = content; + // Restore the string buffer location, effectively discarding any temporary string storage + _json_iter->string_buf_loc() = saved_string_buf_loc; return SUCCESS; } simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_wobbly_string() noexcept { @@ -62712,9 +71743,13 @@ simdjson_warn_unused simdjson_inline simdjson_result value_ite template simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept { std::string_view content; + // Save the string buffer location so that we can restore it after get_string + auto saved_string_buf_loc = _json_iter->string_buf_loc(); auto err = get_root_string(check_trailing, allow_replacement).get(content); if (err) { return err; } receiver = content; + // Restore the string buffer location, effectively discarding any temporary string storage + _json_iter->string_buf_loc() = saved_string_buf_loc; return SUCCESS; } simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_wobbly_string(bool check_trailing) noexcept { @@ -75701,9 +84736,13 @@ simdjson_warn_unused simdjson_inline simdjson_result value_ite template simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept { std::string_view content; + // Save the string buffer location so that we can restore it after get_string + auto saved_string_buf_loc = _json_iter->string_buf_loc(); auto err = get_string(allow_replacement).get(content); if (err) { return err; } receiver = content; + // Restore the string buffer location, effectively discarding any temporary string storage + _json_iter->string_buf_loc() = saved_string_buf_loc; return SUCCESS; } simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_wobbly_string() noexcept { @@ -75843,9 +84882,13 @@ simdjson_warn_unused simdjson_inline simdjson_result value_ite template simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept { std::string_view content; + // Save the string buffer location so that we can restore it after get_string + auto saved_string_buf_loc = _json_iter->string_buf_loc(); auto err = get_root_string(check_trailing, allow_replacement).get(content); if (err) { return err; } receiver = content; + // Restore the string buffer location, effectively discarding any temporary string storage + _json_iter->string_buf_loc() = saved_string_buf_loc; return SUCCESS; } simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_wobbly_string(bool check_trailing) noexcept { @@ -78062,6 +87105,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 2, "Haswell kernel should use two registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -89331,9 +98375,13 @@ simdjson_warn_unused simdjson_inline simdjson_result value_ite template simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept { std::string_view content; + // Save the string buffer location so that we can restore it after get_string + auto saved_string_buf_loc = _json_iter->string_buf_loc(); auto err = get_string(allow_replacement).get(content); if (err) { return err; } receiver = content; + // Restore the string buffer location, effectively discarding any temporary string storage + _json_iter->string_buf_loc() = saved_string_buf_loc; return SUCCESS; } simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_wobbly_string() noexcept { @@ -89473,9 +98521,13 @@ simdjson_warn_unused simdjson_inline simdjson_result value_ite template simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept { std::string_view content; + // Save the string buffer location so that we can restore it after get_string + auto saved_string_buf_loc = _json_iter->string_buf_loc(); auto err = get_root_string(check_trailing, allow_replacement).get(content); if (err) { return err; } receiver = content; + // Restore the string buffer location, effectively discarding any temporary string storage + _json_iter->string_buf_loc() = saved_string_buf_loc; return SUCCESS; } simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_wobbly_string(bool check_trailing) noexcept { @@ -91647,6 +100699,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 1, "Icelake kernel should use one register per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -102961,9 +112014,13 @@ simdjson_warn_unused simdjson_inline simdjson_result value_ite template simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept { std::string_view content; + // Save the string buffer location so that we can restore it after get_string + auto saved_string_buf_loc = _json_iter->string_buf_loc(); auto err = get_string(allow_replacement).get(content); if (err) { return err; } receiver = content; + // Restore the string buffer location, effectively discarding any temporary string storage + _json_iter->string_buf_loc() = saved_string_buf_loc; return SUCCESS; } simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_wobbly_string() noexcept { @@ -103103,9 +112160,13 @@ simdjson_warn_unused simdjson_inline simdjson_result value_ite template simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept { std::string_view content; + // Save the string buffer location so that we can restore it after get_string + auto saved_string_buf_loc = _json_iter->string_buf_loc(); auto err = get_root_string(check_trailing, allow_replacement).get(content); if (err) { return err; } receiver = content; + // Restore the string buffer location, effectively discarding any temporary string storage + _json_iter->string_buf_loc() = saved_string_buf_loc; return SUCCESS; } simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_wobbly_string(bool check_trailing) noexcept { @@ -105414,6 +114475,7 @@ template struct simd8x64 { static_assert(NUM_CHUNKS == 4, "PPC64 kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64 &o) = delete; // no copy allowed simd8x64 & @@ -116706,9 +125768,13 @@ simdjson_warn_unused simdjson_inline simdjson_result value_ite template simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept { std::string_view content; + // Save the string buffer location so that we can restore it after get_string + auto saved_string_buf_loc = _json_iter->string_buf_loc(); auto err = get_string(allow_replacement).get(content); if (err) { return err; } receiver = content; + // Restore the string buffer location, effectively discarding any temporary string storage + _json_iter->string_buf_loc() = saved_string_buf_loc; return SUCCESS; } simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_wobbly_string() noexcept { @@ -116848,9 +125914,13 @@ simdjson_warn_unused simdjson_inline simdjson_result value_ite template simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept { std::string_view content; + // Save the string buffer location so that we can restore it after get_string + auto saved_string_buf_loc = _json_iter->string_buf_loc(); auto err = get_root_string(check_trailing, allow_replacement).get(content); if (err) { return err; } receiver = content; + // Restore the string buffer location, effectively discarding any temporary string storage + _json_iter->string_buf_loc() = saved_string_buf_loc; return SUCCESS; } simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_wobbly_string(bool check_trailing) noexcept { @@ -119077,6 +128147,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, "Westmere kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -119505,6 +128576,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, "Westmere kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -130767,9 +139839,13 @@ simdjson_warn_unused simdjson_inline simdjson_result value_ite template simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept { std::string_view content; + // Save the string buffer location so that we can restore it after get_string + auto saved_string_buf_loc = _json_iter->string_buf_loc(); auto err = get_string(allow_replacement).get(content); if (err) { return err; } receiver = content; + // Restore the string buffer location, effectively discarding any temporary string storage + _json_iter->string_buf_loc() = saved_string_buf_loc; return SUCCESS; } simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_wobbly_string() noexcept { @@ -130909,9 +139985,13 @@ simdjson_warn_unused simdjson_inline simdjson_result value_ite template simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept { std::string_view content; + // Save the string buffer location so that we can restore it after get_string + auto saved_string_buf_loc = _json_iter->string_buf_loc(); auto err = get_root_string(check_trailing, allow_replacement).get(content); if (err) { return err; } receiver = content; + // Restore the string buffer location, effectively discarding any temporary string storage + _json_iter->string_buf_loc() = saved_string_buf_loc; return SUCCESS; } simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_wobbly_string(bool check_trailing) noexcept { @@ -133005,6 +142085,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, "LSX kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -144303,9 +153384,13 @@ simdjson_warn_unused simdjson_inline simdjson_result value_ite template simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept { std::string_view content; + // Save the string buffer location so that we can restore it after get_string + auto saved_string_buf_loc = _json_iter->string_buf_loc(); auto err = get_string(allow_replacement).get(content); if (err) { return err; } receiver = content; + // Restore the string buffer location, effectively discarding any temporary string storage + _json_iter->string_buf_loc() = saved_string_buf_loc; return SUCCESS; } simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_wobbly_string() noexcept { @@ -144445,9 +153530,13 @@ simdjson_warn_unused simdjson_inline simdjson_result value_ite template simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept { std::string_view content; + // Save the string buffer location so that we can restore it after get_string + auto saved_string_buf_loc = _json_iter->string_buf_loc(); auto err = get_root_string(check_trailing, allow_replacement).get(content); if (err) { return err; } receiver = content; + // Restore the string buffer location, effectively discarding any temporary string storage + _json_iter->string_buf_loc() = saved_string_buf_loc; return SUCCESS; } simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_wobbly_string(bool check_trailing) noexcept { @@ -146589,6 +155678,7 @@ namespace simd { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 2, "LASX kernel should use two registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; + template simd8 get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8(); } simd8x64(const simd8x64& o) = delete; // no copy allowed simd8x64& operator=(const simd8& other) = delete; // no assignment allowed @@ -157862,9 +166952,13 @@ simdjson_warn_unused simdjson_inline simdjson_result value_ite template simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept { std::string_view content; + // Save the string buffer location so that we can restore it after get_string + auto saved_string_buf_loc = _json_iter->string_buf_loc(); auto err = get_string(allow_replacement).get(content); if (err) { return err; } receiver = content; + // Restore the string buffer location, effectively discarding any temporary string storage + _json_iter->string_buf_loc() = saved_string_buf_loc; return SUCCESS; } simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_wobbly_string() noexcept { @@ -158004,9 +167098,13 @@ simdjson_warn_unused simdjson_inline simdjson_result value_ite template simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept { std::string_view content; + // Save the string buffer location so that we can restore it after get_string + auto saved_string_buf_loc = _json_iter->string_buf_loc(); auto err = get_root_string(check_trailing, allow_replacement).get(content); if (err) { return err; } receiver = content; + // Restore the string buffer location, effectively discarding any temporary string storage + _json_iter->string_buf_loc() = saved_string_buf_loc; return SUCCESS; } simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_wobbly_string(bool check_trailing) noexcept { @@ -159649,6 +168747,13570 @@ SIMDJSON_UNTARGET_REGION #endif // SIMDJSON_LASX_ONDEMAND_H /* end file simdjson/lasx/ondemand.h */ +#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(rvv_vls) +/* including simdjson/rvv-vls/ondemand.h: #include "simdjson/rvv-vls/ondemand.h" */ +/* begin file simdjson/rvv-vls/ondemand.h */ +#ifndef SIMDJSON_RVV_VLS_ONDEMAND_H +#define SIMDJSON_RVV_VLS_ONDEMAND_H + +/* including simdjson/rvv-vls/begin.h: #include "simdjson/rvv-vls/begin.h" */ +/* begin file simdjson/rvv-vls/begin.h */ +/* defining SIMDJSON_IMPLEMENTATION to "rvv_vls" */ +#define SIMDJSON_IMPLEMENTATION rvv_vls +/* including simdjson/rvv-vls/base.h: #include "simdjson/rvv-vls/base.h" */ +/* begin file simdjson/rvv-vls/base.h */ +#ifndef SIMDJSON_RVV_VLS_BASE_H +#define SIMDJSON_RVV_VLS_BASE_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +/** + * RVV-VLS implementation. + */ +namespace rvv_vls { + +class implementation; + +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_BASE_H +/* end file simdjson/rvv-vls/base.h */ +/* including simdjson/rvv-vls/intrinsics.h: #include "simdjson/rvv-vls/intrinsics.h" */ +/* begin file simdjson/rvv-vls/intrinsics.h */ +#ifndef SIMDJSON_RVV_VLS_INTRINSICS_H +#define SIMDJSON_RVV_VLS_INTRINSICS_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include + +#define simdutf_vrgather_u8m1x2(tbl, idx) \ + __riscv_vcreate_v_u8m1_u8m2( \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m2_u8m1(idx, 0), \ + __riscv_vsetvlmax_e8m1()), \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m2_u8m1(idx, 1), \ + __riscv_vsetvlmax_e8m1())) + +#define simdutf_vrgather_u8m1x4(tbl, idx) \ + __riscv_vcreate_v_u8m1_u8m4( \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 0), \ + __riscv_vsetvlmax_e8m1()), \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 1), \ + __riscv_vsetvlmax_e8m1()), \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 2), \ + __riscv_vsetvlmax_e8m1()), \ + __riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 3), \ + __riscv_vsetvlmax_e8m1())) + +#if __riscv_zbc +#include +#endif + +#endif // SIMDJSON_RVV_VLS_INTRINSICS_H +/* end file simdjson/rvv-vls/intrinsics.h */ +/* including simdjson/rvv-vls/bitmanipulation.h: #include "simdjson/rvv-vls/bitmanipulation.h" */ +/* begin file simdjson/rvv-vls/bitmanipulation.h */ +#ifndef SIMDJSON_RVV_VLS_BITMANIPULATION_H +#define SIMDJSON_RVV_VLS_BITMANIPULATION_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { + +// We sometimes call trailing_zero on inputs that are zero, +// but the algorithms do not end up using the returned value. +// Sadly, sanitizers are not smart enough to figure it out. +SIMDJSON_NO_SANITIZE_UNDEFINED +// This function can be used safely even if not all bytes have been +// initialized. +// See issue https://github.com/simdjson/simdjson/issues/1965 +SIMDJSON_NO_SANITIZE_MEMORY +simdjson_inline int trailing_zeroes(uint64_t input_num) { + return __builtin_ctzll(input_num); +} + +/* result might be undefined when input_num is zero */ +simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) { + return input_num & (input_num-1); +} + +/* result might be undefined when input_num is zero */ +simdjson_inline int leading_zeroes(uint64_t input_num) { + return __builtin_clzll(input_num); +} + +simdjson_inline long long int count_ones(uint64_t input_num) { + return __builtin_popcountll(input_num); +} + +simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, + uint64_t *result) { + return __builtin_uaddll_overflow(value1, value2, + reinterpret_cast(result)); +} + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_BITMANIPULATION_H +/* end file simdjson/rvv-vls/bitmanipulation.h */ +/* including simdjson/rvv-vls/bitmask.h: #include "simdjson/rvv-vls/bitmask.h" */ +/* begin file simdjson/rvv-vls/bitmask.h */ +#ifndef SIMDJSON_RVV_VLS_BITMASK_H +#define SIMDJSON_RVV_VLS_BITMASK_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/intrinsics.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { + +// +// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered. +// +// For example, prefix_xor(00100100) == 00011100 +// +simdjson_inline uint64_t prefix_xor(uint64_t bitmask) { +#if __riscv_zbc + return __riscv_clmul_64(bitmask, ~(uint64_t)0); +#elif __riscv_zvbc + return __riscv_vmv_x(__riscv_vclmul(__riscv_vmv_s_x_u64m1(bitmask, 1), ~(uint64_t)0, 1)); +#else + bitmask ^= bitmask << 1; + bitmask ^= bitmask << 2; + bitmask ^= bitmask << 4; + bitmask ^= bitmask << 8; + bitmask ^= bitmask << 16; + bitmask ^= bitmask << 32; +#endif + return bitmask; +} + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_BITMASK_H + +/* end file simdjson/rvv-vls/bitmask.h */ +/* including simdjson/rvv-vls/simd.h: #include "simdjson/rvv-vls/simd.h" */ +/* begin file simdjson/rvv-vls/simd.h */ +#ifndef SIMDJSON_RVV_VLS_SIMD_H +#define SIMDJSON_RVV_VLS_SIMD_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/bitmanipulation.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/simdprune_tables.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { +namespace simd { + +#if __riscv_v_fixed_vlen >= 512 + static constexpr size_t VL8 = 512/8; + using vint8_t = vint8m1_t __attribute__((riscv_rvv_vector_bits(512))); + using vuint8_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(512))); + using vbool_t = vbool8_t __attribute__((riscv_rvv_vector_bits(512/8))); + using vbitmask_t = uint64_t; +#else + static constexpr size_t VL8 = __riscv_v_fixed_vlen/8; + using vint8_t = vint8m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen))); + using vuint8_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen))); + using vbool_t = vbool8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/8))); + #if __riscv_v_fixed_vlen == 128 + using vbitmask_t = uint16_t; + #elif __riscv_v_fixed_vlen == 256 + using vbitmask_t = uint32_t; + #endif +#endif + +#if __riscv_v_fixed_vlen == 128 + using vuint8x64_t = vuint8m4_t __attribute__((riscv_rvv_vector_bits(512))); + using vboolx64_t = vbool2_t __attribute__((riscv_rvv_vector_bits(512/8))); +#elif __riscv_v_fixed_vlen == 256 + using vuint8x64_t = vuint8m2_t __attribute__((riscv_rvv_vector_bits(512))); + using vboolx64_t = vbool4_t __attribute__((riscv_rvv_vector_bits(512/8))); +#else + using vuint8x64_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(512))); + using vboolx64_t = vbool8_t __attribute__((riscv_rvv_vector_bits(512/8))); +#endif + + template + struct simd8; + + // SIMD byte mask type (returned by things like eq and gt) + template<> + struct simd8 { + vbool_t value; + using bitmask_t = vbitmask_t; + static constexpr int SIZE = sizeof(value); + + simdjson_inline simd8(const vbool_t _value) : value(_value) {} + simdjson_inline simd8() : simd8(__riscv_vmclr_m_b8(VL8)) {} + simdjson_inline simd8(bool _value) : simd8(splat(_value)) {} + + simdjson_inline operator const vbool_t&() const { return value; } + simdjson_inline operator vbool_t&() { return value; } + + static simdjson_inline simd8 splat(bool _value) { + return __riscv_vreinterpret_b8(__riscv_vmv_v_x_u64m1(((uint64_t)!_value)-1, 1)); + } + + simdjson_inline vbitmask_t to_bitmask() const { +#if __riscv_v_fixed_vlen == 128 + return __riscv_vmv_x(__riscv_vreinterpret_u16m1(value)); +#elif __riscv_v_fixed_vlen == 256 + return __riscv_vmv_x(__riscv_vreinterpret_u32m1(value)); +#else + return __riscv_vmv_x(__riscv_vreinterpret_u64m1(value)); +#endif + } + + // Bit operations + simdjson_inline simd8 operator|(const simd8 other) const { return __riscv_vmor(*this, other, VL8); } + simdjson_inline simd8 operator&(const simd8 other) const { return __riscv_vmand(*this, other, VL8); } + simdjson_inline simd8 operator^(const simd8 other) const { return __riscv_vmxor(*this, other, VL8); } + simdjson_inline simd8 bit_andnot(const simd8 other) const { return __riscv_vmandn(other, *this, VL8); } + simdjson_inline simd8 operator~() const { return __riscv_vmnot(*this, VL8); } + simdjson_inline simd8& operator|=(const simd8 other) { auto this_cast = static_cast*>(this); *this_cast = *this_cast | other; return *this_cast; } + simdjson_inline simd8& operator&=(const simd8 other) { auto this_cast = static_cast*>(this); *this_cast = *this_cast & other; return *this_cast; } + simdjson_inline simd8& operator^=(const simd8 other) { auto this_cast = static_cast*>(this); *this_cast = *this_cast ^ other; return *this_cast; } + }; + + // Unsigned bytes + template<> + struct simd8 { + + vuint8_t value; + static constexpr int SIZE = sizeof(value); + + simdjson_inline simd8(const vuint8_t _value) : value(_value) {} + simdjson_inline simd8() : simd8(zero()) {} + simdjson_inline simd8(const uint8_t values[VL8]) : simd8(load(values)) {} + simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {} + simdjson_inline simd8(simd8 mask) : value(__riscv_vmerge_vxm_u8m1(zero(), -1, (vbool_t)mask, VL8)) {} + + simdjson_inline operator const vuint8_t&() const { return this->value; } + simdjson_inline operator vuint8_t&() { return this->value; } + + simdjson_inline simd8( + uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7, + uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15 + ) : simd8(vuint8_t{ + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + }) {} + + // Repeat 16 values as many times as necessary (usually for lookup tables) + simdjson_inline static simd8 repeat_16( + uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7, + uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15 + ) { + return simd8( + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + ); + } + + static simdjson_inline vuint8_t splat(uint8_t _value) { return __riscv_vmv_v_x_u8m1(_value, VL8); } + static simdjson_inline vuint8_t zero() { return splat(0); } + static simdjson_inline vuint8_t load(const uint8_t values[VL8]) { return __riscv_vle8_v_u8m1(values, VL8); } + + // Bit operations + simdjson_inline simd8 operator|(const simd8 other) const { return __riscv_vor_vv_u8m1( value, other, VL8); } + simdjson_inline simd8 operator&(const simd8 other) const { return __riscv_vand_vv_u8m1( value, other, VL8); } + simdjson_inline simd8 operator^(const simd8 other) const { return __riscv_vxor_vv_u8m1( value, other, VL8); } + simdjson_inline simd8 operator~() const { return __riscv_vnot_v_u8m1(value, VL8); } +#if __riscv_zvbb + simdjson_inline simd8 bit_andnot(const simd8 other) const { return __riscv_vandn_vv_u8m1(other, value, VL8); } +#else + simdjson_inline simd8 bit_andnot(const simd8 other) const { return other & ~*this; } +#endif + simdjson_inline simd8& operator|=(const simd8 other) { value = *this | other; return *this; } + simdjson_inline simd8& operator&=(const simd8 other) { value = *this & other; return *this; } + simdjson_inline simd8& operator^=(const simd8 other) { value = *this ^ other; return *this; } + + simdjson_inline simd8 operator==(const simd8 other) const { return __riscv_vmseq(value, other, VL8); } + simdjson_inline simd8 operator==(uint8_t other) const { return __riscv_vmseq(value, other, VL8); } + + template + simdjson_inline simd8 prev(const simd8 prev_chunk) const { + return __riscv_vslideup(__riscv_vslidedown(prev_chunk, VL8-N, VL8), value, N, VL8); + } + + // Store to array + simdjson_inline void store(uint8_t dst[VL8]) const { return __riscv_vse8(dst, value, VL8); } + + // Saturated math + simdjson_inline simd8 saturating_add(const simd8 other) const { return __riscv_vsaddu(value, other, VL8); } + simdjson_inline simd8 saturating_sub(const simd8 other) const { return __riscv_vssubu(value, other, VL8); } + + // Addition/subtraction are the same for signed and unsigned + simdjson_inline simd8 operator+(const simd8 other) const { return __riscv_vadd(value, other, VL8); } + simdjson_inline simd8 operator-(const simd8 other) const { return __riscv_vsub(value, other, VL8); } + simdjson_inline simd8& operator+=(const simd8 other) { value = *this + other; return *this; } + simdjson_inline simd8& operator-=(const simd8 other) { value = *this - other; return *this; } + + // Order-specific operations + simdjson_inline simd8 operator<=(const simd8 other) const { return __riscv_vmsleu(value, other, VL8); } + simdjson_inline simd8 operator>=(const simd8 other) const { return __riscv_vmsgeu(value, other, VL8); } + simdjson_inline simd8 operator<(const simd8 other) const { return __riscv_vmsltu(value, other, VL8); } + simdjson_inline simd8 operator>(const simd8 other) const { return __riscv_vmsgtu(value, other, VL8); } + + // Same as >, but instead of guaranteeing all 1's == true, false = 0 and true = nonzero. + simdjson_inline simd8 gt_bits(const simd8 other) const { return simd8(*this > other); } + // Same as <, but instead of guaranteeing all 1's == true, false = 0 and true = nonzero. + simdjson_inline simd8 lt_bits(const simd8 other) const { return simd8(*this < other); } + + // Bit-specific operations + simdjson_inline bool any_bits_set_anywhere() const { + return __riscv_vfirst(__riscv_vmsne(value, 0, VL8), VL8) >= 0; + } + simdjson_inline bool any_bits_set_anywhere(simd8 bits) const { return (*this & bits).any_bits_set_anywhere(); } + template + simdjson_inline simd8 shr() const { return __riscv_vsrl(value, N, VL8); } + template + simdjson_inline simd8 shl() const { return __riscv_vsll(value, N, VL8); } + + + // Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values) + template + simdjson_inline simd8 lookup_16(simd8 lookup_table) const { + return __riscv_vrgather(lookup_table, value, VL8); + } + + // compress inactive elements, to match AVX-512 behavior + template + simdjson_inline void compress(vbitmask_t mask, L * output) const { + mask = (vbitmask_t)~mask; +#if __riscv_v_fixed_vlen == 128 + vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u16m1(mask, 1)); +#elif __riscv_v_fixed_vlen == 256 + vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u32m1(mask, 1)); +#else + vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u64m1(mask, 1)); +#endif + __riscv_vse8_v_u8m1(output, __riscv_vcompress(value, m, VL8), count_ones(mask)); + } + + template + simdjson_inline simd8 lookup_16( + L replace0, L replace1, L replace2, L replace3, + L replace4, L replace5, L replace6, L replace7, + L replace8, L replace9, L replace10, L replace11, + L replace12, L replace13, L replace14, L replace15) const { + return lookup_16(simd8::repeat_16( + replace0, replace1, replace2, replace3, + replace4, replace5, replace6, replace7, + replace8, replace9, replace10, replace11, + replace12, replace13, replace14, replace15 + )); + } + }; + + // Signed bytes + template<> + struct simd8 { + vint8_t value; + static constexpr int SIZE = sizeof(value); + + simdjson_inline simd8(const vint8_t _value) : value(_value) {} + simdjson_inline simd8() : simd8(zero()) {} + simdjson_inline simd8(const int8_t values[VL8]) : simd8(load(values)) {} + simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {} + + simdjson_inline operator const vint8_t&() const { return this->value; } + simdjson_inline operator vint8_t&() { return this->value; } + + simdjson_inline simd8( + int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7, + int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15 + ) : simd8(vint8_t{ + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + }) {} + + // Repeat 16 values as many times as necessary (usually for lookup tables) + simdjson_inline static simd8 repeat_16( + int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7, + int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15 + ) { + return simd8( + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10,v11,v12,v13,v14,v15 + ); + } + + static simdjson_inline vint8_t splat(int8_t _value) { return __riscv_vmv_v_x_i8m1(_value, VL8); } + static simdjson_inline vint8_t zero() { return splat(0); } + static simdjson_inline vint8_t load(const int8_t values[VL8]) { return __riscv_vle8_v_i8m1(values, VL8); } + + + simdjson_inline void store(int8_t dst[VL8]) const { return __riscv_vse8(dst, value, VL8); } + + // Explicit conversion to/from unsigned + simdjson_inline explicit simd8(const vuint8_t other): simd8(__riscv_vreinterpret_i8m1(other)) {} + simdjson_inline explicit operator simd8() const { return __riscv_vreinterpret_u8m1(value); } + + // Math + simdjson_inline simd8 operator+(const simd8 other) const { return __riscv_vadd(value, other, VL8); } + simdjson_inline simd8 operator-(const simd8 other) const { return __riscv_vsub(value, other, VL8); } + simdjson_inline simd8& operator+=(const simd8 other) { value = *this + other; return *this; } + simdjson_inline simd8& operator-=(const simd8 other) { value = *this - other; return *this; } + + // Order-sensitive comparisons + simdjson_inline simd8 max_val( const simd8 other) const { return __riscv_vmax( value, other, VL8); } + simdjson_inline simd8 min_val( const simd8 other) const { return __riscv_vmin( value, other, VL8); } + simdjson_inline simd8 operator>( const simd8 other) const { return __riscv_vmsgt(value, other, VL8); } + simdjson_inline simd8 operator<( const simd8 other) const { return __riscv_vmslt(value, other, VL8); } + simdjson_inline simd8 operator==(const simd8 other) const { return __riscv_vmseq(value, other, VL8); } + + template + simdjson_inline simd8 prev(const simd8 prev_chunk) const { + return __riscv_vslideup(__riscv_vslidedown(prev_chunk, VL8-N, VL8), value, N, VL8); + } + + // Perform a lookup assuming no value is larger than 16 + template + simdjson_inline simd8 lookup_16(simd8 lookup_table) const { + return __riscv_vrgather(lookup_table, value, VL8); + } + template + simdjson_inline simd8 lookup_16( + L replace0, L replace1, L replace2, L replace3, + L replace4, L replace5, L replace6, L replace7, + L replace8, L replace9, L replace10, L replace11, + L replace12, L replace13, L replace14, L replace15) const { + return lookup_16(simd8::repeat_16( + replace0, replace1, replace2, replace3, + replace4, replace5, replace6, replace7, + replace8, replace9, replace10, replace11, + replace12, replace13, replace14, replace15 + )); + } + }; + + template + struct simd8x64; + template<> + struct simd8x64 { + static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); + vuint8x64_t value; + +#if __riscv_v_fixed_vlen >= 512 + template simd8 get() const { return value; } +#else + template simd8 get() const { return __riscv_vget_u8m1(value, idx); } +#endif + + simdjson_inline operator const vuint8x64_t&() const { return this->value; } + simdjson_inline operator vuint8x64_t&() { return this->value; } + + simd8x64(const simd8x64& o) = delete; // no copy allowed + simd8x64& operator=(const simd8& other) = delete; // no assignment allowed + simd8x64() = delete; // no default constructor allowed + +#if __riscv_v_fixed_vlen == 128 + simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m4(ptr, n)) {} +#elif __riscv_v_fixed_vlen == 256 + simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m2(ptr, n)) {} +#else + simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m1(ptr, n)) {} +#endif + + simdjson_inline void store(uint8_t ptr[64]) const { + __riscv_vse8(ptr, value, 64); + } + + simdjson_inline bool is_ascii() const { +#if __riscv_v_fixed_vlen == 128 + return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m4(value), 0, 64), 64) < 0; +#elif __riscv_v_fixed_vlen == 256 + return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m2(value), 0, 64), 64) < 0; +#else + return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m1(value), 0, 64), 64) < 0; +#endif + } + + // compress inactive elements, to match AVX-512 behavior + simdjson_inline uint64_t compress(uint64_t mask, uint8_t * output) const { + mask = ~mask; +#if __riscv_v_fixed_vlen == 128 + vboolx64_t m = __riscv_vreinterpret_b2(__riscv_vmv_s_x_u64m1(mask, 1)); +#elif __riscv_v_fixed_vlen == 256 + vboolx64_t m = __riscv_vreinterpret_b4(__riscv_vmv_s_x_u64m1(mask, 1)); +#else + vboolx64_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u64m1(mask, 1)); +#endif + size_t cnt = count_ones(mask); + __riscv_vse8(output, __riscv_vcompress(value, m, 64), cnt); + return cnt; + } + + simdjson_inline uint64_t eq(const uint8_t m) const { + return __riscv_vmv_x(__riscv_vreinterpret_u64m1(__riscv_vmseq(value, m, 64))); + } + + simdjson_inline uint64_t lteq(const uint8_t m) const { + return __riscv_vmv_x(__riscv_vreinterpret_u64m1(__riscv_vmsleu(value, m, 64))); + } + }; // struct simd8x64 + +} // namespace simd +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_SIMD_H +/* end file simdjson/rvv-vls/simd.h */ +/* including simdjson/rvv-vls/stringparsing_defs.h: #include "simdjson/rvv-vls/stringparsing_defs.h" */ +/* begin file simdjson/rvv-vls/stringparsing_defs.h */ +#ifndef SIMDJSON_RVV_VLS_STRINGPARSING_DEFS_H +#define SIMDJSON_RVV_VLS_STRINGPARSING_DEFS_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace { + +using namespace simd; + +// Holds backslashes and quotes locations. +struct backslash_and_quote { +public: + static constexpr uint64_t BYTES_PROCESSED = sizeof(simd8); + simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + + simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; } + simdjson_inline bool has_backslash() { return ((quote_bits - 1) & bs_bits) != 0; } + simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); } + simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); } + + uint64_t bs_bits; + uint64_t quote_bits; +}; // struct backslash_and_quote + +simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) { + static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes"); + simd8 v(src); + v.store(dst); + return { (v == '\\').to_bitmask(), (v == '"').to_bitmask() }; +} + +struct escaping { + static constexpr uint64_t BYTES_PROCESSED = sizeof(simd8); + simdjson_inline static escaping copy_and_find(const uint8_t *src, uint8_t *dst); + + simdjson_inline bool has_escape() { return escape_bits != 0; } + simdjson_inline int escape_index() { return trailing_zeroes(escape_bits) / 4; } + + uint64_t escape_bits; +}; // struct escaping + +simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *dst) { + static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "escaping finder must process fewer than SIMDJSON_PADDING bytes"); + simd8 v(src); + v.store(dst); + return { ((v == '"') | (v == '\\') | (v == 32)).to_bitmask() }; +} + + +} // unnamed namespace +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_RVV_VLS_STRINGPARSING_DEFS_H +/* end file simdjson/rvv-vls/stringparsing_defs.h */ +/* including simdjson/rvv-vls/numberparsing_defs.h: #include "simdjson/rvv-vls/numberparsing_defs.h" */ +/* begin file simdjson/rvv-vls/numberparsing_defs.h */ +#ifndef SIMDJSON_RVV_VLS_NUMBERPARSING_DEFS_H +#define SIMDJSON_RVV_VLS_NUMBERPARSING_DEFS_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/numberparsing_tables.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include + +#ifdef JSON_TEST_NUMBERS // for unit testing +void found_invalid_number(const uint8_t *buf); +void found_integer(int64_t result, const uint8_t *buf); +void found_unsigned_integer(uint64_t result, const uint8_t *buf); +void found_float(double result, const uint8_t *buf); +#endif + +namespace simdjson { +namespace rvv_vls { +namespace numberparsing { + +// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/ +/** @private */ +static simdjson_inline uint32_t parse_eight_digits_unrolled(const char *chars) { + uint64_t val; +#if __riscv_misaligned_fast + memcpy(&val, chars, sizeof(uint64_t)); +#else + val = __riscv_vmv_x(__riscv_vreinterpret_u64m1(__riscv_vlmul_ext_u8m1(__riscv_vle8_v_u8mf2((uint8_t*)chars, 8)))); +#endif + val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8; + val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16; + return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32); +} + +/** @private */ +static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) { + return parse_eight_digits_unrolled(reinterpret_cast(chars)); +} + +/** @private */ +simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) { + internal::value128 answer; + __uint128_t r = (static_cast<__uint128_t>(value1)) * value2; + answer.low = uint64_t(r); + answer.high = uint64_t(r >> 64); + return answer; +} + +} // namespace numberparsing +} // namespace rvv_vls +} // namespace simdjson + +#define SIMDJSON_SWAR_NUMBER_PARSING 1 + +#endif // SIMDJSON_RVV_VLS_NUMBERPARSING_DEFS_H +/* end file simdjson/rvv-vls/numberparsing_defs.h */ + +#define SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT 1 +/* end file simdjson/rvv-vls/begin.h */ +/* including simdjson/generic/ondemand/amalgamated.h for rvv_vls: #include "simdjson/generic/ondemand/amalgamated.h" */ +/* begin file simdjson/generic/ondemand/amalgamated.h for rvv_vls */ +#if defined(SIMDJSON_CONDITIONAL_INCLUDE) && !defined(SIMDJSON_GENERIC_BUILDER_DEPENDENCIES_H) +#error simdjson/generic/ondemand/dependencies.h must be included before simdjson/generic/ondemand/amalgamated.h! +#endif + +// Stuff other things depend on +/* including simdjson/generic/ondemand/base.h for rvv_vls: #include "simdjson/generic/ondemand/base.h" */ +/* begin file simdjson/generic/ondemand/base.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_BASE_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_BASE_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +/** + * A fast, simple, DOM-like interface that parses JSON as you use it. + * + * Designed for maximum speed and a lower memory profile. + */ +namespace ondemand { + +/** Represents the depth of a JSON value (number of nested arrays/objects). */ +using depth_t = int32_t; + +/** @copydoc simdjson::rvv_vls::number_type */ +using number_type = simdjson::rvv_vls::number_type; + +/** @private Position in the JSON buffer indexes */ +using token_position = const uint32_t *; + +class array; +class array_iterator; +class document; +class document_reference; +class document_stream; +class field; +class json_iterator; +enum class json_type; +struct number; +class object; +class object_iterator; +class parser; +class raw_json_string; +class token_iterator; +class value; +class value_iterator; + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_BASE_H +/* end file simdjson/generic/ondemand/base.h for rvv_vls */ +/* including simdjson/generic/ondemand/deserialize.h for rvv_vls: #include "simdjson/generic/ondemand/deserialize.h" */ +/* begin file simdjson/generic/ondemand/deserialize.h for rvv_vls */ +#if SIMDJSON_SUPPORTS_CONCEPTS + +#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { + +struct deserialize_tag; + +/// These types are deserializable in a built-in way +template struct is_builtin_deserializable : std::false_type {}; +template <> struct is_builtin_deserializable : std::true_type {}; +template <> struct is_builtin_deserializable : std::true_type {}; +template <> struct is_builtin_deserializable : std::true_type {}; +template <> struct is_builtin_deserializable : std::true_type {}; +template <> struct is_builtin_deserializable : std::true_type {}; +template <> struct is_builtin_deserializable : std::true_type {}; +template <> struct is_builtin_deserializable : std::true_type {}; +template <> struct is_builtin_deserializable : std::true_type {}; +template <> struct is_builtin_deserializable : std::true_type {}; + +template +concept is_builtin_deserializable_v = is_builtin_deserializable::value; + +template +concept custom_deserializable = tag_invocable; + +template +concept deserializable = custom_deserializable || is_builtin_deserializable_v || concepts::optional_type; + +template +concept nothrow_custom_deserializable = nothrow_tag_invocable; + +// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned. +template +concept nothrow_deserializable = nothrow_custom_deserializable || is_builtin_deserializable_v; + +/// Deserialize Tag +inline constexpr struct deserialize_tag { + using array_type = rvv_vls::ondemand::array; + using object_type = rvv_vls::ondemand::object; + using value_type = rvv_vls::ondemand::value; + using document_type = rvv_vls::ondemand::document; + using document_reference_type = rvv_vls::ondemand::document_reference; + + // Customization Point for array + template + requires custom_deserializable + simdjson_warn_unused constexpr /* error_code */ auto operator()(array_type &object, T& output) const noexcept(nothrow_custom_deserializable) { + return tag_invoke(*this, object, output); + } + + // Customization Point for object + template + requires custom_deserializable + simdjson_warn_unused constexpr /* error_code */ auto operator()(object_type &object, T& output) const noexcept(nothrow_custom_deserializable) { + return tag_invoke(*this, object, output); + } + + // Customization Point for value + template + requires custom_deserializable + simdjson_warn_unused constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable) { + return tag_invoke(*this, object, output); + } + + // Customization Point for document + template + requires custom_deserializable + simdjson_warn_unused constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable) { + return tag_invoke(*this, object, output); + } + + // Customization Point for document reference + template + requires custom_deserializable + simdjson_warn_unused constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_custom_deserializable) { + return tag_invoke(*this, object, output); + } + + +} deserialize{}; + +} // namespace simdjson + +#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H +#endif // SIMDJSON_SUPPORTS_CONCEPTS + +/* end file simdjson/generic/ondemand/deserialize.h for rvv_vls */ +/* including simdjson/generic/ondemand/value_iterator.h for rvv_vls: #include "simdjson/generic/ondemand/value_iterator.h" */ +/* begin file simdjson/generic/ondemand/value_iterator.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +/** + * Iterates through a single JSON value at a particular depth. + * + * Does not keep track of the type of value: provides methods for objects, arrays and scalars and expects + * the caller to call the right ones. + * + * @private This is not intended for external use. + */ +class value_iterator { +protected: + /** The underlying JSON iterator */ + json_iterator *_json_iter{}; + /** The depth of this value */ + depth_t _depth{}; + /** + * The starting token index for this value + */ + token_position _start_position{}; + +public: + simdjson_inline value_iterator() noexcept = default; + + /** + * Denote that we're starting a document. + */ + simdjson_inline void start_document() noexcept; + + /** + * Skips a non-iterated or partially-iterated JSON value, whether it is a scalar, array or object. + * + * Optimized for scalars. + */ + simdjson_warn_unused simdjson_inline error_code skip_child() noexcept; + + /** + * Tell whether the iterator is at the EOF mark + */ + simdjson_inline bool at_end() const noexcept; + + /** + * Tell whether the iterator is at the start of the value + */ + simdjson_inline bool at_start() const noexcept; + + /** + * Tell whether the value is open--if the value has not been used, or the array/object is still open. + */ + simdjson_inline bool is_open() const noexcept; + + /** + * Tell whether the value is at an object's first field (just after the {). + */ + simdjson_inline bool at_first_field() const noexcept; + + /** + * Abandon all iteration. + */ + simdjson_inline void abandon() noexcept; + + /** + * Get the child value as a value_iterator. + */ + simdjson_inline value_iterator child_value() const noexcept; + + /** + * Get the depth of this value. + */ + simdjson_inline int32_t depth() const noexcept; + + /** + * Get the JSON type of this value. + * + * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse". + */ + simdjson_inline simdjson_result type() const noexcept; + + /** + * @addtogroup object Object iteration + * + * Methods to iterate and find object fields. These methods generally *assume* the value is + * actually an object; the caller is responsible for keeping track of that fact. + * + * @{ + */ + + /** + * Start an object iteration. + * + * @returns Whether the object had any fields (returns false for empty). + * @error INCORRECT_TYPE if there is no opening { + */ + simdjson_warn_unused simdjson_inline simdjson_result start_object() noexcept; + /** + * Start an object iteration from the root. + * + * @returns Whether the object had any fields (returns false for empty). + * @error INCORRECT_TYPE if there is no opening { + * @error TAPE_ERROR if there is no matching } at end of document + */ + simdjson_warn_unused simdjson_inline simdjson_result start_root_object() noexcept; + /** + * Checks whether an object could be started from the root. May be called by start_root_object. + * + * @returns SUCCESS if it is possible to safely start an object from the root (document level). + * @error INCORRECT_TYPE if there is no opening { + * @error TAPE_ERROR if there is no matching } at end of document + */ + simdjson_warn_unused simdjson_inline error_code check_root_object() noexcept; + /** + * Start an object iteration after the user has already checked and moved past the {. + * + * Does not move the iterator unless the object is empty ({}). + * + * @returns Whether the object had any fields (returns false for empty). + * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. + */ + simdjson_warn_unused simdjson_inline simdjson_result started_object() noexcept; + /** + * Start an object iteration from the root, after the user has already checked and moved past the {. + * + * Does not move the iterator unless the object is empty ({}). + * + * @returns Whether the object had any fields (returns false for empty). + * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. + */ + simdjson_warn_unused simdjson_inline simdjson_result started_root_object() noexcept; + + /** + * Moves to the next field in an object. + * + * Looks for , and }. If } is found, the object is finished and the iterator advances past it. + * Otherwise, it advances to the next value. + * + * @return whether there is another field in the object. + * @error TAPE_ERROR If there is a comma missing between fields. + * @error TAPE_ERROR If there is a comma, but not enough tokens remaining to have a key, :, and value. + */ + simdjson_warn_unused simdjson_inline simdjson_result has_next_field() noexcept; + + /** + * Get the current field's key. + */ + simdjson_warn_unused simdjson_inline simdjson_result field_key() noexcept; + + /** + * Pass the : in the field and move to its value. + */ + simdjson_warn_unused simdjson_inline error_code field_value() noexcept; + + /** + * Find the next field with the given key. + * + * Assumes you have called next_field() or otherwise matched the previous value. + * + * This means the iterator must be sitting at the next key: + * + * ``` + * { "a": 1, "b": 2 } + * ^ + * ``` + * + * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to + * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may + * fail to match some keys with escapes (\u, \n, etc.). + */ + simdjson_warn_unused simdjson_inline error_code find_field(const std::string_view key) noexcept; + + /** + * Find the next field with the given key, *without* unescaping. This assumes object order: it + * will not find the field if it was already passed when looking for some *other* field. + * + * Assumes you have called next_field() or otherwise matched the previous value. + * + * This means the iterator must be sitting at the next key: + * + * ``` + * { "a": 1, "b": 2 } + * ^ + * ``` + * + * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to + * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may + * fail to match some keys with escapes (\u, \n, etc.). + */ + simdjson_warn_unused simdjson_inline simdjson_result find_field_raw(const std::string_view key) noexcept; + + /** + * Find the field with the given key without regard to order, and *without* unescaping. + * + * This is an unordered object lookup: if the field is not found initially, it will cycle around and scan from the beginning. + * + * Assumes you have called next_field() or otherwise matched the previous value. + * + * This means the iterator must be sitting at the next key: + * + * ``` + * { "a": 1, "b": 2 } + * ^ + * ``` + * + * Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to + * unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may + * fail to match some keys with escapes (\u, \n, etc.). + */ + simdjson_warn_unused simdjson_inline simdjson_result find_field_unordered_raw(const std::string_view key) noexcept; + + /** @} */ + + /** + * @addtogroup array Array iteration + * Methods to iterate over array elements. These methods generally *assume* the value is actually + * an object; the caller is responsible for keeping track of that fact. + * @{ + */ + + /** + * Check for an opening [ and start an array iteration. + * + * @returns Whether the array had any elements (returns false for empty). + * @error INCORRECT_TYPE If there is no [. + */ + simdjson_warn_unused simdjson_inline simdjson_result start_array() noexcept; + /** + * Check for an opening [ and start an array iteration while at the root. + * + * @returns Whether the array had any elements (returns false for empty). + * @error INCORRECT_TYPE If there is no [. + * @error TAPE_ERROR if there is no matching ] at end of document + */ + simdjson_warn_unused simdjson_inline simdjson_result start_root_array() noexcept; + /** + * Checks whether an array could be started from the root. May be called by start_root_array. + * + * @returns SUCCESS if it is possible to safely start an array from the root (document level). + * @error INCORRECT_TYPE If there is no [. + * @error TAPE_ERROR if there is no matching ] at end of document + */ + simdjson_warn_unused simdjson_inline error_code check_root_array() noexcept; + /** + * Start an array iteration, after the user has already checked and moved past the [. + * + * Does not move the iterator unless the array is empty ([]). + * + * @returns Whether the array had any elements (returns false for empty). + * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. + */ + simdjson_warn_unused simdjson_inline simdjson_result started_array() noexcept; + /** + * Start an array iteration from the root, after the user has already checked and moved past the [. + * + * Does not move the iterator unless the array is empty ([]). + * + * @returns Whether the array had any elements (returns false for empty). + * @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent* + * array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that + * invalidates the document. + */ + simdjson_warn_unused simdjson_inline simdjson_result started_root_array() noexcept; + + /** + * Moves to the next element in an array. + * + * Looks for , and ]. If ] is found, the array is finished and the iterator advances past it. + * Otherwise, it advances to the next value. + * + * @return Whether there is another element in the array. + * @error TAPE_ERROR If there is a comma missing between elements. + */ + simdjson_warn_unused simdjson_inline simdjson_result has_next_element() noexcept; + + /** + * Get a child value iterator. + */ + simdjson_warn_unused simdjson_inline value_iterator child() const noexcept; + + /** @} */ + + /** + * @defgroup scalar Scalar values + * @addtogroup scalar + * @{ + */ + + simdjson_warn_unused simdjson_inline simdjson_result get_string(bool allow_replacement) noexcept; + template + simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement) noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_wobbly_string() noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_raw_json_string() noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_uint64() noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_uint64_in_string() noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_int64() noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_int64_in_string() noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_double() noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_double_in_string() noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_bool() noexcept; + simdjson_warn_unused simdjson_inline simdjson_result is_null() noexcept; + simdjson_warn_unused simdjson_inline bool is_negative() noexcept; + simdjson_warn_unused simdjson_inline simdjson_result is_integer() noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_number_type() noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_number() noexcept; + + simdjson_warn_unused simdjson_inline simdjson_result get_root_string(bool check_trailing, bool allow_replacement) noexcept; + template + simdjson_warn_unused simdjson_inline error_code get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_root_wobbly_string(bool check_trailing) noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_root_raw_json_string(bool check_trailing) noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_root_uint64(bool check_trailing) noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_root_uint64_in_string(bool check_trailing) noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_root_int64(bool check_trailing) noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_root_int64_in_string(bool check_trailing) noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_root_double(bool check_trailing) noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_root_double_in_string(bool check_trailing) noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_root_bool(bool check_trailing) noexcept; + simdjson_warn_unused simdjson_inline bool is_root_negative() noexcept; + simdjson_warn_unused simdjson_inline simdjson_result is_root_integer(bool check_trailing) noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_root_number_type(bool check_trailing) noexcept; + simdjson_warn_unused simdjson_inline simdjson_result get_root_number(bool check_trailing) noexcept; + simdjson_warn_unused simdjson_inline simdjson_result is_root_null(bool check_trailing) noexcept; + + simdjson_warn_unused simdjson_inline error_code error() const noexcept; + simdjson_inline uint8_t *&string_buf_loc() noexcept; + simdjson_inline const json_iterator &json_iter() const noexcept; + simdjson_inline json_iterator &json_iter() noexcept; + + simdjson_inline void assert_is_valid() const noexcept; + simdjson_inline bool is_valid() const noexcept; + + /** @} */ +protected: + /** + * Restarts an array iteration. + * @returns Whether the array has any elements (returns false for empty). + */ + simdjson_inline simdjson_result reset_array() noexcept; + /** + * Restarts an object iteration. + * @returns Whether the object has any fields (returns false for empty). + */ + simdjson_inline simdjson_result reset_object() noexcept; + /** + * move_at_start(): moves us so that we are pointing at the beginning of + * the container. It updates the index so that at_start() is true and it + * syncs the depth. The user can then create a new container instance. + * + * Usage: used with value::count_elements(). + **/ + simdjson_inline void move_at_start() noexcept; + + /** + * move_at_container_start(): moves us so that we are pointing at the beginning of + * the container so that assert_at_container_start() passes. + * + * Usage: used with reset_array() and reset_object(). + **/ + simdjson_inline void move_at_container_start() noexcept; + /* Useful for debugging and logging purposes. */ + inline std::string to_string() const noexcept; + simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept; + + simdjson_inline simdjson_result parse_null(const uint8_t *json) const noexcept; + simdjson_inline simdjson_result parse_bool(const uint8_t *json) const noexcept; + simdjson_inline const uint8_t *peek_start() const noexcept; + simdjson_inline uint32_t peek_start_length() const noexcept; + simdjson_inline uint32_t peek_root_length() const noexcept; + + /** + * The general idea of the advance_... methods and the peek_* methods + * is that you first peek and check that you have desired type. If you do, + * and only if you do, then you advance. + * + * We used to unconditionally advance. But this made reasoning about our + * current state difficult. + * Suppose you always advance. Look at the 'value' matching the key + * "shadowable" in the following example... + * + * ({"globals":{"a":{"shadowable":[}}}}) + * + * If the user thinks it is a Boolean and asks for it, then we check the '[', + * decide it is not a Boolean, but still move into the next character ('}'). Now + * we are left pointing at '}' right after a '['. And we have not yet reported + * an error, only that we do not have a Boolean. + * + * If, instead, you just stand your ground until it is content that you know, then + * you will only even move beyond the '[' if the user tells you that you have an + * array. So you will be at the '}' character inside the array and, hopefully, you + * will then catch the error because an array cannot start with '}', but the code + * processing Boolean values does not know this. + * + * So the contract is: first call 'peek_...' and then call 'advance_...' only + * if you have determined that it is a type you can handle. + * + * Unfortunately, it makes the code more verbose, longer and maybe more error prone. + */ + + simdjson_inline void advance_scalar(const char *type) noexcept; + simdjson_inline void advance_root_scalar(const char *type) noexcept; + simdjson_inline void advance_non_root_scalar(const char *type) noexcept; + + simdjson_inline const uint8_t *peek_scalar(const char *type) noexcept; + simdjson_inline const uint8_t *peek_root_scalar(const char *type) noexcept; + simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept; + + + simdjson_warn_unused simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept; + simdjson_warn_unused simdjson_inline error_code end_container() noexcept; + + /** + * Advance to a place expecting a value (increasing depth). + * + * @return The current token (the one left behind). + * @error TAPE_ERROR If the document ended early. + */ + simdjson_inline simdjson_result advance_to_value() noexcept; + + simdjson_warn_unused simdjson_inline error_code incorrect_type_error(const char *message) const noexcept; + simdjson_warn_unused simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const noexcept; + + simdjson_inline bool is_at_start() const noexcept; + /** + * is_at_iterator_start() returns true on an array or object after it has just been + * created, whether the instance is empty or not. + * + * Usage: used by array::begin() in debug mode (SIMDJSON_DEVELOPMENT_CHECKS) + */ + simdjson_inline bool is_at_iterator_start() const noexcept; + + /** + * Assuming that we are within an object, this returns true if we + * are pointing at a key. + * + * Usage: the skip_child() method should never be used while we are pointing + * at a key inside an object. + */ + simdjson_inline bool is_at_key() const noexcept; + + inline void assert_at_start() const noexcept; + inline void assert_at_container_start() const noexcept; + inline void assert_at_root() const noexcept; + inline void assert_at_child() const noexcept; + inline void assert_at_next() const noexcept; + inline void assert_at_non_root_start() const noexcept; + + /** Get the starting position of this value */ + simdjson_inline token_position start_position() const noexcept; + + /** @copydoc error_code json_iterator::position() const noexcept; */ + simdjson_inline token_position position() const noexcept; + /** @copydoc error_code json_iterator::end_position() const noexcept; */ + simdjson_inline token_position last_position() const noexcept; + /** @copydoc error_code json_iterator::end_position() const noexcept; */ + simdjson_inline token_position end_position() const noexcept; + /** @copydoc error_code json_iterator::report_error(error_code error, const char *message) noexcept; */ + simdjson_warn_unused simdjson_inline error_code report_error(error_code error, const char *message) noexcept; + + friend class document; + friend class object; + friend class object_iterator; + friend class array; + friend class value; + friend class field; +}; // value_iterator + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +template<> +struct simdjson_result : public rvv_vls::implementation_simdjson_result_base { +public: + simdjson_inline simdjson_result(rvv_vls::ondemand::value_iterator &&value) noexcept; ///< @private + simdjson_inline simdjson_result(error_code error) noexcept; ///< @private + simdjson_inline simdjson_result() noexcept = default; +}; + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_H +/* end file simdjson/generic/ondemand/value_iterator.h for rvv_vls */ +/* including simdjson/generic/ondemand/value.h for rvv_vls: #include "simdjson/generic/ondemand/value.h" */ +/* begin file simdjson/generic/ondemand/value.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include + +namespace simdjson { + +namespace rvv_vls { +namespace ondemand { +/** + * An ephemeral JSON value returned during iteration. It is only valid for as long as you do + * not access more data in the JSON document. + */ +class value { +public: + /** + * Create a new invalid value. + * + * Exists so you can declare a variable and later assign to it before use. + */ + simdjson_inline value() noexcept = default; + + /** + * Get this value as the given type. + * + * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool + * + * You may use get_double(), get_bool(), get_uint64(), get_int64(), + * get_object(), get_array(), get_raw_json_string(), or get_string() instead. + * When SIMDJSON_SUPPORTS_CONCEPTS is set, custom types are also supported. + * + * @returns A value of the given type, parsed from the JSON. + * @returns INCORRECT_TYPE If the JSON value is not the given type. + */ + template + simdjson_inline simdjson_result get() +#if SIMDJSON_SUPPORTS_CONCEPTS + noexcept(custom_deserializable ? nothrow_custom_deserializable : true) +#else + noexcept +#endif + { + static_assert(std::is_default_constructible::value, "The specified type is not default constructible."); + T out{}; + SIMDJSON_TRY(get(out)); + return out; + } + + + /** + * Get this value as the given type. + * + * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool + * If the macro SIMDJSON_SUPPORTS_CONCEPTS is set, then custom types are also supported. + * + * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized. + * @returns INCORRECT_TYPE If the JSON value is not an object. + * @returns SUCCESS If the parse succeeded and the out parameter was set to the value. + */ + template + simdjson_warn_unused simdjson_inline error_code get(T &out) +#if SIMDJSON_SUPPORTS_CONCEPTS + noexcept(custom_deserializable ? nothrow_custom_deserializable : true) +#else + noexcept +#endif + { + #if SIMDJSON_SUPPORTS_CONCEPTS + if constexpr (custom_deserializable) { + return deserialize(*this, out); + } else if constexpr (concepts::optional_type) { + using value_type = typename std::remove_cvref_t::value_type; + + // Check if the value is null + bool is_null_value; + SIMDJSON_TRY( is_null().get(is_null_value) ); + if (is_null_value) { + out.reset(); // Set to nullopt + return SUCCESS; + } + + if (!out) { + out.emplace(); + } + return get(out.value()); + } else { + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; + } +#else // SIMDJSON_SUPPORTS_CONCEPTS + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif + } + + /** + * Cast this JSON value to an array. + * + * @returns An object that can be used to iterate the array. + * @returns INCORRECT_TYPE If the JSON value is not an array. + */ + simdjson_inline simdjson_result get_array() noexcept; + + /** + * Cast this JSON value to an object. + * + * @returns An object that can be used to look up or iterate fields. + * @returns INCORRECT_TYPE If the JSON value is not an object. + */ + simdjson_inline simdjson_result get_object() noexcept; + + /** + * Cast this JSON value to an unsigned integer. + * + * @returns A unsigned 64-bit integer. + * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer. + */ + simdjson_inline simdjson_result get_uint64() noexcept; + + /** + * Cast this JSON value (inside string) to a unsigned integer. + * + * @returns A unsigned 64-bit integer. + * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer. + */ + simdjson_inline simdjson_result get_uint64_in_string() noexcept; + + /** + * Cast this JSON value to a signed integer. + * + * @returns A signed 64-bit integer. + * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer. + */ + simdjson_inline simdjson_result get_int64() noexcept; + + /** + * Cast this JSON value (inside string) to a signed integer. + * + * @returns A signed 64-bit integer. + * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer. + */ + simdjson_inline simdjson_result get_int64_in_string() noexcept; + + /** + * Cast this JSON value to a double. + * + * @returns A double. + * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number. + */ + simdjson_inline simdjson_result get_double() noexcept; + + /** + * Cast this JSON value (inside string) to a double + * + * @returns A double. + * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number. + */ + simdjson_inline simdjson_result get_double_in_string() noexcept; + + /** + * Cast this JSON value to a string. + * + * The string is guaranteed to be valid UTF-8. + * + * Equivalent to get(). + * + * Important: a value should be consumed once. Calling get_string() twice on the same value + * is an error. + * + * In some instances, you may want to allow replacement of invalid Unicode sequences. + * You may do so by passing the allow_replacement parameter as true. In the following + * example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true + * to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode + * replacement character (U+FFFD). + * + * simdjson::ondemand::parser parser; + * auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded; + * simdjson::ondemand::document doc = parser.iterate(json); + * auto view = doc["deviceId"].get_string(true); + * + * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next + * time it parses a document or when it is destroyed. + * @returns INCORRECT_TYPE if the JSON value is not a string. + */ + simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; + + /** + * Attempts to fill the provided std::string reference with the parsed value of the current string. + * + * The string is guaranteed to be valid UTF-8. + * + * Important: a value should be consumed once. Calling get_string() twice on the same value + * is an error. + * + * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory. + * We recommend you avoid allocating an std::string unless you need to. + * + * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS. + */ + template + simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + + /** + * Cast this JSON value to a "wobbly" string. + * + * The string is may not be a valid UTF-8 string. + * See https://simonsapin.github.io/wtf-8/ + * + * Important: a value should be consumed once. Calling get_wobbly_string() twice on the same value + * is an error. + * + * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next + * time it parses a document or when it is destroyed. + * @returns INCORRECT_TYPE if the JSON value is not a string. + */ + simdjson_inline simdjson_result get_wobbly_string() noexcept; + /** + * Cast this JSON value to a raw_json_string. + * + * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n). + * + * @returns A pointer to the raw JSON for the given string. + * @returns INCORRECT_TYPE if the JSON value is not a string. + */ + simdjson_inline simdjson_result get_raw_json_string() noexcept; + + /** + * Cast this JSON value to a bool. + * + * @returns A bool value. + * @returns INCORRECT_TYPE if the JSON value is not true or false. + */ + simdjson_inline simdjson_result get_bool() noexcept; + + /** + * Checks if this JSON value is null. If and only if the value is + * null, then it is consumed (we advance). If we find a token that + * begins with 'n' but is not 'null', then an error is returned. + * + * @returns Whether the value is null. + * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'. + */ + simdjson_inline simdjson_result is_null() noexcept; + +#if SIMDJSON_EXCEPTIONS + /** + * Cast this JSON value to an instance of type T. The programmer is responsible for + * providing an implementation of get for the type T, if T is not one of the types + * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.). + * + * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types + * + * @returns An instance of type T + */ + template + explicit simdjson_inline operator T() noexcept(false); + /** + * Cast this JSON value to an array. + * + * @returns An object that can be used to iterate the array. + * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array. + */ + simdjson_inline operator array() noexcept(false); + /** + * Cast this JSON value to an object. + * + * @returns An object that can be used to look up or iterate fields. + * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object. + */ + simdjson_inline operator object() noexcept(false); + /** + * Cast this JSON value to an unsigned integer. + * + * @returns A signed 64-bit integer. + * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer. + */ + simdjson_inline operator uint64_t() noexcept(false); + /** + * Cast this JSON value to a signed integer. + * + * @returns A signed 64-bit integer. + * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer. + */ + simdjson_inline operator int64_t() noexcept(false); + /** + * Cast this JSON value to a double. + * + * @returns A double. + * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number. + */ + simdjson_inline operator double() noexcept(false); + /** + * Cast this JSON value to a string. + * + * The string is guaranteed to be valid UTF-8. + * + * Equivalent to get(). + * + * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next + * time it parses a document or when it is destroyed. + * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string. + */ + simdjson_inline operator std::string_view() noexcept(false); + /** + * Cast this JSON value to a raw_json_string. + * + * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n). + * + * @returns A pointer to the raw JSON for the given string. + * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string. + */ + simdjson_inline operator raw_json_string() noexcept(false); + /** + * Cast this JSON value to a bool. + * + * @returns A bool value. + * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false. + */ + simdjson_inline operator bool() noexcept(false); +#endif + + /** + * Begin array iteration. + * + * Part of the std::iterable interface. + * + * @returns INCORRECT_TYPE If the JSON value is not an array. + */ + simdjson_inline simdjson_result begin() & noexcept; + /** + * Sentinel representing the end of the array. + * + * Part of the std::iterable interface. + */ + simdjson_inline simdjson_result end() & noexcept; + /** + * This method scans the array and counts the number of elements. + * The count_elements method should always be called before you have begun + * iterating through the array: it is expected that you are pointing at + * the beginning of the array. + * The runtime complexity is linear in the size of the array. After + * calling this function, if successful, the array is 'rewinded' at its + * beginning as if it had never been accessed. If the JSON is malformed (e.g., + * there is a missing comma), then an error is returned and it is no longer + * safe to continue. + * + * Performance hint: You should only call count_elements() as a last + * resort as it may require scanning the document twice or more. + */ + simdjson_inline simdjson_result count_elements() & noexcept; + /** + * This method scans the object and counts the number of key-value pairs. + * The count_fields method should always be called before you have begun + * iterating through the object: it is expected that you are pointing at + * the beginning of the object. + * The runtime complexity is linear in the size of the object. After + * calling this function, if successful, the object is 'rewinded' at its + * beginning as if it had never been accessed. If the JSON is malformed (e.g., + * there is a missing comma), then an error is returned and it is no longer + * safe to continue. + * + * To check that an object is empty, it is more performant to use + * the is_empty() method on the object instance. + * + * Performance hint: You should only call count_fields() as a last + * resort as it may require scanning the document twice or more. + */ + simdjson_inline simdjson_result count_fields() & noexcept; + /** + * Get the value at the given index in the array. This function has linear-time complexity. + * This function should only be called once on an array instance since the array iterator is not reset between each call. + * + * @return The value at the given index, or: + * - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length + */ + simdjson_inline simdjson_result at(size_t index) noexcept; + /** + * Look up a field by name on an object (order-sensitive). By order-sensitive, we mean that + * fields must be accessed in the order they appear in the JSON text (although you can + * skip fields). See find_field_unordered() and operator[] for an order-insensitive version. + * + * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the + * JSON `{ "x": 1, "y": 2, "z": 3 }`: + * + * ```cpp + * simdjson::ondemand::parser parser; + * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded); + * double z = obj.find_field("z"); + * double y = obj.find_field("y"); + * double x = obj.find_field("x"); + * ``` + * If you have multiple fields with a matching key ({"x": 1, "x": 1}) be mindful + * that only one field is returned. + + * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys. + * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`. + * + * @param key The key to look up. + * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object. + */ + simdjson_inline simdjson_result find_field(std::string_view key) noexcept; + /** @overload simdjson_inline simdjson_result find_field(std::string_view key) noexcept; */ + simdjson_inline simdjson_result find_field(const char *key) noexcept; + + /** + * Look up a field by name on an object, without regard to key order. + * + * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies + * and often appears negligible. It starts out normally, starting out at the last field; but if + * the field is not found, it scans from the beginning of the object to see if it missed it. That + * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object + * in question is large. The fact that the extra code is there also bumps the executable size. + * + * We default operator[] on find_field_unordered() for convenience. + * It is the default because it would be highly surprising (and hard to debug) if the + * default behavior failed to look up a field just because it was in the wrong order--and many + * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order. + * + * If you have multiple fields with a matching key ({"x": 1, "x": 1}) be mindful + * that only one field is returned. + * + * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the + * field as not there when they are not in order). + * + * @param key The key to look up. + * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object. + */ + simdjson_inline simdjson_result find_field_unordered(std::string_view key) noexcept; + /** @overload simdjson_inline simdjson_result find_field_unordered(std::string_view key) noexcept; */ + simdjson_inline simdjson_result find_field_unordered(const char *key) noexcept; + /** @overload simdjson_inline simdjson_result find_field_unordered(std::string_view key) noexcept; */ + simdjson_inline simdjson_result operator[](std::string_view key) noexcept; + /** @overload simdjson_inline simdjson_result find_field_unordered(std::string_view key) noexcept; */ + simdjson_inline simdjson_result operator[](const char *key) noexcept; + simdjson_result operator[](int) noexcept = delete; + + /** + * Get the type of this JSON value. It does not validate or consume the value. + * E.g., you must still call "is_null()" to check that a value is null even if + * "type()" returns json_type::null. + * + * NOTE: If you're only expecting a value to be one type (a typical case), it's generally + * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just + * let it throw an exception). + * + * @return The type of JSON value (json_type::array, json_type::object, json_type::string, + * json_type::number, json_type::boolean, or json_type::null). + * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse". + */ + simdjson_inline simdjson_result type() noexcept; + + /** + * Checks whether the value is a scalar (string, number, null, Boolean). + * Returns false when there it is an array or object. + * + * @returns true if the type is string, number, null, Boolean + * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse". + */ + simdjson_inline simdjson_result is_scalar() noexcept; + /** + * Checks whether the value is a string. + * + * @returns true if the type is string + * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse". + */ + simdjson_inline simdjson_result is_string() noexcept; + + /** + * Checks whether the value is a negative number. + * + * @returns true if the number if negative. + */ + simdjson_inline bool is_negative() noexcept; + /** + * Checks whether the value is an integer number. Note that + * this requires to partially parse the number string. If + * the value is determined to be an integer, it may still + * not parse properly as an integer in subsequent steps + * (e.g., it might overflow). + * + * Performance note: if you call this function systematically + * before parsing a number, you may have fallen for a performance + * anti-pattern. + * + * @returns true if the number if negative. + */ + simdjson_inline simdjson_result is_integer() noexcept; + /** + * Determine the number type (integer or floating-point number) as quickly + * as possible. This function does not fully validate the input. It is + * useful when you only need to classify the numbers, without parsing them. + * + * If you are planning to retrieve the value or you need full validation, + * consider using the get_number() method instead: it will fully parse + * and validate the input, and give you access to the type: + * get_number().get_number_type(). + * + * get_number_type() is number_type::unsigned_integer if we have + * an integer greater or equal to 9223372036854775808. + * get_number_type() is number_type::signed_integer if we have an + * integer that is less than 9223372036854775808. + * get_number_type() is number_type::big_integer for integers that do not fit in 64 bits, + * in which case the digit_count is set to the length of the big integer string. + * Otherwise, get_number_type() has value number_type::floating_point_number. + * + * This function requires processing the number string, but it is expected + * to be faster than get_number().get_number_type() because it is does not + * parse the number value. + * + * @returns the type of the number + */ + simdjson_inline simdjson_result get_number_type() noexcept; + + /** + * Attempt to parse an ondemand::number. An ondemand::number may + * contain an integer value or a floating-point value, the simdjson + * library will autodetect the type. Thus it is a dynamically typed + * number. Before accessing the value, you must determine the detected + * type. + * + * number.get_number_type() is number_type::signed_integer if we have + * an integer in [-9223372036854775808,9223372036854775808) + * You can recover the value by calling number.get_int64() and you + * have that number.is_int64() is true. + * + * number.get_number_type() is number_type::unsigned_integer if we have + * an integer in [9223372036854775808,18446744073709551616) + * You can recover the value by calling number.get_uint64() and you + * have that number.is_uint64() is true. + * + * For integers that do not fit in 64 bits, the function returns BIGINT_ERROR error code. + * + * Otherwise, number.get_number_type() has value number_type::floating_point_number + * and we have a binary64 number. + * You can recover the value by calling number.get_double() and you + * have that number.is_double() is true. + * + * You must check the type before accessing the value: it is an error + * to call "get_int64()" when number.get_number_type() is not + * number_type::signed_integer and when number.is_int64() is false. + * + * Performance note: this is designed with performance in mind. When + * calling 'get_number()', you scan the number string only once, determining + * efficiently the type and storing it in an efficient manner. + */ + simdjson_warn_unused simdjson_inline simdjson_result get_number() noexcept; + + /** + * Get the raw JSON for this token. + * + * The string_view will always point into the input buffer. + * + * The string_view will start at the beginning of the token, and include the entire token + * *as well as all spaces until the next token (or EOF).* This means, for example, that a + * string token always begins with a " and is always terminated by the final ", possibly + * followed by a number of spaces. + * + * The string_view is *not* null-terminated. However, if this is a scalar (string, number, + * boolean, or null), the character after the end of the string_view is guaranteed to be + * a non-space token. + * + * Tokens include: + * - { + * - [ + * - "a string (possibly with UTF-8 or backslashed characters like \\\")". + * - -1.2e-100 + * - true + * - false + * - null + * + * See also value::raw_json(). + */ + simdjson_inline std::string_view raw_json_token() noexcept; + + /** + * Get a string_view pointing at this value in the JSON document. + * If this element is an array or an object, it consumes the array or the object + * and returns a string_view instance corresponding to the + * array as represented in JSON. It points inside the original document. + * If this element is a scalar (string, number, Boolean, null), it returns what + * raw_json_token() would return. + */ + simdjson_inline simdjson_result raw_json() noexcept; + + /** + * Returns the current location in the document if in bounds. + */ + simdjson_inline simdjson_result current_location() noexcept; + + /** + * Returns the current depth in the document if in bounds. + * + * E.g., + * 0 = finished with document + * 1 = document root value (could be [ or {, not yet known) + * 2 = , or } inside root array/object + * 3 = key or value inside root array/object. + */ + simdjson_inline int32_t current_depth() const noexcept; + + /** + * Get the value associated with the given JSON pointer. We use the RFC 6901 + * https://tools.ietf.org/html/rfc6901 standard. + * + * ondemand::parser parser; + * auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded; + * auto doc = parser.iterate(json); + * doc.at_pointer("/foo/a/1") == 20 + * + * It is allowed for a key to be the empty string: + * + * ondemand::parser parser; + * auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded; + * auto doc = parser.iterate(json); + * doc.at_pointer("//a/1") == 20 + * + * Note that at_pointer() called on the document automatically calls the document's rewind + * method between each call. It invalidates all previously accessed arrays, objects and values + * that have not been consumed. + * + * Calling at_pointer() on non-document instances (e.g., arrays and objects) is not + * standardized (by RFC 6901). We provide some experimental support for JSON pointers + * on non-document instances. Yet it is not the case when calling at_pointer on an array + * or an object instance: there is no rewind and no invalidation. + * + * You may only call at_pointer on an array after it has been created, but before it has + * been first accessed. When calling at_pointer on an array, the pointer is advanced to + * the location indicated by the JSON pointer (in case of success). It is no longer possible + * to call at_pointer on the same array. + * + * You may call at_pointer more than once on an object, but each time the pointer is advanced + * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding + * key (as well as the current key) can no longer be used with following JSON pointer calls. + * + * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching + * + * @return The value associated with the given JSON pointer, or: + * - NO_SUCH_FIELD if a field does not exist in an object + * - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length + * - INCORRECT_TYPE if a non-integer is used to access an array + * - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed + */ + simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; + + /** + * Get the value associated with the given JSONPath expression. We only support + * JSONPath queries that trivially convertible to JSON Pointer queries: key + * names and array indices. + * + * @return The value associated with the given JSONPath expression, or: + * - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails + * - NO_SUCH_FIELD if a field does not exist in an object + * - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length + * - INCORRECT_TYPE if a non-integer is used to access an array + */ + simdjson_inline simdjson_result at_path(std::string_view at_path) noexcept; + + /** + * Get all values matching the given JSONPath expression with wildcard support. + * Supports wildcard character (*) for arrays or ".*" for objects. + * + * @param json_path JSONPath expression with wildcards + * @return Vector of values matching the wildcard pattern + */ + simdjson_inline simdjson_result> at_path_with_wildcard(std::string_view json_path) noexcept; + +protected: + /** + * Create a value. + */ + simdjson_inline value(const value_iterator &iter) noexcept; + + /** + * Skip this value, allowing iteration to continue. + */ + simdjson_inline void skip() noexcept; + + /** + * Start a value at the current position. + * + * (It should already be started; this is just a self-documentation method.) + */ + static simdjson_inline value start(const value_iterator &iter) noexcept; + + /** + * Resume a value. + */ + static simdjson_inline value resume(const value_iterator &iter) noexcept; + + /** + * Get the object, starting or resuming it as necessary + */ + simdjson_inline simdjson_result start_or_resume_object() noexcept; + + // simdjson_inline void log_value(const char *type) const noexcept; + // simdjson_inline void log_error(const char *message) const noexcept; + + value_iterator iter{}; + + friend class document; + friend class array_iterator; + friend class field; + friend class object; + friend struct simdjson_result; + friend struct simdjson_result; + friend class field; +}; + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +template<> +struct simdjson_result : public rvv_vls::implementation_simdjson_result_base { +public: + simdjson_inline simdjson_result(rvv_vls::ondemand::value &&value) noexcept; ///< @private + simdjson_inline simdjson_result(error_code error) noexcept; ///< @private + simdjson_inline simdjson_result() noexcept = default; + + simdjson_inline simdjson_result get_array() noexcept; + simdjson_inline simdjson_result get_object() noexcept; + + simdjson_inline simdjson_result get_uint64() noexcept; + simdjson_inline simdjson_result get_uint64_in_string() noexcept; + simdjson_inline simdjson_result get_int64() noexcept; + simdjson_inline simdjson_result get_int64_in_string() noexcept; + simdjson_inline simdjson_result get_double() noexcept; + simdjson_inline simdjson_result get_double_in_string() noexcept; + simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; + template + simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + simdjson_inline simdjson_result get_wobbly_string() noexcept; + simdjson_inline simdjson_result get_raw_json_string() noexcept; + simdjson_inline simdjson_result get_bool() noexcept; + simdjson_inline simdjson_result is_null() noexcept; + + template simdjson_inline simdjson_result get() noexcept; + + template simdjson_inline error_code get(T &out) noexcept; + +#if SIMDJSON_EXCEPTIONS + template + explicit simdjson_inline operator T() noexcept(false); + simdjson_inline operator rvv_vls::ondemand::array() noexcept(false); + simdjson_inline operator rvv_vls::ondemand::object() noexcept(false); + simdjson_inline operator uint64_t() noexcept(false); + simdjson_inline operator int64_t() noexcept(false); + simdjson_inline operator double() noexcept(false); + simdjson_inline operator std::string_view() noexcept(false); + simdjson_inline operator rvv_vls::ondemand::raw_json_string() noexcept(false); + simdjson_inline operator bool() noexcept(false); +#endif + simdjson_inline simdjson_result count_elements() & noexcept; + simdjson_inline simdjson_result count_fields() & noexcept; + simdjson_inline simdjson_result at(size_t index) noexcept; + simdjson_inline simdjson_result begin() & noexcept; + simdjson_inline simdjson_result end() & noexcept; + + /** + * Look up a field by name on an object (order-sensitive). By order-sensitive, we mean that + * fields must be accessed in the order they appear in the JSON text (although you can + * skip fields). See find_field_unordered() and operator[] for an order-insensitive version. + * + * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the + * JSON `{ "x": 1, "y": 2, "z": 3 }`: + * + * ```cpp + * simdjson::ondemand::parser parser; + * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded); + * double z = obj.find_field("z"); + * double y = obj.find_field("y"); + * double x = obj.find_field("x"); + * ``` + * + * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys. + * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`. + * + * @param key The key to look up. + * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object. + */ + simdjson_inline simdjson_result find_field(std::string_view key) noexcept; + /** @overload simdjson_inline simdjson_result find_field(std::string_view key) noexcept; */ + simdjson_inline simdjson_result find_field(const char *key) noexcept; + + /** + * Look up a field by name on an object, without regard to key order. + * + * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies + * and often appears negligible. It starts out normally, starting out at the last field; but if + * the field is not found, it scans from the beginning of the object to see if it missed it. That + * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object + * in question is large. The fact that the extra code is there also bumps the executable size. + * + * We default operator[] on find_field_unordered() for convenience. + * It is the default because it would be highly surprising (and hard to debug) if the + * default behavior failed to look up a field just because it was in the wrong order--and many + * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order. + * + * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the + * field as not there when they are not in order). + * + * @param key The key to look up. + * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object. + */ + simdjson_inline simdjson_result find_field_unordered(std::string_view key) noexcept; + /** @overload simdjson_inline simdjson_result find_field_unordered(std::string_view key) noexcept; */ + simdjson_inline simdjson_result find_field_unordered(const char *key) noexcept; + /** @overload simdjson_inline simdjson_result find_field_unordered(std::string_view key) noexcept; */ + simdjson_inline simdjson_result operator[](std::string_view key) noexcept; + /** @overload simdjson_inline simdjson_result find_field_unordered(std::string_view key) noexcept; */ + simdjson_inline simdjson_result operator[](const char *key) noexcept; + simdjson_result operator[](int) noexcept = delete; + + /** + * Get the type of this JSON value. It does not validate or consume the value. + * E.g., you must still call "is_null()" to check that a value is null even if + * "type()" returns json_type::null. + * + * Given a valid JSON document, the answer can be one of + * simdjson::ondemand::json_type::object, + * simdjson::ondemand::json_type::array, + * simdjson::ondemand::json_type::string, + * simdjson::ondemand::json_type::number, + * simdjson::ondemand::json_type::boolean, + * simdjson::ondemand::json_type::null. + * + * Starting with simdjson 4.0, this function will return simdjson::ondemand::json_type::unknown + * given a bad token. + * This allows you to identify a case such as {"key": NaN} and identify the NaN value. + * The simdjson::ondemand::json_type::unknown value should only happen with non-valid JSON. + * + * NOTE: If you're only expecting a value to be one type (a typical case), it's generally + * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just + * let it throw an exception). + */ + simdjson_inline simdjson_result type() noexcept; + simdjson_inline simdjson_result is_scalar() noexcept; + simdjson_inline simdjson_result is_string() noexcept; + simdjson_inline simdjson_result is_negative() noexcept; + simdjson_inline simdjson_result is_integer() noexcept; + simdjson_inline simdjson_result get_number_type() noexcept; + simdjson_inline simdjson_result get_number() noexcept; + + /** @copydoc simdjson_inline std::string_view value::raw_json_token() const noexcept */ + simdjson_inline simdjson_result raw_json_token() noexcept; + simdjson_inline simdjson_result raw_json() noexcept; + + /** @copydoc simdjson_inline simdjson_result current_location() noexcept */ + simdjson_inline simdjson_result current_location() noexcept; + /** @copydoc simdjson_inline int32_t current_depth() const noexcept */ + simdjson_inline simdjson_result current_depth() const noexcept; + simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; + simdjson_inline simdjson_result at_path(std::string_view json_path) noexcept; + simdjson_inline simdjson_result> at_path_with_wildcard(std::string_view json_path) noexcept; +}; + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_H +/* end file simdjson/generic/ondemand/value.h for rvv_vls */ +/* including simdjson/generic/ondemand/logger.h for rvv_vls: #include "simdjson/generic/ondemand/logger.h" */ +/* begin file simdjson/generic/ondemand/logger.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +// Logging should be free unless SIMDJSON_VERBOSE_LOGGING is set. Importantly, it is critical +// that the call to the log functions be side-effect free. Thus, for example, you should not +// create temporary std::string instances. +namespace logger { + +enum class log_level : int32_t { + info = 0, + error = 1 +}; + +#if SIMDJSON_VERBOSE_LOGGING + static constexpr const bool LOG_ENABLED = true; +#else + static constexpr const bool LOG_ENABLED = false; +#endif + +// We do not want these functions to be 'really inlined' since real inlining is +// for performance purposes and if you are using the loggers, you do not care about +// performance (or should not). +static inline void log_headers() noexcept; +// If args are provided, title will be treated as format string +template +static inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept; +template +static inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept; +static inline void log_event(const json_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept; +static inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept; +static inline void log_value(const json_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept; +static inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept; +static inline void log_start_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept; +static inline void log_end_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept; + +static inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail="") noexcept; +static inline void log_error(const json_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept; + +static inline void log_event(const value_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept; +static inline void log_value(const value_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept; +static inline void log_start_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept; +static inline void log_end_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept; +static inline void log_error(const value_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept; + +} // namespace logger +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_H +/* end file simdjson/generic/ondemand/logger.h for rvv_vls */ +/* including simdjson/generic/ondemand/token_iterator.h for rvv_vls: #include "simdjson/generic/ondemand/token_iterator.h" */ +/* begin file simdjson/generic/ondemand/token_iterator.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +/** + * Iterates through JSON tokens (`{` `}` `[` `]` `,` `:` `""` `123` `true` `false` `null`) + * detected by stage 1. + * + * @private This is not intended for external use. + */ +class token_iterator { +public: + /** + * Create a new invalid token_iterator. + * + * Exists so you can declare a variable and later assign to it before use. + */ + simdjson_inline token_iterator() noexcept = default; + simdjson_inline token_iterator(token_iterator &&other) noexcept = default; + simdjson_inline token_iterator &operator=(token_iterator &&other) noexcept = default; + simdjson_inline token_iterator(const token_iterator &other) noexcept = default; + simdjson_inline token_iterator &operator=(const token_iterator &other) noexcept = default; + + /** + * Advance to the next token (returning the current one). + */ + simdjson_inline const uint8_t *return_current_and_advance() noexcept; + /** + * Reports the current offset in bytes from the start of the underlying buffer. + */ + simdjson_inline uint32_t current_offset() const noexcept; + /** + * Get the JSON text for a given token (relative). + * + * This is not null-terminated; it is a view into the JSON. + * + * @param delta The relative position of the token to retrieve. e.g. 0 = current token, + * 1 = next token, -1 = prev token. + * + * TODO consider a string_view, assuming the length will get stripped out by the optimizer when + * it is not used... + */ + simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept; + /** + * Get the maximum length of the JSON text for a given token. + * + * The length will include any whitespace at the end of the token. + * + * @param delta The relative position of the token to retrieve. e.g. 0 = current token, + * 1 = next token, -1 = prev token. + */ + simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept; + + /** + * Get the JSON text for a given token. + * + * This is not null-terminated; it is a view into the JSON. + * + * @param position The position of the token. + * + */ + simdjson_inline const uint8_t *peek(token_position position) const noexcept; + /** + * Get the maximum length of the JSON text for a given token. + * + * The length will include any whitespace at the end of the token. + * + * @param position The position of the token. + */ + simdjson_inline uint32_t peek_length(token_position position) const noexcept; + /** + * Get the maximum length of the JSON text for a root token. + * + * The length will include any whitespace at the end of the token. + * + * @param position The position of the token (start of the document). + */ + simdjson_inline uint32_t peek_root_length(token_position position) const noexcept; + /** + * Return the current index. + */ + simdjson_inline token_position position() const noexcept; + /** + * Reset to a previously saved index. + */ + simdjson_inline void set_position(token_position target_position) noexcept; + + // NOTE: we don't support a full C++ iterator interface, because we expect people to make + // different calls to advance the iterator based on *their own* state. + + simdjson_inline bool operator==(const token_iterator &other) const noexcept; + simdjson_inline bool operator!=(const token_iterator &other) const noexcept; + simdjson_inline bool operator>(const token_iterator &other) const noexcept; + simdjson_inline bool operator>=(const token_iterator &other) const noexcept; + simdjson_inline bool operator<(const token_iterator &other) const noexcept; + simdjson_inline bool operator<=(const token_iterator &other) const noexcept; + +protected: + simdjson_inline token_iterator(const uint8_t *buf, token_position position) noexcept; + + /** + * Get the index of the JSON text for a given token (relative). + * + * This is not null-terminated; it is a view into the JSON. + * + * @param delta The relative position of the token to retrieve. e.g. 0 = current token, + * 1 = next token, -1 = prev token. + */ + simdjson_inline uint32_t peek_index(int32_t delta=0) const noexcept; + /** + * Get the index of the JSON text for a given token. + * + * This is not null-terminated; it is a view into the JSON. + * + * @param position The position of the token. + * + */ + simdjson_inline uint32_t peek_index(token_position position) const noexcept; + + const uint8_t *buf{}; + token_position _position{}; + + friend class json_iterator; + friend class value_iterator; + friend class object; + template + friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept; + template + friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept; +}; + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +template<> +struct simdjson_result : public rvv_vls::implementation_simdjson_result_base { +public: + simdjson_inline simdjson_result(rvv_vls::ondemand::token_iterator &&value) noexcept; ///< @private + simdjson_inline simdjson_result(error_code error) noexcept; ///< @private + simdjson_inline simdjson_result() noexcept = default; + simdjson_inline ~simdjson_result() noexcept = default; ///< @private +}; + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_H +/* end file simdjson/generic/ondemand/token_iterator.h for rvv_vls */ +/* including simdjson/generic/ondemand/json_iterator.h for rvv_vls: #include "simdjson/generic/ondemand/json_iterator.h" */ +/* begin file simdjson/generic/ondemand/json_iterator.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +/** + * Iterates through JSON tokens, keeping track of depth and string buffer. + * + * @private This is not intended for external use. + */ +class json_iterator { +protected: + token_iterator token{}; + ondemand::parser *parser{}; + /** + * Next free location in the string buffer. + * + * Used by raw_json_string::unescape() to have a place to unescape strings to. + */ + uint8_t *_string_buf_loc{}; + /** + * JSON error, if there is one. + * + * INCORRECT_TYPE and NO_SUCH_FIELD are *not* stored here, ever. + * + * PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first + * iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If + * this is not elided, we should make sure it's at least not using up a register. Failing that, + * we should store it in document so there's only one of them. + */ + error_code error{SUCCESS}; + /** + * Depth of the current token in the JSON. + * + * - 0 = finished with document + * - 1 = document root value (could be [ or {, not yet known) + * - 2 = , or } inside root array/object + * - 3 = key or value inside root array/object. + */ + depth_t _depth{}; + /** + * Beginning of the document indexes. + * Normally we have root == parser->implementation->structural_indexes.get() + * but this may differ, especially in streaming mode (where we have several + * documents); + */ + token_position _root{}; + /** + * Normally, a json_iterator operates over a single document, but in + * some cases, we may have a stream of documents. This attribute is meant + * as meta-data: the json_iterator works the same irrespective of the + * value of this attribute. + */ + bool _streaming{false}; + +public: + simdjson_inline json_iterator() noexcept = default; + simdjson_inline json_iterator(json_iterator &&other) noexcept; + simdjson_inline json_iterator &operator=(json_iterator &&other) noexcept; + simdjson_inline explicit json_iterator(const json_iterator &other) noexcept = default; + simdjson_inline json_iterator &operator=(const json_iterator &other) noexcept = default; + /** + * Skips a JSON value, whether it is a scalar, array or object. + */ + simdjson_warn_unused simdjson_inline error_code skip_child(depth_t parent_depth) noexcept; + + /** + * Tell whether the iterator is still at the start + */ + simdjson_inline bool at_root() const noexcept; + + /** + * Tell whether we should be expected to run in streaming + * mode (iterating over many documents). It is pure metadata + * that does not affect how the iterator works. It is used by + * start_root_array() and start_root_object(). + */ + simdjson_inline bool streaming() const noexcept; + + /** + * Get the root value iterator + */ + simdjson_inline token_position root_position() const noexcept; + /** + * Assert that we are at the document depth (== 1) + */ + simdjson_inline void assert_at_document_depth() const noexcept; + /** + * Assert that we are at the root of the document + */ + simdjson_inline void assert_at_root() const noexcept; + + /** + * Tell whether the iterator is at the EOF mark + */ + simdjson_inline bool at_end() const noexcept; + + /** + * Tell whether the iterator is live (has not been moved). + */ + simdjson_inline bool is_alive() const noexcept; + + /** + * Abandon this iterator, setting depth to 0 (as if the document is finished). + */ + simdjson_inline void abandon() noexcept; + + /** + * Advance the current token without modifying depth. + */ + simdjson_inline const uint8_t *return_current_and_advance() noexcept; + + /** + * Returns true if there is a single token in the index (i.e., it is + * a JSON with a scalar value such as a single number). + * + * @return whether there is a single token + */ + simdjson_inline bool is_single_token() const noexcept; + + /** + * Assert that there are at least the given number of tokens left. + * + * Has no effect in release builds. + */ + simdjson_inline void assert_more_tokens(uint32_t required_tokens=1) const noexcept; + /** + * Assert that the given position addresses an actual token (is within bounds). + * + * Has no effect in release builds. + */ + simdjson_inline void assert_valid_position(token_position position) const noexcept; + /** + * Get the JSON text for a given token (relative). + * + * This is not null-terminated; it is a view into the JSON. + * + * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token. + * + * TODO consider a string_view, assuming the length will get stripped out by the optimizer when + * it is not used ... + */ + simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept; + /** + * Get the maximum length of the JSON text for the current token (or relative). + * + * The length will include any whitespace at the end of the token. + * + * @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token. + */ + simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept; + /** + * Get a pointer to the current location in the input buffer. + * + * This is not null-terminated; it is a view into the JSON. + * + * You may be pointing outside of the input buffer: it is not generally + * safe to dereference this pointer. + */ + simdjson_inline const uint8_t *unsafe_pointer() const noexcept; + /** + * Get the JSON text for a given token. + * + * This is not null-terminated; it is a view into the JSON. + * + * @param position The position of the token to retrieve. + * + * TODO consider a string_view, assuming the length will get stripped out by the optimizer when + * it is not used ... + */ + simdjson_inline const uint8_t *peek(token_position position) const noexcept; + /** + * Get the maximum length of the JSON text for the current token (or relative). + * + * The length will include any whitespace at the end of the token. + * + * @param position The position of the token to retrieve. + */ + simdjson_inline uint32_t peek_length(token_position position) const noexcept; + /** + * Get the maximum length of the JSON text for the current root token. + * + * The length will include any whitespace at the end of the token. + * + * @param position The position of the token to retrieve. + */ + simdjson_inline uint32_t peek_root_length(token_position position) const noexcept; + /** + * Get the JSON text for the last token in the document. + * + * This is not null-terminated; it is a view into the JSON. + * + * TODO consider a string_view, assuming the length will get stripped out by the optimizer when + * it is not used ... + */ + simdjson_inline const uint8_t *peek_last() const noexcept; + + /** + * Ascend one level. + * + * Validates that the depth - 1 == parent_depth. + * + * @param parent_depth the expected parent depth. + */ + simdjson_inline void ascend_to(depth_t parent_depth) noexcept; + + /** + * Descend one level. + * + * Validates that the new depth == child_depth. + * + * @param child_depth the expected child depth. + */ + simdjson_inline void descend_to(depth_t child_depth) noexcept; + simdjson_inline void descend_to(depth_t child_depth, int32_t delta) noexcept; + + /** + * Get current depth. + */ + simdjson_inline depth_t depth() const noexcept; + + /** + * Get current (writeable) location in the string buffer. + */ + simdjson_inline uint8_t *&string_buf_loc() noexcept; + + /** + * Report an unrecoverable error, preventing further iteration. + * + * @param error The error to report. Must not be SUCCESS, UNINITIALIZED, INCORRECT_TYPE, or NO_SUCH_FIELD. + * @param message An error message to report with the error. + */ + simdjson_warn_unused simdjson_inline error_code report_error(error_code error, const char *message) noexcept; + + /** + * Log error, but don't stop iteration. + * @param error The error to report. Must be INCORRECT_TYPE, or NO_SUCH_FIELD. + * @param message An error message to report with the error. + */ + simdjson_warn_unused simdjson_inline error_code optional_error(error_code error, const char *message) noexcept; + + /** + * Take an input in json containing max_len characters and attempt to copy it over to tmpbuf, a buffer with + * N bytes of capacity. It will return false if N is too small (smaller than max_len) of if it is zero. + * The buffer (tmpbuf) is padded with space characters. + */ + simdjson_warn_unused simdjson_inline bool copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept; + + simdjson_inline token_position position() const noexcept; + /** + * Write the raw_json_string to the string buffer and return a string_view. + * Each raw_json_string should be unescaped once, or else the string buffer might + * overflow. + */ + simdjson_inline simdjson_result unescape(raw_json_string in, bool allow_replacement) noexcept; + simdjson_inline simdjson_result unescape_wobbly(raw_json_string in) noexcept; + + simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept; + + simdjson_warn_unused simdjson_inline error_code consume_character(char c) noexcept; +#if SIMDJSON_DEVELOPMENT_CHECKS + simdjson_inline token_position start_position(depth_t depth) const noexcept; + simdjson_inline void set_start_position(depth_t depth, token_position position) noexcept; +#endif + + /* Useful for debugging and logging purposes. */ + inline std::string to_string() const noexcept; + + /** + * Returns the current location in the document if in bounds. + */ + inline simdjson_result current_location() const noexcept; + + /** + * Updates this json iterator so that it is back at the beginning of the document, + * as if it had just been created. + */ + inline void rewind() noexcept; + /** + * This checks whether the {,},[,] are balanced so that the document + * ends with proper zero depth. This requires scanning the whole document + * and it may be expensive. It is expected that it will be rarely called. + * It does not attempt to match { with } and [ with ]. + */ + inline bool balanced() const noexcept; +protected: + simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser) noexcept; +#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON + simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser, bool streaming) noexcept; +#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON + /// The last token before the end + simdjson_inline token_position last_position() const noexcept; + /// The token *at* the end. This points at gibberish and should only be used for comparison. + simdjson_inline token_position end_position() const noexcept; + /// The end of the buffer. + simdjson_inline token_position end() const noexcept; + + friend class document; + friend class document_stream; + friend class object; + friend class array; + friend class value; + friend class raw_json_string; + friend class parser; + friend class value_iterator; + friend class field; + template + friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept; + template + friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept; +}; // json_iterator + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +template<> +struct simdjson_result : public rvv_vls::implementation_simdjson_result_base { +public: + simdjson_inline simdjson_result(rvv_vls::ondemand::json_iterator &&value) noexcept; ///< @private + simdjson_inline simdjson_result(error_code error) noexcept; ///< @private + + simdjson_inline simdjson_result() noexcept = default; +}; + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_H +/* end file simdjson/generic/ondemand/json_iterator.h for rvv_vls */ +/* including simdjson/generic/ondemand/json_type.h for rvv_vls: #include "simdjson/generic/ondemand/json_type.h" */ +/* begin file simdjson/generic/ondemand/json_type.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +/** + * The type of a JSON value. + */ +enum class json_type { + unknown=0, + // Start at 1 to catch uninitialized / default values more easily + array=1, ///< A JSON array ( [ 1, 2, 3 ... ] ) + object, ///< A JSON object ( { "a": 1, "b" 2, ... } ) + number, ///< A JSON number ( 1 or -2.3 or 4.5e6 ...) + string, ///< A JSON string ( "a" or "hello world\n" ...) + boolean, ///< A JSON boolean (true or false) + null ///< A JSON null (null) +}; + +/** + * A type representing a JSON number. + * The design of the struct is deliberately straight-forward. All + * functions return standard values with no error check. + */ +struct number { + + /** + * return the automatically determined type of + * the number: number_type::floating_point_number, + * number_type::signed_integer or number_type::unsigned_integer. + * + * enum class number_type { + * floating_point_number=1, /// a binary64 number + * signed_integer, /// a signed integer that fits in a 64-bit word using two's complement + * unsigned_integer /// a positive integer larger or equal to 1<<63 + * }; + */ + simdjson_inline ondemand::number_type get_number_type() const noexcept; + /** + * return true if the automatically determined type of + * the number is number_type::unsigned_integer. + */ + simdjson_inline bool is_uint64() const noexcept; + /** + * return the value as a uint64_t, only valid if is_uint64() is true. + */ + simdjson_inline uint64_t get_uint64() const noexcept; + simdjson_inline operator uint64_t() const noexcept; + + /** + * return true if the automatically determined type of + * the number is number_type::signed_integer. + */ + simdjson_inline bool is_int64() const noexcept; + /** + * return the value as a int64_t, only valid if is_int64() is true. + */ + simdjson_inline int64_t get_int64() const noexcept; + simdjson_inline operator int64_t() const noexcept; + + + /** + * return true if the automatically determined type of + * the number is number_type::floating_point_number. + */ + simdjson_inline bool is_double() const noexcept; + /** + * return the value as a double, only valid if is_double() is true. + */ + simdjson_inline double get_double() const noexcept; + simdjson_inline operator double() const noexcept; + + /** + * Convert the number to a double. Though it always succeed, the conversion + * may be lossy if the number cannot be represented exactly. + */ + simdjson_inline double as_double() const noexcept; + + +protected: + /** + * The next block of declaration is designed so that we can call the number parsing + * functions on a number type. They are protected and should never be used outside + * of the core simdjson library. + */ + friend class value_iterator; + template + friend error_code numberparsing::write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer); + template + friend error_code numberparsing::parse_number(const uint8_t *const src, W &writer); + /** Store a signed 64-bit value to the number. */ + simdjson_inline void append_s64(int64_t value) noexcept; + /** Store an unsigned 64-bit value to the number. */ + simdjson_inline void append_u64(uint64_t value) noexcept; + /** Store a double value to the number. */ + simdjson_inline void append_double(double value) noexcept; + /** Specifies that the value is a double, but leave it undefined. */ + simdjson_inline void skip_double() noexcept; + /** + * End of friend declarations. + */ + + /** + * Our attributes are a union type (size = 64 bits) + * followed by a type indicator. + */ + union { + double floating_point_number; + int64_t signed_integer; + uint64_t unsigned_integer; + } payload{0}; + number_type type{number_type::signed_integer}; +}; + +/** + * Write the JSON type to the output stream + * + * @param out The output stream. + * @param type The json_type. + */ +inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept; + +#if SIMDJSON_EXCEPTIONS +/** + * Send JSON type to an output stream. + * + * @param out The output stream. + * @param type The json_type. + * @throw simdjson_error if the result being printed has an error. If there is an error with the + * underlying output stream, that error will be propagated (simdjson_error will not be + * thrown). + */ +inline std::ostream& operator<<(std::ostream& out, simdjson_result &type) noexcept(false); +#endif + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +template<> +struct simdjson_result : public rvv_vls::implementation_simdjson_result_base { +public: + simdjson_inline simdjson_result(rvv_vls::ondemand::json_type &&value) noexcept; ///< @private + simdjson_inline simdjson_result(error_code error) noexcept; ///< @private + simdjson_inline simdjson_result() noexcept = default; + simdjson_inline ~simdjson_result() noexcept = default; ///< @private +}; + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_H +/* end file simdjson/generic/ondemand/json_type.h for rvv_vls */ +/* including simdjson/generic/ondemand/raw_json_string.h for rvv_vls: #include "simdjson/generic/ondemand/raw_json_string.h" */ +/* begin file simdjson/generic/ondemand/raw_json_string.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +/** + * A string escaped per JSON rules, terminated with quote ("). They are used to represent + * unescaped keys inside JSON documents. + * + * (In other words, a pointer to the beginning of a string, just after the start quote, inside a + * JSON file.) + * + * This class is deliberately simplistic and has little functionality. You can + * compare a raw_json_string instance with an unescaped C string, but + * that is nearly all you can do. + * + * The raw_json_string is unescaped. If you wish to write an unescaped version of it to your own + * buffer, you may do so using the parser.unescape(string, buff) method, using an ondemand::parser + * instance. Doing so requires you to have a sufficiently large buffer. + * + * The raw_json_string instances originate typically from field instance which in turn represent + * key-value pairs from object instances. From a field instance, you get the raw_json_string + * instance by calling key(). You can, if you want a more usable string_view instance, call + * the unescaped_key() method on the field instance. You may also create a raw_json_string from + * any other string value, with the value.get_raw_json_string() method. Again, you can get + * a more usable string_view instance by calling get_string(). + * + */ +class raw_json_string { +public: + /** + * Create a new invalid raw_json_string. + * + * Exists so you can declare a variable and later assign to it before use. + */ + simdjson_inline raw_json_string() noexcept = default; + + /** + * Create a new invalid raw_json_string pointed at the given location in the JSON. + * + * The given location must be just *after* the beginning quote (") in the JSON file. + * + * It *must* be terminated by a ", and be a valid JSON string. + */ + simdjson_inline raw_json_string(const uint8_t * _buf) noexcept; + /** + * Get the raw pointer to the beginning of the string in the JSON (just after the "). + * + * It is possible for this function to return a null pointer if the instance + * has outlived its existence. + */ + simdjson_inline const char * raw() const noexcept; + + /** + * Get the character at index i. This is unchecked. + * [0] when the string is of length 0 returns the final quote ("). + */ + simdjson_inline char operator[](size_t i) const noexcept; + + /** + * This compares the current instance to the std::string_view target: returns true if + * they are byte-by-byte equal (no escaping is done) on target.size() characters, + * and if the raw_json_string instance has a quote character at byte index target.size(). + * We never read more than length + 1 bytes in the raw_json_string instance. + * If length is smaller than target.size(), this will return false. + * + * The std::string_view instance may contain any characters. However, the caller + * is responsible for setting length so that length bytes may be read in the + * raw_json_string. + * + * Performance: the comparison may be done using memcmp which may be efficient + * for long strings. + */ + simdjson_inline bool unsafe_is_equal(size_t length, std::string_view target) const noexcept; + + /** + * This compares the current instance to the std::string_view target: returns true if + * they are byte-by-byte equal (no escaping is done). + * The std::string_view instance should not contain unescaped quote characters: + * the caller is responsible for this check. See is_free_from_unescaped_quote. + * + * Performance: the comparison is done byte-by-byte which might be inefficient for + * long strings. + * + * If target is a compile-time constant, and your compiler likes you, + * you should be able to do the following without performance penalty... + * + * static_assert(raw_json_string::is_free_from_unescaped_quote(target), ""); + * s.unsafe_is_equal(target); + */ + simdjson_inline bool unsafe_is_equal(std::string_view target) const noexcept; + + /** + * This compares the current instance to the C string target: returns true if + * they are byte-by-byte equal (no escaping is done). + * The provided C string should not contain an unescaped quote character: + * the caller is responsible for this check. See is_free_from_unescaped_quote. + * + * If target is a compile-time constant, and your compiler likes you, + * you should be able to do the following without performance penalty... + * + * static_assert(raw_json_string::is_free_from_unescaped_quote(target), ""); + * s.unsafe_is_equal(target); + */ + simdjson_inline bool unsafe_is_equal(const char* target) const noexcept; + + /** + * This compares the current instance to the std::string_view target: returns true if + * they are byte-by-byte equal (no escaping is done). + */ + simdjson_inline bool is_equal(std::string_view target) const noexcept; + + /** + * This compares the current instance to the C string target: returns true if + * they are byte-by-byte equal (no escaping is done). + */ + simdjson_inline bool is_equal(const char* target) const noexcept; + + /** + * Returns true if target is free from unescaped quote. If target is known at + * compile-time, we might expect the computation to happen at compile time with + * many compilers (not all!). + */ + static simdjson_inline bool is_free_from_unescaped_quote(std::string_view target) noexcept; + static simdjson_inline bool is_free_from_unescaped_quote(const char* target) noexcept; + +private: + + + /** + * This will set the inner pointer to zero, effectively making + * this instance unusable. + */ + simdjson_inline void consume() noexcept { buf = nullptr; } + + /** + * Checks whether the inner pointer is non-null and thus usable. + */ + simdjson_inline simdjson_warn_unused bool alive() const noexcept { return buf != nullptr; } + + /** + * Unescape this JSON string, replacing \\ with \, \n with newline, etc. + * The result will be a valid UTF-8. + * + * ## IMPORTANT: string_view lifetime + * + * The string_view is only valid until the next parse() call on the parser. + * + * @param iter A json_iterator, which contains a buffer where the string will be written. + * @param allow_replacement Whether we allow replacement of invalid surrogate pairs. + */ + simdjson_inline simdjson_warn_unused simdjson_result unescape(json_iterator &iter, bool allow_replacement) const noexcept; + + /** + * Unescape this JSON string, replacing \\ with \, \n with newline, etc. + * The result may not be a valid UTF-8. https://simonsapin.github.io/wtf-8/ + * + * ## IMPORTANT: string_view lifetime + * + * The string_view is only valid until the next parse() call on the parser. + * + * @param iter A json_iterator, which contains a buffer where the string will be written. + */ + simdjson_inline simdjson_warn_unused simdjson_result unescape_wobbly(json_iterator &iter) const noexcept; + const uint8_t * buf{}; + friend class object; + friend class field; + friend class parser; + friend struct simdjson_result; +}; + +simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &, const raw_json_string &) noexcept; + +/** + * Comparisons between raw_json_string and std::string_view instances are potentially unsafe: the user is responsible + * for providing a string with no unescaped quote. Note that unescaped quotes cannot be present in valid JSON strings. + */ +simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept; +simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept; +simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept; +simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept; + + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +template<> +struct simdjson_result : public rvv_vls::implementation_simdjson_result_base { +public: + simdjson_inline simdjson_result(rvv_vls::ondemand::raw_json_string &&value) noexcept; ///< @private + simdjson_inline simdjson_result(error_code error) noexcept; ///< @private + simdjson_inline simdjson_result() noexcept = default; + simdjson_inline ~simdjson_result() noexcept = default; ///< @private + + simdjson_inline simdjson_result raw() const noexcept; + simdjson_inline char operator[](size_t) const noexcept; + simdjson_inline simdjson_warn_unused simdjson_result unescape(rvv_vls::ondemand::json_iterator &iter, bool allow_replacement) const noexcept; + simdjson_inline simdjson_warn_unused simdjson_result unescape_wobbly(rvv_vls::ondemand::json_iterator &iter) const noexcept; +}; +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H +/* end file simdjson/generic/ondemand/raw_json_string.h for rvv_vls */ +/* including simdjson/generic/ondemand/parser.h for rvv_vls: #include "simdjson/generic/ondemand/parser.h" */ +/* begin file simdjson/generic/ondemand/parser.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include +#include + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +/** + * The default batch size for document_stream instances for this On-Demand kernel. + * Note that different On-Demand kernel may use a different DEFAULT_BATCH_SIZE value + * in the future. + */ +static constexpr size_t DEFAULT_BATCH_SIZE = 1000000; +/** + * Some adversary might try to set the batch size to 0 or 1, which might cause problems. + * We set a minimum of 32B since anything else is highly likely to be an error. In practice, + * most users will want a much larger batch size. + * + * All non-negative MINIMAL_BATCH_SIZE values should be 'safe' except that, obviously, no JSON + * document can ever span 0 or 1 byte and that very large values would create memory allocation issues. + */ +static constexpr size_t MINIMAL_BATCH_SIZE = 32; + +/** + * A JSON fragment iterator. + * + * This holds the actual iterator as well as the buffer for writing strings. + */ +class parser { +public: + /** + * Create a JSON parser. + * + * The new parser will have zero capacity. + */ + inline explicit parser(size_t max_capacity = SIMDJSON_MAXSIZE_BYTES) noexcept; + + inline parser(parser &&other) noexcept = default; + simdjson_inline parser(const parser &other) = delete; + simdjson_inline parser &operator=(const parser &other) = delete; + simdjson_inline parser &operator=(parser &&other) noexcept = default; + + /** Deallocate the JSON parser. */ + inline ~parser() noexcept = default; + + /** + * Start iterating an on-demand JSON document. + * + * ondemand::parser parser; + * document doc = parser.iterate(json); + * + * It is expected that the content is a valid UTF-8 file, containing a valid JSON document. + * Otherwise the iterate method may return an error. In particular, the whole input should be + * valid: we do not attempt to tolerate incorrect content either before or after a JSON + * document. If there is a UTF-8 BOM, the parser skips it. + * + * ### IMPORTANT: Validate what you use + * + * Calling iterate on an invalid JSON document may not immediately trigger an error. The call to + * iterate does not parse and validate the whole document. + * + * ### IMPORTANT: Buffer Lifetime + * + * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as + * long as the document iteration. + * + * ### IMPORTANT: Document Lifetime + * + * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during + * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before + * you call parse() again or destroy the parser. + * + * ### REQUIRED: Buffer Padding + * + * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what + * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you + * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the + * SIMDJSON_PADDING bytes to avoid runtime warnings. + * + * ### std::string references + * + * If you pass a mutable std::string reference (std::string&), the parser will seek to extend + * its capacity to SIMDJSON_PADDING bytes beyond the end of the string. + * + * Whenever you pass an std::string reference, the parser will access the bytes beyond the end of + * the string but before the end of the allocated memory (std::string::capacity()). + * If you are using a sanitizer that checks for reading uninitialized bytes or std::string's + * container-overflow checks, you may encounter sanitizer warnings. + * You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the + * string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view + * which can be be passed to the parser's iterate function: + * + * std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )"; + * document doc = parser.iterate(simdjson::pad(json)); + * + * @param json The JSON to parse. + * @param len The length of the JSON. + * @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING). + * + * @return The document, or an error: + * - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes. + * - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory + * allocation fails. + * - EMPTY if the document is all whitespace. + * - UTF8_ERROR if the document is not valid UTF-8. + * - UNESCAPED_CHARS if a string contains control characters that must be escaped + * - UNCLOSED_STRING if there is an unclosed string in the document. + */ + simdjson_warn_unused simdjson_result iterate(padded_string_view json) & noexcept; +#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON + simdjson_warn_unused simdjson_result iterate_allow_incomplete_json(padded_string_view json) & noexcept; +#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON + /** @overload simdjson_result iterate(padded_string_view json) & noexcept */ + simdjson_warn_unused simdjson_result iterate(const char *json, size_t len, size_t capacity) & noexcept; + /** @overload simdjson_result iterate(padded_string_view json) & noexcept */ + simdjson_warn_unused simdjson_result iterate(const uint8_t *json, size_t len, size_t capacity) & noexcept; + /** @overload simdjson_result iterate(padded_string_view json) & noexcept */ + simdjson_warn_unused simdjson_result iterate(std::string_view json, size_t capacity) & noexcept; + /** @overload simdjson_result iterate(padded_string_view json) & noexcept */ + simdjson_warn_unused simdjson_result iterate(const std::string &json) & noexcept; + /** @overload simdjson_result iterate(padded_string_view json) & noexcept + The string instance might be have its capacity extended. Note that this can still + result in AddressSanitizer: container-overflow in some cases. */ + simdjson_warn_unused simdjson_result iterate(std::string &json) & noexcept; + /** @overload simdjson_result iterate(padded_string_view json) & noexcept */ + simdjson_warn_unused simdjson_result iterate(const simdjson_result &json) & noexcept; + /** @overload simdjson_result iterate(padded_string_view json) & noexcept */ + simdjson_warn_unused simdjson_result iterate(const simdjson_result &json) & noexcept; + /** @overload simdjson_result iterate(padded_string_view json) & noexcept */ + simdjson_warn_unused simdjson_result iterate(padded_string &&json) & noexcept = delete; + + /** + * @private + * + * Start iterating an on-demand JSON document. + * + * ondemand::parser parser; + * json_iterator doc = parser.iterate(json); + * + * ### IMPORTANT: Buffer Lifetime + * + * Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as + * long as the document iteration. + * + * ### IMPORTANT: Document Lifetime + * + * Only one iteration at a time can happen per parser, and the parser *must* be kept alive during + * iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before + * you call parse() again or destroy the parser. + * + * The ondemand::document instance holds the iterator. The document must remain in scope + * while you are accessing instances of ondemand::value, ondemand::object, ondemand::array. + * + * ### REQUIRED: Buffer Padding + * + * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what + * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you + * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the + * SIMDJSON_PADDING bytes to avoid runtime warnings. + * + * @param json The JSON to parse. + * + * @return The iterator, or an error: + * - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes. + * - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory + * allocation fails. + * - EMPTY if the document is all whitespace. + * - UTF8_ERROR if the document is not valid UTF-8. + * - UNESCAPED_CHARS if a string contains control characters that must be escaped + * - UNCLOSED_STRING if there is an unclosed string in the document. + */ + simdjson_warn_unused simdjson_result iterate_raw(padded_string_view json) & noexcept; + + + /** + * Parse a buffer containing many JSON documents. + * + * auto json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )"_padded; + * ondemand::parser parser; + * ondemand::document_stream docs = parser.iterate_many(json); + * for (auto & doc : docs) { + * std::cout << doc["foo"] << std::endl; + * } + * // Prints 1 2 3 + * + * No copy of the input buffer is made. + * + * The function is lazy: it may be that no more than one JSON document at a time is parsed. + * + * The caller is responsabile to ensure that the input string data remains unchanged and is + * not deleted during the loop. + * + * ### Format + * + * The buffer must contain a series of one or more JSON documents, concatenated into a single + * buffer, separated by ASCII whitespace. It effectively parses until it has a fully valid document, + * then starts parsing the next document at that point. (It does this with more parallelism and + * lookahead than you might think, though.) + * + * documents that consist of an object or array may omit the whitespace between them, concatenating + * with no separator. Documents that consist of a single primitive (i.e. documents that are not + * arrays or objects) MUST be separated with ASCII whitespace. + * + * The characters inside a JSON document, and between JSON documents, must be valid Unicode (UTF-8). + * If there is a UTF-8 BOM, the parser skips it. + * + * The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse. + * Setting batch_size to excessively large or excessively small values may impact negatively the + * performance. + * + * ### Threads + * + * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the + * hood to do some lookahead. + * + * ### REQUIRED: Buffer Padding + * + * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what + * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you + * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the + * SIMDJSON_PADDING bytes to avoid runtime warnings. + * + * This is checked automatically with all iterate_many function calls, except for the two + * that take pointers (const char* or const uint8_t*). + * + * ### Threads + * + * ### Parser Capacity + * + * If the parser's current capacity is less than batch_size, it will allocate enough capacity + * to handle it (up to max_capacity). + * + * @param buf The concatenated JSON to parse. + * @param len The length of the concatenated JSON. + * @param batch_size The batch size to use. MUST be larger than the largest document. The sweet + * spot is cache-related: small enough to fit in cache, yet big enough to + * parse as many documents as possible in one tight loop. + * Defaults to 10MB, which has been a reasonable sweet spot in our tests. + * @param allow_comma_separated (defaults on false) This allows a mode where the documents are + * separated by commas instead of whitespace. It comes with a performance + * penalty because the entire document is indexed at once (and the document must be + * less than 4 GB), and there is no multithreading. In this mode, the batch_size parameter + * is effectively ignored, as it is set to at least the document size. + * @return The stream, or an error. An empty input will yield 0 documents rather than an EMPTY error. Errors: + * - MEMALLOC if the parser does not have enough capacity and memory allocation fails + * - CAPACITY if the parser does not have enough capacity and batch_size > max_capacity. + * - other json errors if parsing fails. You should not rely on these errors to always the same for the + * same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware). + */ + inline simdjson_result iterate_many(const uint8_t *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept; + /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */ + inline simdjson_result iterate_many(padded_string_view json, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept; + /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */ + inline simdjson_result iterate_many(const char *buf, size_t len, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept; + /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */ + inline simdjson_result iterate_many(const std::string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept; + /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) + the string might be automatically padded with up to SIMDJSON_PADDING whitespace characters */ + inline simdjson_result iterate_many(std::string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept; + /** @overload parse_many(const uint8_t *buf, size_t len, size_t batch_size) */ + inline simdjson_result iterate_many(const padded_string &s, size_t batch_size = DEFAULT_BATCH_SIZE, bool allow_comma_separated = false) noexcept; + /** @private We do not want to allow implicit conversion from C string to std::string. */ + simdjson_result iterate_many(const char *buf, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept = delete; + + /** The capacity of this parser (the largest document it can process). */ + simdjson_pure simdjson_inline size_t capacity() const noexcept; + /** The maximum capacity of this parser (the largest document it is allowed to process). */ + simdjson_pure simdjson_inline size_t max_capacity() const noexcept; + simdjson_inline void set_max_capacity(size_t max_capacity) noexcept; + /** + * The maximum depth of this parser (the most deeply nested objects and arrays it can process). + * This parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true. + * The document's instance current_depth() method should be used to monitor the parsing + * depth and limit it if desired. + */ + simdjson_pure simdjson_inline size_t max_depth() const noexcept; + + /** + * Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length + * and `max_depth` depth. + * + * The max_depth parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true. + * The document's instance current_depth() method should be used to monitor the parsing + * depth and limit it if desired. + * + * @param capacity The new capacity. + * @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH. + * @return The error, if there is one. + */ + simdjson_warn_unused error_code allocate(size_t capacity, size_t max_depth=DEFAULT_MAX_DEPTH) noexcept; + + #ifdef SIMDJSON_THREADS_ENABLED + /** + * The parser instance can use threads when they are available to speed up some + * operations. It is enabled by default. Changing this attribute will change the + * behavior of the parser for future operations. + */ + bool threaded{true}; + #else + /** + * When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads. + */ + bool threaded{false}; + #endif + /** + * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer. + * The result must be valid UTF-8. + * The provided pointer is advanced to the end of the string by reference, and a string_view instance + * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least + * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer. + * + * This unescape function is a low-level function. If you want a more user-friendly approach, you should + * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string() + * instead of get_raw_json_string()). + * + * ## IMPORTANT: string_view lifetime + * + * The string_view is only valid as long as the bytes in dst. + * + * @param raw_json_string input + * @param dst A pointer to a buffer at least large enough to write this string as well as + * an additional SIMDJSON_PADDING bytes. + * @param allow_replacement Whether we allow a replacement if the input string contains unmatched surrogate pairs. + * @return A string_view pointing at the unescaped string in dst + * @error STRING_ERROR if escapes are incorrect. + */ + simdjson_inline simdjson_result unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement = false) const noexcept; + + /** + * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer. + * The result may not be valid UTF-8. See https://simonsapin.github.io/wtf-8/ + * The provided pointer is advanced to the end of the string by reference, and a string_view instance + * is returned. You can ensure that your buffer is large enough by allocating a block of memory at least + * as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer. + * + * This unescape function is a low-level function. If you want a more user-friendly approach, you should + * avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string() + * instead of get_raw_json_string()). + * + * ## IMPORTANT: string_view lifetime + * + * The string_view is only valid as long as the bytes in dst. + * + * @param raw_json_string input + * @param dst A pointer to a buffer at least large enough to write this string as well as + * an additional SIMDJSON_PADDING bytes. + * @return A string_view pointing at the unescaped string in dst + * @error STRING_ERROR if escapes are incorrect. + */ + simdjson_inline simdjson_result unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept; + +#if SIMDJSON_DEVELOPMENT_CHECKS + /** + * Returns true if string_buf_loc is outside of the allocated range for the + * the string buffer. When true, it indicates that the string buffer has overflowed. + * This is a development-time check that is not needed in production. It can be + * used to detect buffer overflows in the string buffer and usafe usage of the + * string buffer. + */ + bool string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept; +#endif + + /** + * Get a unique parser instance corresponding to the current thread. + * This instance can be safely used within the current thread, but it should + * not be passed to other threads. + * + * A parser should only be used for one document at a time. + * + * Our simdjson::from functions use this parser instance. + * + * You can free the related parser by calling release_parser(). + */ + static simdjson_inline simdjson_warn_unused ondemand::parser& get_parser(); + /** + * Release the parser instance initialized by get_parser() and all the + * associated resources (memory). Returns true if a parser instance + * was released. + */ + static simdjson_inline bool release_parser(); + +private: + friend bool release_parser(); + friend ondemand::parser& get_parser(); + /** Get the thread-local parser instance, allocates it if needed */ + static simdjson_inline simdjson_warn_unused std::unique_ptr& get_parser_instance(); + /** Get the thread-local parser instance, it might be null */ + static simdjson_inline simdjson_warn_unused std::unique_ptr& get_threadlocal_parser_if_exists(); + /** @private [for benchmarking access] The implementation to use */ + std::unique_ptr implementation{}; + size_t _capacity{0}; + size_t _max_capacity; + size_t _max_depth{DEFAULT_MAX_DEPTH}; + std::unique_ptr string_buf{}; + +#if SIMDJSON_DEVELOPMENT_CHECKS + std::unique_ptr start_positions{}; +#endif + + friend class json_iterator; + friend class document_stream; +}; + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +template<> +struct simdjson_result : public rvv_vls::implementation_simdjson_result_base { +public: + simdjson_inline simdjson_result(rvv_vls::ondemand::parser &&value) noexcept; ///< @private + simdjson_inline simdjson_result(error_code error) noexcept; ///< @private + simdjson_inline simdjson_result() noexcept = default; +}; + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H +/* end file simdjson/generic/ondemand/parser.h for rvv_vls */ + +// All other declarations +/* including simdjson/generic/ondemand/array.h for rvv_vls: #include "simdjson/generic/ondemand/array.h" */ +/* begin file simdjson/generic/ondemand/array.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +/** + * A forward-only JSON array. + */ +class array { +public: + /** + * Create a new invalid array. + * + * Exists so you can declare a variable and later assign to it before use. + */ + simdjson_inline array() noexcept = default; + + /** + * Begin array iteration. + * + * Part of the std::iterable interface. + */ + simdjson_inline simdjson_result begin() noexcept; + /** + * Sentinel representing the end of the array. + * + * Part of the std::iterable interface. + */ + simdjson_inline simdjson_result end() noexcept; + /** + * This method scans the array and counts the number of elements. + * The count_elements method should always be called before you have begun + * iterating through the array: it is expected that you are pointing at + * the beginning of the array. + * The runtime complexity is linear in the size of the array. After + * calling this function, if successful, the array is 'rewinded' at its + * beginning as if it had never been accessed. If the JSON is malformed (e.g., + * there is a missing comma), then an error is returned and it is no longer + * safe to continue. Note that count_elements() does not validate the JSON values, + * only the structure of the array. + * + * To check that an array is empty, it is more performant to use + * the is_empty() method. + */ + simdjson_inline simdjson_result count_elements() & noexcept; + /** + * This method scans the beginning of the array and checks whether the + * array is empty. + * The runtime complexity is constant time. After + * calling this function, if successful, the array is 'rewinded' at its + * beginning as if it had never been accessed. If the JSON is malformed (e.g., + * there is a missing comma), then an error is returned and it is no longer + * safe to continue. + */ + simdjson_inline simdjson_result is_empty() & noexcept; + /** + * Reset the iterator so that we are pointing back at the + * beginning of the array. You should still consume values only once even if you + * can iterate through the array more than once. If you unescape a string + * within the array more than once, you have unsafe code. Note that rewinding + * an array means that you may need to reparse it anew: it is not a free + * operation. + * + * @returns true if the array contains some elements (not empty) + */ + inline simdjson_result reset() & noexcept; + /** + * Get the value associated with the given JSON pointer. We use the RFC 6901 + * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node + * as the root of its own JSON document. + * + * ondemand::parser parser; + * auto json = R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])"_padded; + * auto doc = parser.iterate(json); + * doc.at_pointer("/0/foo/a/1") == 20 + * + * Note that at_pointer() called on the document automatically calls the document's rewind + * method between each call. It invalidates all previously accessed arrays, objects and values + * that have not been consumed. Yet it is not the case when calling at_pointer on an array + * instance: there is no rewind and no invalidation. + * + * You may only call at_pointer on an array after it has been created, but before it has + * been first accessed. When calling at_pointer on an array, the pointer is advanced to + * the location indicated by the JSON pointer (in case of success). It is no longer possible + * to call at_pointer on the same array. + * + * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching. + * + * @return The value associated with the given JSON pointer, or: + * - NO_SUCH_FIELD if a field does not exist in an object + * - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length + * - INCORRECT_TYPE if a non-integer is used to access an array + * - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed + */ + inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; + + /** + * Get the value associated with the given JSONPath expression. We only support + * JSONPath queries that trivially convertible to JSON Pointer queries: key + * names and array indices. + * + * https://www.rfc-editor.org/rfc/rfc9535 (RFC 9535) + * + * @return The value associated with the given JSONPath expression, or: + * - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails + * - NO_SUCH_FIELD if a field does not exist in an object + * - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length + * - INCORRECT_TYPE if a non-integer is used to access an array + */ + inline simdjson_result at_path(std::string_view json_path) noexcept; + + /** + * Get all values matching the given JSONPath expression with wildcard support. + * Supports wildcard patterns like "[*]" to match all array elements. + * + * @param json_path JSONPath expression with wildcards + * @return Vector of values matching the wildcard pattern + */ + inline simdjson_result> at_path_with_wildcard(std::string_view json_path) noexcept; + + /** + * Consumes the array and returns a string_view instance corresponding to the + * array as represented in JSON. It points inside the original document. + */ + simdjson_inline simdjson_result raw_json() noexcept; + + /** + * Get the value at the given index. This function has linear-time complexity. + * This function should only be called once on an array instance since the array iterator is not reset between each call. + * + * @return The value at the given index, or: + * - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length + */ + simdjson_inline simdjson_result at(size_t index) noexcept; + +#if SIMDJSON_SUPPORTS_CONCEPTS + /** + * Get this array as the given type. + * + * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized. + * @returns INCORRECT_TYPE If the JSON array is not of the given type. + * @returns SUCCESS If the parse succeeded and the out parameter was set to the value. + */ + template + simdjson_warn_unused simdjson_inline error_code get(T &out) + noexcept(custom_deserializable ? nothrow_custom_deserializable : true) { + static_assert(custom_deserializable); + return deserialize(*this, out); + } + /** + * Get this array as the given type. + * + * @returns A value of the given type, parsed from the JSON. + * @returns INCORRECT_TYPE If the JSON value is not the given type. + */ + template + simdjson_inline simdjson_result get() + noexcept(custom_deserializable ? nothrow_custom_deserializable : true) + { + static_assert(std::is_default_constructible::value, "The specified type is not default constructible."); + T out{}; + SIMDJSON_TRY(get(out)); + return out; + } +#endif // SIMDJSON_SUPPORTS_CONCEPTS +protected: + /** + * Go to the end of the array, no matter where you are right now. + */ + simdjson_warn_unused simdjson_inline error_code consume() noexcept; + + /** + * Begin array iteration. + * + * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the + * resulting array. + * @error INCORRECT_TYPE if the iterator is not at [. + */ + static simdjson_inline simdjson_result start(value_iterator &iter) noexcept; + /** + * Begin array iteration from the root. + * + * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the + * resulting array. + * @error INCORRECT_TYPE if the iterator is not at [. + * @error TAPE_ERROR if there is no closing ] at the end of the document. + */ + static simdjson_inline simdjson_result start_root(value_iterator &iter) noexcept; + /** + * Begin array iteration. + * + * This version of the method should be called after the initial [ has been verified, and is + * intended for use by switch statements that check the type of a value. + * + * @param iter The iterator. Must be after the initial [. Will be *moved* into the resulting array. + */ + static simdjson_inline simdjson_result started(value_iterator &iter) noexcept; + + /** + * Create an array at the given Internal array creation. Call array::start() or array::started() instead of this. + * + * @param iter The iterator. Must either be at the start of the first element with iter.is_alive() + * == true, or past the [] with is_alive() == false if the array is empty. Will be *moved* + * into the resulting array. + */ + simdjson_inline array(const value_iterator &iter) noexcept; + + /** + * Iterator marking current position. + * + * iter.is_alive() == false indicates iteration is complete. + */ + value_iterator iter{}; + + friend class value; + friend class document; + friend struct simdjson_result; + friend struct simdjson_result; + friend class array_iterator; +}; + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +template<> +struct simdjson_result : public rvv_vls::implementation_simdjson_result_base { +public: + simdjson_inline simdjson_result(rvv_vls::ondemand::array &&value) noexcept; ///< @private + simdjson_inline simdjson_result(error_code error) noexcept; ///< @private + simdjson_inline simdjson_result() noexcept = default; + + simdjson_inline simdjson_result begin() noexcept; + simdjson_inline simdjson_result end() noexcept; + inline simdjson_result count_elements() & noexcept; + inline simdjson_result is_empty() & noexcept; + inline simdjson_result reset() & noexcept; + simdjson_inline simdjson_result at(size_t index) noexcept; + simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; + simdjson_inline simdjson_result at_path(std::string_view json_path) noexcept; + simdjson_inline simdjson_result> at_path_with_wildcard(std::string_view json_path) noexcept; + simdjson_inline simdjson_result raw_json() noexcept; +#if SIMDJSON_SUPPORTS_CONCEPTS + // TODO: move this code into object-inl.h + + template + simdjson_inline simdjson_result get() noexcept { + if (error()) { return error(); } + if constexpr (std::is_same_v) { + return first; + } + return first.get(); + } + template + simdjson_warn_unused simdjson_inline error_code get(T& out) noexcept { + if (error()) { return error(); } + if constexpr (std::is_same_v) { + out = first; + } else { + SIMDJSON_TRY( first.get(out) ); + } + return SUCCESS; + } +#endif // SIMDJSON_SUPPORTS_CONCEPTS +}; + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_H +/* end file simdjson/generic/ondemand/array.h for rvv_vls */ +/* including simdjson/generic/ondemand/array_iterator.h for rvv_vls: #include "simdjson/generic/ondemand/array_iterator.h" */ +/* begin file simdjson/generic/ondemand/array_iterator.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +/** + * A forward-only JSON array. + * + * This is an input_iterator, meaning: + * - It is forward-only + * - * must be called at most once per element. + * - ++ must be called exactly once in between each * (*, ++, *, ++, * ...) + */ +class array_iterator { +public: + using iterator_category = std::input_iterator_tag; + using value_type = simdjson_result; + using difference_type = std::ptrdiff_t; + using pointer = void; + using reference = value_type; + + /** Create a new, invalid array iterator. */ + simdjson_inline array_iterator() noexcept = default; + + // + // Iterator interface + // + + /** + * Get the current element. + * + * Part of the std::iterator interface. + */ + simdjson_inline simdjson_result + operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION. + /** + * Check if we are at the end of the JSON. + * + * Part of the std::iterator interface. + * + * @return true if there are no more elements in the JSON array. + */ + simdjson_inline bool operator==(const array_iterator &) const noexcept; + /** + * Check if there are more elements in the JSON array. + * + * Part of the std::iterator interface. + * + * @return true if there are more elements in the JSON array. + */ + simdjson_inline bool operator!=(const array_iterator &) const noexcept; + /** + * Move to the next element. + * + * Part of the std::iterator interface. + */ + simdjson_inline array_iterator &operator++() noexcept; + + /** + * Check if the array is at the end. + */ + simdjson_warn_unused simdjson_inline bool at_end() const noexcept; + +private: +#if SIMDJSON_DEVELOPMENT_CHECKS + bool has_been_referenced{false}; +#endif + value_iterator iter{}; + + simdjson_inline array_iterator(const value_iterator &iter) noexcept; + + friend class array; + friend class value; + friend struct simdjson_result; +}; + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +template<> +struct simdjson_result : public rvv_vls::implementation_simdjson_result_base { + using iterator_category = std::input_iterator_tag; + using value_type = simdjson_result; + using difference_type = std::ptrdiff_t; + using pointer = void; + using reference = value_type; + + simdjson_inline simdjson_result(rvv_vls::ondemand::array_iterator &&value) noexcept; ///< @private + simdjson_inline simdjson_result(error_code error) noexcept; ///< @private + simdjson_inline simdjson_result() noexcept = default; + + // + // Iterator interface + // + + simdjson_inline simdjson_result operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION. + simdjson_inline bool operator==(const simdjson_result &) const noexcept; + simdjson_inline bool operator!=(const simdjson_result &) const noexcept; + simdjson_inline simdjson_result &operator++() noexcept; + + simdjson_warn_unused simdjson_inline bool at_end() const noexcept; +}; + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_H +/* end file simdjson/generic/ondemand/array_iterator.h for rvv_vls */ +/* including simdjson/generic/ondemand/document.h for rvv_vls: #include "simdjson/generic/ondemand/document.h" */ +/* begin file simdjson/generic/ondemand/document.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +/** + * A JSON document. It holds a json_iterator instance. + * + * Used by tokens to get text, and string buffer location. + * + * You must keep the document around during iteration. + */ +class document { +public: + /** + * Create a new invalid document. + * + * Exists so you can declare a variable and later assign to it before use. + */ + simdjson_inline document() noexcept = default; + simdjson_inline document(const document &other) noexcept = delete; // pass your documents by reference, not by copy + simdjson_inline document(document &&other) noexcept = default; + simdjson_inline document &operator=(const document &other) noexcept = delete; + simdjson_inline document &operator=(document &&other) noexcept = default; + + /** + * Cast this JSON value to an array. + * + * @returns An object that can be used to iterate the array. + * @returns INCORRECT_TYPE If the JSON value is not an array. + */ + simdjson_inline simdjson_result get_array() & noexcept; + /** + * Cast this JSON value to an object. + * + * @returns An object that can be used to look up or iterate fields. + * @returns INCORRECT_TYPE If the JSON value is not an object. + */ + simdjson_inline simdjson_result get_object() & noexcept; + /** + * Cast this JSON value to an unsigned integer. + * + * @returns A signed 64-bit integer. + * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer. + */ + simdjson_inline simdjson_result get_uint64() noexcept; + /** + * Cast this JSON value (inside string) to an unsigned integer. + * + * @returns A signed 64-bit integer. + * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer. + */ + simdjson_inline simdjson_result get_uint64_in_string() noexcept; + /** + * Cast this JSON value to a signed integer. + * + * @returns A signed 64-bit integer. + * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer. + */ + simdjson_inline simdjson_result get_int64() noexcept; + /** + * Cast this JSON value (inside string) to a signed integer. + * + * @returns A signed 64-bit integer. + * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer. + */ + simdjson_inline simdjson_result get_int64_in_string() noexcept; + /** + * Cast this JSON value to a double. + * + * @returns A double. + * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number. + */ + simdjson_inline simdjson_result get_double() noexcept; + + /** + * Cast this JSON value (inside string) to a double. + * + * @returns A double. + * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number. + */ + simdjson_inline simdjson_result get_double_in_string() noexcept; + /** + * Cast this JSON value to a string. + * + * The string is guaranteed to be valid UTF-8. + * + * Important: Calling get_string() twice on the same document is an error. + * + * @param Whether to allow a replacement character for unmatched surrogate pairs. + * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next + * time it parses a document or when it is destroyed. + * @returns INCORRECT_TYPE if the JSON value is not a string. + */ + simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; + /** + * Attempts to fill the provided std::string reference with the parsed value of the current string. + * + * The string is guaranteed to be valid UTF-8. + * + * Important: a value should be consumed once. Calling get_string() twice on the same value + * is an error. + * + * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory. + * We recommend you avoid allocating an std::string unless you need to. + * + * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS. + */ + template + simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + /** + * Cast this JSON value to a string. + * + * The string is not guaranteed to be valid UTF-8. See https://simonsapin.github.io/wtf-8/ + * + * Important: Calling get_wobbly_string() twice on the same document is an error. + * + * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next + * time it parses a document or when it is destroyed. + * @returns INCORRECT_TYPE if the JSON value is not a string. + */ + simdjson_inline simdjson_result get_wobbly_string() noexcept; + /** + * Cast this JSON value to a raw_json_string. + * + * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n). + * + * @returns A pointer to the raw JSON for the given string. + * @returns INCORRECT_TYPE if the JSON value is not a string. + */ + simdjson_inline simdjson_result get_raw_json_string() noexcept; + /** + * Cast this JSON value to a bool. + * + * @returns A bool value. + * @returns INCORRECT_TYPE if the JSON value is not true or false. + */ + simdjson_inline simdjson_result get_bool() noexcept; + /** + * Cast this JSON value to a value when the document is an object or an array. + * + * You must not have begun iterating through the object or array. When + * SIMDJSON_DEVELOPMENT_CHECKS is set to 1 (which is the case when building in Debug mode + * by default), and you have already begun iterating, + * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use + * rewind() to reset the document to its initial state before calling this method. + * + * @returns A value if a JSON array or object cannot be found. + * @returns SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function). + */ + simdjson_inline simdjson_result get_value() noexcept; + + /** + * Checks if this JSON value is null. If and only if the value is + * null, then it is consumed (we advance). If we find a token that + * begins with 'n' but is not 'null', then an error is returned. + * + * @returns Whether the value is null. + * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'. + */ + simdjson_inline simdjson_result is_null() noexcept; + + /** + * Get this value as the given type. + * + * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool + * + * You may use get_double(), get_bool(), get_uint64(), get_int64(), + * get_object(), get_array(), get_raw_json_string(), or get_string() instead. + * + * @returns A value of the given type, parsed from the JSON. + * @returns INCORRECT_TYPE If the JSON value is not the given type. + */ + template + simdjson_inline simdjson_result get() & +#if SIMDJSON_SUPPORTS_CONCEPTS + noexcept(custom_deserializable ? nothrow_custom_deserializable : true) +#else + noexcept +#endif + { + static_assert(std::is_default_constructible::value, "Cannot initialize the specified type."); + T out{}; + SIMDJSON_TRY(get(out)); + return out; + } + /** + * @overload template simdjson_result get() & noexcept + * + * We disallow the use tag_invoke CPO on a moved document; it may create UB + * if user uses `ondemand::array` or `ondemand::object` in their custom type. + * + * The member function is still remains specialize-able for compatibility + * reasons, but we completely disallow its use when a tag_invoke customization + * is provided. + */ + template + simdjson_inline simdjson_result get() && +#if SIMDJSON_SUPPORTS_CONCEPTS + noexcept(custom_deserializable ? nothrow_custom_deserializable : true) +#else + noexcept +#endif + { + static_assert(!std::is_same::value && !std::is_same::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour."); + return static_cast(*this).get(); + } + + /** + * Get this value as the given type. + * + * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value + * + * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances. + * + * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized. + * @returns INCORRECT_TYPE If the JSON value is of the given type. + * @returns SUCCESS If the parse succeeded and the out parameter was set to the value. + */ + template + simdjson_warn_unused simdjson_inline error_code get(T &out) & +#if SIMDJSON_SUPPORTS_CONCEPTS + noexcept(custom_deserializable ? nothrow_custom_deserializable : true) +#else + noexcept +#endif + { +#if SIMDJSON_SUPPORTS_CONCEPTS + if constexpr (custom_deserializable) { + return deserialize(*this, out); + } else { + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; + } +#else // SIMDJSON_SUPPORTS_CONCEPTS + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_CONCEPTS + } + + /** @overload template error_code get(T &out) & noexcept */ + template simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept; + +#if SIMDJSON_EXCEPTIONS + /** + * Cast this JSON value to an instance of type T. The programmer is responsible for + * providing an implementation of get for the type T, if T is not one of the types + * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.) + * + * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types + * + * @returns An instance of type T + */ + template + explicit simdjson_inline operator T() & noexcept(false); + template + explicit simdjson_deprecated simdjson_inline operator T() && noexcept(false); + + /** + * Cast this JSON value to an array. + * + * @returns An object that can be used to iterate the array. + * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array. + */ + simdjson_inline operator array() & noexcept(false); + /** + * Cast this JSON value to an object. + * + * @returns An object that can be used to look up or iterate fields. + * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object. + */ + simdjson_inline operator object() & noexcept(false); + /** + * Cast this JSON value to an unsigned integer. + * + * @returns A signed 64-bit integer. + * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer. + */ + simdjson_inline operator uint64_t() noexcept(false); + /** + * Cast this JSON value to a signed integer. + * + * @returns A signed 64-bit integer. + * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer. + */ + simdjson_inline operator int64_t() noexcept(false); + /** + * Cast this JSON value to a double. + * + * @returns A double. + * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number. + */ + simdjson_inline operator double() noexcept(false); + /** + * Cast this JSON value to a string. + * + * The string is guaranteed to be valid UTF-8. + * + * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next + * time it parses a document or when it is destroyed. + * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string. + */ + simdjson_inline operator std::string_view() noexcept(false) simdjson_lifetime_bound; + /** + * Cast this JSON value to a raw_json_string. + * + * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n). + * + * @returns A pointer to the raw JSON for the given string. + * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string. + */ + simdjson_inline operator raw_json_string() noexcept(false) simdjson_lifetime_bound; + /** + * Cast this JSON value to a bool. + * + * @returns A bool value. + * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false. + */ + simdjson_inline operator bool() noexcept(false); + /** + * Cast this JSON value to a value when the document is an object or an array. + * + * You must not have begun iterating through the object or array. When + * SIMDJSON_DEVELOPMENT_CHECKS is defined, and you have already begun iterating, + * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use + * rewind() to reset the document to its initial state before calling this method. + * + * @returns A value value if a JSON array or object cannot be found. + * @exception SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function). + */ + simdjson_inline operator value() noexcept(false); +#endif + /** + * This method scans the array and counts the number of elements. + * The count_elements method should always be called before you have begun + * iterating through the array: it is expected that you are pointing at + * the beginning of the array. + * The runtime complexity is linear in the size of the array. After + * calling this function, if successful, the array is 'rewinded' at its + * beginning as if it had never been accessed. If the JSON is malformed (e.g., + * there is a missing comma), then an error is returned and it is no longer + * safe to continue. Note that count_elements() does not validate the JSON values, + * only the structure of the array. + */ + simdjson_inline simdjson_result count_elements() & noexcept; + /** + * This method scans the object and counts the number of key-value pairs. + * The count_fields method should always be called before you have begun + * iterating through the object: it is expected that you are pointing at + * the beginning of the object. + * The runtime complexity is linear in the size of the object. After + * calling this function, if successful, the object is 'rewinded' at its + * beginning as if it had never been accessed. If the JSON is malformed (e.g., + * there is a missing comma), then an error is returned and it is no longer + * safe to continue. + * + * To check that an object is empty, it is more performant to use + * the is_empty() method. + */ + simdjson_inline simdjson_result count_fields() & noexcept; + /** + * Get the value at the given index in the array. This function has linear-time complexity. + * This function should only be called once on an array instance since the array iterator is not reset between each call. + * + * @return The value at the given index, or: + * - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length + */ + simdjson_inline simdjson_result at(size_t index) & noexcept; + /** + * Begin array iteration. + * + * Part of the std::iterable interface. + */ + simdjson_inline simdjson_result begin() & noexcept; + /** + * Sentinel representing the end of the array. + * + * Part of the std::iterable interface. + */ + simdjson_inline simdjson_result end() & noexcept; + + /** + * Look up a field by name on an object (order-sensitive). By order-sensitive, we mean that + * fields must be accessed in the order they appear in the JSON text (although you can + * skip fields). See find_field_unordered() and operator[] for an order-insensitive version. + * + * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the + * JSON `{ "x": 1, "y": 2, "z": 3 }`: + * + * ```cpp + * simdjson::ondemand::parser parser; + * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded); + * double z = obj.find_field("z"); + * double y = obj.find_field("y"); + * double x = obj.find_field("x"); + * ``` + * + * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys. + * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`. + * + * + * You must consume the fields on an object one at a time. A request for a new key + * invalidates previous field values: it makes them unsafe. E.g., the array + * given by content["bids"].get_array() should not be accessed after you have called + * content["asks"].get_array(). You can detect such mistakes by first compiling and running + * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an + * OUT_OF_ORDER_ITERATION error is generated. + * + * You are expected to access keys only once. You should access the value corresponding to + * a key a single time. Doing object["mykey"].to_string()and then again object["mykey"].to_string() + * is an error. + * + * @param key The key to look up. + * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object. + */ + simdjson_inline simdjson_result find_field(std::string_view key) & noexcept; + /** @overload simdjson_inline simdjson_result find_field(std::string_view key) & noexcept; */ + simdjson_inline simdjson_result find_field(const char *key) & noexcept; + + /** + * Look up a field by name on an object, without regard to key order. + * + * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies + * and often appears negligible. It starts out normally, starting out at the last field; but if + * the field is not found, it scans from the beginning of the object to see if it missed it. That + * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object + * in question is large. The fact that the extra code is there also bumps the executable size. + * + * We default operator[] on find_field_unordered() for convenience. + * It is the default because it would be highly surprising (and hard to debug) if the + * default behavior failed to look up a field just because it was in the wrong order--and many + * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order. + * + * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the + * field was not there when they are not in order). + * + * You must consume the fields on an object one at a time. A request for a new key + * invalidates previous field values: it makes them unsafe. E.g., the array + * given by content["bids"].get_array() should not be accessed after you have called + * content["asks"].get_array(). You can detect such mistakes by first compiling and running + * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an + * OUT_OF_ORDER_ITERATION error is generated. + * + * You are expected to access keys only once. You should access the value corresponding to a key + * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string() + * is an error. + * + * @param key The key to look up. + * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object. + */ + simdjson_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; + /** @overload simdjson_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ + simdjson_inline simdjson_result find_field_unordered(const char *key) & noexcept; + /** @overload simdjson_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ + simdjson_inline simdjson_result operator[](std::string_view key) & noexcept; + /** @overload simdjson_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ + simdjson_inline simdjson_result operator[](const char *key) & noexcept; + simdjson_result operator[](int) & noexcept = delete; + + /** + * Get the type of this JSON value. It does not validate or consume the value. + * E.g., you must still call "is_null()" to check that a value is null even if + * "type()" returns json_type::null. + * + * The answer can be one of + * simdjson::ondemand::json_type::object, + * simdjson::ondemand::json_type::array, + * simdjson::ondemand::json_type::string, + * simdjson::ondemand::json_type::number, + * simdjson::ondemand::json_type::boolean, + * simdjson::ondemand::json_type::null. + * + * Starting with simdjson 4.0, this function will return simdjson::ondemand::json_type::unknown + * given a bad token. + * This allows you to identify a case such as {"key": NaN} and identify the NaN value. + * The simdjson::ondemand::json_type::unknown value should only happen with non-valid JSON. + * + * NOTE: If you're only expecting a value to be one type (a typical case), it's generally + * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just + * let it throw an exception). + * + * Prior to simdjson 4.0, this function would return an error given a bad token. + * Starting with simdjson 4.0, it will return simdjson::ondemand::json_type::unknown. + * This allows you to identify a case such as {"key": NaN} and identify the NaN value. + * The simdjson::ondemand::json_type::unknown value should only happen with non-valid JSON. + */ + simdjson_inline simdjson_result type() noexcept; + + /** + * Checks whether the document is a scalar (string, number, null, Boolean). + * Returns false when there it is an array or object. + * + * @returns true if the type is string, number, null, Boolean + * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse". + */ + simdjson_inline simdjson_result is_scalar() noexcept; + + /** + * Checks whether the document is a string. + * + * @returns true if the type is string + * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse". + */ + simdjson_inline simdjson_result is_string() noexcept; + + /** + * Checks whether the document is a negative number. + * + * @returns true if the number if negative. + */ + simdjson_inline bool is_negative() noexcept; + /** + * Checks whether the document is an integer number. Note that + * this requires to partially parse the number string. If + * the value is determined to be an integer, it may still + * not parse properly as an integer in subsequent steps + * (e.g., it might overflow). + * + * @returns true if the number if negative. + */ + simdjson_inline simdjson_result is_integer() noexcept; + /** + * Determine the number type (integer or floating-point number) as quickly + * as possible. This function does not fully validate the input. It is + * useful when you only need to classify the numbers, without parsing them. + * + * If you are planning to retrieve the value or you need full validation, + * consider using the get_number() method instead: it will fully parse + * and validate the input, and give you access to the type: + * get_number().get_number_type(). + * + * get_number_type() is number_type::unsigned_integer if we have + * an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615. + * get_number_type() is number_type::signed_integer if we have an + * integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808. + * get_number_type() is number_type::big_integer if we have an integer outside + * of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808). + * Otherwise, get_number_type() has value number_type::floating_point_number + * + * This function requires processing the number string, but it is expected + * to be faster than get_number().get_number_type() because it is does not + * parse the number value. + * + * @returns the type of the number + */ + simdjson_inline simdjson_result get_number_type() noexcept; + + /** + * Attempt to parse an ondemand::number. An ondemand::number may + * contain an integer value or a floating-point value, the simdjson + * library will autodetect the type. Thus it is a dynamically typed + * number. Before accessing the value, you must determine the detected + * type. + * + * number.get_number_type() is number_type::signed_integer if we have + * an integer in [-9223372036854775808,9223372036854775808) + * You can recover the value by calling number.get_int64() and you + * have that number.is_int64() is true. + * + * number.get_number_type() is number_type::unsigned_integer if we have + * an integer in [9223372036854775808,18446744073709551616) + * You can recover the value by calling number.get_uint64() and you + * have that number.is_uint64() is true. + * + * Otherwise, number.get_number_type() has value number_type::floating_point_number + * and we have a binary64 number. + * You can recover the value by calling number.get_double() and you + * have that number.is_double() is true. + * + * You must check the type before accessing the value: it is an error + * to call "get_int64()" when number.get_number_type() is not + * number_type::signed_integer and when number.is_int64() is false. + */ + simdjson_warn_unused simdjson_inline simdjson_result get_number() noexcept; + + /** + * Get the raw JSON for this token. + * + * The string_view will always point into the input buffer. + * + * The string_view will start at the beginning of the token, and include the entire token + * *as well as all spaces until the next token (or EOF).* This means, for example, that a + * string token always begins with a " and is always terminated by the final ", possibly + * followed by a number of spaces. + * + * The string_view is *not* null-terminated. If this is a scalar (string, number, + * boolean, or null), the character after the end of the string_view may be the padded buffer. + * + * Tokens include: + * - { + * - [ + * - "a string (possibly with UTF-8 or backslashed characters like \\\")". + * - -1.2e-100 + * - true + * - false + * - null + */ + simdjson_inline simdjson_result raw_json_token() noexcept; + + /** + * Reset the iterator inside the document instance so we are pointing back at the + * beginning of the document, as if it had just been created. It invalidates all + * values, objects and arrays that you have created so far (including unescaped strings). + */ + inline void rewind() noexcept; + /** + * Returns debugging information. + */ + inline std::string to_debug_string() noexcept; + /** + * Some unrecoverable error conditions may render the document instance unusable. + * The is_alive() method returns true when the document is still suitable. + */ + inline bool is_alive() noexcept; + + /** + * Returns the current location in the document if in bounds. + */ + inline simdjson_result current_location() const noexcept; + + /** + * Returns true if this document has been fully parsed. + * If you have consumed the whole document and at_end() returns + * false, then there may be trailing content. + */ + inline bool at_end() const noexcept; + + /** + * Returns the current depth in the document if in bounds. + * + * E.g., + * 0 = finished with document + * 1 = document root value (could be [ or {, not yet known) + * 2 = , or } inside root array/object + * 3 = key or value inside root array/object. + */ + simdjson_inline int32_t current_depth() const noexcept; + + /** + * Get the value associated with the given JSON pointer. We use the RFC 6901 + * https://tools.ietf.org/html/rfc6901 standard. + * + * ondemand::parser parser; + * auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded; + * auto doc = parser.iterate(json); + * doc.at_pointer("/foo/a/1") == 20 + * + * It is allowed for a key to be the empty string: + * + * ondemand::parser parser; + * auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded; + * auto doc = parser.iterate(json); + * doc.at_pointer("//a/1") == 20 + * + * Key values are matched exactly, without unescaping or Unicode normalization. + * We do a byte-by-byte comparison. E.g. + * + * const padded_string json = "{\"\\u00E9\":123}"_padded; + * auto doc = parser.iterate(json); + * doc.at_pointer("/\\u00E9") == 123 + * doc.at_pointer((const char*)u8"/\u00E9") returns an error (NO_SUCH_FIELD) + * + * Note that at_pointer() automatically calls rewind between each call. Thus + * all values, objects and arrays that you have created so far (including unescaped strings) + * are invalidated. After calling at_pointer, you need to consume the result: string values + * should be stored in your own variables, arrays should be decoded and stored in your own array-like + * structures and so forth. + * + * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching + * + * @return The value associated with the given JSON pointer, or: + * - NO_SUCH_FIELD if a field does not exist in an object + * - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length + * - INCORRECT_TYPE if a non-integer is used to access an array + * - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed + * - SCALAR_DOCUMENT_AS_VALUE if the json_pointer is empty and the document is not a scalar (see is_scalar() function). + */ + simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; + + /** + * Get the value associated with the given JSONPath expression. We only support + * JSONPath queries that trivially convertible to JSON Pointer queries: key + * names and array indices. + * + * https://www.rfc-editor.org/rfc/rfc9535 (RFC 9535) + * + * Key values are matched exactly, without unescaping or Unicode normalization. + * We do a byte-by-byte comparison. E.g. + * + * const padded_string json = "{\"\\u00E9\":123}"_padded; + * auto doc = parser.iterate(json); + * doc.at_path(".\\u00E9") == 123 + * doc.at_path((const char*)u8".\u00E9") returns an error (NO_SUCH_FIELD) + * + * @return The value associated with the given JSONPath expression, or: + * - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails + * - NO_SUCH_FIELD if a field does not exist in an object + * - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length + * - INCORRECT_TYPE if a non-integer is used to access an array + */ + simdjson_inline simdjson_result at_path(std::string_view json_path) noexcept; + + /** + * Get all values matching the given JSONPath expression with wildcard support. + * + * Supports wildcard patterns like "$.array[*]" or "$.object.*" to match multiple elements. + * + * This method materializes all matching values into a vector. + * The document will be consumed after this call. + * + * @param json_path JSONPath expression with wildcards + * @return Vector of values matching the wildcard pattern, or: + * - INVALID_JSON_POINTER if the JSONPath cannot be parsed + * - NO_SUCH_FIELD if a field does not exist + * - INDEX_OUT_OF_BOUNDS if an array index is out of bounds + * - INCORRECT_TYPE if path traversal encounters wrong type + */ + simdjson_inline simdjson_result> at_path_with_wildcard(std::string_view json_path) noexcept; + + /** + * Consumes the document and returns a string_view instance corresponding to the + * document as represented in JSON. It points inside the original byte array containing + * the JSON document. + */ + simdjson_inline simdjson_result raw_json() noexcept; + +#if SIMDJSON_STATIC_REFLECTION + /** + * Extract only specific fields from the JSON object into a struct. + * + * This allows selective deserialization of only the fields you need, + * potentially improving performance by skipping unwanted fields. + * + * Example: + * ```cpp + * struct Car { + * std::string make; + * std::string model; + * int year; + * double price; + * }; + * + * Car car; + * doc.extract_into<"make", "model">(car); + * // Only 'make' and 'model' fields are extracted from JSON + * ``` + * + * @tparam FieldNames Compile-time string literals specifying which fields to extract + * @param out The output struct to populate with selected fields + * @returns SUCCESS on success, or an error code if a required field is missing or has wrong type + */ + template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) + simdjson_warn_unused simdjson_inline error_code extract_into(T& out) & noexcept; +#endif // SIMDJSON_STATIC_REFLECTION +protected: + /** + * Consumes the document. + */ + simdjson_warn_unused simdjson_inline error_code consume() noexcept; + + simdjson_inline document(ondemand::json_iterator &&iter) noexcept; + simdjson_inline const uint8_t *text(uint32_t idx) const noexcept; + + simdjson_inline value_iterator resume_value_iterator() noexcept; + simdjson_inline value_iterator get_root_value_iterator() noexcept; + simdjson_inline simdjson_result start_or_resume_object() noexcept; + static simdjson_inline document start(ondemand::json_iterator &&iter) noexcept; + + // + // Fields + // + json_iterator iter{}; ///< Current position in the document + static constexpr depth_t DOCUMENT_DEPTH = 0; ///< document depth is always 0 + + friend class array_iterator; + friend class value; + friend class ondemand::parser; + friend class object; + friend class array; + friend class field; + friend class token; + friend class document_stream; + friend class document_reference; +}; + + +/** + * A document_reference is a thin wrapper around a document reference instance. + * The document_reference instances are used primarily/solely for streams of JSON + * documents. They differ from document instances when parsing a scalar value + * (a document that is not an array or an object). In the case of a document, + * we expect the document to be fully consumed. In the case of a document_reference, + * we allow trailing content. + */ +class document_reference { +public: + simdjson_inline document_reference() noexcept; + simdjson_inline document_reference(document &d) noexcept; + simdjson_inline document_reference(const document_reference &other) noexcept = default; + simdjson_inline document_reference& operator=(const document_reference &other) noexcept = default; + simdjson_inline void rewind() noexcept; + simdjson_inline simdjson_result get_array() & noexcept; + simdjson_inline simdjson_result get_object() & noexcept; + simdjson_inline simdjson_result get_uint64() noexcept; + simdjson_inline simdjson_result get_uint64_in_string() noexcept; + simdjson_inline simdjson_result get_int64() noexcept; + simdjson_inline simdjson_result get_int64_in_string() noexcept; + simdjson_inline simdjson_result get_double() noexcept; + simdjson_inline simdjson_result get_double_in_string() noexcept; + simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; + template + simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + simdjson_inline simdjson_result get_wobbly_string() noexcept; + simdjson_inline simdjson_result get_raw_json_string() noexcept; + simdjson_inline simdjson_result get_bool() noexcept; + simdjson_inline simdjson_result get_value() noexcept; + + simdjson_inline simdjson_result is_null() noexcept; + template + simdjson_inline simdjson_result get() & +#if SIMDJSON_SUPPORTS_CONCEPTS + noexcept(custom_deserializable ? nothrow_custom_deserializable : true) +#else + noexcept +#endif + { + static_assert(std::is_default_constructible::value, "Cannot initialize the specified type."); + T out{}; + SIMDJSON_TRY(get(out)); + return out; + } + template + simdjson_inline simdjson_result get() && +#if SIMDJSON_SUPPORTS_CONCEPTS + noexcept(custom_deserializable ? nothrow_custom_deserializable : true) +#else + noexcept +#endif + { + static_assert(!std::is_same::value && !std::is_same::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour."); + return static_cast(*this).get(); + } + + /** + * Get this value as the given type. + * + * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value + * + * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances. + * + * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized. + * @returns INCORRECT_TYPE If the JSON value is not an object. + * @returns SUCCESS If the parse succeeded and the out parameter was set to the value. + */ + template + simdjson_warn_unused simdjson_inline error_code get(T &out) & +#if SIMDJSON_SUPPORTS_CONCEPTS + noexcept(custom_deserializable ? nothrow_custom_deserializable : true) +#else + noexcept +#endif + { +#if SIMDJSON_SUPPORTS_CONCEPTS + if constexpr (custom_deserializable) { + return deserialize(*this, out); + } else { + static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " + "And you do not seem to have added support for it. Indeed, we have that " + "simdjson::custom_deserializable is false and the type T is not a default type " + "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, or bool."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; + } +#else // SIMDJSON_SUPPORTS_CONCEPTS + // Unless the simdjson library or the user provides an inline implementation, calling this method should + // immediately fail. + static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " + "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " + "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " + " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." + " You may also add support for custom types, see our documentation."); + static_cast(out); // to get rid of unused errors + return UNINITIALIZED; +#endif // SIMDJSON_SUPPORTS_CONCEPTS + } + + /** @overload template error_code get(T &out) & noexcept */ + template simdjson_inline error_code get(T &out) && noexcept; + simdjson_inline simdjson_result raw_json() noexcept; +#if SIMDJSON_STATIC_REFLECTION + template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) + simdjson_warn_unused simdjson_inline error_code extract_into(T& out) & noexcept; +#endif // SIMDJSON_STATIC_REFLECTION + simdjson_inline operator document&() const noexcept; +#if SIMDJSON_EXCEPTIONS + template + explicit simdjson_inline operator T() noexcept(false); + simdjson_inline operator array() & noexcept(false); + simdjson_inline operator object() & noexcept(false); + simdjson_inline operator uint64_t() noexcept(false); + simdjson_inline operator int64_t() noexcept(false); + simdjson_inline operator double() noexcept(false); + simdjson_inline operator std::string_view() noexcept(false); + simdjson_inline operator raw_json_string() noexcept(false); + simdjson_inline operator bool() noexcept(false); + simdjson_inline operator value() noexcept(false); +#endif + simdjson_inline simdjson_result count_elements() & noexcept; + simdjson_inline simdjson_result count_fields() & noexcept; + simdjson_inline simdjson_result at(size_t index) & noexcept; + simdjson_inline simdjson_result begin() & noexcept; + simdjson_inline simdjson_result end() & noexcept; + simdjson_inline simdjson_result find_field(std::string_view key) & noexcept; + simdjson_inline simdjson_result find_field(const char *key) & noexcept; + simdjson_inline simdjson_result operator[](std::string_view key) & noexcept; + simdjson_inline simdjson_result operator[](const char *key) & noexcept; + simdjson_result operator[](int) & noexcept = delete; + simdjson_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; + simdjson_inline simdjson_result find_field_unordered(const char *key) & noexcept; + + simdjson_inline simdjson_result type() noexcept; + simdjson_inline simdjson_result is_scalar() noexcept; + simdjson_inline simdjson_result is_string() noexcept; + + simdjson_inline simdjson_result current_location() noexcept; + simdjson_inline int32_t current_depth() const noexcept; + simdjson_inline bool is_negative() noexcept; + simdjson_inline simdjson_result is_integer() noexcept; + simdjson_inline simdjson_result get_number_type() noexcept; + simdjson_inline simdjson_result get_number() noexcept; + simdjson_inline simdjson_result raw_json_token() noexcept; + simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; + simdjson_inline simdjson_result at_path(std::string_view json_path) noexcept; + simdjson_inline simdjson_result> at_path_with_wildcard(std::string_view json_path) noexcept; + +private: + document *doc{nullptr}; +}; +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +template<> +struct simdjson_result : public rvv_vls::implementation_simdjson_result_base { +public: + simdjson_inline simdjson_result(rvv_vls::ondemand::document &&value) noexcept; ///< @private + simdjson_inline simdjson_result(error_code error) noexcept; ///< @private + simdjson_inline simdjson_result() noexcept = default; + simdjson_inline error_code rewind() noexcept; + + simdjson_inline simdjson_result get_array() & noexcept; + simdjson_inline simdjson_result get_object() & noexcept; + simdjson_inline simdjson_result get_uint64() noexcept; + simdjson_inline simdjson_result get_uint64_in_string() noexcept; + simdjson_inline simdjson_result get_int64() noexcept; + simdjson_inline simdjson_result get_int64_in_string() noexcept; + simdjson_inline simdjson_result get_double() noexcept; + simdjson_inline simdjson_result get_double_in_string() noexcept; + simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; + template + simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + simdjson_inline simdjson_result get_wobbly_string() noexcept; + simdjson_inline simdjson_result get_raw_json_string() noexcept; + simdjson_inline simdjson_result get_bool() noexcept; + simdjson_inline simdjson_result get_value() noexcept; + simdjson_inline simdjson_result is_null() noexcept; + + template simdjson_inline simdjson_result get() & noexcept; + template simdjson_deprecated simdjson_inline simdjson_result get() && noexcept; + + template simdjson_inline error_code get(T &out) & noexcept; + template simdjson_inline error_code get(T &out) && noexcept; +#if SIMDJSON_EXCEPTIONS + + using rvv_vls::implementation_simdjson_result_base::operator*; + using rvv_vls::implementation_simdjson_result_base::operator->; + template ::value == false>::type> + explicit simdjson_inline operator T() noexcept(false); + simdjson_inline operator rvv_vls::ondemand::array() & noexcept(false); + simdjson_inline operator rvv_vls::ondemand::object() & noexcept(false); + simdjson_inline operator uint64_t() noexcept(false); + simdjson_inline operator int64_t() noexcept(false); + simdjson_inline operator double() noexcept(false); + simdjson_inline operator std::string_view() noexcept(false); + simdjson_inline operator rvv_vls::ondemand::raw_json_string() noexcept(false); + simdjson_inline operator bool() noexcept(false); + simdjson_inline operator rvv_vls::ondemand::value() noexcept(false); +#endif + simdjson_inline simdjson_result count_elements() & noexcept; + simdjson_inline simdjson_result count_fields() & noexcept; + simdjson_inline simdjson_result at(size_t index) & noexcept; + simdjson_inline simdjson_result begin() & noexcept; + simdjson_inline simdjson_result end() & noexcept; + simdjson_inline simdjson_result find_field(std::string_view key) & noexcept; + simdjson_inline simdjson_result find_field(const char *key) & noexcept; + simdjson_inline simdjson_result operator[](std::string_view key) & noexcept; + simdjson_inline simdjson_result operator[](const char *key) & noexcept; + simdjson_result operator[](int) & noexcept = delete; + simdjson_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; + simdjson_inline simdjson_result find_field_unordered(const char *key) & noexcept; + simdjson_inline simdjson_result type() noexcept; + simdjson_inline simdjson_result is_scalar() noexcept; + simdjson_inline simdjson_result is_string() noexcept; + simdjson_inline simdjson_result current_location() noexcept; + simdjson_inline int32_t current_depth() const noexcept; + simdjson_inline bool at_end() const noexcept; + simdjson_inline bool is_negative() noexcept; + simdjson_inline simdjson_result is_integer() noexcept; + simdjson_inline simdjson_result get_number_type() noexcept; + simdjson_inline simdjson_result get_number() noexcept; + /** @copydoc simdjson_inline std::string_view document::raw_json_token() const noexcept */ + simdjson_inline simdjson_result raw_json_token() noexcept; + + simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; + simdjson_inline simdjson_result at_path(std::string_view json_path) noexcept; + simdjson_inline simdjson_result> at_path_with_wildcard(std::string_view json_path) noexcept; +#if SIMDJSON_STATIC_REFLECTION + template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) + simdjson_warn_unused simdjson_inline error_code extract_into(T& out) & noexcept; +#endif // SIMDJSON_STATIC_REFLECTION +}; + + +} // namespace simdjson + + + +namespace simdjson { + +template<> +struct simdjson_result : public rvv_vls::implementation_simdjson_result_base { +public: + simdjson_inline simdjson_result(rvv_vls::ondemand::document_reference value, error_code error) noexcept; + simdjson_inline simdjson_result() noexcept = default; + simdjson_inline error_code rewind() noexcept; + + simdjson_inline simdjson_result get_array() & noexcept; + simdjson_inline simdjson_result get_object() & noexcept; + simdjson_inline simdjson_result get_uint64() noexcept; + simdjson_inline simdjson_result get_uint64_in_string() noexcept; + simdjson_inline simdjson_result get_int64() noexcept; + simdjson_inline simdjson_result get_int64_in_string() noexcept; + simdjson_inline simdjson_result get_double() noexcept; + simdjson_inline simdjson_result get_double_in_string() noexcept; + simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; + template + simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + simdjson_inline simdjson_result get_wobbly_string() noexcept; + simdjson_inline simdjson_result get_raw_json_string() noexcept; + simdjson_inline simdjson_result get_bool() noexcept; + simdjson_inline simdjson_result get_value() noexcept; + simdjson_inline simdjson_result is_null() noexcept; + + template simdjson_inline simdjson_result get() & noexcept; + template simdjson_inline simdjson_result get() && noexcept; + + template simdjson_inline error_code get(T &out) & noexcept; + template simdjson_inline error_code get(T &out) && noexcept; +#if SIMDJSON_EXCEPTIONS + template + explicit simdjson_inline operator T() noexcept(false); + simdjson_inline operator rvv_vls::ondemand::array() & noexcept(false); + simdjson_inline operator rvv_vls::ondemand::object() & noexcept(false); + simdjson_inline operator uint64_t() noexcept(false); + simdjson_inline operator int64_t() noexcept(false); + simdjson_inline operator double() noexcept(false); + simdjson_inline operator std::string_view() noexcept(false); + simdjson_inline operator rvv_vls::ondemand::raw_json_string() noexcept(false); + simdjson_inline operator bool() noexcept(false); + simdjson_inline operator rvv_vls::ondemand::value() noexcept(false); +#endif + simdjson_inline simdjson_result count_elements() & noexcept; + simdjson_inline simdjson_result count_fields() & noexcept; + simdjson_inline simdjson_result at(size_t index) & noexcept; + simdjson_inline simdjson_result begin() & noexcept; + simdjson_inline simdjson_result end() & noexcept; + simdjson_inline simdjson_result find_field(std::string_view key) & noexcept; + simdjson_inline simdjson_result find_field(const char *key) & noexcept; + simdjson_inline simdjson_result operator[](std::string_view key) & noexcept; + simdjson_inline simdjson_result operator[](const char *key) & noexcept; + simdjson_result operator[](int) & noexcept = delete; + simdjson_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; + simdjson_inline simdjson_result find_field_unordered(const char *key) & noexcept; + simdjson_inline simdjson_result type() noexcept; + simdjson_inline simdjson_result is_scalar() noexcept; + simdjson_inline simdjson_result is_string() noexcept; + simdjson_inline simdjson_result current_location() noexcept; + simdjson_inline simdjson_result current_depth() const noexcept; + simdjson_inline simdjson_result is_negative() noexcept; + simdjson_inline simdjson_result is_integer() noexcept; + simdjson_inline simdjson_result get_number_type() noexcept; + simdjson_inline simdjson_result get_number() noexcept; + /** @copydoc simdjson_inline std::string_view document_reference::raw_json_token() const noexcept */ + simdjson_inline simdjson_result raw_json_token() noexcept; + + simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; + simdjson_inline simdjson_result at_path(std::string_view json_path) noexcept; + simdjson_inline simdjson_result> at_path_with_wildcard(std::string_view json_path) noexcept; +#if SIMDJSON_STATIC_REFLECTION + template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) + simdjson_warn_unused simdjson_inline error_code extract_into(T& out) & noexcept; +#endif // SIMDJSON_STATIC_REFLECTION +}; + + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H +/* end file simdjson/generic/ondemand/document.h for rvv_vls */ +/* including simdjson/generic/ondemand/document_stream.h for rvv_vls: #include "simdjson/generic/ondemand/document_stream.h" */ +/* begin file simdjson/generic/ondemand/document_stream.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#ifdef SIMDJSON_THREADS_ENABLED +#include +#include +#include +#endif + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +#ifdef SIMDJSON_THREADS_ENABLED +/** @private Custom worker class **/ +struct stage1_worker { + stage1_worker() noexcept = default; + stage1_worker(const stage1_worker&) = delete; + stage1_worker(stage1_worker&&) = delete; + stage1_worker operator=(const stage1_worker&) = delete; + ~stage1_worker(); + /** + * We only start the thread when it is needed, not at object construction, this may throw. + * You should only call this once. + **/ + void start_thread(); + /** + * Start a stage 1 job. You should first call 'run', then 'finish'. + * You must call start_thread once before. + */ + void run(document_stream * ds, parser * stage1, size_t next_batch_start); + /** Wait for the run to finish (blocking). You should first call 'run', then 'finish'. **/ + void finish(); + +private: + + /** + * Normally, we would never stop the thread. But we do in the destructor. + * This function is only safe assuming that you are not waiting for results. You + * should have called run, then finish, and be done. + **/ + void stop_thread(); + + std::thread thread{}; + /** These three variables define the work done by the thread. **/ + ondemand::parser * stage1_thread_parser{}; + size_t _next_batch_start{}; + document_stream * owner{}; + /** + * We have two state variables. This could be streamlined to one variable in the future but + * we use two for clarity. + */ + bool has_work{false}; + bool can_work{true}; + + /** + * We lock using a mutex. + */ + std::mutex locking_mutex{}; + std::condition_variable cond_var{}; + + friend class document_stream; +}; +#endif // SIMDJSON_THREADS_ENABLED + +/** + * A forward-only stream of documents. + * + * Produced by parser::iterate_many. + * + */ +class document_stream { +public: + /** + * Construct an uninitialized document_stream. + * + * ```cpp + * document_stream docs; + * auto error = parser.iterate_many(json).get(docs); + * ``` + */ + simdjson_inline document_stream() noexcept; + /** Move one document_stream to another. */ + simdjson_inline document_stream(document_stream &&other) noexcept = default; + /** Move one document_stream to another. */ + simdjson_inline document_stream &operator=(document_stream &&other) noexcept = default; + + simdjson_inline ~document_stream() noexcept; + + /** + * Returns the input size in bytes. + */ + inline size_t size_in_bytes() const noexcept; + + /** + * After iterating through the stream, this method + * returns the number of bytes that were not parsed at the end + * of the stream. If truncated_bytes() differs from zero, + * then the input was truncated maybe because incomplete JSON + * documents were found at the end of the stream. You + * may need to process the bytes in the interval [size_in_bytes()-truncated_bytes(), size_in_bytes()). + * + * You should only call truncated_bytes() after streaming through all + * documents, like so: + * + * document_stream stream = parser.iterate_many(json,window); + * for(auto & doc : stream) { + * // do something with doc + * } + * size_t truncated = stream.truncated_bytes(); + * + */ + inline size_t truncated_bytes() const noexcept; + + class iterator { + public: + using value_type = simdjson_result; + using reference = simdjson_result; + using pointer = void; + using difference_type = std::ptrdiff_t; + using iterator_category = std::input_iterator_tag; + + /** + * Default constructor. + */ + simdjson_inline iterator() noexcept; + simdjson_inline iterator(const iterator &other) noexcept = default; + /** + * Get the current document (or error). + */ + simdjson_inline reference operator*() noexcept; + /** + * Advance to the next document (prefix). + */ + inline iterator& operator++() noexcept; + /** + * Check if we're at the end yet. + * @param other the end iterator to compare to. + */ + simdjson_inline bool operator!=(const iterator &other) const noexcept; + simdjson_inline bool operator==(const iterator &other) const noexcept; + /** + * @private + * + * Gives the current index in the input document in bytes. + * + * document_stream stream = parser.parse_many(json,window); + * for(auto i = stream.begin(); i != stream.end(); ++i) { + * auto doc = *i; + * size_t index = i.current_index(); + * } + * + * This function (current_index()) is experimental and the usage + * may change in future versions of simdjson: we find the API somewhat + * awkward and we would like to offer something friendlier. + */ + simdjson_inline size_t current_index() const noexcept; + + /** + * @private + * + * Gives a view of the current document at the current position. + * + * document_stream stream = parser.iterate_many(json,window); + * for(auto i = stream.begin(); i != stream.end(); ++i) { + * std::string_view v = i.source(); + * } + * + * The returned string_view instance is simply a map to the (unparsed) + * source string: it may thus include white-space characters and all manner + * of padding. + * + * This function (source()) is experimental and the usage + * may change in future versions of simdjson: we find the API somewhat + * awkward and we would like to offer something friendlier. + * + */ + simdjson_inline std::string_view source() const noexcept; + + /** + * Returns error of the stream (if any). + */ + inline error_code error() const noexcept; + + /** + * Returns whether the iterator is at the end. + */ + inline bool at_end() const noexcept; + + private: + simdjson_inline iterator(document_stream *s, bool finished) noexcept; + /** The document_stream we're iterating through. */ + document_stream* stream; + /** Whether we're finished or not. */ + bool finished; + + friend class document; + friend class document_stream; + friend class json_iterator; + }; + using iterator = document_stream::iterator; + + /** + * Start iterating the documents in the stream. + */ + simdjson_inline iterator begin() noexcept; + /** + * The end of the stream, for iterator comparison purposes. + */ + simdjson_inline iterator end() noexcept; + +private: + + document_stream &operator=(const document_stream &) = delete; // Disallow copying + document_stream(const document_stream &other) = delete; // Disallow copying + + /** + * Construct a document_stream. Does not allocate or parse anything until the iterator is + * used. + * + * @param parser is a reference to the parser instance used to generate this document_stream + * @param buf is the raw byte buffer we need to process + * @param len is the length of the raw byte buffer in bytes + * @param batch_size is the size of the windows (must be strictly greater or equal to the largest JSON document) + */ + simdjson_inline document_stream( + ondemand::parser &parser, + const uint8_t *buf, + size_t len, + size_t batch_size, + bool allow_comma_separated + ) noexcept; + + /** + * Parse the first document in the buffer. Used by begin(), to handle allocation and + * initialization. + */ + inline void start() noexcept; + + /** + * Parse the next document found in the buffer previously given to document_stream. + * + * The content should be a valid JSON document encoded as UTF-8. If there is a + * UTF-8 BOM, the parser skips it. + * + * You do NOT need to pre-allocate a parser. This function takes care of + * pre-allocating a capacity defined by the batch_size defined when creating the + * document_stream object. + * + * The function returns simdjson::EMPTY if there is no more data to be parsed. + * + * The function returns simdjson::SUCCESS (as integer = 0) in case of success + * and indicates that the buffer has successfully been parsed to the end. + * Every document it contained has been parsed without error. + * + * The function returns an error code from simdjson/simdjson.h in case of failure + * such as simdjson::CAPACITY, simdjson::MEMALLOC, simdjson::DEPTH_ERROR and so forth; + * the simdjson::error_message function converts these error codes into a string). + * + * You can also check validity by calling parser.is_valid(). The same parser can + * and should be reused for the other documents in the buffer. + */ + inline void next() noexcept; + + /** Move the json_iterator of the document to the location of the next document in the stream. */ + inline void next_document() noexcept; + + /** Get the next document index. */ + inline size_t next_batch_start() const noexcept; + + /** Pass the next batch through stage 1 with the given parser. */ + inline error_code run_stage1(ondemand::parser &p, size_t batch_start) noexcept; + + // Fields + ondemand::parser *parser; + const uint8_t *buf; + size_t len; + size_t batch_size; + bool allow_comma_separated; + /** + * We are going to use just one document instance. The document owns + * the json_iterator. It implies that we only ever pass a reference + * to the document to the users. + */ + document doc{}; + /** The error (or lack thereof) from the current document. */ + error_code error; + size_t batch_start{0}; + size_t doc_index{}; + + #ifdef SIMDJSON_THREADS_ENABLED + /** Indicates whether we use threads. Note that this needs to be a constant during the execution of the parsing. */ + bool use_thread; + + inline void load_from_stage1_thread() noexcept; + + /** Start a thread to run stage 1 on the next batch. */ + inline void start_stage1_thread() noexcept; + + /** Wait for the stage 1 thread to finish and capture the results. */ + inline void finish_stage1_thread() noexcept; + + /** The error returned from the stage 1 thread. */ + error_code stage1_thread_error{UNINITIALIZED}; + /** The thread used to run stage 1 against the next batch in the background. */ + std::unique_ptr worker{new(std::nothrow) stage1_worker()}; + /** + * The parser used to run stage 1 in the background. Will be swapped + * with the regular parser when finished. + */ + ondemand::parser stage1_thread_parser{}; + + friend struct stage1_worker; + #endif // SIMDJSON_THREADS_ENABLED + + friend class parser; + friend class document; + friend class json_iterator; + friend struct simdjson_result; + friend struct simdjson::internal::simdjson_result_base; +}; // document_stream + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { +template<> +struct simdjson_result : public rvv_vls::implementation_simdjson_result_base { +public: + simdjson_inline simdjson_result(rvv_vls::ondemand::document_stream &&value) noexcept; ///< @private + simdjson_inline simdjson_result(error_code error) noexcept; ///< @private + simdjson_inline simdjson_result() noexcept = default; +}; + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H +/* end file simdjson/generic/ondemand/document_stream.h for rvv_vls */ +/* including simdjson/generic/ondemand/field.h for rvv_vls: #include "simdjson/generic/ondemand/field.h" */ +/* begin file simdjson/generic/ondemand/field.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +/** + * A JSON field (key/value pair) in an object. + * + * Returned from object iteration. + * + * Extends from std::pair so you can use C++ algorithms that rely on pairs. + */ +class field : public std::pair { +public: + /** + * Create a new invalid field. + * + * Exists so you can declare a variable and later assign to it before use. + */ + simdjson_inline field() noexcept; + + /** + * Get the key as a string_view (for higher speed, consider raw_key). + * We deliberately use a more cumbersome name (unescaped_key) to force users + * to think twice about using it. + * + * This consumes the key: once you have called unescaped_key(), you cannot + * call it again nor can you call key(). + */ + simdjson_inline simdjson_warn_unused simdjson_result unescaped_key(bool allow_replacement = false) noexcept; + /** + * Get the key as a string_view (for higher speed, consider raw_key). + * We deliberately use a more cumbersome name (unescaped_key) to force users + * to think twice about using it. The content is stored in the receiver. + * + * This consumes the key: once you have called unescaped_key(), you cannot + * call it again nor can you call key(). + */ + template + simdjson_inline simdjson_warn_unused error_code unescaped_key(string_type& receiver, bool allow_replacement = false) noexcept; + /** + * Get the key as a raw_json_string. Can be used for direct comparison with + * an unescaped C string: e.g., key() == "test". This does not count as + * consumption of the content: you can safely call it repeatedly. + * See escaped_key() for a similar function which returns + * a more convenient std::string_view result. + */ + simdjson_inline raw_json_string key() const noexcept; + /** + * Get the unprocessed key as a string_view. This includes the quotes and may include + * some spaces after the last quote. This does not count as + * consumption of the content: you can safely call it repeatedly. + * See escaped_key(). + */ + simdjson_inline std::string_view key_raw_json_token() const noexcept; + /** + * Get the key as a string_view. This does not include the quotes and + * the string is unprocessed key so it may contain escape characters + * (e.g., \uXXXX or \n). It does not count as a consumption of the content: + * you can safely call it repeatedly. Use unescaped_key() to get the unescaped key. + */ + simdjson_inline std::string_view escaped_key() const noexcept; + /** + * Get the field value. + */ + simdjson_inline ondemand::value &value() & noexcept; + /** + * @overload ondemand::value &ondemand::value() & noexcept + */ + simdjson_inline ondemand::value value() && noexcept; + +protected: + simdjson_inline field(raw_json_string key, ondemand::value &&value) noexcept; + static simdjson_inline simdjson_result start(value_iterator &parent_iter) noexcept; + static simdjson_inline simdjson_result start(const value_iterator &parent_iter, raw_json_string key) noexcept; + friend struct simdjson_result; + friend class object_iterator; +}; + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +template<> +struct simdjson_result : public rvv_vls::implementation_simdjson_result_base { +public: + simdjson_inline simdjson_result(rvv_vls::ondemand::field &&value) noexcept; ///< @private + simdjson_inline simdjson_result(error_code error) noexcept; ///< @private + simdjson_inline simdjson_result() noexcept = default; + + simdjson_inline simdjson_result unescaped_key(bool allow_replacement = false) noexcept; + template + simdjson_inline error_code unescaped_key(string_type &receiver, bool allow_replacement = false) noexcept; + simdjson_inline simdjson_result key() noexcept; + simdjson_inline simdjson_result key_raw_json_token() noexcept; + simdjson_inline simdjson_result escaped_key() noexcept; + simdjson_inline simdjson_result value() noexcept; +}; + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_H +/* end file simdjson/generic/ondemand/field.h for rvv_vls */ +/* including simdjson/generic/ondemand/object.h for rvv_vls: #include "simdjson/generic/ondemand/object.h" */ +/* begin file simdjson/generic/ondemand/object.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #if SIMDJSON_STATIC_REFLECTION && SIMDJSON_SUPPORTS_CONCEPTS */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_string_builder.h" // for constevalutil::fixed_string */ +/* amalgamation skipped (editor-only): #endif */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +/** + * A forward-only JSON object field iterator. + */ +class object { +public: + /** + * Create a new invalid object. + * + * Exists so you can declare a variable and later assign to it before use. + */ + simdjson_inline object() noexcept = default; + + /** + * Get an iterator to the start of the object. We recommend using a range-based for loop. + * + * Using the iterator directly is also possible but error-prone and discouraged. In particular, + * you must dereference the iterator exactly once per iteration (before calling '++'). + * Doing otherwise is unsafe and may lead to errors. You are responsible for ensuring + */ + simdjson_inline simdjson_result begin() noexcept; + simdjson_inline simdjson_result end() noexcept; + /** + * Look up a field by name on an object (order-sensitive). By order-sensitive, we mean that + * fields must be accessed in the order they appear in the JSON text (although you can + * skip fields). See find_field_unordered() and operator[] for an order-insensitive version. + * + * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the + * JSON `{ "x": 1, "y": 2, "z": 3 }`: + * + * ```cpp + * simdjson::ondemand::parser parser; + * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded); + * double z = obj.find_field("z"); + * double y = obj.find_field("y"); + * double x = obj.find_field("x"); + * ``` + * If you have multiple fields with a matching key ({"x": 1, "x": 1}) be mindful + * that only one field is returned. + * + * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys. + * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`. + * + * You must consume the fields on an object one at a time. A request for a new key + * invalidates previous field values: it makes them unsafe. The value instance you get + * from `content["bids"]` becomes invalid when you call `content["asks"]`. The array + * given by content["bids"].get_array() should not be accessed after you have called + * content["asks"].get_array(). You can detect such mistakes by first compiling and running + * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an + * OUT_OF_ORDER_ITERATION error is generated. + * + * You are expected to access keys only once. You should access the value corresponding to a + * key a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string() + * is an error. + * + * If you expect to have keys with escape characters, please review our documentation. + * + * @param key The key to look up. + * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object. + */ + simdjson_inline simdjson_result find_field(std::string_view key) & noexcept; + /** @overload simdjson_inline simdjson_result find_field(std::string_view key) & noexcept; */ + simdjson_inline simdjson_result find_field(std::string_view key) && noexcept; + + /** + * Look up a field by name on an object, without regard to key order. + * + * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies + * and often appears negligible. It starts out normally, starting out at the last field; but if + * the field is not found, it scans from the beginning of the object to see if it missed it. That + * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object + * in question is large. The fact that the extra code is there also bumps the executable size. + * + * We default operator[] on find_field_unordered() for convenience. + * It is the default because it would be highly surprising (and hard to debug) if the + * default behavior failed to look up a field just because it was in the wrong order--and many + * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order. + * + * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the + * field was not there when they are not in order). + * + * If you have multiple fields with a matching key ({"x": 1, "x": 1}) be mindful + * that only one field is returned. + * + * You must consume the fields on an object one at a time. A request for a new key + * invalidates previous field values: it makes them unsafe. The value instance you get + * from `content["bids"]` becomes invalid when you call `content["asks"]`. The array + * given by content["bids"].get_array() should not be accessed after you have called + * content["asks"].get_array(). You can detect such mistakes by first compiling and running + * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an + * OUT_OF_ORDER_ITERATION error is generated. + * + * You are expected to access keys only once. You should access the value corresponding to a key + * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string() is an error. + * + * If you expect to have keys with escape characters, please review our documentation. + * + * @param key The key to look up. + * @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object. + */ + simdjson_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; + /** @overload simdjson_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ + simdjson_inline simdjson_result find_field_unordered(std::string_view key) && noexcept; + /** @overload simdjson_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ + simdjson_inline simdjson_result operator[](std::string_view key) & noexcept; + /** @overload simdjson_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ + simdjson_inline simdjson_result operator[](std::string_view key) && noexcept; + + /** + * Get the value associated with the given JSON pointer. We use the RFC 6901 + * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node + * as the root of its own JSON document. + * + * ondemand::parser parser; + * auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded; + * auto doc = parser.iterate(json); + * doc.at_pointer("/foo/a/1") == 20 + * + * It is allowed for a key to be the empty string: + * + * ondemand::parser parser; + * auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded; + * auto doc = parser.iterate(json); + * doc.at_pointer("//a/1") == 20 + * + * Note that at_pointer() called on the document automatically calls the document's rewind + * method between each call. It invalidates all previously accessed arrays, objects and values + * that have not been consumed. Yet it is not the case when calling at_pointer on an object + * instance: there is no rewind and no invalidation. + * + * You may call at_pointer more than once on an object, but each time the pointer is advanced + * to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding + * key (as well as the current key) can no longer be used with following JSON pointer calls. + * + * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching. + * + * @return The value associated with the given JSON pointer, or: + * - NO_SUCH_FIELD if a field does not exist in an object + * - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length + * - INCORRECT_TYPE if a non-integer is used to access an array + * - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed + */ + inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; + + /** + * Get the value associated with the given JSONPath expression. We only support + * JSONPath queries that trivially convertible to JSON Pointer queries: key + * names and array indices. + * + * @return The value associated with the given JSONPath expression, or: + * - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails + * - NO_SUCH_FIELD if a field does not exist in an object + * - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length + * - INCORRECT_TYPE if a non-integer is used to access an array + */ + inline simdjson_result at_path(std::string_view json_path) noexcept; + + /** + * Get all values matching the given JSONPath expression with wildcard support. + * Supports wildcard patterns like ".*" to match all object fields. + * + * @param json_path JSONPath expression with wildcards + * @return Vector of values matching the wildcard pattern + */ + inline simdjson_result> at_path_with_wildcard(std::string_view json_path) noexcept; + + /** + * Reset the iterator so that we are pointing back at the + * beginning of the object. You should still consume values only once even if you + * can iterate through the object more than once. If you unescape a string or a key + * within the object more than once, you have unsafe code. Note that rewinding an object + * means that you may need to reparse it anew: it is not a free operation. + * + * @returns true if the object contains some elements (not empty) + */ + inline simdjson_result reset() & noexcept; + /** + * This method scans the beginning of the object and checks whether the + * object is empty. + * The runtime complexity is constant time. After + * calling this function, if successful, the object is 'rewinded' at its + * beginning as if it had never been accessed. If the JSON is malformed (e.g., + * there is a missing comma), then an error is returned and it is no longer + * safe to continue. + */ + inline simdjson_result is_empty() & noexcept; + /** + * This method scans the object and counts the number of key-value pairs. + * The count_fields method should always be called before you have begun + * iterating through the object: it is expected that you are pointing at + * the beginning of the object. + * The runtime complexity is linear in the size of the object. After + * calling this function, if successful, the object is 'rewinded' at its + * beginning as if it had never been accessed. If the JSON is malformed (e.g., + * there is a missing comma), then an error is returned and it is no longer + * safe to continue. + * + * To check that an object is empty, it is more performant to use + * the is_empty() method. + * + * Performance hint: You should only call count_fields() as a last + * resort as it may require scanning the document twice or more. + */ + simdjson_inline simdjson_result count_fields() & noexcept; + /** + * Consumes the object and returns a string_view instance corresponding to the + * object as represented in JSON. It points inside the original byte array containing + * the JSON document. + */ + simdjson_inline simdjson_result raw_json() noexcept; + +#if SIMDJSON_SUPPORTS_CONCEPTS + /** + * Get this object as the given type. + * + * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized. + * @returns INCORRECT_TYPE If the JSON object is not of the given type. + * @returns SUCCESS If the parse succeeded and the out parameter was set to the value. + */ + template + simdjson_warn_unused simdjson_inline error_code get(T &out) + noexcept(custom_deserializable ? nothrow_custom_deserializable : true) { + static_assert(custom_deserializable); + return deserialize(*this, out); + } + /** + * Get this array as the given type. + * + * @returns A value of the given type, parsed from the JSON. + * @returns INCORRECT_TYPE If the JSON value is not the given type. + */ + template + simdjson_inline simdjson_result get() + noexcept(custom_deserializable ? nothrow_custom_deserializable : true) + { + static_assert(std::is_default_constructible::value, "The specified type is not default constructible."); + T out{}; + SIMDJSON_TRY(get(out)); + return out; + } + +#if SIMDJSON_STATIC_REFLECTION + /** + * Extract only specific fields from the JSON object into a struct. + * + * This allows selective deserialization of only the fields you need, + * potentially improving performance by skipping unwanted fields. + * + * Example: + * ```cpp + * struct Car { + * std::string make; + * std::string model; + * int year; + * double price; + * }; + * + * Car car; + * object.extract_into<"make", "model">(car); + * // Only 'make' and 'model' fields are extracted from JSON + * ``` + * + * @tparam FieldNames Compile-time string literals specifying which fields to extract + * @param out The output struct to populate with selected fields + * @returns SUCCESS on success, or an error code if a required field is missing or has wrong type + */ + template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) + simdjson_warn_unused simdjson_inline error_code extract_into(T& out) & noexcept; +#endif // SIMDJSON_STATIC_REFLECTION +#endif // SIMDJSON_SUPPORTS_CONCEPTS +protected: + /** + * Go to the end of the object, no matter where you are right now. + */ + simdjson_warn_unused simdjson_inline error_code consume() noexcept; + static simdjson_inline simdjson_result start(value_iterator &iter) noexcept; + static simdjson_inline simdjson_result start_root(value_iterator &iter) noexcept; + static simdjson_inline simdjson_result started(value_iterator &iter) noexcept; + static simdjson_inline object resume(const value_iterator &iter) noexcept; + simdjson_inline object(const value_iterator &iter) noexcept; + + simdjson_warn_unused simdjson_inline error_code find_field_raw(const std::string_view key) noexcept; + + value_iterator iter{}; + + friend class value; + friend class document; + friend struct simdjson_result; +}; + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +template<> +struct simdjson_result : public rvv_vls::implementation_simdjson_result_base { +public: + simdjson_inline simdjson_result(rvv_vls::ondemand::object &&value) noexcept; ///< @private + simdjson_inline simdjson_result(error_code error) noexcept; ///< @private + simdjson_inline simdjson_result() noexcept = default; + + simdjson_inline simdjson_result begin() noexcept; + simdjson_inline simdjson_result end() noexcept; + simdjson_inline simdjson_result find_field(std::string_view key) & noexcept; + simdjson_inline simdjson_result find_field(std::string_view key) && noexcept; + simdjson_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; + simdjson_inline simdjson_result find_field_unordered(std::string_view key) && noexcept; + simdjson_inline simdjson_result operator[](std::string_view key) & noexcept; + simdjson_inline simdjson_result operator[](std::string_view key) && noexcept; + simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; + simdjson_inline simdjson_result at_path(std::string_view json_path) noexcept; + simdjson_inline simdjson_result> at_path_with_wildcard(std::string_view json_path) noexcept; + inline simdjson_result reset() noexcept; + inline simdjson_result is_empty() noexcept; + inline simdjson_result count_fields() & noexcept; + inline simdjson_result raw_json() noexcept; + #if SIMDJSON_SUPPORTS_CONCEPTS + // TODO: move this code into object-inl.h + + template + simdjson_inline simdjson_result get() noexcept { + if (error()) { return error(); } + if constexpr (std::is_same_v) { + return first; + } + return first.get(); + } + template + simdjson_warn_unused simdjson_inline error_code get(T& out) noexcept { + if (error()) { return error(); } + if constexpr (std::is_same_v) { + out = first; + } else { + SIMDJSON_TRY( first.get(out) ); + } + return SUCCESS; + } + +#if SIMDJSON_STATIC_REFLECTION + // TODO: move this code into object-inl.h + template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) + simdjson_warn_unused simdjson_inline error_code extract_into(T& out) noexcept { + if (error()) { return error(); } + return first.extract_into(out); + } +#endif // SIMDJSON_STATIC_REFLECTION +#endif // SIMDJSON_SUPPORTS_CONCEPTS +}; + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_H +/* end file simdjson/generic/ondemand/object.h for rvv_vls */ +/* including simdjson/generic/ondemand/object_iterator.h for rvv_vls: #include "simdjson/generic/ondemand/object_iterator.h" */ +/* begin file simdjson/generic/ondemand/object_iterator.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +class object_iterator { +public: + /** + * Create a new invalid object_iterator. + * + * Exists so you can declare a variable and later assign to it before use. + */ + simdjson_inline object_iterator() noexcept = default; + + // + // Iterator interface + // + + // Reads key and value, yielding them to the user. + // MUST ONLY BE CALLED ONCE PER ITERATION. + simdjson_inline simdjson_result operator*() noexcept; + // Assumes it's being compared with the end. true if depth < iter->depth. + simdjson_inline bool operator==(const object_iterator &) const noexcept; + // Assumes it's being compared with the end. true if depth >= iter->depth. + simdjson_inline bool operator!=(const object_iterator &) const noexcept; + // Checks for ']' and ',' + // YOU MUST NOT CALL THIS IF operator* YIELDED AN ERROR. + // YOU MUST NOT CALL THIS WITHOUT A CORRESPONDING operator* CALL. + simdjson_inline object_iterator &operator++() noexcept; + +private: +#if SIMDJSON_DEVELOPMENT_CHECKS + bool has_been_referenced{false}; +#endif + /** + * The underlying JSON iterator. + * + * PERF NOTE: expected to be elided in favor of the parent document: this is set when the object + * is first used, and never changes afterwards. + */ + value_iterator iter{}; + + simdjson_inline object_iterator(const value_iterator &iter) noexcept; + friend struct simdjson_result; + friend class object; +}; + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +template<> +struct simdjson_result : public rvv_vls::implementation_simdjson_result_base { +public: + simdjson_inline simdjson_result(rvv_vls::ondemand::object_iterator &&value) noexcept; ///< @private + simdjson_inline simdjson_result(error_code error) noexcept; ///< @private + simdjson_inline simdjson_result() noexcept = default; + + // + // Iterator interface + // + + // Reads key and value, yielding them to the user. + simdjson_inline simdjson_result operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION. + // Assumes it's being compared with the end. true if depth < iter->depth. + simdjson_inline bool operator==(const simdjson_result &) const noexcept; + // Assumes it's being compared with the end. true if depth >= iter->depth. + simdjson_inline bool operator!=(const simdjson_result &) const noexcept; + // Checks for ']' and ',' + simdjson_inline simdjson_result &operator++() noexcept; +}; + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_H +/* end file simdjson/generic/ondemand/object_iterator.h for rvv_vls */ +/* including simdjson/generic/ondemand/serialization.h for rvv_vls: #include "simdjson/generic/ondemand/serialization.h" */ +/* begin file simdjson/generic/ondemand/serialization.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +/** + * Create a string-view instance out of a document instance. The string-view instance + * contains JSON text that is suitable to be parsed as JSON again. It does not + * validate the content. + */ +inline simdjson_result to_json_string(rvv_vls::ondemand::document& x) noexcept; +/** + * Create a string-view instance out of a value instance. The string-view instance + * contains JSON text that is suitable to be parsed as JSON again. The value must + * not have been accessed previously. It does not + * validate the content. + */ +inline simdjson_result to_json_string(rvv_vls::ondemand::value& x) noexcept; +/** + * Create a string-view instance out of an object instance. The string-view instance + * contains JSON text that is suitable to be parsed as JSON again. It does not + * validate the content. + */ +inline simdjson_result to_json_string(rvv_vls::ondemand::object& x) noexcept; +/** + * Create a string-view instance out of an array instance. The string-view instance + * contains JSON text that is suitable to be parsed as JSON again. It does not + * validate the content. + */ +inline simdjson_result to_json_string(rvv_vls::ondemand::array& x) noexcept; +inline simdjson_result to_json_string(simdjson_result x); +inline simdjson_result to_json_string(simdjson_result x); +inline simdjson_result to_json_string(simdjson_result x); +inline simdjson_result to_json_string(simdjson_result x); + +#if SIMDJSON_STATIC_REFLECTION +/** + * Create a JSON string from any user-defined type using static reflection. + * Only available when SIMDJSON_STATIC_REFLECTION is enabled. + */ +template + requires(!std::same_as && + !std::same_as && + !std::same_as && + !std::same_as) +inline std::string to_json_string(const T& obj); +#endif + +} // namespace simdjson + +/** + * We want to support argument-dependent lookup (ADL). + * Hence we should define operator<< in the namespace + * where the argument (here value, object, etc.) resides. + * Credit: @madhur4127 + * See https://github.com/simdjson/simdjson/issues/1768 + */ +namespace simdjson { namespace rvv_vls { namespace ondemand { + +/** + * Print JSON to an output stream. It does not + * validate the content. + * + * @param out The output stream. + * @param value The element. + * @throw if there is an error with the underlying output stream. simdjson itself will not throw. + */ +inline std::ostream& operator<<(std::ostream& out, simdjson::rvv_vls::ondemand::value x); +#if SIMDJSON_EXCEPTIONS +inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result x); +#endif +/** + * Print JSON to an output stream. It does not + * validate the content. + * + * @param out The output stream. + * @param value The array. + * @throw if there is an error with the underlying output stream. simdjson itself will not throw. + */ +inline std::ostream& operator<<(std::ostream& out, simdjson::rvv_vls::ondemand::array value); +#if SIMDJSON_EXCEPTIONS +inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result x); +#endif +/** + * Print JSON to an output stream. It does not + * validate the content. + * + * @param out The output stream. + * @param value The array. + * @throw if there is an error with the underlying output stream. simdjson itself will not throw. + */ +inline std::ostream& operator<<(std::ostream& out, simdjson::rvv_vls::ondemand::document& value); +#if SIMDJSON_EXCEPTIONS +inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result&& x); +#endif +inline std::ostream& operator<<(std::ostream& out, simdjson::rvv_vls::ondemand::document_reference& value); +#if SIMDJSON_EXCEPTIONS +inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result&& x); +#endif +/** + * Print JSON to an output stream. It does not + * validate the content. + * + * @param out The output stream. + * @param value The object. + * @throw if there is an error with the underlying output stream. simdjson itself will not throw. + */ +inline std::ostream& operator<<(std::ostream& out, simdjson::rvv_vls::ondemand::object value); +#if SIMDJSON_EXCEPTIONS +inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result x); +#endif +}}} // namespace simdjson::rvv_vls::ondemand + +#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_H +/* end file simdjson/generic/ondemand/serialization.h for rvv_vls */ + +// Deserialization for standard types +/* including simdjson/generic/ondemand/std_deserialize.h for rvv_vls: #include "simdjson/generic/ondemand/std_deserialize.h" */ +/* begin file simdjson/generic/ondemand/std_deserialize.h for rvv_vls */ +#if SIMDJSON_SUPPORTS_CONCEPTS + +#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_ONDEMAND_DESERIALIZE_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include +#include +#if SIMDJSON_STATIC_REFLECTION +#include +// #include // for std::define_static_string - header not available yet +#endif + +namespace simdjson { + +////////////////////////////// +// Number deserialization +////////////////////////////// + +template +error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { + using limits = std::numeric_limits; + + uint64_t x; + SIMDJSON_TRY(val.get_uint64().get(x)); + if (x > (limits::max)()) { + return NUMBER_OUT_OF_RANGE; + } + out = static_cast(x); + return SUCCESS; +} + +template +error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { + double x; + SIMDJSON_TRY(val.get_double().get(x)); + out = static_cast(x); + return SUCCESS; +} + +template +error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { + using limits = std::numeric_limits; + + int64_t x; + SIMDJSON_TRY(val.get_int64().get(x)); + if (x > (limits::max)() || x < (limits::min)()) { + return NUMBER_OUT_OF_RANGE; + } + out = static_cast(x); + return SUCCESS; +} + +////////////////////////////// +// String deserialization +////////////////////////////// + +// just a character! +error_code tag_invoke(deserialize_tag, auto &val, char &out) noexcept { + std::string_view x; + SIMDJSON_TRY(val.get_string().get(x)); + if(x.size() != 1) { + return INCORRECT_TYPE; + } + out = x[0]; + return SUCCESS; +} + +// any string-like type (can be constructed from std::string_view) +template +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v) { + std::string_view str; + SIMDJSON_TRY(val.get_string().get(str)); + out = T{str}; + return SUCCESS; +} + + +/** + * STL containers have several constructors including one that takes a single + * size argument. Thus, some compilers (Visual Studio) will not be able to + * disambiguate between the size and container constructor. Users should + * explicitly specify the type of the container as needed: e.g., + * doc.get>(). + */ +template +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { + using value_type = typename std::remove_cvref_t::value_type; + static_assert( + deserializable, + "The specified type inside the container must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified type inside the container must default constructible."); + rvv_vls::ondemand::array arr; + if constexpr (std::is_same_v, rvv_vls::ondemand::array>) { + arr = val; + } else { + SIMDJSON_TRY(val.get_array().get(arr)); + } + + for (auto v : arr) { + if constexpr (concepts::returns_reference) { + if (auto const err = v.get().get(concepts::emplace_one(out)); + err) { + // If an error occurs, the empty element that we just inserted gets + // removed. We're not using a temp variable because if T is a heavy + // type, we want the valid path to be the fast path and the slow path be + // the path that has errors in it. + if constexpr (requires { out.pop_back(); }) { + static_cast(out.pop_back()); + } + return err; + } + } else { + value_type temp; + if (auto const err = v.get().get(temp); err) { + return err; + } + concepts::emplace_one(out, std::move(temp)); + } + } + return SUCCESS; +} + + +/** + * We want to support std::map and std::unordered_map but only for + * string-keyed types. + */ + template +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { + using value_type = typename std::remove_cvref_t::mapped_type; + static_assert( + deserializable, + "The specified value type inside the container must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified value type inside the container must default constructible."); + rvv_vls::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + for (auto field : obj) { + std::string_view key; + SIMDJSON_TRY(field.unescaped_key().get(key)); + value_type this_value; + SIMDJSON_TRY(field.value().get().get(this_value)); + [[maybe_unused]] std::pair result = out.emplace(key, this_value); + // unclear what to do if the key already exists + // if (result.second == false) { + // // key already exists + // } + } + (void)out; + return SUCCESS; +} + +template +error_code tag_invoke(deserialize_tag, rvv_vls::ondemand::object &obj, T &out) noexcept { + using value_type = typename std::remove_cvref_t::mapped_type; + + out.clear(); + for (auto field : obj) { + std::string_view key; + SIMDJSON_TRY(field.unescaped_key().get(key)); + + rvv_vls::ondemand::value value_obj; + SIMDJSON_TRY(field.value().get(value_obj)); + + value_type this_value; + SIMDJSON_TRY(value_obj.get(this_value)); + out.emplace(typename T::key_type(key), std::move(this_value)); + } + return SUCCESS; +} + +template +error_code tag_invoke(deserialize_tag, rvv_vls::ondemand::value &val, T &out) noexcept { + rvv_vls::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} + +template +error_code tag_invoke(deserialize_tag, rvv_vls::ondemand::document &doc, T &out) noexcept { + rvv_vls::ondemand::object obj; + SIMDJSON_TRY(doc.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} + +template +error_code tag_invoke(deserialize_tag, rvv_vls::ondemand::document_reference &doc, T &out) noexcept { + rvv_vls::ondemand::object obj; + SIMDJSON_TRY(doc.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} + + +/** + * This CPO (Customization Point Object) will help deserialize into + * smart pointers. + * + * If constructing T is nothrow, this conversion should be nothrow as well since + * we return MEMALLOC if we're not able to allocate memory instead of throwing + * the error message. + * + * @tparam T The type inside the smart pointer + * @tparam ValT document/value type + * @param val document/value + * @param out a reference to the smart pointer + * @return status of the conversion + */ +template +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable::element_type, ValT>) { + using element_type = typename std::remove_cvref_t::element_type; + + // For better error messages, don't use these as constraints on + // the tag_invoke CPO. + static_assert( + deserializable, + "The specified type inside the unique_ptr must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified type inside the unique_ptr must default constructible."); + + auto ptr = new (std::nothrow) element_type(); + if (ptr == nullptr) { + return MEMALLOC; + } + SIMDJSON_TRY(val.template get(*ptr)); + out.reset(ptr); + return SUCCESS; +} + +/** + * This CPO (Customization Point Object) will help deserialize into optional types. + */ +template +error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept(nothrow_deserializable::value_type, decltype(val)>) { + using value_type = typename std::remove_cvref_t::value_type; + + // Check if the value is null + bool is_null_value; + SIMDJSON_TRY( val.is_null().get(is_null_value) ); + if (is_null_value) { + out.reset(); // Set to nullopt + return SUCCESS; + } + + if (!out) { + out.emplace(); + } + SIMDJSON_TRY(val.template get(out.value())); + return SUCCESS; +} + + +#if SIMDJSON_STATIC_REFLECTION + + +template +constexpr bool user_defined_type = (std::is_class_v +&& !std::is_same_v && !std::is_same_v && !concepts::optional_type && +!concepts::appendable_containers); + + +template + requires(user_defined_type && std::is_class_v) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept { + rvv_vls::ondemand::object obj; + if constexpr (std::is_same_v, rvv_vls::ondemand::object>) { + obj = val; + } else { + SIMDJSON_TRY(val.get_object().get(obj)); + } + template for (constexpr auto mem : std::define_static_array(std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()))) { + if constexpr (!std::meta::is_const(mem) && std::meta::is_public(mem)) { + constexpr std::string_view key = std::define_static_string(std::meta::identifier_of(mem)); + if constexpr (concepts::optional_type) { + // for optional members, it's ok if the key is missing + auto error = obj[key].get(out.[:mem:]); + if (error && error != NO_SUCH_FIELD) { + if(error == NO_SUCH_FIELD) { + out.[:mem:].reset(); + continue; + } + return error; + } + } else { + // for non-optional members, the key must be present + SIMDJSON_TRY(obj[key].get(out.[:mem:])); + } + } + }; + return simdjson::SUCCESS; +} + +// Support for enum deserialization - deserialize from string representation using expand approach from P2996R12 +template + requires(std::is_enum_v) +error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept { +#if SIMDJSON_STATIC_REFLECTION + std::string_view str; + SIMDJSON_TRY(val.get_string().get(str)); + constexpr auto enumerators = std::define_static_array(std::meta::enumerators_of(^^T)); + template for (constexpr auto enum_val : enumerators) { + if (str == std::meta::identifier_of(enum_val)) { + out = [:enum_val:]; + return SUCCESS; + } + }; + + return INCORRECT_TYPE; +#else + // Fallback: deserialize as integer if reflection not available + std::underlying_type_t int_val; + SIMDJSON_TRY(val.get(int_val)); + out = static_cast(int_val); + return SUCCESS; +#endif +} + +template + requires(user_defined_type>) +error_code tag_invoke(deserialize_tag, simdjson_value &val, std::unique_ptr &out) noexcept { + if (!out) { + out = std::make_unique(); + if (!out) { + return MEMALLOC; + } + } + if (auto err = val.get(*out)) { + out.reset(); + return err; + } + return SUCCESS; +} + +template + requires(user_defined_type>) +error_code tag_invoke(deserialize_tag, simdjson_value &val, std::shared_ptr &out) noexcept { + if (!out) { + out = std::make_shared(); + if (!out) { + return MEMALLOC; + } + } + if (auto err = val.get(*out)) { + out.reset(); + return err; + } + return SUCCESS; +} + +#endif // SIMDJSON_STATIC_REFLECTION + +//////////////////////////////////////// +// Unique pointers +//////////////////////////////////////// +error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr &out) noexcept { + bool is_null_value; + SIMDJSON_TRY( val.is_null().get(is_null_value) ); + if (is_null_value) { + out.reset(); + return SUCCESS; + } + if (!out) { + out = std::make_unique(); + if (!out) { return MEMALLOC; } + } + SIMDJSON_TRY(val.get_bool().get(*out)); + return SUCCESS; +} + +error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr &out) noexcept { + bool is_null_value; + SIMDJSON_TRY( val.is_null().get(is_null_value) ); + if (is_null_value) { + out.reset(); + return SUCCESS; + } + if (!out) { + out = std::make_unique(); + if (!out) { return MEMALLOC; } + } + SIMDJSON_TRY(val.get_int64().get(*out)); + return SUCCESS; +} + +error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr &out) noexcept { + bool is_null_value; + SIMDJSON_TRY( val.is_null().get(is_null_value) ); + if (is_null_value) { + out.reset(); + return SUCCESS; + } + if (!out) { + out = std::make_unique(); + if (!out) { return MEMALLOC; } + } + SIMDJSON_TRY(val.get_uint64().get(*out)); + return SUCCESS; +} + +error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr &out) noexcept { + bool is_null_value; + SIMDJSON_TRY( val.is_null().get(is_null_value) ); + if (is_null_value) { + out.reset(); + return SUCCESS; + } + if (!out) { + out = std::make_unique(); + if (!out) { return MEMALLOC; } + } + SIMDJSON_TRY(val.get_double().get(*out)); + return SUCCESS; +} + +error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr &out) noexcept { + bool is_null_value; + SIMDJSON_TRY( val.is_null().get(is_null_value) ); + if (is_null_value) { + out.reset(); + return SUCCESS; + } + if (!out) { + out = std::make_unique(); + if (!out) { return MEMALLOC; } + } + SIMDJSON_TRY(val.get_string().get(*out)); + return SUCCESS; +} + + +//////////////////////////////////////// +// Shared pointers +//////////////////////////////////////// +error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr &out) noexcept { + bool is_null_value; + SIMDJSON_TRY( val.is_null().get(is_null_value) ); + if (is_null_value) { + out.reset(); + return SUCCESS; + } + if (!out) { + out = std::make_shared(); + if (!out) { return MEMALLOC; } + } + SIMDJSON_TRY(val.get_bool().get(*out)); + return SUCCESS; +} + +error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr &out) noexcept { + bool is_null_value; + SIMDJSON_TRY( val.is_null().get(is_null_value) ); + if (is_null_value) { + out.reset(); + return SUCCESS; + } + if (!out) { + out = std::make_shared(); + if (!out) { return MEMALLOC; } + } + SIMDJSON_TRY(val.get_int64().get(*out)); + return SUCCESS; +} + +error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr &out) noexcept { + bool is_null_value; + SIMDJSON_TRY( val.is_null().get(is_null_value) ); + if (is_null_value) { + out.reset(); + return SUCCESS; + } + if (!out) { + out = std::make_shared(); + if (!out) { return MEMALLOC; } + } + SIMDJSON_TRY(val.get_uint64().get(*out)); + return SUCCESS; +} + +error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr &out) noexcept { + bool is_null_value; + SIMDJSON_TRY( val.is_null().get(is_null_value) ); + if (is_null_value) { + out.reset(); + return SUCCESS; + } + if (!out) { + out = std::make_shared(); + if (!out) { return MEMALLOC; } + } + SIMDJSON_TRY(val.get_double().get(*out)); + return SUCCESS; +} + +error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr &out) noexcept { + bool is_null_value; + SIMDJSON_TRY( val.is_null().get(is_null_value) ); + if (is_null_value) { + out.reset(); + return SUCCESS; + } + if (!out) { + out = std::make_shared(); + if (!out) { return MEMALLOC; } + } + SIMDJSON_TRY(val.get_string().get(*out)); + return SUCCESS; +} + + +//////////////////////////////////////// +// Explicit optional specializations +//////////////////////////////////////// + +//////////////////////////////////////// +// Explicit smart pointer specializations for string and int types +//////////////////////////////////////// +error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr &out) noexcept { + // Check if the value is null + bool is_null_value; + SIMDJSON_TRY( val.is_null().get(is_null_value) ); + if (is_null_value) { + out.reset(); // Set to nullptr + return SUCCESS; + } + + if (!out) { + out = std::make_unique(); + } + std::string_view str; + SIMDJSON_TRY(val.get_string().get(str)); + *out = std::string{str}; + return SUCCESS; +} + +error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr &out) noexcept { + // Check if the value is null + bool is_null_value; + SIMDJSON_TRY( val.is_null().get(is_null_value) ); + if (is_null_value) { + out.reset(); // Set to nullptr + return SUCCESS; + } + + if (!out) { + out = std::make_shared(); + } + std::string_view str; + SIMDJSON_TRY(val.get_string().get(str)); + *out = std::string{str}; + return SUCCESS; +} + +error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr &out) noexcept { + // Check if the value is null + bool is_null_value; + SIMDJSON_TRY( val.is_null().get(is_null_value) ); + if (is_null_value) { + out.reset(); // Set to nullptr + return SUCCESS; + } + + if (!out) { + out = std::make_unique(); + } + int64_t temp; + SIMDJSON_TRY(val.get_int64().get(temp)); + *out = static_cast(temp); + return SUCCESS; +} + +} // namespace simdjson + +#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H +#endif // SIMDJSON_SUPPORTS_CONCEPTS +/* end file simdjson/generic/ondemand/std_deserialize.h for rvv_vls */ + +// Inline definitions +/* including simdjson/generic/ondemand/array-inl.h for rvv_vls: #include "simdjson/generic/ondemand/array-inl.h" */ +/* begin file simdjson/generic/ondemand/array-inl.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H */ +/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator-inl.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +// +// ### Live States +// +// While iterating or looking up values, depth >= iter->depth. at_start may vary. Error is +// always SUCCESS: +// +// - Start: This is the state when the array is first found and the iterator is just past the `{`. +// In this state, at_start == true. +// - Next: After we hand a scalar value to the user, or an array/object which they then fully +// iterate over, the iterator is at the `,` before the next value (or `]`). In this state, +// depth == iter->depth, at_start == false, and error == SUCCESS. +// - Unfinished Business: When we hand an array/object to the user which they do not fully +// iterate over, we need to finish that iteration by skipping child values until we reach the +// Next state. In this state, depth > iter->depth, at_start == false, and error == SUCCESS. +// +// ## Error States +// +// In error states, we will yield exactly one more value before stopping. iter->depth == depth +// and at_start is always false. We decrement after yielding the error, moving to the Finished +// state. +// +// - Chained Error: When the array iterator is part of an error chain--for example, in +// `for (auto tweet : doc["tweets"])`, where the tweet element may be missing or not be an +// array--we yield that error in the loop, exactly once. In this state, error != SUCCESS and +// iter->depth == depth, and at_start == false. We decrement depth when we yield the error. +// - Missing Comma Error: When the iterator ++ method discovers there is no comma between elements, +// we flag that as an error and treat it exactly the same as a Chained Error. In this state, +// error == TAPE_ERROR, iter->depth == depth, and at_start == false. +// +// ## Terminal State +// +// The terminal state has iter->depth < depth. at_start is always false. +// +// - Finished: When we have reached a `]` or have reported an error, we are finished. We signal this +// by decrementing depth. In this state, iter->depth < depth, at_start == false, and +// error == SUCCESS. +// + +simdjson_inline array::array(const value_iterator &_iter) noexcept + : iter{_iter} +{ +} + +simdjson_inline simdjson_result array::start(value_iterator &iter) noexcept { + // We don't need to know if the array is empty to start iteration, but we do want to know if there + // is an error--thus `simdjson_unused`. + simdjson_unused bool has_value; + SIMDJSON_TRY( iter.start_array().get(has_value) ); + return array(iter); +} +simdjson_inline simdjson_result array::start_root(value_iterator &iter) noexcept { + simdjson_unused bool has_value; + SIMDJSON_TRY( iter.start_root_array().get(has_value) ); + return array(iter); +} +simdjson_inline simdjson_result array::started(value_iterator &iter) noexcept { + bool has_value; + SIMDJSON_TRY(iter.started_array().get(has_value)); + return array(iter); +} + +simdjson_inline simdjson_result array::begin() noexcept { +#if SIMDJSON_DEVELOPMENT_CHECKS + if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; } +#endif + return array_iterator(iter); +} +simdjson_inline simdjson_result array::end() noexcept { + return array_iterator(iter); +} +simdjson_warn_unused simdjson_warn_unused simdjson_inline error_code array::consume() noexcept { + auto error = iter.json_iter().skip_child(iter.depth()-1); + if(error) { iter.abandon(); } + return error; +} + +simdjson_inline simdjson_result array::raw_json() noexcept { + const uint8_t * starting_point{iter.peek_start()}; + auto error = consume(); + if(error) { return error; } + // After 'consume()', we could be left pointing just beyond the document, but that + // is ok because we are not going to dereference the final pointer position, we just + // use it to compute the length in bytes. + const uint8_t * final_point{iter._json_iter->unsafe_pointer()}; + return std::string_view(reinterpret_cast(starting_point), size_t(final_point - starting_point)); +} + +SIMDJSON_PUSH_DISABLE_WARNINGS +SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING +simdjson_inline simdjson_result array::count_elements() & noexcept { + size_t count{0}; + // Important: we do not consume any of the values. + for(simdjson_unused auto v : *this) { count++; } + // The above loop will always succeed, but we want to report errors. + if(iter.error()) { return iter.error(); } + // We need to move back at the start because we expect users to iterate through + // the array after counting the number of elements. + iter.reset_array(); + return count; +} +SIMDJSON_POP_DISABLE_WARNINGS + +simdjson_inline simdjson_result array::is_empty() & noexcept { + bool is_not_empty; + auto error = iter.reset_array().get(is_not_empty); + if(error) { return error; } + return !is_not_empty; +} + +inline simdjson_result array::reset() & noexcept { + return iter.reset_array(); +} + +inline simdjson_result array::at_pointer(std::string_view json_pointer) noexcept { + if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; } + json_pointer = json_pointer.substr(1); + // - means "the append position" or "the element after the end of the array" + // We don't support this, because we're returning a real element, not a position. + if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; } + + // Read the array index + size_t array_index = 0; + size_t i; + for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) { + uint8_t digit = uint8_t(json_pointer[i] - '0'); + // Check for non-digit in array index. If it's there, we're trying to get a field in an object + if (digit > 9) { return INCORRECT_TYPE; } + array_index = array_index*10 + digit; + } + + // 0 followed by other digits is invalid + if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0" + + // Empty string is invalid; so is a "/" with no digits before it + if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index" + // Get the child + auto child = at(array_index); + // If there is an error, it ends here + if(child.error()) { + return child; + } + + // If there is a /, we're not done yet, call recursively. + if (i < json_pointer.length()) { + child = child.at_pointer(json_pointer.substr(i)); + } + return child; +} + +inline simdjson_result array::at_path(std::string_view json_path) noexcept { + auto json_pointer = json_path_to_pointer_conversion(json_path); + if (json_pointer == "-1") { return INVALID_JSON_POINTER; } + return at_pointer(json_pointer); +} + +inline simdjson_result> array::at_path_with_wildcard(std::string_view json_path) noexcept { + std::vector result; + + auto result_pair = get_next_key_and_json_path(json_path); + std::string_view key = result_pair.first; + std::string_view remaining_path = result_pair.second; + // Wildcard case + if(key=="*"){ + for(auto element: *this){ + + if(element.error()){ + return element.error(); + } + + if(remaining_path.empty()){ + // Use value_unsafe() because we've already checked for errors above. + // The 'element' is a simdjson_result wrapper, and we need to extract + // the underlying value. value_unsafe() is safe here because error() returned false. + result.push_back(std::move(element).value_unsafe()); + + }else{ + auto nested_result = element.at_path_with_wildcard(remaining_path); + + if(nested_result.error()){ + return nested_result.error(); + } + // Same logic as above. + std::vector nested_matches = std::move(nested_result).value_unsafe(); + + result.insert(result.end(), + std::make_move_iterator(nested_matches.begin()), + std::make_move_iterator(nested_matches.end())); + } + } + return result; + }else{ + // Specific index case in which we access the element at the given index + size_t idx=0; + + for(char c:key){ + if(c < '0' || c > '9'){ + return INVALID_JSON_POINTER; + } + idx = idx*10 + (c - '0'); + } + + auto element = at(idx); + + if(element.error()){ + return element.error(); + } + + if(remaining_path.empty()){ + result.push_back(std::move(element).value_unsafe()); + return result; + }else{ + return element.at_path_with_wildcard(remaining_path); + } + } +} + +simdjson_inline simdjson_result array::at(size_t index) noexcept { + size_t i = 0; + for (auto value : *this) { + if (i == index) { return value; } + i++; + } + return INDEX_OUT_OF_BOUNDS; +} + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +simdjson_inline simdjson_result::simdjson_result( + rvv_vls::ondemand::array &&value +) noexcept + : implementation_simdjson_result_base( + std::forward(value) + ) +{ +} +simdjson_inline simdjson_result::simdjson_result( + error_code error +) noexcept + : implementation_simdjson_result_base(error) +{ +} + +simdjson_inline simdjson_result simdjson_result::begin() noexcept { + if (error()) { return error(); } + return first.begin(); +} +simdjson_inline simdjson_result simdjson_result::end() noexcept { + if (error()) { return error(); } + return first.end(); +} +simdjson_inline simdjson_result simdjson_result::count_elements() & noexcept { + if (error()) { return error(); } + return first.count_elements(); +} +simdjson_inline simdjson_result simdjson_result::is_empty() & noexcept { + if (error()) { return error(); } + return first.is_empty(); +} +simdjson_inline simdjson_result simdjson_result::at(size_t index) noexcept { + if (error()) { return error(); } + return first.at(index); +} +simdjson_inline simdjson_result simdjson_result::at_pointer(std::string_view json_pointer) noexcept { + if (error()) { return error(); } + return first.at_pointer(json_pointer); +} +simdjson_inline simdjson_result simdjson_result::at_path(std::string_view json_path) noexcept { + if (error()) { return error(); } + return first.at_path(json_path); +} +simdjson_inline simdjson_result> simdjson_result::at_path_with_wildcard(std::string_view json_path) noexcept { + if (error()) { return error(); } + return first.at_path_with_wildcard(json_path); +} +simdjson_inline simdjson_result simdjson_result::raw_json() noexcept { + if (error()) { return error(); } + return first.raw_json(); +} +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H +/* end file simdjson/generic/ondemand/array-inl.h for rvv_vls */ +/* including simdjson/generic/ondemand/array_iterator-inl.h for rvv_vls: #include "simdjson/generic/ondemand/array_iterator-inl.h" */ +/* begin file simdjson/generic/ondemand/array_iterator-inl.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept + : iter{_iter} +{} + +simdjson_inline simdjson_result array_iterator::operator*() noexcept { +#if SIMDJSON_DEVELOPMENT_CHECKS + SIMDJSON_ASSUME(!has_been_referenced); + has_been_referenced = true; +#endif + if (iter.error()) { iter.abandon(); return iter.error(); } + return value(iter.child()); +} +simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept { + return !(*this != other); +} +simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept { + return iter.is_open(); +} +simdjson_inline array_iterator &array_iterator::operator++() noexcept { +#if SIMDJSON_DEVELOPMENT_CHECKS + has_been_referenced = false; +#endif + error_code error; + // PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here. + // However, it does not seem to make a perf difference, so we add it out of an abundance of caution. + if (( error = iter.error() )) { return *this; } + if (( error = iter.skip_child() )) { return *this; } + if (( error = iter.has_next_element().error() )) { return *this; } + return *this; +} + +simdjson_inline bool array_iterator::at_end() const noexcept { + return iter.at_end(); +} +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +simdjson_inline simdjson_result::simdjson_result( + rvv_vls::ondemand::array_iterator &&value +) noexcept + : rvv_vls::implementation_simdjson_result_base(std::forward(value)) +{ + first.iter.assert_is_valid(); +} +simdjson_inline simdjson_result::simdjson_result(error_code error) noexcept + : rvv_vls::implementation_simdjson_result_base({}, error) +{ +} + +simdjson_inline simdjson_result simdjson_result::operator*() noexcept { + if (error()) { return error(); } + return *first; +} +simdjson_inline bool simdjson_result::operator==(const simdjson_result &other) const noexcept { + if (!first.iter.is_valid()) { return !error(); } + return first == other.first; +} +simdjson_inline bool simdjson_result::operator!=(const simdjson_result &other) const noexcept { + if (!first.iter.is_valid()) { return error(); } + return first != other.first; +} +simdjson_inline simdjson_result &simdjson_result::operator++() noexcept { + // Clear the error if there is one, so we don't yield it twice + if (error()) { second = SUCCESS; return *this; } + ++(first); + return *this; +} +simdjson_inline bool simdjson_result::at_end() const noexcept { + return !first.iter.is_valid() || first.at_end(); +} +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_ITERATOR_INL_H +/* end file simdjson/generic/ondemand/array_iterator-inl.h for rvv_vls */ +/* including simdjson/generic/ondemand/value-inl.h for rvv_vls: #include "simdjson/generic/ondemand/value-inl.h" */ +/* begin file simdjson/generic/ondemand/value-inl.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +simdjson_inline value::value(const value_iterator &_iter) noexcept + : iter{_iter} +{ +} +simdjson_inline value value::start(const value_iterator &iter) noexcept { + return iter; +} +simdjson_inline value value::resume(const value_iterator &iter) noexcept { + return iter; +} + +simdjson_inline simdjson_result value::get_array() noexcept { + return array::start(iter); +} +simdjson_inline simdjson_result value::get_object() noexcept { + return object::start(iter); +} +simdjson_inline simdjson_result value::start_or_resume_object() noexcept { + if (iter.at_start()) { + return get_object(); + } else { + return object::resume(iter); + } +} + +simdjson_inline simdjson_result value::get_raw_json_string() noexcept { + return iter.get_raw_json_string(); +} +simdjson_inline simdjson_result value::get_string(bool allow_replacement) noexcept { + return iter.get_string(allow_replacement); +} +template +simdjson_warn_unused simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept { + return iter.get_string(receiver, allow_replacement); +} +simdjson_inline simdjson_result value::get_wobbly_string() noexcept { + return iter.get_wobbly_string(); +} +simdjson_inline simdjson_result value::get_double() noexcept { + return iter.get_double(); +} +simdjson_inline simdjson_result value::get_double_in_string() noexcept { + return iter.get_double_in_string(); +} +simdjson_inline simdjson_result value::get_uint64() noexcept { + return iter.get_uint64(); +} +simdjson_inline simdjson_result value::get_uint64_in_string() noexcept { + return iter.get_uint64_in_string(); +} +simdjson_inline simdjson_result value::get_int64() noexcept { + return iter.get_int64(); +} +simdjson_inline simdjson_result value::get_int64_in_string() noexcept { + return iter.get_int64_in_string(); +} +simdjson_inline simdjson_result value::get_bool() noexcept { + return iter.get_bool(); +} +simdjson_inline simdjson_result value::is_null() noexcept { + return iter.is_null(); +} + +template<> simdjson_inline simdjson_result value::get() noexcept { return get_array(); } +template<> simdjson_inline simdjson_result value::get() noexcept { return get_object(); } +template<> simdjson_inline simdjson_result value::get() noexcept { return get_raw_json_string(); } +template<> simdjson_inline simdjson_result value::get() noexcept { return get_string(false); } +template<> simdjson_inline simdjson_result value::get() noexcept { return get_number(); } +template<> simdjson_inline simdjson_result value::get() noexcept { return get_double(); } +template<> simdjson_inline simdjson_result value::get() noexcept { return get_uint64(); } +template<> simdjson_inline simdjson_result value::get() noexcept { return get_int64(); } +template<> simdjson_inline simdjson_result value::get() noexcept { return get_bool(); } + + +template<> simdjson_warn_unused simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); } +template<> simdjson_warn_unused simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); } +template<> simdjson_warn_unused simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); } +template<> simdjson_warn_unused simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); } +template<> simdjson_warn_unused simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); } +template<> simdjson_warn_unused simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); } +template<> simdjson_warn_unused simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); } +template<> simdjson_warn_unused simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); } +template<> simdjson_warn_unused simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); } + +#if SIMDJSON_EXCEPTIONS +template +simdjson_inline value::operator T() noexcept(false) { + return get(); +} +simdjson_inline value::operator array() noexcept(false) { + return get_array(); +} +simdjson_inline value::operator object() noexcept(false) { + return get_object(); +} +simdjson_inline value::operator uint64_t() noexcept(false) { + return get_uint64(); +} +simdjson_inline value::operator int64_t() noexcept(false) { + return get_int64(); +} +simdjson_inline value::operator double() noexcept(false) { + return get_double(); +} +simdjson_inline value::operator std::string_view() noexcept(false) { + return get_string(false); +} +simdjson_inline value::operator raw_json_string() noexcept(false) { + return get_raw_json_string(); +} +simdjson_inline value::operator bool() noexcept(false) { + return get_bool(); +} +#endif + +simdjson_inline simdjson_result value::begin() & noexcept { + return get_array().begin(); +} +simdjson_inline simdjson_result value::end() & noexcept { + return {}; +} +simdjson_inline simdjson_result value::count_elements() & noexcept { + simdjson_result answer; + auto a = get_array(); + answer = a.count_elements(); + // count_elements leaves you pointing inside the array, at the first element. + // We need to move back so that the user can create a new array (which requires that + // we point at '['). + iter.move_at_start(); + return answer; +} +simdjson_inline simdjson_result value::count_fields() & noexcept { + simdjson_result answer; + auto a = get_object(); + answer = a.count_fields(); + iter.move_at_start(); + return answer; +} +simdjson_inline simdjson_result value::at(size_t index) noexcept { + auto a = get_array(); + return a.at(index); +} + +simdjson_inline simdjson_result value::find_field(std::string_view key) noexcept { + return start_or_resume_object().find_field(key); +} +simdjson_inline simdjson_result value::find_field(const char *key) noexcept { + return start_or_resume_object().find_field(key); +} + +simdjson_inline simdjson_result value::find_field_unordered(std::string_view key) noexcept { + return start_or_resume_object().find_field_unordered(key); +} +simdjson_inline simdjson_result value::find_field_unordered(const char *key) noexcept { + return start_or_resume_object().find_field_unordered(key); +} + +simdjson_inline simdjson_result value::operator[](std::string_view key) noexcept { + return start_or_resume_object()[key]; +} +simdjson_inline simdjson_result value::operator[](const char *key) noexcept { + return start_or_resume_object()[key]; +} + +simdjson_inline simdjson_result value::type() noexcept { + return iter.type(); +} + +simdjson_inline simdjson_result value::is_scalar() noexcept { + json_type this_type; + auto error = type().get(this_type); + if(error) { return error; } + return ! ((this_type == json_type::array) || (this_type == json_type::object)); +} + +simdjson_inline simdjson_result value::is_string() noexcept { + json_type this_type; + auto error = type().get(this_type); + if(error) { return error; } + return (this_type == json_type::string); +} + + +simdjson_inline bool value::is_negative() noexcept { + return iter.is_negative(); +} + +simdjson_inline simdjson_result value::is_integer() noexcept { + return iter.is_integer(); +} +simdjson_warn_unused simdjson_inline simdjson_result value::get_number_type() noexcept { + return iter.get_number_type(); +} +simdjson_warn_unused simdjson_inline simdjson_result value::get_number() noexcept { + return iter.get_number(); +} + +simdjson_inline std::string_view value::raw_json_token() noexcept { + return std::string_view(reinterpret_cast(iter.peek_start()), iter.peek_start_length()); +} + +simdjson_inline simdjson_result value::raw_json() noexcept { + json_type t; + SIMDJSON_TRY(type().get(t)); + switch (t) + { + case json_type::array: { + ondemand::array array; + SIMDJSON_TRY(get_array().get(array)); + return array.raw_json(); + } + case json_type::object: { + ondemand::object object; + SIMDJSON_TRY(get_object().get(object)); + return object.raw_json(); + } + default: + return raw_json_token(); + } +} + +simdjson_inline simdjson_result value::current_location() noexcept { + return iter.json_iter().current_location(); +} + +simdjson_inline int32_t value::current_depth() const noexcept{ + return iter.json_iter().depth(); +} + +inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept { + if (simdjson_unlikely(json_pointer.empty())) { // can't be + return false; + } + if (simdjson_unlikely(json_pointer[0] != '/')) { + return false; + } + size_t escape = json_pointer.find('~'); + if (escape == std::string_view::npos) { + return true; + } + if (escape == json_pointer.size() - 1) { + return false; + } + if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') { + return false; + } + return true; +} + +simdjson_inline simdjson_result value::at_pointer(std::string_view json_pointer) noexcept { + json_type t; + SIMDJSON_TRY(type().get(t)); + switch (t) + { + case json_type::array: + return (*this).get_array().at_pointer(json_pointer); + case json_type::object: + return (*this).get_object().at_pointer(json_pointer); + default: + // a non-empty string can be invalid, or accessing a primitive (issue 2154) + if (is_pointer_well_formed(json_pointer)) { + return NO_SUCH_FIELD; + } + return INVALID_JSON_POINTER; + } +} + +simdjson_inline simdjson_result value::at_path(std::string_view json_path) noexcept { + json_type t; + SIMDJSON_TRY(type().get(t)); + switch (t) { + case json_type::array: + return (*this).get_array().at_path(json_path); + case json_type::object: + return (*this).get_object().at_path(json_path); + default: + return INVALID_JSON_POINTER; + } +} + +inline simdjson_result> value::at_path_with_wildcard(std::string_view json_path) noexcept { + json_type t; + SIMDJSON_TRY(type().get(t)); + switch (t) { + case json_type::array: + return (*this).get_array().at_path_with_wildcard(json_path); + case json_type::object: + return (*this).get_object().at_path_with_wildcard(json_path); + default: + return INVALID_JSON_POINTER; + } +} + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +simdjson_inline simdjson_result::simdjson_result( + rvv_vls::ondemand::value &&value +) noexcept : + implementation_simdjson_result_base( + std::forward(value) + ) +{ +} +simdjson_inline simdjson_result::simdjson_result( + error_code error +) noexcept : + implementation_simdjson_result_base(error) +{ +} +simdjson_inline simdjson_result simdjson_result::count_elements() & noexcept { + if (error()) { return error(); } + return first.count_elements(); +} +simdjson_inline simdjson_result simdjson_result::count_fields() & noexcept { + if (error()) { return error(); } + return first.count_fields(); +} +simdjson_inline simdjson_result simdjson_result::at(size_t index) noexcept { + if (error()) { return error(); } + return first.at(index); +} +simdjson_inline simdjson_result simdjson_result::begin() & noexcept { + if (error()) { return error(); } + return first.begin(); +} +simdjson_inline simdjson_result simdjson_result::end() & noexcept { + if (error()) { return error(); } + return {}; +} + +simdjson_inline simdjson_result simdjson_result::find_field(std::string_view key) noexcept { + if (error()) { return error(); } + return first.find_field(key); +} +simdjson_inline simdjson_result simdjson_result::find_field(const char *key) noexcept { + if (error()) { return error(); } + return first.find_field(key); +} + +simdjson_inline simdjson_result simdjson_result::find_field_unordered(std::string_view key) noexcept { + if (error()) { return error(); } + return first.find_field_unordered(key); +} +simdjson_inline simdjson_result simdjson_result::find_field_unordered(const char *key) noexcept { + if (error()) { return error(); } + return first.find_field_unordered(key); +} + +simdjson_inline simdjson_result simdjson_result::operator[](std::string_view key) noexcept { + if (error()) { return error(); } + return first[key]; +} +simdjson_inline simdjson_result simdjson_result::operator[](const char *key) noexcept { + if (error()) { return error(); } + return first[key]; +} + +simdjson_inline simdjson_result simdjson_result::get_array() noexcept { + if (error()) { return error(); } + return first.get_array(); +} +simdjson_inline simdjson_result simdjson_result::get_object() noexcept { + if (error()) { return error(); } + return first.get_object(); +} +simdjson_inline simdjson_result simdjson_result::get_uint64() noexcept { + if (error()) { return error(); } + return first.get_uint64(); +} +simdjson_inline simdjson_result simdjson_result::get_uint64_in_string() noexcept { + if (error()) { return error(); } + return first.get_uint64_in_string(); +} +simdjson_inline simdjson_result simdjson_result::get_int64() noexcept { + if (error()) { return error(); } + return first.get_int64(); +} +simdjson_inline simdjson_result simdjson_result::get_int64_in_string() noexcept { + if (error()) { return error(); } + return first.get_int64_in_string(); +} +simdjson_inline simdjson_result simdjson_result::get_double() noexcept { + if (error()) { return error(); } + return first.get_double(); +} +simdjson_inline simdjson_result simdjson_result::get_double_in_string() noexcept { + if (error()) { return error(); } + return first.get_double_in_string(); +} +simdjson_inline simdjson_result simdjson_result::get_string(bool allow_replacement) noexcept { + if (error()) { return error(); } + return first.get_string(allow_replacement); +} +template +simdjson_inline error_code simdjson_result::get_string(string_type& receiver, bool allow_replacement) noexcept { + if (error()) { return error(); } + return first.get_string(receiver, allow_replacement); +} +simdjson_inline simdjson_result simdjson_result::get_wobbly_string() noexcept { + if (error()) { return error(); } + return first.get_wobbly_string(); +} +simdjson_inline simdjson_result simdjson_result::get_raw_json_string() noexcept { + if (error()) { return error(); } + return first.get_raw_json_string(); +} +simdjson_inline simdjson_result simdjson_result::get_bool() noexcept { + if (error()) { return error(); } + return first.get_bool(); +} +simdjson_inline simdjson_result simdjson_result::is_null() noexcept { + if (error()) { return error(); } + return first.is_null(); +} + +template<> simdjson_inline error_code simdjson_result::get(rvv_vls::ondemand::value &out) noexcept { + if (error()) { return error(); } + out = first; + return SUCCESS; +} + +template simdjson_inline simdjson_result simdjson_result::get() noexcept { + if (error()) { return error(); } + return first.get(); +} +template simdjson_inline error_code simdjson_result::get(T &out) noexcept { + if (error()) { return error(); } + return first.get(out); +} + +template<> simdjson_inline simdjson_result simdjson_result::get() noexcept { + if (error()) { return error(); } + return std::move(first); +} + +simdjson_inline simdjson_result simdjson_result::type() noexcept { + if (error()) { return error(); } + return first.type(); +} +simdjson_inline simdjson_result simdjson_result::is_scalar() noexcept { + if (error()) { return error(); } + return first.is_scalar(); +} +simdjson_inline simdjson_result simdjson_result::is_string() noexcept { + if (error()) { return error(); } + return first.is_string(); +} +simdjson_inline simdjson_result simdjson_result::is_negative() noexcept { + if (error()) { return error(); } + return first.is_negative(); +} +simdjson_inline simdjson_result simdjson_result::is_integer() noexcept { + if (error()) { return error(); } + return first.is_integer(); +} +simdjson_inline simdjson_result simdjson_result::get_number_type() noexcept { + if (error()) { return error(); } + return first.get_number_type(); +} +simdjson_inline simdjson_result simdjson_result::get_number() noexcept { + if (error()) { return error(); } + return first.get_number(); +} +#if SIMDJSON_EXCEPTIONS +template +simdjson_inline simdjson_result::operator T() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first.get(); +} +simdjson_inline simdjson_result::operator rvv_vls::ondemand::array() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator rvv_vls::ondemand::object() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator uint64_t() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator int64_t() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator double() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator std::string_view() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator rvv_vls::ondemand::raw_json_string() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator bool() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +#endif + +simdjson_inline simdjson_result simdjson_result::raw_json_token() noexcept { + if (error()) { return error(); } + return first.raw_json_token(); +} + +simdjson_inline simdjson_result simdjson_result::raw_json() noexcept { + if (error()) { return error(); } + return first.raw_json(); +} + +simdjson_inline simdjson_result simdjson_result::current_location() noexcept { + if (error()) { return error(); } + return first.current_location(); +} + +simdjson_inline simdjson_result simdjson_result::current_depth() const noexcept { + if (error()) { return error(); } + return first.current_depth(); +} + +simdjson_inline simdjson_result simdjson_result::at_pointer( + std::string_view json_pointer) noexcept { + if (error()) { + return error(); + } + return first.at_pointer(json_pointer); +} + +simdjson_inline simdjson_result simdjson_result::at_path( + std::string_view json_path) noexcept { + if (error()) { + return error(); + } + return first.at_path(json_path); +} + +inline simdjson_result> simdjson_result::at_path_with_wildcard( + std::string_view json_path) noexcept { + if (error()) { + return error(); + } + return first.at_path_with_wildcard(json_path); +} + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_INL_H +/* end file simdjson/generic/ondemand/value-inl.h for rvv_vls */ +/* including simdjson/generic/ondemand/document-inl.h for rvv_vls: #include "simdjson/generic/ondemand/document-inl.h" */ +/* begin file simdjson/generic/ondemand/document-inl.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array_iterator.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array-inl.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object-inl.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/deserialize.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +simdjson_inline document::document(ondemand::json_iterator &&_iter) noexcept + : iter{std::forward(_iter)} +{ + logger::log_start_value(iter, "document"); +} + +simdjson_inline document document::start(json_iterator &&iter) noexcept { + return document(std::forward(iter)); +} + +inline void document::rewind() noexcept { + iter.rewind(); +} + +inline std::string document::to_debug_string() noexcept { + return iter.to_string(); +} + +inline simdjson_result document::current_location() const noexcept { + return iter.current_location(); +} + +inline int32_t document::current_depth() const noexcept { + return iter.depth(); +} + +inline bool document::at_end() const noexcept { + return iter.at_end(); +} + + +inline bool document::is_alive() noexcept { + return iter.is_alive(); +} +simdjson_inline value_iterator document::resume_value_iterator() noexcept { + return value_iterator(&iter, 1, iter.root_position()); +} +simdjson_inline value_iterator document::get_root_value_iterator() noexcept { + return resume_value_iterator(); +} +simdjson_inline simdjson_result document::start_or_resume_object() noexcept { + if (iter.at_root()) { + return get_object(); + } else { + return object::resume(resume_value_iterator()); + } +} +simdjson_inline simdjson_result document::get_value() noexcept { + // Make sure we start any arrays or objects before returning, so that start_root_() + // gets called. + + // It is the convention throughout the code that the macro `SIMDJSON_DEVELOPMENT_CHECKS` determines whether + // we check for OUT_OF_ORDER_ITERATION. Proper on::demand code should never trigger this error. +#if SIMDJSON_DEVELOPMENT_CHECKS + if (!iter.at_root()) { return OUT_OF_ORDER_ITERATION; } +#endif + // assert_at_root() serves two purposes: in Debug mode, whether or not + // SIMDJSON_DEVELOPMENT_CHECKS is set or not, it checks that we are at the root of + // the document (this will typically be redundant). In release mode, it generates + // SIMDJSON_ASSUME statements to allow the compiler to make assumptions. + iter.assert_at_root(); + switch (*iter.peek()) { + case '[': { + // The following lines check that the document ends with ]. + auto value_iterator = get_root_value_iterator(); + auto error = value_iterator.check_root_array(); + if(error) { return error; } + return value(get_root_value_iterator()); + } + case '{': { + // The following lines would check that the document ends with }. + auto value_iterator = get_root_value_iterator(); + auto error = value_iterator.check_root_object(); + if(error) { return error; } + return value(get_root_value_iterator()); + } + default: + // Unfortunately, scalar documents are a special case in simdjson and they cannot + // be safely converted to value instances. + return SCALAR_DOCUMENT_AS_VALUE; + } +} +simdjson_inline simdjson_result document::get_array() & noexcept { + auto value = get_root_value_iterator(); + return array::start_root(value); +} +simdjson_inline simdjson_result document::get_object() & noexcept { + auto value = get_root_value_iterator(); + return object::start_root(value); +} + +/** + * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should + * give an error, so we check for trailing content. We want to disallow trailing + * content. + * Thus, in several implementations below, we pass a 'true' parameter value to + * a get_root_value_iterator() method: this indicates that we disallow trailing content. + */ + +simdjson_inline simdjson_result document::get_uint64() noexcept { + return get_root_value_iterator().get_root_uint64(true); +} +simdjson_inline simdjson_result document::get_uint64_in_string() noexcept { + return get_root_value_iterator().get_root_uint64_in_string(true); +} +simdjson_inline simdjson_result document::get_int64() noexcept { + return get_root_value_iterator().get_root_int64(true); +} +simdjson_inline simdjson_result document::get_int64_in_string() noexcept { + return get_root_value_iterator().get_root_int64_in_string(true); +} +simdjson_inline simdjson_result document::get_double() noexcept { + return get_root_value_iterator().get_root_double(true); +} +simdjson_inline simdjson_result document::get_double_in_string() noexcept { + return get_root_value_iterator().get_root_double_in_string(true); +} +simdjson_inline simdjson_result document::get_string(bool allow_replacement) noexcept { + return get_root_value_iterator().get_root_string(true, allow_replacement); +} +template +simdjson_warn_unused simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept { + return get_root_value_iterator().get_root_string(receiver, true, allow_replacement); +} +simdjson_inline simdjson_result document::get_wobbly_string() noexcept { + return get_root_value_iterator().get_root_wobbly_string(true); +} +simdjson_inline simdjson_result document::get_raw_json_string() noexcept { + return get_root_value_iterator().get_root_raw_json_string(true); +} +simdjson_inline simdjson_result document::get_bool() noexcept { + return get_root_value_iterator().get_root_bool(true); +} +simdjson_inline simdjson_result document::is_null() noexcept { + return get_root_value_iterator().is_root_null(true); +} + +template<> simdjson_inline simdjson_result document::get() & noexcept { return get_array(); } +template<> simdjson_inline simdjson_result document::get() & noexcept { return get_object(); } +template<> simdjson_inline simdjson_result document::get() & noexcept { return get_raw_json_string(); } +template<> simdjson_inline simdjson_result document::get() & noexcept { return get_string(false); } +template<> simdjson_inline simdjson_result document::get() & noexcept { return get_double(); } +template<> simdjson_inline simdjson_result document::get() & noexcept { return get_uint64(); } +template<> simdjson_inline simdjson_result document::get() & noexcept { return get_int64(); } +template<> simdjson_inline simdjson_result document::get() & noexcept { return get_bool(); } +template<> simdjson_inline simdjson_result document::get() & noexcept { return get_value(); } + +template<> simdjson_warn_unused simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); } +template<> simdjson_warn_unused simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); } +template<> simdjson_warn_unused simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); } +template<> simdjson_warn_unused simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); } +template<> simdjson_warn_unused simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); } +template<> simdjson_warn_unused simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); } +template<> simdjson_warn_unused simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); } +template<> simdjson_warn_unused simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); } +template<> simdjson_warn_unused simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); } + +template<> simdjson_deprecated simdjson_inline simdjson_result document::get() && noexcept { return get_raw_json_string(); } +template<> simdjson_deprecated simdjson_inline simdjson_result document::get() && noexcept { return get_string(false); } +template<> simdjson_deprecated simdjson_inline simdjson_result document::get() && noexcept { return std::forward(*this).get_double(); } +template<> simdjson_deprecated simdjson_inline simdjson_result document::get() && noexcept { return std::forward(*this).get_uint64(); } +template<> simdjson_deprecated simdjson_inline simdjson_result document::get() && noexcept { return std::forward(*this).get_int64(); } +template<> simdjson_deprecated simdjson_inline simdjson_result document::get() && noexcept { return std::forward(*this).get_bool(); } +template<> simdjson_deprecated simdjson_inline simdjson_result document::get() && noexcept { return get_value(); } + +#if SIMDJSON_EXCEPTIONS +template +simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get(); } +template +simdjson_inline document::operator T() & noexcept(false) { return get(); } +simdjson_inline document::operator array() & noexcept(false) { return get_array(); } +simdjson_inline document::operator object() & noexcept(false) { return get_object(); } +simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); } +simdjson_inline document::operator int64_t() noexcept(false) { return get_int64(); } +simdjson_inline document::operator double() noexcept(false) { return get_double(); } +simdjson_inline document::operator std::string_view() noexcept(false) simdjson_lifetime_bound { return get_string(false); } +simdjson_inline document::operator raw_json_string() noexcept(false) simdjson_lifetime_bound { return get_raw_json_string(); } +simdjson_inline document::operator bool() noexcept(false) { return get_bool(); } +simdjson_inline document::operator value() noexcept(false) { return get_value(); } + +#endif +simdjson_inline simdjson_result document::count_elements() & noexcept { + auto a = get_array(); + simdjson_result answer = a.count_elements(); + /* If there was an array, we are now left pointing at its first element. */ + if(answer.error() == SUCCESS) { rewind(); } + return answer; +} +simdjson_inline simdjson_result document::count_fields() & noexcept { + auto a = get_object(); + simdjson_result answer = a.count_fields(); + /* If there was an object, we are now left pointing at its first element. */ + if(answer.error() == SUCCESS) { rewind(); } + return answer; +} +simdjson_inline simdjson_result document::at(size_t index) & noexcept { + auto a = get_array(); + return a.at(index); +} +simdjson_inline simdjson_result document::begin() & noexcept { + return get_array().begin(); +} +simdjson_inline simdjson_result document::end() & noexcept { + return {}; +} + +simdjson_inline simdjson_result document::find_field(std::string_view key) & noexcept { + return start_or_resume_object().find_field(key); +} +simdjson_inline simdjson_result document::find_field(const char *key) & noexcept { + return start_or_resume_object().find_field(key); +} +simdjson_inline simdjson_result document::find_field_unordered(std::string_view key) & noexcept { + return start_or_resume_object().find_field_unordered(key); +} +simdjson_inline simdjson_result document::find_field_unordered(const char *key) & noexcept { + return start_or_resume_object().find_field_unordered(key); +} +simdjson_inline simdjson_result document::operator[](std::string_view key) & noexcept { + return start_or_resume_object()[key]; +} +simdjson_inline simdjson_result document::operator[](const char *key) & noexcept { + return start_or_resume_object()[key]; +} + +simdjson_warn_unused simdjson_inline error_code document::consume() noexcept { + bool scalar = false; + auto error = is_scalar().get(scalar); + if(error) { return error; } + if(scalar) { + iter.return_current_and_advance(); + return SUCCESS; + } + error = iter.skip_child(0); + if(error) { iter.abandon(); } + return error; +} + +simdjson_inline simdjson_result document::raw_json() noexcept { + auto _iter = get_root_value_iterator(); + const uint8_t * starting_point{_iter.peek_start()}; + auto error = consume(); + if(error) { return error; } + // After 'consume()', we could be left pointing just beyond the document, but that + // is ok because we are not going to dereference the final pointer position, we just + // use it to compute the length in bytes. + const uint8_t * final_point{iter.unsafe_pointer()}; + return std::string_view(reinterpret_cast(starting_point), size_t(final_point - starting_point)); +} + +simdjson_inline simdjson_result document::type() noexcept { + return get_root_value_iterator().type(); +} + +simdjson_inline simdjson_result document::is_scalar() noexcept { + // For more speed, we could do: + // return iter.is_single_token(); + json_type this_type; + auto error = type().get(this_type); + if(error) { return error; } + return ! ((this_type == json_type::array) || (this_type == json_type::object)); +} + +simdjson_inline simdjson_result document::is_string() noexcept { + json_type this_type; + auto error = type().get(this_type); + if(error) { return error; } + return (this_type == json_type::string); +} + +simdjson_inline bool document::is_negative() noexcept { + return get_root_value_iterator().is_root_negative(); +} + +simdjson_inline simdjson_result document::is_integer() noexcept { + return get_root_value_iterator().is_root_integer(true); +} + +simdjson_inline simdjson_result document::get_number_type() noexcept { + return get_root_value_iterator().get_root_number_type(true); +} + +simdjson_inline simdjson_result document::get_number() noexcept { + return get_root_value_iterator().get_root_number(true); +} + + +simdjson_inline simdjson_result document::raw_json_token() noexcept { + auto _iter = get_root_value_iterator(); + return std::string_view(reinterpret_cast(_iter.peek_start()), _iter.peek_root_length()); +} + +simdjson_inline simdjson_result document::at_pointer(std::string_view json_pointer) noexcept { + rewind(); // Rewind the document each time at_pointer is called + if (json_pointer.empty()) { + return this->get_value(); + } + json_type t; + SIMDJSON_TRY(type().get(t)); + switch (t) + { + case json_type::array: + return (*this).get_array().at_pointer(json_pointer); + case json_type::object: + return (*this).get_object().at_pointer(json_pointer); + default: + return INVALID_JSON_POINTER; + } +} + +simdjson_inline simdjson_result document::at_path(std::string_view json_path) noexcept { + rewind(); // Rewind the document each time at_pointer is called + if (json_path.empty()) { + return this->get_value(); + } + json_type t; + SIMDJSON_TRY(type().get(t)); + switch (t) { + case json_type::array: + return (*this).get_array().at_path(json_path); + case json_type::object: + return (*this).get_object().at_path(json_path); + default: + return INVALID_JSON_POINTER; + } +} + +simdjson_inline simdjson_result> document::at_path_with_wildcard(std::string_view json_path) noexcept { + rewind(); // Rewind the document each time at_path_with_wildcard is called + if (json_path.empty()) { + return INVALID_JSON_POINTER; + } + json_type t; + SIMDJSON_TRY(type().get(t)); + switch (t) { + case json_type::array: + return (*this).get_array().at_path_with_wildcard(json_path); + case json_type::object: + return (*this).get_object().at_path_with_wildcard(json_path); + default: + return INVALID_JSON_POINTER; + } +} + +#if SIMDJSON_SUPPORTS_CONCEPTS && SIMDJSON_STATIC_REFLECTION + +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_inline error_code document::extract_into(T& out) & noexcept { + // Helper to check if a field name matches any of the requested fields + auto should_extract = [](std::string_view field_name) constexpr -> bool { + return ((FieldNames.view() == field_name) || ...); + }; + + // Iterate through all members of T using reflection + template for (constexpr auto mem : std::define_static_array( + std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()))) { + + if constexpr (!std::meta::is_const(mem) && std::meta::is_public(mem)) { + constexpr std::string_view key = std::define_static_string(std::meta::identifier_of(mem)); + + // Only extract this field if it's in our list of requested fields + if constexpr (should_extract(key)) { + // Try to find and extract the field + if constexpr (concepts::optional_type) { + // For optional fields, it's ok if they're missing + auto field_result = find_field_unordered(key); + if (!field_result.error()) { + auto error = field_result.get(out.[:mem:]); + if (error && error != NO_SUCH_FIELD) { + return error; + } + } else if (field_result.error() != NO_SUCH_FIELD) { + return field_result.error(); + } else { + out.[:mem:].reset(); + } + } else { + // For required fields (in the requested list), fail if missing + SIMDJSON_TRY((*this)[key].get(out.[:mem:])); + } + } + } + }; + + return SUCCESS; +} + +#endif // SIMDJSON_SUPPORTS_CONCEPTS && SIMDJSON_STATIC_REFLECTION + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +simdjson_inline simdjson_result::simdjson_result( + rvv_vls::ondemand::document &&value +) noexcept : + implementation_simdjson_result_base( + std::forward(value) + ) +{ +} +simdjson_inline simdjson_result::simdjson_result( + error_code error +) noexcept : + implementation_simdjson_result_base( + error + ) +{ +} +simdjson_inline simdjson_result simdjson_result::count_elements() & noexcept { + if (error()) { return error(); } + return first.count_elements(); +} +simdjson_inline simdjson_result simdjson_result::count_fields() & noexcept { + if (error()) { return error(); } + return first.count_fields(); +} +simdjson_inline simdjson_result simdjson_result::at(size_t index) & noexcept { + if (error()) { return error(); } + return first.at(index); +} +simdjson_inline error_code simdjson_result::rewind() noexcept { + if (error()) { return error(); } + first.rewind(); + return SUCCESS; +} +simdjson_inline simdjson_result simdjson_result::begin() & noexcept { + if (error()) { return error(); } + return first.begin(); +} +simdjson_inline simdjson_result simdjson_result::end() & noexcept { + return {}; +} +simdjson_inline simdjson_result simdjson_result::find_field_unordered(std::string_view key) & noexcept { + if (error()) { return error(); } + return first.find_field_unordered(key); +} +simdjson_inline simdjson_result simdjson_result::find_field_unordered(const char *key) & noexcept { + if (error()) { return error(); } + return first.find_field_unordered(key); +} +simdjson_inline simdjson_result simdjson_result::operator[](std::string_view key) & noexcept { + if (error()) { return error(); } + return first[key]; +} +simdjson_inline simdjson_result simdjson_result::operator[](const char *key) & noexcept { + if (error()) { return error(); } + return first[key]; +} +simdjson_inline simdjson_result simdjson_result::find_field(std::string_view key) & noexcept { + if (error()) { return error(); } + return first.find_field(key); +} +simdjson_inline simdjson_result simdjson_result::find_field(const char *key) & noexcept { + if (error()) { return error(); } + return first.find_field(key); +} +simdjson_inline simdjson_result simdjson_result::get_array() & noexcept { + if (error()) { return error(); } + return first.get_array(); +} +simdjson_inline simdjson_result simdjson_result::get_object() & noexcept { + if (error()) { return error(); } + return first.get_object(); +} +simdjson_inline simdjson_result simdjson_result::get_uint64() noexcept { + if (error()) { return error(); } + return first.get_uint64(); +} +simdjson_inline simdjson_result simdjson_result::get_uint64_in_string() noexcept { + if (error()) { return error(); } + return first.get_uint64_in_string(); +} +simdjson_inline simdjson_result simdjson_result::get_int64() noexcept { + if (error()) { return error(); } + return first.get_int64(); +} +simdjson_inline simdjson_result simdjson_result::get_int64_in_string() noexcept { + if (error()) { return error(); } + return first.get_int64_in_string(); +} +simdjson_inline simdjson_result simdjson_result::get_double() noexcept { + if (error()) { return error(); } + return first.get_double(); +} +simdjson_inline simdjson_result simdjson_result::get_double_in_string() noexcept { + if (error()) { return error(); } + return first.get_double_in_string(); +} +simdjson_inline simdjson_result simdjson_result::get_string(bool allow_replacement) noexcept { + if (error()) { return error(); } + return first.get_string(allow_replacement); +} +template +simdjson_warn_unused simdjson_inline error_code simdjson_result::get_string(string_type& receiver, bool allow_replacement) noexcept { + if (error()) { return error(); } + return first.get_string(receiver, allow_replacement); +} +simdjson_inline simdjson_result simdjson_result::get_wobbly_string() noexcept { + if (error()) { return error(); } + return first.get_wobbly_string(); +} +simdjson_inline simdjson_result simdjson_result::get_raw_json_string() noexcept { + if (error()) { return error(); } + return first.get_raw_json_string(); +} +simdjson_inline simdjson_result simdjson_result::get_bool() noexcept { + if (error()) { return error(); } + return first.get_bool(); +} +simdjson_inline simdjson_result simdjson_result::get_value() noexcept { + if (error()) { return error(); } + return first.get_value(); +} +simdjson_inline simdjson_result simdjson_result::is_null() noexcept { + if (error()) { return error(); } + return first.is_null(); +} + +template +simdjson_inline simdjson_result simdjson_result::get() & noexcept { + if (error()) { return error(); } + return first.get(); +} +template +simdjson_deprecated simdjson_inline simdjson_result simdjson_result::get() && noexcept { + if (error()) { return error(); } + return std::forward(first).get(); +} +template +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) & noexcept { + if (error()) { return error(); } + return first.get(out); +} +template +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) && noexcept { + if (error()) { return error(); } + return std::forward(first).get(out); +} + +template<> simdjson_inline simdjson_result simdjson_result::get() & noexcept = delete; +template<> simdjson_deprecated simdjson_inline simdjson_result simdjson_result::get() && noexcept { + if (error()) { return error(); } + return std::forward(first); +} +template<> simdjson_warn_unused simdjson_inline error_code simdjson_result::get(rvv_vls::ondemand::document &out) & noexcept = delete; +template<> simdjson_warn_unused simdjson_inline error_code simdjson_result::get(rvv_vls::ondemand::document &out) && noexcept { + if (error()) { return error(); } + out = std::forward(first); + return SUCCESS; +} + +simdjson_inline simdjson_result simdjson_result::type() noexcept { + if (error()) { return error(); } + return first.type(); +} + +simdjson_inline simdjson_result simdjson_result::is_scalar() noexcept { + if (error()) { return error(); } + return first.is_scalar(); +} + +simdjson_inline simdjson_result simdjson_result::is_string() noexcept { + if (error()) { return error(); } + return first.is_string(); +} + +simdjson_inline bool simdjson_result::is_negative() noexcept { + if (error()) { return error(); } + return first.is_negative(); +} + +simdjson_inline simdjson_result simdjson_result::is_integer() noexcept { + if (error()) { return error(); } + return first.is_integer(); +} + +simdjson_inline simdjson_result simdjson_result::get_number_type() noexcept { + if (error()) { return error(); } + return first.get_number_type(); +} + +simdjson_inline simdjson_result simdjson_result::get_number() noexcept { + if (error()) { return error(); } + return first.get_number(); +} + + +#if SIMDJSON_EXCEPTIONS +template ::value == false>::type> +simdjson_inline simdjson_result::operator T() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator rvv_vls::ondemand::array() & noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator rvv_vls::ondemand::object() & noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator uint64_t() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator int64_t() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator double() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator std::string_view() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator rvv_vls::ondemand::raw_json_string() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator bool() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator rvv_vls::ondemand::value() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +#endif + + +simdjson_inline simdjson_result simdjson_result::current_location() noexcept { + if (error()) { return error(); } + return first.current_location(); +} + +simdjson_inline bool simdjson_result::at_end() const noexcept { + if (error()) { return error(); } + return first.at_end(); +} + + +simdjson_inline int32_t simdjson_result::current_depth() const noexcept { + if (error()) { return error(); } + return first.current_depth(); +} + +simdjson_inline simdjson_result simdjson_result::raw_json_token() noexcept { + if (error()) { return error(); } + return first.raw_json_token(); +} + +simdjson_inline simdjson_result simdjson_result::at_pointer(std::string_view json_pointer) noexcept { + if (error()) { return error(); } + return first.at_pointer(json_pointer); +} + +simdjson_inline simdjson_result simdjson_result::at_path(std::string_view json_path) noexcept { + if (error()) { return error(); } + return first.at_path(json_path); +} + +simdjson_inline simdjson_result> simdjson_result::at_path_with_wildcard(std::string_view json_path) noexcept { + if (error()) { return error(); } + return first.at_path_with_wildcard(json_path); +} + +#if SIMDJSON_STATIC_REFLECTION +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_inline error_code simdjson_result::extract_into(T& out) & noexcept { + if (error()) { return error(); } + return first.extract_into(out); +} +#endif // SIMDJSON_STATIC_REFLECTION + +} // namespace simdjson + + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {} +simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {} +simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); } +simdjson_inline simdjson_result document_reference::get_array() & noexcept { return doc->get_array(); } +simdjson_inline simdjson_result document_reference::get_object() & noexcept { return doc->get_object(); } +/** + * The document_reference instances are used primarily/solely for streams of JSON + * documents. + * We decided that calling 'get_double()' on the JSON document '1.233 blabla' should + * give an error, so we check for trailing content. + * + * However, for streams of JSON documents, we want to be able to start from + * "321" "321" "321" + * and parse it successfully as a stream of JSON documents, calling get_uint64_in_string() + * successfully each time. + * + * To achieve this result, we pass a 'false' to a get_root_value_iterator() method: + * this indicates that we allow trailing content. + */ +simdjson_inline simdjson_result document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); } +simdjson_inline simdjson_result document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); } +simdjson_inline simdjson_result document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); } +simdjson_inline simdjson_result document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); } +simdjson_inline simdjson_result document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); } +simdjson_inline simdjson_result document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); } +simdjson_inline simdjson_result document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); } +template +simdjson_warn_unused simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); } +simdjson_inline simdjson_result document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); } +simdjson_inline simdjson_result document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); } +simdjson_inline simdjson_result document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); } +simdjson_inline simdjson_result document_reference::get_value() noexcept { return doc->get_value(); } +simdjson_inline simdjson_result document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); } +template<> simdjson_inline simdjson_result document_reference::get() & noexcept { return get_array(); } +template<> simdjson_inline simdjson_result document_reference::get() & noexcept { return get_object(); } +template<> simdjson_inline simdjson_result document_reference::get() & noexcept { return get_raw_json_string(); } +template<> simdjson_inline simdjson_result document_reference::get() & noexcept { return get_string(false); } +template<> simdjson_inline simdjson_result document_reference::get() & noexcept { return get_double(); } +template<> simdjson_inline simdjson_result document_reference::get() & noexcept { return get_uint64(); } +template<> simdjson_inline simdjson_result document_reference::get() & noexcept { return get_int64(); } +template<> simdjson_inline simdjson_result document_reference::get() & noexcept { return get_bool(); } +template<> simdjson_inline simdjson_result document_reference::get() & noexcept { return get_value(); } +#if SIMDJSON_EXCEPTIONS +template +simdjson_inline document_reference::operator T() noexcept(false) { return get(); } +simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); } +simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); } +simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); } +simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); } +simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); } +simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); } +simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return get_raw_json_string(); } +simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); } +simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); } +#endif +simdjson_inline simdjson_result document_reference::count_elements() & noexcept { return doc->count_elements(); } +simdjson_inline simdjson_result document_reference::count_fields() & noexcept { return doc->count_fields(); } +simdjson_inline simdjson_result document_reference::at(size_t index) & noexcept { return doc->at(index); } +simdjson_inline simdjson_result document_reference::begin() & noexcept { return doc->begin(); } +simdjson_inline simdjson_result document_reference::end() & noexcept { return doc->end(); } +simdjson_inline simdjson_result document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); } +simdjson_inline simdjson_result document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); } +simdjson_inline simdjson_result document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; } +simdjson_inline simdjson_result document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; } +simdjson_inline simdjson_result document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); } +simdjson_inline simdjson_result document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); } +simdjson_inline simdjson_result document_reference::type() noexcept { return doc->type(); } +simdjson_inline simdjson_result document_reference::is_scalar() noexcept { return doc->is_scalar(); } +simdjson_inline simdjson_result document_reference::is_string() noexcept { return doc->is_string(); } +simdjson_inline simdjson_result document_reference::current_location() noexcept { return doc->current_location(); } +simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); } +simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); } +simdjson_inline simdjson_result document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); } +simdjson_inline simdjson_result document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); } +simdjson_inline simdjson_result document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); } +simdjson_inline simdjson_result document_reference::raw_json_token() noexcept { return doc->raw_json_token(); } +simdjson_inline simdjson_result document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); } +simdjson_inline simdjson_result document_reference::at_path(std::string_view json_path) noexcept { return doc->at_path(json_path); } +simdjson_inline simdjson_result> document_reference::at_path_with_wildcard(std::string_view json_path) noexcept { return doc->at_path_with_wildcard(json_path); } +simdjson_inline simdjson_result document_reference::raw_json() noexcept { return doc->raw_json();} +simdjson_inline document_reference::operator document&() const noexcept { return *doc; } +#if SIMDJSON_SUPPORTS_CONCEPTS && SIMDJSON_STATIC_REFLECTION +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_inline error_code document_reference::extract_into(T& out) & noexcept { + return doc->extract_into(out); +} +#endif // SIMDJSON_SUPPORTS_CONCEPTS && SIMDJSON_STATIC_REFLECTION +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + + + +namespace simdjson { +simdjson_inline simdjson_result::simdjson_result(rvv_vls::ondemand::document_reference value, error_code error) + noexcept : implementation_simdjson_result_base(std::forward(value), error) {} + + +simdjson_inline simdjson_result simdjson_result::count_elements() & noexcept { + if (error()) { return error(); } + return first.count_elements(); +} +simdjson_inline simdjson_result simdjson_result::count_fields() & noexcept { + if (error()) { return error(); } + return first.count_fields(); +} +simdjson_inline simdjson_result simdjson_result::at(size_t index) & noexcept { + if (error()) { return error(); } + return first.at(index); +} +simdjson_inline error_code simdjson_result::rewind() noexcept { + if (error()) { return error(); } + first.rewind(); + return SUCCESS; +} +simdjson_inline simdjson_result simdjson_result::begin() & noexcept { + if (error()) { return error(); } + return first.begin(); +} +simdjson_inline simdjson_result simdjson_result::end() & noexcept { + return {}; +} +simdjson_inline simdjson_result simdjson_result::find_field_unordered(std::string_view key) & noexcept { + if (error()) { return error(); } + return first.find_field_unordered(key); +} +simdjson_inline simdjson_result simdjson_result::find_field_unordered(const char *key) & noexcept { + if (error()) { return error(); } + return first.find_field_unordered(key); +} +simdjson_inline simdjson_result simdjson_result::operator[](std::string_view key) & noexcept { + if (error()) { return error(); } + return first[key]; +} +simdjson_inline simdjson_result simdjson_result::operator[](const char *key) & noexcept { + if (error()) { return error(); } + return first[key]; +} +simdjson_inline simdjson_result simdjson_result::find_field(std::string_view key) & noexcept { + if (error()) { return error(); } + return first.find_field(key); +} +simdjson_inline simdjson_result simdjson_result::find_field(const char *key) & noexcept { + if (error()) { return error(); } + return first.find_field(key); +} +simdjson_inline simdjson_result simdjson_result::get_array() & noexcept { + if (error()) { return error(); } + return first.get_array(); +} +simdjson_inline simdjson_result simdjson_result::get_object() & noexcept { + if (error()) { return error(); } + return first.get_object(); +} +simdjson_inline simdjson_result simdjson_result::get_uint64() noexcept { + if (error()) { return error(); } + return first.get_uint64(); +} +simdjson_inline simdjson_result simdjson_result::get_uint64_in_string() noexcept { + if (error()) { return error(); } + return first.get_uint64_in_string(); +} +simdjson_inline simdjson_result simdjson_result::get_int64() noexcept { + if (error()) { return error(); } + return first.get_int64(); +} +simdjson_inline simdjson_result simdjson_result::get_int64_in_string() noexcept { + if (error()) { return error(); } + return first.get_int64_in_string(); +} +simdjson_inline simdjson_result simdjson_result::get_double() noexcept { + if (error()) { return error(); } + return first.get_double(); +} +simdjson_inline simdjson_result simdjson_result::get_double_in_string() noexcept { + if (error()) { return error(); } + return first.get_double_in_string(); +} +simdjson_inline simdjson_result simdjson_result::get_string(bool allow_replacement) noexcept { + if (error()) { return error(); } + return first.get_string(allow_replacement); +} +template +simdjson_warn_unused simdjson_inline error_code simdjson_result::get_string(string_type& receiver, bool allow_replacement) noexcept { + if (error()) { return error(); } + return first.get_string(receiver, allow_replacement); +} +simdjson_inline simdjson_result simdjson_result::get_wobbly_string() noexcept { + if (error()) { return error(); } + return first.get_wobbly_string(); +} +simdjson_inline simdjson_result simdjson_result::get_raw_json_string() noexcept { + if (error()) { return error(); } + return first.get_raw_json_string(); +} +simdjson_inline simdjson_result simdjson_result::get_bool() noexcept { + if (error()) { return error(); } + return first.get_bool(); +} +simdjson_inline simdjson_result simdjson_result::get_value() noexcept { + if (error()) { return error(); } + return first.get_value(); +} +simdjson_inline simdjson_result simdjson_result::is_null() noexcept { + if (error()) { return error(); } + return first.is_null(); +} +template +simdjson_inline simdjson_result simdjson_result::get() & noexcept { + if (error()) { return error(); } + return first.get(); +} +template +simdjson_inline simdjson_result simdjson_result::get() && noexcept { + if (error()) { return error(); } + return std::forward(first).get(); +} +template +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) & noexcept { + if (error()) { return error(); } + return first.get(out); +} +template +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) && noexcept { + if (error()) { return error(); } + return std::forward(first).get(out); +} +simdjson_inline simdjson_result simdjson_result::type() noexcept { + if (error()) { return error(); } + return first.type(); +} +simdjson_inline simdjson_result simdjson_result::is_scalar() noexcept { + if (error()) { return error(); } + return first.is_scalar(); +} +simdjson_inline simdjson_result simdjson_result::is_string() noexcept { + if (error()) { return error(); } + return first.is_string(); +} +template <> +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(rvv_vls::ondemand::document_reference &out) & noexcept { + if (error()) { return error(); } + out = first; + return SUCCESS; +} +template <> +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(rvv_vls::ondemand::document_reference &out) && noexcept { + if (error()) { return error(); } + out = first; + return SUCCESS; +} +simdjson_inline simdjson_result simdjson_result::is_negative() noexcept { + if (error()) { return error(); } + return first.is_negative(); +} +simdjson_inline simdjson_result simdjson_result::is_integer() noexcept { + if (error()) { return error(); } + return first.is_integer(); +} +simdjson_inline simdjson_result simdjson_result::get_number_type() noexcept { + if (error()) { return error(); } + return first.get_number_type(); +} +simdjson_inline simdjson_result simdjson_result::get_number() noexcept { + if (error()) { return error(); } + return first.get_number(); +} +#if SIMDJSON_EXCEPTIONS +template +simdjson_inline simdjson_result::operator T() noexcept(false) { + static_assert(std::is_same::value == false, "You should not call get when T is a document"); + static_assert(std::is_same::value == false, "You should not call get when T is a document"); + if (error()) { throw simdjson_error(error()); } + return first.get(); +} +simdjson_inline simdjson_result::operator rvv_vls::ondemand::array() & noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator rvv_vls::ondemand::object() & noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator uint64_t() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator int64_t() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator double() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator std::string_view() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator rvv_vls::ondemand::raw_json_string() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator bool() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +simdjson_inline simdjson_result::operator rvv_vls::ondemand::value() noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first; +} +#endif + +simdjson_inline simdjson_result simdjson_result::current_location() noexcept { + if (error()) { return error(); } + return first.current_location(); +} + +simdjson_inline simdjson_result simdjson_result::raw_json_token() noexcept { + if (error()) { return error(); } + return first.raw_json_token(); +} + +simdjson_inline simdjson_result simdjson_result::at_pointer(std::string_view json_pointer) noexcept { + if (error()) { return error(); } + return first.at_pointer(json_pointer); +} + +simdjson_inline simdjson_result simdjson_result::at_path(std::string_view json_path) noexcept { + if (error()) { + return error(); + } + return first.at_path(json_path); +} +simdjson_inline simdjson_result> simdjson_result::at_path_with_wildcard(std::string_view json_path) noexcept { + if (error()) { + return error(); + } + return first.at_path_with_wildcard(json_path); +} +#if SIMDJSON_STATIC_REFLECTION +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_inline error_code simdjson_result::extract_into(T& out) & noexcept { + if (error()) { return error(); } + return first.extract_into(out); +} +#endif // SIMDJSON_STATIC_REFLECTION +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H +/* end file simdjson/generic/ondemand/document-inl.h for rvv_vls */ +/* including simdjson/generic/ondemand/document_stream-inl.h for rvv_vls: #include "simdjson/generic/ondemand/document_stream-inl.h" */ +/* begin file simdjson/generic/ondemand/document_stream-inl.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include +#include + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +#ifdef SIMDJSON_THREADS_ENABLED + +inline void stage1_worker::finish() { + // After calling "run" someone would call finish() to wait + // for the end of the processing. + // This function will wait until either the thread has done + // the processing or, else, the destructor has been called. + std::unique_lock lock(locking_mutex); + cond_var.wait(lock, [this]{return has_work == false;}); +} + +inline stage1_worker::~stage1_worker() { + // The thread may never outlive the stage1_worker instance + // and will always be stopped/joined before the stage1_worker + // instance is gone. + stop_thread(); +} + +inline void stage1_worker::start_thread() { + std::unique_lock lock(locking_mutex); + if(thread.joinable()) { + return; // This should never happen but we never want to create more than one thread. + } + thread = std::thread([this]{ + while(true) { + std::unique_lock thread_lock(locking_mutex); + // We wait for either "run" or "stop_thread" to be called. + cond_var.wait(thread_lock, [this]{return has_work || !can_work;}); + // If, for some reason, the stop_thread() method was called (i.e., the + // destructor of stage1_worker is called, then we want to immediately destroy + // the thread (and not do any more processing). + if(!can_work) { + break; + } + this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser, + this->_next_batch_start); + this->has_work = false; + // The condition variable call should be moved after thread_lock.unlock() for performance + // reasons but thread sanitizers may report it as a data race if we do. + // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock + cond_var.notify_one(); // will notify "finish" + thread_lock.unlock(); + } + } + ); +} + + +inline void stage1_worker::stop_thread() { + std::unique_lock lock(locking_mutex); + // We have to make sure that all locks can be released. + can_work = false; + has_work = false; + cond_var.notify_all(); + lock.unlock(); + if(thread.joinable()) { + thread.join(); + } +} + +inline void stage1_worker::run(document_stream * ds, parser * stage1, size_t next_batch_start) { + std::unique_lock lock(locking_mutex); + owner = ds; + _next_batch_start = next_batch_start; + stage1_thread_parser = stage1; + has_work = true; + // The condition variable call should be moved after thread_lock.unlock() for performance + // reasons but thread sanitizers may report it as a data race if we do. + // See https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock + cond_var.notify_one(); // will notify the thread lock that we have work + lock.unlock(); +} + +#endif // SIMDJSON_THREADS_ENABLED + +simdjson_inline document_stream::document_stream( + ondemand::parser &_parser, + const uint8_t *_buf, + size_t _len, + size_t _batch_size, + bool _allow_comma_separated +) noexcept + : parser{&_parser}, + buf{_buf}, + len{_len}, + batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size}, + allow_comma_separated{_allow_comma_separated}, + error{SUCCESS} + #ifdef SIMDJSON_THREADS_ENABLED + , use_thread(_parser.threaded) // we need to make a copy because _parser.threaded can change + #endif +{ +#ifdef SIMDJSON_THREADS_ENABLED + if(worker.get() == nullptr) { + error = MEMALLOC; + } +#endif +} + +simdjson_inline document_stream::document_stream() noexcept + : parser{nullptr}, + buf{nullptr}, + len{0}, + batch_size{0}, + allow_comma_separated{false}, + error{UNINITIALIZED} + #ifdef SIMDJSON_THREADS_ENABLED + , use_thread(false) + #endif +{ +} + +simdjson_inline document_stream::~document_stream() noexcept +{ + #ifdef SIMDJSON_THREADS_ENABLED + worker.reset(); + #endif +} + +inline size_t document_stream::size_in_bytes() const noexcept { + return len; +} + +inline size_t document_stream::truncated_bytes() const noexcept { + if(error == CAPACITY) { return len - batch_start; } + return parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] - parser->implementation->structural_indexes[parser->implementation->n_structural_indexes + 1]; +} + +simdjson_inline document_stream::iterator::iterator() noexcept + : stream{nullptr}, finished{true} { +} + +simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept + : stream{_stream}, finished{is_end} { +} + +simdjson_inline simdjson_result document_stream::iterator::operator*() noexcept { + return simdjson_result(stream->doc, stream->error); +} + +simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept { + // If there is an error, then we want the iterator + // to be finished, no matter what. (E.g., we do not + // keep generating documents with errors, or go beyond + // a document with errors.) + // + // Users do not have to call "operator*()" when they use operator++, + // so we need to end the stream in the operator++ function. + // + // Note that setting finished = true is essential otherwise + // we would enter an infinite loop. + if (stream->error) { finished = true; } + // Note that stream->error() is guarded against error conditions + // (it will immediately return if stream->error casts to false). + // In effect, this next function does nothing when (stream->error) + // is true (hence the risk of an infinite loop). + stream->next(); + // If that was the last document, we're finished. + // It is the only type of error we do not want to appear + // in operator*. + if (stream->error == EMPTY) { finished = true; } + // If we had any other kind of error (not EMPTY) then we want + // to pass it along to the operator* and we cannot mark the result + // as "finished" just yet. + return *this; +} + +simdjson_inline bool document_stream::iterator::at_end() const noexcept { + return finished; +} + + +simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept { + return finished != other.finished; +} + +simdjson_inline bool document_stream::iterator::operator==(const document_stream::iterator &other) const noexcept { + return finished == other.finished; +} + +simdjson_inline document_stream::iterator document_stream::begin() noexcept { + start(); + // If there are no documents, we're finished. + return iterator(this, error == EMPTY); +} + +simdjson_inline document_stream::iterator document_stream::end() noexcept { + return iterator(this, true); +} + +inline void document_stream::start() noexcept { + if (error) { return; } + error = parser->allocate(batch_size); + if (error) { return; } + // Always run the first stage 1 parse immediately + batch_start = 0; + error = run_stage1(*parser, batch_start); + while(error == EMPTY) { + // In exceptional cases, we may start with an empty block + batch_start = next_batch_start(); + if (batch_start >= len) { return; } + error = run_stage1(*parser, batch_start); + } + if (error) { return; } + doc_index = batch_start; + doc = document(json_iterator(&buf[batch_start], parser)); + doc.iter._streaming = true; + + #ifdef SIMDJSON_THREADS_ENABLED + if (use_thread && next_batch_start() < len) { + // Kick off the first thread on next batch if needed + error = stage1_thread_parser.allocate(batch_size); + if (error) { return; } + worker->start_thread(); + start_stage1_thread(); + if (error) { return; } + } + #endif // SIMDJSON_THREADS_ENABLED +} + +inline void document_stream::next() noexcept { + // We always enter at once once in an error condition. + if (error) { return; } + next_document(); + if (error) { return; } + auto cur_struct_index = doc.iter._root - parser->implementation->structural_indexes.get(); + doc_index = batch_start + parser->implementation->structural_indexes[cur_struct_index]; + + // Check if at end of structural indexes (i.e. at end of batch) + if(cur_struct_index >= static_cast(parser->implementation->n_structural_indexes)) { + error = EMPTY; + // Load another batch (if available) + while (error == EMPTY) { + batch_start = next_batch_start(); + if (batch_start >= len) { break; } + #ifdef SIMDJSON_THREADS_ENABLED + if(use_thread) { + load_from_stage1_thread(); + } else { + error = run_stage1(*parser, batch_start); + } + #else + error = run_stage1(*parser, batch_start); + #endif + /** + * Whenever we move to another window, we need to update all pointers to make + * it appear as if the input buffer started at the beginning of the window. + * + * Take this input: + * + * {"z":5} {"1":1,"2":2,"4":4} [7, 10, 9] [15, 11, 12, 13] [154, 110, 112, 1311] + * + * Say you process the following window... + * + * '{"z":5} {"1":1,"2":2,"4":4} [7, 10, 9]' + * + * When you do so, the json_iterator has a pointer at the beginning of the memory region + * (pointing at the beginning of '{"z"...'. + * + * When you move to the window that starts at... + * + * '[7, 10, 9] [15, 11, 12, 13] ... + * + * then it is not sufficient to just run stage 1. You also need to re-anchor the + * json_iterator so that it believes we are starting at '[7, 10, 9]...'. + * + * Under the DOM front-end, this gets done automatically because the parser owns + * the pointer the data, and when you call stage1 and then stage2 on the same + * parser, then stage2 will run on the pointer acquired by stage1. + * + * That is, stage1 calls "this->buf = _buf" so the parser remembers the buffer that + * we used. But json_iterator has no callback when stage1 is called on the parser. + * In fact, I think that the parser is unaware of json_iterator. + * + * + * So we need to re-anchor the json_iterator after each call to stage 1 so that + * all of the pointers are in sync. + */ + doc.iter = json_iterator(&buf[batch_start], parser); + doc.iter._streaming = true; + /** + * End of resync. + */ + + if (error) { continue; } // If the error was EMPTY, we may want to load another batch. + doc_index = batch_start; + } + } +} + +inline void document_stream::next_document() noexcept { + // Go to next place where depth=0 (document depth) + error = doc.iter.skip_child(0); + if (error) { return; } + // Always set depth=1 at the start of document + doc.iter._depth = 1; + // consume comma if comma separated is allowed + if (allow_comma_separated) { + error_code ignored = doc.iter.consume_character(','); + static_cast(ignored); // ignored on purpose + } + // Resets the string buffer at the beginning, thus invalidating the strings. + doc.iter._string_buf_loc = parser->string_buf.get(); + doc.iter._root = doc.iter.position(); +} + +inline size_t document_stream::next_batch_start() const noexcept { + return batch_start + parser->implementation->structural_indexes[parser->implementation->n_structural_indexes]; +} + +inline error_code document_stream::run_stage1(ondemand::parser &p, size_t _batch_start) noexcept { + // This code only updates the structural index in the parser, it does not update any json_iterator + // instance. + size_t remaining = len - _batch_start; + if (remaining <= batch_size) { + return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final); + } else { + return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial); + } +} + +simdjson_inline size_t document_stream::iterator::current_index() const noexcept { + return stream->doc_index; +} + +simdjson_inline std::string_view document_stream::iterator::source() const noexcept { + auto depth = stream->doc.iter.depth(); + auto cur_struct_index = stream->doc.iter._root - stream->parser->implementation->structural_indexes.get(); + + // If at root, process the first token to determine if scalar value + if (stream->doc.iter.at_root()) { + switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) { + case '{': case '[': // Depth=1 already at start of document + break; + case '}': case ']': + depth--; + break; + default: // Scalar value document + // TODO: We could remove trailing whitespaces + // This returns a string spanning from start of value to the beginning of the next document (excluded) + { + auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index]; + // normally the length would be next_index - current_index() - 1, except for the last document + size_t svlen = next_index - current_index(); + const char *start = reinterpret_cast(stream->buf) + current_index(); + while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) { + svlen--; + } + return std::string_view(start, svlen); + } + } + cur_struct_index++; + } + + while (cur_struct_index <= static_cast(stream->parser->implementation->n_structural_indexes)) { + switch (stream->buf[stream->batch_start + stream->parser->implementation->structural_indexes[cur_struct_index]]) { + case '{': case '[': + depth++; + break; + case '}': case ']': + depth--; + break; + } + if (depth == 0) { break; } + cur_struct_index++; + } + + return std::string_view(reinterpret_cast(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[cur_struct_index] - current_index() + stream->batch_start + 1);; +} + +inline error_code document_stream::iterator::error() const noexcept { + return stream->error; +} + +#ifdef SIMDJSON_THREADS_ENABLED + +inline void document_stream::load_from_stage1_thread() noexcept { + worker->finish(); + // Swap to the parser that was loaded up in the thread. Make sure the parser has + // enough memory to swap to, as well. + std::swap(stage1_thread_parser,*parser); + error = stage1_thread_error; + if (error) { return; } + + // If there's anything left, start the stage 1 thread! + if (next_batch_start() < len) { + start_stage1_thread(); + } +} + +inline void document_stream::start_stage1_thread() noexcept { + // we call the thread on a lambda that will update + // this->stage1_thread_error + // there is only one thread that may write to this value + // TODO this is NOT exception-safe. + this->stage1_thread_error = UNINITIALIZED; // In case something goes wrong, make sure it's an error + size_t _next_batch_start = this->next_batch_start(); + + worker->run(this, & this->stage1_thread_parser, _next_batch_start); +} + +#endif // SIMDJSON_THREADS_ENABLED + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +simdjson_inline simdjson_result::simdjson_result( + error_code error +) noexcept : + implementation_simdjson_result_base(error) +{ +} +simdjson_inline simdjson_result::simdjson_result( + rvv_vls::ondemand::document_stream &&value +) noexcept : + implementation_simdjson_result_base( + std::forward(value) + ) +{ +} + +} + +#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_INL_H +/* end file simdjson/generic/ondemand/document_stream-inl.h for rvv_vls */ +/* including simdjson/generic/ondemand/field-inl.h for rvv_vls: #include "simdjson/generic/ondemand/field-inl.h" */ +/* begin file simdjson/generic/ondemand/field-inl.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +// clang 6 does not think the default constructor can be noexcept, so we make it explicit +simdjson_inline field::field() noexcept : std::pair() {} + +simdjson_inline field::field(raw_json_string key, ondemand::value &&value) noexcept + : std::pair(key, std::forward(value)) +{ +} + +simdjson_inline simdjson_result field::start(value_iterator &parent_iter) noexcept { + raw_json_string key; + SIMDJSON_TRY( parent_iter.field_key().get(key) ); + SIMDJSON_TRY( parent_iter.field_value() ); + return field::start(parent_iter, key); +} + +simdjson_inline simdjson_result field::start(const value_iterator &parent_iter, raw_json_string key) noexcept { + return field(key, parent_iter.child()); +} + +simdjson_inline simdjson_warn_unused simdjson_result field::unescaped_key(bool allow_replacement) noexcept { + SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us. + simdjson_result answer = first.unescape(second.iter.json_iter(), allow_replacement); + first.consume(); + return answer; +} + +template +simdjson_inline simdjson_warn_unused error_code field::unescaped_key(string_type& receiver, bool allow_replacement) noexcept { + std::string_view key; + SIMDJSON_TRY( unescaped_key(allow_replacement).get(key) ); + receiver = key; + return SUCCESS; +} + +simdjson_inline raw_json_string field::key() const noexcept { + SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us. + return first; +} + + +simdjson_inline std::string_view field::key_raw_json_token() const noexcept { + SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us. + return std::string_view(reinterpret_cast(first.buf-1), second.iter._json_iter->token.peek(-1) - first.buf + 1); +} + +simdjson_inline std::string_view field::escaped_key() const noexcept { + SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us. + auto end_quote = second.iter._json_iter->token.peek(-1); + while(*end_quote != '"') end_quote--; + return std::string_view(reinterpret_cast(first.buf), end_quote - first.buf); +} + +simdjson_inline value &field::value() & noexcept { + return second; +} + +simdjson_inline value field::value() && noexcept { + return std::forward(*this).second; +} + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +simdjson_inline simdjson_result::simdjson_result( + rvv_vls::ondemand::field &&value +) noexcept : + implementation_simdjson_result_base( + std::forward(value) + ) +{ +} +simdjson_inline simdjson_result::simdjson_result( + error_code error +) noexcept : + implementation_simdjson_result_base(error) +{ +} + +simdjson_inline simdjson_result simdjson_result::key() noexcept { + if (error()) { return error(); } + return first.key(); +} + +simdjson_inline simdjson_result simdjson_result::key_raw_json_token() noexcept { + if (error()) { return error(); } + return first.key_raw_json_token(); +} + +simdjson_inline simdjson_result simdjson_result::escaped_key() noexcept { + if (error()) { return error(); } + return first.escaped_key(); +} + +simdjson_inline simdjson_result simdjson_result::unescaped_key(bool allow_replacement) noexcept { + if (error()) { return error(); } + return first.unescaped_key(allow_replacement); +} + +template +simdjson_warn_unused simdjson_inline error_code simdjson_result::unescaped_key(string_type &receiver, bool allow_replacement) noexcept { + if (error()) { return error(); } + return first.unescaped_key(receiver, allow_replacement); +} + +simdjson_inline simdjson_result simdjson_result::value() noexcept { + if (error()) { return error(); } + return std::move(first.value()); +} + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_FIELD_INL_H +/* end file simdjson/generic/ondemand/field-inl.h for rvv_vls */ +/* including simdjson/generic/ondemand/json_iterator-inl.h for rvv_vls: #include "simdjson/generic/ondemand/json_iterator-inl.h" */ +/* begin file simdjson/generic/ondemand/json_iterator-inl.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger-inl.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser-inl.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator-inl.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept + : token(std::forward(other.token)), + parser{other.parser}, + _string_buf_loc{other._string_buf_loc}, + error{other.error}, + _depth{other._depth}, + _root{other._root}, + _streaming{other._streaming} +{ + other.parser = nullptr; +} +simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept { + token = other.token; + parser = other.parser; + _string_buf_loc = other._string_buf_loc; + error = other.error; + _depth = other._depth; + _root = other._root; + _streaming = other._streaming; + other.parser = nullptr; + return *this; +} + +simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept + : token(buf, &_parser->implementation->structural_indexes[0]), + parser{_parser}, + _string_buf_loc{parser->string_buf.get()}, + _depth{1}, + _root{parser->implementation->structural_indexes.get()}, + _streaming{false} + +{ + logger::log_headers(); +#if SIMDJSON_CHECK_EOF + assert_more_tokens(); +#endif +} + +#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON +simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept + : token(buf, &_parser->implementation->structural_indexes[0]), + parser{_parser}, + _string_buf_loc{parser->string_buf.get()}, + _depth{1}, + _root{parser->implementation->structural_indexes.get()}, + _streaming{streaming} + +{ + logger::log_headers(); +#if SIMDJSON_CHECK_EOF + assert_more_tokens(); +#endif +} +#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON + +inline void json_iterator::rewind() noexcept { + token.set_position( root_position() ); + logger::log_headers(); // We start again + _string_buf_loc = parser->string_buf.get(); + _depth = 1; +} + +inline bool json_iterator::balanced() const noexcept { + token_iterator ti(token); + int32_t count{0}; + ti.set_position( root_position() ); + while(ti.peek() <= peek_last()) { + switch (*ti.return_current_and_advance()) + { + case '[': case '{': + count++; + break; + case ']': case '}': + count--; + break; + default: + break; + } + } + return count == 0; +} + + +// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller +// relating depth and parent_depth, which is a desired effect. The warning does not show up if the +// skip_child() function is not marked inline). +SIMDJSON_PUSH_DISABLE_WARNINGS +SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING +simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept { + if (depth() <= parent_depth) { return SUCCESS; } + switch (*return_current_and_advance()) { + // TODO consider whether matching braces is a requirement: if non-matching braces indicates + // *missing* braces, then future lookups are not in the object/arrays they think they are, + // violating the rule "validate enough structure that the user can be confident they are + // looking at the right values." + // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth + + // For the first open array/object in a value, we've already incremented depth, so keep it the same + // We never stop at colon, but if we did, it wouldn't affect depth + case '[': case '{': case ':': + logger::log_start_value(*this, "skip"); + break; + // If there is a comma, we have just finished a value in an array/object, and need to get back in + case ',': + logger::log_value(*this, "skip"); + break; + // ] or } means we just finished a value and need to jump out of the array/object + case ']': case '}': + logger::log_end_value(*this, "skip"); + _depth--; + if (depth() <= parent_depth) { return SUCCESS; } +#if SIMDJSON_CHECK_EOF + // If there are no more tokens, the parent is incomplete. + if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); } +#endif // SIMDJSON_CHECK_EOF + break; + case '"': + if(*peek() == ':') { + // We are at a key!!! + // This might happen if you just started an object and you skip it immediately. + // Performance note: it would be nice to get rid of this check as it is somewhat + // expensive. + // https://github.com/simdjson/simdjson/issues/1742 + logger::log_value(*this, "key"); + return_current_and_advance(); // eat up the ':' + break; // important!!! + } + simdjson_fallthrough; + // Anything else must be a scalar value + default: + // For the first scalar, we will have incremented depth already, so we decrement it here. + logger::log_value(*this, "skip"); + _depth--; + if (depth() <= parent_depth) { return SUCCESS; } + break; + } + + // Now that we've considered the first value, we only increment/decrement for arrays/objects + while (position() < end_position()) { + switch (*return_current_and_advance()) { + case '[': case '{': + logger::log_start_value(*this, "skip"); + _depth++; + break; + // TODO consider whether matching braces is a requirement: if non-matching braces indicates + // *missing* braces, then future lookups are not in the object/arrays they think they are, + // violating the rule "validate enough structure that the user can be confident they are + // looking at the right values." + // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth + case ']': case '}': + logger::log_end_value(*this, "skip"); + _depth--; + if (depth() <= parent_depth) { return SUCCESS; } + break; + default: + logger::log_value(*this, "skip", ""); + break; + } + } + + return report_error(TAPE_ERROR, "not enough close braces"); +} + +SIMDJSON_POP_DISABLE_WARNINGS + +simdjson_inline bool json_iterator::at_root() const noexcept { + return position() == root_position(); +} + +simdjson_inline bool json_iterator::is_single_token() const noexcept { + return parser->implementation->n_structural_indexes == 1; +} + +simdjson_inline bool json_iterator::streaming() const noexcept { + return _streaming; +} + +simdjson_inline token_position json_iterator::root_position() const noexcept { + return _root; +} + +simdjson_inline void json_iterator::assert_at_document_depth() const noexcept { + SIMDJSON_ASSUME( _depth == 1 ); +} + +simdjson_inline void json_iterator::assert_at_root() const noexcept { + SIMDJSON_ASSUME( _depth == 1 ); +#ifndef SIMDJSON_CLANG_VISUAL_STUDIO + // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument + // has side effects that will be discarded. + SIMDJSON_ASSUME( token.position() == _root ); +#endif +} + +simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept { + assert_valid_position(token._position + required_tokens - 1); +} + +simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept { + (void)position; // Suppress unused parameter warning +#ifndef SIMDJSON_CLANG_VISUAL_STUDIO + SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] ); + SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] ); +#endif +} + +simdjson_inline bool json_iterator::at_end() const noexcept { + return position() == end_position(); +} +simdjson_inline token_position json_iterator::end_position() const noexcept { + uint32_t n_structural_indexes{parser->implementation->n_structural_indexes}; + return &parser->implementation->structural_indexes[n_structural_indexes]; +} + +inline std::string json_iterator::to_string() const noexcept { + if( !is_alive() ) { return "dead json_iterator instance"; } + const char * current_structural = reinterpret_cast(token.peek()); + return std::string("json_iterator [ depth : ") + std::to_string(_depth) + + std::string(", structural : '") + std::string(current_structural,1) + + std::string("', offset : ") + std::to_string(token.current_offset()) + + std::string("', error : ") + error_message(error) + + std::string(" ]"); +} + +inline simdjson_result json_iterator::current_location() const noexcept { + if (!is_alive()) { // Unrecoverable error + if (!at_root()) { + return reinterpret_cast(token.peek(-1)); + } else { + return reinterpret_cast(token.peek()); + } + } + if (at_end()) { + return OUT_OF_BOUNDS; + } + return reinterpret_cast(token.peek()); +} + +simdjson_inline bool json_iterator::is_alive() const noexcept { + return parser; +} + +simdjson_inline void json_iterator::abandon() noexcept { + parser = nullptr; + _depth = 0; +} + +simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept { +#if SIMDJSON_CHECK_EOF + assert_more_tokens(); +#endif // SIMDJSON_CHECK_EOF + return token.return_current_and_advance(); +} + +simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept { + // deliberately done without safety guard: + return token.peek(); +} + +simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept { +#if SIMDJSON_CHECK_EOF + assert_more_tokens(delta+1); +#endif // SIMDJSON_CHECK_EOF + return token.peek(delta); +} + +simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept { +#if SIMDJSON_CHECK_EOF + assert_more_tokens(delta+1); +#endif // #if SIMDJSON_CHECK_EOF + return token.peek_length(delta); +} + +simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept { + // todo: currently we require end-of-string buffering, but the following + // assert_valid_position should be turned on if/when we lift that condition. + // assert_valid_position(position); + // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF + // is ON by default, we have no choice but to disable it for real with a comment. + return token.peek(position); +} + +simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept { +#if SIMDJSON_CHECK_EOF + assert_valid_position(position); +#endif // SIMDJSON_CHECK_EOF + return token.peek_length(position); +} +simdjson_inline uint32_t json_iterator::peek_root_length(token_position position) const noexcept { +#if SIMDJSON_CHECK_EOF + assert_valid_position(position); +#endif // SIMDJSON_CHECK_EOF + return token.peek_root_length(position); +} + +simdjson_inline token_position json_iterator::last_position() const noexcept { + // The following line fails under some compilers... + // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0); + // since it has side-effects. + uint32_t n_structural_indexes{parser->implementation->n_structural_indexes}; + SIMDJSON_ASSUME(n_structural_indexes > 0); + return &parser->implementation->structural_indexes[n_structural_indexes - 1]; +} +simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept { + return token.peek(last_position()); +} + +simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept { + SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1); + SIMDJSON_ASSUME(_depth == parent_depth + 1); + _depth = parent_depth; +} + +simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept { + SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX); + SIMDJSON_ASSUME(_depth == child_depth - 1); + _depth = child_depth; +} + +simdjson_inline depth_t json_iterator::depth() const noexcept { + return _depth; +} + +simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept { + return _string_buf_loc; +} + +simdjson_warn_unused simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept { + SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD); + logger::log_error(*this, message); + error = _error; + return error; +} + +simdjson_inline token_position json_iterator::position() const noexcept { + return token.position(); +} + +simdjson_inline simdjson_result json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept { +#if SIMDJSON_DEVELOPMENT_CHECKS + auto result = parser->unescape(in, _string_buf_loc, allow_replacement); +#if !defined(SIMDJSON_VISUAL_STUDIO) && !defined(SIMDJSON_CLANG_VISUAL_STUDIO) + // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument + // has side effects that will be discarded. + SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc)); +#endif // !defined(SIMDJSON_VISUAL_STUDIO) && !defined(SIMDJSON_CLANG_VISUAL_STUDIO) + return result; +#else + return parser->unescape(in, _string_buf_loc, allow_replacement); +#endif +} + +simdjson_inline simdjson_result json_iterator::unescape_wobbly(raw_json_string in) noexcept { +#if SIMDJSON_DEVELOPMENT_CHECKS + auto result = parser->unescape_wobbly(in, _string_buf_loc); +#if !defined(SIMDJSON_VISUAL_STUDIO) && !defined(SIMDJSON_CLANG_VISUAL_STUDIO) + // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument + // has side effects that will be discarded. + SIMDJSON_ASSUME(!parser->string_buffer_overflow(_string_buf_loc)); +#endif // !defined(SIMDJSON_VISUAL_STUDIO) && !defined(SIMDJSON_CLANG_VISUAL_STUDIO) + return result; +#else + return parser->unescape_wobbly(in, _string_buf_loc); +#endif +} + +simdjson_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept { + SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX); + SIMDJSON_ASSUME(_depth == child_depth - 1); +#if SIMDJSON_DEVELOPMENT_CHECKS +#ifndef SIMDJSON_CLANG_VISUAL_STUDIO + SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth()); + SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]); +#endif +#endif + token.set_position(position); + _depth = child_depth; +} + +simdjson_warn_unused simdjson_inline error_code json_iterator::consume_character(char c) noexcept { + if (*peek() == c) { + return_current_and_advance(); + return SUCCESS; + } + return TAPE_ERROR; +} + +#if SIMDJSON_DEVELOPMENT_CHECKS + +simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept { + SIMDJSON_ASSUME(size_t(depth) < parser->max_depth()); + return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0; +} + +simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept { + SIMDJSON_ASSUME(size_t(depth) < parser->max_depth()); + if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; } +} + +#endif + + +simdjson_warn_unused simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept { + SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD); + logger::log_error(*this, message); + return _error; +} + + +simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept { + // This function is not expected to be called in performance-sensitive settings. + // Let us guard against silly cases: + if((N < max_len) || (N == 0)) { return false; } + // Copy to the buffer. + std::memcpy(tmpbuf, json, max_len); + if(N > max_len) { // We pad whatever remains with ' '. + std::memset(tmpbuf + max_len, ' ', N - max_len); + } + return true; +} + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +simdjson_inline simdjson_result::simdjson_result(rvv_vls::ondemand::json_iterator &&value) noexcept + : implementation_simdjson_result_base(std::forward(value)) {} +simdjson_inline simdjson_result::simdjson_result(error_code error) noexcept + : implementation_simdjson_result_base(error) {} + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_ITERATOR_INL_H +/* end file simdjson/generic/ondemand/json_iterator-inl.h for rvv_vls */ +/* including simdjson/generic/ondemand/json_type-inl.h for rvv_vls: #include "simdjson/generic/ondemand/json_type-inl.h" */ +/* begin file simdjson/generic/ondemand/json_type-inl.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept { + switch (type) { + case json_type::array: out << "array"; break; + case json_type::object: out << "object"; break; + case json_type::number: out << "number"; break; + case json_type::string: out << "string"; break; + case json_type::boolean: out << "boolean"; break; + case json_type::null: out << "null"; break; + default: SIMDJSON_UNREACHABLE(); + } + return out; +} + +#if SIMDJSON_EXCEPTIONS +inline std::ostream& operator<<(std::ostream& out, simdjson_result &type) noexcept(false) { + return out << type.value(); +} +#endif + + + +simdjson_inline number_type number::get_number_type() const noexcept { + return type; +} + +simdjson_inline bool number::is_uint64() const noexcept { + return get_number_type() == number_type::unsigned_integer; +} + +simdjson_inline uint64_t number::get_uint64() const noexcept { + return payload.unsigned_integer; +} + +simdjson_inline number::operator uint64_t() const noexcept { + return get_uint64(); +} + +simdjson_inline bool number::is_int64() const noexcept { + return get_number_type() == number_type::signed_integer; +} + +simdjson_inline int64_t number::get_int64() const noexcept { + return payload.signed_integer; +} + +simdjson_inline number::operator int64_t() const noexcept { + return get_int64(); +} + +simdjson_inline bool number::is_double() const noexcept { + return get_number_type() == number_type::floating_point_number; +} + +simdjson_inline double number::get_double() const noexcept { + return payload.floating_point_number; +} + +simdjson_inline number::operator double() const noexcept { + return get_double(); +} + +simdjson_inline double number::as_double() const noexcept { + if(is_double()) { + return payload.floating_point_number; + } + if(is_int64()) { + return double(payload.signed_integer); + } + return double(payload.unsigned_integer); +} + +simdjson_inline void number::append_s64(int64_t value) noexcept { + payload.signed_integer = value; + type = number_type::signed_integer; +} + +simdjson_inline void number::append_u64(uint64_t value) noexcept { + payload.unsigned_integer = value; + type = number_type::unsigned_integer; +} + +simdjson_inline void number::append_double(double value) noexcept { + payload.floating_point_number = value; + type = number_type::floating_point_number; +} + +simdjson_inline void number::skip_double() noexcept { + type = number_type::floating_point_number; +} + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +simdjson_inline simdjson_result::simdjson_result(rvv_vls::ondemand::json_type &&value) noexcept + : implementation_simdjson_result_base(std::forward(value)) {} +simdjson_inline simdjson_result::simdjson_result(error_code error) noexcept + : implementation_simdjson_result_base(error) {} + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_JSON_TYPE_INL_H +/* end file simdjson/generic/ondemand/json_type-inl.h for rvv_vls */ +/* including simdjson/generic/ondemand/logger-inl.h for rvv_vls: #include "simdjson/generic/ondemand/logger-inl.h" */ +/* begin file simdjson/generic/ondemand/logger-inl.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/logger.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +#include +#include + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { +namespace logger { + +static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"; +static constexpr const int LOG_EVENT_LEN = 20; +static constexpr const int LOG_BUFFER_LEN = 30; +static constexpr const int LOG_SMALL_BUFFER_LEN = 10; +static int log_depth = 0; // Not threadsafe. Log only. + +// Helper to turn unprintable or newline characters into spaces +static inline char printable_char(char c) { + if (c >= 0x20) { + return c; + } else { + return ' '; + } +} + +template +static inline std::string string_format(const std::string& format, const Args&... args) +{ + SIMDJSON_PUSH_DISABLE_ALL_WARNINGS + int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; + auto size = static_cast(size_s); + if (size <= 0) return std::string(); + std::unique_ptr buf(new char[size]); + std::snprintf(buf.get(), size, format.c_str(), args...); + SIMDJSON_POP_DISABLE_WARNINGS + return std::string(buf.get(), buf.get() + size - 1); +} + +static inline log_level get_log_level_from_env() +{ + SIMDJSON_PUSH_DISABLE_WARNINGS + SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe + char *lvl = getenv("SIMDJSON_LOG_LEVEL"); + SIMDJSON_POP_DISABLE_WARNINGS + if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; } + return log_level::info; +} + +static inline log_level log_threshold() +{ + static log_level threshold = get_log_level_from_env(); + return threshold; +} + +static inline bool should_log(log_level level) +{ + return level >= log_threshold(); +} + +inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept { + log_line(iter, "", type, detail, delta, depth_delta, log_level::info); +} + +inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept { + log_line(iter, index, depth, "", type, detail, log_level::info); +} +inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept { + log_line(iter, "", type, detail, delta, depth_delta, log_level::info); +} + +inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept { + log_line(iter, index, depth, "+", type, detail, log_level::info); + if (LOG_ENABLED) { log_depth++; } +} +inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept { + log_line(iter, "+", type, "", delta, depth_delta, log_level::info); + if (LOG_ENABLED) { log_depth++; } +} + +inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept { + if (LOG_ENABLED) { log_depth--; } + log_line(iter, "-", type, "", delta, depth_delta, log_level::info); +} + +inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept { + log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error); +} +inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept { + log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error); +} + +inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept { + log_event(iter.json_iter(), type, detail, delta, depth_delta); +} + +inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept { + log_value(iter.json_iter(), type, detail, delta, depth_delta); +} + +inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept { + log_start_value(iter.json_iter(), type, delta, depth_delta); +} + +inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept { + log_end_value(iter.json_iter(), type, delta, depth_delta); +} + +inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept { + log_error(iter.json_iter(), error, detail, delta, depth_delta); +} + +inline void log_headers() noexcept { + if (LOG_ENABLED) { + if (simdjson_unlikely(should_log(log_level::info))) { + // Technically a static variable is not thread-safe, but if you are using threads and logging... well... + static bool displayed_hint{false}; + log_depth = 0; + printf("\n"); + if (!displayed_hint) { + // We only print this helpful header once. + printf("# Logging provides the depth and position of the iterator user-visible steps:\n"); + printf("# +array says 'this is where we were when we discovered the start array'\n"); + printf( + "# -array says 'this is where we were when we ended the array'\n"); + printf("# skip says 'this is a structural or value I am skipping'\n"); + printf("# +/-skip says 'this is a start/end array or object I am skipping'\n"); + printf("#\n"); + printf("# The indentation of the terms (array, string,...) indicates the depth,\n"); + printf("# in addition to the depth being displayed.\n"); + printf("#\n"); + printf("# Every token in the document has a single depth determined by the tokens before it,\n"); + printf("# and is not affected by what the token actually is.\n"); + printf("#\n"); + printf("# Not all structural elements are presented as tokens in the logs.\n"); + printf("#\n"); + printf("# We never give control to the user within an empty array or an empty object.\n"); + printf("#\n"); + printf("# Inside an array, having a depth greater than the array's depth means that\n"); + printf("# we are pointing inside a value.\n"); + printf("# Having a depth equal to the array means that we are pointing right before a value.\n"); + printf("# Having a depth smaller than the array means that we have moved beyond the array.\n"); + displayed_hint = true; + } + printf("\n"); + printf("| %-*s ", LOG_EVENT_LEN, "Event"); + printf("| %-*s ", LOG_BUFFER_LEN, "Buffer"); + printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next"); + // printf("| %-*s ", 5, "Next#"); + printf("| %-*s ", 5, "Depth"); + printf("| Detail "); + printf("|\n"); + + printf("|%.*s", LOG_EVENT_LEN + 2, DASHES); + printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES); + printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES); + // printf("|%.*s", 5+2, DASHES); + printf("|%.*s", 5 + 2, DASHES); + printf("|--------"); + printf("|\n"); + fflush(stdout); + } + } +} + +template +inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept { + log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward(args)...); +} + +template +inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept { + if (LOG_ENABLED) { + if (simdjson_unlikely(should_log(level))) { + const int indent = depth * 2; + const auto buf = iter.token.buf; + auto msg = string_format(title, std::forward(args)...); + printf("| %*s%s%-*s ", indent, "", title_prefix, + LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str()); + { + // Print the current structural. + printf("| "); + // Before we begin, the index might point right before the document. + // This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938 + if (index < iter._root) { + printf("%*s", LOG_BUFFER_LEN, ""); + } else { + auto current_structural = &buf[*index]; + for (int i = 0; i < LOG_BUFFER_LEN; i++) { + printf("%c", printable_char(current_structural[i])); + } + } + printf(" "); + } + { + // Print the next structural. + printf("| "); + auto next_structural = &buf[*(index + 1)]; + for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) { + printf("%c", printable_char(next_structural[i])); + } + printf(" "); + } + // printf("| %5u ", *(index+1)); + printf("| %5i ", depth); + printf("| %6.*s ", int(detail.size()), detail.data()); + printf("|\n"); + fflush(stdout); + } + } +} + +} // namespace logger +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_LOGGER_INL_H +/* end file simdjson/generic/ondemand/logger-inl.h for rvv_vls */ +/* including simdjson/generic/ondemand/object-inl.h for rvv_vls: #include "simdjson/generic/ondemand/object-inl.h" */ +/* begin file simdjson/generic/ondemand/object-inl.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value-inl.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/jsonpathutil.h" */ +/* amalgamation skipped (editor-only): #if SIMDJSON_STATIC_REFLECTION */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_string_builder.h" // for constevalutil::fixed_string */ +/* amalgamation skipped (editor-only): #include */ +/* amalgamation skipped (editor-only): #endif */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +simdjson_inline simdjson_result object::find_field_unordered(const std::string_view key) & noexcept { + bool has_value; + SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) ); + if (!has_value) { + logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast(key.size()), key.data()); + return NO_SUCH_FIELD; + } + return value(iter.child()); +} +simdjson_inline simdjson_result object::find_field_unordered(const std::string_view key) && noexcept { + bool has_value; + SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) ); + if (!has_value) { + logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast(key.size()), key.data()); + return NO_SUCH_FIELD; + } + return value(iter.child()); +} +simdjson_inline simdjson_result object::operator[](const std::string_view key) & noexcept { + return find_field_unordered(key); +} +simdjson_inline simdjson_result object::operator[](const std::string_view key) && noexcept { + return std::forward(*this).find_field_unordered(key); +} +simdjson_inline simdjson_result object::find_field(const std::string_view key) & noexcept { + bool has_value; + SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) ); + if (!has_value) { + logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast(key.size()), key.data()); + return NO_SUCH_FIELD; + } + return value(iter.child()); +} +simdjson_inline simdjson_result object::find_field(const std::string_view key) && noexcept { + bool has_value; + SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) ); + if (!has_value) { + logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast(key.size()), key.data()); + return NO_SUCH_FIELD; + } + return value(iter.child()); +} + +simdjson_inline simdjson_result object::start(value_iterator &iter) noexcept { + SIMDJSON_TRY( iter.start_object().error() ); + return object(iter); +} +simdjson_inline simdjson_result object::start_root(value_iterator &iter) noexcept { + SIMDJSON_TRY( iter.start_root_object().error() ); + return object(iter); +} +simdjson_warn_unused simdjson_inline error_code object::consume() noexcept { + if(iter.is_at_key()) { + /** + * whenever you are pointing at a key, calling skip_child() is + * unsafe because you will hit a string and you will assume that + * it is string value, and this mistake will lead you to make bad + * depth computation. + */ + /** + * We want to 'consume' the key. We could really + * just do _json_iter->return_current_and_advance(); at this + * point, but, for clarity, we will use the high-level API to + * eat the key. We assume that the compiler optimizes away + * most of the work. + */ + simdjson_unused raw_json_string actual_key; + auto error = iter.field_key().get(actual_key); + if (error) { iter.abandon(); return error; }; + // Let us move to the value while we are at it. + if ((error = iter.field_value())) { iter.abandon(); return error; } + } + auto error_skip = iter.json_iter().skip_child(iter.depth()-1); + if(error_skip) { iter.abandon(); } + return error_skip; +} + +simdjson_inline simdjson_result object::raw_json() noexcept { + const uint8_t * starting_point{iter.peek_start()}; + auto error = consume(); + if(error) { return error; } + const uint8_t * final_point{iter._json_iter->peek()}; + return std::string_view(reinterpret_cast(starting_point), size_t(final_point - starting_point)); +} + +simdjson_inline simdjson_result object::started(value_iterator &iter) noexcept { + SIMDJSON_TRY( iter.started_object().error() ); + return object(iter); +} + +simdjson_inline object object::resume(const value_iterator &iter) noexcept { + return iter; +} + +simdjson_inline object::object(const value_iterator &_iter) noexcept + : iter{_iter} +{ +} + +simdjson_inline simdjson_result object::begin() noexcept { +#if SIMDJSON_DEVELOPMENT_CHECKS + if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; } +#endif + return object_iterator(iter); +} +simdjson_inline simdjson_result object::end() noexcept { + return object_iterator(iter); +} + +inline simdjson_result object::at_pointer(std::string_view json_pointer) noexcept { + if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; } + json_pointer = json_pointer.substr(1); + size_t slash = json_pointer.find('/'); + std::string_view key = json_pointer.substr(0, slash); + // Grab the child with the given key + simdjson_result child; + + // If there is an escape character in the key, unescape it and then get the child. + size_t escape = key.find('~'); + if (escape != std::string_view::npos) { + // Unescape the key + std::string unescaped(key); + do { + switch (unescaped[escape+1]) { + case '0': + unescaped.replace(escape, 2, "~"); + break; + case '1': + unescaped.replace(escape, 2, "/"); + break; + default: + return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer"); + } + escape = unescaped.find('~', escape+1); + } while (escape != std::string::npos); + child = find_field(unescaped); // Take note find_field does not unescape keys when matching + } else { + child = find_field(key); + } + if(child.error()) { + return child; // we do not continue if there was an error + } + // If there is a /, we have to recurse and look up more of the path + if (slash != std::string_view::npos) { + child = child.at_pointer(json_pointer.substr(slash)); + } + return child; +} + +inline simdjson_result object::at_path(std::string_view json_path) noexcept { + auto json_pointer = json_path_to_pointer_conversion(json_path); + if (json_pointer == "-1") { + return INVALID_JSON_POINTER; + } + return at_pointer(json_pointer); +} + +inline simdjson_result> object::at_path_with_wildcard(std::string_view json_path) noexcept { + std::vector result; + + auto result_pair = get_next_key_and_json_path(json_path); + std::string_view key = result_pair.first; + std::string_view remaining_path = result_pair.second; + // Handle when its the case for wildcard + if (key == "*") { + // Loop through each field in the object + for (auto field : *this) { + value val; + SIMDJSON_TRY(field.value().get(val)); + + if (remaining_path.empty()) { + result.push_back(std::move(val)); + } else { + auto nested_result = val.at_path_with_wildcard(remaining_path); + + if (nested_result.error()) { + return nested_result.error(); + } + // Extract and append all nested matches to our result + std::vector nested_vec; + SIMDJSON_TRY(std::move(nested_result).get(nested_vec)); + + result.insert(result.end(), + std::make_move_iterator(nested_vec.begin()), + std::make_move_iterator(nested_vec.end())); + } + } + return result; + } else { + value val; + SIMDJSON_TRY(find_field(key).get(val)); + + if (remaining_path.empty()) { + result.push_back(std::move(val)); + return result; + } else { + return val.at_path_with_wildcard(remaining_path); + } + } +} + +simdjson_inline simdjson_result object::count_fields() & noexcept { + size_t count{0}; + // Important: we do not consume any of the values. + for(simdjson_unused auto v : *this) { count++; } + // The above loop will always succeed, but we want to report errors. + if(iter.error()) { return iter.error(); } + // We need to move back at the start because we expect users to iterate through + // the object after counting the number of elements. + iter.reset_object(); + return count; +} + +simdjson_inline simdjson_result object::is_empty() & noexcept { + bool is_not_empty; + auto error = iter.reset_object().get(is_not_empty); + if(error) { return error; } + return !is_not_empty; +} + +simdjson_inline simdjson_result object::reset() & noexcept { + return iter.reset_object(); +} + +#if SIMDJSON_SUPPORTS_CONCEPTS && SIMDJSON_STATIC_REFLECTION + +template + requires(std::is_class_v && (sizeof...(FieldNames) > 0)) +simdjson_warn_unused simdjson_inline error_code object::extract_into(T& out) & noexcept { + // Helper to check if a field name matches any of the requested fields + auto should_extract = [](std::string_view field_name) constexpr -> bool { + return ((FieldNames.view() == field_name) || ...); + }; + + // Iterate through all members of T using reflection + template for (constexpr auto mem : std::define_static_array( + std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()))) { + + if constexpr (!std::meta::is_const(mem) && std::meta::is_public(mem)) { + constexpr std::string_view key = std::define_static_string(std::meta::identifier_of(mem)); + + // Only extract this field if it's in our list of requested fields + if constexpr (should_extract(key)) { + // Try to find and extract the field + if constexpr (concepts::optional_type) { + // For optional fields, it's ok if they're missing + auto field_result = find_field_unordered(key); + if (!field_result.error()) { + auto error = field_result.get(out.[:mem:]); + if (error && error != NO_SUCH_FIELD) { + return error; + } + } else if (field_result.error() != NO_SUCH_FIELD) { + return field_result.error(); + } else { + out.[:mem:].reset(); + } + } else { + // For required fields (in the requested list), fail if missing + SIMDJSON_TRY((*this)[key].get(out.[:mem:])); + } + } + } + }; + + return SUCCESS; +} + +#endif // SIMDJSON_SUPPORTS_CONCEPTS && SIMDJSON_STATIC_REFLECTION + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +simdjson_inline simdjson_result::simdjson_result(rvv_vls::ondemand::object &&value) noexcept + : implementation_simdjson_result_base(std::forward(value)) {} +simdjson_inline simdjson_result::simdjson_result(error_code error) noexcept + : implementation_simdjson_result_base(error) {} + +simdjson_inline simdjson_result simdjson_result::begin() noexcept { + if (error()) { return error(); } + return first.begin(); +} +simdjson_inline simdjson_result simdjson_result::end() noexcept { + if (error()) { return error(); } + return first.end(); +} +simdjson_inline simdjson_result simdjson_result::find_field_unordered(std::string_view key) & noexcept { + if (error()) { return error(); } + return first.find_field_unordered(key); +} +simdjson_inline simdjson_result simdjson_result::find_field_unordered(std::string_view key) && noexcept { + if (error()) { return error(); } + return std::forward(first).find_field_unordered(key); +} +simdjson_inline simdjson_result simdjson_result::operator[](std::string_view key) & noexcept { + if (error()) { return error(); } + return first[key]; +} +simdjson_inline simdjson_result simdjson_result::operator[](std::string_view key) && noexcept { + if (error()) { return error(); } + return std::forward(first)[key]; +} +simdjson_inline simdjson_result simdjson_result::find_field(std::string_view key) & noexcept { + if (error()) { return error(); } + return first.find_field(key); +} +simdjson_inline simdjson_result simdjson_result::find_field(std::string_view key) && noexcept { + if (error()) { return error(); } + return std::forward(first).find_field(key); +} + +simdjson_inline simdjson_result simdjson_result::at_pointer(std::string_view json_pointer) noexcept { + if (error()) { return error(); } + return first.at_pointer(json_pointer); +} + +simdjson_inline simdjson_result simdjson_result::at_path( + std::string_view json_path) noexcept { + if (error()) { + return error(); + } + return first.at_path(json_path); +} + +simdjson_inline simdjson_result> simdjson_result::at_path_with_wildcard(std::string_view json_path) noexcept { + if (error()) { return error(); } + return first.at_path_with_wildcard(json_path); +} + +inline simdjson_result simdjson_result::reset() noexcept { + if (error()) { return error(); } + return first.reset(); +} + +inline simdjson_result simdjson_result::is_empty() noexcept { + if (error()) { return error(); } + return first.is_empty(); +} + +simdjson_inline simdjson_result simdjson_result::count_fields() & noexcept { + if (error()) { return error(); } + return first.count_fields(); +} + +simdjson_inline simdjson_result simdjson_result::raw_json() noexcept { + if (error()) { return error(); } + return first.raw_json(); +} + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H +/* end file simdjson/generic/ondemand/object-inl.h for rvv_vls */ +/* including simdjson/generic/ondemand/object_iterator-inl.h for rvv_vls: #include "simdjson/generic/ondemand/object_iterator-inl.h" */ +/* begin file simdjson/generic/ondemand/object_iterator-inl.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object_iterator.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/field-inl.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator-inl.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +// +// object_iterator +// + +simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept + : iter{_iter} +{} + +simdjson_inline simdjson_result object_iterator::operator*() noexcept { +#if SIMDJSON_DEVELOPMENT_CHECKS + // We must call * once per iteration. + SIMDJSON_ASSUME(!has_been_referenced); + has_been_referenced = true; +#endif + error_code error = iter.error(); + if (error) { iter.abandon(); return error; } + auto result = field::start(iter); + // TODO this is a safety rail ... users should exit loops as soon as they receive an error. + // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free. + if (result.error()) { iter.abandon(); } + return result; +} +simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept { + return !(*this != other); +} +simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept { + return iter.is_open(); +} + +SIMDJSON_PUSH_DISABLE_WARNINGS +SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING +simdjson_inline object_iterator &object_iterator::operator++() noexcept { +#if SIMDJSON_DEVELOPMENT_CHECKS + // Before calling ++, we must have called *. + SIMDJSON_ASSUME(has_been_referenced); + has_been_referenced = false; +#endif + // TODO this is a safety rail ... users should exit loops as soon as they receive an error. + // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free. + if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error + + simdjson_unused error_code error; + if ((error = iter.skip_child() )) { return *this; } + + simdjson_unused bool has_value; + if ((error = iter.has_next_field().get(has_value) )) { return *this; }; + return *this; +} +SIMDJSON_POP_DISABLE_WARNINGS + +// +// ### Live States +// +// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is +// always SUCCESS: +// +// - Start: This is the state when the object is first found and the iterator is just past the {. +// In this state, at_start == true. +// - Next: After we hand a scalar value to the user, or an array/object which they then fully +// iterate over, the iterator is at the , or } before the next value. In this state, +// depth == iter.depth, at_start == false, and error == SUCCESS. +// - Unfinished Business: When we hand an array/object to the user which they do not fully +// iterate over, we need to finish that iteration by skipping child values until we reach the +// Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS. +// +// ## Error States +// +// In error states, we will yield exactly one more value before stopping. iter.depth == depth +// and at_start is always false. We decrement after yielding the error, moving to the Finished +// state. +// +// - Chained Error: When the object iterator is part of an error chain--for example, in +// `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an +// object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and +// iter.depth == depth, and at_start == false. We decrement depth when we yield the error. +// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields, +// we flag that as an error and treat it exactly the same as a Chained Error. In this state, +// error == TAPE_ERROR, iter.depth == depth, and at_start == false. +// +// Errors that occur while reading a field to give to the user (such as when the key is not a +// string or the field is missing a colon) are yielded immediately. Depth is then decremented, +// moving to the Finished state without transitioning through an Error state at all. +// +// ## Terminal State +// +// The terminal state has iter.depth < depth. at_start is always false. +// +// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth. +// In this state, iter.depth < depth, at_start == false, and error == SUCCESS. +// + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +simdjson_inline simdjson_result::simdjson_result( + rvv_vls::ondemand::object_iterator &&value +) noexcept + : implementation_simdjson_result_base(std::forward(value)) +{ + first.iter.assert_is_valid(); +} +simdjson_inline simdjson_result::simdjson_result(error_code error) noexcept + : implementation_simdjson_result_base({}, error) +{ +} + +simdjson_inline simdjson_result simdjson_result::operator*() noexcept { + if (error()) { return error(); } + return *first; +} +// If we're iterating and there is an error, return the error once. +simdjson_inline bool simdjson_result::operator==(const simdjson_result &other) const noexcept { + if (!first.iter.is_valid()) { return !error(); } + return first == other.first; +} +// If we're iterating and there is an error, return the error once. +simdjson_inline bool simdjson_result::operator!=(const simdjson_result &other) const noexcept { + if (!first.iter.is_valid()) { return error(); } + return first != other.first; +} +// Checks for ']' and ',' +simdjson_inline simdjson_result &simdjson_result::operator++() noexcept { + // Clear the error if there is one, so we don't yield it twice + if (error()) { second = SUCCESS; return *this; } + ++first; + return *this; +} + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_ITERATOR_INL_H +/* end file simdjson/generic/ondemand/object_iterator-inl.h for rvv_vls */ +/* including simdjson/generic/ondemand/parser-inl.h for rvv_vls: #include "simdjson/generic/ondemand/parser-inl.h" */ +/* begin file simdjson/generic/ondemand/parser-inl.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H */ +/* amalgamation skipped (editor-only): #include "simdjson/padded_string.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/padded_string_view.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/internal/dom_parser_implementation.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document_stream.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/parser.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +simdjson_inline parser::parser(size_t max_capacity) noexcept + : _max_capacity{max_capacity} { +} + +simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept { + if (new_capacity > max_capacity()) { return CAPACITY; } + if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; } + + // string_capacity copied from document::allocate + _capacity = 0; + size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64); + string_buf.reset(new (std::nothrow) uint8_t[string_capacity]); +#if SIMDJSON_DEVELOPMENT_CHECKS + start_positions.reset(new (std::nothrow) token_position[new_max_depth]); +#endif + if (implementation) { + SIMDJSON_TRY( implementation->set_capacity(new_capacity) ); + SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) ); + } else { + SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) ); + } + _capacity = new_capacity; + _max_depth = new_max_depth; + return SUCCESS; +} +#if SIMDJSON_DEVELOPMENT_CHECKS +simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept { + return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity()); +} +#endif + +simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(padded_string_view json) & noexcept { + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } + + json.remove_utf8_bom(); + + // Allocate if needed + if (capacity() < json.length() || !string_buf) { + SIMDJSON_TRY( allocate(json.length(), max_depth()) ); + } + + // Run stage 1. + SIMDJSON_TRY( implementation->stage1(reinterpret_cast(json.data()), json.length(), stage1_mode::regular) ); + return document::start({ reinterpret_cast(json.data()), this }); +} + +#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON +simdjson_warn_unused simdjson_inline simdjson_result parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept { + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } + + json.remove_utf8_bom(); + + // Allocate if needed + if (capacity() < json.length() || !string_buf) { + SIMDJSON_TRY( allocate(json.length(), max_depth()) ); + } + + // Run stage 1. + const simdjson::error_code err = implementation->stage1(reinterpret_cast(json.data()), json.length(), stage1_mode::regular); + if (err) { + if (err != UNCLOSED_STRING) + return err; + } + return document::start({ reinterpret_cast(json.data()), this, true }); +} +#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON + +simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(const char *json, size_t len, size_t allocated) & noexcept { + return iterate(padded_string_view(json, len, allocated)); +} + +simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept { + return iterate(padded_string_view(json, len, allocated)); +} + +simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(std::string_view json, size_t allocated) & noexcept { + return iterate(padded_string_view(json, allocated)); +} + +simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(std::string &json) & noexcept { + return iterate(pad_with_reserve(json)); +} + +simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(const std::string &json) & noexcept { + return iterate(padded_string_view(json)); +} + +simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(const simdjson_result &result) & noexcept { + // We don't presently have a way to temporarily get a const T& from a simdjson_result without throwing an exception + SIMDJSON_TRY( result.error() ); + padded_string_view json = result.value_unsafe(); + return iterate(json); +} + +simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(const simdjson_result &result) & noexcept { + // We don't presently have a way to temporarily get a const T& from a simdjson_result without throwing an exception + SIMDJSON_TRY( result.error() ); + const padded_string &json = result.value_unsafe(); + return iterate(json); +} + +simdjson_warn_unused simdjson_inline simdjson_result parser::iterate_raw(padded_string_view json) & noexcept { + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } + + json.remove_utf8_bom(); + + // Allocate if needed + if (capacity() < json.length()) { + SIMDJSON_TRY( allocate(json.length(), max_depth()) ); + } + + // Run stage 1. + SIMDJSON_TRY( implementation->stage1(reinterpret_cast(json.data()), json.length(), stage1_mode::regular) ); + return json_iterator(reinterpret_cast(json.data()), this); +} + +inline simdjson_result parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept { + // Warning: no check is done on the buffer padding. We trust the user. + if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; } + if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) { + buf += 3; + len -= 3; + } + if(allow_comma_separated && batch_size < len) { batch_size = len; } + return document_stream(*this, buf, len, batch_size, allow_comma_separated); +} + +inline simdjson_result parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept { + // Warning: no check is done on the buffer padding. We trust the user. + return iterate_many(reinterpret_cast(buf), len, batch_size, allow_comma_separated); +} +inline simdjson_result parser::iterate_many(padded_string_view s, size_t batch_size, bool allow_comma_separated) noexcept { + if (!s.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } + return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated); +} +inline simdjson_result parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept { + return iterate_many(padded_string_view(s), batch_size, allow_comma_separated); +} +inline simdjson_result parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept { + return iterate_many(padded_string_view(s), batch_size, allow_comma_separated); +} +inline simdjson_result parser::iterate_many(std::string &s, size_t batch_size, bool allow_comma_separated) noexcept { + return iterate_many(pad(s), batch_size, allow_comma_separated); +} +simdjson_pure simdjson_inline size_t parser::capacity() const noexcept { + return _capacity; +} +simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept { + return _max_capacity; +} +simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept { + return _max_depth; +} + +simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept { + if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) { + _max_capacity = max_capacity; + } else { + _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY; + } +} + +simdjson_inline simdjson_warn_unused simdjson_result parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept { + uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement); + if (!end) { return STRING_ERROR; } + std::string_view result(reinterpret_cast(dst), end-dst); + dst = end; + return result; +} + +simdjson_inline simdjson_warn_unused simdjson_result parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept { + uint8_t *end = implementation->parse_wobbly_string(in.buf, dst); + if (!end) { return STRING_ERROR; } + std::string_view result(reinterpret_cast(dst), end-dst); + dst = end; + return result; +} + +simdjson_inline simdjson_warn_unused ondemand::parser& parser::get_parser() { + return *parser::get_parser_instance(); +} + +simdjson_inline bool release_parser() { + auto &parser_instance = parser::get_threadlocal_parser_if_exists(); + if (parser_instance) { + parser_instance.reset(); + return true; + } + return false; +} + +simdjson_inline simdjson_warn_unused std::unique_ptr& parser::get_parser_instance() { + std::unique_ptr& parser_instance = get_threadlocal_parser_if_exists(); + if (!parser_instance) { + parser_instance.reset(new ondemand::parser()); + } + return parser_instance; +} + +simdjson_inline simdjson_warn_unused std::unique_ptr& parser::get_threadlocal_parser_if_exists() { + // @the-moisrex points out that this could be implemented with std::optional (C++17). + thread_local std::unique_ptr parser_instance = nullptr; + return parser_instance; +} + + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +simdjson_inline simdjson_result::simdjson_result(rvv_vls::ondemand::parser &&value) noexcept + : implementation_simdjson_result_base(std::forward(value)) {} +simdjson_inline simdjson_result::simdjson_result(error_code error) noexcept + : implementation_simdjson_result_base(error) {} + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H +/* end file simdjson/generic/ondemand/parser-inl.h for rvv_vls */ +/* including simdjson/generic/ondemand/raw_json_string-inl.h for rvv_vls: #include "simdjson/generic/ondemand/raw_json_string-inl.h" */ +/* begin file simdjson/generic/ondemand/raw_json_string-inl.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator-inl.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { + +namespace rvv_vls { +namespace ondemand { + +simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {} + +simdjson_inline const char * raw_json_string::raw() const noexcept { + return reinterpret_cast(buf); +} + +simdjson_inline char raw_json_string::operator[](size_t i) const noexcept { + return reinterpret_cast(buf)[i]; +} + +simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept { + size_t pos{0}; + while(pos < target.size()) { + pos = target.find('"', pos); + if(pos == std::string_view::npos) { return true; } + if(pos != 0 && target[pos-1] != '\\') { return false; } + if(pos > 1 && target[pos-2] == '\\') { + size_t backslash_count{2}; + for(size_t i = 3; i <= pos; i++) { + if(target[pos-i] == '\\') { backslash_count++; } + else { break; } + } + if(backslash_count % 2 == 0) { return false; } + } + pos++; + } + return true; +} + +simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept { + size_t pos{0}; + while(target[pos]) { + const char * result = strchr(target+pos, '"'); + if(result == nullptr) { return true; } + pos = result - target; + if(pos != 0 && target[pos-1] != '\\') { return false; } + if(pos > 1 && target[pos-2] == '\\') { + size_t backslash_count{2}; + for(size_t i = 3; i <= pos; i++) { + if(target[pos-i] == '\\') { backslash_count++; } + else { break; } + } + if(backslash_count % 2 == 0) { return false; } + } + pos++; + } + return true; +} + + +simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept { + // If we are going to call memcmp, then we must know something about the length of the raw_json_string. + return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size()); +} + +simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept { + // Assumptions: does not contain unescaped quote characters("), and + // the raw content is quote terminated within a valid JSON string. + if(target.size() <= SIMDJSON_PADDING) { + return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size()); + } + const char * r{raw()}; + size_t pos{0}; + for(;pos < target.size();pos++) { + if(r[pos] != target[pos]) { return false; } + } + if(r[pos] != '"') { return false; } + return true; +} + +simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept { + const char * r{raw()}; + size_t pos{0}; + bool escaping{false}; + for(;pos < target.size();pos++) { + if(r[pos] != target[pos]) { return false; } + // if target is a compile-time constant and it is free from + // quotes, then the next part could get optimized away through + // inlining. + if((target[pos] == '"') && !escaping) { + // We have reached the end of the raw_json_string but + // the target is not done. + return false; + } else if(target[pos] == '\\') { + escaping = !escaping; + } else { + escaping = false; + } + } + if(r[pos] != '"') { return false; } + return true; +} + + +simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept { + // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and + // the raw content is quote terminated within a valid JSON string. + const char * r{raw()}; + size_t pos{0}; + for(;target[pos];pos++) { + if(r[pos] != target[pos]) { return false; } + } + if(r[pos] != '"') { return false; } + return true; +} + +simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept { + // Assumptions: does not contain unescaped quote characters, and + // the raw content is quote terminated within a valid JSON string. + const char * r{raw()}; + size_t pos{0}; + bool escaping{false}; + for(;target[pos];pos++) { + if(r[pos] != target[pos]) { return false; } + // if target is a compile-time constant and it is free from + // quotes, then the next part could get optimized away through + // inlining. + if((target[pos] == '"') && !escaping) { + // We have reached the end of the raw_json_string but + // the target is not done. + return false; + } else if(target[pos] == '\\') { + escaping = !escaping; + } else { + escaping = false; + } + } + if(r[pos] != '"') { return false; } + return true; +} + +simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept { + return a.unsafe_is_equal(c); +} + +simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept { + return a == c; +} + +simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept { + return !(a == c); +} + +simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept { + return !(a == c); +} + + +simdjson_inline simdjson_warn_unused simdjson_result raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept { + return iter.unescape(*this, allow_replacement); +} + +simdjson_inline simdjson_warn_unused simdjson_result raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept { + return iter.unescape_wobbly(*this); +} + +simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept { + bool in_escape = false; + const char *s = str.raw(); + while (true) { + switch (*s) { + case '\\': in_escape = !in_escape; break; + case '"': if (in_escape) { in_escape = false; } else { return out; } break; + default: if (in_escape) { in_escape = false; } + } + out << *s; + s++; + } +} + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +simdjson_inline simdjson_result::simdjson_result(rvv_vls::ondemand::raw_json_string &&value) noexcept + : implementation_simdjson_result_base(std::forward(value)) {} +simdjson_inline simdjson_result::simdjson_result(error_code error) noexcept + : implementation_simdjson_result_base(error) {} + +simdjson_inline simdjson_result simdjson_result::raw() const noexcept { + if (error()) { return error(); } + return first.raw(); +} +simdjson_inline char simdjson_result::operator[](size_t i) const noexcept { + if (error()) { return error(); } + return first[i]; +} +simdjson_inline simdjson_warn_unused simdjson_result simdjson_result::unescape(rvv_vls::ondemand::json_iterator &iter, bool allow_replacement) const noexcept { + if (error()) { return error(); } + return first.unescape(iter, allow_replacement); +} +simdjson_inline simdjson_warn_unused simdjson_result simdjson_result::unescape_wobbly(rvv_vls::ondemand::json_iterator &iter) const noexcept { + if (error()) { return error(); } + return first.unescape_wobbly(iter); +} +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H +/* end file simdjson/generic/ondemand/raw_json_string-inl.h for rvv_vls */ +/* including simdjson/generic/ondemand/token_iterator-inl.h for rvv_vls: #include "simdjson/generic/ondemand/token_iterator-inl.h" */ +/* begin file simdjson/generic/ondemand/token_iterator-inl.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/token_iterator.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/implementation_simdjson_result_base-inl.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +simdjson_inline token_iterator::token_iterator( + const uint8_t *_buf, + token_position position +) noexcept : buf{_buf}, _position{position} +{ +} + +simdjson_inline uint32_t token_iterator::current_offset() const noexcept { + return *(_position); +} + + +simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept { + return &buf[*(_position++)]; +} + +simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept { + return &buf[*position]; +} +simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept { + return *position; +} +simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept { + return *(position+1) - *position; +} + +simdjson_inline uint32_t token_iterator::peek_root_length(token_position position) const noexcept { + return *(position+2) - *(position) > *(position+1) - *(position) ? + *(position+1) - *(position) + : *(position+2) - *(position); +} +simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept { + return &buf[*(_position+delta)]; +} +simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept { + return *(_position+delta); +} +simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept { + return *(_position+delta+1) - *(_position+delta); +} + +simdjson_inline token_position token_iterator::position() const noexcept { + return _position; +} +simdjson_inline void token_iterator::set_position(token_position target_position) noexcept { + _position = target_position; +} + +simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept { + return _position == other._position; +} +simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept { + return _position != other._position; +} +simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept { + return _position > other._position; +} +simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept { + return _position >= other._position; +} +simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept { + return _position < other._position; +} +simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept { + return _position <= other._position; +} + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +simdjson_inline simdjson_result::simdjson_result(rvv_vls::ondemand::token_iterator &&value) noexcept + : implementation_simdjson_result_base(std::forward(value)) {} +simdjson_inline simdjson_result::simdjson_result(error_code error) noexcept + : implementation_simdjson_result_base(error) {} + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_TOKEN_ITERATOR_INL_H +/* end file simdjson/generic/ondemand/token_iterator-inl.h for rvv_vls */ +/* including simdjson/generic/ondemand/value_iterator-inl.h for rvv_vls: #include "simdjson/generic/ondemand/value_iterator-inl.h" */ +/* begin file simdjson/generic/ondemand/value_iterator-inl.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/atomparsing.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/numberparsing.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_iterator.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value_iterator.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type-inl.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/raw_json_string-inl.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { + +simdjson_inline value_iterator::value_iterator( + json_iterator *json_iter, + depth_t depth, + token_position start_position +) noexcept : _json_iter{json_iter}, _depth{depth}, _start_position{start_position} +{ +} + +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::start_object() noexcept { + SIMDJSON_TRY( start_container('{', "Not an object", "object") ); + return started_object(); +} + +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::start_root_object() noexcept { + SIMDJSON_TRY( start_container('{', "Not an object", "object") ); + return started_root_object(); +} + +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::started_object() noexcept { + assert_at_container_start(); +#if SIMDJSON_DEVELOPMENT_CHECKS + _json_iter->set_start_position(_depth, start_position()); +#endif + if (*_json_iter->peek() == '}') { + logger::log_value(*_json_iter, "empty object"); + _json_iter->return_current_and_advance(); + SIMDJSON_TRY(end_container()); + return false; + } + return true; +} + +simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_object() noexcept { + // When in streaming mode, we cannot expect peek_last() to be the last structural element of the + // current document. It only works in the normal mode where we have indexed a single document. + // Note that adding a check for 'streaming' is not expensive since we only have at most + // one root element. + if ( ! _json_iter->streaming() ) { + // The following lines do not fully protect against garbage content within the + // object: e.g., `{"a":2} foo }`. Users concerned with garbage content should + // call `at_end()` on the document instance at the end of the processing to + // ensure that the processing has finished at the end. + // + if (*_json_iter->peek_last() != '}') { + _json_iter->abandon(); + return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end"); + } + // If the last character is } *and* the first gibberish character is also '}' + // then on-demand could accidentally go over. So we need additional checks. + // https://github.com/simdjson/simdjson/issues/1834 + // Checking that the document is balanced requires a full scan which is potentially + // expensive, but it only happens in edge cases where the first padding character is + // a closing bracket. + if ((*_json_iter->peek(_json_iter->end_position()) == '}') && (!_json_iter->balanced())) { + _json_iter->abandon(); + // The exact error would require more work. It will typically be an unclosed object. + return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced"); + } + } + return SUCCESS; +} + +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::started_root_object() noexcept { + auto error = check_root_object(); + if(error) { return error; } + return started_object(); +} + +simdjson_warn_unused simdjson_inline error_code value_iterator::end_container() noexcept { +#if SIMDJSON_CHECK_EOF + if (depth() > 1 && at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing parent ] or }"); } + // if (depth() <= 1 && !at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing [ or { at start"); } +#endif // SIMDJSON_CHECK_EOF + _json_iter->ascend_to(depth()-1); + return SUCCESS; +} + +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::has_next_field() noexcept { + assert_at_next(); + // It's illegal to call this unless there are more tokens: anything that ends in } or ] is + // obligated to verify there are more tokens if they are not the top level. + switch (*_json_iter->return_current_and_advance()) { + case '}': + logger::log_end_value(*_json_iter, "object"); + SIMDJSON_TRY( end_container() ); + return false; + case ',': + return true; + default: + return report_error(TAPE_ERROR, "Missing comma between object fields"); + } +} + +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::find_field_raw(const std::string_view key) noexcept { + error_code error; + bool has_value; + // + // Initially, the object can be in one of a few different places: + // + // 1. The start of the object, at the first field: + // + // ``` + // { "a": [ 1, 2 ], "b": [ 3, 4 ] } + // ^ (depth 2, index 1) + // ``` + if (at_first_field()) { + has_value = true; + + // + // 2. When a previous search did not yield a value or the object is empty: + // + // ``` + // { "a": [ 1, 2 ], "b": [ 3, 4 ] } + // ^ (depth 0) + // { } + // ^ (depth 0, index 2) + // ``` + // + } else if (!is_open()) { +#if SIMDJSON_DEVELOPMENT_CHECKS + // If we're past the end of the object, we're being iterated out of order. + // Note: this is not perfect detection. It's possible the user is inside some other object; if so, + // this object iterator will blithely scan that object for fields. + if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; } +#endif + return false; + + // 3. When a previous search found a field or an iterator yielded a value: + // + // ``` + // // When a field was not fully consumed (or not even touched at all) + // { "a": [ 1, 2 ], "b": [ 3, 4 ] } + // ^ (depth 2) + // // When a field was fully consumed + // { "a": [ 1, 2 ], "b": [ 3, 4 ] } + // ^ (depth 1) + // // When the last field was fully consumed + // { "a": [ 1, 2 ], "b": [ 3, 4 ] } + // ^ (depth 1) + // ``` + // + } else { + if ((error = skip_child() )) { abandon(); return error; } + if ((error = has_next_field().get(has_value) )) { abandon(); return error; } +#if SIMDJSON_DEVELOPMENT_CHECKS + if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; } +#endif + } + while (has_value) { + // Get the key and colon, stopping at the value. + raw_json_string actual_key; + // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes + // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2. + // field_key() advances the pointer and checks that '"' is found (corresponding to a key). + // The depth is left unchanged by field_key(). + if ((error = field_key().get(actual_key) )) { abandon(); return error; }; + // field_value() will advance and check that we find a ':' separating the + // key and the value. It will also increment the depth by one. + if ((error = field_value() )) { abandon(); return error; } + // If it matches, stop and return + // We could do it this way if we wanted to allow arbitrary + // key content (including escaped quotes). + //if (actual_key.unsafe_is_equal(max_key_length, key)) { + // Instead we do the following which may trigger buffer overruns if the + // user provides an adversarial key (containing a well placed unescaped quote + // character and being longer than the number of bytes remaining in the JSON + // input). + if (actual_key.unsafe_is_equal(key)) { + logger::log_event(*this, "match", key, -2); + // If we return here, then we return while pointing at the ':' that we just checked. + return true; + } + + // No match: skip the value and see if , or } is next + logger::log_event(*this, "no match", key, -2); + // The call to skip_child is meant to skip over the value corresponding to the key. + // After skip_child(), we are right before the next comma (',') or the final brace ('}'). + SIMDJSON_TRY( skip_child() ); // Skip the value entirely + // The has_next_field() advances the pointer and check that either ',' or '}' is found. + // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found, + // then we are in error and we abort. + if ((error = has_next_field().get(has_value) )) { abandon(); return error; } + } + + // If the loop ended, we're out of fields to look at. + return false; +} + +SIMDJSON_PUSH_DISABLE_WARNINGS +SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::find_field_unordered_raw(const std::string_view key) noexcept { + /** + * When find_field_unordered_raw is called, we can either be pointing at the + * first key, pointing outside (at the closing brace) or if a key was matched + * we can be either pointing right afterthe ':' right before the value (that we need skip), + * or we may have consumed the value and we might be at a comma or at the + * final brace (ready for a call to has_next_field()). + */ + error_code error; + bool has_value; + + // First, we scan from that point to the end. + // If we don't find a match, we may loop back around, and scan from the beginning to that point. + token_position search_start = _json_iter->position(); + + // We want to know whether we need to go back to the beginning. + bool at_first = at_first_field(); + /////////////// + // Initially, the object can be in one of a few different places: + // + // 1. At the first key: + // + // ``` + // { "a": [ 1, 2 ], "b": [ 3, 4 ] } + // ^ (depth 2, index 1) + // ``` + // + if (at_first) { + has_value = true; + + // 2. When a previous search did not yield a value or the object is empty: + // + // ``` + // { "a": [ 1, 2 ], "b": [ 3, 4 ] } + // ^ (depth 0) + // { } + // ^ (depth 0, index 2) + // ``` + // + } else if (!is_open()) { + +#if SIMDJSON_DEVELOPMENT_CHECKS + // If we're past the end of the object, we're being iterated out of order. + // Note: this is not perfect detection. It's possible the user is inside some other object; if so, + // this object iterator will blithely scan that object for fields. + if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; } +#endif + SIMDJSON_TRY(reset_object().get(has_value)); + at_first = true; + // 3. When a previous search found a field or an iterator yielded a value: + // + // ``` + // // When a field was not fully consumed (or not even touched at all) + // { "a": [ 1, 2 ], "b": [ 3, 4 ] } + // ^ (depth 2) + // // When a field was fully consumed + // { "a": [ 1, 2 ], "b": [ 3, 4 ] } + // ^ (depth 1) + // // When the last field was fully consumed + // { "a": [ 1, 2 ], "b": [ 3, 4 ] } + // ^ (depth 1) + // ``` + // + } else { + // If someone queried a key but they not did access the value, then we are left pointing + // at the ':' and we need to move forward through the value... If the value was + // processed then skip_child() does not move the iterator (but may adjust the depth). + if ((error = skip_child() )) { abandon(); return error; } + search_start = _json_iter->position(); + if ((error = has_next_field().get(has_value) )) { abandon(); return error; } +#if SIMDJSON_DEVELOPMENT_CHECKS + if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; } +#endif + } + + // After initial processing, we will be in one of two states: + // + // ``` + // // At the beginning of a field + // { "a": [ 1, 2 ], "b": [ 3, 4 ] } + // ^ (depth 1) + // { "a": [ 1, 2 ], "b": [ 3, 4 ] } + // ^ (depth 1) + // // At the end of the object + // { "a": [ 1, 2 ], "b": [ 3, 4 ] } + // ^ (depth 0) + // ``` + // + // Next, we find a match starting from the current position. + while (has_value) { + SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field + + // Get the key and colon, stopping at the value. + raw_json_string actual_key; + // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes + // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2. + // field_key() advances the pointer and checks that '"' is found (corresponding to a key). + // The depth is left unchanged by field_key(). + if ((error = field_key().get(actual_key) )) { abandon(); return error; }; + // field_value() will advance and check that we find a ':' separating the + // key and the value. It will also increment the depth by one. + if ((error = field_value() )) { abandon(); return error; } + + // If it matches, stop and return + // We could do it this way if we wanted to allow arbitrary + // key content (including escaped quotes). + // if (actual_key.unsafe_is_equal(max_key_length, key)) { + // Instead we do the following which may trigger buffer overruns if the + // user provides an adversarial key (containing a well placed unescaped quote + // character and being longer than the number of bytes remaining in the JSON + // input). + if (actual_key.unsafe_is_equal(key)) { + logger::log_event(*this, "match", key, -2); + // If we return here, then we return while pointing at the ':' that we just checked. + return true; + } + + // No match: skip the value and see if , or } is next + logger::log_event(*this, "no match", key, -2); + // The call to skip_child is meant to skip over the value corresponding to the key. + // After skip_child(), we are right before the next comma (',') or the final brace ('}'). + SIMDJSON_TRY( skip_child() ); + // The has_next_field() advances the pointer and check that either ',' or '}' is found. + // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found, + // then we are in error and we abort. + if ((error = has_next_field().get(has_value) )) { abandon(); return error; } + } + // Performance note: it maybe wasteful to rewind to the beginning when there might be + // no other query following. Indeed, it would require reskipping the whole object. + // Instead, you can just stay where you are. If there is a new query, there is always time + // to rewind. + if(at_first) { return false; } + + // If we reach the end without finding a match, search the rest of the fields starting at the + // beginning of the object. + // (We have already run through the object before, so we've already validated its structure. We + // don't check errors in this bit.) + SIMDJSON_TRY(reset_object().get(has_value)); + while (true) { + SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object + SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field + + // Get the key and colon, stopping at the value. + raw_json_string actual_key; + // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes + // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2. + // field_key() advances the pointer and checks that '"' is found (corresponding to a key). + // The depth is left unchanged by field_key(). + error = field_key().get(actual_key); SIMDJSON_ASSUME(!error); + // field_value() will advance and check that we find a ':' separating the + // key and the value. It will also increment the depth by one. + error = field_value(); SIMDJSON_ASSUME(!error); + + // If it matches, stop and return + // We could do it this way if we wanted to allow arbitrary + // key content (including escaped quotes). + // if (actual_key.unsafe_is_equal(max_key_length, key)) { + // Instead we do the following which may trigger buffer overruns if the + // user provides an adversarial key (containing a well placed unescaped quote + // character and being longer than the number of bytes remaining in the JSON + // input). + if (actual_key.unsafe_is_equal(key)) { + logger::log_event(*this, "match", key, -2); + // If we return here, then we return while pointing at the ':' that we just checked. + return true; + } + + // No match: skip the value and see if , or } is next + logger::log_event(*this, "no match", key, -2); + // The call to skip_child is meant to skip over the value corresponding to the key. + // After skip_child(), we are right before the next comma (',') or the final brace ('}'). + SIMDJSON_TRY( skip_child() ); + // If we reached the end of the key-value pair we started from, then we know + // that the key is not there so we return false. We are either right before + // the next comma or the final brace. + if(_json_iter->position() == search_start) { return false; } + // The has_next_field() advances the pointer and check that either ',' or '}' is found. + // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found, + // then we are in error and we abort. + error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error); + // If we make the mistake of exiting here, then we could be left pointing at a key + // in the middle of an object. That's not an allowable state. + } + // If the loop ended, we're out of fields to look at. The program should + // never reach this point. + return false; +} +SIMDJSON_POP_DISABLE_WARNINGS + +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::field_key() noexcept { + assert_at_next(); + + const uint8_t *key = _json_iter->return_current_and_advance(); + if (*(key++) != '"') { return report_error(TAPE_ERROR, "Object key is not a string"); } + return raw_json_string(key); +} + +simdjson_warn_unused simdjson_inline error_code value_iterator::field_value() noexcept { + assert_at_next(); + + if (*_json_iter->return_current_and_advance() != ':') { return report_error(TAPE_ERROR, "Missing colon in object field"); } + _json_iter->descend_to(depth()+1); + return SUCCESS; +} + +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::start_array() noexcept { + SIMDJSON_TRY( start_container('[', "Not an array", "array") ); + return started_array(); +} + +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::start_root_array() noexcept { + SIMDJSON_TRY( start_container('[', "Not an array", "array") ); + return started_root_array(); +} + +inline std::string value_iterator::to_string() const noexcept { + auto answer = std::string("value_iterator [ depth : ") + std::to_string(_depth) + std::string(", "); + if(_json_iter != nullptr) { answer += _json_iter->to_string(); } + answer += std::string(" ]"); + return answer; +} + +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::started_array() noexcept { + assert_at_container_start(); + if (*_json_iter->peek() == ']') { + logger::log_value(*_json_iter, "empty array"); + _json_iter->return_current_and_advance(); + SIMDJSON_TRY( end_container() ); + return false; + } + _json_iter->descend_to(depth()+1); +#if SIMDJSON_DEVELOPMENT_CHECKS + _json_iter->set_start_position(_depth, start_position()); +#endif + return true; +} + +simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_array() noexcept { + // When in streaming mode, we cannot expect peek_last() to be the last structural element of the + // current document. It only works in the normal mode where we have indexed a single document. + // Note that adding a check for 'streaming' is not expensive since we only have at most + // one root element. + if ( ! _json_iter->streaming() ) { + // The following lines do not fully protect against garbage content within the + // array: e.g., `[1, 2] foo]`. Users concerned with garbage content should + // also call `at_end()` on the document instance at the end of the processing to + // ensure that the processing has finished at the end. + // + if (*_json_iter->peek_last() != ']') { + _json_iter->abandon(); + return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end"); + } + // If the last character is ] *and* the first gibberish character is also ']' + // then on-demand could accidentally go over. So we need additional checks. + // https://github.com/simdjson/simdjson/issues/1834 + // Checking that the document is balanced requires a full scan which is potentially + // expensive, but it only happens in edge cases where the first padding character is + // a closing bracket. + if ((*_json_iter->peek(_json_iter->end_position()) == ']') && (!_json_iter->balanced())) { + _json_iter->abandon(); + // The exact error would require more work. It will typically be an unclosed array. + return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced"); + } + } + return SUCCESS; +} + +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::started_root_array() noexcept { + auto error = check_root_array(); + if (error) { return error; } + return started_array(); +} + +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::has_next_element() noexcept { + assert_at_next(); + + logger::log_event(*this, "has_next_element"); + switch (*_json_iter->return_current_and_advance()) { + case ']': + logger::log_end_value(*_json_iter, "array"); + SIMDJSON_TRY( end_container() ); + return false; + case ',': + _json_iter->descend_to(depth()+1); + return true; + default: + return report_error(TAPE_ERROR, "Missing comma between array elements"); + } +} + +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::parse_bool(const uint8_t *json) const noexcept { + auto not_true = atomparsing::str4ncmp(json, "true"); + auto not_false = atomparsing::str4ncmp(json, "fals") | (json[4] ^ 'e'); + bool error = (not_true && not_false) || jsoncharutils::is_not_structural_or_whitespace(json[not_true ? 5 : 4]); + if (error) { return incorrect_type_error("Not a boolean"); } + return simdjson_result(!not_true); +} +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::parse_null(const uint8_t *json) const noexcept { + bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]); + // if we start with 'n', we must be a null + if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); } + return is_null_string; +} + +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_string(bool allow_replacement) noexcept { + return get_raw_json_string().unescape(json_iter(), allow_replacement); +} +template +simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept { + std::string_view content; + // Save the string buffer location so that we can restore it after get_string + auto saved_string_buf_loc = _json_iter->string_buf_loc(); + auto err = get_string(allow_replacement).get(content); + if (err) { return err; } + receiver = content; + // Restore the string buffer location, effectively discarding any temporary string storage + _json_iter->string_buf_loc() = saved_string_buf_loc; + return SUCCESS; +} +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_wobbly_string() noexcept { + return get_raw_json_string().unescape_wobbly(json_iter()); +} +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_raw_json_string() noexcept { + auto json = peek_scalar("string"); + if (*json != '"') { return incorrect_type_error("Not a string"); } + advance_scalar("string"); + return raw_json_string(json+1); +} +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_uint64() noexcept { + auto result = numberparsing::parse_unsigned(peek_non_root_scalar("uint64")); + if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); } + return result; +} +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_uint64_in_string() noexcept { + auto result = numberparsing::parse_unsigned_in_string(peek_non_root_scalar("uint64")); + if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); } + return result; +} +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_int64() noexcept { + auto result = numberparsing::parse_integer(peek_non_root_scalar("int64")); + if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); } + return result; +} +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_int64_in_string() noexcept { + auto result = numberparsing::parse_integer_in_string(peek_non_root_scalar("int64")); + if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); } + return result; +} +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_double() noexcept { + auto result = numberparsing::parse_double(peek_non_root_scalar("double")); + if(result.error() == SUCCESS) { advance_non_root_scalar("double"); } + return result; +} +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_double_in_string() noexcept { + auto result = numberparsing::parse_double_in_string(peek_non_root_scalar("double")); + if(result.error() == SUCCESS) { advance_non_root_scalar("double"); } + return result; +} +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_bool() noexcept { + auto result = parse_bool(peek_non_root_scalar("bool")); + if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); } + return result; +} +simdjson_inline simdjson_result value_iterator::is_null() noexcept { + bool is_null_value; + SIMDJSON_TRY(parse_null(peek_non_root_scalar("null")).get(is_null_value)); + if(is_null_value) { advance_non_root_scalar("null"); } + return is_null_value; +} +simdjson_inline bool value_iterator::is_negative() noexcept { + return numberparsing::is_negative(peek_non_root_scalar("numbersign")); +} +simdjson_inline bool value_iterator::is_root_negative() noexcept { + return numberparsing::is_negative(peek_root_scalar("numbersign")); +} +simdjson_inline simdjson_result value_iterator::is_integer() noexcept { + return numberparsing::is_integer(peek_non_root_scalar("integer")); +} +simdjson_inline simdjson_result value_iterator::get_number_type() noexcept { + return numberparsing::get_number_type(peek_non_root_scalar("integer")); +} +simdjson_inline simdjson_result value_iterator::get_number() noexcept { + number num; + error_code error = numberparsing::parse_number(peek_non_root_scalar("number"), num); + if(error) { return error; } + return num; +} + +simdjson_inline simdjson_result value_iterator::is_root_integer(bool check_trailing) noexcept { + auto max_len = peek_root_length(); + auto json = peek_root_scalar("is_root_integer"); + uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer + tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated. + if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) { + return false; // if there are more than 20 characters, it cannot be represented as an integer. + } + auto answer = numberparsing::is_integer(tmpbuf); + // If the parsing was a success, we must still check that it is + // a single scalar. Note that we parse first because of cases like '[]' where + // getting TRAILING_CONTENT is wrong. + if(check_trailing && (answer.error() == SUCCESS) && (!_json_iter->is_single_token())) { return TRAILING_CONTENT; } + return answer; +} + +simdjson_inline simdjson_result value_iterator::get_root_number_type(bool check_trailing) noexcept { + auto max_len = peek_root_length(); + auto json = peek_root_scalar("number"); + // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/, + // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest + // number: -0.e-308. + uint8_t tmpbuf[1074+8+1+1]; + tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated. + if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) { + if(numberparsing::check_if_integer(json, max_len)) { + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + logger::log_error(*_json_iter, start_position(), depth(), "Found big integer"); + return number_type::big_integer; + } + logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer"); + return NUMBER_ERROR; + } + auto answer = numberparsing::get_number_type(tmpbuf); + if (check_trailing && (answer.error() == SUCCESS) && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + return answer; +} +simdjson_inline simdjson_result value_iterator::get_root_number(bool check_trailing) noexcept { + auto max_len = peek_root_length(); + auto json = peek_root_scalar("number"); + // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/, + // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest + // number: -0.e-308. + // NOTE: the current approach doesn't work for very big integer numbers containing more than 1074 digits. + uint8_t tmpbuf[1074+8+1+1]; + tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated. + if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) { + if(numberparsing::check_if_integer(json, max_len)) { + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + logger::log_error(*_json_iter, start_position(), depth(), "Found big integer"); + return BIGINT_ERROR; + } + logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer"); + return NUMBER_ERROR; + } + number num; + error_code error = numberparsing::parse_number(tmpbuf, num); + if(error) { return error; } + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("number"); + return num; +} +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_string(bool check_trailing, bool allow_replacement) noexcept { + return get_root_raw_json_string(check_trailing).unescape(json_iter(), allow_replacement); +} +template +simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept { + std::string_view content; + // Save the string buffer location so that we can restore it after get_string + auto saved_string_buf_loc = _json_iter->string_buf_loc(); + auto err = get_root_string(check_trailing, allow_replacement).get(content); + if (err) { return err; } + receiver = content; + // Restore the string buffer location, effectively discarding any temporary string storage + _json_iter->string_buf_loc() = saved_string_buf_loc; + return SUCCESS; +} +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_wobbly_string(bool check_trailing) noexcept { + return get_root_raw_json_string(check_trailing).unescape_wobbly(json_iter()); +} +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_raw_json_string(bool check_trailing) noexcept { + auto json = peek_scalar("string"); + if (*json != '"') { return incorrect_type_error("Not a string"); } + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_scalar("string"); + return raw_json_string(json+1); +} +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_uint64(bool check_trailing) noexcept { + auto max_len = peek_root_length(); + auto json = peek_root_scalar("uint64"); + uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer + tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated. + if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) { + logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters"); + return NUMBER_ERROR; + } + auto result = numberparsing::parse_unsigned(tmpbuf); + if(result.error() == SUCCESS) { + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("uint64"); + } + return result; +} +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_uint64_in_string(bool check_trailing) noexcept { + auto max_len = peek_root_length(); + auto json = peek_root_scalar("uint64"); + uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer + tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated. + if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) { + logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters"); + return NUMBER_ERROR; + } + auto result = numberparsing::parse_unsigned_in_string(tmpbuf); + if(result.error() == SUCCESS) { + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("uint64"); + } + return result; +} +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_int64(bool check_trailing) noexcept { + auto max_len = peek_root_length(); + auto json = peek_root_scalar("int64"); + uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer + tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated. + if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) { + logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters"); + return NUMBER_ERROR; + } + + auto result = numberparsing::parse_integer(tmpbuf); + if(result.error() == SUCCESS) { + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("int64"); + } + return result; +} +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_int64_in_string(bool check_trailing) noexcept { + auto max_len = peek_root_length(); + auto json = peek_root_scalar("int64"); + uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer + tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated. + if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) { + logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters"); + return NUMBER_ERROR; + } + + auto result = numberparsing::parse_integer_in_string(tmpbuf); + if(result.error() == SUCCESS) { + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("int64"); + } + return result; +} +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_double(bool check_trailing) noexcept { + auto max_len = peek_root_length(); + auto json = peek_root_scalar("double"); + // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/, + // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest + // number: -0.e-308. + uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination. + tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated. + if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) { + logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters"); + return NUMBER_ERROR; + } + auto result = numberparsing::parse_double(tmpbuf); + if(result.error() == SUCCESS) { + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("double"); + } + return result; +} + +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_double_in_string(bool check_trailing) noexcept { + auto max_len = peek_root_length(); + auto json = peek_root_scalar("double"); + // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/, + // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest + // number: -0.e-308. + uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination. + tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated. + if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) { + logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters"); + return NUMBER_ERROR; + } + auto result = numberparsing::parse_double_in_string(tmpbuf); + if(result.error() == SUCCESS) { + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("double"); + } + return result; +} + +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_root_bool(bool check_trailing) noexcept { + auto max_len = peek_root_length(); + auto json = peek_root_scalar("bool"); + // We have a boolean if we have either "true" or "false" and the next character is either + // a structural character or whitespace. We also check that the length is correct: + // "true" and "false" are 4 and 5 characters long, respectively. + bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") && + (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4]))); + bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") && + (max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5]))); + if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); } + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("bool"); + return value_true; +} + +simdjson_inline simdjson_result value_iterator::is_root_null(bool check_trailing) noexcept { + auto max_len = peek_root_length(); + auto json = peek_root_scalar("null"); + bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") && + (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4]))); + if(result) { // we have something that looks like a null. + if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } + advance_root_scalar("null"); + } else if (json[0] == 'n') { + return incorrect_type_error("Not a null but starts with n"); + } + return result; +} + +simdjson_warn_unused simdjson_inline error_code value_iterator::skip_child() noexcept { + SIMDJSON_ASSUME( _json_iter->token._position > _start_position ); + SIMDJSON_ASSUME( _json_iter->_depth >= _depth ); + + return _json_iter->skip_child(depth()); +} + +simdjson_inline value_iterator value_iterator::child() const noexcept { + assert_at_child(); + return { _json_iter, depth()+1, _json_iter->token.position() }; +} + +// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller +// relating depth and iterator depth, which is a desired effect. It does not happen if is_open is +// marked non-inline. +SIMDJSON_PUSH_DISABLE_WARNINGS +SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING +simdjson_inline bool value_iterator::is_open() const noexcept { + return _json_iter->depth() >= depth(); +} +SIMDJSON_POP_DISABLE_WARNINGS + +simdjson_inline bool value_iterator::at_end() const noexcept { + return _json_iter->at_end(); +} + +simdjson_inline bool value_iterator::at_start() const noexcept { + return _json_iter->token.position() == start_position(); +} + +simdjson_inline bool value_iterator::at_first_field() const noexcept { + SIMDJSON_ASSUME( _json_iter->token._position > _start_position ); + return _json_iter->token.position() == start_position() + 1; +} + +simdjson_inline void value_iterator::abandon() noexcept { + _json_iter->abandon(); +} + +simdjson_warn_unused simdjson_inline depth_t value_iterator::depth() const noexcept { + return _depth; +} +simdjson_warn_unused simdjson_inline error_code value_iterator::error() const noexcept { + return _json_iter->error; +} +simdjson_warn_unused simdjson_inline uint8_t *&value_iterator::string_buf_loc() noexcept { + return _json_iter->string_buf_loc(); +} +simdjson_warn_unused simdjson_inline const json_iterator &value_iterator::json_iter() const noexcept { + return *_json_iter; +} +simdjson_warn_unused simdjson_inline json_iterator &value_iterator::json_iter() noexcept { + return *_json_iter; +} + +simdjson_inline const uint8_t *value_iterator::peek_start() const noexcept { + return _json_iter->peek(start_position()); +} +simdjson_inline uint32_t value_iterator::peek_start_length() const noexcept { + return _json_iter->peek_length(start_position()); +} +simdjson_inline uint32_t value_iterator::peek_root_length() const noexcept { + return _json_iter->peek_root_length(start_position()); +} + +simdjson_inline const uint8_t *value_iterator::peek_scalar(const char *type) noexcept { + logger::log_value(*_json_iter, start_position(), depth(), type); + // If we're not at the position anymore, we don't want to advance the cursor. + if (!is_at_start()) { return peek_start(); } + + // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value. + assert_at_start(); + return _json_iter->peek(); +} + +simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept { + logger::log_value(*_json_iter, start_position(), depth(), type); + // If we're not at the position anymore, we don't want to advance the cursor. + if (!is_at_start()) { return; } + + // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value. + assert_at_start(); + _json_iter->return_current_and_advance(); + _json_iter->ascend_to(depth()-1); +} + +simdjson_warn_unused simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept { + logger::log_start_value(*_json_iter, start_position(), depth(), type); + // If we're not at the position anymore, we don't want to advance the cursor. + const uint8_t *json; + if (!is_at_start()) { +#if SIMDJSON_DEVELOPMENT_CHECKS + if (!is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; } +#endif + json = peek_start(); + if (*json != start_char) { return incorrect_type_error(incorrect_type_message); } + } else { + assert_at_start(); + /** + * We should be prudent. Let us peek. If it is not the right type, we + * return an error. Only once we have determined that we have the right + * type are we allowed to advance! + */ + json = _json_iter->peek(); + if (*json != start_char) { return incorrect_type_error(incorrect_type_message); } + _json_iter->return_current_and_advance(); + } + + + return SUCCESS; +} + + +simdjson_inline const uint8_t *value_iterator::peek_root_scalar(const char *type) noexcept { + logger::log_value(*_json_iter, start_position(), depth(), type); + if (!is_at_start()) { return peek_start(); } + + assert_at_root(); + return _json_iter->peek(); +} +simdjson_inline const uint8_t *value_iterator::peek_non_root_scalar(const char *type) noexcept { + logger::log_value(*_json_iter, start_position(), depth(), type); + if (!is_at_start()) { return peek_start(); } + + assert_at_non_root_start(); + return _json_iter->peek(); +} + +simdjson_inline void value_iterator::advance_root_scalar(const char *type) noexcept { + logger::log_value(*_json_iter, start_position(), depth(), type); + if (!is_at_start()) { return; } + + assert_at_root(); + _json_iter->return_current_and_advance(); + _json_iter->ascend_to(depth()-1); +} +simdjson_inline void value_iterator::advance_non_root_scalar(const char *type) noexcept { + logger::log_value(*_json_iter, start_position(), depth(), type); + if (!is_at_start()) { return; } + + assert_at_non_root_start(); + _json_iter->return_current_and_advance(); + _json_iter->ascend_to(depth()-1); +} + +simdjson_inline error_code value_iterator::incorrect_type_error(const char *message) const noexcept { + logger::log_error(*_json_iter, start_position(), depth(), message); + return INCORRECT_TYPE; +} + +simdjson_inline bool value_iterator::is_at_start() const noexcept { + return position() == start_position(); +} + +simdjson_inline bool value_iterator::is_at_key() const noexcept { + // Keys are at the same depth as the object. + // Note here that we could be safer and check that we are within an object, + // but we do not. + // + // As long as we are at the object's depth, in a valid document, + // we will only ever be at { , : or the actual string key: ". + return _depth == _json_iter->_depth && *_json_iter->peek() == '"'; +} + +simdjson_inline bool value_iterator::is_at_iterator_start() const noexcept { + // We can legitimately be either at the first value ([1]), or after the array if it's empty ([]). + auto delta = position() - start_position(); + return delta == 1 || delta == 2; +} + +inline void value_iterator::assert_at_start() const noexcept { + SIMDJSON_ASSUME( _json_iter->token._position == _start_position ); + SIMDJSON_ASSUME( _json_iter->_depth == _depth ); + SIMDJSON_ASSUME( _depth > 0 ); +} + +inline void value_iterator::assert_at_container_start() const noexcept { + SIMDJSON_ASSUME( _json_iter->token._position == _start_position + 1 ); + SIMDJSON_ASSUME( _json_iter->_depth == _depth ); + SIMDJSON_ASSUME( _depth > 0 ); +} + +inline void value_iterator::assert_at_next() const noexcept { + SIMDJSON_ASSUME( _json_iter->token._position > _start_position ); + SIMDJSON_ASSUME( _json_iter->_depth == _depth ); + SIMDJSON_ASSUME( _depth > 0 ); +} + +simdjson_inline void value_iterator::move_at_start() noexcept { + _json_iter->_depth = _depth; + _json_iter->token.set_position(_start_position); +} + +simdjson_inline void value_iterator::move_at_container_start() noexcept { + _json_iter->_depth = _depth; + _json_iter->token.set_position(_start_position + 1); +} + +simdjson_inline simdjson_result value_iterator::reset_array() noexcept { + if(error()) { return error(); } + move_at_container_start(); + return started_array(); +} + +simdjson_inline simdjson_result value_iterator::reset_object() noexcept { + if(error()) { return error(); } + move_at_container_start(); + return started_object(); +} + +inline void value_iterator::assert_at_child() const noexcept { + SIMDJSON_ASSUME( _json_iter->token._position > _start_position ); + SIMDJSON_ASSUME( _json_iter->_depth == _depth + 1 ); + SIMDJSON_ASSUME( _depth > 0 ); +} + +inline void value_iterator::assert_at_root() const noexcept { + assert_at_start(); + SIMDJSON_ASSUME( _depth == 1 ); +} + +inline void value_iterator::assert_at_non_root_start() const noexcept { + assert_at_start(); + SIMDJSON_ASSUME( _depth > 1 ); +} + +inline void value_iterator::assert_is_valid() const noexcept { + SIMDJSON_ASSUME( _json_iter != nullptr ); +} + +simdjson_inline bool value_iterator::is_valid() const noexcept { + return _json_iter != nullptr; +} + +simdjson_inline simdjson_result value_iterator::type() const noexcept { + switch (*peek_start()) { + case '{': + return json_type::object; + case '[': + return json_type::array; + case '"': + return json_type::string; + case 'n': + return json_type::null; + case 't': case 'f': + return json_type::boolean; + case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + return json_type::number; + default: + return json_type::unknown; + } +} + +simdjson_inline token_position value_iterator::start_position() const noexcept { + return _start_position; +} + +simdjson_inline token_position value_iterator::position() const noexcept { + return _json_iter->position(); +} + +simdjson_inline token_position value_iterator::end_position() const noexcept { + return _json_iter->end_position(); +} + +simdjson_inline token_position value_iterator::last_position() const noexcept { + return _json_iter->last_position(); +} + +simdjson_inline error_code value_iterator::report_error(error_code error, const char *message) noexcept { + return _json_iter->report_error(error, message); +} + +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +namespace simdjson { + +simdjson_inline simdjson_result::simdjson_result(rvv_vls::ondemand::value_iterator &&value) noexcept + : implementation_simdjson_result_base(std::forward(value)) {} +simdjson_inline simdjson_result::simdjson_result(error_code error) noexcept + : implementation_simdjson_result_base(error) {} + +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H +/* end file simdjson/generic/ondemand/value_iterator-inl.h for rvv_vls */ +/* including simdjson/generic/ondemand/serialization-inl.h for rvv_vls: #include "simdjson/generic/ondemand/serialization-inl.h" */ +/* begin file simdjson/generic/ondemand/serialization-inl.h for rvv_vls */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/base.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/document-inl.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/json_type.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/object.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/serialization.h" */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/value.h" */ +/* amalgamation skipped (editor-only): #if SIMDJSON_STATIC_REFLECTION */ +/* amalgamation skipped (editor-only): #include "simdjson/generic/builder/json_builder.h" */ +/* amalgamation skipped (editor-only): #endif */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +namespace simdjson { + +inline std::string_view trim(const std::string_view str) noexcept { + // We can almost surely do better by rolling our own find_first_not_of function. + size_t first = str.find_first_not_of(" \t\n\r"); + // If we have the empty string (just white space), then no trimming is possible, and + // we return the empty string_view. + if (std::string_view::npos == first) { return std::string_view(); } + size_t last = str.find_last_not_of(" \t\n\r"); + return str.substr(first, (last - first + 1)); +} + + +inline simdjson_result to_json_string(rvv_vls::ondemand::document& x) noexcept { + std::string_view v; + auto error = x.raw_json().get(v); + if(error) {return error; } + return trim(v); +} + +inline simdjson_result to_json_string(rvv_vls::ondemand::document_reference& x) noexcept { + std::string_view v; + auto error = x.raw_json().get(v); + if(error) {return error; } + return trim(v); +} + +inline simdjson_result to_json_string(rvv_vls::ondemand::value& x) noexcept { + /** + * If we somehow receive a value that has already been consumed, + * then the following code could be in trouble. E.g., we create + * an array as needed, but if an array was already created, then + * it could be bad. + */ + using namespace rvv_vls::ondemand; + rvv_vls::ondemand::json_type t; + auto error = x.type().get(t); + if(error != SUCCESS) { return error; } + switch (t) + { + case json_type::array: + { + rvv_vls::ondemand::array array; + error = x.get_array().get(array); + if(error) { return error; } + return to_json_string(array); + } + case json_type::object: + { + rvv_vls::ondemand::object object; + error = x.get_object().get(object); + if(error) { return error; } + return to_json_string(object); + } + default: + return trim(x.raw_json_token()); + } +} + +inline simdjson_result to_json_string(rvv_vls::ondemand::object& x) noexcept { + std::string_view v; + auto error = x.raw_json().get(v); + if(error) {return error; } + return trim(v); +} + +inline simdjson_result to_json_string(rvv_vls::ondemand::array& x) noexcept { + std::string_view v; + auto error = x.raw_json().get(v); + if(error) {return error; } + return trim(v); +} + +inline simdjson_result to_json_string(simdjson_result x) { + if (x.error()) { return x.error(); } + return to_json_string(x.value_unsafe()); +} + +inline simdjson_result to_json_string(simdjson_result x) { + if (x.error()) { return x.error(); } + return to_json_string(x.value_unsafe()); +} + +inline simdjson_result to_json_string(simdjson_result x) { + if (x.error()) { return x.error(); } + return to_json_string(x.value_unsafe()); +} + +inline simdjson_result to_json_string(simdjson_result x) { + if (x.error()) { return x.error(); } + return to_json_string(x.value_unsafe()); +} + +inline simdjson_result to_json_string(simdjson_result x) { + if (x.error()) { return x.error(); } + return to_json_string(x.value_unsafe()); +} +} // namespace simdjson + +namespace simdjson { namespace rvv_vls { namespace ondemand { + +#if SIMDJSON_EXCEPTIONS +inline std::ostream& operator<<(std::ostream& out, simdjson::rvv_vls::ondemand::value x) { + std::string_view v; + auto error = simdjson::to_json_string(x).get(v); + if(error == simdjson::SUCCESS) { + return (out << v); + } else { + throw simdjson::simdjson_error(error); + } +} +inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result x) { + if (x.error()) { throw simdjson::simdjson_error(x.error()); } + return (out << x.value()); +} +#else +inline std::ostream& operator<<(std::ostream& out, simdjson::rvv_vls::ondemand::value x) { + std::string_view v; + auto error = simdjson::to_json_string(x).get(v); + if(error == simdjson::SUCCESS) { + return (out << v); + } else { + return (out << error); + } +} +#endif + +#if SIMDJSON_EXCEPTIONS +inline std::ostream& operator<<(std::ostream& out, simdjson::rvv_vls::ondemand::array value) { + std::string_view v; + auto error = simdjson::to_json_string(value).get(v); + if(error == simdjson::SUCCESS) { + return (out << v); + } else { + throw simdjson::simdjson_error(error); + } +} +inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result x) { + if (x.error()) { throw simdjson::simdjson_error(x.error()); } + return (out << x.value()); +} +#else +inline std::ostream& operator<<(std::ostream& out, simdjson::rvv_vls::ondemand::array value) { + std::string_view v; + auto error = simdjson::to_json_string(value).get(v); + if(error == simdjson::SUCCESS) { + return (out << v); + } else { + return (out << error); + } +} +#endif + +#if SIMDJSON_EXCEPTIONS +inline std::ostream& operator<<(std::ostream& out, simdjson::rvv_vls::ondemand::document& value) { + std::string_view v; + auto error = simdjson::to_json_string(value).get(v); + if(error == simdjson::SUCCESS) { + return (out << v); + } else { + throw simdjson::simdjson_error(error); + } +} +inline std::ostream& operator<<(std::ostream& out, simdjson::rvv_vls::ondemand::document_reference& value) { + std::string_view v; + auto error = simdjson::to_json_string(value).get(v); + if(error == simdjson::SUCCESS) { + return (out << v); + } else { + throw simdjson::simdjson_error(error); + } +} +inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result&& x) { + if (x.error()) { throw simdjson::simdjson_error(x.error()); } + return (out << x.value()); +} +inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result&& x) { + if (x.error()) { throw simdjson::simdjson_error(x.error()); } + return (out << x.value()); +} +#else +inline std::ostream& operator<<(std::ostream& out, simdjson::rvv_vls::ondemand::document& value) { + std::string_view v; + auto error = simdjson::to_json_string(value).get(v); + if(error == simdjson::SUCCESS) { + return (out << v); + } else { + return (out << error); + } +} +#endif + +#if SIMDJSON_EXCEPTIONS +inline std::ostream& operator<<(std::ostream& out, simdjson::rvv_vls::ondemand::object value) { + std::string_view v; + auto error = simdjson::to_json_string(value).get(v); + if(error == simdjson::SUCCESS) { + return (out << v); + } else { + throw simdjson::simdjson_error(error); + } +} +inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result x) { + if (x.error()) { throw simdjson::simdjson_error(x.error()); } + return (out << x.value()); +} +#else +inline std::ostream& operator<<(std::ostream& out, simdjson::rvv_vls::ondemand::object value) { + std::string_view v; + auto error = simdjson::to_json_string(value).get(v); + if(error == simdjson::SUCCESS) { + return (out << v); + } else { + return (out << error); + } +} +#endif +}}} // namespace simdjson::rvv_vls::ondemand + +#endif // SIMDJSON_GENERIC_ONDEMAND_SERIALIZATION_INL_H +/* end file simdjson/generic/ondemand/serialization-inl.h for rvv_vls */ + +// JSON path accessor (compile-time) - must be after inline definitions +/* including simdjson/generic/ondemand/compile_time_accessors.h for rvv_vls: #include "simdjson/generic/ondemand/compile_time_accessors.h" */ +/* begin file simdjson/generic/ondemand/compile_time_accessors.h for rvv_vls */ +/** + * Compile-time JSON Path and JSON Pointer accessors using C++26 reflection (P2996) + * + * This file validates JSON paths/pointers against struct definitions at compile time + * and generates optimized accessor code with zero runtime overhead. + * + * ## How It Works + * + * **Compile Time**: Path is parsed, validated against struct, types are checked + * **Runtime**: Direct navigation with no parsing or validation overhead + * + * Example: + * ```cpp + * struct User { std::string name; std::vector emails; }; + * + * std::string email; + * path_accessor::extract_field(doc, email); + * + * // Compile time validates: + * // 1. User has "emails" field + * // 2. "emails" is array-like + * // 3. Element type is std::string + * // 4. static_assert(^^std::string == ^^std::string) + * + * // Runtime just navigates: + * // doc.get_object().find_field("emails").get_array().at(0).get(email) + * ``` + * + * ## Key Reflection APIs + * + * - `^^Type`: Reflect operator, converts type to std::meta::info + * - `std::meta::nonstatic_data_members_of(type)`: Get all fields of a struct + * - `std::meta::identifier_of(member)`: Get field name as string_view + * - `std::meta::type_of(member)`: Get reflected type of a field + * - `std::meta::is_array_type(type)`: Check if C-style array + * - `std::meta::remove_extent(array)`: Extract element type from array + * - `std::meta::members_of(type)`: Get all members including typedefs + * - `std::meta::is_type(member)`: Check if member is a type (vs field) + * + * All operations execute at compile time in consteval contexts. + */ +#ifndef SIMDJSON_GENERIC_ONDEMAND_COMPILE_TIME_ACCESSORS_H + +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #define SIMDJSON_GENERIC_ONDEMAND_COMPILE_TIME_ACCESSORS_H */ +/* amalgamation skipped (editor-only): */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +// Arguably, we should just check SIMDJSON_STATIC_REFLECTION since it +// is unlikely that we will have reflection support without concepts support. +#if SIMDJSON_SUPPORTS_CONCEPTS && SIMDJSON_STATIC_REFLECTION + +#include +#include +#include + +namespace simdjson { +namespace rvv_vls { +namespace ondemand { +/*** + * JSONPath implementation for compile-time access + * RFC 9535 JSONPath: Query Expressions for JSON, https://www.rfc-editor.org/rfc/rfc9535 + */ +namespace json_path { + +// Note: value type must be fully defined before this header is included +// This is ensured by including this in amalgamated.h after value-inl.h + +using ::simdjson::rvv_vls::ondemand::value; + +// Path step types +enum class step_type { + field, // .field_name or ["field_name"] + array_index // [index] +}; + +// Represents a single step in a JSON path +template +struct path_step { + step_type type; + char key[N]; // Field name (empty for array indices) + std::size_t index; // Array index (0 for field access) + + constexpr path_step(step_type t, const char (&k)[N], std::size_t idx = 0) + : type(t), index(idx) { + for (std::size_t i = 0; i < N; ++i) { + key[i] = k[i]; + } + } + + constexpr std::string_view key_view() const { + return {key, N - 1}; + } +}; + +// Helper to create field step +template +consteval auto make_field_step(const char (&name)[N]) { + return path_step(step_type::field, name, 0); +} + +// Helper to create array index step +consteval auto make_index_step(std::size_t idx) { + return path_step<1>(step_type::array_index, "", idx); +} + +// Parse state for compile-time JSON path parsing +struct parse_result { + bool success; + std::size_t pos; + std::string_view error_msg; +}; + +// Compile-time JSON path parser +// Supports subset: .field, ["field"], [index], nested combinations +template +struct json_path_parser { + static constexpr std::string_view path_str = Path.view(); + + // Skip leading $ if present + static consteval std::size_t skip_root() { + if (!path_str.empty() && path_str[0] == '$') { + return 1; + } + return 0; + } + + // Count the number of steps in the path at compile time + static consteval std::size_t count_steps() { + std::size_t count = 0; + std::size_t i = skip_root(); + + while (i < path_str.size()) { + if (path_str[i] == '.') { + // Field access: .field + ++i; + if (i >= path_str.size()) break; + + // Skip field name + while (i < path_str.size() && path_str[i] != '.' && path_str[i] != '[') { + ++i; + } + ++count; + } else if (path_str[i] == '[') { + // Array or bracket notation + ++i; + if (i >= path_str.size()) break; + + if (path_str[i] == '"' || path_str[i] == '\'') { + // Field access: ["field"] or ['field'] + char quote = path_str[i]; + ++i; + while (i < path_str.size() && path_str[i] != quote) { + ++i; + } + if (i < path_str.size()) ++i; // skip closing quote + if (i < path_str.size() && path_str[i] == ']') ++i; + } else { + // Array index: [0], [123] + while (i < path_str.size() && path_str[i] != ']') { + ++i; + } + if (i < path_str.size()) ++i; // skip ] + } + ++count; + } else { + ++i; + } + } + + return count; + } + + // Parse a field name at compile time + static consteval std::size_t parse_field_name(std::size_t start, char* out, std::size_t max_len) { + std::size_t len = 0; + std::size_t i = start; + + while (i < path_str.size() && path_str[i] != '.' && path_str[i] != '[' && len < max_len - 1) { + out[len++] = path_str[i++]; + } + out[len] = '\0'; + return i; + } + + // Parse an array index at compile time + static consteval std::pair parse_array_index(std::size_t start) { + std::size_t index = 0; + std::size_t i = start; + + while (i < path_str.size() && path_str[i] >= '0' && path_str[i] <= '9') { + index = index * 10 + (path_str[i] - '0'); + ++i; + } + + return {i, index}; + } +}; + +// Compile-time path accessor generator +template +struct path_accessor { + using value = ::simdjson::rvv_vls::ondemand::value; + + static constexpr auto parser = json_path_parser(); + static constexpr std::size_t num_steps = parser.count_steps(); + static constexpr std::string_view path_view = Path.view(); + + // Compile-time accessor generation + // If T is a struct, validates the path at compile time + // If T is void, skips validation + template + static inline simdjson_result access(DocOrValue& doc_or_val) noexcept { + // Validate path at compile time if T is a struct + if constexpr (std::is_class_v) { + constexpr bool path_valid = validate_path(); + static_assert(path_valid, "JSON path does not match struct definition"); + } + + // Parse the path at compile time to build access steps + return access_impl(doc_or_val.get_value()); + } + + // Extract value at path directly into target with compile-time type validation + // Example: std::string name; path_accessor::extract_field(doc, name); + template + static inline error_code extract_field(DocOrValue& doc_or_val, FieldType& target) noexcept { + static_assert(std::is_class_v, "extract_field requires T to be a struct type for validation"); + + // Validate path exists in struct definition + constexpr bool path_valid = validate_path(); + static_assert(path_valid, "JSON path does not match struct definition"); + + // Get the type at the end of the path + constexpr auto final_type = get_final_type(); + + // Verify target type matches the field type + static_assert(final_type == ^^FieldType, "Target type does not match the field type at the path"); + + // All validation done at compile time - just navigate and extract + auto json_value = access_impl(doc_or_val.get_value()); + if (json_value.error()) return json_value.error(); + + return json_value.get(target); + } + +private: + // Get the final type by walking the path through the struct type + template + static consteval std::enable_if_t, std::meta::info> get_final_type() { + auto current_type = ^^T; + std::size_t i = parser.skip_root(); + + while (i < path_view.size()) { + if (path_view[i] == '.') { + // .field syntax + ++i; + std::size_t field_start = i; + while (i < path_view.size() && path_view[i] != '.' && path_view[i] != '[') { + ++i; + } + + std::string_view field_name = path_view.substr(field_start, i - field_start); + + auto members = std::meta::nonstatic_data_members_of( + current_type, std::meta::access_context::unchecked() + ); + + for (auto mem : members) { + if (std::meta::identifier_of(mem) == field_name) { + current_type = std::meta::type_of(mem); + break; + } + } + + } else if (path_view[i] == '[') { + ++i; + if (i >= path_view.size()) break; + + if (path_view[i] == '"' || path_view[i] == '\'') { + // ["field"] syntax + char quote = path_view[i]; + ++i; + std::size_t field_start = i; + while (i < path_view.size() && path_view[i] != quote) { + ++i; + } + + std::string_view field_name = path_view.substr(field_start, i - field_start); + if (i < path_view.size()) ++i; // skip quote + if (i < path_view.size() && path_view[i] == ']') ++i; + + auto members = std::meta::nonstatic_data_members_of( + current_type, std::meta::access_context::unchecked() + ); + + for (auto mem : members) { + if (std::meta::identifier_of(mem) == field_name) { + current_type = std::meta::type_of(mem); + break; + } + } + + } else { + // [index] syntax - extract element type + while (i < path_view.size() && path_view[i] >= '0' && path_view[i] <= '9') { + ++i; + } + if (i < path_view.size() && path_view[i] == ']') ++i; + + current_type = get_element_type_reflected(current_type); + } + } else { + ++i; + } + } + + return current_type; + } + +private: + // Walk path and extract directly into final field using compile-time reflection + template + static inline error_code extract_with_reflection(simdjson_result current, TargetType& target_ref) noexcept { + if (current.error()) return current.error(); + + // Base case: end of path - extract into target + if constexpr (PathPos >= path_view.size()) { + return current.get(target_ref); + } + // Field access: .field_name + else if constexpr (path_view[PathPos] == '.') { + constexpr auto field_info = parse_next_field(PathPos); + constexpr std::string_view field_name = std::get<0>(field_info); + constexpr std::size_t next_pos = std::get<1>(field_info); + + constexpr auto member_info = find_member_by_name(CurrentType, field_name); + static_assert(member_info != ^^void, "Field not found in struct"); + + constexpr auto member_type = std::meta::type_of(member_info); + + auto obj_result = current.get_object(); + if (obj_result.error()) return obj_result.error(); + auto obj = obj_result.value_unsafe(); + auto field_value = obj.find_field_unordered(field_name); + + if constexpr (next_pos >= path_view.size()) { + return field_value.get(target_ref); + } else { + return extract_with_reflection(field_value, target_ref); + } + } + // Bracket notation: [index] or ["field"] + else if constexpr (path_view[PathPos] == '[') { + constexpr auto bracket_info = parse_bracket(PathPos); + constexpr bool is_field = std::get<0>(bracket_info); + constexpr std::size_t next_pos = std::get<2>(bracket_info); + + if constexpr (is_field) { + constexpr std::string_view field_name = std::get<1>(bracket_info); + constexpr auto member_info = find_member_by_name(CurrentType, field_name); + static_assert(member_info != ^^void, "Field not found in struct"); + constexpr auto member_type = std::meta::type_of(member_info); + + auto obj_result = current.get_object(); + if (obj_result.error()) return obj_result.error(); + auto obj = obj_result.value_unsafe(); + auto field_value = obj.find_field_unordered(field_name); + + if constexpr (next_pos >= path_view.size()) { + return field_value.get(target_ref); + } else { + return extract_with_reflection(field_value, target_ref); + } + } else { + constexpr std::size_t index = std::get<3>(bracket_info); + constexpr auto elem_type = get_element_type_reflected(CurrentType); + static_assert(elem_type != ^^void, "Could not determine array element type"); + + auto arr_result = current.get_array(); + if (arr_result.error()) return arr_result.error(); + auto arr = arr_result.value_unsafe(); + auto elem_value = arr.at(index); + + if constexpr (next_pos >= path_view.size()) { + return elem_value.get(target_ref); + } else { + return extract_with_reflection(elem_value, target_ref); + } + } + } + // Skip unexpected characters and continue + else { + return extract_with_reflection(current, target_ref); + } + } + + // Find member by name in reflected type + static consteval std::meta::info find_member_by_name(std::meta::info type_refl, std::string_view name) { + auto members = std::meta::nonstatic_data_members_of(type_refl, std::meta::access_context::unchecked()); + for (auto mem : members) { + if (std::meta::identifier_of(mem) == name) { + return mem; + } + } + } + + // Generate compile-time accessor code by walking the path + template + static inline simdjson_result access_impl(simdjson_result current) noexcept { + if (current.error()) return current; + + if constexpr (PathPos >= path_view.size()) { + return current; + } else if constexpr (path_view[PathPos] == '.') { + constexpr auto field_info = parse_next_field(PathPos); + constexpr std::string_view field_name = std::get<0>(field_info); + constexpr std::size_t next_pos = std::get<1>(field_info); + + auto obj_result = current.get_object(); + if (obj_result.error()) return obj_result.error(); + + auto obj = obj_result.value_unsafe(); + auto next_value = obj.find_field_unordered(field_name); + + return access_impl(next_value); + + } else if constexpr (path_view[PathPos] == '[') { + constexpr auto bracket_info = parse_bracket(PathPos); + constexpr bool is_field = std::get<0>(bracket_info); + constexpr std::size_t next_pos = std::get<2>(bracket_info); + + if constexpr (is_field) { + constexpr std::string_view field_name = std::get<1>(bracket_info); + + auto obj_result = current.get_object(); + if (obj_result.error()) return obj_result.error(); + + auto obj = obj_result.value_unsafe(); + auto next_value = obj.find_field_unordered(field_name); + + return access_impl(next_value); + + } else { + constexpr std::size_t index = std::get<3>(bracket_info); + + auto arr_result = current.get_array(); + if (arr_result.error()) return arr_result.error(); + + auto arr = arr_result.value_unsafe(); + auto next_value = arr.at(index); + + return access_impl(next_value); + } + } else { + return access_impl(current); + } + } + + // Parse next field name + static consteval auto parse_next_field(std::size_t start) { + std::size_t i = start + 1; + std::size_t field_start = i; + while (i < path_view.size() && path_view[i] != '.' && path_view[i] != '[') { + ++i; + } + std::string_view field_name = path_view.substr(field_start, i - field_start); + return std::make_tuple(field_name, i); + } + + // Parse bracket notation: returns (is_field, field_name, next_pos, index) + static consteval auto parse_bracket(std::size_t start) { + std::size_t i = start + 1; // skip '[' + + if (i < path_view.size() && (path_view[i] == '"' || path_view[i] == '\'')) { + // Field access + char quote = path_view[i]; + ++i; + std::size_t field_start = i; + while (i < path_view.size() && path_view[i] != quote) { + ++i; + } + std::string_view field_name = path_view.substr(field_start, i - field_start); + if (i < path_view.size()) ++i; // skip closing quote + if (i < path_view.size() && path_view[i] == ']') ++i; + + return std::make_tuple(true, field_name, i, std::size_t(0)); + } else { + // Array index + std::size_t index = 0; + while (i < path_view.size() && path_view[i] >= '0' && path_view[i] <= '9') { + index = index * 10 + (path_view[i] - '0'); + ++i; + } + if (i < path_view.size() && path_view[i] == ']') ++i; + + return std::make_tuple(false, std::string_view{}, i, index); + } + } + +public: + // Check if reflected type is array-like (C-style array or indexable container) + // Uses reflection to test: 1) std::meta::is_array_type() for C arrays + // 2) std::meta::substitute() to test concepts::indexable_container concept + static consteval bool is_array_like_reflected(std::meta::info type_reflection) { + if (std::meta::is_array_type(type_reflection)) { + return true; + } + + if (std::meta::can_substitute(^^concepts::indexable_container_v, {type_reflection})) { + return std::meta::extract(std::meta::substitute(^^concepts::indexable_container_v, {type_reflection})); + } + return false; + } + + // Extract element type from reflected array or container + // For C arrays: uses std::meta::remove_extent() + // For containers: finds value_type member using std::meta::members_of() + static consteval std::meta::info get_element_type_reflected(std::meta::info type_reflection) { + if (std::meta::is_array_type(type_reflection)) { + return std::meta::remove_extent(type_reflection); + } + + auto members = std::meta::members_of(type_reflection, std::meta::access_context::unchecked()); + for (auto mem : members) { + if (std::meta::is_type(mem)) { + auto name = std::meta::identifier_of(mem); + if (name == "value_type") { + return mem; + } + } + } + return ^^void; + } + +private: + // Check if type has member with given name + template + static consteval bool has_member(std::string_view member_name) { + constexpr auto members = std::meta::nonstatic_data_members_of(^^Type, std::meta::access_context::unchecked()); + for (auto mem : members) { + if (std::meta::identifier_of(mem) == member_name) { + return true; + } + } + return false; + } + + // Get type of member by name + template + static consteval auto get_member_type(std::string_view member_name) { + constexpr auto members = std::meta::nonstatic_data_members_of(^^Type, std::meta::access_context::unchecked()); + for (auto mem : members) { + if (std::meta::identifier_of(mem) == member_name) { + return std::meta::type_of(mem); + } + } + return ^^void; + } + + // Check if non-reflected type is array-like + template + static consteval bool is_container_type() { + using BaseType = std::remove_cvref_t; + if constexpr (requires { typename BaseType::value_type; }) { + return true; + } + if constexpr (std::is_array_v) { + return true; + } + return false; + } + + // Extract element type from non-reflected container + template + using extract_element_type = std::conditional_t< + requires { typename std::remove_cvref_t::value_type; }, + typename std::remove_cvref_t::value_type, + std::conditional_t< + std::is_array_v>, + std::remove_extent_t>, + void + > + >; + + // Validate path matches struct definition + static consteval bool validate_path() { + if constexpr (!std::is_class_v) { + return true; + } + + auto current_type = ^^T; + std::size_t i = parser.skip_root(); + + while (i < path_view.size()) { + if (path_view[i] == '.') { + ++i; + std::size_t field_start = i; + while (i < path_view.size() && path_view[i] != '.' && path_view[i] != '[') { + ++i; + } + + std::string_view field_name = path_view.substr(field_start, i - field_start); + + bool found = false; + auto members = std::meta::nonstatic_data_members_of(current_type, std::meta::access_context::unchecked()); + + for (auto mem : members) { + if (std::meta::identifier_of(mem) == field_name) { + current_type = std::meta::type_of(mem); + found = true; + break; + } + } + + if (!found) { + return false; + } + + } else if (path_view[i] == '[') { + ++i; + if (i >= path_view.size()) return false; + + if (path_view[i] == '"' || path_view[i] == '\'') { + char quote = path_view[i]; + ++i; + std::size_t field_start = i; + while (i < path_view.size() && path_view[i] != quote) { + ++i; + } + + std::string_view field_name = path_view.substr(field_start, i - field_start); + if (i < path_view.size()) ++i; + if (i < path_view.size() && path_view[i] == ']') ++i; + + bool found = false; + auto members = std::meta::nonstatic_data_members_of(current_type, std::meta::access_context::unchecked()); + + for (auto mem : members) { + if (std::meta::identifier_of(mem) == field_name) { + current_type = std::meta::type_of(mem); + found = true; + break; + } + } + + if (!found) { + return false; + } + + } else { + while (i < path_view.size() && path_view[i] >= '0' && path_view[i] <= '9') { + ++i; + } + + if (i < path_view.size() && path_view[i] == ']') ++i; + + if (!is_array_like_reflected(current_type)) { + return false; + } + + auto new_type = get_element_type_reflected(current_type); + + if (new_type == ^^void) { + return false; + } + + current_type = new_type; + } + } else { + ++i; + } + } + + return true; + } +}; + +// Compile-time path accessor with validation +template +inline simdjson_result<::simdjson::rvv_vls::ondemand::value> at_path_compiled(DocOrValue& doc_or_val) noexcept { + using accessor = path_accessor; + return accessor::access(doc_or_val); +} + +// Overload without type parameter (no validation) +template +inline simdjson_result<::simdjson::rvv_vls::ondemand::value> at_path_compiled(DocOrValue& doc_or_val) noexcept { + using accessor = path_accessor; + return accessor::access(doc_or_val); +} + +// ============================================================================ +// JSON Pointer Compile-Time Support (RFC 6901) +// ============================================================================ + +// JSON Pointer parser: /field/0/nested (slash-separated) +template +struct json_pointer_parser { + static constexpr std::string_view pointer_str = Pointer.view(); + + // Unescape token: ~0 -> ~, ~1 -> / + static consteval void unescape_token(std::string_view src, char* dest, std::size_t& out_len) { + out_len = 0; + for (std::size_t i = 0; i < src.size(); ++i) { + if (src[i] == '~' && i + 1 < src.size()) { + if (src[i + 1] == '0') { + dest[out_len++] = '~'; + ++i; + } else if (src[i + 1] == '1') { + dest[out_len++] = '/'; + ++i; + } else { + dest[out_len++] = src[i]; + } + } else { + dest[out_len++] = src[i]; + } + } + } + + // Check if token is numeric + static consteval bool is_numeric(std::string_view token) { + if (token.empty()) return false; + if (token[0] == '0' && token.size() > 1) return false; + for (char c : token) { + if (c < '0' || c > '9') return false; + } + return true; + } + + // Parse numeric token to index + static consteval std::size_t parse_index(std::string_view token) { + std::size_t result = 0; + for (char c : token) { + result = result * 10 + (c - '0'); + } + return result; + } + + // Count tokens in pointer + static consteval std::size_t count_tokens() { + if (pointer_str.empty() || pointer_str == "/") return 0; + + std::size_t count = 0; + std::size_t pos = pointer_str[0] == '/' ? 1 : 0; + + while (pos < pointer_str.size()) { + ++count; + std::size_t next_slash = pointer_str.find('/', pos); + if (next_slash == std::string_view::npos) break; + pos = next_slash + 1; + } + + return count; + } + + // Get Nth token + static consteval std::string_view get_token(std::size_t token_index) { + std::size_t pos = pointer_str[0] == '/' ? 1 : 0; + std::size_t current_token = 0; + + while (current_token < token_index) { + std::size_t next_slash = pointer_str.find('/', pos); + pos = next_slash + 1; + ++current_token; + } + + std::size_t token_end = pointer_str.find('/', pos); + if (token_end == std::string_view::npos) token_end = pointer_str.size(); + + return pointer_str.substr(pos, token_end - pos); + } +}; + +// JSON Pointer accessor +template +struct pointer_accessor { + using parser = json_pointer_parser; + static constexpr std::string_view pointer_view = Pointer.view(); + static constexpr std::size_t token_count = parser::count_tokens(); + + // Validate pointer against struct definition + static consteval bool validate_pointer() { + if constexpr (!std::is_class_v) { + return true; + } + + auto current_type = ^^T; + std::size_t pos = pointer_view[0] == '/' ? 1 : 0; + + while (pos < pointer_view.size()) { + // Extract token up to next / + std::size_t token_end = pointer_view.find('/', pos); + if (token_end == std::string_view::npos) token_end = pointer_view.size(); + + std::string_view token = pointer_view.substr(pos, token_end - pos); + + if (parser::is_numeric(token)) { + if (!path_accessor::is_array_like_reflected(current_type)) { + return false; + } + current_type = path_accessor::get_element_type_reflected(current_type); + } else { + bool found = false; + auto members = std::meta::nonstatic_data_members_of(current_type, std::meta::access_context::unchecked()); + + for (auto mem : members) { + if (std::meta::identifier_of(mem) == token) { + current_type = std::meta::type_of(mem); + found = true; + break; + } + } + + if (!found) return false; + } + + pos = token_end + 1; + } + + return true; + } + + // Recursive accessor + template + static inline simdjson_result access_impl(simdjson_result current) noexcept { + if constexpr (TokenIndex >= token_count) { + return current; + } else { + constexpr std::string_view token = parser::get_token(TokenIndex); + + if constexpr (parser::is_numeric(token)) { + constexpr std::size_t index = parser::parse_index(token); + auto arr = current.get_array().value_unsafe(); + auto next_value = arr.at(index); + return access_impl(next_value); + } else { + auto obj = current.get_object().value_unsafe(); + auto next_value = obj.find_field_unordered(token); + return access_impl(next_value); + } + } + } + + // Access JSON value at pointer + template + static inline simdjson_result access(DocOrValue& doc_or_val) noexcept { + if constexpr (std::is_class_v) { + constexpr bool pointer_valid = validate_pointer(); + static_assert(pointer_valid, "JSON Pointer does not match struct definition"); + } + + if (pointer_view.empty() || pointer_view == "/") { + if constexpr (requires { doc_or_val.get_value(); }) { + return doc_or_val.get_value(); + } else { + return doc_or_val; + } + } + + simdjson_result current = doc_or_val.get_value(); + return access_impl<0>(current); + } + + // Extract value at pointer directly into target with type validation + template + static inline error_code extract_field(DocOrValue& doc_or_val, FieldType& target) noexcept { + static_assert(std::is_class_v, "extract_field requires T to be a struct type for validation"); + + constexpr bool pointer_valid = validate_pointer(); + static_assert(pointer_valid, "JSON Pointer does not match struct definition"); + + constexpr auto final_type = get_final_type(); + static_assert(final_type == ^^FieldType, "Target type does not match the field type at the pointer"); + + simdjson_result current_value = doc_or_val.get_value(); + auto json_value = access_impl<0>(current_value); + if (json_value.error()) return json_value.error(); + + return json_value.get(target); + } + +private: + // Get final type by walking pointer through struct + template + static consteval std::enable_if_t, std::meta::info> get_final_type() { + auto current_type = ^^T; + std::size_t pos = pointer_view[0] == '/' ? 1 : 0; + + while (pos < pointer_view.size()) { + std::size_t token_end = pointer_view.find('/', pos); + if (token_end == std::string_view::npos) token_end = pointer_view.size(); + + std::string_view token = pointer_view.substr(pos, token_end - pos); + + if (parser::is_numeric(token)) { + current_type = path_accessor::get_element_type_reflected(current_type); + } else { + auto members = std::meta::nonstatic_data_members_of(current_type, std::meta::access_context::unchecked()); + + for (auto mem : members) { + if (std::meta::identifier_of(mem) == token) { + current_type = std::meta::type_of(mem); + break; + } + } + } + + pos = token_end + 1; + } + + return current_type; + } +}; + +// Compile-time JSON Pointer accessor with validation +template +inline simdjson_result<::simdjson::rvv_vls::ondemand::value> at_pointer_compiled(DocOrValue& doc_or_val) noexcept { + using accessor = pointer_accessor; + return accessor::access(doc_or_val); +} + +// Overload without type parameter (no validation) +template +inline simdjson_result<::simdjson::rvv_vls::ondemand::value> at_pointer_compiled(DocOrValue& doc_or_val) noexcept { + using accessor = pointer_accessor; + return accessor::access(doc_or_val); +} + +} // namespace json_path +} // namespace ondemand +} // namespace rvv_vls +} // namespace simdjson + +#endif // SIMDJSON_SUPPORTS_CONCEPTS && SIMDJSON_STATIC_REFLECTION +#endif // SIMDJSON_GENERIC_ONDEMAND_COMPILE_TIME_ACCESSORS_H + +/* end file simdjson/generic/ondemand/compile_time_accessors.h for rvv_vls */ + +/* end file simdjson/generic/ondemand/amalgamated.h for rvv_vls */ +/* including simdjson/rvv-vls/end.h: #include "simdjson/rvv-vls/end.h" */ +/* begin file simdjson/rvv-vls/end.h */ +/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ +/* amalgamation skipped (editor-only): #include "simdjson/rvv-vls/base.h" */ +/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ + +/* undefining SIMDJSON_IMPLEMENTATION from "rvv_vls" */ +#undef SIMDJSON_IMPLEMENTATION +/* end file simdjson/rvv-vls/end.h */ + +#endif // SIMDJSON_RVV_VLS_ONDEMAND_H +/* end file simdjson/rvv-vls/ondemand.h */ #else #error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION #endif diff --git a/singleheader/singleheader.zip b/singleheader/singleheader.zip index a87d41c550f8d742bf1e90cb1be23a11b133b138..5428ea895b3df4fca0d62abb302a07d52cdbffe4 100644 GIT binary patch delta 197937 zcmeFa33yc3ktjS3-D)kM1?~Hl1X8#576QwXkkzb~K_FHeW4mcdEodWki|&>X#-!1B z5)x+|n=nJg89Rna>|`br8}i<`^Rhx_vO6)#zDyjj`nmPf+wQn+$up6(r<{L- ze@_(FSGF{`+O(GD_U5+s70b1T<`vD&joP>`6!r%LT5IF-#^!VT#&S>oAa@V!@GNUR znVG-xqT7X=8U{&4yG z3k%hksn6Hu#J=-i3-7YPxgRbpk?&()yIA{)h4Kl`{b-@nE>Mb1U0&!qTtx(@aag4_ zPqa1TPd#>0B1A6{^9O!e`%3Ird#srqc}PJMmOb0o>{{6h$NteeTtMVCedOIrh07)Bt-SSA%y`TN7;A6>y^Z&Cb8D9Q& z$r89UVYfksb8Q+t`%m^1SoC$RJ%;bL4%xJO@6{aO{mR0E8aacit7ninOu#r}t{>U| zBQ+VvrL!4{09Ph+szCdN{ebD!>H;d@!UFZ0KQKBLX;c+XtSTIzYgzA(%vuJiB@Pln z2Kt&uaF@q@ZRvu`?|5rIG&dekf>-`Fr`k%T;LNVf@`Y4!bXR7r{>st?u1}8T#7^Ir z(`13}FWT3ga+DUr7I$GA+8bXadGpkVo6?S#Pd3HMC!4psW64!%Cjx)P&K+7}WYfnN*&(`WQ4Zr! z)y0|gH~nN||J z^plLF{&~ip#@I;Gb@0$j_U*^tds}Agy|-m8m|8k#4c~li8a_1@4t_6K668sk=Yal6?H`-X*cSd$Ygvp}z)Z1JQXd(YfR}DsoijxsQJ7Itvu* zmh0R=Wm@b~!HP9Y5;5EHsoE8>soIr4SrcpfQ~n?Q*BO<+QeQh$3^Mur*}Ux7`7akN z**DMLI(rK{_0sET=I#AhS~jWp<7lkLwz!K{T)56`zztJRX(Emki=FeEij$9LR29cE zs!Ddg@2`T-{v5_NFJR{v6kE@v2ekYo4gk&^SWqs1pS0!`NLD)YOh#_1 zK*)1*>dCDZ=7(Z_xXWX~QU$EJ%e_=RSbmY)N)Ozn_QkAa1R5XU${#lB^}V00Em2ht zp024<4|~6qr8~DKzm%o?m@(InlhP~=h)@GLT+QCH##F7gDK+37@r6gd13u+Eo2pMM zhRk;?&QK_soptsCy&DzZzo|l@Vd>APR1YUUTE={%+y(i^9hHixu7|VB)q^`F?>(x{ zK40*;w`@E6;zL00EZNxRv;)wJQqaSB* z0;c?yW$;|REvZ;}r3XSj^sAwFn#$5YEl_dyvKBa&Ww)Qq$WL7PK0M-`@c0OX6a7vZ_FQ;NmObT-w&4 z|0qrqn5wYpGQhIHrb~y5=ZbXi`k8Ze`orV`TcetM2g{b$=+n}lvQ#~Io7)~$#k|?6 zN9ln%y)XYZ_p6puk5A;px<^*uVu5`xWoE)dc?CB@-*>YrVQA0fTDTa=SOK5eGkI3l z0+Tqo{6w}x0k`<_>ea)ECAM<)VEJrawR&)WyhxWIlbhUn$1ki&`$tvm#PhcG>fy{U zZ@iBln2dGj*uE7tZeI~~H7(?ejD-Tq!#prNGB)g4+3H|)4j-u3-r^va{K{5O#M$iZ zNUib>8%Jn75s>kbanFQ9jWUDD9&cdVX81MinedFQY(>eT+CeTiwNlT54^A6 z_;?cEH-qLa?oQP!qHBg!KC63n^t!ii1Xt4ig^CE558<#P5tvXucf3{CC*EIX=^SIZ zFGVM*`(xQkpFsJ&8ShpAO!PfBl=r;Cl~9_RZWxHGbf|BkXdf=?cgHxdc?`^QkEdmIj~DcG1YZQ()sg&hdXNyJjX z#4ZX0#(w9}7_jIyL+i&)RE7-UMi00_Gk46I+RV7+h#^N9t2D`5aA|yLF_inQc0nG+ zJ%&xzH;rD2fJ-E!d^l#K;ME8?8+Z;$8D{ALHHrOyBeU1o1=#~4$ebx6*r6)w8xH&8q(U5_Ny@x=SjGv4 zy4huxM3cosz?pGd4QLzNZ1A?S_B(FSjxaW3@&<7n_YRNwNWw`OXJp@T_0R$5EyYFf zw(`7mNGq@}hTq*_E3q*k;Bwho;No~%Dm-?REh%5|=E%Ts$TQ;UZ*!nzcEY(8dF7D# z^`ZB&e5}x(-Z@7o-oW5YV1C|Wn=_b+gxFmE$zlhbdcH2lO4xw=`(;IC zg00Xj9t=2GC+juQ59+|w+Rp9*oyh{hh(u3xZz-&Pp{|evJW*nAnPitsC%XzbBmf1DEm5r}u zmBYuoY=sg?W;L$0Gd{FBxd{nzr$O>4z{9>a;Q`?D7%t&~AFWAY zlLP+zhoW+aj#4n>k&Xe4)6O&T}6gAb(QxNgMo1Es0ZuaGv411mRsyg;pFpm`Op|>s}RQYIL#Z?u$VsrccNK` z29IsASHQ&vdn&K|mfM<^rfJpMTi7ha?@x``N*Pt(^}D)M*z`hO20VMSZOLK=1vNM; z2i{g&9z1ljtr>n$Y)@F?%)c)dB{r?FB`o27t`&Lh_jM`6b-B>|fr1RE-;L02dPiD$ zxuVHP*msZ*yovrK%TiaZVyXpIHMovzg{6`e6IVh1-Ad3}F-qy!AJVLFBxG9*PcB-N za_XKO8+>`Uz2p|vXn5E^=o=f=ry6@P7(5hkpspMDu(&NYIt`ooAk|9-{2;N!oD`gU^t=*vq6EZJp~ixs)%=Ra4bQGEB<-afL+V}`?b2WVDWX|3g=g}?}W^Of~Bzc&qa3VKB=X&3icZEhr$t^HAcb#pCnwfWCj{o ztqUVY!TsXI9ylFp%Yf(pT(_@Cbt4=ambC=SxNop;)%iX=9QU0geB}pa|5YOp5#CS7 za4>jaY}6C+_7D4vtab9ir*mB)UpS1Ob?-pLKkn0fJl+yzXe6ldxM26L+Zu4yt@Zo% zd&m935O|N|btX$Y6b?RDRuv^Jf|DP$3i+(U2hfA^7WyBZCsF|qlL7AmFxtv2;Pipg;n`4F?HK(^GOu6VA17lEnssV}Xb#81RK1)PggXl|K5m1@P=G_9Po~ z!OU)$h%%;?gs@Ar-?b(|(-|$VYU;_uI|niYY1}l02vW>;qfup5a)00{+?)o zOb9>|;^5OKSM?dp2vsX%qrF`3FuK%e>EKUfN2n^wj8JbT2W>^man{XZLNJg_iU|{f zNq`IgnNk5|#r0`QS{Ex(JY8BtUvd3Pc&xQ46V8^@=iVUACt;C`7+zgC7+IXP&n^CGyo z%kB~%rh>Lniw0Tuxa*Zx^-egXk`tx{(i;$DQ+!E(AYsYn?bAwz_eCUQ8)4pNpI&l! zhLR0rH8kjga|VNfY5(Ry)LajRY*skC+rIM6)c56;^&fSr8GSX$9Q)Dj_MQcB_KB2a z=)0@E+R_18%j_la`+ZG|p=TK`_Fw;0YXdYsZ%^6FJq4W6xW|L>a0l)n%_Iy_@t{O! zYm_+#r?22J$#mN`YeWi{NDTP>#xZMQL=Ww6+$9@AOE*?r{(v>D0!kfQp+q(_>1 zl&g^6m30@Kx`56N>t|CMVB=@;x3%Tnd1Qzt!*71u(g?4Qcec;$q2^vWIQP=xr2t=d zrQb$pV^H}7Q2DHEO|XzsON>^>Xe3mx1)R7LVWgOe!rXhPH{qId6D^_%$m(lf1{WXA zOJz8&nlk`b9FC+>fJw1e>g~x;S<#)Z@1T;w$+{%Q1W%`2ITtL4=I`Y$hVGv&PKnOU zMasFE$d@tA2*T;9v%kSDgi^1SPjOtDqJ4w|!2ZFb5Y1>lpkHrx8Z$1Q?%}wW_FHCY zf4^e)zpM@EWJ=UW<`g`6;_2+BYc$4S%4f?zbvm!YE`0cK;<1cEX^maG1;)k4%r;ny zK7^*7Et3T^9G%mEF&pe^4YtmyLFG{6F!wP3`pmsB`yuuHIa4nTc9@uX19*C86}Y@R z^EaDqGe=^h%xse}wnh+a>&h@;@D;cqttmx}pf&_^Ug_;EHc6L|5rtjq@!$+UUGw)EUZRLv3X?h@u`*WHeNOJDI zX|-yXvEtPUmwGtZT3@RGxEB}eJJ#oxEj_J@88@k+BDU&X3s7vGi>=Cqis$Wl@VDF2 zb0E{6ll}DX7B63br)mn?;rx=~V`zn(4eTsfP>)`Wrzi6v>j7JHf|{3#m)JoYYyUGW zPh0+H_|w-jl5f-;j&a(|si~}SYItmkKiqML;b}SUOEyM=v`a~hgii9K9jQmb^^i>+ zA~bJ}pLobtr@B;eepQotn7o{&6X-&Hr%s@$*B9#qI%Cb#3FLl0OA#n`W<$q<1q6<5 zhi@&hRlw2DRQ`Lh(I6P{hrPr8eF5K~XUH2yCOltRiw8^jE(&S`<3h~5$vq1fvMqHy z5yD>TV0D(nKNH(7*`Kl@2uB@%dl51 zF#049`(Pm)mKEjytz$AZm|Gp|el_JkQdE6JZUvlw5?z#E{kV;>AnUH>6E>YRNR3kH zdjyGo>=U-NvT6)*O;LEpCVyM`JG=Y_2Vcy)Q9i`7K5w(w<$ToTeAMN9)Fs6)%|~78 zTgLNImx31aQI{AShcWk#qs^HG=cQI|Y{v@t%#5Xm_obvau~;Q6RambYa- z>e7&GeLm_k{&>wSk)`udml)HmCo&MnROX{D=c6v?qb~7&gZZdSI(u=wqb@5KiNLld zIG=#r^BIaLpWJ+g zA|K3WD8dwl*OHNNK10#?e1@XABte?bP&A*RXs+oZ=Q9+sdqn0l6nVyt5nwWr(En2z ziuAkLmZ-EElV!>LN@(>4^Te!Sw?eBom%mw1$?k+!Z`{i>EBKYX>Xqxoj2-F$4;AAb zI`U#(_4>l)41PDSdc&Hh`+3zH0?n@I{UBb^tCEetb3ZKksVZ~k>jm#n4+QkoQ)w)r z2+I_5xu>E9PJg37bR#_YLW!P}<;11T0>~`M(J6K2 zwoJ^gbSYDR<9#{f4u!^NN^&-;hb!gDPPlX#LG+d8=s8jl4+nhuXC?Mn#&P@Ydh?h9 z#|f`Lnwb`B`c1|W{r$OPh22!XK>=n+T>5nZ%M!wRJ9RL51$cg5!g46FH>{OUxpJ~& z&;Gn*Qipb-HD_r|d%*r}9U;~L7G0+rIQQRLyL#~2GKbZ}xr2ob(DAC42_0|CITOR* zY831k!u~0{>WyK5VAsKDjOQj|ZxHWl@VJsQ;FXwNPnC0~BEA8vl?9#H0BFU98L=O1 z$thB;0Me-{R=PFkaZ?XiQ!cm^v$O0-ti6hw(p3uctj`s8z^{u7Z;)?dNTS7xw_@(H z!V}r^*Pt4%w!~Y0n{=`hm#E9mB@F?G)R5k%0%z^n&5JVOU8Re3b|s#PoqgF}p@jJx|94Jt?53_o-%)tRP7D@) zCrwphyp5%HsyB%7GU#he)^7$x@v~Qcjv=zU7OE%YwfCBUMdc^zc{RNJ)l!||k&mlj z@12XX;LgwGbgP1_`_FzZ=Yv-Dil%xDr~2RNvn*?JadGU)FH|g6Jpp9jWw7^si!xO` z1B@Jd$CKR(B#Jm)XiR;nutj~b z+?`bnXBX${WrJTX)TJAKX3}k$s&L|arH)wlR|>s)7qFvc@QN3&dGE{2eMpsbeWPMT zJ)HSQh2E&^d!f7Mj1fC?$6KhlM{^7{{(u=KfkwLWZypDnwuZRpA!(aQQbCifK5oi(gL8 zgs(lZ>+P|=e@Z@~AdCP-Qh2Y96T=%T-K1b5`8CjXS7yMm-b!6QUOAQ90$PvW zx7gM{EP9V3Obqj#Evi;PChyA9nUq01|IS>zSm2H_6T~ve{B!aWc;x0HL%KMk$;*GA zn;R?bDf))F2QeJQi#h~sWetqJiV$AkQ>JGko7`HYivt`>4Ia9qtV`jBL`O;RA4|WW zb0kqGhNJrKHdTrdM)PN7z*iqGGYsgZ%u;yyONBYA;8S1EU7;Sl?=NeGM$58~#eVdU zmHifY=(UVwIPm0+i!%>}cTi6FJ+75^Vl>ea%8$5svy~DTg7?WA^D}~@rtfg&xTQQ= z(_T}r)f}OJ>gk`O_z&i7ZKi4%U@G%ijvopeQwXXQfG&q<6|<mRB zWx>Or%(}%m@&7?Rc($bcPCe}DOZlXHh?Q(jxk1THc=>~6UsRty^Fr-2q_FSB+)Ap%zRW#IVP(0z&vH#)Un<`4jM1ptkbjunR!p#B_kOVQhFW?3^5n4% zOeN5lJNmq!C;^!qJ_ssM}wgVc45Ld*g$!M zwe3BCO`p1^#@a21} zM=Z@?+1-^5qsQ!JaQl(!C9xw%tAF+_7`>~*UNPv6cQ0RIqaM8M-FTLu(rh!aB7F}5;7lVRmW$767U_uTb_|7 z!6Ei6!SxJjhl699H$?aMA+*6D-4cqIvqt;~QS*+DVxLfO(rsqw(+-JiL>W@WgB}jX z(?8}PrjJ9x5MEUh!CU7}X^sMTS4pZJ%6eBc`uK%^0G0$&GFrTB)1`~!aCGLAO^Lb|b0K@~>?3}~#+^u?=< zE@EROP=nF^HAV3IJsmml`c3w63GKmoJ94%{3X> zq7R4sk^P9NKjQZe!=)`XB`{i2lTt;aDBfxVUc6SEMq7-gpg#i+k1tr22`Qg%TLSlP z@T5a`uf>+8Xo6SB5C)ZU$Q&jD$+uc{br8JYvXv$w;W1A!T;Ao#h4*f*S=^u(36A$bcK;WFicmYza;@?;Qn8CmB9Ir zEK15U&QvxEaAEs>xg|K=_!k_s{;{DUoEtcuXPO0Pp4nWOCBC8@8yN8UaLU7zYaN*6 zcDTa^PycamW*)EYV1(2tf3sGL&A@*Wgs-uem(Jsfib_X(K_rNWt$LY}ACnI^<S(PwNv&W8cVV1bc#)Jdxm*6B$1Y2g7jU+naJyb%-$8 z}GF+Fg^`1|L3Jvn08_T`(fk1-*CNoRY-(3l6Sr%z-U0?6y^F zXasD=Q_M7gYEB`&kK$j^6itiE57uP&XmuK|PqseZjNrg89;OC6k@ac$#h&m&5gIUp zyahRD2$cY8Ja2$FPtJ_0q{3V^={!VO4-yp@KhX5{nu=Trn5`;gOE7hRO>q@Mb)#Mx z;N%+eqKSp0KMj0|V+}DQYVk1BT-1cX+JLIoh1ZrH{9SualvPJrP)ITZ1P&ONI&7A+&LOOwql4ZB5g)wtu9_+< z;Q@;uswqmAG=PhTYm4EYdukTPir!r_l;*%H`rOBHQxe@zW((8D#7bc}cu!4!iQv!n z_5^i6`^LH=2;Wnan;BmW9$T;~Zz1A1NSbrn>EV|PH!Fy^7CF!(kL1CDRbQKiO zrpMha?(8U$KttM82PIj!9^Z2(Lyb`2QxKcyUE!}}7uak0z&{D}c&GR)UQ_nK(5te; z#+Pv&OV!|}p_}sf;%1cobo@?1e0x2`2LJB$| zs$8~JrI7q=$D$^NV;vh?ytjy(1g5#fL{Z%;F}?V_K|z=eAG_F*3AcV{RTkJ9Y6_%< zT>9J91@OwfHRUO)hu}@Uv&u$r*w_{nC7x;R?Od7Vz{RXv(&43d*Q70W5PJ0tJ14Ik zovE_WsPTj|O;Az_xNJDWJW>32#;QV0Qe!m0;)_AX;HWbEQ#H=w_$=8K%QF%Q2A90U z_yF9?cI3hbj@A@aDr(4)ph|d7PggnMjn?F~awR6(LqVs1C(O9iCd*61C7x^xx?k8` zTq*z>g$AL?lwt=wmD89P-4_a?y=BztzKK!10Wd&z{P1C>tH@ZvmQWsse4{=un!p+@ zIk;*FlkF*0hio2iVrp%^aiyGaCIo8na5*7<6mO0UZ}ABwW-5ZbWqfXG>7d3Ls{MyG zSL2Eas*isar!$>`ePe2^)L7Z1+GsdoYh_9{G(7xPJ3RPWcan`jyJ7NYtFto+Bz1+2 zo>W;k5j4(pM%EJ;#LYsD$rMIpUJ3o82XdXI@I!aH9e(ggdJ5iZI+y`_pHE6X{_vwU zv4$kbr?AW<&-CDTZdVe8YBB<(}=a%ho>?;c!8B}O)aNcn02aa?|`cO?? z6ul{IWw|C881nBM!&MR)NZzskpAi1)0|G4I@(`PSV8HT?^KR$7ck1-5Mp+3n2GK`%?ldpO(_?7thmPGK#)AN^Id zGTiSCF#7^Sst*(HIGE^7!ExZw^);yhVg5-+woS*C`-LQ3vB%t=#AU*M#(cc0XoV=J z6Szf^cb&M4772>AbS6kdZzH)0*Y!B6YjlrPGmn1g zDh&mrA;Gl_13t|)$-sJ}=sodCI^Ig&F&~48>m1g_Fx8f|xPOZ};76{|4)_j-v6N4? z>mv<`Wc1?OVSkh^$s*K{;yNj5*G4qKZ&vnj5sGX?n3%iQi;H~{FabqL)YRw|MfYmR zzi%H+K-PcsG58F8v7GfMYL*oKfM}0_SfwpDH-+LB@zuEjf#n;*g`NcVjLLfLell%4%*+n?HQ&@JdFpj#MK{`qahhFFwKK;!T6DN`0G4s&7q~LB!MOkVTx-_*th#J!r$ZalN>N2Kv z529M6d5X}^;04MJ(Eev=&8ac%-qh zk$e}#*WNK&HK5%s$F+KA zOslW`^#f3_ySB*Cy1VOs3{ylOfY~+R-LYdS1CwqZJ9uz+ZE0q&$GGC(vKd}(cNQ>L zKziJV%%4;@CjftGkJUx5i{V#$tQa_n?W3c>4(I>mOgd$)wZX_(Z9Tm2b!QqhPt@Mc z3c%YfwK?$egmW2;{%SBE(tYR>eCSuTi?e8p8F?1h+#WA(*BrhF4leH~g!5bK6Mggk zUylao4=hOZ?d&Qyx;aMcQgTUkdA9G^wv#zKJnqfzO}lT03m>mVM@pwNB`@Lkb*EY^ z4IEkF`&h}JdY`DtfQ|*VPH32L-e@K@(xM$a*|}-fO0-Wvd#fV{LLXhW1fG4HrD8!C z&kbg6tAb-sTGQZ_wU*@QChpH*hB-33E*|+b(d7k6m8Mi5TKHlkpDQpAt9b;KdC%re zJ)76n1@v|3FhPHu zFN(XQ-8frZ4e%JQ62W$QQ+R zVlx{W?mj`Yg2hUR1qmZ4IuFLs^JfIt7xFbw&uC!VX`hj=9p$)A_b=VV!E%Gw8xUw} ztD+iPU&u9~)Bb)kqb@TebCPA0qoxhE~A<6040h0|JfnBDUv?RJVo|hE zpcM88Wd?T)i&2GxpQ_1@N>=ZZOc0=M7^be9iG5reuoZ`*Fu5}jQ5tm99Mfl(rlzHC zgQ0_ggA0*c3Cl*&bA=HkTq=%I)Kw5S#2LxgZs|2N(oQm2t_k7cT=3J1dCE>DY3{Yg7!W+NB8@YfFYa(=tV-eIFol~A>%{W z84I36x{qQ_oG3z)Fkd$FQIUw#@!f0z|(36SI_9!2{&-o8Sr9@ z+-={K%45jXkO&Qp!L@~I+UO*)zG)hnsYM) zVL*Qd2(<2!A#RC)Il=qAzb%aN8HCe@W{8xsT=SXcBThSVW^^MbdPi767WgD<-~<+v z(NvCDKtquzHi+a>5T_)0(Q)S|N;^7C4GRIl+`)J3aI~Y@Ql-HoUlQah^OinQJ z#jqf+0s7*ID=x&Lu9IZ1xGIgJU~o{c5ny1@i=HMFc}(o+Q(L-U#lYZaHZHu_wT%kz zLbp!!US?)VvNMpZ40UP-igK+erXwROt5%J8gS%l>)wPq+ux#pvqi7wOW1422JRZ?gW0%A$K8JX821YUr(&n9FeNB!iw+l7q zRX{Io7%qH$QF&At6f=>LSDLZS>8&VxPe7c#Pu?iaFC%!xzi5OD+jWNiU`v9b=G0VT zhCqSHIAW&8q)j57$A;Zp6+DZU+Q9G_^OGMO3r5h~V*XJi-6*PivmGw&dl{K-C4eyb z-_D#UTI`I$q=-}YP{Ovw29?pqSFrgvvE7RfR<@gi`}G36+NCg6*hCu@EOHO~6In@_ zbNyGTqSv6aWUR^ekek7S;0HBMwsYg zg+xZLbkRo+1!V^$frK7mzEsn$AJhG435)JKnj4#u25T^&r&-t7f=RFptqMGxI2i9L z_x_Ci;vZ4RfaO!xWkSU;h!T{| z7x0$&^I)`a!3y{hSZ8v8UHa|nBIZ2Hp5}Bzdo}C*i%a3rur)bL_ZkWg7cRLy)|3R_ zq)RT*H|3Jc(p`(|w`}Wm@7STc*$=xYKkkY8Z z)j_L7Wu?n?9-%20W@@0olJBgFsz(t!fW7K6t<dKT659x8BT|@ID5Xq;&Jm#n)SP|buq``X#*QjuLATu8>rumW}n(wqhV}UcB zI~9of1^`HF6$Ap7Cl?jNTk@TnlgyI%w#1h7><#^Wfs=N-ss47{Wn__z;;fzUdoY&? z(@xAD5BnlwiZVxt!#IVhsNVMtSA!?3Mrj|O5`oDV_>4iPW*th{3B!!rMa)H}s~3DJ z{f}m3nQ)ND5#lTmLU8~+p3F(WzHuu@*eiq+uO5#LdS3?)D16v}8Vm{&zNV17gvepI z9_k&e8MJC)H<9Q(C{8ru;2ZUVmxN)$hKFKdk&t>so4$0?cyD=UjVMQr zwg(#rWA(UkSVP*99HNKNC4;^Z^zJgBH`B(%-5k;QFbmcM4@_W{FfaifO!K_;xhcse+YyZr%lWTB?w0VCXo!Z4_P0d~?& zZ=A*!BPXyt*KA=Sk=S-2zf+-;6SJ#YKs3)sIfFP5CQK%@D0Y^&sn2!83=j>H;F&N} z5`~6)aNJ9tC$z-^D9w;r2s;D4=&iunKr4#vkRd6NDA{q?S>ep%5EwlSa99Zp*fjND zP8ghQW8Pt*?a}NuEcFr#Yso|&+>+Iz2Du~Ww3J0C&kbLVZeL}5%jF`I6dtTV@d9$m zBR?8uq$onX##u2+&P`mI;u|(Y6o1ihP-)>QN1(L-ZysksalsF)KVs};(_;KMVg{e` z_ED6WNY;CzsQOWdl226ZxO3S`dmz*70^#>0z00fsS%Z6$(UD9RE%}grVdgD%HL7(h zO47|8HYqQx+#@6lnv^2qGi)KC#W`qjf7guNZ8hu2wLFAVF zTtGIMEdMx|+(Ac!AqJcqAHl`Wlyc%^6a`W~OLIvw6=eNlOAUOv)VVmCcw)*5G67te+H3we}*FZBYRPYSF zn2jVIq6TMM8ALfGT zbVN-9ISbh+fLUnMY4nP6l)PbX4P0MDo$G{IRQmat z*qke~a|vcdNqQ&n|Jm4m8n-8&e?me^e#a0HiU6tCD*N&OmZQ@di&sd%_gBL!IuM?f z@dYMw6!^&DrnY`4X4<$3Tx6BmsWdILLSb_??iNQmxX*byMds*Sj^ZNKJ3N5r4N$fT zOL3ar%V#e;yux~$(B_d)OxB>ZhT|n7Y6AWPn;KTt*qFeEbAQ@c$Xs`1uTJyW_G0us z9dTkj%8W~?+bNbnB|q>Ag0RgdWw4ta#UmV)hbdI)nB_{NfMF^mHTV4|^i?JB3`sv# zO0BL41?7C9#{D!zsa4#a?bA93a367h7i4{IK!bNJ%y%;H4<1-+!av$}scEI57Sei5 zC$y0FZLPj%d26&T#qO8h194CkFjy^3}Ow=9ms7&ATz>`rh8|uHUxJ zy&KP92-%{G9NK6mmZTp#3rj%Z%&Qx6;p^|)m<(=auYm<|W^y;)mvkvv;>5Uf3Mva74t-7Kp2yVvRF7%7go{HFFPDMpXp;{kKmnWX9X&E*eam`7~ zo{$pD$VM^=Mcyp2SRe64S!iSZVJLZC#2{-x}hZ&1Z zz6$FhIPE5_6*Hc!V5tZy(d6(|Qowa3^KDhar@x9}`Xu>m3_*DEHK$g06{xKo7OCn= z@czE17Dl)2vF#OdM^wJL9!#tTxoqYtnxVvAm=rkMY>YA)%Js#y${rW%fLk8+bTPME zzmFVoaZBIulx{A?72F!`s|`Q*$&I}*?S z8I&H6O2yH`V5ACrS84661B2No1WLGuf-4Vp6hTH&mn|Ak9gc$lh2l~wC{fPAzGHF_ zc7nZ5b1}to6)A^po4_{eL_;sPbi#7EH3JTcwn0L(Z@B3MSH94f8#MuBr-bmhCyoP->Ka{DVNin$W6cpKF&w%YGmg7n0ne%O z^3z6}2c{r&wwL2YGlk;CIem<F!>=C zrXST&HqP7@=t91V>#6e6)1h!_FUqh*e?hDZ|PQppD*;(}WgqEoUh z1EbO1;wtf#{4Q*hD8<2F#W)dJW$+v`5>3`e-VkFN-^;mMJqVbb4`@sqAy1=Hb+uNZ zn$=0sNZIoa>sGlea`pDvDI7*f4dst$K5irhGZ4Sxh6i&LGC!ft5u7h*>P?$UGw`hh z#`qHLNtClumZ|mHNjU8o67LS{%@M}3b0Y^TD)aUgVmSu7Rzq6Ns$W$NB|fo+E>v|rO=-uZZYd$p)?Z7FZV{PBD0?c`#AK06S2Cu} z#9S#9Mb{*x8Jhx8KC{D8wW@9!v?XaF?cRIU9DS2C2vZwB;?bo<>qbQx>)lT_U5nsqQ;C=A$SK2c8aLiDR6w_0FuE zWKq}!-u1h4q2v9-dC}SW<}ok5-2U@aTSkh2sr5@H5~0 z2(sTX-)7~qM%NAdDpA-mgI;uls$oVu?IyU8y&yM=k4_vLoo^o4_(h~v4Q0Ad;^MOni;vmwLIKS z?yeXdnlr2f4Cd1`XG8K_qRv^5P*}@g^hV?1DK<$lfUJ}M!s30pc*3bc7P?NO!B+iT z!sC?+p)jtPxM!L5g^u}p*lR6nj7s8pH+eOq^ArJ2_a)Hs9tR(LD5*$%NpFSkos!KO zy${0W&fVX#4m_Nz9XPR!;0j216S9kf+%18>n8(nvr{H7^X{Yb z9X#BUk2fc%XhtRr-B)Tk#CawO_VHm7N7BT8T%_3he#32N?&#B=?nialUu_?KT zMpZ8;2|;gJLC750Y=gac?j*`M2@mcXo1+VO^u{F|?nxrXkPUOzF_z`M5Uj_?m``9X zc-aRUC-td{c1ETR6-Mpq0j^;<_F8ulG_Bs0w0;{}CV1P5ChZayi^3%oTkgb4dp za1$n#=DgWun&T|zJGsD`unUw93-j2ABb~CS4wftzmTO8kObr{6SULX4e0w_`oxn(A zUd%C2!oo3xK9!CF87jn%UcqRit;%@zO3Z;&_O3bM`77Ptl1n$`xP;(Z?6m>Q_I9~l zD%3Yhd9JR+>>a|O8h<~!=^}KClQ7mq!c!hOPT316^=;g7-i9tyT2$f)8Wlu|1xI4y zed+Af-G35aX;>QF7r5duHH(Y+X}#wYPA(*jNkojj>_t>mH@VKD_-`FS3TJDatIL#$ zOfyM!U#Q8APKq0id_6z3Xi+L5p^dNZC6#0%fP8yBI(P3Vzs8Dod4zmQM6SfHQ0h&h z((7)E^3+LejmBf0)~lHI^*p%(21L#r?35t1%9!g7#VhSIs4NhPV7+q!mmZ+EZdcsObZ>^|dr_ zRB_JLvtd(;*zl>sQdQvZ_=g=sB81@J_~~p?adzZX$;7%K}8BCq1vb~*Ws(ZMC);<kOqZE;H3px-KPn66ZNJBFF7m9XssB1f= z$9d6MiTccgqm5*|8Y@z}$#^`F1m}c#Rtl7i&}JSK)3H6%L=j--DlxrLI@&jx}YbL1$?Ypk0qB}fZhD#kGnoNHWFic1$gR<@c)$8!Rr zY1@a1$$XltUB;Q~YZ0|ChO^v6~R&srUvjq{y z%un}VGLuHp2MR!>eM>2j_%ckP($a1|YbY#Ojs#xgg@+jFmcbC)mk_vMLS4i}kW3&X zn+XM-IzsVb%rlcqIC~kcidb%uV2qtWV7aSsF9i7;^9WFWGP$=VJXo~(hI^O^Xe9fj z;;VG(c)Z(L(w^x=QXOQd$?geIbMKh+k<8pPUV^rH-rTNr$T0R<`o`Oy-Z}8Tlv$jr zPaHUFaThElQ6olOcdMf`5SbJ`^b#tb*jfa~{&7oYsb1YYEm<~nCYRGBG%NsH>uR&z zGuMe@H-n=|aG*%OCYIr8rMyJke3`a{U&@y22bj6W881<2G84-v;bsbje`AsGOG);K zesM0te^nrq2sO|nf8W%A_+^H+1sC9di5hoh3lxn3?%>|AG#j2S+LqCA)gj|uGYlAe zVGJX+&T+6Rrp3+3!IBH_>09A^P{r68Ruj^{Lb=ckv|zZQ=|D=%VH^(SwC{&^K5#r0 zE)^!*ZZpA~wlq%&TKF3D7%NjNa?mFqIG)3rSYv8}`7aWJRR=1KI8TF?XM!f90@@*K zbYo7fkrO>K1R@c3PJQ%O&u#Q2L1$xvMbTMjtcV*hbO6{Qi4NIV<;jHGvODwFxgSyVQUxWyfj$l!Up3mJ^$bYeqy_(2q`X> zn1qsf|4+i=rZ-&vLT6#G!~i*F#LK%ujLP;Rga?H}Z}nR`B&!?PxsmPhqw@f!Uf!7v zKiXJncbfpgM|t~Y2&+4Z>T5l<80doxW!$of!iP9=JcDV!Y%BIXTC zCGWvq3KG3EcPJRYur=|l;&hy8TCoWI42hzcKXBnIcjZPCr0kIidk`l5(DX3lf|1YC zdS;#j{uM1yj_SSlikehgHagvh(b9}N7dIRs2RFu*pncD6YUxp@nmm6DfmaX(JowC$ zwFM~(JR_kdNJ!1nj~Qtq;K7ce>=uRkHOh)h9mz@X+JhY#{OAIry`JZh5R*)}E*Yi< zd3!BVS@maDxy;0Jbn`kkvvB$*-kQ12atFhmj4`9vB6rxVF^rXB5wm;KVHN<4uKJL= zaZ<>|bRq#JfpR%L)3nQ9tdkt&5?p+4dk%Q&YHe%hsK=F=F`Fh|JV&Wg%cM%CL8>sQ z>|FXjN-4?CrK2cNIzf-?A*If|@4Qfac)TD7x8`QEW#GymR%gS5wq;4t+0NywgYDQX z+diG1fk>nuLUb`LJ3rtb=K^DA0TqM_XgIfwf2h!VzL zZQr?O&ARQ|^^O{*99(%SCojsZ2DV$dffDGE^FgvHljQ8a2qL$*C_=rNVS!ycHwv6@BRs0Q~$1z_P3 zl~}TF;CAych8a);h$7lk0tHHnt(wJa2!u65LqgQ7;2e*|bv)F};C8!i)8pY_(+JF{ zs&xnkgB;F$druB@k1k3=qf|AE$QmaaAU#32X*EMtCg-MlcJxE|4+$O}X0?ms^&9zEi6Z+`Z@ilnzOM6!=dk(SD&1sL?L!Sggs$nXTP+g5=xKVk^$X~wW(>U zJ=|G6_^-7&QBFQqTC`51HiSpzF$nyKc!lxl`tInpSwn=G67+G_0RoNUH5}sV6&^LA z#!E7+zC2=cU3j03vPJa?S7QdTGxLg!aJq>X6$uJd**yxFd1e&V+5?{ zV<2%8t_p(&FjN%gVJ=<)W}I_QVUS`0X1)L~Y)5vyC7l)@m#o z^|%KS6TrKyHg{N9H*EcGP7a(7Z?Z=vUz&EsxC#|Q-z32juc38RBsg7mFo{n{2!nwe z25k9^${Ko}tWDc4YsGD2ax@G&nqDxhWQA$gks<_H9)Gb}tSrpg%;NMpn#Fa@EM93a zi)An37Teg#X^tqiXx=E;NKpiN2whQF9wE(S->F#i1iq+ri2*nC$N^NsmW6ilfth;h zffo2iV{QhshodKy0HQb-!)MNR&$L8ef60!_Jq=0Nj*0vRLIbM>f(k zwaL)Q^w&{-D4MHJa~(CUjJ2dw+xw}pymfOVn{3@MJrhtb3(Y_Z`Jbjm1!1`KdV|_s z4*P5#=o@G8Ky!SBRh)R*m(4!ybt5S~!4&_0+uh8ijZ#8nuX58(w^~i=2i2s0xArw? zof#NFNGh43=}i_@@eDVEq#E+$`TaqDlkRnPZpRBV9)0MD@(IiJh;nY5ICCa8HyCUP z1a-3re2fbTklyV$=QeM`Q?3NU>=QYAj$*K$iNPCY)U>9aU57dM7phfB>%Zn~VEH?* ztKy!0HuS5^hJ5~uwS)1&B=(%;i;nf%On%?)SD@0>ZYw%U`KQ?@p_h0UB$b4$I4 zcNX_--T)6wIa9Bi7A=oVYRM^ldf_3w>!0t;)Gj~gOmQZ9IK%ZzWOmi2uUCe$t2X@R zryg5Q!;5sqRi_+eiV|gOV7#e7MYc6EUl4z-kAWf6*dke-7NpSp(b^*T^KXU=pydl4 z*)yh)Z*QL^wX4yeW6bQzPr+OZ+s`clAPY^z75^HRx{xo-@hCl|2apMCQFHMhVJY!t zdtAN(UINKM3lhANk!3BwTjC8K9_||884FbQf)q?;U`Stpr*5!zg7gI(J~b_q7=Zho z_vgcVmOBgebOjYX!2)>wx#|pv{;$k5_@BJqi~-DGLY4Ufd8S~bxLkmEK#d(iM;_s| zIqpo_P^>8X9+%IKQIhN_Vl2vJp$^HjQ~10CNNIT%{|z0*=THo-=tuH1W zcpniB7BnOU7w?{Fklvh(jVyr7K*5CLgjXsBbDTsbaeSXTY3>ER;V1W}_2AZ-dhljs zbnGRp*c>yYsGxVqqj<)a&(68zslX06@!;U0McGM)6csd?NCdjzN?vb18<4Ftb>}Zj z0LgONRuCCyPw{v#eQRF+io~;+@;%lpGUf`Qu&m;wRw{lJMt3>$@g(>?K2M~}5ZfPb zFweC2$Yy}SYF4ozA)bnweM+1W9OWL?PPFUEWAkZCgc690U>+W5gEg20H7WsS+2MF# z+ftY&*pkDV#L^_7fKn2q88+mg?1Zz3PBaPVa=|P2WX#(_X1w0m&XDeJWvx=X3sEuX zYw2~2TWK3W=9)^l;egUoCR7)i3AqKgAdp4z#7rt={X=$+7kyv}^{K(sHMsn7LbJGj z| zkC4Laj~s=m`#K6SIS=0N!?`-HB!Q;Gf>%kDPQW+@C`0hVKJW0%Cj_)`KOI73RcM-p z`{DD;oaGSs%xy{V%Vo~W5v1+OeBfUaN^ztJfYXnk8$;bOvsSV;0qCU`-L}fnBU0B1p-!q%ZqQx zH5_rhe4w@zPJh#pbTby2MevA2Lk{9e`h6BLR57@*Fi{H@OhmH0ta0r%NFbb6eRw{T zU!rl#_AQvKip3wK!oirMV9+!-27?16g0RYFADy|OE5!H?I7=_WaKG)nan34ZGTY{`S5+mf`C7vWjSu`&E6G;JspR05{mjCpsrajBd>FF>H^Z6yVidQ} zF3gBEpRZk!0q@T*&Vpml)MgZK+qKKHYtwdZdr$9LYRJ>G-6P(?)P>p#yL>>9`orb# zFDz7FraoVr6Z_78ExgMD=YF`bM81!G?PBdG7Ro0$_oIbQyFe*6b$Q|H1+jnocI~DG zVE;~Sb&2>u8(9JGh%bzp2k;JI-htSa@7DhFk}Bc?L=OSr~jd@S~dk)-qi*4(14@>x21-CVGmcHwHCs~pC{$0&y%@Js};gqkJVMFhpcC< zkEmi>SEO%%)3;`HLbKJ@qgtAJwC+)O<^9%ViFl>B&_t`;*0X(0!!B(XW}%Dt0^wNM z(YkM0R7LN@$qlNd3r|~XR7>X$*A>8E%KaaSb$zhzF}#)rf26ADq}2dMkYlbccJMx!daWp@kq4J=-r4I}bMwy48@HnsKCpi*a3H(~zff!fuePHLw@JZz_Z>Pd1mrL+Q)cz@^6*rNOiB z?A!nsldS15>aKq`TzVnJ&Wm(^G;akxros8VTMJ{OY3Zr{7vsHA@n8`}kDtir7@`%I%L_XCyfDdrA`_A*Sv5O~uK_GpdSX8C4~@ zZiod|*2Z3Pv^~4|I-|C9LG04uwnr*vLG6`)s7yZoz@u%k2Ohogp>FtiV5M1h+nDTz ziaoW3NnDJB<*l}I`TL|buRuaS^Grr=s?Z3Yn^RA2wdj)n@>sA`$}(u~axYa6mS5zy z(gW#AnEGPYG6Ibc7zDjhukZb2ZHcOK@N`X;df5A=ET!{c@=IAtF~(d!PD-;hAVLkK zVcD4?3YTXq2Ywa#G+hT%^=ZYB`HsaI3MI34uovjvsQCU(6$%YYe@3NxIPuXkrfj*= z`{RyErCwYQXP2u7cS_!SRGrH=?B0K4$R8fS&SMI^Al??%g?EJw`iAJ}2`P)Q$dG3| zglR+f<0+4^wh`AvizCuMj9KOeCt%8NSq9J5+mebs9sy+luX2v~Jmah^{nG*!cQ0#! zV_A0l$&CEel@b=xo4|2ksyaDh*@qVX6730E@g zx$u@Od&(Pa!zJ2SJ7XKps}ZL4+6dG7#t75;S0IeB4M~_coA|~yTCURo8{1ee+SoAb z0HecAe!r)Gz;J6GXYYQ0WW*crkK#0esS2Ae11t+{x^%dBu1GiM&YY{$A0`*r8r9@G zShloApO*fVrRu@k-1ev{=FLt$N)IHfVwZoL`&G-S$0u@P-6N}SvB18UGBe?!yn-8{ z@4H!*FtlfKEnJLbtbot#nLI0Nfk~WPej?kUfLnZd_3Gio5?i@?uzZ#q)Lfi=yhxWI zlbhUn$1ki&`$tvh#PhcG>fy{UZ@iBln2dGj*uE95ileSd)g?(jFpM{|dRDeN7@flh z>b18xWU5{#U1L|}8#cli$03>qWPD`YGvSaR#~Doacmor2_%-aA@Qkf&MaiMsK`uA7 zRgY2ZyuGjwyszK*coJW)L-Q7Qr|K2aHA5<&)jd0U-P<>UE9w41MTE!Qhm@KF$H_~?;bMsE%I(VG+ z4)EOG3Rerbzq`6Px@%J#E~oIZsg2gXV{Cal&esvR(paUj-$z_{$UwunfH}=V{(eg4 z>Tx*uBw%C8w1o%h7j_^lC(kb`fQeNJ1IB*m&=@extapvjDBOf0L%7icE_mjSSyP)C zw;VC#2xFBdc?&L$FD-_0ztt|tqqxUF#W#&!iGWKaqkK4Kqu|vDI2(8leHMydb$Aj% zS2UiH0decp)zXISrWh`M7+fnol#+A3W}f0EHby8dD^|`1WqAvOqJgD;O?EU9uCyn? zQ86;>1lt)#{^IP~irn$WSf5DCfoWP)GAtr>%?vviGR)EgY7+bZMrNSmW&5>4j#hcn~08qhYj+2Czu?RVTDLL8X9K^)l@ z6^Tp9zee^QR}UR<-cnoyZ!6DBhqMCwV))$+wh|iy0xp-W1ul-KrNU!3*^=@VZ;lKM zhdd*m{x%0nW+$9mkyj3xUoXmlvY*wJ!r2E?GGXsKTQdZdGdcCS@Uzpq7sE@J>IzE) ze$^P@azr{OIj*=-dUgQwvSzO7EP{OxXqoGTfgZvu<#0C$!w@6XsE!9JYNZz)y4tPa zmlZo3@D^;B6WrdN<#y3wnEFIPfk~^!PggnVucoApNR7ExqGo2j5GvT9^5Yw5SrO#| z;hI`l-V)bBm{P0KkMPzSsba7tOlUF#V%(dBo0l9C0K zoqON8=bn4+Irp3!TtF5ShTJ13DCtFKy!SIjPYzc~8gZ6Hy)dboAs{_K-wu5yd~dEk zxbP~WphwwsU|!ADT{W1FDMvH@yPy;}{c?K5OfniU{W?A--b+>}7T4KRyd(F12l;@} z)rH1rj!wJ7BM;B}dC5@nO8Q(0U|*a*OZv<3+w}R+f5JbP;4u(JWA#&2*#*uGIvtcO z(M?r4A9{BNrb6#s!s1}bbdMLrC>MhBQTiC@x6jf+w=iSogazyCt)yD9bKt=xk#R8C zxIE-KGV+17*#gOm1feK0i~ePnl&jK2wOHNz$(0LA$BI>E!?<*o_Kp_m6o>K29K@PR z7FUXQF{hHI((JdM%8R9|Umg-Jf0LgyJc|c>wg)CcS|X0YT%vnbu47uI+bJ$Q8}bVu zFqalaf>^7Il*{Z3^hwBYG zzKN>kFwz&90+zKpKe{F+HbxTUttsNCX-rna#KuVRSJ(Kp7=8F+_NhqFs!x@^6qW0E zc2t}t+iPmTr(B;5r(RBvf-L*;M6WR2PSy?U*t>qbV<$K(z?V=r>J#ByranMw+_@t= zIZ#+AbkbFZHdW3=0MKZqC+5~3Zbn$5txv`aMFTr5J?lS!aw0<0Yyc0 zYr(A=49A7J^JG$-x(Vv^q~kHJXxiWD`%a$@fjgo zo0Bg!no;LCV3*=aP&){noy-l=BzYY#GXyCOLmB!Cy0#O`3d85gi^OePo>J%bu*!5& zAZ%B3M*^#YCdalZJ~;7?qFP?b-BvSICDYsKXX4pcAfzb(ak3B2)@SnC2y*J$ivVdM zT}LSZDo^{zoG!yPGxkpUdT(A|PW}!!w|90$xe%JC4IRAcnLk#;2 zx2suhrk{~ctEZovwd{M#>Z|lco|*|a=Man z4rO9#kx7icAB&NlY;Jr`807;oEZBK$20UG^_tjCg%asKaZ=I>+65*XZU&tO1{M5q9 z>6gM&VX(wF$9sk#Y91g$gx;(1QOFR(+l?=HdmthNpa{`=_EeEsAx5xPAr<-r{=ukH zBS(j(spJUOgozO>r>9OAvlv(16+{RMk}g!Q2thf($YcJA5FeWn$hdVZW5tuXHJD>F zmcp65>`)kt%b2rF7N5Klxz{GnnS+wVY5$VsPEKZX2?X4Ww&tgDuAr<>EgG8V+IU+msR5EP%0$16_F&9UM_$Z_b>rr_rII@LD4!CNru&^dhs2s>oTV7scdBSn%x z)f;i_-t37ro9t88T%13trn|u-6Sn%GGP!2+G&M7c)R4&;=QIKX-TiawaOdiE>1M)U zm44|*x!)%wWqd1@t>_Qp%;JTe`mz}?c$dE)nD^!{^eKR_1^PI6w;?+S$`;^Z|MJ6m znUM9e-oIMX6i9?7X*?(mqvQFsyjN1u(o^VFTJM)gFo~o|-v7PYreT?T=PZ<$3o*A* zn)PmmXl|o>mRH$*X&K6lMEl^+zJ+p+K$etGA@9T+qfd{Za%1KX{WGEBhxpg(1Y;x- zME&4TZ{=pe<@Un-={3}nRt|>V2ucQc#t^*2d!d=U&$u*iih~q8V&tVb$t5;Bd25oQ z;>z0%@4|4^UF3SZfG~6Z0yuYjWB?sw(NzO5Oc*2CQGjx>iy3-9NJ=zDaSJLDIO!*O z=VWOfTpDsDK+X$ug24FuApfrEsfZ~zr_yCi5`u7fa`IQGg^=szNlP4$rYIlb1knEx z?+_FpP_K7o98aT5`7r(GUZMX+M(&ffC?BQ|S;;ijH&UhGslKz}*&k9EgHf9<>U4i( zqTZ{+hrTl*b7g7l!%JWi`M-xBI%Enp zDui|HqWbmeze25t#;lBqZ+942qBSogjR7zP#d3@F z(1PTCR!wQ7hD5RGGc%BF4T(i_An|2=B;2?uI08cT5#eXw30gb@j6aFahvC_=-6(|& z+P6l}$UrT|*`6o}yH%GnMa!|+*?JJ#^52KWfs5aVe>@Z7w?arsX(!~1k0#^0!+6f2 z33NN;DSRq9HOu25R!Txhs3gabZ}?bjua4bHRh!29dUfgSlM;uEvRR^MJd7h~B%_cc zX!LRrN6^5`NRA-W%V7*b;=tO188ZktY7VcA(K=2N=qd!XeenDn<=$^V`NO* z@4`l)`>_93u#Y5dfbA6pVPJnO=>VL!^*q8p2rc2UaB^v3KBtwJ!y>^M6+4IF5HU3u zLOS&Pia@I|gOh6C{@w9#&X`fcfSRHcUSo-&pXt(}ztli4Q&1$f-e-&#b57~}uW)r! zZY~au`#;8S-}XElStl1k<-)@-2 z>J0oOvz;X>_hj(PW%yOO;JjbD_Cba%`YcKK3m?g7-JFG@@ooPf`Lp&oxFs-rKdLBy z_MncEApKmQhjbh@h>dw*{xTxH`yt(Gxv7X_^=IQ0d)`WVM=zH_>;FcskP~9q|LA;l zatdgV7yl4h#d0cNi(JPNiD%c9!{F**I&pL?J?1!**u6RSAo~z;DVXR5d$&5Q# zVjz0H0>NbD=N1O6WyJ)+;>Evb?qwqfTp#gb{BLy?zh$-P7zeMpiSh8{TS$T;$*|p@BAfzfy(cDKN3V*&_)ju9;9dT=oEGmpzv2%w zVEK%+j4-upR90gWwAzcM=}7z_#3Gvi_K!ipI2{qYsWN3QXOPU(vH z>`3T8wkih3I`ldSNnMTPceiOXNtS}~sPQ?l^yg!$HeZ@O}n*TE&ss76s3X8=@f0lpmbuc!jqloZRKGCtRKfg$sKKD{ZBpXwx zvSi&T4u=eHqUXi%O~r8#IwQbuV!;DHNI;S<)#PZE}+YfGlr z{|DV#B*zzWf0Q&=)go`e)V0;x+(Kg;8sReW{$-uD2A@$sNW!st-*coMH;%S0qNx&U z4icwgTQdfR#haI!EF|^DM90qz8VeIU zk)CiTcTby|tr(^Ap#0Ta&^9X6x7krEilDIT8XSY0M%E+`1l8GGi`)V}txYj2Ju659 z;3}}yg$=n=6+R!4CK$5#Y)HVo?qo#S+GKA+kJCEI^GdpH;j+~?4w@)3pa4`alNIqq?4oX8=J=A^uYIVQw5v7n>v-Mp|pbFk>~i4hZrHVkzkouS#?a;xO=e%n4M_ zr%?_`uc(jnhR&MJ_$n^?6d?%-Wl{#dBvoI(5s}Uc5DXg*r5OsvdkcUJ+uM&!1kyr8 zZJLWLT^n&2gX}bXklOgv&IE9tFN~^EA)Dcvo{1%gxh*tOox9$C2=x*^^&v~cHuI^c65a$6@LUP^MltRqkB{xrggF9 z`cW>mt6yoR>6RLCbN5)0Byn;aB!Vs8jS<{Ve59IkW*QIxqtvElL)dQ$A2K6q>AR$a zs8f(0<#@pV(wf^OQ#GzRFZoIFl5xYBuuEWb0tb{l%!O8YdKd)h5z zJ>TF9hP2c<|1Lfo3n*X~7kD=UtE**cUVgq;%*fB5xTP{KPbZYHEL3Rt++7eJdPK&N zl5MTJO14GzqUrDhiO)BL&$yOkFQH(T5(TG|isvj+F0sNjB-Y0U;=P-dl~pY5AByh> zPwl2`$Z4((2Vped7yh~+c+NzTy82#YjzTCGQ7HeMF1V>4osa~}`pv5>+pgaP1J=9< z_+zY25Bi~kg<$@Dq3`L;RZ-JdOT42vg?O&crh>P4Zm8fJAxp_R#<(yT$_j&kHP_%v zPt=zjot^3ke<2Z_h1NEQB!m!M2!5;01%q!Erh_GMkuQAXuZ2mz78=bC!d4WUAm>n; zKZL%AcPx{BSnv$poYAQ|(^^}LVOxm6TqihDu%;rb+>NKv>OuJ$gUh1uEi^l7v6>`$ zQtdSx0f`I120?{wlz7QF>uerL1f^0ZgKz6tPWKkFdhkJQE6ULJ20RFmw=0oR5pYDJ zZ6W6le7hNAwPQ>R;ef-nKMRJxSAc2{?8MB+B$!iNh8Ldi3pHhh<;xsJs1@dkr(k*%Miw;0Y`$Y0cgHW(B< zumWwrs?p}9mdOO-&L>*P3>x%|iiXP0@VHbc;4mm4#Zc`S+rVv+qOze9d&E#2kwye7 zbcR=z;4{`PS1b7zW&Y_u7~`&2W{}UGsv=%4scrVq_BhjZm?T0 zmNb0%14C#Xro*A1zlMbNXOzjw5}$kUN;LQ{t`=&z68Zk6c^%|- zy4Afjj|`fsF5!5OE@Y`{5E3q=*`?NlW(TQ`7Ry$Ah63NJM-QG90t7C-5;JF6W7E{7 zqxKYUJ+stulf9c*ySmgOB@`ULpd!g2^Z7djV?_J@bp zOn}qabOkueaZ#%33kXZbiPCzk8aebmnH4Uu!C2@k!x)Rig0qSDoN(j>4748FBP?XK zNLLeU;@G4PA?zOu!tuQrf+9pc3HoPPDvg6LzDzljMy)5jVhV=Ms}ph~j}*uTp*9!Q zSrpNbX_?4Myo;K2Lw7PCI~blQNQ#u0xGRM)FXXLKyHt2!aq)_4#s|Bu%m;CZ7E24> zz-q!pO4f#@rNx4jYOvUxO~}gfysQj)jk4+r!t&HrSIAtCgkj`$Hz8cZq{@qNfzUOM z=O;CrWc$q2Y?90rQ#uthE@7eF)SE8l^Gtc;t&{_9zP$lJ9Uv!6S)WV!bGn~L#K|uZJ=83(!DlP zg;{H_<$_O^S1wXDadez&#Y+o5Vd@1>Gz-+irWW!#Vefo@e=vT!T?fmaD2SWDF64C# zj*)^zV(^a&{xJhWvWr8Z`&j-g(f*cE@Cimrps(aek{t}iZHS1p6ZI=jHd?3USVFje zfOBU>#3mx19YB32>PNGPj?XPgNo*@+(xbyGGET7@y9HZ)eN!!-(@?U^f|ZvG9UGCB z5HbRs0v?{vnH-vl4-rW$5+j_o93-?yHZr@z8#$JWCAK=~TUopsO8#n$Ct%l*XJnih z93Y=nBmyc~v{-fQa$yA|{-j```0UE!8|M+}*z9tks@g5&VaE;RNcku%ll%n}@(nHv6J_knw3?h;|4k+G&Fiz9BvQZ@x4)57H7>Qg8-i>Q#d@hw>ZjYF#br z39a%b2UrN^c z!0?s=Kd8QLeiDR!yAUJkZ7Ilw>gVlY%*uxMji0ysL-pGwI;pbr&q?UaIKIN~>_Gl` zyhS-wAc*h(wdAL0y+aeA*U;Dd?IeHk4|f*)N@?f|x~Jfg>rVeFX|kQ~@}YuQ=s#4j zK%qT=>5Y9@efdP)!$)i9yY6gK9{l{(Le0)c4#1k75BDx&&eZIDnw^g-yEHqWH>|B3 zgH*Hg{mT}3&CaLU`S7en?hBzn={43|ja6M?=Oc30C(+K=b63G`h%_w-%lrgc_Si?m zjHKf5Yi-Q~l)4kdpMJfd^P@58iFk5&N;BkXhCI!Xry24zL!M^Ho1mH340)(0)eL!> zA0EiE* zi1^UTUdd-q;mw!cvDII^b+GWWYHz;#1O3jPFU07C)bfYUd~aO`=FjY!Y~MTct-_U8 zXWGM>=$QDGS#zM@cjhFYy^q$&H~;p)#hQ^1uNZ62e3~<#=FImmITmToe3~=g)wtPe zMn28R_pciH%qVw#5{-Q5G#v}VSfLT#IusNN51lXcPyU4X@2S5U0+WgZuDQKW7R6_Z z&%IK3!$)KEgPi^T5h7l!6E(}9X8F@Bf12e_v;1k6Kh5&TT>~{2KFx(sbKz6PY0zBw zG#5V2g^xN}YL>r`o#l_X@I9VgIMIdg+;0m5;l7{jiKnqTMdPZXv3=LvLV)nk>GyK7yy_1}}yOMvDTvFA7-$!Lw&p(<477{Jn)uH-33j2!1i2}P z{^A(bq~YHl3>4~OJ3_Tspy&YQ4TY=40wn>lG#^3DM^K9eDl=wv*j>6~Xt6*iN8bH6 z!~zwb3;E=l4^i4Q7I}RuG1zajb-(SC7Y&pk!B;{8yqj1&?^>G@#eXCffAJ$SAXfi6 zB!Wua;?qL~-_)##niWyAB5GDd&5Ed55j88KW<}Hjfl4t=wLqZwj;aKwq`x5Mv@hU%)|Fv)b-8#E^r zs+TXGEj=-aN!@oJS-EMFgW-GgSDx`kBt5xfrT^*A&W@)6NyU?kRyHIlBa52*X8VfI zZd$2&Lh#KkEAPFIHbRr6>IK0Y7OlL>7X)wEu`=%T;qYtxfZ!{)hieZA;`2|M&!P5! zp!R^Ep!pnrxKM}M1A_m=)1I2oq2_b=FZ&##*!79^IYjZ2Js{|G)_xKn5F{v&9}uJ{ z__sVDh%)&{^MD|}kbsYNYi|c?ZwG2`2WoEz9)Y6>|8!s9Dfmk*-It| zNd3*dM&tAWQYZR0_I}EkcWr$ezZx8wr};Lbol^5{)O;JY(5RZ3QZrLp)IRxzU7ByB z=G*AB);4(#re-zRJSpr6&{U#Ozz643AnZ>O5is~zsSeJa4feg}zKy~s)Qa#d4h;< zD1LsTW23n8DbrDvWl&g`FjGA9SJRKBR}+DTLw)QYrcQYJJyRlyiR$(dAODBx1eVty znrtcD@N-ka^p-+p3D%5+mfs5hj;9n?y(466Pbq3{jRBy!HEM2+np>k?vlnXiLL`DT z!RWQhY%w+3G<)IyEqfsbuSaR@6Kga?sk3l}mpq%@9iO~7s00B490C6hmqs8`xmbSL z)bTIJLlu2=C2wj0P_+Q4S^!in0IKHAsM!ZK`=DkY)a-+reNeLxYW6|RKG@LcX>qtc zsTqQ&(PkGKn;IH5`{2jgK3H9uu$nFTeopk@~IXl6mpEI2RIQL`^YXtFnX@Woh5 zt@Zz!S&)cgpIEaXikwCHvQ^CbNwfMn!kYN!_eO1!kHu!e4>Dc%M4FsFV)yF>81xjC zI~dFJUSldaf03^PG!tGAEthZ7L$~iO@gf@Xel!E-EiPE7ceS@$+MC@FW-W;(iA<8X z{9sxFOSIlpOsmn7;l%|B`c2!mS+=d)48u1S$FaotO~py9&3Kz*9!umDo03_==MQu8 zNP>1c`jfB)zET1%y;s2pVEsW_9Bb0rzi2*7R6h~M`|NolY_2>2(ePW}K%Yz;TPBW8 zXlijb+gfaPkJZ!UuxFuNE<3<(ZLzsg4Tt!X2apjM3!x{1LfDY3U+~M6LBfbWntw*( zuU96rVffU9@UQLrR(vWeG5u{z5(8lPLO4g4$v^V*tlIdps>T(rCU-4j!dB~XxUw3H z0|MsP+3K6@Hu~;lo2TB=?rN~2W#46KTi#;m$W8IoG^0wft^-D!d=|j@44rSR#o~oh z>#|urHcLCLOa7M&iTf7hLU)*6e<~y@V5tlXzny@SfU)Kn-ArnmE0tm|8A48K2Hd_- zmp+$ObK5-a%`Mgri;aLtO@&J#`Z>@UruYA6`!IO>SUqhYsUL)xybp(%ynhZcdH)8) zDEp8R^HC#T*+=d*nqXxgi@klUz2XF8EIqmWP)%*X{3d&Cb6cHFD3r*%rpeP{wKq9& znZRhGj`IMY89L4#&JD#ZVoPjbD4i#IX6Uk5No#!aBDO|NP5#L&Va-{7JF8|54>&>+ zgjb2uP7;qn3WClz0&DL>->+{2O&Tvf+#&8bOv(Cgnd}LMNZ5+VMx-~2@@Y;%_Btdzs zDMI&b*Zc|C6>tafw7KjI<+aT%ZOxXYc_|dn?)@1;XG&X>-Lo{$;z`ZHV2AT<%}N;U zI7O3yw70ZdI#T3WY^N}3av5cFSn9TPSlX86A?INIAeF27$`A~xQh)fkx%KjjJALQd z>~&4`kh9TL$i9l;HN?9QSxU;btT%100E6!>a~TrG58$*S66m%ybUcsmC)U@(IK}uJ z_2(!xeJ`BtCy;PM$Y&XVJ|%vK>LXufBkAjjPE1hZx7||T)M2Yb7&11JprEgIWZBErV~g-kIYKNF zWZHtU_T*SdXqu__qK8qB0*fCRzNP{$53);|jw@mCgAjNn@DlVZVDtm0XDa9n$I}vE zQITNCU5*sOXk_9v7?xT*NJ47_^%7T+F+#~*vh+$&7UxnZ0{CRC3h$a~tO6T~m+~p9 zI|zp%^d*riNn9;~$uq}MD*+RPE}39)P{LKi^CI(V&~Sw>AYJ13|1+zXP>1{p@)r<< zeCRLevNgMH6S%?zL=!Ia(T#EfV@SU;&tizCe0`u@w+Mua=PRU#}XogAuw7W1n(@<#px&zFc@^XaIQTt0M4w``9?9? zY^iN_Sz0VL%Ttgur^3*Z$OH&|CME>pf1f@N22c9qtM31u7vhC75Rowle&1ge1aFL` z&yDkrZ(&NRa9G|S1y2gdQlJlG&XgkW7#zRKuhKM7uQ%DMJz!2ptg;fsIF_vtY0_G6I^$(}N4h zf+`jq{L4^GzPo*b@}G*4rbJ433PAs{_K-wu5yd~dEkxbP~W;K_VCFt6t7 zt{P0ol%pB{T~G>~emOm2CK(NwejOhZ?y!f331sw%s{xk0Cck|nySO6NoG&cIaY zy-QdejO$ri(3HW$`6zu1^xJ3Ypj((RbHal4m39I3ik$-wE{TkT!N%nw*O8GAtj!ik zRwM{Tky-RFv%9IKZn<}&TCDEJUK&4t6b`KV1ZuXy;S@?ECC)Y*3FfHgf7IhcE~*?e%XkKJqpgl z05{u~do=*kI!2nts;OXoDn9%4`Ql)3URdQ%7YDrmUQ9v?ACkjmkre}igge!880m{l z0n1vQA6*j@8zTww)|7!v)0nJ;iH(usudeZHG5YYu>{F4TRi7$-X@PJA&yI?-WP42w z_>}9D;nd6NQIKU{p6C^(+sV3N9edZ0ckBdb1p=Jes857*nfd^!ap#WgL#eaTM9y+-XFT(3!DjuUAiE+f7UGj(}yB-@MM)fuAFu1Zf>fxwK@4xqZxIM z1NIc$>)I`~jcs;mS!HgJCMiQEFewc~8TtykwiC+=!{^D1#BE!iQs?%t%5+j7Y*%zg z0;^)Jt81I$gA?y4s^yj3Z8cL>GQFLCCZ2r-LYe{)C;Q-ReI~DsAg8Xq2#^-ib(8|2 z^0a@<=`vh1WACJ|_vZEG|-{Sl%7|YGiR90=6vTEYa?8-DQ ziLkFi(4J{PS7uLHzhSESxEPKEK;^qJQQ%ysTO%zfco73X4)->Ccq;=}#**OLm2{zee zx7K=^+HHbO(jX%b^*DqUtEaY6Fm2nBiKlL%#@1+UZ*sW6dN{JsPnJWW^?dyNF0zZ@ z;>TTu=&aoPQG?P+{zWBo9xoZZtk%)ubS2{) z%EZzllUS{z&F--{>^64_=^<4N3w9ox0Z*6feRWjra%I89TSs-0@X95^J9)m4Js|k0 zg_F}Sg{Q(`iE)ni3_%n#K!garSL36QA%?dbU-0%oLlBC|q_V68$b^a=cf zQKd$X4oy?Z5v&OlBUnyPoi1iEuDUCT5ELZkVqOt~a)6P?{1YKQHY1R6>sZE$Cv$5s z$7U>rGkMveFc_CHXPGQMc_s3EYUWTJgp?#s`NR*0*WnAwUY3N7?1 z1&f6S82x)p#1aW6ku<%E7D2d*reT?T=PZ<$3o*A*nx(L)QIGCfUS;>CWhgTe?Snu2 z7Ro&WSyDcQyc2JXK0SiUjhR36&xDE};$N#1jFChT^@BgXm74{Z+Y9rj*HBAZIT(5) zC>h`xL+}oF6Mc-qj+@WYyeSS+?1+(<;`F#O1bZqTL?|kz!?2`1gu8dNKb0NX zl2Yz!C<0=4sgQWUm^%UP>JJZBaZr;1n^KL5u!voT;LZ;Opgov zBFWGf1Jjt5G4bsV1532#Wu!3xrl44Eu^w8G+|Q~hjnt4R7JX(0vaKPpXbvR4tdE2n zHw8yPs6Hb6>^nh=XMpi1(fKeuJGL98kU{&_=ouNP#W>p&1!1@9a;9iG7CT!HLR`|yuvLi|<;DJgg(sYqCqv?x`$0na%!v3s{7wHWP^Ssn+mQj+C>O7bIk6B7)* zI(kut8m3jI@xESNI{T!=;i7Do=ot^=2pY*K}t8K+BxBabG1H&!VSv^2S`%}otz&okm=`)7Twr0mDDS6XUqqt%6yHnEvf)w{h8Y`+T|f$qcpTfsh(v;nqP6oi5O zv7`fV-q!O7`yfPPESy|gn9phD<*-O_M#auyI7Cd%g^&(Czar3T%t)h8Ml(30gWdRa z^wT93EGI0v;V@vd1&kniDF0@bjTO_>uSnDRA=nj7qa~w0tmeq8g;DfDX_gaqk8v&t zzbtu9l_O?X75K4cV&eU#?^0_$oiN(OI94dY<-3gm%66OJ;$233-}=Y8KyXDAucRR- zlojT}q;?{L`vU6*fpJF6?9E^yAdD4%S8lN?Ononjzrrlm<^@hJadd!R>Li)#801dhxIc zTAjw&$>{f`i8@PZ;fTZoaKy+pFeEx2tibaHMwL@!$k2bw&M z!WtK9(GX-^xw{J+dLK^3D=+y3sv(PqNs)k|w=~{tp_(?l*;?OZs}ssMZ`|O$CgZZz zH)Amlfwa!e63oahaTsLuSmtn{dd}^wtLT|l*W&dPw05ycvI!|IZD7u%}z_j-Q}sB3E(_m7*#cafgwpFt)-@Bc*T8T3wdv2~HOFtXJepC36*~{uJ``ixuN4DlRWoHYUJvOIc$QQii zCrBMn+9i;(-JZJqd@ngMLMG}!N(hu?;EDCplllMG19SL!k17G5)ZiRSkyR36i@a>h ziA*>?RV7_jC=z#n6Ede9FQECloK3w=*#u8NwzTH+nW^a?#aZK7=dm=^Ry3;Ll2 z{m_DbXhA=;pdVV$4=w127W6~90s*6^GQ-31(A(6EdJqe_?wo;l*xdUeyHgh#C8XnF zSy4tE{Ltaf(5Z{)!a@tx0DGG3mRipt>BzP~>hKi#f_ zWlt2uO<)(zj#{d|1jk6hA~E{%*Z{S!SwxZH7B-iyUoAKtZj1^^w4zOjQS<`D z=Cpg8(AwsZlySr$gvV-|%PrXI>zitu5FyP6vtZ@rLdQl4sR(cic&KEl(}I3zK|i#h zAD^(GAM#NfdLE8k!rurW!9P~BvfexElhlUaflujTNHKMk?s+>amLVo>`)+?==b`UeMWIYZ2`7zvU0&>RVR*@l)6M-GXmkCl(#n z&Bl9l=Dm?HXx^)Xu@1fNcu4AM{9TW~HTYYLzf$~_;jdf_Nv&vGrzabhwH_oAQF*|HRlSi=DBa;@$eLhM1h`gDq9Nh?^&YOq3X*~vf zsYMNBw^)$?H?~zYlf7Y+1crCCEQ4@+V(DtPq1Lqy1B6&zbc?XsQ3;Fp6CEzA>mX67 zlYN5>!rFkYo&@Z?DBLio>J@wr#utc#PW$_zcvXLGgm}?s%Xr|m|H`DK6FvXtuLS(c zrDEv(6NgHmdrN6O^xn2Q1Ug6Uv!VaGiZGH42IJ|~v!VKP<%Q7yTtz4Z>*|A!pM0(Y zf9vqK9)BC~w-JA4{8i#_lX&vE&0mkc_9*+$5yr)%>jU8R%*voo26dbs&s+w=Uk)Tf zf8WNr5SqFtKq8Yz_3QHpail}{`|Bg1w|AqClm=2V0f%9;H!tTI`_hSRg|5w2ti|2n ze8s%@c<7cbV(6Bwy8^B;x07CJN%cAYK=oGqZNuMo{O!PB75;YOZ@< zmb=0Nj}M#o;?IJ=YW!L8SA)M={MCuWX4{%gA7>iBxXj`&-v1rj8z28IJg2i}AN0?x z4~E`Fd%~grO-uN3Op5(88}z=(SLJm<95!;$mjkcRZ`iutvZ{3JhKkL?O0*fESE_p# zmh3@iamj&vOK}Qy!U%xY7aVb-`R(vKaZQ-_W@GUcy!F~o`+rUxuFh%=fUlhMd_u%wIM?ZEhOsiIQjpl#>5gD|UO|FL z#-~RW`Ceh-@?g8SE)|RseM+Iaf98QI2I+3`hXnd zes+0+MBgE&mP@Y|g42`{!?`&8%+h?uud;_KipG;?-+h1Nq0Qo_aOcb;qNg1ZouCW{B`25OU(D}K34K^UMuI89oE4* z-_B3OS~*+-gGEQIFlImKRV;Mha43W%WyQjSUHNeCzHUje0FM?Q2@x?l{N6Ptc=k-E z#Lyq=@mIXnNu`#YFUI>FfB2yu{N0GZqxkz2{%*qGG5j4DAAacOUzUE1DOJpgJn@&0 zxzxPncVND!o(2$={AZMboge*t2lWV{y50vqyNbt06+XR6V0v4hTUX6viJW`udALk1 zu(K5US_|wMaZSqtne`R8hZowdNu zA3hK^+lUlVqvi0xT43j^iD)c`*X2RW(3niZFld3DrI0%ofg>HiwiBV zGsY?>tAjic!NNE*F@oi2ft|I$&eEHr$`F`}V9{D&XDzTZD)zL%&RSq+WngJ7urq49 z<)_)Sz|LA=XA&`53+$`~c9vdil%6bRitqo+ft@R79K4=+=8pVf?IP%QZ)Gu^MU3g3 z#UuX?^fl*Axai8-8vdtrA-m>kWo^VuoA)NO6pWdiG*mZ@$JMJp_!uuT46JKs(8kjm ziddrcmg+^|%(yWEvhP^8OwRu9sAstkoFs&u4jVxg*YUq#?;?S*Iqu6(f z<7d~suu(39)^A%jv4nMOYaI07w%VWNBtGTK@AzSHsazrs^){^MUxl6Lz(wal#c-;Q zErDMD^@{k>zcpuwCtDA`#>N6YtFMnf8?^o>9vQ59Jc#o-u=2+B9I9$OiI3onId^TN z51dmR^<^Hzz~5olk8pUi8aY{x%xbJ;@wCOtyL9#w*n^B{uTFd6Pky0&d7A zAZ9`TOAVpCug)Fw#o(0d8~7&}-q?o0a7(QZfHCv>E>_dfvSYoR5C>8kJNXO`)VP}D zA{d#s&%qL-E8J#yI^fV@mV-o;4#L^>`2Nn3Z5#{8UKWCLZEFduNSKB=wzjp6&576- zbSQTguQ0H#7_fprTz=-p#Vk9l$-?K@de1iWRs7Dn1u*#fjWmcoT~y=SS{-coA`skpHA8chq6nmmK%w=PNp653tiRN>b_3^BU zdO+pQ1o-)xL(_1Sp5L^Vv4$gAYhz*fx{BFiZ`INJ`KSv2|-=JZws`9k-F z)~~Sa*2f!{vjnB$u|JlDLd%~mxh$LRf5V^K;4eP<)9e4iIuS>HcD;)+67@`v?B7mb z`IrK!OI?h<#l*xlOBg)pDzE0?a4bup>u-lRCmP>TlObOC+aU$PnQqvZCk~27e?YHg z)6P_=r2D1WRXq*;)8c+tHJ{+Vjr-@q>#ph%{_!szWsy4}5w^d@O0L9WKY*ol2UaaQ zTj!d|zuho?^j#UU*kfKZPf^ssF$RbhbjNp=hQqm6j&gpAxXFZbjV^yNyV2FnX^kSN z|48*}PE0BU^|@RN_pi@g(LvT6ppaMk-^IOU_87-WH~b3aw$|P5CG0>7MT6kCb0&% z>(?j~@uy!typm-M{L;-!ahqnlEcA8m*vYElmd@u71%d`vLfEW`8}=_b%9WcnjQ{oU zd#v)b3robkdW1tT)ou}>cfs0e=De?U$2tbHuc0g+f^B7U!MV~W5JERv|C^P4n8_D$ z@*`)krXROCB0|;c(0|XyU$ak~I8U`;zj4O^E571n9rpoa<(gy|e0D=1e7VNT_iwuR z2lMs?GeE88n^%IR*2=fkfm&-GUxFxj%oTgLxWCULB17d7cO`2-{&aI3to-(lX#@{i z?0j(}6FkI`hP7r+Oarz1*x3v!Kh?ejzPu?AeLNrOjD!naZqB5r(0A^ojliftOg!pt zoW%yB;!BC&ZV3nb<2$CIQCe*7b#uOS>G2)E;G;smGY@X~tb3F}r-zM)@3h{^aw_k# z^6lMVF)xMRJh5ZK&Tf3e>Mv&9ZM}`*Q^alK*ZhlBgT@1AB;@#3@sC#VE$d5o0_^gw zVuOZ}XK#pr!B?z5W`pXmcY3jGvm9U;vqd7Zfap5RZIxcP|HiM zDBO#0{@(gHN9kx#)nDb7;%IQy2%AS3G2EOF&bpiUcZc16!y&mcP#MX2-wm@N^OrY% z0r0Od@#6oi1qNH}yWkf2fkA~+>*(5fr{A?sLkFZ3oUsa&Vot0$yvm%&paUhAN3AzK z&PIflzRMCl@m2hERat&>0$l!^^-fkil2FANI+X&uGxy*r>gzYqaAx$-G4S(!w=2+r zCw(#J{u@@ZA&8;RujNvUSh?>eo`MU%+}Fr^`}NuymKfS-wy*@Hp8glta^8$08fX4= zr*`_*B(Mgpe{pka#@75Cg)&sQ_>Gs=I{5$-FRU$RDG1wYzKOxXQACNiXI3es(Z28B zaDtWNFrvhZFRxXUBa4VY@~k?@DpmfaA_n#us_5HdR2Uryt^rnz+f0JEH>9RWF^2Lz zbK&AHGnbiU49o=c%lnd8TXWl%VyJ%f2L7nth0AUQM#=HBe@WFAxdCdBzRtN$g8RfA zh}(BIy`xfrg|SkW9* z8j;8v2d(j_4i4!s_EqyLxmZNu_(z<#jdWGr#G8(Mze^$B8;(Rke~X8ortv($<(aS+ z&mtKpgnhLt9KMus#K3YAy{)&i9IV5aRnN9k&J=0guY9%2$?8rn?%rO?36wT?)8Y9N zYd~}MY~Ii5FA>V;D~luHGgYOWMNKUJ9X!u+1k!O@S z5wP+Z^Rq0+(BMLS&)2KCY)g+V=Dnp`Ssi*}3EjCrNE}{r9IDJ zW|APf-nTD^q>7JE|Hd56fU35l%9{PDti-3=!p0B2ag28g{aD7SFXc_smUO^=T_c%h1M4@ zRSisA90%wBRMmNf;`Mha7O$kLaFlU!u`Z~LhW1D+}D~{cx zOvFQitBmtx+F?v;NG^o)Y<*tEY-tUdFL4j{T~nC z%P0^m;{+|`Bv*clwIBLoWhP5t@mZD_{fUQp6|1SVYu{OmOzGqc8!Pj^WBN&I6`(_X&IXzE1e0&p*z3H;HYL72M_@{ zVLSQqP;GgnSVRzl4{MG`RQ@KZskyTd1~1kumy1O_4cx~!vBbzugBWthk#BNNsN%yt z1IN+{wDOipzNUII+xTRuxNv1w8=qiR2|}r2LsY>}tlRm>)FtD$R`OX_ zwV}!~$34for*24#ow;p%uTZr{xER}XbuAz29;;}0@Yq6@z+uMt70P0wVRc(GE4p&Mxv+6t?HX2D?n?*V>1BKfYVc&qu@+%# zltic+#>9GYsFmG$J!{GPT9;YIbuW{57P>w!tZloAHN`pLJ1-_;q3g&_F89+ZO1Qg{ zO9C|KX9TIX9p=Pg`p_OEXlq@l8VwT)FkohVSP#A5nG35~w^M zVhQA%38$Yt#@Ph@;*Y;Gx=W{<&c(;@y#<OxSXRqr z0oq_=Sts9UXih>~8QW;YA>HvAoVGBP0me5g`TjC~Kry4L{bi)1j3b)@zW-p^G+PTT zc0RF_Z!JDg?&Ji8#b_#kwwYl3OQi}0G`pOAFr`xGTb1=Jhcb!4KP5^ZGS8{ew zo0{KIh+dPqFQwStFSc;jkCk!RbNpMi zihYKdA(6uegRr}klNf2mKDScI)Kw)arcQf$^ScVBPIKaaP|BAd&6&5jk~4LhFDs*9Z61?OI^5ir30&G8Hb@~tFjInm5d0(8O$PnI2JbyRF2 zOgPTxT2F2WMtz=0Jf0$6tnX~)t7>$-67Pfz*D5sn)CzX-*|OOT2wK7Lx?1oi zE*_y3Y$=TGNb?m}o-X^v3|5oc!*ae*wj!TpsZJb*dpbGcp!I9sZTHu4eGZm#ttP6u z=Y#X6|}f>#jY1wF}Z04z4^Pi zrlRr{j|p;iwJ(6Ntnz5NqS&KvFP+I!qk-)wxjtWoD!fO0B{h3{X;>LS76|;#YH^b(N)f?KM znr3z{{q%SW1Bkb*HnBuv5k{a5DJthu2j-Np;_;`B^V#*;*?uo8k#FkZg{SHkK3Zzs z!V7%9;QZdE)vPupMrU}}gQ_t{i*MTNis$oMV7bF$-sBokF%2T(=7|YeyU|L%TYn0<2Ap!OL10KipR9L|7?3BYmM+?pv&Hs z%5qfjd|undIlHRF`n`6(Qy>)1UR2d+j}JJzxIjL+_|dPF>%sY8JMT%w{V52n!`TYv zM1t`LiUH6%UD-Et$!`4OF0LEF;yM#;*i%<1gxF zDu_sF0ULUyj&n|8W`>Jr%Q>4dh~<2{#l$>#bj{7{Sclj;3;O@Ni}QGE?&kHZ7;V&i zDUIiD{v|8H#6q<_1#Q%O;C8Vp6E1$IrHNG>daj+5E7tiDD+yb=Ig2F-JP}PP3Ue)9 zbTq)Zn#~h9LHDc8sQM$kw!g0{i~*pi>wc|n3um~OX79e04_~!1eO_)^z?$Nn#$@_x z4$HAV)D;23|5LCqYrA6AVe5U$y8J9iS(x#amKauycT4d-vjaE#LddJ-YvpWl^aovk z;FC;QO8>VzL*UKV%XQ-5;hXy+<*J|>_`s=~Inw02q(!W*VP?fVNSIl{xe4Z!vSMuQ zW{IB5EnMWb>MCwyC76hZ|K7IyyDZ0$XX89hx|q6s_e;v+g|HHC_G3Bx@~YXd;!T!~ zccoWA^(n=i;)UrvFn?+@r%Ajky+o}3!p$2Pe#G(A1E;6ihww&pEExMXbD?YW&YQQh z4oAc6aqwuEog)Nu*faoZ4ZTI>d{NR?gR|{lW^gLQ?R@JQdA_U!s_(g(E0ob0Vu@(k zxBKhY$t^^*JRYF7=@j`D@jy5q(!;>C0QJ7#&zL)V$=tRR(MM~&B2tg*#1~l`yrII` z1K#<-dv%sAe4&qfPW%t6i+73Q;oR>kM3&Q2v*mj%fj2*Y$P#$3XATH;TR2ap7i@Z? z>hEB6P!lr;E*SUV!-#*VILNXS51p{f331@HicEf5lcD0RV#k(skQ3aoiq)(P?3mAM z;w7SJu{W+>aTQAL?oPQ0kV=4+z5vyab@RhI!L=CLvSk(rhsa(iX8pM$o@e2uqhD}H zc*O|f!aMF`ITT1v>y|j)BCLGRx4`^pcQq8hTfz4&88K*7c5FeRxopoZ3<@^6#1eQH z=|+|?yk+lW2`XEg*X^m1bHs1{y!&wl8%I|v@%F8I_|?j@zUz|NVdS*$x(KoRJkdGt$29JWJrypM00QhOd75 z99ox1Iwe8o#ZCUVlspx({gF+(cg%ju6Zk;tf8h_l`s^*~iQ6!<_`Nsh|G%%h|BL(r Y{)_+jwVowd?agOziS=E*>vqil|Fu;5djJ3c delta 8875 zcmeHN3sh6rnr=cuUO++;o_TNpQF#Ooh%bDQgzyOA5y3(gA>l1PAmyQjszj|xTP?&= z`Pa0g(%WhEs#oZE%bxa*n)co<=e9m*X`Q9FweeA>tyR-@s=d8ZXP+cs432fynl;P2 z9M<|+oPY1L&p!X-`~QC*j-wwLwgdYa5qg~;L;M)^^T*EAWp4z&<1fyRdkkZHL{dzu zB6T*Anx2tHW~9$16y!{jOeWUUx3)F4G!yB`Y02sE@?iY5H+zag`aTa?+V|~TfhbQ^ zYFJvPRvWZMi%YacrP{1gc$Z|R%p^!6C532TUf)_zG_?`69j&eP&F!l?iRKn!ZFMKn z-a^#Xx7XLU<2g-jTrNSxHZ}C|LS=nrp&^hKnJNc|Ll@B39;yhz3zcX~vlL}S8BzaK zdwnytqrTfAq21b2LrGZ~k&173EkKlN3pM$r#YKjDY>b#Xl`t4uo7!sE7`oQf)DR07 z5UHf=$8|qJ?Rfk_cxNrGgu1$|sg_VTwJTOvH#eC&R#ms-M|)<+*7f;^@@04rlm^B( zQQutG)IhzC>yN&caLMMwVb;T8Gz>aA9Ojq#7NiA|La>je2vO$=zcfBFeD2poLs!oE z{lO32y5J}5M6;JMex8R!|G@ZR0lb*Z3x^RpGaNZTXEf4bC|$yVO%8?vUZpW3k;B1A zr1u9;<3Q9^h7>+K&)}eq7a4^dN`|m3;3c$aYv%z!q};;1B}dflbZ~~JvaP$fr=s24 z)4o)qk^k_Ajd!NeLcu8)N5ar1HWN-*Sz86(<Er~1{Q@Tf_;Cgq=zC{nfz!_8LH8kECYW|+?uFvt^Mv4#aq+Jo(q>YZEXaJt zC<8-R1`F{O5{1mPspao)p(f-=-LXRGvxU(6m4E{{Rx$uzve1B&zw42W8W^w$a_@wV zHNH`R;v0kMAE6iL2oFbFs^<(>&%L3BW4C8Z(e0h0e`}-$-orE}7aw_awI)!8WP#&p zHVXzSqYI$7Ma%?+K^WX$6&+(ewL^?f?Fbn-Msc-YG4(r|hxnH}3pt<<2*-^5`aBtO zuF5#d9*^;T83ERc6QQW$L|E5;-`nPM+|GOOvk0l%Z}DGjAe`Z>erM-=IC6-$9n8%c zY%pF47sJSHKIXgaED^Gu3m>k3^ti#353Wb#c$r9^j8&%pIgA13&mtndGQ*G*4`9Vf zthU7w$hJ6gx7~|m5vKJEQY+5K*i_Pn0iU5OBDZOj9a07&u1Gr`-H>p6FI@l*lQ;^T z4T8CFeV&XB%6T#=n5v@1@Y_5|5SS8Vp;Xpo!$3s<+banV1j$lC|CX4GzIZb(jNZRc zCPU;Ht5yo`RV@My;5lsgX5|ahf&3^g8TRH$_@Ez?3c&nPTm}4eL6!vekK-cIwGGi{ zXjbDhGGu&4er_8TOtExOS~8=77~si4+N4X)7S()&xaOsi;46cWuL9(UDf_gt(x-0cVC9&HeiRneaOLM_&>h{{AoUlHh$ zjYJsO7MLxJSp_&}?D!8DBN$i5)H`$<04{+#*Y!m$`z z{bLwVG#H=o01Xhr4baEo|KI&k-PVJ5Ke+3m{SuCJ7ZYyL7`Tm$0oCh_FsS)5;Swzk zaxW*WrlmvirE(HZUrG?6pDrhS^(i=B5^~ViBZ+@u!nQvp9z~Z=CbH(BcQ{FHJQxd_ zfdkae;97Udlh7`?qPNF-{HOvQKbrjI3$SOWNR0Y#rd(tGTB8+9M|(oZ0y^|vAv2&! zqzgow!^y=$!0p#J(5%Pplw$=w8iq(x1cWkH4pCJM8IUdXNYtA|w!Dq-jRj_k2kz5e zz24;Ghu8+}@(%BlA_IYW*Dp3PXXksy&Ub%#w;btUcONst@KM^A=Un6c{<<&tcZL zwzjl_S*p`Q(>|3POhq~Z8TP3b`Hm~WSgunbQ<|oV4P*?{A8q}2)d`xSN>M15%49%YcwjWh8xcPnXRH|JUBEbz6;=_heyuZ|Ebz6a4p&5lA{-%;3 zL6_zh9o0y)l4#I+p`e*X5KRrl^ynS5EOD5t?T(Kpo~F(>8mimc2~&0Z@@RPTVu23O z_4*(%n>AsOcCkQ(VlEYIl0lR`To6drHm|V0WrG5E)e_pU@^3^rx92$T*Tlr=x&I_4I5X9cW?MFH5+vdcQi% zrB1-=#F)H(xF7V1Pa7#9|x`Jbtn z?meOP->WxFvf7v`!ohP6Ve%|t1+u)rB?)dk<{>4 zS-dzO#cEMipyrkTJ__b?eQwAEex~Mmv~Gb$;fFFxHR~oRalpnA!@)HLJS00@aNwa; zB0NWFsT`l`VE#b3`*-+iK?}MMS~zgME&FAUH=EZ6^T77@ERQ$iOBOgnm&@GVj4!4A z3Vhawd5eV%gX(ki{u=@@!n!zpUx&thHyeHUo9xla4t?tFY$Y6iEqkT6LyrsdQO}-i z0S%@6A$yV;s3-p&SOK#Te*1KA25G|3sgxW;J(bNy!(CSCA2r3e`F!9N5odTX=N@$a z^=OWV&c7JVxj&to^g@5cqvhU%&aa2%E<^^uTukTMh+JPfpYzZ&IoUhc!{o}yTn?Oz z?Q}Ca!itNgqiwd_vvv0<3|y%bA0UV@Mdw8#=aRg`lY(HlJMUFr;azlW9}D52?gM#~ z=@{)gn0Lev-S|`9WU4jVGeZ78{1d<5OqYKG_D?N1-_Hv`*XL@_FS=g^heMMp;qF~n7bu99(B3cO)oow@>wuQwV+1626wP~wFodA^l$2a}a?4#sxoPH064%$L9hJpX`)9rs z2-kH5Q(#<-bL1A)+WwoJ_&bQR6Mq63DP)5FU0lA~3d_U5o+QDin^O#8D;~fo!YIbj zV=Tfb!6-$=Ba0jJ;m7QaD`3{TItgl7)Djuo|6MT)ty4UHjYo~};g{h`lWQ38a0w9a zRx(kh@~IBB)w%w0j53UJj3+RbU@XO`z*vTy>nr~?!gqNfW|VWG>eHoxXm?G^`Coeo z*fuX+1p`H8OdwV)=Yk-*PYC?YOT-g04hSl{gg}NiCxZRc@d3frSFmP2X$XX)Z!Pmo zcF6`mX-K5@5HYb{`Q5kevG$HtqTaEp9fy_2#Pe-^;#!gv~E9maZ$4H(_{lYx1uVbZhoCEZ~Uq;fF-WdnA^eK;aqKB!;$ zG2_Jnu2BKF{LMCPowvU^8aG4$HpU)&RNC!1NGH?QPXm43 z^Wh*nu#xThssZ-X4N^!MZplViw$ORcbZNz>uNa##p266HVZpFsJd00epF>rX-r4xp zW+t3^Z_5Klpz-}@YmmA6`89v@iU&^uaM9771Tb)ZtHg(^s7wGj6L@je{BLA@pr%?K z?OQRnVZ4CRgVBp&!`O}-?Jt^hC+*$2p-1$9_8RQ11LM+d-ZApUP>*0j=7|xr?71Wu z`m$F{S;WH`gziPpygQtsU%D;C#Tf|OzxFqX=>13Xxa(Ne>%U6CP_Z*H+UKnGF|O+$ ZP~5-%Y2(7|IM`pYQ{w;Zr_W>Ae*qRZKXU*8